Skip to content

Commit 864a1e1

Browse files
4039 Launchpad view can cause an unwanted "add remote" prompt on load (#4081)
* Fixes remote and open branch matching on base ref * Uses command message node instead of prompt for missing remote * Updates view styling --------- Co-authored-by: Eric Amodio <[email protected]>
1 parent d8adb3f commit 864a1e1

File tree

11 files changed

+118
-35
lines changed

11 files changed

+118
-35
lines changed

contributions.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4817,6 +4817,11 @@
48174817
]
48184818
}
48194819
},
4820+
"gitlens.views.addPullRequestRemote": {
4821+
"label": "Add Pull Request Remote",
4822+
"icon": "$(add)",
4823+
"enablement": "!operationInProgress"
4824+
},
48204825
"gitlens.views.addRemote": {
48214826
"label": "Add Remote...",
48224827
"icon": "$(add)",

package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7648,6 +7648,12 @@
76487648
"title": "Add Co-authors...",
76497649
"icon": "$(person-add)"
76507650
},
7651+
{
7652+
"command": "gitlens.views.addPullRequestRemote",
7653+
"title": "Add Pull Request Remote",
7654+
"icon": "$(add)",
7655+
"enablement": "!operationInProgress"
7656+
},
76517657
{
76527658
"command": "gitlens.views.addRemote",
76537659
"title": "Add Remote...",
@@ -11353,6 +11359,10 @@
1135311359
"command": "gitlens.views.addAuthors",
1135411360
"when": "false"
1135511361
},
11362+
{
11363+
"command": "gitlens.views.addPullRequestRemote",
11364+
"when": "false"
11365+
},
1135611366
{
1135711367
"command": "gitlens.views.addRemote",
1135811368
"when": "false"

src/constants.commands.generated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ export type ContributedCommands =
177177
| 'gitlens.views.addAuthor'
178178
| 'gitlens.views.addAuthor.multi'
179179
| 'gitlens.views.addAuthors'
180+
| 'gitlens.views.addPullRequestRemote'
180181
| 'gitlens.views.addRemote'
181182
| 'gitlens.views.applyChanges'
182183
| 'gitlens.views.associateIssueWithBranch'

src/constants.commands.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ type InternalPlusCommands =
182182
| 'gitlens.plus.showPlans'
183183
| 'gitlens.plus.validate';
184184

185+
type InternalPullRequestViewCommands = 'gitlens.views.addPullRequestRemote';
186+
185187
type InternalScmGroupedViewCommands =
186188
| 'gitlens.views.scm.grouped.welcome.dismiss'
187189
| 'gitlens.views.scm.grouped.welcome.restore';
@@ -221,6 +223,7 @@ type InternalGlCommands =
221223
| InternalHomeWebviewViewCommands
222224
| InternalLaunchPadCommands
223225
| InternalPlusCommands
226+
| InternalPullRequestViewCommands
224227
| InternalScmGroupedViewCommands
225228
| InternalSearchAndCompareViewCommands
226229
| InternalTimelineWebviewViewCommands

src/git/utils/-webview/pullRequest.utils.ts

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { createRevisionRange } from '../revision.utils';
1010
export async function ensurePullRequestRefs(
1111
pr: PullRequest,
1212
repo: Repository,
13-
options?: { promptMessage?: string },
13+
options?: { silent?: true; promptMessage?: never } | { silent?: never; promptMessage?: string },
1414
refs?: PullRequestComparisonRefs,
1515
): Promise<LeftRightCommitCountResult | undefined> {
1616
if (pr.refs == null) return undefined;
@@ -32,7 +32,7 @@ export async function ensurePullRequestRefs(
3232
export async function ensurePullRequestRemote(
3333
pr: PullRequest,
3434
repo: Repository,
35-
options?: { promptMessage?: string },
35+
options?: { silent?: true; promptMessage?: never } | { silent?: never; promptMessage?: string },
3636
): Promise<boolean> {
3737
const identity = getRepositoryIdentityForPullRequest(pr);
3838
if (identity.remote.url == null) return false;
@@ -51,20 +51,22 @@ export async function ensurePullRequestRemote(
5151

5252
const confirm = { title: 'Add Remote' };
5353
const cancel = { title: 'Cancel', isCloseAffordance: true };
54-
const result = await window.showInformationMessage(
55-
`${
56-
options?.promptMessage ?? `Unable to find a remote for PR #${pr.id}.`
57-
}\nWould you like to add a remote for '${identity.provider.repoDomain}?`,
58-
{ modal: true },
59-
confirm,
60-
cancel,
61-
);
62-
63-
if (result === confirm) {
64-
await repo.git
65-
.remotes()
66-
.addRemoteWithResult?.(identity.provider.repoDomain, identity.remote.url, { fetch: true });
67-
return true;
54+
if (!options?.silent) {
55+
const result = await window.showInformationMessage(
56+
`${
57+
options?.promptMessage ?? `Unable to find a remote for PR #${pr.id}.`
58+
}\nWould you like to add a remote for '${identity.provider.repoDomain}?`,
59+
{ modal: true },
60+
confirm,
61+
cancel,
62+
);
63+
64+
if (result === confirm) {
65+
await repo.git
66+
.remotes()
67+
.addRemoteWithResult?.(identity.provider.repoDomain, identity.remote.url, { fetch: true });
68+
return true;
69+
}
6870
}
6971

7072
return false;

src/plus/launchpad/launchpadProvider.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export type LaunchpadItem = LaunchpadPullRequest & {
109109

110110
export type OpenRepository = {
111111
repo: Repository;
112-
remote: GitRemote;
112+
remote?: GitRemote;
113113
localBranch?: GitBranch;
114114
};
115115

@@ -551,12 +551,16 @@ export class LaunchpadProvider implements Disposable {
551551
): Promise<OpenRepository | undefined> {
552552
if (pr.repoIdentity.remote.url == null) return undefined;
553553

554-
const match =
555-
matchingRemoteMap.get(pr.repoIdentity.remote.url) ??
556-
(pr.underlyingPullRequest?.refs?.base?.url
557-
? matchingRemoteMap.get(pr.underlyingPullRequest.refs.base.url)
558-
: undefined);
559-
if (match == null) return undefined;
554+
let match = matchingRemoteMap.get(pr.repoIdentity.remote.url);
555+
if (match == null) {
556+
if (pr.underlyingPullRequest?.refs?.base?.url == null) return undefined;
557+
558+
match = matchingRemoteMap.get(pr.underlyingPullRequest.refs.base.url);
559+
if (match == null) return undefined;
560+
561+
const [repo] = match;
562+
return { repo: repo };
563+
}
560564

561565
const [repo, remote] = match;
562566

src/views/nodes/common.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,10 @@ export class CommandMessageNode extends MessageNode {
5151
description?: string,
5252
tooltip?: string,
5353
iconPath?: TreeItem['iconPath'],
54+
contextValue?: string,
55+
resourceUri?: Uri,
5456
) {
55-
super(view, parent, message, description, tooltip, iconPath);
57+
super(view, parent, message, description, tooltip, iconPath, contextValue, resourceUri);
5658
}
5759

5860
override getTreeItem(): TreeItem | Promise<TreeItem> {

src/views/nodes/pullRequestNode.ts

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { MarkdownString, TreeItem, TreeItemCollapsibleState } from 'vscode';
1+
import { MarkdownString, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode';
2+
import type { Colors } from '../../constants.colors';
23
import { GitUri } from '../../git/gitUri';
34
import { GitBranch } from '../../git/models/branch';
45
import type { GitCommit } from '../../git/models/commit';
@@ -7,16 +8,25 @@ import type { GitBranchReference } from '../../git/models/reference';
78
import type { Repository } from '../../git/models/repository';
89
import { getAheadBehindFilesQuery, getCommitsQuery } from '../../git/queryResults';
910
import { getIssueOrPullRequestMarkdownIcon, getIssueOrPullRequestThemeIcon } from '../../git/utils/-webview/icons';
10-
import { ensurePullRequestRefs, getOrOpenPullRequestRepository } from '../../git/utils/-webview/pullRequest.utils';
11-
import { getComparisonRefsForPullRequest } from '../../git/utils/pullRequest.utils';
11+
import {
12+
ensurePullRequestRefs,
13+
ensurePullRequestRemote,
14+
getOrOpenPullRequestRepository,
15+
} from '../../git/utils/-webview/pullRequest.utils';
16+
import {
17+
getComparisonRefsForPullRequest,
18+
getRepositoryIdentityForPullRequest,
19+
} from '../../git/utils/pullRequest.utils';
1220
import { createRevisionRange } from '../../git/utils/revision.utils';
21+
import { createCommand } from '../../system/-webview/command';
1322
import { pluralize } from '../../system/string';
1423
import type { ViewsWithCommits } from '../viewBase';
24+
import { createViewDecorationUri } from '../viewDecorationProvider';
1525
import { CacheableChildrenViewNode } from './abstract/cacheableChildrenViewNode';
1626
import type { ClipboardType, ViewNode } from './abstract/viewNode';
1727
import { ContextValues, getViewNodeId } from './abstract/viewNode';
1828
import { CodeSuggestionsNode } from './codeSuggestionsNode';
19-
import { MessageNode } from './common';
29+
import { CommandMessageNode, MessageNode } from './common';
2030
import { ResultsCommitsNode } from './resultsCommitsNode';
2131
import { ResultsFilesNode } from './resultsFilesNode';
2232

@@ -159,6 +169,31 @@ export async function getPullRequestChildren(
159169

160170
const repoPath = repo.path;
161171
const refs = getComparisonRefsForPullRequest(repoPath, pullRequest.refs!);
172+
const identity = getRepositoryIdentityForPullRequest(pullRequest);
173+
if (!(await ensurePullRequestRemote(pullRequest, repo, { silent: true }))) {
174+
return [
175+
new CommandMessageNode(
176+
view,
177+
parent,
178+
createCommand<[ViewNode, PullRequest, Repository]>(
179+
'gitlens.views.addPullRequestRemote',
180+
'Add Pull Request Remote...',
181+
parent,
182+
pullRequest,
183+
repo,
184+
),
185+
`Unable to find a remote for '${identity.provider.repoDomain}'`,
186+
undefined,
187+
`Click to add a remote for '${identity.provider.repoDomain}'`,
188+
new ThemeIcon(
189+
'question',
190+
new ThemeColor('gitlens.decorations.workspaceRepoMissingForegroundColor' satisfies Colors),
191+
),
192+
undefined,
193+
createViewDecorationUri('remote', { state: 'missing' }),
194+
),
195+
];
196+
}
162197

163198
const counts = await ensurePullRequestRefs(
164199
pullRequest,

src/views/nodes/remoteNode.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ export class RemoteNode extends ViewNode<'remote', ViewsWithRemotes> {
130130
if (this.remote.default) {
131131
item.contextValue += '+default';
132132
}
133-
item.resourceUri = createViewDecorationUri('remote', { default: this.remote.default });
133+
item.resourceUri = createViewDecorationUri('remote', { state: this.remote.default ? 'default' : undefined });
134134

135135
for (const { type, url } of this.remote.urls) {
136136
tooltip += `\\\n${url} (${type})`;

src/views/viewCommands.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ import * as StashActions from '../git/actions/stash';
2222
import * as TagActions from '../git/actions/tag';
2323
import * as WorktreeActions from '../git/actions/worktree';
2424
import { GitUri } from '../git/gitUri';
25+
import type { PullRequest } from '../git/models/pullRequest';
2526
import { RemoteResourceType } from '../git/models/remoteResource';
27+
import type { Repository } from '../git/models/repository';
2628
import { deletedOrMissing } from '../git/models/revision';
2729
import {
2830
ensurePullRequestRefs,
@@ -238,6 +240,8 @@ export class ViewCommands implements Disposable {
238240
registerViewCommand('gitlens.views.addAuthor', this.addAuthor, this),
239241
registerViewCommand('gitlens.views.addAuthor.multi', this.addAuthor, this, true),
240242

243+
registerViewCommand('gitlens.views.addPullRequestRemote', this.addPullRequestRemote, this),
244+
241245
registerViewCommand(
242246
'gitlens.views.openBranchOnRemote',
243247
n => executeCommand(GlCommand.OpenBranchOnRemote, n),
@@ -481,6 +485,15 @@ export class ViewCommands implements Disposable {
481485
return RemoteActions.add(getNodeRepoPath(node));
482486
}
483487

488+
@log()
489+
private async addPullRequestRemote(node: ViewNode, pr: PullRequest, repo: Repository) {
490+
const identity = getRepositoryIdentityForPullRequest(pr);
491+
if (identity.remote?.url == null) return;
492+
493+
await repo.git.remotes().addRemote?.(identity.provider.repoDomain, identity.remote.url, { fetch: true });
494+
return node.triggerChange(true);
495+
}
496+
484497
@log()
485498
private applyChanges(node: ViewRefFileNode) {
486499
if (node.is('results-file')) {

0 commit comments

Comments
 (0)