forked from microsoft/vscode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpostCommitCommands.ts
More file actions
209 lines (170 loc) · 7.99 KB
/
postCommitCommands.ts
File metadata and controls
209 lines (170 loc) · 7.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Command, commands, Disposable, Event, EventEmitter, Memento, Uri, workspace, l10n } from 'vscode';
import { PostCommitCommandsProvider } from './api/git';
import { Operation, Repository } from './repository';
import { ApiRepository } from './api/api1';
import { dispose } from './util';
export interface IPostCommitCommandsProviderRegistry {
readonly onDidChangePostCommitCommandsProviders: Event<void>;
getPostCommitCommandsProviders(): PostCommitCommandsProvider[];
registerPostCommitCommandsProvider(provider: PostCommitCommandsProvider): Disposable;
}
export class GitPostCommitCommandsProvider implements PostCommitCommandsProvider {
getCommands(apiRepository: ApiRepository): Command[] {
const config = workspace.getConfiguration('git', Uri.file(apiRepository.repository.root));
// Branch protection
const isBranchProtected = apiRepository.repository.isBranchProtected();
const branchProtectionPrompt = config.get<'alwaysCommit' | 'alwaysCommitToNewBranch' | 'alwaysPrompt'>('branchProtectionPrompt')!;
const alwaysPrompt = isBranchProtected && branchProtectionPrompt === 'alwaysPrompt';
const alwaysCommitToNewBranch = isBranchProtected && branchProtectionPrompt === 'alwaysCommitToNewBranch';
// Icon
const repository = apiRepository.repository;
const isCommitInProgress = repository.operations.isRunning(Operation.Commit) || repository.operations.isRunning(Operation.PostCommitCommand);
const icon = isCommitInProgress ? '$(sync~spin)' : alwaysPrompt ? '$(lock)' : alwaysCommitToNewBranch ? '$(git-branch)' : undefined;
// Tooltip (default)
let pushCommandTooltip = !alwaysCommitToNewBranch ?
l10n.t('Commit & Push Changes') :
l10n.t('Commit to New Branch & Push Changes');
let syncCommandTooltip = !alwaysCommitToNewBranch ?
l10n.t('Commit & Sync Changes') :
l10n.t('Commit to New Branch & Synchronize Changes');
// Tooltip (in progress)
if (isCommitInProgress) {
pushCommandTooltip = !alwaysCommitToNewBranch ?
l10n.t('Committing & Pushing Changes...') :
l10n.t('Committing to New Branch & Pushing Changes...');
syncCommandTooltip = !alwaysCommitToNewBranch ?
l10n.t('Committing & Synchronizing Changes...') :
l10n.t('Committing to New Branch & Synchronizing Changes...');
}
return [
{
command: 'git.push',
title: l10n.t('{0} Commit & Push', icon ?? '$(arrow-up)'),
tooltip: pushCommandTooltip
},
{
command: 'git.sync',
title: l10n.t('{0} Commit & Sync', icon ?? '$(sync)'),
tooltip: syncCommandTooltip
},
];
}
}
export class CommitCommandsCenter {
private _onDidChange = new EventEmitter<void>();
get onDidChange(): Event<void> { return this._onDidChange.event; }
private disposables: Disposable[] = [];
set postCommitCommand(command: string | null | undefined) {
if (command === undefined) {
// Commit WAS NOT initiated using the action button
// so there is no need to store the post-commit command
return;
}
this.globalState.update(this.repository.root, command)
.then(() => this._onDidChange.fire());
}
constructor(
private readonly globalState: Memento,
private readonly repository: Repository,
private readonly postCommitCommandsProviderRegistry: IPostCommitCommandsProviderRegistry
) {
const root = Uri.file(repository.root);
const onRememberPostCommitCommandChange = async () => {
const config = workspace.getConfiguration('git', root);
if (!config.get<boolean>('rememberPostCommitCommand')) {
await this.globalState.update(repository.root, undefined);
}
};
this.disposables.push(workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('git.rememberPostCommitCommand', root)) {
onRememberPostCommitCommandChange();
}
}));
onRememberPostCommitCommandChange();
this.disposables.push(postCommitCommandsProviderRegistry.onDidChangePostCommitCommandsProviders(() => this._onDidChange.fire()));
}
getPrimaryCommand(): Command {
const allCommands = this.getSecondaryCommands().map(c => c).flat();
const commandFromStorage = allCommands.find(c => c.arguments?.length === 2 && c.arguments[1] === this.getPostCommitCommandStringFromStorage());
const commandFromSetting = allCommands.find(c => c.arguments?.length === 2 && c.arguments[1] === this.getPostCommitCommandStringFromSetting());
return commandFromStorage ?? commandFromSetting ?? this.getCommitCommand();
}
getSecondaryCommands(): Command[][] {
const commandGroups: Command[][] = [];
for (const provider of this.postCommitCommandsProviderRegistry.getPostCommitCommandsProviders()) {
const commands = provider.getCommands(new ApiRepository(this.repository));
commandGroups.push((commands ?? []).map(c => {
return { command: 'git.commit', title: c.title, tooltip: c.tooltip, arguments: [this.repository.sourceControl, c.command] };
}));
}
if (commandGroups.length > 0) {
commandGroups[0].splice(0, 0, this.getCommitCommand());
}
return commandGroups;
}
async executePostCommitCommand(command: string | null | undefined): Promise<void> {
try {
if (command === null) {
// No post-commit command
return;
}
if (command === undefined) {
// Commit WAS NOT initiated using the action button (ex: keybinding, toolbar action,
// command palette) so we have to honour the default post commit command (memento/setting).
const primaryCommand = this.getPrimaryCommand();
command = primaryCommand.arguments?.length === 2 ? primaryCommand.arguments[1] : null;
}
if (command !== null) {
await commands.executeCommand(command!.toString(), new ApiRepository(this.repository));
}
} catch (err) {
throw err;
}
finally {
if (!this.isRememberPostCommitCommandEnabled()) {
await this.globalState.update(this.repository.root, undefined);
this._onDidChange.fire();
}
}
}
private getCommitCommand(): Command {
const config = workspace.getConfiguration('git', Uri.file(this.repository.root));
// Branch protection
const isBranchProtected = this.repository.isBranchProtected();
const branchProtectionPrompt = config.get<'alwaysCommit' | 'alwaysCommitToNewBranch' | 'alwaysPrompt'>('branchProtectionPrompt')!;
const alwaysPrompt = isBranchProtected && branchProtectionPrompt === 'alwaysPrompt';
const alwaysCommitToNewBranch = isBranchProtected && branchProtectionPrompt === 'alwaysCommitToNewBranch';
// Icon
const icon = alwaysPrompt ? '$(lock)' : alwaysCommitToNewBranch ? '$(git-branch)' : undefined;
// Tooltip (default)
let tooltip = !alwaysCommitToNewBranch ?
l10n.t('Commit Changes') :
l10n.t('Commit Changes to New Branch');
// Tooltip (in progress)
if (this.repository.operations.isRunning(Operation.Commit)) {
tooltip = !alwaysCommitToNewBranch ?
l10n.t('Committing Changes...') :
l10n.t('Committing Changes to New Branch...');
}
return { command: 'git.commit', title: l10n.t('{0} Commit', icon ?? '$(check)'), tooltip, arguments: [this.repository.sourceControl, null] };
}
private getPostCommitCommandStringFromSetting(): string | undefined {
const config = workspace.getConfiguration('git', Uri.file(this.repository.root));
const postCommitCommandSetting = config.get<string>('postCommitCommand');
return postCommitCommandSetting === 'push' || postCommitCommandSetting === 'sync' ? `git.${postCommitCommandSetting}` : undefined;
}
private getPostCommitCommandStringFromStorage(): string | null | undefined {
return this.globalState.get<string | null>(this.repository.root);
}
private isRememberPostCommitCommandEnabled(): boolean {
const config = workspace.getConfiguration('git', Uri.file(this.repository.root));
return config.get<boolean>('rememberPostCommitCommand') === true;
}
dispose(): void {
this.disposables = dispose(this.disposables);
}
}