From e83a019c61e2cc85caa4f655596df2be58da413a Mon Sep 17 00:00:00 2001 From: Ahmed Saleh Date: Tue, 20 Oct 2026 15:48:07 +0200 Subject: [PATCH 1/2] Publish to Maven Central via the Sonatype Central Portal OSSRH (oss.sonatype.org) was shut down on 2025-06-30, which is why the 1.3.5 publish job failed. Upload through the Portal's OSSRH Staging API compatibility endpoint instead, and release by calling its manual/upload endpoint from the same job as the upload. Also adds a workflow_dispatch trigger to retry a publish for the current version without re-tagging, and replaces deprecated set-output and the archived actions/create-release. Co-Authored-By: Claude Opus 5.5 (1M context) --- .github/workflows/release.yml | 60 +++++++++++++--------------- build.gradle | 5 ++- scripts/get_staging_repository_id.py | 29 -------------- 3 files changed, 31 insertions(+), 63 deletions(-) delete mode 100644 scripts/get_staging_repository_id.py diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c7699b8..a368bcb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,9 +1,13 @@ on: push: branches: [ master ] + # Manual run: publishes the current build.gradle version to Maven Central + # without creating a tag / GitHub release (e.g. to retry a failed publish). + workflow_dispatch: jobs: check-release-tag: + if: ${{ github.event_name == 'push' }} runs-on: ubuntu-latest steps: - name: Checkout code @@ -26,7 +30,7 @@ jobs: id: release_output if: ${{ steps.prepare_tag.outcome == 'success' }} run: | - echo "::set-output name=tag::${{ env.TAG }}" + echo "tag=${{ env.TAG }}" >> $GITHUB_OUTPUT outputs: tag: ${{ steps.release_output.outputs.tag }} @@ -34,27 +38,23 @@ jobs: runs-on: ubuntu-latest needs: check-release-tag if: ${{ needs.check-release-tag.outputs.tag }} + permissions: + contents: write steps: - uses: actions/checkout@v4 - name: Prepare tag run: | export TAG=v$(awk '/^version = / { gsub("\"", ""); print $3 }' build.gradle) echo "TAG=$TAG" >> $GITHUB_ENV - - name: Setup git - run: | - git config user.email "pusher-ci@pusher.com" - git config user.name "Pusher CI" - name: Prepare description run: | csplit -s CHANGELOG.md "/##/" {1} cat xx01 > CHANGELOG.tmp - name: Create Release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + uses: softprops/action-gh-release@v2 with: tag_name: ${{ env.TAG }} - release_name: ${{ env.TAG }} + name: ${{ env.TAG }} body_path: CHANGELOG.tmp draft: false prerelease: false @@ -62,16 +62,20 @@ jobs: publish: runs-on: ubuntu-latest needs: create-github-release + if: ${{ always() && (needs.create-github-release.result == 'success' || github.event_name == 'workflow_dispatch') }} steps: - uses: actions/checkout@v4 + - name: Set up JDK + uses: actions/setup-java@v4 + with: + java-version: "11" + distribution: "temurin" - name: Create gradle.properties shell: bash run: | mkdir -p _gradle_user_home echo "GRADLE_USER_HOME=_gradle_user_home" >> $GITHUB_ENV cat < _gradle_user_home/gradle.properties - github.username=${{ secrets.PUSHER_CI_GITHUB_PRIVATE_TOKEN }} - github.password="" maven.username=${{ secrets.MAVEN_USERNAME }} maven.password=${{ secrets.MAVEN_PASSWORD }} signing.keyId=${{ secrets.SIGNING_KEY_ID }} @@ -79,25 +83,17 @@ jobs: signing.secretKeyRingFile=_gradle_user_home/pusher-maven-gpg-signing-key.gpg FILE echo "${{ secrets.PUSHER_MAVEN_GPG_SIGNING_KEY }}" | base64 --decode > _gradle_user_home/pusher-maven-gpg-signing-key.gpg - - name: Publish - run: | - ./gradlew publish - - finish-release: - runs-on: ubuntu-latest - needs: publish - env: - NEXUS_USERNAME: ${{ secrets.MAVEN_USERNAME }} - NEXUS_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} - steps: - - uses: actions/checkout@v4 - - id: get_staging_repository_id - name: Get staging repository id + - name: Upload to Sonatype staging + run: ./gradlew publish + # Hands the uploaded staging repository to the Central Portal, which + # validates it and releases it to Maven Central. Must run from the same + # job (same IP address) as the upload above. + - name: Release to Maven Central + env: + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} run: | - echo "staging_repository_id=$(python3 scripts/get_staging_repository_id.py)" >> $GITHUB_OUTPUT - - name: Release - uses: nexus-actions/release-nexus-staging-repo@main - with: - username: ${{ secrets.MAVEN_USERNAME }} - password: ${{ secrets.MAVEN_PASSWORD }} - staging_repository_id: ${{ steps.get_staging_repository_id.outputs.staging_repository_id }} + TOKEN=$(printf '%s:%s' "$MAVEN_USERNAME" "$MAVEN_PASSWORD" | base64 -w0) + curl --fail-with-body -sS -X POST \ + -H "Authorization: Bearer $TOKEN" \ + "https://ossrh-staging-api.central.sonatype.com/manual/upload/defaultRepository/com.pusher?publishing_type=automatic" diff --git a/build.gradle b/build.gradle index 1d96b01..ebbbaaf 100644 --- a/build.gradle +++ b/build.gradle @@ -131,8 +131,9 @@ publishing { } repositories { maven { - def releaseRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" - def snapshotRepositoryUrl = "https://oss.sonatype.org/content/repositories/snapshots/" + // Sonatype Central Portal (OSSRH was shut down on 2025-06-30) + def releaseRepositoryUrl = "https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/" + def snapshotRepositoryUrl = "https://central.sonatype.com/repository/maven-snapshots/" url = version.endsWith("SNAPSHOT") ? snapshotRepositoryUrl : releaseRepositoryUrl credentials { username = findProperty("maven.username") ?: "" diff --git a/scripts/get_staging_repository_id.py b/scripts/get_staging_repository_id.py deleted file mode 100644 index 4d73556..0000000 --- a/scripts/get_staging_repository_id.py +++ /dev/null @@ -1,29 +0,0 @@ -import base64 -import json -import os -import sys -import urllib.request - -username = os.environ.get('NEXUS_USERNAME') -password = os.environ.get('NEXUS_PASSWORD') - -def get(url, username, password): - req = urllib.request.Request(url) - base64_auth = base64.b64encode(bytes('{}:{}'.format(username, password),'ascii')) - req.add_header("Authorization", "Basic {}".format(base64_auth.decode('utf-8'))) - req.add_header('Accept', 'application/json') - with urllib.request.urlopen(req) as response: - return response.read() - -def getRepositories(username, password): - return json.loads(get("https://oss.sonatype.org/service/local/staging/profile_repositories", username, password)) - -repositories = getRepositories(username, password).get("data") -if len(repositories) != 1: - sys.stderr.write("Zero or more than one staging repository. Exiting. Please execute the process manually.") - exit(1) - -repositoryId = repositories[0].get("repositoryId") -print(repositoryId) - - From 0579450fd351ac03b598f7052f57f8bdc9348e52 Mon Sep 17 00:00:00 2001 From: Ahmed Saleh Date: Tue, 20 Oct 2026 15:52:14 +0200 Subject: [PATCH 2/2] Pin softprops/action-gh-release to a commit SHA Co-Authored-By: Claude Opus 5.5 (1M context) --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a368bcb..61a579d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -51,7 +51,7 @@ jobs: csplit -s CHANGELOG.md "/##/" {1} cat xx01 > CHANGELOG.tmp - name: Create Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2 with: tag_name: ${{ env.TAG }} name: ${{ env.TAG }}