Nexus \ OSSRH \ 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.
Custom container on Jiro
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, otherwisesettings.xml
andsettings-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'
}
}
}
}
}
How can artifacts be deployed to Nexus OSS (repo.eclipse.org)?
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.
Custom container on Jiro
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, otherwisesettings.xml
andsettings-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'
}
}
}
}
}
How can artifacts be deployed to OSSRH / Maven Central?
Deploying artifacts to OSSRH (OSS Repository Hosting provided by Sonatype) requires an account at OSSRH. 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 OSSRH is not necessary. 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.
If you are using a custom container, please see Custom container on Jiro
Required steps for a freestyle job
Required steps for a pipeline job
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'
}
}
}
}
Custom container on Jiro
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/repository
is not writable
* the toolchains-xml
volume 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'
}
}
}
}
}
Common issues with GPG
Error message | Solution |
---|---|
gpg: signing failed: Not a tty |
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) |
Signing with Gradle
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
GnupgSignatory
by callinguseGpgCmd()
in the signing task -
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
How can artifacts be released from OSSRH to Maven Central?
There are different ways of "releasing" from OSSRH to Maven Central.
- a) you can create an OSSRH account (https://issues.sonatype.org/secure/Signup!default.jspa) and ask for permissions for your user on the JIRA issue that was created when your project requested access to OSSRH. With the given permissions you can access the Nexus UI at oss.sonatype.org and release via the UI.
- b) you can release "headless" (e.g. with a build job) via the nexus-staging-maven-plugin (see https://github.com/sonatype/nexus-maven-plugins/tree/main/staging/maven-plugin#release, see also the rc-* CLI commands)
- c) with the Gradle Nexus Publish Plugin: https://github.com/gradle-nexus/publish-plugin/
See also: https://central.sonatype.org/publish/release/#locate-and-examine-your-staging-repository