Skip to content

Commit b1790a3

Browse files
committed
fix(azure): add azure devops http header (git clone & git fetch)
1 parent a698afd commit b1790a3

File tree

1 file changed

+73
-13
lines changed

1 file changed

+73
-13
lines changed

packages/backend/src/git.ts

Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,38 @@ import { env } from './env.js';
44

55
type onProgressFn = (event: SimpleGitProgressEvent) => void;
66

7+
// Helper function to prepare Azure DevOps authentication
8+
const prepareAzureDevOpsAuth = (cloneUrl: string) => {
9+
// Check if this is an Azure DevOps URL
10+
const isAzureDevOps = cloneUrl.includes('dev.azure.com') || cloneUrl.includes('devops');
11+
12+
if (!isAzureDevOps) {
13+
return { url: cloneUrl, authHeader: null };
14+
}
15+
16+
let token = '';
17+
try {
18+
const url = new (globalThis as any).URL(cloneUrl);
19+
token = url.password;
20+
} catch (e) {
21+
return { url: cloneUrl, authHeader: null };
22+
}
23+
24+
if (!token) {
25+
return { url: cloneUrl, authHeader: null };
26+
}
27+
28+
// For Azure DevOps, we need to remove the token from the URL and pass it as a header
29+
const url = new (globalThis as any).URL(cloneUrl);
30+
url.password = '';
31+
const cleanUrl = url.toString();
32+
33+
// Create the authorization header
34+
const authHeader = `Authorization: Basic ${(globalThis as any).Buffer.from(`:${token}`).toString('base64')}`;
35+
36+
return { url: cleanUrl, authHeader };
37+
};
38+
739
export const cloneRepository = async (
840
{
941
cloneUrl,
@@ -18,20 +50,34 @@ export const cloneRepository = async (
1850
try {
1951
await mkdir(path, { recursive: true });
2052

53+
2154
const git = simpleGit({
2255
progress: onProgress,
2356
}).cwd({
2457
path,
2558
})
2659

27-
await git.clone(
28-
cloneUrl,
29-
path,
30-
[
31-
"--bare",
32-
]
33-
);
60+
const { url: cleanUrl, authHeader } = prepareAzureDevOpsAuth(cloneUrl);
3461

62+
if (authHeader) {
63+
await git.clone(
64+
cleanUrl,
65+
path,
66+
[
67+
"--bare",
68+
"-c",
69+
`http.extraHeader=${authHeader}`
70+
]
71+
);
72+
} else {
73+
await git.clone(
74+
cloneUrl,
75+
path,
76+
[
77+
"--bare",
78+
]
79+
);
80+
}
3581
await unsetGitConfig(path, ["remote.origin.url"]);
3682
} catch (error: unknown) {
3783
const baseLog = `Failed to clone repository: ${path}`;
@@ -65,12 +111,26 @@ export const fetchRepository = async (
65111
path: path,
66112
})
67113

68-
await git.fetch([
69-
cloneUrl,
70-
"+refs/heads/*:refs/heads/*",
71-
"--prune",
72-
"--progress"
73-
]);
114+
const { url: cleanUrl, authHeader } = prepareAzureDevOpsAuth(cloneUrl);
115+
116+
if (authHeader) {
117+
// Temporarily set git configuration
118+
await git.addConfig('http.extraHeader', authHeader);
119+
120+
await git.fetch([
121+
cleanUrl,
122+
"+refs/heads/*:refs/heads/*",
123+
"--prune",
124+
"--progress"
125+
]);
126+
} else {
127+
await git.fetch([
128+
cloneUrl,
129+
"+refs/heads/*:refs/heads/*",
130+
"--prune",
131+
"--progress"
132+
]);
133+
}
74134
} catch (error: unknown) {
75135
const baseLog = `Failed to fetch repository: ${path}`;
76136
if (env.SOURCEBOT_LOG_LEVEL !== "debug") {

0 commit comments

Comments
 (0)