From 2e7eda03205fefb25ed9b683fd44a6d4bd0f67a7 Mon Sep 17 00:00:00 2001 From: Rik Date: Mon, 28 Sep 2026 16:05:53 +1000 Subject: [PATCH] CI: reusable Publish workflow, runnable by hand for any release A job rerun does not pick up secrets added after the original run, so the Firefox job for v2.0.1 skipped even after AMO credentials were set. Store publishing now lives in publish.yml: release.yml calls it after a tag build, and it can be dispatched for any existing tag and any subset of stores. The WIF provider condition now also admits workflow_dispatch runs on main. Co-Authored-By: Claude Opus 5.5 (1M context) --- .github/workflows/publish.yml | 83 +++++++++++++++++++++++++++++++++++ .github/workflows/release.yml | 75 +++---------------------------- README.md | 5 ++- 3 files changed, 94 insertions(+), 69 deletions(-) create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..39106cb --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,83 @@ +name: Publish + +# Submits an existing GitHub release to the stores. Runs automatically after a tag release +# (release.yml calls it), or by hand to retry a store or pick up newly added credentials: +# gh workflow run publish.yml -f tag=v2.0.1 +# gh workflow run publish.yml -f tag=v2.0.1 -f stores=firefox +# Chrome Web Store keyless, via Workload Identity Federation (clicktrack-505800) +# Firefox (AMO) secrets AMO_JWT_ISSUER, AMO_JWT_SECRET +# Microsoft Edge secrets EDGE_PRODUCT_ID, EDGE_CLIENT_ID, EDGE_API_KEY +# A store with no credentials is skipped, not failed. +on: + workflow_call: + inputs: + tag: { type: string, required: true } + stores: { type: string, default: 'chrome,firefox,edge' } + workflow_dispatch: + inputs: + tag: { description: 'Release tag, e.g. v2.0.1', type: string, required: true } + stores: { description: 'Comma-separated: chrome,firefox,edge', type: string, default: 'chrome,firefox,edge' } + +jobs: + chrome: + if: contains(inputs.stores, 'chrome') + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@v4 + with: { ref: '${{ inputs.tag }}' } + - uses: actions/setup-node@v4 + with: { node-version: 22 } + - id: auth + uses: google-github-actions/auth@v2 + with: + workload_identity_provider: projects/667575805085/locations/global/workloadIdentityPools/github/providers/silentblock + service_account: cws-publisher@clicktrack-505800.iam.gserviceaccount.com + token_format: access_token + access_token_scopes: https://www.googleapis.com/auth/chromewebstore + - name: Download release zips + env: { GH_TOKEN: '${{ github.token }}' } + run: gh release download "${{ inputs.tag }}" --dir release + - name: Submit to the Chrome Web Store + env: { CWS_ACCESS_TOKEN: '${{ steps.auth.outputs.access_token }}' } + run: node scripts/publish/chrome.mjs + + firefox: + if: contains(inputs.stores, 'firefox') + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + with: { ref: '${{ inputs.tag }}' } + - uses: actions/setup-node@v4 + with: { node-version: 22 } + - name: Download release zips + env: { GH_TOKEN: '${{ github.token }}' } + run: gh release download "${{ inputs.tag }}" --dir release + - name: Submit to addons.mozilla.org + env: + AMO_JWT_ISSUER: ${{ secrets.AMO_JWT_ISSUER }} + AMO_JWT_SECRET: ${{ secrets.AMO_JWT_SECRET }} + run: node scripts/publish/firefox.mjs + + edge: + if: contains(inputs.stores, 'edge') + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + with: { ref: '${{ inputs.tag }}' } + - uses: actions/setup-node@v4 + with: { node-version: 22 } + - name: Download release zips + env: { GH_TOKEN: '${{ github.token }}' } + run: gh release download "${{ inputs.tag }}" --dir release + - name: Submit to Microsoft Edge Add-ons + env: + EDGE_PRODUCT_ID: ${{ secrets.EDGE_PRODUCT_ID }} + EDGE_CLIENT_ID: ${{ secrets.EDGE_CLIENT_ID }} + EDGE_API_KEY: ${{ secrets.EDGE_API_KEY }} + run: node scripts/publish/edge.mjs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a2c840f..2629cab 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,12 +1,8 @@ name: Release # Push a tag like v2.0.1 and this builds, tests, creates the GitHub release, then submits -# the new version to every store it has credentials for: -# Chrome Web Store keyless, via Workload Identity Federation (clicktrack-505800) -# Firefox (AMO) secrets AMO_JWT_ISSUER, AMO_JWT_SECRET -# Microsoft Edge secrets EDGE_PRODUCT_ID, EDGE_CLIENT_ID, EDGE_API_KEY -# A store with no credentials is skipped, not failed. Each store then reviews the upload -# before it reaches users. +# the new version to every store it has credentials for (publish.yml). Each store then +# reviews the upload before it reaches users. on: push: tags: ['v*'] @@ -49,69 +45,12 @@ jobs: GH_TOKEN: ${{ github.token }} run: gh release create "$GITHUB_REF_NAME" release/*.zip --title "SilentBlock ${GITHUB_REF_NAME#v}" --notes-file notes.md - chrome: + publish: needs: build - runs-on: ubuntu-latest - timeout-minutes: 10 + uses: ./.github/workflows/publish.yml + with: + tag: ${{ github.ref_name }} permissions: contents: read id-token: write - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 22 - - id: auth - uses: google-github-actions/auth@v2 - with: - workload_identity_provider: projects/667575805085/locations/global/workloadIdentityPools/github/providers/silentblock - service_account: cws-publisher@clicktrack-505800.iam.gserviceaccount.com - token_format: access_token - access_token_scopes: https://www.googleapis.com/auth/chromewebstore - - name: Download release zips - env: - GH_TOKEN: ${{ github.token }} - run: gh release download "$GITHUB_REF_NAME" --dir release - - name: Submit to the Chrome Web Store - env: - CWS_ACCESS_TOKEN: ${{ steps.auth.outputs.access_token }} - run: node scripts/publish/chrome.mjs - - firefox: - needs: build - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 22 - - name: Download release zips - env: - GH_TOKEN: ${{ github.token }} - run: gh release download "$GITHUB_REF_NAME" --dir release - - name: Submit to addons.mozilla.org - env: - AMO_JWT_ISSUER: ${{ secrets.AMO_JWT_ISSUER }} - AMO_JWT_SECRET: ${{ secrets.AMO_JWT_SECRET }} - run: node scripts/publish/firefox.mjs - - edge: - needs: build - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 22 - - name: Download release zips - env: - GH_TOKEN: ${{ github.token }} - run: gh release download "$GITHUB_REF_NAME" --dir release - - name: Submit to Microsoft Edge Add-ons - env: - EDGE_PRODUCT_ID: ${{ secrets.EDGE_PRODUCT_ID }} - EDGE_CLIENT_ID: ${{ secrets.EDGE_CLIENT_ID }} - EDGE_API_KEY: ${{ secrets.EDGE_API_KEY }} - run: node scripts/publish/edge.mjs + secrets: inherit diff --git a/README.md b/README.md index 227b66c..8add66a 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,10 @@ each store it has credentials for. Every store reviews the upload before users g | Firefox (AMO) | `silentblock@local` | Repo secrets `AMO_JWT_ISSUER`, `AMO_JWT_SECRET` | | Microsoft Edge | `hhdolnhpfeeipbomjfkalbhegkakbkmo` | Repo secrets `EDGE_PRODUCT_ID`, `EDGE_CLIENT_ID`, `EDGE_API_KEY` | -A store with no credentials is skipped. The same scripts run locally: `npm run package`, then +A store with no credentials is skipped. To retry a store, or publish an existing release after +adding credentials, run the Publish workflow by hand: +`gh workflow run publish.yml -f tag=v2.0.1 -f stores=firefox` (stores defaults to all three). +The same scripts run locally: `npm run package`, then `npm run publish:chrome` (signs in through your gcloud login), `publish:firefox` or `publish:edge` with the variables above. `npm run store:status` shows what Chrome has. Listing text and images: `docs/store-listing.md` and `npm run store:art`.