Skip to content

feat(release): add --from to scope set-commits to a local range#1197

Merged
betegon merged 10 commits into
mainfrom
feat/release-set-commits-from
Jul 6, 2026
Merged

feat(release): add --from to scope set-commits to a local range#1197
betegon merged 10 commits into
mainfrom
feat/release-set-commits-from

Conversation

@betegon

@betegon betegon commented Jul 3, 2026

Copy link
Copy Markdown
Member

Summary

Adds a --from <ref> flag to sentry release set-commits so monorepo users can associate only the commits that changed a given subtree since the last release — the use case raised in the last comment of #1156:

sentry release set-commits 1.0.0 --from v0.9.0 --path apps/mobile,apps/shared

This reads the local v0.9.0..HEAD range, keeps only commits touching those paths, and sends them.

Why a new flag instead of --commit PREV..SHA --path ...

Path filtering can only happen client-side. --commit/--auto send a ref range that Sentry expands server-side, and the API has no concept of paths (confirmed in set_refs/set_commits on the backend) — so a path filter there would be silently ignored. That's why --path already implies local git, and why the range it needs must also be local. --from reuses the existing getCommitLog(from, paths) path (git log <ref>..HEAD -- <paths>).

What changed

  • --from <ref> (implies --local): reads <ref>..HEAD from local git. Combines with --path. Cannot be combined with --auto/--commit (same rule as --path), and rejects an empty ref.
  • Depth handling: a from..HEAD range is self-bounding, so --initial-depth is dropped when --from is set. getCommitLog now only adds --max-count for a positive depth (omitting it reads the whole range).
  • Extracted parseCommitRefs and parseLocalScope helpers to keep func under the cognitive-complexity limit.
  • Requires a full (non-shallow) checkout spanning the range — already surfaced via the existing shallow-clone warning.

Test plan

  • pnpm vitest run test/commands/release/set-commits.test.ts test/lib/git-commit-log.test.ts — 28 pass (new: --from implies local, combines with --path, rejects empty/--auto/--commit; getCommitLog omits --max-count for a range and applies it for a positive depth).
  • pnpm tsc --noEmit, biome, and pnpm run check:fragments all clean.

Follow-up to #1156 (the --clear fix landed in #1196).

Made with Cursor

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://cli.sentry.dev/_preview/pr-1197/

Built to branch gh-pages at 2026-07-06 09:14 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

Comment thread src/lib/git.ts
betegon added a commit that referenced this pull request Jul 3, 2026
…t crash

getCommitLog with --from drops --max-count, so `git log <ref>..HEAD` can
emit more than execFileSync's 1 MB default maxBuffer and throw
ERR_CHILD_PROCESS_STDIO_MAXBUFFER on large histories. Raise the git()
helper's maxBuffer to 100 MB.

Addresses sentry-warden review feedback on #1197.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Codecov Results 📊

✅ Patch coverage is 83.33%. Project has 5333 uncovered lines.
✅ Project coverage is 81.8%. Comparing base (base) to head (head).

Files with missing lines (1)
File Patch % Lines
src/commands/release/set-commits.ts 80.00% ⚠️ 8 Missing and 1 partials
Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
+ Coverage    81.80%    81.80%        —%
==========================================
  Files          423       423         —
  Lines        29282     29308       +26
  Branches     19051     19082       +31
==========================================
+ Hits         23953     23975       +22
- Misses        5329      5333        +4
- Partials      1983      1982        -1

Generated by Codecov Action

Comment thread src/commands/release/set-commits.ts
@betegon betegon marked this pull request as ready for review July 3, 2026 16:52
@github-actions github-actions Bot added the risk: high PR risk score: high label Jul 3, 2026
betegon added a commit that referenced this pull request Jul 3, 2026
…tion

A --from value starting with "-" (e.g. --format=%H) became the argv element
`--format=%H..HEAD`, which git parses as a --format override, silently
corrupting the NUL-delimited output. Reject option-like refs in parseLocalScope
with a clear error, and add `--end-of-options` before the range in getCommitLog
as defense-in-depth so any caller-supplied ref is treated as a revision.

Addresses sentry-warden review feedback on #1197.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread src/lib/git.ts Outdated
betegon added a commit that referenced this pull request Jul 3, 2026
…compat)

--end-of-options requires git >= 2.24 and would crash older git with
`fatal: unknown option '--end-of-options'`, regressing all local git ops
(--local, --path, --from). Replace it with a version-independent guard that
rejects an option-like `from` (leading '-') in getCommitLog, matching
getMergeBase. Git refs cannot start with '-', so this fully closes the
argument-injection vector without the flag.

Addresses Seer review feedback on #1197.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread src/commands/release/set-commits.ts Outdated
betegon added a commit that referenced this pull request Jul 3, 2026
…-path

The "No commits found" warning suggested "Check the ref and path(s)"
whenever --from was set, even if no --path was given. Make the suggestion
conditional on whether paths were actually provided.

Addresses Seer review feedback on #1197.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread src/lib/git.ts Outdated
betegon added a commit that referenced this pull request Jul 3, 2026
Removing the default let getCommitLog(cwd) / getCommitLog(cwd, {}) walk the
entire history instead of the documented 20-commit cap — a footgun for any
caller that omits depth. Restore depth = 20 and use an explicit non-positive
depth (0) to opt into the uncapped whole-range read used by --from.

Addresses Seer review feedback on #1197.

Co-authored-by: Cursor <cursoragent@cursor.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 306f19b. Configure here.

Comment thread src/lib/git.ts Outdated
betegon added a commit that referenced this pull request Jul 6, 2026
getCommitLog omitted --max-count for any non-positive depth, but uncapped
history was only intended when --from sets a self-bounding range (depth 0).
--local --initial-depth 0 without --from would walk all of HEAD. Only skip
max-count when from is set and depth is non-positive.

Addresses Cursor Bugbot review on #1197.

Co-authored-by: Cursor <cursoragent@cursor.com>
betegon and others added 10 commits July 6, 2026 11:10
Adds a --from <ref> flag to `release set-commits` that reads the local
`<ref>..HEAD` range (e.g. the previous release tag through the current
checkout) and associates those commits. It implies --local and combines
with --path, so monorepo users can scope a release to the commits that
touched specific subtrees since the last release:

  sentry release set-commits 1.0.0 --from v0.9.0 --path apps/mobile,apps/shared

Path filtering can only happen client-side (the Sentry API expands
`--commit`/`--auto` ranges server-side with no path awareness), so --from
runs through local git via getCommitLog. Because a `from..HEAD` range is
self-bounding, the --initial-depth cap is dropped when --from is set;
getCommitLog now only applies --max-count for a positive depth.

Reported in #1156.

Co-authored-by: Cursor <cursoragent@cursor.com>
…t crash

getCommitLog with --from drops --max-count, so `git log <ref>..HEAD` can
emit more than execFileSync's 1 MB default maxBuffer and throw
ERR_CHILD_PROCESS_STDIO_MAXBUFFER on large histories. Raise the git()
helper's maxBuffer to 100 MB.

Addresses sentry-warden review feedback on #1197.

Co-authored-by: Cursor <cursoragent@cursor.com>
The --from tests exercised HEAD~1/HEAD~3 against the real repo, which fails
in CI's shallow (depth-1) checkout where those ancestors don't exist. Stub
getCommitLog so the tests verify command wiring (local mode, from/paths
passed) without depending on real git history.

Co-authored-by: Cursor <cursoragent@cursor.com>
…tion

A --from value starting with "-" (e.g. --format=%H) became the argv element
`--format=%H..HEAD`, which git parses as a --format override, silently
corrupting the NUL-delimited output. Reject option-like refs in parseLocalScope
with a clear error, and add `--end-of-options` before the range in getCommitLog
as defense-in-depth so any caller-supplied ref is treated as a revision.

Addresses sentry-warden review feedback on #1197.

Co-authored-by: Cursor <cursoragent@cursor.com>
…compat)

--end-of-options requires git >= 2.24 and would crash older git with
`fatal: unknown option '--end-of-options'`, regressing all local git ops
(--local, --path, --from). Replace it with a version-independent guard that
rejects an option-like `from` (leading '-') in getCommitLog, matching
getMergeBase. Git refs cannot start with '-', so this fully closes the
argument-injection vector without the flag.

Addresses Seer review feedback on #1197.

Co-authored-by: Cursor <cursoragent@cursor.com>
…-path

The "No commits found" warning suggested "Check the ref and path(s)"
whenever --from was set, even if no --path was given. Make the suggestion
conditional on whether paths were actually provided.

Addresses Seer review feedback on #1197.

Co-authored-by: Cursor <cursoragent@cursor.com>
Removing the default let getCommitLog(cwd) / getCommitLog(cwd, {}) walk the
entire history instead of the documented 20-commit cap — a footgun for any
caller that omits depth. Restore depth = 20 and use an explicit non-positive
depth (0) to opt into the uncapped whole-range read used by --from.

Addresses Seer review feedback on #1197.

Co-authored-by: Cursor <cursoragent@cursor.com>
getCommitLog omitted --max-count for any non-positive depth, but uncapped
history was only intended when --from sets a self-bounding range (depth 0).
--local --initial-depth 0 without --from would walk all of HEAD. Only skip
max-count when from is set and depth is non-positive.

Addresses Cursor Bugbot review on #1197.

Co-authored-by: Cursor <cursoragent@cursor.com>
token-host: filter saasSubdomainArb to labels that compose a valid
https://<label>.sentry.io URL (e.g. `xn--` is invalid in WHATWG URL).

snapshots upload: uploads run in parallel, so putSpy call order is
non-deterministic — locate the a.png objectstore key by content hash
instead of assuming mock.calls[0].

Co-authored-by: Cursor <cursoragent@cursor.com>
@betegon betegon force-pushed the feat/release-set-commits-from branch from 0581d7c to 5258174 Compare July 6, 2026 09:13
@betegon betegon merged commit b3ff789 into main Jul 6, 2026
32 checks passed
@betegon betegon deleted the feat/release-set-commits-from branch July 6, 2026 16:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: high PR risk score: high

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant