Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions .github/scripts/await-central-validation.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/usr/bin/env bash
# Waits for a central portal deployment to validate, and fails if it does not.
#
# `publishToMavenCentral` uploads and exits 0 whatever the portal makes of the
# bundle - the vanniktech plugin only validates when `automaticRelease` is on,
# which would also release it, and releasing is deliberately a human's job here.
# So the release path polls the portal itself. The maven jar gets this for free:
# the sonatype maven plugin blocks and reports.
#
# await-central-validation.sh <gradle-log>
#
# Takes the gradle output to read the deployment id out of, and the portal token
# as MAVEN_CENTRAL_USERNAME / MAVEN_CENTRAL_PASSWORD.

set -euo pipefail

log="${1:?usage: await-central-validation.sh <gradle-log>}"
: "${MAVEN_CENTRAL_USERNAME:?}" "${MAVEN_CENTRAL_PASSWORD:?}"

deployment=$(grep -oE 'deployment id: [0-9a-fA-F-]{36}' "$log" | tail -1 | awk '{print $3}')
if [ -z "$deployment" ]; then
echo "no deployment id in $log - did the upload actually run?" >&2
exit 1
fi

token=$(printf '%s:%s' "$MAVEN_CENTRAL_USERNAME" "$MAVEN_CENTRAL_PASSWORD" | base64 | tr -d '\n')
echo "waiting on deployment ${deployment}"

# Validation is usually seconds; the ceiling is only here so a portal that never
# answers fails the release instead of hanging until github's own timeout.
for _ in $(seq 60); do
response=$(curl -sS -X POST -H "Authorization: Bearer ${token}" \
"https://central.sonatype.com/api/v1/publisher/status?id=${deployment}")
state=$(printf '%s' "$response" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("deploymentState",""))')

case "$state" in
VALIDATED|PUBLISHING|PUBLISHED)
echo "deployment ${deployment} is ${state}"
exit 0
;;
FAILED)
echo "deployment ${deployment} failed validation:" >&2
printf '%s\n' "$response" >&2
exit 1
;;
PENDING|VALIDATING|"")
sleep 10
;;
*)
echo "unexpected deployment state '${state}':" >&2
printf '%s\n' "$response" >&2
exit 1
;;
esac
done

echo "deployment ${deployment} still not validated after 10 minutes" >&2
exit 1
13 changes: 12 additions & 1 deletion .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -255,9 +255,20 @@ jobs:
# still be dropped instead of lived with.
- name: publish to maven central
working-directory: android
run: ./gradlew publishToMavenCentral -Podr.abis=
# `shell: bash` for the pipefail it sets - the default `bash -e` would
# let tee's exit code hide a failing gradle
shell: bash
run: ./gradlew publishToMavenCentral -Podr.abis= | tee "${RUNNER_TEMP}/publish.log"
env:
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SIGNING_KEY }}
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_PASS }}

# The step above exits 0 however the portal judges the bundle, so without
# this a release central rejected looks like one that worked.
- name: await central validation
env:
MAVEN_CENTRAL_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
run: .github/scripts/await-central-validation.sh "${RUNNER_TEMP}/publish.log"
7 changes: 6 additions & 1 deletion android/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import com.vanniktech.maven.publish.AndroidSingleVariantLibrary
import com.vanniktech.maven.publish.DeploymentValidation

plugins {
alias(libs.plugins.android.library)
Expand Down Expand Up @@ -176,7 +177,11 @@ mavenPublishing {

// Uploads to the portal and stops. A human releases it from there, so a bad
// artifact is still recallable — Central is immutable once released.
publishToMavenCentral()
//
// Waiting for VALIDATED is what makes a failed deployment fail the release:
// the default uploads, prints "Skipping deployment validation!" and exits 0
// whatever the portal then makes of the bundle.
publishToMavenCentral(false, DeploymentValidation.VALIDATED)
Comment thread
andiwand marked this conversation as resolved.

// Only Central demands a signature. Making it unconditional would mean no
// `publishToMavenLocal` and no GitHub Packages publish without a private
Expand Down
Loading