Skip to content

fix(release): find the last release by a marker tag on main - #620

Merged
Vivswan merged 6 commits into
mainfrom
fix/release-marker-tag
Nov 13, 2026
Merged

Vivswan merged 6 commits into
mainfrom
fix/release-marker-tag

Conversation

@Vivswan

@Vivswan Vivswan commented Nov 12, 2026 •

Copy link
Copy Markdown
Owner

Before

main:   A -- B -- M (release 3.0.0) -- C
                   \
                    P   <- v3.0.0, v3, latest   (the packaged commit; what users pin)

release-please looks up v3.0.0, gets P, walks main, and never meets P.
So last-release-sha tells it where to stop, a hook job stamps that value
inside every release PR, and two checks police it.

After

main:   A -- B -- M (release 3.0.1) -- C
                  ^ \
     source-v3.0.1   P   <- v3.0.1, v3, latest   (unchanged for users)

release-please names its own tag source-vX.Y.Z and creates it on the release merge.
It finds its previous release by that tag.
deleted
  last-release-sha                     release-please-config.json
  anchor.ts, 269 lines                 the stamp and the code of both checks
  job anchor                           update-release-pr.yml
  jobs boundary-check, anchor-check    checks.yml
  24 test titles                       the tests of the three above

How

  • Config: the tag carries component source, tag creation is forced, the title pattern stays.
  • Parse: resolve-source turns the handed source-vX.Y.Z into vX.Y.Z once, refusing any other name and a published release.
  • Marker check: package holds the marker to the release merge before any push and names the repair.
  • Rename: rename-draft gives the draft vX.Y.Z as tag and title, still a draft, after the mint.
  • Ruleset: source-tags freezes source-v*, with an admin bypass.

Proof

  • Red, then green: 15 new cases fail on main's behavior for their titles' reasons and pass here.
  • Targeted tests: bun test test/scripts test/workflows: 644 pass, 0 fail.
  • Census: the six deleted names appear nowhere outside CHANGELOG.md.
Technical details

Migration

State when this was written: main at 2982e7ea, manifest 3.0.0, release PR #587 open, no source-v* tag on origin.

0  WAIT     the platform sync PR (publish by release id) is merged here
1  PUSH     the marker for the manifest's version, on its release merge:
              git push origin f2b96b13c0a5be9e7e9fed78beddb835a2a06af4:refs/tags/source-v3.0.0
            read back:
              git ls-remote origin refs/tags/source-v3.0.0
              f2b96b13c0a5be9e7e9fed78beddb835a2a06af4	refs/tags/source-v3.0.0
2  DRY RUN  optional and read-only: the command under "Dry run", against this branch
3  FREEZE   merge no release PR from step 1 until step 5 is done
4  MERGE    this PR; its own main run is release-please's first run on the new config
5  CLOSE    #587 without merging, then delete its branch release-please--branches--main
6  RELEASE  approve the NEW release PR's run; merge it once release-please has rebuilt it for the newest fix or feat
  • The rule behind step 1: the marker is source-v<version> for the version in .release-please-manifest.json on main, on the commit titled chore(main): release <version> (#N).
  • The other order: if chore(main): release 3.0.1 #587 were merged first, the marker is source-v3.0.1 on that merge commit, pushed the same way.
  • Then main is merged into this branch, keeping this config.

What must never happen

State Result
The new config on main with no marker for the manifest's version release-please walks the whole history and opens a PR that lists released commits with a wrong bump. No error.
A release PR built under the old config (#587, or any PR on release-please--branches--main) merged after this PR No release is cut, the PR keeps autorelease: pending, and later release runs abort.
A marker moved to a packaged commit or to another merge The next changelog repeats or loses commits, with no error. The hook checks only the marker of the release it is cutting. The source-tags ruleset holds the older ones.
The draft renamed or published by hand before package minted vX.Y.Z GitHub creates vX.Y.Z on main, at the draft's target.

First run after the merge

The release job's log, in release-please 17.6.0's wording:

WARN Found release tag with component '', but not configured in manifest     one per published vX.Y.Z release
WARN Expected 1 releases, only found 0
WARN Missing 1 paths: .
     looking for tagName: source-v3.0.0
     found: source-v3.0.0 f2b96b13c0a5be9e7e9fed78beddb835a2a06af4
     Splitting <n> commits by path
WARN pullRequestTitlePattern miss the part of '${component}'                   the cost of keeping the title

gone   Using configured lastReleaseSha
       Expected 1 commits, only found 0
       No latest release pull request found.

then   a NEW pull request "chore(main): release 3.0.1"
       branch    release-please--branches--main--components--source
       heading   compare/source-v3.0.0...source-v3.0.1
       commits   the ones #587 lists, plus this PR's fix
       npm       update-release-pr publishes one `next` for it

wrong  no "found:" line, or a title that is not 3.0.1 above the whole history
       -> the marker is missing or misplaced: close that PR, repair the tag, rerun the release job

When that release PR merges:

release          draft named source-v3.0.1, tag source-v3.0.1 created on the release merge
update-release   package:       created v3.0.1 on packaged commit <sha>; ...
                 rename-draft:  release source-v3.0.1 now carries tag v3.0.1 and title v3.0.1
publish-release  publishes release v3.0.1, found by its id
tags             source-v3.0.1 -> the release merge on main
                 v3.0.1, v3, latest -> the packaged commit

What the hook prints for a release it will not take

resolve-source, handed source-v3.0.1
  a draft                   exit 0   writes sha=<merge sha> and tag=v3.0.1, prints nothing
  a published release       exit 1   ::error::release source-v3.0.1 is published, not a draft: users already see the marker's name as a release, so nothing is packaged from it.
                                     Fix release-please-config.json by PR: "draft": true on package ".".
  no release by that name   exit 1   ::error::no release is named source-v3.0.1.
                                     If the release v3.0.1 exists, the hook already renamed the draft and this job is done: do not re-run it.
  • No release by that name is what a job re-run after the rename meets.
  • No fallback: the hook never proceeds as vX.Y.Z when source-vX.Y.Z is gone.

Dry run

npx --yes release-please@17.6.0 release-pr --dry-run --debug \
  --repo-url=Vivswan/github-settings-as-code \
  --target-branch=fix/release-marker-tag \
  --token=<a READ-ONLY token>
  • Run it after step 1. Without the marker it prints the whole-history pull request.
  • Use a read-only token. --dry-run only builds and prints the pull request, and the token keeps safety off one flag.
  • Never add --local --local-path in a working checkout. It runs git reset --hard origin/main there.
  • Title and branch in its output carry fix/release-marker-tag in place of main.
  • It proves the propose side only: the marker is found, the walk stops there, the commit list, the compare link.
  • Run for this PR, after step 1: it found the marker and proposed one pull request for 3.0.1.
looking for tagName: source-v3.0.0
found: source-v3.0.0 f2b96b13c0a5be9e7e9fed78beddb835a2a06af4
Would open 1 pull requests
## [3.0.1](.../compare/source-v3.0.0...source-v3.0.1)
24 entries: the 20 fixes since 3.0.0, and this branch's 4 commits (one entry after the squash merge)

What changes besides the mechanism

Thing Before After
Compare links in the changelog and release notes compare/v3.0.0...v3.0.1 compare/source-v3.0.0...source-v3.0.1
Tags a user can see v*, latest, build/* plus source-vX.Y.Z, which is not a pin
Release PR branch release-please--branches--main release-please--branches--main--components--source
release-please's comment on the release PR names vX.Y.Z names source-vX.Y.Z
A fix that lands after the release PR's notes were built, merged without a rebuild the release was parked it ships in that release and appears in no changelog

Line accounting

Kind Deleted Added
Scripts 322 146
Workflows 82 41
Tests 600 257
Config 3 28
Docs 2 11
Rendered by the sync 1 17
Total 1010 500
  • Deleted test titles, each with its subject: test/scripts/release-pipeline.test.ts 21, test/workflows/checks-workflow.test.ts 3 (the whole file).
  • Deleted table row: test/workflows/post-green-workflow.test.ts 1, the anchor job's grant control.
  • Census: git grep -n 'last-release-sha\|anchor-check\|boundary-check\|anchorCheck\|boundaryCheck\|anchorReleasePr' -- . ':!CHANGELOG.md' prints nothing.

The config contract test

  • Main's test asserted three keys of release-please-config.json.
  • The rewritten test holds the release's name alone.
Main asserted Held now by
draft: true resolve-source refuses a published release. One test, with a draft passing beside it.
force-tag-creation: false The reverse is required now. package refuses a missing marker and names the push that creates it.
skip-github-release: false Not pinned here: when the cut makes no release the hook never runs.

Files

  • release-please-config.json: include-component-in-tag on, component, the title pattern, force-tag-creation on, last-release-sha gone.
  • .github/scripts/release-pipeline/anchor.ts: deleted.
  • .github/scripts/release-pipeline.ts: three subcommands gone, rename-draft added, resolve-source writes tag.
  • .github/scripts/release-pipeline/{draft.ts,tags.ts}: the parse, the draft check, the marker check, the rename.
  • .github/scripts/release-pipeline/npm.ts: unchanged, it is handed vX.Y.Z.
  • .github/workflows/update-release.yml: steps take vX.Y.Z from resolve-source, the rename is the last step of verify-release.
  • .github/workflows/update-release-pr.yml: the anchor job and its comment lines gone, both inputs described as read by no job, publish-next untouched.
  • .github/workflows/checks.yml: boundary-check and anchor-check gone.
  • .github/settings.local.yml: ruleset source-tags.
  • test/workflows/{checks-workflow.test.ts,head-ref.ts}: deleted.
  • test/scripts/release-pipeline{.test.ts,-fixture.ts,-build.test.ts}, test/workflows/{post-green-workflow.test.ts,workflow-loader.ts}: the tests above.
  • AGENTS.md, CONTRIBUTING.md, README.md: the marker rule.

Gates

  • bun run typecheck, lint, lint:arch, knip, check:compat, build:check, check:headers: exit 0.
  • actionlint on the three changed workflows: exit 0.
  • git diff --stat origin/main...HEAD -- src prints nothing.

Recorded, not built

  • A gate that the marker exists before release-please proposes: out of scope, and step 1 covers the one known case.
  • A rerun of package-release after the rename does not converge: resolve-source stops it, saying no release is named source-vX.Y.Z.
  • A rerun of verify-release alone after the rename still fails with gh's release not found, at verify-assets.
  • The hand finish for a dead run is in the workflow header.
  • A warning for a late commit in a release PR merged without a rebuild: accepted, and CONTRIBUTING.md states the rule.
  • A check of earlier releases' markers before release-please proposes: an admin moving one is outside this change.

release-please names its own tag source-vX.Y.Z, creates it on the release
merge on main, and finds its previous release by it. The release hook
parses the handed name into vX.Y.Z once, holds the marker to the merge
commit before it mints anything, and last gives the draft vX.Y.Z as its
tag and title.

last-release-sha, the hook job that stamped it, and the two checks that
judged it are deleted.
Copilot AI balanced review requested due to automatic review settings November 12, 2026 23:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Human confirmation of release-ID platform synchronization, initial marker placement, and ruleset deployment is needed because current publishers still reference the original tag that the hook renames.

No open issues 🎉

What changed in this PR

Replaces the manually maintained release boundary with source-vX.Y.Z tags on main, allowing release-please to find previous releases while keeping consumer tags on packaged commits.

Changes:

  • Enables source marker tags and removes the anchor script, jobs, and checks.
  • Parses and validates markers, then renames packaged draft releases to vX.Y.Z.
  • Declares marker protection and updates tests and release documentation.

Migration requires the publish-by-release-ID platform sync and initial marker tag before merging.

File Description
test/​workflows/​workflow-loader.ts Makes the workflow text helper private.
test/​workflows/​post-green-workflow.test.ts Updates permission and wiring checks for marker-based releases.
test/​workflows/​head-ref.ts Removes the obsolete release-branch condition helper.
test/​workflows/​checks-workflow.test.ts Removes tests for the deleted anchor check.
test/​scripts/​release-pipeline.test.ts Replaces anchor tests with marker validation and draft-renaming cases.
test/​scripts/​release-pipeline-fixture.ts Seeds release markers and removes anchor-specific helpers.
test/​scripts/​release-pipeline-build.test.ts Adds a marker to the later-release fixture.
release-please-config.json Enables source-component tags and removes the manual boundary.
README.md Explains why source markers are not runnable action pins.
CONTRIBUTING.md Documents marker-based releases and release-PR refresh requirements.
AGENTS.md Distinguishes source markers from packaged consumer refs.
.github/​workflows/​update-release.yml Passes resolved version tags downstream and renames the draft.
.github/​workflows/​update-release-pr.yml Removes the anchor job, retaining npm prerelease publication.
.github/​workflows/​checks.yml Removes boundary and anchor checks.
.github/​settings.local.yml Declares marker-tag protection with an admin repair bypass.
.github/​scripts/​release-pipeline/​tags.ts Parses marker names and verifies their targets before release pushes.
.github/​scripts/​release-pipeline/​draft.ts Resolves version tags and adds draft renaming.
.github/​scripts/​release-pipeline/​anchor.ts Deletes the manual release-boundary implementation.
.github/​scripts/​release-pipeline.ts Replaces anchor commands with marker-aware draft handling.

Review effort: Balanced

@Vivswan Vivswan added the repo-platform:sync Sync this pull request's branch from repo-platform (the workflow removes the label) label Nov 12, 2026
@github-actions github-actions Bot removed the repo-platform:sync Sync this pull request's branch from repo-platform (the workflow removes the label) label Nov 12, 2026
@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Build 0bfaaa6e1f528c1d99c4b41b8e0d84461bc9fb78 NOT pushed: the sync changes .github/workflows/ci.yml, and the repository token cannot create or update a workflow file (run).
The owner's dispatch of sync-repos.yml in Vivswan/repo-platform with repo=<owner>/<name> and branch=fix/release-marker-tag pushes the same commit with the fleet token.

Sync report

Build Modules Visibility
0bfaaa6e1f528c1d99c4b41b8e0d84461bc9fb78 bun, site, release-please, pr-title, fuzzer, nightly public

Written

Path Class Change Detail
.editorconfig split unchanged
.gitattributes split unchanged
.gitignore split unchanged
.github/CODEOWNERS split unchanged
.github/dependabot.yml managed unchanged
.github/actionlint.yaml starter unchanged
.github/instructions/review.instructions.md managed unchanged
.github/settings.local.yml starter unchanged
.github/settings.yml managed unchanged
.github/workflows/ci.yml managed updated
.github/workflows/checks.yml starter unchanged
.github/workflows/post-green.yml starter unchanged
.github/workflows/release-gate.yml starter unchanged
.github/workflows/update-release.yml starter unchanged
.github/workflows/update-release-pr.yml starter unchanged
.github/actions/site-build/action.yml starter unchanged
.github/workflows/copilot-setup-steps.yml starter unchanged
.gitleaks.toml starter unchanged
.yamllint managed unchanged
.github/workflows/auto-assign.yml managed unchanged
.github/workflows/sync-branch.yml managed unchanged
.github/workflows/auto-format.yml starter unchanged
.typography-allow managed unchanged
AGENTS.md split unchanged
LICENSE.md split unchanged
.bun-version managed unchanged
biome.json managed unchanged
biome.local.jsonc starter unchanged
.release-please-manifest.json starter unchanged
release-please-config.json starter unchanged
.github/workflows/pr-title.yml managed unchanged
.github/workflows/nightly-fuzz.yml starter unchanged
.github/workflows/nightly.yml starter unchanged

Mirrors

Source Target Outcome Detail
AGENTS.md CLAUDE.md current
AGENTS.md .github/agents.md current
AGENTS.md .github/copilot-instructions.md current

Review

Hold for review: no

Copilot AI balanced review requested due to automatic review settings November 12, 2026 23:30

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The hook renames a tag still referenced by CI and the fetched stable publisher, so publish-by-ID deployment and the source-marker migration require coordinated human verification.

No open issues 🎉

Review effort: Balanced

…, and log the rename

- resolve-source reads the handed release's draft state and refuses a published one, naming the config key that hands the hook a draft.
- resolve-source says in its own words when no release carries the handed name, as after the hook's rename, and points at the renamed release.
- rename-draft prints the old name and the new one on success.
- The pipeline header and the packageRelease comment fit their caps, and the header no longer says the marker is the only tag on main.
- The input descriptions in update-release-pr.yml and the hook order in CONTRIBUTING.md say what the workflows do.
- The two rename-draft rows that repeated the shared "must be set" message are deleted.
Copilot AI balanced review requested due to automatic review settings November 12, 2026 23:56

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The release migration requires confirming that platform synchronization preserves release identity across tag renaming and that the initial source marker is correctly placed, while the checked-in caller still passes a tag.

No open issues 🎉

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings November 13, 2026 00:04

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The hook renames tags still used by the stable publisher, so merging requires a coordinated publish-by-ID rollout, verification of the manifest-version source marker on main, and closure of the old-config release PR.

No open issues 🎉

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings November 13, 2026 00:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The hook renames tags still used by the stable publisher, requiring coordinated rollout and human confirmation of release-ID publishing deployment, migration marker placement, and closure of the old release PR.

No open issues 🎉

Review effort: Balanced

@Vivswan Vivswan added the repo-platform:sync Sync this pull request's branch from repo-platform (the workflow removes the label) label Nov 13, 2026
@github-actions github-actions Bot removed the repo-platform:sync Sync this pull request's branch from repo-platform (the workflow removes the label) label Nov 13, 2026
Copilot AI balanced review requested due to automatic review settings November 13, 2026 02:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The migration requires maintainer verification that the manifest marker targets its release merge, the old release PR remains unmerged, and source-tags protection is deployed; the release-please discovery dry run was not performed.

No open issues 🎉

Review effort: Balanced

@Vivswan
Vivswan marked this pull request as ready for review November 13, 2026 02:23
@Vivswan
Vivswan merged commit befb746 into main Nov 13, 2026
28 checks passed
@Vivswan
Vivswan deleted the fix/release-marker-tag branch November 13, 2026 02:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants