Skip to content

Commit efa3eb3

Browse files
committed
Substitutes repository of the selected issue
(#3621)
1 parent d2ff189 commit efa3eb3

File tree

4 files changed

+80
-3
lines changed

4 files changed

+80
-3
lines changed

src/git/models/issue.ts

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
import { ColorThemeKind, ThemeColor, ThemeIcon, window } from 'vscode';
1+
import { ColorThemeKind, ThemeColor, ThemeIcon, Uri, window } from 'vscode';
2+
import { Schemes } from '../../constants';
23
import type { Colors } from '../../constants.colors';
4+
import type { Container } from '../../container';
5+
import type { RepositoryIdentityDescriptor } from '../../gk/models/repositoryIdentities';
36
import type { ProviderReference } from './remoteProvider';
7+
import type { Repository } from './repository';
48

59
export type IssueOrPullRequestType = 'issue' | 'pullrequest';
610
export type IssueOrPullRequestState = 'opened' | 'closed' | 'merged';
@@ -45,6 +49,7 @@ export interface IssueRepository {
4549
owner: string;
4650
repo: string;
4751
accessLevel?: RepositoryAccessLevel;
52+
url?: string;
4853
}
4954

5055
export interface IssueShape extends IssueOrPullRequest {
@@ -217,6 +222,7 @@ export function serializeIssue(value: IssueShape): IssueShape {
217222
: {
218223
owner: value.repository.owner,
219224
repo: value.repository.repo,
225+
url: value.repository.url,
220226
},
221227
assignees: value.assignees.map(assignee => ({
222228
id: assignee.id,
@@ -261,3 +267,67 @@ export class Issue implements IssueShape {
261267
public readonly body?: string,
262268
) {}
263269
}
270+
271+
export type IssueRepositoryIdentityDescriptor = RequireSomeWithProps<
272+
RequireSome<RepositoryIdentityDescriptor<string>, 'provider'>,
273+
'provider',
274+
'id' | 'domain' | 'repoDomain' | 'repoName'
275+
> &
276+
RequireSomeWithProps<RequireSome<RepositoryIdentityDescriptor<string>, 'remote'>, 'remote', 'domain'>;
277+
278+
export function getRepositoryIdentityForIssue(issue: IssueShape | Issue): IssueRepositoryIdentityDescriptor {
279+
if (issue.repository == null) throw new Error('Missing repository');
280+
281+
return {
282+
remote: {
283+
url: issue.repository.url,
284+
domain: issue.provider.domain,
285+
},
286+
name: `${issue.repository.owner}/${issue.repository.repo}`,
287+
provider: {
288+
id: issue.provider.id,
289+
domain: issue.provider.domain,
290+
repoDomain: issue.repository.owner,
291+
repoName: issue.repository.repo,
292+
repoOwnerDomain: issue.repository.owner,
293+
},
294+
};
295+
}
296+
297+
export function getVirtualUriForIssue(issue: IssueShape | Issue): Uri | undefined {
298+
if (issue.repository == null) throw new Error('Missing repository');
299+
if (issue.provider.id !== 'github') return undefined;
300+
301+
const uri = Uri.parse(issue.repository.url ?? issue.url);
302+
return uri.with({ scheme: Schemes.Virtual, authority: 'github', path: uri.path });
303+
}
304+
305+
export async function getOrOpenIssueRepository(
306+
container: Container,
307+
issue: IssueShape | Issue,
308+
options?: { promptIfNeeded?: boolean; skipVirtual?: boolean },
309+
): Promise<Repository | undefined> {
310+
const identity = getRepositoryIdentityForIssue(issue);
311+
let repo = await container.repositoryIdentity.getRepository(identity, {
312+
openIfNeeded: true,
313+
keepOpen: false,
314+
prompt: false,
315+
});
316+
317+
if (repo == null && !options?.skipVirtual) {
318+
const virtualUri = getVirtualUriForIssue(issue);
319+
if (virtualUri != null) {
320+
repo = await container.git.getOrOpenRepository(virtualUri, { closeOnOpen: true, detectNested: false });
321+
}
322+
}
323+
324+
if (repo == null && options?.promptIfNeeded) {
325+
repo = await container.repositoryIdentity.getRepository(identity, {
326+
openIfNeeded: true,
327+
keepOpen: false,
328+
prompt: true,
329+
});
330+
}
331+
332+
return repo;
333+
}

src/plus/integrations/providers/github/github.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ repository {
190190
login
191191
}
192192
viewerPermission
193+
url
193194
}
194195
`;
195196

src/plus/integrations/providers/github/models.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ export interface GitHubIssue extends Omit<GitHubIssueOrPullRequest, '__typename'
133133
login: string;
134134
};
135135
viewerPermission: GitHubViewerPermission;
136+
url: string;
136137
};
137138
body: string;
138139
}
@@ -421,6 +422,7 @@ export function fromGitHubIssue(value: GitHubIssue, provider: Provider): Issue {
421422
owner: value.repository.owner.login,
422423
repo: value.repository.name,
423424
accessLevel: fromGitHubViewerPermissionToAccessLevel(value.repository.viewerPermission),
425+
url: value.repository.url,
424426
},
425427
value.assignees.nodes.map(assignee => ({
426428
id: assignee.login,

src/plus/startWork/startWork.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { HostingIntegrationId } from '../../constants.integrations';
2424
import type { Source, Sources, StartWorkTelemetryContext } from '../../constants.telemetry';
2525
import type { Container } from '../../container';
2626
import type { SearchedIssue } from '../../git/models/issue';
27+
import { getOrOpenIssueRepository } from '../../git/models/issue';
2728
import type { QuickPickItemOfT } from '../../quickpicks/items/common';
2829
import { createQuickPickItemOfT, createQuickPickSeparator } from '../../quickpicks/items/common';
2930
import type { DirectiveQuickPickItem } from '../../quickpicks/items/directive';
@@ -152,6 +153,9 @@ export class StartWorkCommand extends QuickCommand<State> {
152153
state.action = result;
153154
}
154155

156+
const issue = state.item.item.issue;
157+
const repo = await getOrOpenIssueRepository(this.container, issue);
158+
155159
if (typeof state.action === 'string') {
156160
switch (state.action) {
157161
case 'start':
@@ -161,8 +165,8 @@ export class StartWorkCommand extends QuickCommand<State> {
161165
command: 'branch',
162166
state: {
163167
subcommand: 'create',
164-
repo: undefined,
165-
name: slug(`${state.item.item.issue.id}-${state.item.item.issue.title}`),
168+
repo: repo,
169+
name: slug(`${issue.id}-${issue.title}`),
166170
suggestNameOnly: true,
167171
},
168172
},

0 commit comments

Comments
 (0)