mirror of
https://github.com/actions/checkout.git
synced 2026-03-21 23:22:13 +01:00
Add retry logic to checkout and submoduleUpdate for partial clone resilience
When using partial clones (filter=blob:none, which is automatically set for sparse checkouts), `git checkout` lazily fetches missing blobs from the promisor remote. If the remote is temporarily unavailable, this network call fails and surfaces as a hard error with no retry. The `fetch`, `getDefaultBranch`, and `lfsFetch` methods already use retryHelper, but `checkout` and `submoduleUpdate` did not, despite both performing network operations: - `checkout`: fetches blobs on-demand from promisor remotes during partial clone checkouts - `submoduleUpdate`: clones/fetches submodule repositories This was observed in production when GitHub's git service had a brief outage, causing the checkout step to fail with: fatal: unable to access '...': Failed to connect to github.com port 443 after 135272 ms: Couldn't connect to server fatal: could not fetch <sha> from promisor remote Wrapping both methods with the existing retryHelper (3 attempts with 10-20s jittered backoff) makes these operations resilient to transient network failures, consistent with how fetch already behaves. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0c366fd6a8
commit
b6a00b350f
2 changed files with 24 additions and 4 deletions
14
dist/index.js
vendored
14
dist/index.js
vendored
|
|
@ -789,7 +789,14 @@ class GitCommandManager {
|
|||
else {
|
||||
args.push(ref);
|
||||
}
|
||||
yield this.execGit(args);
|
||||
// Retry checkout because it can trigger network I/O when using partial
|
||||
// clones (filter=blob:none). In that mode git lazily fetches missing
|
||||
// blobs from the promisor remote during checkout, so a transient network
|
||||
// failure would otherwise surface as a hard error here.
|
||||
const that = this;
|
||||
yield retryHelper.execute(() => __awaiter(this, void 0, void 0, function* () {
|
||||
yield that.execGit(args);
|
||||
}));
|
||||
});
|
||||
}
|
||||
checkoutDetach() {
|
||||
|
|
@ -990,7 +997,10 @@ class GitCommandManager {
|
|||
if (recursive) {
|
||||
args.push('--recursive');
|
||||
}
|
||||
yield this.execGit(args);
|
||||
const that = this;
|
||||
yield retryHelper.execute(() => __awaiter(this, void 0, void 0, function* () {
|
||||
yield that.execGit(args);
|
||||
}));
|
||||
});
|
||||
}
|
||||
submoduleStatus() {
|
||||
|
|
|
|||
|
|
@ -228,7 +228,14 @@ class GitCommandManager {
|
|||
args.push(ref)
|
||||
}
|
||||
|
||||
await this.execGit(args)
|
||||
// Retry checkout because it can trigger network I/O when using partial
|
||||
// clones (filter=blob:none). In that mode git lazily fetches missing
|
||||
// blobs from the promisor remote during checkout, so a transient network
|
||||
// failure would otherwise surface as a hard error here.
|
||||
const that = this
|
||||
await retryHelper.execute(async () => {
|
||||
await that.execGit(args)
|
||||
})
|
||||
}
|
||||
|
||||
async checkoutDetach(): Promise<void> {
|
||||
|
|
@ -457,7 +464,10 @@ class GitCommandManager {
|
|||
args.push('--recursive')
|
||||
}
|
||||
|
||||
await this.execGit(args)
|
||||
const that = this
|
||||
await retryHelper.execute(async () => {
|
||||
await that.execGit(args)
|
||||
})
|
||||
}
|
||||
|
||||
async submoduleStatus(): Promise<boolean> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue