Upload to maven central with individually versioned bundles

We recently started uploading our bundles to maven central. To do that a trusted staging repository is needed (in our case sonatype). They perform certain checks, to make sure your artifacts meet the standards (like e.g. jars need to be signed) of maven central. BND can smoothly handle the the signing of artifacts and upload to the sonatype staging repo. We do our builds on release builds on jenkins, but the following principle should work on other build systems as well. The only prerequisit is that gpg needs to be installed whereever you do the build.

First step is, to decide if a release build is needed. We only want our jenkins to do that and thus bnd needs to omit such a release.

On our jenkins, we have the GNUPG_PASSPHRASE set as environment variable. This acts as a marker in our build to trigger the release to sonartype and the actuall signing.

Somewhere in the build.bnd or in your cnf/ext folder:

#This includes the central.bnd if the GNUPG_PASSPHRASE is set
-include: ${if;${env;GNUPG_PASSPHRASE};\
              ${build}/releng/central.bnd\
          }

central.bnd:

# Add the sonartype repo
-plugin.sonatype: \
    aQute.bnd.repository.maven.provider.MavenBndRepository;\
        snapshotUrl=https://oss.sonatype.org/content/repositories/snapshots/;\
        releaseUrl=https://oss.sonatype.org/service/local/staging/deploy/maven2/;\
        index=${.}/sonatype.maven;\
        name='Sonatype'

# add the repo to the release repos
-releaserepo.sonatype: Sonatype

# tell bnd what we want to sign the 
-maven-release:\
    sign;passphrase=${env;GNUPG_PASSPHRASE}

# With this set, you can modify how bnd calls gpg. The -homedir points to the keyring to use.
# The --pinentry-mode loopback allows for a headless run without any manual input
gpg: gpg --homedir /var/jenkins_home/.gnupg --pinentry-mode loopback

Everything is fine and dandy as long as we do a simultaneous release, where we bump the version for all projects in a workspace. For individually versioned bundles, we ran into a problem. Sonatype opens a staging repository for a release. This is empty by nature and causes bnd to upload all bundles in the workspace. When we want to close and release it, sonartype will appear to do the upload, but none of the artifacts will ever arrive on central..

Thus I only want to release bundles that aren’t already released. We have a Baseline repo, which can tell us about that.

I came up with the following Construct that needs to replace the -maven-release instruction of the previous example

# We need to strip the -SNAPSHOT from our Version, the Bundleversion set in our bnd files will always have 
# the -SNAPSHOT attached, regardles of a release or snapshot build. Thus we need to strip it
releaseVersion: ${get;0;${split;-;${Bundle-Version}}}

# is there a bundle with the release version in one of our Repos? If so, we already released it to our 
# baseline repo an no release is necessary
releaseNotNeeded: ${findproviders;osgi.identity;(&(osgi.identity=${p})(version=${releaseVersion}));REPOS}

# local only puts the artifacts in the local maven repo
-maven-release: ${if;${def;releaseNotNeeded};local;remote};\
    sign;passphrase=${env;GNUPG_PASSPHRASE}

I hope this helps.

by Jürgen Albert