Fix bundle transport in shallow checkouts#31603
Conversation
Co-authored-by: mrjf <180956+mrjf@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes failures when applying git bundles in shallow (fetch-depth: 1) checkouts by unshallowing the repository before git fetch <bundle> so bundle prerequisite commits are available locally.
Changes:
- Added
ensureFullHistoryForBundle()ingit_helpers.cjsto detect shallow repos and rungit fetch --unshallow originonly when needed. - Invoked the shallow-history guard before bundle fetch in both
create_pull_requestandpush_to_pull_request_branch. - Added regression tests to validate unshallow happens before bundle fetch (and only when shallow).
Show a summary per file
| File | Description |
|---|---|
| actions/setup/js/git_helpers.cjs | Adds ensureFullHistoryForBundle() helper to unshallow before bundle fetch when required. |
| actions/setup/js/git_helpers.test.cjs | Adds unit tests covering shallow vs non-shallow behavior for the new helper. |
| actions/setup/js/create_pull_request.cjs | Calls the new helper before fetching from a bundle during PR creation. |
| actions/setup/js/create_pull_request.test.cjs | Adds regression test asserting unshallow occurs before bundle fetch in shallow checkouts. |
| actions/setup/js/push_to_pull_request_branch.cjs | Calls the new helper before fetching from a bundle when pushing to an existing PR branch. |
| actions/setup/js/push_to_pull_request_branch.test.cjs | Updates test to simulate shallow repo and assert unshallow precedes bundle fetch. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 6/6 changed files
- Comments generated: 0
There was a problem hiding this comment.
Skills-Based Review 🧠
Applied /diagnose and /tdd — this is a bug fix with regression tests, the classic pairing.
Key Themes
- Missing error resilience in the guard:
ensureFullHistoryForBundledoes not catch a failure fromgit rev-parse --is-shallow-repository. If that command fails for any environmental reason, the error bubbles up to the outertry/catchand surfaces as a generic bundle-apply failure, masking the real cause. - Dead mock branch in the new test: The
cmd.startsWith("git ls-remote")condition in thecreate_pull_requestbundle test is never true (cmd is"git"), so the intent is invisible and the mock is slightly misleading.
Positive Highlights
- ✅ Correct seam for the regression test — the fix is tested at the call-site level (integration-style), not just unit-tested in isolation.
- ✅ Ordering assertion — both tests verify that unshallow happens before the bundle fetch using call-index comparison. That's exactly the right assertion for this bug class.
- ✅ Shared helper — extracting
ensureFullHistoryForBundleintogit_helpers.cjskeeps both call sites DRY and testable independently. - ✅
push_to_pull_request_branchpasses auth env — the options includinggitAuthEnvare forwarded correctly.
Verdict
No blocking issues. The two items above are worth a quick follow-up (error resilience, dead mock branch) but neither is a correctness bug in the happy path.
🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · ● 7.4M
| * @returns {Promise<void>} | ||
| */ | ||
| async function ensureFullHistoryForBundle(execApi, options = {}) { | ||
| const { stdout } = await execApi.getExecOutput("git", ["rev-parse", "--is-shallow-repository"], options); |
There was a problem hiding this comment.
[/diagnose] The getExecOutput call has no error handling for when git rev-parse --is-shallow-repository fails (e.g., unusual git environment). An error here propagates out and is caught by the outer bundle-fetch try/catch, silently aborting the PR creation with { success: false } — which looks like a bundle error, not a shallow-check error.
Consider treating any failure as non-shallow and logging a warning:
try {
({ stdout } = await execApi.getExecOutput(
'git', ['rev-parse', '--is-shallow-repository'], options
));
} catch {
core.warning('Could not determine shallow status; skipping unshallow');
return;
}Adding a test for this error path would lock in the fallback behaviour.
| if (cmd === "git" && args[0] === "rev-list") { | ||
| return Promise.resolve({ exitCode: 0, stdout: "1\n", stderr: "" }); | ||
| } | ||
| if (typeof cmd === "string" && cmd.startsWith("git ls-remote")) { |
There was a problem hiding this comment.
[/tdd] This mock branch is dead code. cmd is "git" (just the executable), so cmd.startsWith("git ls-remote") is always false. The catch-all return covers ls-remote calls, but the intent is invisible.
Fix to match by args:
if (cmd === 'git' && args && args[0] === 'ls-remote') {
return Promise.resolve({ exitCode: 0, stdout: '', stderr: '' });
}The pattern used in the existing tests at lines ~1848 (cmdStr.includes('ls-remote --heads origin')) is an alternative. Either way, the dead branch should be removed so the mock accurately documents its contract.
🧪 Test Quality Sentinel ReportTest Quality Score: 80/100✅ Excellent — all new tests enforce behavioral contracts.
Test Classification DetailsView all 4 tests
Test Inflation Note
Mocking AssessmentAll mocking targets are external I/O or GitHub Actions runtime globals ( Language SupportTests analyzed:
Verdict
📖 Understanding Test ClassificationsDesign Tests (High Value) verify what the system does:
Implementation Tests (Low Value) verify how the system does it:
Goal: Shift toward tests that describe the system's behavioral contract — the promises it makes to its users and collaborators. References: §25707268158
|
|
@copilot review all comments |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Bug Fix
What was the bug?
Bundle transport can fail before ref updates in
fetch-depth: 1checkouts becausegit fetch <bundle>rejects bundles whose prerequisite commits are missing locally. This affects bothcreate_pull_requestandpush_to_pull_request_branch.How did you fix it?
Shared shallow-checkout guard
Added
ensureFullHistoryForBundle()to detect shallow repositories before bundle fetch.Runs:
only when
git rev-parse --is-shallow-repositoryreportstrue.If shallow status cannot be determined, logs a warning and skips unshallowing instead of failing bundle application early.
Bundle application paths
git fetch <bundle>in:create_pull_requestpush_to_pull_request_branchRegression coverage