#!/bin/bash
set -eu # we don't want "pipefail" to implement idempotency
###
# Usage: ./publish-mvn.sh
#
# Publishes the content of a release bundle (current directory)to Maven Central.
#
# This script expects the following environment variables to be set to appropriate
# values (which can be achieved by using scripts/with-signing-key.sh):
#
# + GNUPGHOME - A GnuPG home directory containing the signing key
# + KEY_ID - The ID of the GnuPG key that will be used for signing
# + KEY_PASSPHRASE - The passphrase of the provided key.
# + FOR_REAL - Set to "true" to do actual publishing
# + STAGING_PROFILE_ID - The Maven Central (sonatype) staging profile ID (e.g. 68a05363083174)
# + MAVEN_USERNAME - User name for Sonatype
# + MAVEN_PASSWORD - Password for Sonatype
###
error() { echo "❌ $@"; exit 1; }
[ -z "${GNUPGHOME:-}" ] && error "GNUPGHOME is required"
[ -z "${KEY_ID:-}" ] && error "KEY_ID is required"
[ -z "${KEY_PASSPHRASE:-}" ] && echo "KEY_PASSPHRASE is required"
[ -z "${STAGING_PROFILE_ID:-}" ] && echo "STAGING_PROFILE_ID is required"
[ -z "${MAVEN_USERNAME:-}" ] && echo "MAVEN_USERNAME is required"
[ -z "${MAVEN_PASSWORD:-}" ] && echo "MAVEN_PASSWORD is required"
if [[ "${FOR_REAL:-}" == "true" ]]; then
mvn=mvn
dry_run=false
else
echo "==========================================="
echo " 🏜️ DRY-RUN MODE 🏜️"
echo
echo "Set FOR_REAL=true to do actual publishing!"
echo "==========================================="
mvn="echo mvn"
dry_run=true
fi
staging=$(mktemp -d)
workdir=$(mktemp -d)
if [[ ! -d ./java ]]; then
echo "❌ No JARS to publish: 'java/' directory is missing."
exit 1
fi
echo "📦 Publishing to Maven Central"
# Create a settings.xml file with the user+password for maven
mvn_settings="${workdir}/mvn-settings.xml"
cat > ${mvn_settings} <<-EOF
ossrh
${MAVEN_USERNAME}
${MAVEN_PASSWORD}
EOF
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo " Preparing repository"
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
# Sign and stage our artifacts into a local directory
found=false
for pom in $(find ./java -name '*.pom'); do
found=true
source_arg=""
if [[ -f ${pom/.pom/-sources.jar} ]]; then
source_arg="-Dsources=${pom/.pom/-sources.jar}"
fi
javadoc_arg=""
if [[ -f ${pom/.pom/-javadoc.jar} ]]; then
javadoc_arg="-Djavadoc=${pom/.pom/-javadoc.jar}"
fi
$mvn --settings=${mvn_settings} gpg:sign-and-deploy-file \
-Durl=file://${staging} \
-DrepositoryId=maven-central \
-Dgpg.homedir=${GNUPGHOME} \
-Dgpg.keyname=0x${KEY_ID} \
-Dgpg.passphrase=${KEY_PASSPHRASE} \
-DpomFile=${pom} \
-Dfile=${pom/.pom/.jar} \
$source_arg \
$javadoc_arg
done
if ! $found; then
echo "❌ No JARS to publish: no .pom files found in java/ directory."
exit 1
fi
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo " Deploying and closing repository..."
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
nexus_staging_maven_plugin_version='1.6.13'
staging_output="${workdir}/deploy-output.txt"
$mvn --settings=${mvn_settings} \
org.sonatype.plugins:nexus-staging-maven-plugin:${nexus_staging_maven_plugin_version}:deploy-staged-repository \
-DrepositoryDirectory=${staging} \
-DnexusUrl=${MAVEN_ENDPOINT:-https://oss.sonatype.org} \
-DserverId=ossrh \
-DautoReleaseAfterClose=true \
-DstagingProfileId=${STAGING_PROFILE_ID} | tee ${staging_output}
# we need to consule PIPESTATUS sinec "tee" is the last command
if [ ${PIPESTATUS[0]} -ne 0 ]; then
echo "❌ Repository deployment failed"
exit 1
fi
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo " Releasing repository"
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
# Extract the ID of the closed repository from the log output of "deploy-staged-repository"
# This is because "deploy-staged-repository" doesn't seem to support autoReleaseAfterClose
# See https://issues.sonatype.org/browse/OSSRH-42487
if $dry_run; then
echo 'Closing staging repository with ID "dummyrepo"' > ${staging_output}
fi
repository_id="$(cat ${staging_output} | grep "Closing staging repository with ID" | cut -d'"' -f2)"
if [ -z "${repository_id}" ]; then
echo "❌ Unable to extract repository ID from deploy-staged-repository output."
echo "This means it failed to close or there was an unexpected problem."
echo "At any rate, we can't release it. Sorry"
exit 1
fi
echo "Repository ID: ${repository_id}"
# Create a dummy pom.xml because the "release" goal needs one, but it doesn't care about it at all
release_pom="${workdir}/release-pom.xml"
cat > ${release_pom} <
4.0.0
dummy
dummy
0.0.0
HERE
# Release!
release_output="${workdir}/release-output.txt"
export MAVEN_OPTS="--add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.text=ALL-UNNAMED --add-opens=java.desktop/java.awt.font=ALL-UNNAMED"
$mvn --settings ${mvn_settings} -f ${release_pom} \
org.sonatype.plugins:nexus-staging-maven-plugin:${nexus_staging_maven_plugin_version}:release \
-DserverId=ossrh \
-DnexusUrl=${MAVEN_ENDPOINT:-https://oss.sonatype.org} \
-DstagingProfileId=${STAGING_PROFILE_ID} \
-DstagingRepositoryId=${repository_id} | tee ${release_output}
# If release failed, check if this was caused because we are trying to publish
# the same version again, which is not an error. The magic string "does not
# allow updating artifact" for a ".pom" file indicates that we are trying to
# override an existing version. Otherwise, fail!
if [ ${PIPESTATUS[0]} -ne 0 ]; then
if cat ${release_output} | grep "does not allow updating artifact" | grep -q ".pom"; then
echo "⚠️ Artifact already published. Skipping"
else
echo "❌ Release failed"
exit 1
fi
fi
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo "✅ All Done!"