Skip to content

Commit 158fe9e

Browse files
committed
Add retries for cloning git repo
1 parent 2e4220c commit 158fe9e

File tree

1 file changed

+72
-17
lines changed

1 file changed

+72
-17
lines changed

evals/git-evals/setup-test-repo.ts

Lines changed: 72 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,39 @@ export function extractRepoNameFromUrl(repoUrl: string): string {
3535
return parts[parts.length - 1]
3636
}
3737

38+
/**
39+
* Executes a git command with retry logic and exponential backoff
40+
*/
41+
async function executeGitCommandWithRetry(
42+
command: string,
43+
args: string[],
44+
options: any,
45+
maxRetries: number = 3,
46+
baseDelay: number = 1000,
47+
): Promise<void> {
48+
let lastError: Error | undefined
49+
50+
for (let attempt = 0; attempt < maxRetries; attempt++) {
51+
try {
52+
execFileSync(command, args, options)
53+
return // Success!
54+
} catch (error) {
55+
lastError = error as Error
56+
57+
if (attempt < maxRetries - 1) {
58+
const delay = baseDelay * Math.pow(2, attempt)
59+
console.warn(
60+
`Git command failed (attempt ${attempt + 1}/${maxRetries}): ${error instanceof Error ? error.message : String(error)}`,
61+
)
62+
console.warn(`Retrying in ${delay}ms...`)
63+
await new Promise((resolve) => setTimeout(resolve, delay))
64+
}
65+
}
66+
}
67+
68+
throw lastError || new Error('Git command failed after all retries')
69+
}
70+
3871
export async function setupTestRepo(
3972
repoUrl: string,
4073
customRepoName: string,
@@ -115,42 +148,64 @@ export async function setupTestRepo(
115148
...process.env,
116149
GIT_TERMINAL_PROMPT: '0', // Disable interactive prompts
117150
GIT_ASKPASS: 'echo', // Provide empty password if prompted
151+
GIT_HTTP_LOW_SPEED_LIMIT: '1000', // Minimum speed (bytes/sec)
152+
GIT_HTTP_LOW_SPEED_TIME: '30', // Time window for speed check (seconds)
118153
}
119154

120-
execFileSync('git', ['clone', '--no-checkout', cloneUrl, repoDir], {
121-
timeout: 120_000, // 2 minute timeout for cloning
122-
stdio: 'inherit',
123-
env: gitEnv,
124-
})
125-
execFileSync('git', ['fetch', 'origin', commitSha], {
155+
await executeGitCommandWithRetry(
156+
'git',
157+
['clone', '--no-checkout', cloneUrl, repoDir],
158+
{
159+
timeout: 600_000, // 10 minute timeout for cloning
160+
stdio: 'inherit',
161+
env: gitEnv,
162+
},
163+
)
164+
await executeGitCommandWithRetry('git', ['fetch', 'origin', commitSha], {
126165
cwd: repoDir,
127166
stdio: 'inherit',
128167
env: gitEnv,
129168
})
130-
execFileSync('git', ['checkout', commitSha], {
169+
await executeGitCommandWithRetry('git', ['checkout', commitSha], {
131170
cwd: repoDir,
132171
stdio: 'inherit',
133172
})
134173
} else {
135174
// Local development or public repos
136175
console.log(`Local environment detected - cloning from: ${repoUrl}`)
137176

138-
execFileSync(
177+
const localGitEnv = {
178+
...process.env,
179+
GIT_HTTP_LOW_SPEED_LIMIT: '1000', // Minimum speed (bytes/sec)
180+
GIT_HTTP_LOW_SPEED_TIME: '30', // Time window for speed check (seconds)
181+
}
182+
183+
await executeGitCommandWithRetry(
139184
'git',
140185
['clone', '--no-checkout', '--quiet', repoUrl, repoDir],
141186
{
142-
timeout: 120_000, // 2 minute timeout for cloning
187+
timeout: 600_000, // 10 minute timeout for cloning
188+
stdio: 'inherit',
189+
env: localGitEnv,
190+
},
191+
)
192+
await executeGitCommandWithRetry(
193+
'git',
194+
['fetch', 'origin', '--quiet', commitSha],
195+
{
196+
cwd: repoDir,
197+
stdio: 'inherit',
198+
env: localGitEnv,
199+
},
200+
)
201+
await executeGitCommandWithRetry(
202+
'git',
203+
['checkout', '--quiet', commitSha],
204+
{
205+
cwd: repoDir,
143206
stdio: 'inherit',
144207
},
145208
)
146-
execFileSync('git', ['fetch', 'origin', '--quiet', commitSha], {
147-
cwd: repoDir,
148-
stdio: 'inherit',
149-
})
150-
execFileSync('git', ['checkout', '--quiet', commitSha], {
151-
cwd: repoDir,
152-
stdio: 'inherit',
153-
})
154209
}
155210

156211
console.log('Repository cloned successfully!')

0 commit comments

Comments
 (0)