From ad1bf6ea45e1d06c8b383c9e056731178b591217 Mon Sep 17 00:00:00 2001 From: Felipe Zipitria Date: Sun, 6 Sep 2026 20:48:07 -0300 Subject: [PATCH 1/6] ci: add release-please workflow Automate version bumps, changelog generation, and release PRs with release-please. Uses a GitHub App token (RELEASE_PLEASE_CLIENT_ID / RELEASE_PLEASE_APP_PRIVATE_KEY) instead of GITHUB_TOKEN so the release tag it creates triggers the existing tag-triggered goreleaser workflow. release-type is "go" so a future major bump can update the /v2 module path, and skip-github-release leaves goreleaser as the sole creator of the GitHub Release itself. --- .github/.release-please-manifest.json | 3 ++ .github/release-please-config.json | 9 ++++++ .github/workflows/release-please.yml | 45 +++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 .github/.release-please-manifest.json create mode 100644 .github/release-please-config.json create mode 100644 .github/workflows/release-please.yml diff --git a/.github/.release-please-manifest.json b/.github/.release-please-manifest.json new file mode 100644 index 0000000..f393718 --- /dev/null +++ b/.github/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "2.10.0" +} diff --git a/.github/release-please-config.json b/.github/release-please-config.json new file mode 100644 index 0000000..e0a6d13 --- /dev/null +++ b/.github/release-please-config.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "release-type": "go", + "include-v-in-tag": true, + "skip-github-release": true, + "packages": { + ".": {} + } +} diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 0000000..f3dbb11 --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,45 @@ +name: release-please + +# default token permissions: none +permissions: {} + +on: + push: + branches: + - main + workflow_dispatch: + inputs: + dry-run: + description: "Dry run — preview the release PR without creating or modifying anything" + type: boolean + default: false + +jobs: + release-please: + runs-on: ubuntu-latest + permissions: + contents: write # create the release PR, changelog commit and tag + pull-requests: write # open and update the release PR + issues: write # label the release PR + + steps: + # GITHUB_TOKEN-authored pushes never trigger other workflows, so a tag + # created with it would not fire the tag-triggered goreleaser workflow. + # RELEASE_PLEASE_CLIENT_ID/_APP_PRIVATE_KEY currently hold the same + # GitHub App credentials as HOMEBREW_APP_ID/_PRIVATE_KEY. client-id (not + # app-id): create-github-app-token deprecated app-id in favor of it. + - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # ratchet:actions/create-github-app-token@v3.2.0 + id: app-token + with: + client-id: ${{ secrets.RELEASE_PLEASE_CLIENT_ID }} + private-key: ${{ secrets.RELEASE_PLEASE_APP_PRIVATE_KEY }} + permission-contents: write + permission-pull-requests: write + permission-issues: write + + - uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # ratchet:googleapis/release-please-action@v5.0.0 + with: + token: ${{ steps.app-token.outputs.token }} + config-file: .github/release-please-config.json + manifest-file: .github/.release-please-manifest.json + skip-github-pull-request: ${{ inputs.dry-run == true }} From ec44e75fed6b34aa61f148fbe5dc645994dfe39e Mon Sep 17 00:00:00 2001 From: Felipe Zipitria Date: Mon, 7 Sep 2026 08:37:33 -0300 Subject: [PATCH 2/6] ci(release-please): address review feedback - Set include-component-in-tag: false explicitly. Currently a no-op (no package-name/component is configured, so the tag is already plain v), but makes the intent explicit and guards against a future package-name addition silently prefixing tags, which would break the tag-triggered goreleaser workflow. - Split the workflow_dispatch dry-run path off the real run: the pinned release-please-action now only runs for real (non-dry-run) triggers. Dry-run instead runs the release-please CLI's --dry-run directly, which only makes read-only GitHub API calls, so it uses the default GITHUB_TOKEN rather than minting the write-scoped App token. Co-Authored-By: Claude Sonnet 5 --- .github/release-please-config.json | 1 + .github/workflows/release-please.yml | 31 ++++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/.github/release-please-config.json b/.github/release-please-config.json index e0a6d13..122eb86 100644 --- a/.github/release-please-config.json +++ b/.github/release-please-config.json @@ -2,6 +2,7 @@ "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", "release-type": "go", "include-v-in-tag": true, + "include-component-in-tag": false, "skip-github-release": true, "packages": { ".": {} diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index f3dbb11..aca474f 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -18,9 +18,9 @@ jobs: release-please: runs-on: ubuntu-latest permissions: - contents: write # create the release PR, changelog commit and tag - pull-requests: write # open and update the release PR - issues: write # label the release PR + contents: write # create the release PR, changelog commit and tag + pull-requests: write # open and update the release PR + issues: write # label the release PR steps: # GITHUB_TOKEN-authored pushes never trigger other workflows, so a tag @@ -38,8 +38,31 @@ jobs: permission-issues: write - uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # ratchet:googleapis/release-please-action@v5.0.0 + if: inputs.dry-run != true with: token: ${{ steps.app-token.outputs.token }} config-file: .github/release-please-config.json manifest-file: .github/.release-please-manifest.json - skip-github-pull-request: ${{ inputs.dry-run == true }} + + # A real preview: the release-please CLI's --dry-run reports what would + # happen via read-only GitHub API calls, no PR or tag is ever created, + # so it runs on the default GITHUB_TOKEN instead of the write-scoped App + # token above. + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # ratchet:actions/setup-node@v6.0.0 + if: inputs.dry-run == true + with: + node-version: "22" + package-manager-cache: false + + - name: Preview release PR + if: inputs.dry-run == true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO_URL: ${{ github.repository }} + run: | + npx --yes release-please@17.11.2 release-pr \ + --token="${GITHUB_TOKEN}" \ + --repo-url="${REPO_URL}" \ + --config-file=.github/release-please-config.json \ + --manifest-file=.github/.release-please-manifest.json \ + --dry-run From 03144d6d8bfacade195d86d71a2b6af7633910c6 Mon Sep 17 00:00:00 2001 From: Felipe Zipitria Date: Mon, 7 Sep 2026 09:22:00 -0300 Subject: [PATCH 3/6] ci(release-please): tighten dry-run permissions and versions - Job permissions dropped to read-only (contents/pull-requests/issues). The real release path's writes go through the separately-scoped App token via its own permission-* inputs, not the job's GITHUB_TOKEN; GITHUB_TOKEN is only used by the dry-run preview, which only reads. - Gate the App-token step to real runs only (inputs.dry-run != true): the preview never uses it, so skip minting a write-scoped token when it would go unused. - Pin the dry-run CLI to release-please@17.6.0, the exact version googleapis/release-please-action@v5.0.0 bundles, so the preview reflects what the real run would actually compute. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/release-please.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index aca474f..00ab6ef 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -17,10 +17,14 @@ on: jobs: release-please: runs-on: ubuntu-latest + # The real release path's writes (PR, changelog commit, tag) go through + # the separately-scoped App token below, not this job's GITHUB_TOKEN -- + # the only thing GITHUB_TOKEN is used for here is the read-only dry-run + # preview, so it needs no write access. permissions: - contents: write # create the release PR, changelog commit and tag - pull-requests: write # open and update the release PR - issues: write # label the release PR + contents: read + pull-requests: read + issues: read steps: # GITHUB_TOKEN-authored pushes never trigger other workflows, so a tag @@ -28,8 +32,10 @@ jobs: # RELEASE_PLEASE_CLIENT_ID/_APP_PRIVATE_KEY currently hold the same # GitHub App credentials as HOMEBREW_APP_ID/_PRIVATE_KEY. client-id (not # app-id): create-github-app-token deprecated app-id in favor of it. + # Skipped for dry-run: the preview below never uses it. - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # ratchet:actions/create-github-app-token@v3.2.0 id: app-token + if: inputs.dry-run != true with: client-id: ${{ secrets.RELEASE_PLEASE_CLIENT_ID }} private-key: ${{ secrets.RELEASE_PLEASE_APP_PRIVATE_KEY }} @@ -60,7 +66,9 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO_URL: ${{ github.repository }} run: | - npx --yes release-please@17.11.2 release-pr \ + # Pinned to the exact release-please version googleapis/release-please-action@v5.0.0 + # bundles, so the preview matches what the real run above would compute. + npx --yes release-please@17.6.0 release-pr \ --token="${GITHUB_TOKEN}" \ --repo-url="${REPO_URL}" \ --config-file=.github/release-please-config.json \ From 1ace53a2366121b43decf373cb26b58244f1c4ad Mon Sep 17 00:00:00 2001 From: Felipe Zipitria Date: Mon, 7 Sep 2026 18:53:24 -0300 Subject: [PATCH 4/6] ci(release-please): align release-type to simple "go" has no effect over "simple" here: its only extra behavior is an optional version-file updater we don't configure, so it changes nothing for this repo. Matches go-ftw's config (coreruleset/go-ftw#668). --- .github/release-please-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/release-please-config.json b/.github/release-please-config.json index 122eb86..ff08933 100644 --- a/.github/release-please-config.json +++ b/.github/release-please-config.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", - "release-type": "go", + "release-type": "simple", "include-v-in-tag": true, "include-component-in-tag": false, "skip-github-release": true, From bbb9ca2ea2412a3b88a7e3255f764b61d5e45d5d Mon Sep 17 00:00:00 2001 From: Felipe Zipitria Date: Tue, 8 Sep 2026 11:02:16 -0300 Subject: [PATCH 5/6] ci(release-please): create the release (and its tag) after all skip-github-release skips manifest.createReleases() entirely, and that's the only place a release-please tag gets created -- the git tag is a side effect of the GitHub "create release" API call, not a separate step. With it set, release-please would merge the version PR but never push the v* tag the goreleaser workflow triggers on. Removing it does not create a conflict with goreleaser: when the tag's release already exists (created by release-please), goreleaser's default createOrUpdateRelease finds it and updates it in place with the built artifacts, rather than failing. --- .github/release-please-config.json | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/release-please-config.json b/.github/release-please-config.json index ff08933..9250db9 100644 --- a/.github/release-please-config.json +++ b/.github/release-please-config.json @@ -3,7 +3,6 @@ "release-type": "simple", "include-v-in-tag": true, "include-component-in-tag": false, - "skip-github-release": true, "packages": { ".": {} } From 7e2ad9c687344feeaf24d0c5ec793c2d834e61a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Zipitr=C3=ADa?= <3012076+fzipi@users.noreply.github.com> Date: Thu, 24 Sep 2026 08:17:51 -0300 Subject: [PATCH 6/6] Apply suggestion from @fzipi --- .github/workflows/release-please.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 00ab6ef..f557b37 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -57,7 +57,7 @@ jobs: - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # ratchet:actions/setup-node@v6.0.0 if: inputs.dry-run == true with: - node-version: "22" + node-version: "24" package-manager-cache: false - name: Preview release PR