From 27e9d7cb4ee20e4ca85cc46e675f05bc07e5d317 Mon Sep 17 00:00:00 2001 From: Usama <83345144+usamaiqb@users.noreply.github.com> Date: Thu, 5 Nov 2026 15:31:58 +0500 Subject: [PATCH] ci: make the Play upload retryable and read the play-console environment The service account key is in the play-console environment, so the upload job, which asked for `play`, ran with an empty key and failed before reaching Google. The upload moves into its own workflow. release.yml calls it as before, and it can also be run by hand with a release tag: it downloads that release run's bundle and uploads it with the listing and release notes from the tag. A re-run of the release cannot fix a broken upload, because a re-run keeps the workflow file the tag was cut with; this can, without rebuilding or moving the tag. The upload also fails with a plain message when the key is missing, rather than with supply's JSON parse error. --- .github/workflows/play-listing.yml | 2 +- .github/workflows/play-upload.yml | 102 +++++++++++++++++++++++++++++ .github/workflows/release.yml | 48 ++------------ 3 files changed, 110 insertions(+), 42 deletions(-) create mode 100644 .github/workflows/play-upload.yml diff --git a/.github/workflows/play-listing.yml b/.github/workflows/play-listing.yml index f972f7f..2ab2a76 100644 --- a/.github/workflows/play-listing.yml +++ b/.github/workflows/play-listing.yml @@ -15,7 +15,7 @@ jobs: listing: name: Upload store listing runs-on: ubuntu-24.04 - environment: play + environment: play-console steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 diff --git a/.github/workflows/play-upload.yml b/.github/workflows/play-upload.yml new file mode 100644 index 0000000..f4049e3 --- /dev/null +++ b/.github/workflows/play-upload.yml @@ -0,0 +1,102 @@ +name: Play upload + +# Uploads a release's bundle to Google Play. release.yml calls this once the GitHub Release +# exists; it can also be run by hand to retry a failed upload without rebuilding or moving +# the tag. A re-run of the release would not do: a re-run keeps the workflow file the tag +# was cut with, so a fix to this file only reaches a release through here. +# +# The bundle comes from the release run's artifact, which is kept for 7 days. Past that, +# cut a new release. +on: + workflow_call: + inputs: + tag: + type: string + required: true + run_id: + type: string + required: true + workflow_dispatch: + inputs: + tag: + description: Release tag to upload, for example v1.1.1 + required: true + run_id: + description: ID of that tag's Release run. Leave empty to use the latest one. + required: false + +permissions: + contents: read + actions: read # to download the bundle from the release run + +jobs: + play: + name: Upload to Google Play + runs-on: ubuntu-24.04 + # The service account key lives in this environment, so it is only exposed to this job. + environment: play-console + + steps: + - name: Find the release run + id: run + env: + GH_TOKEN: ${{ github.token }} + REPO: ${{ github.repository }} + TAG: ${{ inputs.tag }} + RUN_ID: ${{ inputs.run_id }} + run: | + if [ -z "$RUN_ID" ]; then + RUN_ID=$(gh run list --repo "$REPO" --workflow release.yml --branch "$TAG" \ + --event push --limit 1 --json databaseId --jq '.[0].databaseId') + fi + if [ -z "$RUN_ID" ]; then + echo "❌ No Release run found for $TAG" + exit 1 + fi + echo "Using the bundle from run $RUN_ID" + echo "id=$RUN_ID" >> "$GITHUB_OUTPUT" + + # The listing and the release notes are read from the tag, not from the branch this + # was started on, so a retry uploads what the release described. + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ inputs.tag }} + + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + name: play-bundle + path: play-bundle + run-id: ${{ steps.run.outputs.id }} + github-token: ${{ github.token }} + + - uses: ruby/setup-ruby@de492cf36cbab201753d720ce4f4e336cd688c94 # v1.336.0 + with: + bundler-cache: true + + # Uploads the bundle to the testing track along with everything under + # fastlane/metadata/android: the listing text, the graphics, the screenshots and + # changelogs/.txt as the release notes. The same files F-Droid reads at + # this tag, so both stores describe the same build. + # + # PLAY_TRACK is a repository variable; `alpha` is Play's default closed testing track. + # A custom closed track is addressed by its name. + - name: Upload bundle and store listing + env: + SUPPLY_JSON_KEY_DATA: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }} + TRACK: ${{ vars.PLAY_TRACK || 'alpha' }} + run: | + if [ -z "$SUPPLY_JSON_KEY_DATA" ]; then + echo "❌ PLAY_SERVICE_ACCOUNT_JSON is not set in the play-console environment" + exit 1 + fi + AAB=$(find play-bundle -name '*.aab' | head -n 1) + MAPPING=$(find play-bundle -name 'mapping.txt' | head -n 1) + bundle exec fastlane supply \ + --package_name com.markreader \ + --track "$TRACK" \ + --release_status completed \ + --aab "$AAB" \ + --mapping "$MAPPING" \ + --metadata_path fastlane/metadata/android \ + --sync_image_upload true \ + --skip_upload_apk true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ced1223..4841fba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -66,48 +66,14 @@ jobs: if-no-files-found: error retention-days: 7 - # A separate job so a Play failure never holds back the GitHub Release, and so the service - # account key is only exposed here. The `play` environment can require an approval first. + # A separate job so a Play failure never holds back the GitHub Release. It lives in its own + # workflow so that a failed upload can be retried by hand from there. play: - name: Upload to Google Play needs: release - runs-on: ubuntu-24.04 - environment: play permissions: contents: read - - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 - with: - name: play-bundle - path: play-bundle - - - uses: ruby/setup-ruby@de492cf36cbab201753d720ce4f4e336cd688c94 # v1.336.0 - with: - bundler-cache: true - - # Uploads the bundle to the testing track along with everything under - # fastlane/metadata/android: the listing text, the graphics, the screenshots and - # changelogs/.txt as the release notes. The same files F-Droid reads at - # this tag, so both stores describe the same build. - # - # PLAY_TRACK is a repository variable; `alpha` is Play's default closed testing track. - # A custom closed track is addressed by its name. - - name: Upload bundle and store listing - env: - SUPPLY_JSON_KEY_DATA: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }} - TRACK: ${{ vars.PLAY_TRACK || 'alpha' }} - run: | - AAB=$(find play-bundle -name '*.aab' | head -n 1) - MAPPING=$(find play-bundle -name 'mapping.txt' | head -n 1) - bundle exec fastlane supply \ - --package_name com.markreader \ - --track "$TRACK" \ - --release_status completed \ - --aab "$AAB" \ - --mapping "$MAPPING" \ - --metadata_path fastlane/metadata/android \ - --sync_image_upload true \ - --skip_upload_apk true + actions: read + uses: ./.github/workflows/play-upload.yml + with: + tag: ${{ github.ref_name }} + run_id: ${{ github.run_id }}