Skip to content

Commit 6dbe4e1

Browse files
Copilotalexr00
andauthored
Resolve insteadOf URL aliases in remaining remote-parsing call sites (#8754)
* Initial plan * Apply insteadOf alias resolution in remaining remote parse callers Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com>
1 parent f2eceac commit 6dbe4e1

4 files changed

Lines changed: 62 additions & 9 deletions

File tree

src/github/folderRepositoryManager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import { stripCoAuthoredByTrailers, unwrapCommitMessageBody } from '../common/gi
3838
import { Disposable, disposeAll } from '../common/lifecycle';
3939
import Logger from '../common/logger';
4040
import { Protocol, ProtocolType } from '../common/protocol';
41-
import { GitHubRemote, parseRemote, parseRepositoryRemotes, parseRepositoryRemotesAsync, Remote } from '../common/remote';
41+
import { GitHubRemote, parseRemote, parseRepositoryRemotesAsync, Remote } from '../common/remote';
4242
import {
4343
ALLOW_FETCH,
4444
AUTO_STASH,
@@ -2915,7 +2915,7 @@ export class FolderRepositoryManager extends Disposable {
29152915
Logger.debug(`Skipping inaccessible repository: ${owner}/${repositoryName}`, this.id);
29162916
return undefined;
29172917
}
2918-
const gitRemotes = parseRepositoryRemotes(this.repository);
2918+
const gitRemotes = await parseRepositoryRemotesAsync(this.repository);
29192919
const gitRemote = gitRemotes.find(r => r.owner === owner && r.repositoryName === repositoryName);
29202920
const uri = gitRemote?.url ?? `https://github.com/${owner}/${repositoryName}`;
29212921
const repo = await this.createAndAddGitHubRepository(new Remote(gitRemote?.remoteName ?? repositoryName, uri, new Protocol(uri)), this._credentialStore);

src/github/pullRequestGitHelper.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { IResolvedPullRequestModel, PullRequestModel } from './pullRequestModel'
1111
import { Branch, Repository } from '../api/api';
1212
import Logger from '../common/logger';
1313
import { Protocol } from '../common/protocol';
14-
import { parseRepositoryRemotes, Remote } from '../common/remote';
14+
import { parseRepositoryRemotesAsync, Remote } from '../common/remote';
1515
import { PR_SETTINGS_NAMESPACE, PULL_PR_BRANCH_BEFORE_CHECKOUT, PullPRBranchVariants } from '../common/settingKeys';
1616

1717
const PullRequestRemoteMetadataKey = 'github-pr-remote';
@@ -343,14 +343,14 @@ export class PullRequestGitHelper {
343343
static async createRemote(repository: Repository, baseRemote: Remote, cloneUrl: Protocol) {
344344
Logger.appendLine(`create remote for ${cloneUrl}.`, PullRequestGitHelper.ID);
345345

346-
const remotes = parseRepositoryRemotes(repository);
346+
const remotes = await parseRepositoryRemotesAsync(repository);
347347
for (const remote of remotes) {
348348
if (new Protocol(remote.url).equals(cloneUrl)) {
349349
return remote.remoteName;
350350
}
351351
}
352352

353-
const remoteName = PullRequestGitHelper.getUniqueRemoteName(repository, cloneUrl.owner);
353+
const remoteName = await PullRequestGitHelper.getUniqueRemoteName(repository, cloneUrl.owner);
354354
cloneUrl.update({
355355
type: baseRemote.gitProtocol.type,
356356
});
@@ -390,10 +390,10 @@ export class PullRequestGitHelper {
390390
return result;
391391
}
392392

393-
static getUniqueRemoteName(repository: Repository, name: string) {
393+
static async getUniqueRemoteName(repository: Repository, name: string) {
394394
let uniqueName = name;
395395
let number = 1;
396-
const remotes = parseRepositoryRemotes(repository);
396+
const remotes = await parseRepositoryRemotesAsync(repository);
397397

398398
// eslint-disable-next-line no-loop-func
399399
while (remotes.find(e => e.remoteName === uniqueName)) {

src/issues/stateManager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { CurrentIssue } from './currentIssue';
99
import { Repository } from '../api/api';
1010
import { GitApiImpl } from '../api/api1';
1111
import { AuthProvider } from '../common/authentication';
12-
import { parseRepositoryRemotes } from '../common/remote';
12+
import { parseRepositoryRemotesAsync } from '../common/remote';
1313
import {
1414
DEFAULT,
1515
DEV_MODE,
@@ -321,7 +321,7 @@ export class StateManager {
321321
return;
322322
}
323323
singleRepoState.issueCollection.clear();
324-
const enterpriseRemotes = parseRepositoryRemotes(folderManager.repository).filter(
324+
const enterpriseRemotes = (await parseRepositoryRemotesAsync(folderManager.repository)).filter(
325325
remote => remote.isEnterprise
326326
);
327327
const user = await this.getCurrentUser(enterpriseRemotes.length ? AuthProvider.githubEnterprise : AuthProvider.github);

src/test/common/remote.test.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { default as assert } from 'assert';
7+
import { parseRepositoryRemotesAsync } from '../../common/remote';
8+
import { MockRepository } from '../mocks/mockRepository';
9+
10+
describe('parseRepositoryRemotesAsync', () => {
11+
it('resolves a remote URL using a global "url.<base>.insteadOf" alias', async () => {
12+
const repository = new MockRepository();
13+
// Simulate `git config url."https://github.abc.com/".insteadOf github:`
14+
await repository.setConfig('url.https://github.abc.com/.insteadof', 'github:');
15+
// And a remote stored as `github:org/repo` (as returned by `git config --get remote.origin.url`
16+
// when the user clones with `git clone github:org/repo`).
17+
await repository.addRemote('origin', 'github:org/repo');
18+
19+
const remotes = await parseRepositoryRemotesAsync(repository);
20+
21+
assert.strictEqual(remotes.length, 1);
22+
assert.strictEqual(remotes[0].remoteName, 'origin');
23+
assert.strictEqual(remotes[0].host, 'github.abc.com');
24+
assert.strictEqual(remotes[0].owner, 'org');
25+
assert.strictEqual(remotes[0].repositoryName, 'repo');
26+
});
27+
28+
it('applies the longest matching insteadOf prefix when multiple match', async () => {
29+
const repository = new MockRepository();
30+
await repository.setConfig('url.https://short.example.com/.insteadof', 'gh:');
31+
await repository.setConfig('url.https://long.example.com/.insteadof', 'gh:org/');
32+
await repository.addRemote('origin', 'gh:org/repo');
33+
34+
const remotes = await parseRepositoryRemotesAsync(repository);
35+
36+
assert.strictEqual(remotes.length, 1);
37+
assert.strictEqual(remotes[0].host, 'long.example.com');
38+
assert.strictEqual(remotes[0].repositoryName, 'repo');
39+
});
40+
41+
it('leaves URLs unchanged when no insteadOf alias matches', async () => {
42+
const repository = new MockRepository();
43+
await repository.setConfig('url.https://github.abc.com/.insteadof', 'github:');
44+
await repository.addRemote('origin', 'https://github.com/owner/repo');
45+
46+
const remotes = await parseRepositoryRemotesAsync(repository);
47+
48+
assert.strictEqual(remotes.length, 1);
49+
assert.strictEqual(remotes[0].host, 'github.com');
50+
assert.strictEqual(remotes[0].owner, 'owner');
51+
assert.strictEqual(remotes[0].repositoryName, 'repo');
52+
});
53+
});

0 commit comments

Comments
 (0)