Repository navigation
feat(get-affected-actors): three-dot diff, narrowed per Actor with --since - #204
Conversation
| head: headSha, | ||
| commits, | ||
| // Empty `git log x..x` output doesn't parse as a commit | ||
| commits: range.fromRef === headSha ? [] : await getCommitsBetween(range.fromRef, range.toRef), |
There was a problem hiding this comment.
do we need this anymore?
There was a problem hiding this comment.
From Claude
It was still needed: get-affected-actors skipped the commit list when the range was empty, because getCommitsBetween couldn’t parse git’s empty output and threw. I fixed that at the source instead:
getCommitsBetween now returns [] for an empty range, so the special case in get-affected-actors is gone.
getCommits is shared by get-commits, get-latest-commit and get-changed-files, which all need at least one commit. It still fails on an empty range, but now with a clear message (“ has no commits that are not on ”) instead of “Failed to parse commit string”.
The two mocked tests that checked the special case are gone. Real-git tests replace them:
a branch with no commits of its own, and a release with nothing new, both report nothing;
getCommitsBetween('HEAD', 'HEAD') returns [];
getCommits fails with the new message.
I will go through the refactored code (it tried to satisfy you :) ) once I address everything
|
|
||
| logger.info( | ||
| '[MERGE-FROM-TARGET-OPTIMIZATION]: There is merge from target branch, checking if there are no functional changes in our own branch. If so, we can skip tests', | ||
| const narrowToChangedSince = (branch: ChangedActors, sinceValidated: ChangedActors): ChangedActors => { |
There was a problem hiding this comment.
Personally this function is a bit too cryptic, I would never be able to understand what it is trying to do just by looking at the code. The JSDoc doesn't really help much
There was a problem hiding this comment.
yeah, same.
I remember spending quite a while reading it until i got it because i was so sure there was a bug there somewhere (there isnt) but its quite a smell.
There was a problem hiding this comment.
I hand polished it:
- Rewrote JSDoc to be closer to how we see it (hopefully)
- Renamed variables to be more explicit and added more comments. more verbose code.
- Collapsed some if statements. We redo one git command because of that because we intersect equal sets but I think it is cleaner this way. Basically, since defaults base if no validated commit.
There is still room for improvement but I'm quite happy now
…ctor with --since
--base now inspects `git diff base...HEAD`: what the branch changes, not what
it merged in from base. This replaces the merge-from-target detection and the
branch-only changed files lookup, and applies that optimisation per Actor:
Actors that only base changed are skipped even when the branch changes others.
With --since as well, the changes since the last validated commit are
classified separately and only Actors changed in both are reported, as
functional only when both diffs are functional. --since no longer has to be on
the branch, so a rebase only re-checks Actors that base changed too. A --since
that is HEAD (rerun) or missing locally (force-push) checks the whole branch.
Change detection now takes a { fromRef, toRef } range instead of a commit
list, so the cosmetic .actor JSON check compares the right endpoints for each
diff.
Refs #196
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012dp3mSDDgp5u2QVBT54EpX
…examples Shows how each diff classifies the Actors for a push with only the branch's own changes, a cosmetic merge from base and a functional merge from base, and notes that the scheme assumes the branch is up to date with base. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012dp3mSDDgp5u2QVBT54EpX
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012dp3mSDDgp5u2QVBT54EpX
213cb66 to
bfd9505
Compare
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012dp3mSDDgp5u2QVBT54EpX
…I on real git Adds CLI tests that build real histories and run the compiled CLI on them: the branch's own changes since the last validated commit, a cosmetic merge from base, a functional merge from base, Actors only base changed, code changed in the merge commit itself, a rebase onto unrelated base changes, and a rerun or a --since missing from the history. Five of them fail against master's detection, which is what this PR changes. Following review, the mocked getMergeBase test is dropped, since it only restated the implementation, and findCommitSha is tested on real git. The CLI compile step is shared with the build CLI tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012dp3mSDDgp5u2QVBT54EpX
…p the empty-range special case narrowToChangedSince now walks the branch's Actors and decides each one in steps: left out when nothing changed since the last validated commit, functional only when both diffs are functional, cosmetic otherwise. The output is the same. getCommitsBetween returns no commits for an empty range instead of failing to parse git's empty output, so get-affected-actors no longer special-cases it. getCommits keeps failing on an empty range, now with a clear message, since get-commits, get-latest-commit and get-changed-files need a commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012dp3mSDDgp5u2QVBT54EpX
…d the bundle instagram-scraper-rs was another repository's checkout added by accident as a gitlink. affected-actors.ts gets Prettier's formatting, and the bundle is rebuilt so the CLI bundle check matches the refactor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012dp3mSDDgp5u2QVBT54EpX
| * Exception: if the branch has any functional changes alongside the merge, we must re-test — even | ||
| * individually validated changes can have novel interactions when combined. | ||
| * Returns the Actors the branch's own commits changed, or undefined when it didn't merge base in. | ||
| * This is Juan's magical algorithm where we need just 2 git diffs to determine functional changes on Actors. |
There was a problem hiding this comment.
kinda sus all the git manipulations.
Seems like it should work even for worktrees tho.
#204 removed hasMergeFromTarget and getBranchOnlyChangedFiles, so those conflicts resolve to master's side. getChangedFilesBetween, now the only place changed files are listed, keeps --no-renames. A real-git CLI test covers a file moved between Actors, which fails without the flag. The bundle is rebuilt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012dp3mSDDgp5u2QVBT54EpX
## Problem Git turns on rename detection by default. With it, `git diff --name-only` lists a moved file only under its new path. If a file moves out of an Actor's context, that Actor doesn't count as changed, so it isn't rebuilt or tested even though it lost the file. ## Change `getChangedFilesBetween` lists changed files with `--name-only --no-renames` (the shared `LIST_CHANGED_PATHS` in `bin/git.ts`). A move then shows up as a deletion plus an addition, so both paths count. Since #204, this is the only place changed files are listed: `get-affected-actors` uses it for both the `--base` and `--since` diffs, and `getChangedFiles` delegates to it. The CLI bundle is rebuilt. ## Testing - **Real-git CLI test** (`affected-actors-cli.test.ts`): moving `actors/a/main.ts` to `actors/c/moved.ts` reports both `a` and `c` as functionally changed. Without the flag it reports only `c`; I checked that the test fails that way. - **Unit tests**: the mocked ones assert the new argument. - Typecheck, lint, Prettier and the 420 unit tests pass locally. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_012dp3mSDDgp5u2QVBT54EpX --------- Co-authored-by: Claude <noreply@anthropic.com>
…ed-files (#228) I think this makes sense, users can use `get-affected-actors` to get changedFiles too. ## AI `get-affected-actors` (#204) now computes commits, changed files and changelog in one place from a single diff path. The three older commands (`get-commits`, `get-latest-commit`, `get-changed-files`) are documented as "kept for older workflows", but no workflow in this repo uses them. They still carry a second, parallel git model: - `getCommits`, which has its own rerun and base-commit heuristics and duplicates what `since` does in `get-affected-actors`. - `getChangedFiles`, which is `getChangedFilesBetween` with a `~` hack. - `parseBaseCommit`, with the "SHA or Commit JSON" overload that only existed to pipe `get-latest-commit` output back in. - The `--source-branch`, `--target-branch` and `--base-commit` flags, the `gitRangeOptions` group and the `Config` type. #218 left these out on purpose and said the call belongs to the maintainers. This PR is that proposal. ## What - Remove the three commands and everything only they used. About 140 lines of source and about 250 lines of tests go away. - `resolveReleaseBaseCommit` now validates the SHA inline and reuses `findCommitSha`, instead of a second copy of the "`rev-parse` exit code 1 means missing" handling. - Drop the "Legacy git commands" section from `docs/cli.md`. CONTRIBUTING's CLI example now uses `get-affected-actors --base master`. - Delete `logging.test.ts`. It compiled the whole project with `tsc` (the cause of #227's timeout) just to check log levels through `get-commits`. The same check is now two cases in `cli-bundle.test.ts` that run `get-affected-actors` against the committed bundle. - Rebuild the CLI bundle. ## Breaking Anyone who calls these three commands directly breaks. The `workflows-v0` reusable workflows don't, so only external users scripting the CLI are affected. Since we're before v1, this is the cheapest time to drop them. Whether to do it is the open question for reviewers. ## Other ideas I considered and left out Each overlaps an open PR, so it would conflict: - #218 (build pipeline), #223 (`test` and `notify` commands) and #224 (bundle-based CLI tests) already cover the build and reporting code. - Filling `lib/` gaps from issues (`fails` modifier #159, standby without a task #127) are features, not refactors. ## Checks - [x] `tsc`, eslint, prettier, knip (the unused exports it lists were already on master) and `npm test` pass: 31 files, 438 tests. --- _Generated by [Claude Code](https://claude.ai/code/session_016XtpQvEqmuEhj1cBAaUxML)_ Co-authored-by: Claude <noreply@anthropic.com>
The core logic seems correct and clear improvement. Keeping in draft for further polish.
This is #196's "Solution 2" implemented on top of the simplified
get-affected-actors, so we can discuss a concrete diff. It changes behaviour compared to master. The changes are listed below.What it does
--base: inspectsgit diff $(git merge-base base HEAD) HEAD, which is the same asbase...HEADand GitHub's "Files changed" tab. That is what the branch changes, not what it merged in from base.--baseand--since: also classifiessince..HEAD, which is everything since the last validation, including what came in through a merge or a rebase. It then keeps only the Actors that changed in both diffs. An Actor counts as functional only when both diffs say functional. On the question left open in Diff files logic refactor #196, that means taking the least impactful classification; taking the most impactful would re-test scenario A on every push.--sincealone (releases): unchanged.--since: when--sinceisHEAD(a rerun) or isn't in the local history (a force-push), it is ignored and the whole branch is checked.What goes away
hasMergeFromTarget,getBranchOnlyChangedFilesandgetOwnChangesIfMergedFromBase, together with the merge-from-target log messages and the per-Actor TODO, which this resolves.{ fromRef, toRef }range instead of a commit list. The cosmetic.actorJSON check therefore compares the right endpoints for each diff, which also resolves its "validate this is the right commit range" TODO.bin/: 93 insertions, 132 deletions. With tests and README: 318 insertions, 410 deletions.Behaviour on a scratch repo
I ran this PR's
getAffectedActorson a scratch repo where Actorsaandcsharesrc/andbis isolated. The "Before" column is the code in #203, which matches master..vscodefoo, then merged a masterbarin the same shared contextsrcsrc, then merged a master that only changedbbsrc--since= HEAD)Open points
--sincecommit usually isn't in a fresh checkout, so the rebase improvement only kicks in if the workflow fetches that commit (git fetch origin <sha>). I haven't checked whether GitHub serves force-pushed commits that way. Without the fetch, it falls back to checking the whole branch, which is what master does today.git merge-basepicks one of several merge bases.--baseand--since.Checks
tsc, eslint, prettier and vitest (399 passed) all pass locally. Knip shows only the existing false positives caused by
bin/main.tsnot being a knip entry.Refs #196
🤖 Generated with Claude Code
https://claude.ai/code/session_012dp3mSDDgp5u2QVBT54EpX
Generated by Claude Code