Skip to content

Commit b39cc23

Browse files
Merge pull request #8 from ucudal/fix/7
Fixed #7
2 parents 6d3d2cd + 9553b5c commit b39cc23

File tree

1 file changed

+41
-5
lines changed

1 file changed

+41
-5
lines changed

src/commands/cloneRepos.ts

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export function registerCloneReposCommand(context: vscode.ExtensionContext): voi
6767
}
6868

6969
// Clone repositories with progress
70+
const authHeader = await getGithubAuthHeader(validStudents);
7071
let successCount = 0;
7172
let failureCount = 0;
7273
const failures: { student: string; error: string }[] = [];
@@ -118,7 +119,7 @@ export function registerCloneReposCommand(context: vscode.ExtensionContext): voi
118119
fs.mkdirSync(repoFolder, { recursive: true });
119120

120121
// Clone repository into the repo subfolder
121-
await cloneRepository(student.repositorio, repoFolder);
122+
await cloneRepository(student.repositorio, repoFolder, authHeader);
122123

123124
successCount++;
124125

@@ -162,13 +163,18 @@ export function registerCloneReposCommand(context: vscode.ExtensionContext): voi
162163
/**
163164
* Clones a git repository to the target path
164165
*/
165-
async function cloneRepository(repoUrl: string, targetPath: string): Promise<void> {
166+
async function cloneRepository(repoUrl: string, targetPath: string, authHeader?: string): Promise<void> {
166167
return new Promise((resolve, reject) => {
167-
const { exec } = require('child_process');
168+
const { execFile } = require('child_process');
169+
const args: string[] = [];
168170

169-
const command = `git clone "${repoUrl}" "${targetPath}"`;
171+
if (authHeader && isGithubHttpsRepo(repoUrl)) {
172+
args.push('-c', `http.extraHeader=${authHeader}`);
173+
}
174+
175+
args.push('clone', repoUrl, targetPath);
170176

171-
exec(command, (error: Error | null, _stdout: string, stderr: string) => {
177+
execFile('git', args, { env: { ...process.env, GIT_TERMINAL_PROMPT: '0' } }, (error: Error | null, _stdout: string, stderr: string) => {
172178
if (error) {
173179
reject(new Error(stderr || error.message));
174180
return;
@@ -177,3 +183,33 @@ async function cloneRepository(repoUrl: string, targetPath: string): Promise<voi
177183
});
178184
});
179185
}
186+
187+
function isGithubHttpsRepo(repoUrl: string): boolean {
188+
try {
189+
const parsed = new URL(repoUrl);
190+
return parsed.protocol === 'https:' && parsed.hostname.toLowerCase() === 'github.com';
191+
} catch {
192+
return false;
193+
}
194+
}
195+
196+
async function getGithubAuthHeader(students: StudentSubmission[]): Promise<string | undefined> {
197+
const needsGithubAuth = students.some(student => isGithubHttpsRepo(student.repositorio));
198+
199+
if (!needsGithubAuth) {
200+
return undefined;
201+
}
202+
203+
try {
204+
const session = await vscode.authentication.getSession('github', ['repo'], { createIfNone: true });
205+
if (!session?.accessToken) {
206+
return undefined;
207+
}
208+
209+
const basic = Buffer.from(`x-access-token:${session.accessToken}`).toString('base64');
210+
return `AUTHORIZATION: basic ${basic}`;
211+
} catch {
212+
vscode.window.showWarningMessage('GitHub sign-in was skipped. Private repositories may fail to clone.');
213+
return undefined;
214+
}
215+
}

0 commit comments

Comments
 (0)