From fc09551ce0acd160325155db94c2afec61e66e42 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Sat, 22 Aug 2026 21:39:44 +0100 Subject: [PATCH 1/7] ci: Use goreleaser-npm-publisher-action v1.6.0 --- .github/workflows/release.yml | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e3a983a..c5a9a1e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -77,27 +77,20 @@ jobs: - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 with: node-version: 24 # npm >= 11.5.1 required for OIDC trusted publishing - # TODO: switch to goreleaser-npm-publisher-action once https://github.com/evg4b/goreleaser-npm-publisher/pull/26 is released - # Prebuilt dist committed on the fork branch - - name: Fetch goreleaser-npm-publisher - run: | - git clone https://github.com/khvn26/goreleaser-npm-publisher "$RUNNER_TEMP/gnp" - git -C "$RUNNER_TEMP/gnp" checkout ad16d393106b23b6289d0569beefb8e9b3bd3159 - - name: Install goreleaser-npm-publisher runtime dependencies - working-directory: ${{ runner.temp }}/gnp - # set --mode=skip-build to block third-party install/postinstall scripts - run: corepack yarn install --immutable --mode=skip-build - name: Publish npm packages - run: >- - node "$RUNNER_TEMP/gnp/dist/cli.cjs" publish - --name cli - --bin flagsmith - --prefix @flagsmith - --license MIT - --repository 'git+https://github.com/Flagsmith/flagsmith-cli.git' - --description 'The Flagsmith command-line interface' - --keywords flagsmith feature-flags cli - --files README.md LICENSE + uses: evg4b/goreleaser-npm-publisher-action@16087d5aafd974ba267f861cc3723f52ea14d6e4 # v1.6.0 + with: + name: cli + bin: flagsmith + prefix: "@flagsmith" + license: MIT + # npm rejects the provenance attestation unless this matches the + # building repository, case-sensitively. The shorthand is normalised + # to git+https://github.com/Flagsmith/flagsmith-cli.git on publish. + repository: ${{ github.repository }} + description: The Flagsmith command-line interface + keywords: flagsmith feature-flags cli + files: README.md LICENSE install-script: name: install.sh (${{ matrix.os }}) From 772fe5abc4f451aefb52f21fb42f704abe0180b6 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Sat, 22 Aug 2026 22:34:23 +0100 Subject: [PATCH 2/7] ci: Pass array inputs on separate lines --- .github/workflows/release.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c5a9a1e..9045e0f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -89,8 +89,14 @@ jobs: # to git+https://github.com/Flagsmith/flagsmith-cli.git on publish. repository: ${{ github.repository }} description: The Flagsmith command-line interface - keywords: flagsmith feature-flags cli - files: README.md LICENSE + # stringArray inputs are split on newlines, not spaces + keywords: |- + flagsmith + feature-flags + cli + files: |- + README.md + LICENSE install-script: name: install.sh (${{ matrix.os }}) From 4c8e5e300bb9e4204a123c2bd5da87a82cd87fa8 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Sun, 23 Aug 2026 01:16:00 +0100 Subject: [PATCH 3/7] deslop --- .github/workflows/release.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9045e0f..ac79bfb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,9 +23,6 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - # Empty on a tag push, where the triggering ref is already the tag. - # Dispatched runs are privileged, so the input can only name a tag, - # never a branch or a pull request. ref: ${{ inputs.tag && format('refs/tags/{0}', inputs.tag) || '' }} fetch-depth: 0 persist-credentials: false @@ -55,11 +52,6 @@ jobs: - uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3 with: version: "~> v2" - # A dispatched run only needs dist/ populated so the npm packages can - # be assembled from it, so it rebuilds the tag's binaries and archives - # nothing. Those binaries won't be byte-identical to the ones already - # released - go.mod asks for Go 1.26, so setup-go resolves whatever - # patch is current - which is why nothing else is republished here. args: ${{ github.event_name == 'workflow_dispatch' && 'build --clean' || 'release --clean' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -84,12 +76,8 @@ jobs: bin: flagsmith prefix: "@flagsmith" license: MIT - # npm rejects the provenance attestation unless this matches the - # building repository, case-sensitively. The shorthand is normalised - # to git+https://github.com/Flagsmith/flagsmith-cli.git on publish. repository: ${{ github.repository }} description: The Flagsmith command-line interface - # stringArray inputs are split on newlines, not spaces keywords: |- flagsmith feature-flags From 69b3c84a5dd3e4eda46632ed6847c8e6a4372ba2 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Sun, 23 Aug 2026 01:17:17 +0100 Subject: [PATCH 4/7] improve docs --- .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 ac79bfb..5a9e579 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: permissions: contents: write # upload release artifacts packages: write # push to ghcr.io - id-token: write # attest artifacts + id-token: write # attest artifacts, npm trusted publishing attestations: write steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 From 252e2ee4348231205cd42cbb25e9d12cf77e82b3 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Sun, 23 Aug 2026 01:29:31 +0100 Subject: [PATCH 5/7] ci: Make workflow_dispatch redo the whole release --- .github/workflows/release.yml | 33 +++++++++++++++++++-------------- .goreleaser.yaml | 1 + 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5a9e579..d5fc271 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,6 +12,11 @@ on: permissions: contents: read +# Never release the same tag twice at once: a dispatch while the tag push is +# still in flight would race for the same release and artifacts. +concurrency: + group: release-${{ inputs.tag || github.ref_name }} + jobs: goreleaser: runs-on: ubuntu-latest @@ -29,16 +34,13 @@ jobs: - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version-file: go.mod - - if: github.event_name == 'push' - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 - - if: github.event_name == 'push' - uses: docker/login-action@371161bbe7024a29a25c5e19bfcbc0804fe9ad2c # v4.5.2 + - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 + - uses: docker/login-action@371161bbe7024a29a25c5e19bfcbc0804fe9ad2c # v4.5.2 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Generate GitHub App token - if: github.event_name == 'push' id: app-token uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 with: @@ -52,17 +54,15 @@ jobs: - uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3 with: version: "~> v2" - args: ${{ github.event_name == 'workflow_dispatch' && 'build --clean' || 'release --clean' }} + args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} HOMEBREW_TAP_GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} # Attests every file listed in the checksum file. - - if: github.event_name == 'push' - uses: actions/attest@508db95dd578ae2727ebd6217d5ba78e4fbda05d # v4.2.1 + - uses: actions/attest@508db95dd578ae2727ebd6217d5ba78e4fbda05d # v4.2.1 with: subject-checksums: ./dist/checksums.txt - - if: github.event_name == 'push' - uses: actions/attest@508db95dd578ae2727ebd6217d5ba78e4fbda05d # v4.2.1 + - uses: actions/attest@508db95dd578ae2727ebd6217d5ba78e4fbda05d # v4.2.1 with: subject-checksums: ./dist/digests.txt @@ -70,6 +70,7 @@ jobs: with: node-version: 24 # npm >= 11.5.1 required for OIDC trusted publishing - name: Publish npm packages + continue-on-error: ${{ github.event_name == 'workflow_dispatch' }} uses: evg4b/goreleaser-npm-publisher-action@16087d5aafd974ba267f861cc3723f52ea14d6e4 # v1.6.0 with: name: cli @@ -89,7 +90,6 @@ jobs: install-script: name: install.sh (${{ matrix.os }}) needs: goreleaser - if: github.event_name == 'push' strategy: fail-fast: false matrix: @@ -98,20 +98,25 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + ref: ${{ inputs.tag && format('refs/tags/{0}', inputs.tag) || '' }} persist-credentials: false - - run: sh install.sh --version "$GITHUB_REF_NAME" --bin-dir "$RUNNER_TEMP/bin" + - run: sh install.sh --version "$TAG" --bin-dir "$RUNNER_TEMP/bin" + env: + TAG: ${{ inputs.tag || github.ref_name }} - run: flagsmith --version install-script-windows: name: install.ps1 needs: goreleaser - if: github.event_name == 'push' runs-on: windows-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + ref: ${{ inputs.tag && format('refs/tags/{0}', inputs.tag) || '' }} persist-credentials: false - - run: ./install.ps1 -Version $env:GITHUB_REF_NAME + - run: ./install.ps1 -Version $env:TAG shell: pwsh + env: + TAG: ${{ inputs.tag || github.ref_name }} - run: flagsmith --version shell: pwsh diff --git a/.goreleaser.yaml b/.goreleaser.yaml index e2f7817..1230880 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -89,3 +89,4 @@ changelog: release: mode: keep-existing prerelease: auto + replace_existing_artifacts: true From 03cbcc1e50626258f4a6f2e8523e5ecaece4de17 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Mon, 24 Aug 2026 11:30:16 +0100 Subject: [PATCH 6/7] ci: Verify install scripts against the dispatched tag --- .github/workflows/release.yml | 46 ++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d5fc271..64ab24c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,6 +3,10 @@ name: Release on: push: tags: ["v*"] + + # Dispatch the release workflow for an old tag. + # Useful to backfill previous releases when adding a new publiser, + # or to retry a publisher having fixed a bug in one. workflow_dispatch: inputs: tag: @@ -87,36 +91,34 @@ jobs: README.md LICENSE - install-script: - name: install.sh (${{ matrix.os }}) + install-script-e2e: + name: install (${{ matrix.os }}, ${{ matrix.ref && 'tag' || 'head' }}) needs: goreleaser strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-latest, windows-latest] + # When release is dispatched, test both pinned and latest installers. + # For a normal (tag-pushed) release, test only latest installer. + ref: ${{ fromJSON(inputs.tag && format('["", "refs/tags/{0}"]', inputs.tag) || '[""]') }} runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - ref: ${{ inputs.tag && format('refs/tags/{0}', inputs.tag) || '' }} - persist-credentials: false - - run: sh install.sh --version "$TAG" --bin-dir "$RUNNER_TEMP/bin" - env: - TAG: ${{ inputs.tag || github.ref_name }} - - run: flagsmith --version - - install-script-windows: - name: install.ps1 - needs: goreleaser - runs-on: windows-latest - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ inputs.tag && format('refs/tags/{0}', inputs.tag) || '' }} + ref: ${{ matrix.ref }} persist-credentials: false - - run: ./install.ps1 -Version $env:TAG + - name: Install latest (Linux) + if: ${{ !inputs.tag && runner.os != 'Windows' }} + run: sh install.sh + - name: Install dispatched (Linux) + if: ${{ inputs.tag && runner.os != 'Windows' }} + run: sh install.sh --version "${{ inputs.tag }}" + - name: Install latest (Windows) + if: ${{ !inputs.tag && runner.os == 'Windows' }} + run: ./install.ps1 shell: pwsh - env: - TAG: ${{ inputs.tag || github.ref_name }} - - run: flagsmith --version + - name: Install dispatched (Windows) + if: ${{ inputs.tag && runner.os == 'Windows' }} + run: ./install.ps1 -Version "${{ inputs.tag }}" shell: pwsh + - run: flagsmith --version From e435f818903c0914143034ed86e54cdc0c8f5dd9 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Mon, 24 Aug 2026 12:32:15 +0100 Subject: [PATCH 7/7] deslop Co-authored-by: Matthew Elwell --- .github/workflows/release.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 64ab24c..cb2aaa5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,8 +16,6 @@ on: permissions: contents: read -# Never release the same tag twice at once: a dispatch while the tag push is -# still in flight would race for the same release and artifacts. concurrency: group: release-${{ inputs.tag || github.ref_name }}