diff --git a/.github/scripts/await-central-validation.sh b/.github/scripts/await-central-validation.sh deleted file mode 100755 index 079d389fc..000000000 --- a/.github/scripts/await-central-validation.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/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 -# -# 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 }" -: "${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 diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 91889a2e0..2144028bb 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -243,26 +243,11 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # Uploads a deployment to the portal and leaves it there. Releasing it to - # Maven Central is a click in the portal UI, deliberately: Central never - # forgets a version, so this is the last point at which a bad artifact can - # still be dropped instead of lived with. - name: publish to maven central working-directory: android - # `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" + run: ./gradlew publishToMavenCentral -Podr.abis= 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" diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index e357f922e..de39d2234 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -86,8 +86,6 @@ jobs: gpg-private-key: ${{ secrets.SIGNING_KEY }} gpg-passphrase: MAVEN_GPG_PASSPHRASE - # Uploads and stops, the way the AAR does — released by hand from the - # portal, because Central never forgets a version. - name: publish to maven central run: mvn --batch-mode --no-transfer-progress --file jni/pom.xml deploy -Pcentral -Drevision="${REVISION}" env: diff --git a/android/README.md b/android/README.md index b88ae8bbe..a0912552f 100644 --- a/android/README.md +++ b/android/README.md @@ -124,10 +124,9 @@ key being configured, so `publishToMavenLocal` and the GitHub Packages publish still work without one; an unsigned upload is rejected by the portal, so the release path stays guarded either way. -Publishing **uploads a deployment to the portal and stops**. Releasing it is a -deliberate click in the portal UI, because Central never forgets a version — -that click is the last point at which a bad artifact can be dropped rather than -lived with. +Publishing **releases the deployment**, no click in the portal. The build waits +until it is published, so a green publish job means the version is on Central +and a bundle the portal rejects fails the release. For now OpenDocument.droid keeps building odrcore from the conan package (`with_jni=True`), deploying `libodr_jni.so` and `odr-core-java.jar` out of it. That path is unaffected by anything here, and it is the reason the diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 3fee3a7d8..b49b4c98d 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -175,13 +175,11 @@ dependencies { mavenPublishing { configure(AndroidSingleVariantLibrary(variant = "release")) - // Uploads to the portal and stops. A human releases it from there, so a bad - // artifact is still recallable — Central is immutable once released. - // - // 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) + // Releases the deployment rather than parking it in the portal, and waits + // for it to land: a release is reported as published on the strength of + // this task's exit code, and the default prints "Skipping deployment + // validation!" and exits 0 whatever the portal makes of the bundle. + publishToMavenCentral(true, DeploymentValidation.PUBLISHED) // Only Central demands a signature. Making it unconditional would mean no // `publishToMavenLocal` and no GitHub Packages publish without a private diff --git a/jni/README.md b/jni/README.md index 9387913d2..431291716 100644 --- a/jni/README.md +++ b/jni/README.md @@ -27,7 +27,8 @@ The native library is loaded from `java.library.path` as `odr_jni` The Java classes are published as `app.opendocument:odr-core-java` to Maven Central and to [GitHub Packages](https://github.com/orgs/opendocument-app/packages?repo_name=OpenDocument.core) -on release (`.github/workflows/maven.yml`, built from `pom.xml`). The artifact +on release (`.github/workflows/maven.yml`, built from `pom.xml`); the Central +deployment publishes itself, no click in the portal. The artifact contains **only the Java API** — consumers build the native `odr_jni` library themselves for their target platform (see below) and provide it at runtime. diff --git a/jni/pom.xml b/jni/pom.xml index ec2ff9a86..5d0c1a5f9 100644 --- a/jni/pom.xml +++ b/jni/pom.xml @@ -170,9 +170,11 @@ true central - - false + true + + published