feat(next-version): support monorepo VERSION paths via --version-path + .gstack/version-path#1627
Open
cfeddersen wants to merge 1 commit into
Open
feat(next-version): support monorepo VERSION paths via --version-path + .gstack/version-path#1627cfeddersen wants to merge 1 commit into
cfeddersen wants to merge 1 commit into
Conversation
… + .gstack/version-path The workspace-aware ship queue hardcoded the VERSION file at the repo root. In monorepos where versioning is subproject-scoped (one app inside a larger repo), every PR's VERSION lookup 404s, the queue silently empties, and parallel /ship sessions all bump from "current main + 1" — producing a cascade of slot collisions. Repro: tinas-second-brain repo. Root VERSION is absent; the real VERSION lives at "Tinas Second Brain/health-tracker/VERSION". In one day, four sequential collisions: 0.4.0.1 -> 0.5.0.0 -> 0.5.0.1 -> 0.5.0.2 -> 0.5.0.3. Fix: add a --version-path flag and a repo-local .gstack/version-path config file. Resolution priority: CLI flag > .gstack/version-path > "VERSION". The resolved path threads through all four call sites — git show origin/<base>:<path>, the GitHub Contents API, the GitLab files API, and the local sibling-worktree scan — and shows up in the JSON output as version_path so /ship and operators can see what got picked. The previous warning "could not fetch VERSION (fork or private)" was misleading whenever the real cause was wrong path. The new wording names the path that 404'd and hints at the two knobs. Backward-compatible: no flag, no config, no change in behavior. Tests: 6 unit tests for resolveVersionPath (priority, parsing, blank / missing / empty edge cases) + a second integration smoke that drives --version-path end-to-end and asserts it surfaces in JSON output.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
bin/gstack-next-versionhardcodes the VERSION file at<repo-root>/VERSION. In monorepos where versioning is subproject-scoped — one shippable app inside a larger repo — every PR's VERSION lookup 404s, the workspace-aware ship queue silently empties, and parallel/shipsessions all bump from "current main + 1". The result is a cascade of slot collisions.The fix adds a
--version-pathCLI flag and a repo-local.gstack/version-pathconfig file. Resolution priority: CLI flag > config file >"VERSION"(existing default, backward-compatible). The resolved path threads through every call site that touches the file. The previous misleading warning"could not fetch VERSION (fork or private)"becomes honest and actionable.Repro
A private monorepo I work in. Root VERSION is absent; the real VERSION lives at
Apps With Spaces/web-app/VERSION(path intentionally has a space to exercise URL-encoding). In one day, four sequential collisions:Every parallel
/shipsaw an emptyclaimedarray becausegh api repos/{owner}/{repo}/contents/VERSION?ref=<head>returned 404 for every open PR. The util emitted"PR #X: could not fetch VERSION (fork or private)"for each — a misleading warning, since the real cause was wrong path.Confirmed against an open PR of that repo:
The file is fully accessible — the util just queries the wrong path.
Root cause
Three call sites all hardcode
"VERSION":readBaseVersion—git show origin/${base}:VERSIONfetchGithubClaimed—gh api repos/{owner}/{repo}/contents/VERSION?ref=...fetchGitlabClaimed—glab api projects/:id/repository/files/VERSION?ref=...scanSiblings—join(p, "VERSION")for local sibling-worktree scansNo flag, env, or config knob exists to override.
Fix
New helper
resolveVersionPath(override, repoRoot)with priority:--version-path <path>CLI flag (highest).gstack/version-pathfile at repo root — a single line, the relative path from repo root. Committed to the repo so all collaborators benefit."VERSION"default (current behavior — fully backward-compatible)Path threads through all four call sites. GitHub's Contents API gets the path via
encodeURIso spaces in subproject names (e.g.Apps With Spaces/...) become%20while/segments stay intact. GitLab's files API getsencodeURIComponent(the full path becomes a single URL-encoded segment with%2Fseparators), which matches the existing pattern forref=.The resolved path surfaces in the JSON output as
version_pathso/shipand operators can see what got picked. The previous warning is replaced with:End-to-end verification
Patched binary, run against the monorepo with
.gstack/version-pathcontainingApps With Spaces/web-app/VERSION:{ "version": "0.6.0.1", "version_path": "Apps With Spaces/web-app/VERSION", "claimed": [ { "pr": 274, "version": "0.6.0.0", ... }, { "pr": 272, "version": "0.5.1.1", ... } ], "reason": "bumped past claimed 0.6.0.0", ... }Before the fix:
"claimed": []and 3 misleading "could not fetch VERSION (fork or private)" warnings. After: queue is fully visible, slot allocation is correct.Tests added
test/gstack-next-version.test.tsgains 7 new tests:6 unit tests for
resolveVersionPath(new pure-function export):.gstack/version-path.gstack/version-pathconfig is picked up when no flag"VERSION""VERSION""") falls back to config/default (defensive)1 integration smoke that drives
--version-pathend-to-end and asserts it surfaces in the JSON output asversion_path.The existing integration test gains an assertion that
version_pathdefaults to"VERSION"when no flag/config present.Test plan
bun test test/gstack-next-version.test.ts— 28/28 pass (was 21 pre-change)bun --bun build bin/gstack-next-versionOut of scope (surfaced while investigating)
/shipdoes), so it's a separate fix in a separate file. Happy to follow up if useful.gstack-pr-title-rewrite.shalso references VERSION but takes the version string as an argument — not a file-path bug. No fix needed.🤖 Generated with Claude Code