Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 41 additions & 4 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,16 @@ jobs:
actions: read
attestations: read
contents: read
pull-requests: read
outputs:
ready: ${{ steps.gate.outputs.ready }}
releasable: ${{ steps.release-trigger.outputs.releasable }}
source_sha: ${{ steps.release-trigger.outputs.source_sha }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: main
fetch-depth: 0
persist-credentials: false
- id: gate
env:
Expand All @@ -41,6 +46,26 @@ jobs:
fi
OFFICIAL_ALLOW_MISSING_LATEST_TAG=1 bash scripts/check-prior-official-releases.sh
echo 'ready=true' >>"$GITHUB_OUTPUT"
- name: Install pinned Node for release eligibility
if: steps.gate.outputs.ready == 'true'
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24.20.0
- name: Install locked release policy dependencies
if: steps.gate.outputs.ready == 'true'
working-directory: tools/release-please-policy
run: npm ci --ignore-scripts --no-audit --no-fund
- id: release-trigger
name: Check release eligibility without changing release notes
if: steps.gate.outputs.ready == 'true'
env:
GH_TOKEN: ${{ github.token }}
run: |
planned_main="$(git rev-parse HEAD)"
node tools/release-please-policy/harness.mjs --release-trigger
live_main="$(git ls-remote --exit-code origin refs/heads/main | cut -f1)"
[ "$planned_main" = "$live_main" ] || { echo 'main changed during eligibility planning' >&2; exit 1; }
echo "source_sha=$planned_main" >>"$GITHUB_OUTPUT"

release-please:
needs: gate
Expand All @@ -60,8 +85,8 @@ jobs:
sha: ${{ steps.release.outputs.sha }}
html_url: ${{ steps.release.outputs.html_url }}
upload_url: ${{ steps.release.outputs.upload_url }}
pr: ${{ steps.release.outputs.pr }}
prs_created: ${{ steps.release.outputs.prs_created }}
pr: ${{ steps.release-pr.outputs.pr }}
prs_created: ${{ steps.release-pr.outputs.prs_created }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand All @@ -71,10 +96,12 @@ jobs:
- name: Revalidate protected state before reading the App key
env:
GH_TOKEN: ${{ github.token }}
ELIGIBILITY_SOURCE_SHA: ${{ needs.gate.outputs.source_sha }}
run: |
[ "${{ github.ref }}" = refs/heads/main ]
git fetch --no-tags origin main
live_main="$(git rev-parse origin/main)"
[ "$live_main" = "$ELIGIBILITY_SOURCE_SHA" ] || { echo 'main changed after eligibility planning; rerun from main' >&2; exit 1; }
git checkout --detach "$live_main"
[ "$(git rev-parse HEAD)" = "$live_main" ]
[ "${{ vars.OFFICIAL_RELEASES_ENABLED }}" = true ]
Expand Down Expand Up @@ -108,6 +135,16 @@ jobs:
target-branch: main
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
skip-github-pull-request: true
- id: release-pr
if: steps.missing-draft.outputs.created != 'true' && steps.release.outputs.releases_created != 'true' && needs.gate.outputs.releasable == 'true'
uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0
with:
token: ${{ steps.app-token.outputs.token }}
target-branch: main
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
skip-github-release: true
- name: Validate and summarize result
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
Expand All @@ -121,8 +158,8 @@ jobs:
TAG: ${{ steps.release.outputs.tag_name }}
SHA: ${{ steps.release.outputs.sha }}
URL: ${{ steps.release.outputs.html_url }}
PRS_CREATED: ${{ steps.release.outputs.prs_created }}
PR: ${{ steps.release.outputs.pr }}
PRS_CREATED: ${{ steps.release-pr.outputs.prs_created }}
PR: ${{ steps.release-pr.outputs.pr }}
shell: bash
run: |
if [ "$MISSING_CREATED" = true ]; then
Expand Down
13 changes: 10 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,10 +373,17 @@ release:
Breaking changes use `type!:` or a body footer `BREAKING CHANGE: ...`. Before
1.0 that still bumps minor.

These types stay in git history. They do not write release notes and do not
bump the official version by themselves:
These types appear in release notes when an eligible change opens a release,
but do not open a release or bump the official version by themselves:

`refactor`, `docs`, `test`, `build`, `ci`, `chore`
`docs` (Documentation), `build` (Build System), `ci` (Continuous Integration).
The workflow checks release eligibility separately from note visibility using
the pinned Release Please planner. Breaking changes still follow the policy
above. Eligible pending release branches refresh from `main` even when their
notes have not changed.

`refactor`, `test`, and `chore` remain hidden from ordinary release notes and
do not open a release by themselves.

Pick the type from the user-visible behavior, not the files touched. A Web UI
bug that also updates docs is still `fix(webui):`, not `docs:`. A catalog-only
Expand Down
16 changes: 13 additions & 3 deletions docs/release-automation-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,19 @@ feat!: change the provider selection contract
changelog configuration, contributors must use `fix(revert): ...` and the
accepted-type policy must be revised before automation is enabled.
- `!` or `BREAKING CHANGE:` → breaking-version policy.
- `docs`, `test`, `build`, `ci`, `chore`, and `refactor` appear only in the
configured changelog sections and do not independently force a release unless
explicitly configured.
- Ordinary `docs`, `build`, and `ci` changes appear in the configured
changelog sections of an eligible release but do not independently force a
release. A read-only pinned Manifest planner hides those sections only while
deciding PR eligibility; the action retains them in the actual notes.
- Ordinary `test`, `chore`, and `refactor` changes remain hidden and do not
independently force a release.
- Enable `always-update` so an eligible release branch refreshes from `main`
even when the generated notes are unchanged.
- Eligibility suppresses only release PR creation, never the action that tags
an already merged release. A pending merged release is completed before any
new PR is planned. Tag/draft creation and PR creation run in separate action
steps; creating a release skips the PR step even if eligibility was computed
before the release PR merged.
- Dependabot titles such as `build(deps): ...` remain valid.
- Release Please's own `chore(main): release X.Y.Z` title remains valid.
- Treat these effects as policy assertions, not assumptions about Release
Expand Down
13 changes: 13 additions & 0 deletions docs/release-maintainer-runbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,19 @@ campaign is complete.

## 7. Normal Operations

The release worker includes documentation, build, and CI entries in an
eligible release, while a read-only pinned planner prevents those ordinary
changes from opening a release on their own. It runs in the existing gate job
with the read-only workflow token and no protected environment. The protected
job verifies that `main` still matches the eligibility result before minting
the App token. An eligibility error or source drift fails the run; rerun from
`main` after investigating the failure.

The `always-update` setting refreshes eligible release branches even when
their notes are unchanged. Merge release-policy changes through an ordinary
PR before merging the pending release PR, then verify the worker's regenerated
notes and checks. The bot PR's four-file allowlist must remain intact.

To cut an official release, review and merge the Release Please PR. Do not
manually create its tag or publish its draft. Confirm the App-created tag starts
one Release workflow, all four builds pass, the eleven assets verify, and the
Expand Down
10 changes: 8 additions & 2 deletions docs/releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,14 @@ Please reads for changelog type. Use the templates in
- `fix:` and `perf:` request a patch release;
- `feat:` requests a minor release;
- `type!:` or a `BREAKING CHANGE:` footer requests a breaking release; and
- documentation, tests, build, CI, refactors, and chores are normally hidden
from release notes and do not independently request a release.
- documentation, build, and CI changes appear in their own sections when an
eligible change requests a release, but do not independently request one;
- tests, refactors, and chores are normally hidden from release notes and do
not independently request a release.

Release eligibility is checked separately from note visibility. Once a release
is eligible, Release Please refreshes its branch from `main` even when the
notes have not changed.

Before 1.0, this repository deliberately bumps minor for breaking changes.
Maintainers can use the documented `Release-As: X.Y.Z` footer for an exceptional
Expand Down
7 changes: 4 additions & 3 deletions release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@
"bump-minor-pre-major": true,
"draft": true,
"force-tag-creation": true,
"always-update": true,
"changelog-sections": [
{ "type": "feat", "section": "Features" },
{ "type": "fix", "section": "Bug Fixes" },
{ "type": "perf", "section": "Performance Improvements" },
{ "type": "revert", "section": "Reverts" },
{ "type": "refactor", "section": "Code Refactoring", "hidden": true },
{ "type": "docs", "section": "Documentation", "hidden": true },
{ "type": "docs", "section": "Documentation" },
{ "type": "test", "section": "Tests", "hidden": true },
{ "type": "build", "section": "Build System", "hidden": true },
{ "type": "ci", "section": "Continuous Integration", "hidden": true },
{ "type": "build", "section": "Build System" },
{ "type": "ci", "section": "Continuous Integration" },
{ "type": "chore", "section": "Miscellaneous", "hidden": true }
],
"packages": {
Expand Down
14 changes: 9 additions & 5 deletions tools/release-please-policy/SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ Rollup-generated CommonJS bundle, not hidden source. Review on 2026-08-30 found:
- the upstream release contains one entry-point compatibility fix; and
- npm reports a registry signature for the published package.

`release-please` is intentionally a dev dependency used only by the pinned
policy harness. Release, nightly, and recovery workflows install with
`release-please` is intentionally a dev dependency used by the pinned
policy harness and the isolated read-only Release Please eligibility job.
Credential-adjacent release, nightly, and recovery jobs install with
`npm ci --omit=dev --ignore-scripts`, so neither Release Please nor yargs is
installed in credential-adjacent jobs. The all-dependencies harness also uses
`--ignore-scripts` and runs with read-only repository credentials and no
protected environment secret.
installed in credential-adjacent jobs. The all-dependencies harness and
eligibility job use `--ignore-scripts` and run with read-only repository
credentials and no protected environment secret. Eligibility passes only a
boolean and its inspected source SHA to the protected job; it does not pass
dependencies or executable artifacts. The protected job rejects a changed
`main` before minting the App token.

The exact yargs version and integrity are asserted by the offline policy tests.
Changing either requires a new source and supply-chain review.
Expand Down
8 changes: 4 additions & 4 deletions tools/release-please-policy/fixtures/version-policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
{"name": "performance", "message": "perf(codec): reduce scanning allocations", "version": "0.0.2", "section": "Performance Improvements"},
{"name": "revert", "message": "revert: restore the previous retry policy", "version": "0.0.2", "section": "Reverts"},
{"name": "refactor", "message": "refactor: split the transport helper", "version": null, "section": null},
{"name": "documentation", "message": "docs: clarify provider setup", "version": null, "section": null},
{"name": "documentation", "message": "docs: clarify provider setup", "version": null, "section": "Documentation"},
{"name": "test", "message": "test: cover retry exhaustion", "version": null, "section": null},
{"name": "build", "message": "build: update linker flags", "version": null, "section": null},
{"name": "dependabot", "message": "build(deps): bump serde from 1.0.1 to 1.0.2", "version": null, "section": null},
{"name": "ci", "message": "ci: split the Windows job", "version": null, "section": null},
{"name": "build", "message": "build: update linker flags", "version": null, "section": "Build System"},
{"name": "dependabot", "message": "build(deps): bump serde from 1.0.1 to 1.0.2", "version": null, "section": "Build System"},
{"name": "ci", "message": "ci: split the Windows job", "version": null, "section": "Continuous Integration"},
{"name": "chore", "message": "chore: refresh fixtures", "version": null, "section": null},
{"name": "breaking bang", "message": "feat!: change the provider contract", "version": "0.1.0", "section": "Features"},
{"name": "breaking footer", "message": "fix: change the provider contract\n\nBREAKING CHANGE: providers now require an explicit name", "version": "0.1.0", "section": "Bug Fixes"},
Expand Down
Loading
Loading