Skip to content

Commit 98aa126

Browse files
committed
Adds AI rebase commands
(#4443)
1 parent 6426093 commit 98aa126

File tree

15 files changed

+213
-12
lines changed

15 files changed

+213
-12
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
88

99
### Added
1010

11-
- Adds AI powered operations for a branch: "Explain Unpushed Changed". They are added to the _Commit Graph_ and views context menu for branches ([#4443](https://github.com/gitkraken/vscode-gitlens/issues/4443))
11+
- Adds AI powered operations for a branch: "Recompose branch commits", "Recompose unpushed commits", "Explain Unpushed Changed". They are added to the _Commit Graph_ and views context menu for branches ([#4443](https://github.com/gitkraken/vscode-gitlens/issues/4443))
1212

1313
### Fixed
1414

contributions.json

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,58 @@
2323
]
2424
}
2525
},
26+
"gitlens.ai.aiRebaseBranch:graph": {
27+
"label": "AI Recompose Branch Commits (Preview)",
28+
"icon": "$(sparkle)",
29+
"menus": {
30+
"webview/context": [
31+
{
32+
"when": "webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+recomposable\\b)/ && !listMultiSelection && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled",
33+
"group": "1_gitlens_actions",
34+
"order": 6
35+
}
36+
]
37+
}
38+
},
39+
"gitlens.ai.aiRebaseBranch:views": {
40+
"label": "AI Recompose Branch Commits (Preview)",
41+
"icon": "$(sparkle)",
42+
"menus": {
43+
"view/item/context": [
44+
{
45+
"when": "viewItem =~ /gitlens:branch\\b(?=.*?\\b\\+recomposable\\b)/ && !listMultiSelection && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled",
46+
"group": "1_gitlens_actions",
47+
"order": 6
48+
}
49+
]
50+
}
51+
},
52+
"gitlens.ai.aiRebaseUnpushed:graph": {
53+
"label": "AI Recompose Unpushed Commits (Preview)",
54+
"icon": "$(sparkle)",
55+
"menus": {
56+
"webview/context": [
57+
{
58+
"when": "webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+ahead\\b)/ && !listMultiSelection && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled",
59+
"group": "1_gitlens_actions",
60+
"order": 7
61+
}
62+
]
63+
}
64+
},
65+
"gitlens.ai.aiRebaseUnpushed:views": {
66+
"label": "AI Recompose Unpushed Commits (Preview)",
67+
"icon": "$(sparkle)",
68+
"menus": {
69+
"view/item/context": [
70+
{
71+
"when": "viewItem =~ /gitlens:branch\\b(?=.*?\\b\\+ahead\\b)/ && !listMultiSelection && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled",
72+
"group": "1_gitlens_actions",
73+
"order": 7
74+
}
75+
]
76+
}
77+
},
2678
"gitlens.ai.explainBranch": {
2779
"label": "Explain Branch Changes (Preview)...",
2880
"commandPalette": "gitlens:enabled && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled"

docs/links.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ _{prefix}/integrations/connect(&integration={integration})_
320320
- _github_ - Connects the GitHub integration.
321321
- _gitlab_ - Connects the GitLab integration.
322322
- _bitbucket_ - Connects the Bitbucket integration.
323-
- _azureDevOps_ - Connects the Azure DevOps integration.
323+
- _azuredevOps_ - Connects the Azure DevOps integration.
324324
- _jira_ - Connects the Jira integration.
325325
- _linear_ - Connects the Linear integration.
326326
- _trello_ - Connects the Trello integration.

package.json

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6189,6 +6189,26 @@
61896189
"category": "GitLens",
61906190
"icon": "$(person-add)"
61916191
},
6192+
{
6193+
"command": "gitlens.ai.aiRebaseBranch:graph",
6194+
"title": "AI Recompose Branch Commits (Preview)",
6195+
"icon": "$(sparkle)"
6196+
},
6197+
{
6198+
"command": "gitlens.ai.aiRebaseBranch:views",
6199+
"title": "AI Recompose Branch Commits (Preview)",
6200+
"icon": "$(sparkle)"
6201+
},
6202+
{
6203+
"command": "gitlens.ai.aiRebaseUnpushed:graph",
6204+
"title": "AI Recompose Unpushed Commits (Preview)",
6205+
"icon": "$(sparkle)"
6206+
},
6207+
{
6208+
"command": "gitlens.ai.aiRebaseUnpushed:views",
6209+
"title": "AI Recompose Unpushed Commits (Preview)",
6210+
"icon": "$(sparkle)"
6211+
},
61926212
{
61936213
"command": "gitlens.ai.explainBranch",
61946214
"title": "Explain Branch Changes (Preview)...",
@@ -11014,6 +11034,22 @@
1101411034
"command": "gitlens.addAuthors",
1101511035
"when": "gitlens:enabled && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders"
1101611036
},
11037+
{
11038+
"command": "gitlens.ai.aiRebaseBranch:graph",
11039+
"when": "false"
11040+
},
11041+
{
11042+
"command": "gitlens.ai.aiRebaseBranch:views",
11043+
"when": "false"
11044+
},
11045+
{
11046+
"command": "gitlens.ai.aiRebaseUnpushed:graph",
11047+
"when": "false"
11048+
},
11049+
{
11050+
"command": "gitlens.ai.aiRebaseUnpushed:views",
11051+
"when": "false"
11052+
},
1101711053
{
1101811054
"command": "gitlens.ai.explainBranch",
1101911055
"when": "gitlens:enabled && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled"
@@ -17410,6 +17446,16 @@
1741017446
"when": "viewItem =~ /gitlens:branch\\b(?=.*?\\b\\+(remote|tracking)\\b)(?!.*?\\b\\+closed\\b)/ && !listMultiSelection && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:repos:withRemotes",
1741117447
"group": "1_gitlens_actions@3"
1741217448
},
17449+
{
17450+
"command": "gitlens.ai.aiRebaseBranch:views",
17451+
"when": "viewItem =~ /gitlens:branch\\b(?=.*?\\b\\+recomposable\\b)/ && !listMultiSelection && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled",
17452+
"group": "1_gitlens_actions@6"
17453+
},
17454+
{
17455+
"command": "gitlens.ai.aiRebaseUnpushed:views",
17456+
"when": "viewItem =~ /gitlens:branch\\b(?=.*?\\b\\+ahead\\b)/ && !listMultiSelection && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled",
17457+
"group": "1_gitlens_actions@7"
17458+
},
1741317459
{
1741417460
"command": "gitlens.views.mergeBranchInto",
1741517461
"when": "viewItem =~ /gitlens:branch\\b(?!.*?\\b\\+current\\b)(?!.*?\\b\\+closed\\b)/ && !listMultiSelection && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders",
@@ -23287,6 +23333,16 @@
2328723333
"when": "webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+(remote|tracking)\\b)(?!.*?\\b\\+closed\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:repos:withRemotes",
2328823334
"group": "1_gitlens_actions@3"
2328923335
},
23336+
{
23337+
"command": "gitlens.ai.aiRebaseBranch:graph",
23338+
"when": "webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+recomposable\\b)/ && !listMultiSelection && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled",
23339+
"group": "1_gitlens_actions@6"
23340+
},
23341+
{
23342+
"command": "gitlens.ai.aiRebaseUnpushed:graph",
23343+
"when": "webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+ahead\\b)/ && !listMultiSelection && !gitlens:readonly && !gitlens:untrusted && gitlens:gk:organization:ai:enabled",
23344+
"group": "1_gitlens_actions@7"
23345+
},
2329023346
{
2329123347
"command": "gitlens.graph.mergeBranchInto",
2329223348
"when": "webviewItem =~ /gitlens:branch\\b(?!.*?\\b\\+current\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders",

src/commands/toggleFileAnnotations.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ export class ClearFileAnnotationsCommand extends EditorCommand {
2929

3030
// Clear split editors as though they were linked, because we can't handle the command states effectively
3131
await Promise.allSettled(
32-
// eslint-disable-next-line @typescript-eslint/await-thenable
3332
[editor, ...getOtherVisibleTextEditors(editor)].map(e => this.container.fileAnnotations.clear(e)),
3433
);
3534
} catch (ex) {

src/constants.commands.generated.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
export type ContributedCommands =
55
| ContributedKeybindingCommands
66
| ContributedPaletteCommands
7+
| 'gitlens.ai.aiRebaseBranch:graph'
8+
| 'gitlens.ai.aiRebaseBranch:views'
9+
| 'gitlens.ai.aiRebaseUnpushed:graph'
10+
| 'gitlens.ai.aiRebaseUnpushed:views'
711
| 'gitlens.ai.explainBranch:graph'
812
| 'gitlens.ai.explainBranch:views'
913
| 'gitlens.ai.explainCommit:graph'

src/git/remotes/remoteProvider.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,6 @@ export abstract class RemoteProvider<T extends ResourceDescriptor = ResourceDesc
234234
} else {
235235
urlPromises.push(this.url(resource));
236236
}
237-
// eslint-disable-next-line @typescript-eslint/await-thenable
238237
const urls: string[] = (await Promise.allSettled(urlPromises))
239238
.map(r => getSettledValue(r))
240239
.filter(r => r != null);

src/plus/ai/aiProviderService.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,6 +1708,7 @@ export class AIProviderService implements Disposable {
17081708
setLogScopeExit(
17091709
scope,
17101710
`model: ${model.provider.id}/${model.id}`,
1711+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
17111712
`failed: ${String(ex)} (${String(ex.original)})`,
17121713
);
17131714

@@ -1717,6 +1718,7 @@ export class AIProviderService implements Disposable {
17171718
...telementry.data,
17181719
duration: Date.now() - start,
17191720
failed: true,
1721+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
17201722
'failed.error': String(ex),
17211723
'failed.error.detail': String(ex.original),
17221724
},

src/system/promise.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,6 @@ export function getDeferredPromiseIfPending<T>(deferred: Deferred<T> | undefined
200200
export type MaybePromiseArr<T> = (Promise<T | undefined> | T | undefined)[];
201201

202202
export async function nonnullSettled<T>(arr: MaybePromiseArr<T>): Promise<T[]> {
203-
// eslint-disable-next-line @typescript-eslint/await-thenable
204203
const all = await Promise.allSettled(arr);
205204
return all.map(r => getSettledValue(r)).filter(v => v != null);
206205
}
@@ -451,7 +450,6 @@ export async function pauseOnCancelOrTimeoutMapTuple<Id, T, U extends unknown[]>
451450
}
452451

453452
const results = await Promise.all(
454-
// eslint-disable-next-line @typescript-eslint/await-thenable
455453
map(source, ([id, [promise, ...rest]]) =>
456454
promise == null
457455
? ([id, [undefined, ...rest]] as const)

src/views/nodes/branchNode.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ export class BranchNode
394394
useBaseNameOnly: !(this.view.config.branches?.layout !== 'tree' || this.compacted || this.avoidCompacting),
395395
worktree: this.worktree,
396396
worktreesByBranch: this.context.worktreesByBranch,
397+
isRecomposable: Boolean(this.mergeBase),
397398
});
398399

399400
// TODO@axosoft-ramint Temporary workaround, remove when our git commands work on closed repos.
@@ -519,6 +520,7 @@ export async function getBranchNodeParts(
519520
useBaseNameOnly: boolean;
520521
worktree?: GitWorktree;
521522
worktreesByBranch?: Map<string, GitWorktree>;
523+
isRecomposable?: boolean;
522524
},
523525
): Promise<{
524526
label: string;
@@ -718,6 +720,10 @@ export async function getBranchNodeParts(
718720
iconPath = getBranchIconPath(container, branch);
719721
}
720722

723+
if (options?.isRecomposable) {
724+
contextValue += '+recomposable';
725+
}
726+
721727
return {
722728
label: label,
723729
description: description,

0 commit comments

Comments
 (0)