-
Notifications
You must be signed in to change notification settings - Fork 42
Nexus Maven Central
Every JIPP has a Maven settings file set up that specifies our local Nexus instance as cache for Maven Central.
Important
In Jiro this works out of the box for the default pod templates. No additional configuration is required for Freestyle and Pipeline jobs. For custom containers, see the following section.
You need to add the settings-xml volume, as shown below. Please note, the m2-repo volume is required as well, otherwise /home/jenkins/.m2/repository is not writable.
Note
In custom containers the user.home environment variable needs to be set to /home/jenkins via MAVEN_OPTS, otherwise settings.xml and settings-security.xml can not be found.
pipeline {
agent {
kubernetes {
label 'my-agent-pod'
yaml """
apiVersion: v1
kind: Pod
spec:
containers:
- name: maven
image: maven:alpine
tty: true
command:
- cat
env:
- name: "MAVEN_OPTS"
value: "-Duser.home=/home/jenkins"
volumeMounts:
- name: settings-xml
mountPath: /home/jenkins/.m2/settings.xml
subPath: settings.xml
readOnly: true
- name: m2-repo
mountPath: /home/jenkins/.m2/repository
volumes:
- name: settings-xml
secret:
secretName: m2-secret-dir
items:
- key: settings.xml
path: settings.xml
- name: m2-repo
emptyDir: {}
"""
}
}
stages {
stage('Run maven') {
steps {
container('maven') {
sh 'mvn -version'
}
}
}
}
}If your project does not have its own repo on Nexus yet, then open a HelpDesk issue and specify what project you'd like a Nexus repo for.
If your project does have its own repo on Nexus already, then you can use Maven (or Gradle) to deploy artifacts to repo.eclipse.org.
Note
On our cluster-based infra (Jiro), a separate Maven settings file for deployment to Nexus is not required. All information is contained in the default Maven settings file located at /home/jenkins/.m2/settings.xml, which does not need to be specified explicitly in your job configuration.
You need to add the settings-xml volume, as shown below. Please note, the m2-repo volume is required as well, otherwise /home/jenkins/.m2/repository is not writable.
Note
In custom containers the user.home environment variable needs to be set to /home/jenkins via MAVEN_OPTS, otherwise settings.xml and settings-security.xml can not be found.
pipeline {
agent {
kubernetes {
label 'my-agent-pod'
yaml """
apiVersion: v1
kind: Pod
spec:
containers:
- name: maven
image: maven:alpine
tty: true
command:
- cat
env:
- name: "MAVEN_OPTS"
value: "-Duser.home=/home/jenkins"
volumeMounts:
- name: settings-xml
mountPath: /home/jenkins/.m2/settings.xml
subPath: settings.xml
readOnly: true
- name: settings-security-xml
mountPath: /home/jenkins/.m2/settings-security.xml
subPath: settings-security.xml
readOnly: true
- name: m2-repo
mountPath: /home/jenkins/.m2/repository
volumes:
- name: settings-xml
secret:
secretName: m2-secret-dir
items:
- key: settings.xml
path: settings.xml
- name: settings-security-xml
secret:
secretName: m2-secret-dir
items:
- key: settings-security.xml
path: settings-security.xml
- name: m2-repo
emptyDir: {}
"""
}
}
stages {
stage('Run maven') {
steps {
container('maven') {
sh 'mvn clean deploy'
}
}
}
}
}[!IMPORTANT] As of June 30th, OSSRH is deprecated. New deployments will take place in the Central Portal. Please pay attention to the existing documentation here: https://central.sonatype.org/
Deploying artifacts to Central Portal (OSS Repository Hosting provided by Sonatype) requires an account. It is also required to sign all artifacts with GPG. The Eclipse IT team will set this up for the project.
Please open a HelpDesk issue for this first.
Note
On our cluster-based infra (Jiro), a separate Maven settings file for deployment to Central Portal is not necessary. All information is contained in the default Maven settings file located at /home/jenkins/.m2/settings.xml, with server_id: central which does not need to be specified explicitly in your job configuration.
If you are using a custom container, please see Custom container on Jiro
| Steps | Screenshots |
|---|---|
1. Insert secret-subkeys.asc as secret file in job |
![]() |
2. Import GPG keyring with --batch and trust the keys non-interactively in a shell build step (before the Maven call)gpg --batch --import "${KEYRING}"
for fpr in $(gpg --list-keys --with-colons | awk -F: '/fpr:/ {print $10}' | sort -u);
do
echo -e "5\ny\n" | gpg --batch --command-fd 0 --expert --edit-key $fpr trust;
done |
![]() |
3. If a newer GPG version (> 2.1+) is used, --pinentry-mode loopback needs to be added as GPG argument in the pom.xml.<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin> |
This is a simple pipeline job, that allows to test the GPG signing.
pipeline {
agent any
tools {
maven 'apache-maven-latest'
jdk 'openjdk-jdk17-latest'
}
stages {
stage('Build') {
steps {
sh "mvn -B -U archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false"
sh '''cat >my-app/pom.xml <<EOL
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>my-app</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
EOL'''
withCredentials([file(credentialsId: 'secret-subkeys.asc', variable: 'KEYRING')]) {
sh 'gpg --batch --import "${KEYRING}"'
sh 'for fpr in $(gpg --list-keys --with-colons | awk -F: \'/fpr:/ {print $10}\' | sort -u); do echo -e "5\ny\n" | gpg --batch --command-fd 0 --expert --edit-key ${fpr} trust; done'
}
sh "mvn -B -f my-app/pom.xml clean verify"
sh 'gpg --verify my-app/target/my-app-1.0-SNAPSHOT.jar.asc'
}
}
}
}When you are using a custom container on Jiro, you will need to add the settings-xml and settings-security-xml volumes, as shown below.
Please note:
- the m2-repo volume is required as well, otherwise
/home/jenkins/.m2/repositoryis not writable - the
toolchains-xmlvolume is optional, but added for completeness - you also might need to add additional volumes like
volume-known-hosts(as described here: Pipeline job with custom pod template)
pipeline {
agent {
kubernetes {
label 'my-agent-pod'
yaml """
apiVersion: v1
kind: Pod
spec:
containers:
- name: maven
image: maven:alpine
tty: true
command:
- cat
volumeMounts:
- name: settings-xml
mountPath: /home/jenkins/.m2/settings.xml
subPath: settings.xml
readOnly: true
- name: toolchains-xml
mountPath: /home/jenkins/.m2/toolchains.xml
subPath: toolchains.xml
readOnly: true
- name: settings-security-xml
mountPath: /home/jenkins/.m2/settings-security.xml
subPath: settings-security.xml
readOnly: true
- name: m2-repo
mountPath: /home/jenkins/.m2/repository
volumes:
- name: settings-xml
secret:
secretName: m2-secret-dir
items:
- key: settings.xml
path: settings.xml
- name: toolchains-xml
configMap:
name: m2-dir
items:
- key: toolchains.xml
path: toolchains.xml
- name: settings-security-xml
secret:
secretName: m2-secret-dir
items:
- key: settings-security.xml
path: settings-security.xml
- name: m2-repo
emptyDir: {}
"""
}
}
stages {
stage('Run maven') {
steps {
container('maven') {
sh 'mvn -version'
}
}
}
}
}| Error message | Solution |
|---|---|
gpg: signing failed: Not a tty or gpg: signing failed: Inappropriate ioctl for device
|
GPG version > 2.1 is used and --pinentry-mode loopback needs to be added to the maven-gpg-plugin config in the pom.xml (see above). |
gpg: invalid option "--pinentry-mode" |
GPG version < 2.1 is used and --pinentry-mode loopback needs to be removed from the maven-gpg-plugin config in the pom.xml |
gpg: no default secret key: No secret key or gpg: signing failed: No secret key
|
GPG keyring needs to be imported (see above) |
To sign artifacts with Gradle, the following needs to be done:
-
Import the GPG Keyring as described above
-
Add the GPG Passphrase to the build with a secret binding (type: secret text, variable: PASSPHRASE). Please file a ticket to get the passphrase added to the Jenkins instance.
-
Use
GnupgSignatoryby callinguseGpgCmd()in the signing tasksigning { useGpgCmd() sign <something> }
-
Use pinentry-mode loopback and no-tty config properties by appending it to
~/.gnupg/gpg.conf -
Call Gradle with the following parameters:
-Psigning.gnupg.keyId=<key_id>-Psigning.gnupg.passphrase=${PASSPHRASE}-Psigning.gnupg.executable=gpg
See also: https://docs.gradle.org/current/userguide/signing_plugin.html#sec:using_gpg_agent
- Maven: you can release "headless" (e.g. with a build job) via the
central-publishing-maven-plugin(see https://central.sonatype.org/publish/publish-portal-maven/#automatic-publishing) - Gradle: with the Gradle Nexus Publish Plugin: https://github.com/gradle-nexus/publish-plugin/
Update pom.xml
<build>
<plugins>
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.7.0</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
<autoPublish>true</autoPublish>
<waitUntil>published</waitUntil>
<centralSnapshotsUrl>https://central.sonatype.com/repository/maven-snapshots/</centralSnapshotsUrl>
</configuration>
</plugin>
<plugins>
</build>
