Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Git - Add setting to remember post commit command #158449

Merged
merged 4 commits into from Aug 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions extensions/git/package.json
Expand Up @@ -2176,6 +2176,12 @@
"scope": "resource",
"default": "none"
},
"git.rememberPostCommitCommand": {
"type": "boolean",
"description": "%config.rememberPostCommitCommand%",
"scope": "resource",
"default": false
},
"git.openAfterClone": {
"type": "string",
"enum": [
Expand Down
7 changes: 4 additions & 3 deletions extensions/git/package.nls.json
Expand Up @@ -162,10 +162,11 @@
"config.promptToSaveFilesBeforeCommit.always": "Check for any unsaved files.",
"config.promptToSaveFilesBeforeCommit.staged": "Check only for unsaved staged files.",
"config.promptToSaveFilesBeforeCommit.never": "Disable this check.",
"config.postCommitCommand": "Runs a git command after a successful commit.",
"config.postCommitCommand": "Run a git command after a successful commit.",
"config.postCommitCommand.none": "Don't run any command after a commit.",
"config.postCommitCommand.push": "Run 'Git Push' after a successful commit.",
"config.postCommitCommand.sync": "Run 'Git Sync' after a successful commit.",
"config.postCommitCommand.push": "Run 'git push' after a successful commit.",
"config.postCommitCommand.sync": "Run 'git pull' and 'git push' after a successful commit.",
"config.rememberPostCommitCommand": "Remember the last git command that ran after a commit.",
"config.openAfterClone": "Controls whether to open a repository automatically after cloning.",
"config.openAfterClone.always": "Always open in current window.",
"config.openAfterClone.alwaysNewWindow": "Always open in a new window.",
Expand Down
106 changes: 22 additions & 84 deletions extensions/git/src/actionButton.ts
Expand Up @@ -5,9 +5,8 @@

import * as nls from 'vscode-nls';
import { Command, Disposable, Event, EventEmitter, SourceControlActionButton, Uri, workspace } from 'vscode';
import { ApiRepository } from './api/api1';
import { Branch, Status } from './api/git';
import { IPostCommitCommandsProviderRegistry } from './postCommitCommands';
import { Branch, CommitCommand, Status } from './api/git';
import { CommitCommandsCenter } from './postCommitCommands';
import { Repository, Operation } from './repository';
import { dispose } from './util';

Expand Down Expand Up @@ -39,7 +38,7 @@ export class ActionButtonCommand {

constructor(
readonly repository: Repository,
readonly postCommitCommandsProviderRegistry: IPostCommitCommandsProviderRegistry) {
readonly postCommitCommandCenter: CommitCommandsCenter) {
this._state = {
HEAD: undefined,
isCommitInProgress: false,
Expand All @@ -52,7 +51,7 @@ export class ActionButtonCommand {
repository.onDidRunGitStatus(this.onDidRunGitStatus, this, this.disposables);
repository.onDidChangeOperations(this.onDidChangeOperations, this, this.disposables);

this.disposables.push(postCommitCommandsProviderRegistry.onDidChangePostCommitCommandsProviders(() => this._onDidChange.fire()));
this.disposables.push(postCommitCommandCenter.onDidChange(() => this._onDidChange.fire()));

const root = Uri.file(repository.root);
this.disposables.push(workspace.onDidChangeConfiguration(e => {
Expand All @@ -65,6 +64,7 @@ export class ActionButtonCommand {
if (e.affectsConfiguration('git.branchProtection', root) ||
e.affectsConfiguration('git.branchProtectionPrompt', root) ||
e.affectsConfiguration('git.postCommitCommand', root) ||
e.affectsConfiguration('git.rememberPostCommitCommand', root) ||
e.affectsConfiguration('git.showActionButton', root)) {
this._onDidChange.fire();
}
Expand Down Expand Up @@ -92,14 +92,17 @@ export class ActionButtonCommand {
// The button is disabled
if (!showActionButton.commit) { return undefined; }

const primaryCommand = this.getCommitActionButtonPrimaryCommand();

return {
command: this.getCommitActionButtonPrimaryCommand(),
command: primaryCommand,
secondaryCommands: this.getCommitActionButtonSecondaryCommands(),
description: primaryCommand.description ?? primaryCommand.title,
enabled: (this.state.repositoryHasChangesToCommit || this.state.isRebaseInProgress) && !this.state.isCommitInProgress && !this.state.isMergeInProgress
};
}

private getCommitActionButtonPrimaryCommand(): Command {
private getCommitActionButtonPrimaryCommand(): CommitCommand {
// Rebase Continue
if (this.state.isRebaseInProgress) {
return {
Expand All @@ -111,87 +114,22 @@ export class ActionButtonCommand {
}

// Commit
const config = workspace.getConfiguration('git', Uri.file(this.repository.root));
const postCommitCommand = config.get<string>('postCommitCommand');

// 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;

let commandArg = '';
let title = localize('scm button commit title', "{0} Commit", icon ?? '$(check)');
let tooltip = this.state.isCommitInProgress ? localize('scm button committing tooltip', "Committing Changes...") : localize('scm button commit tooltip', "Commit Changes");

// Title, tooltip
switch (postCommitCommand) {
case 'push': {
commandArg = 'git.push';
title = localize('scm button commit and push title', "{0} Commit & Push", icon ?? '$(arrow-up)');
if (alwaysCommitToNewBranch) {
tooltip = this.state.isCommitInProgress ?
localize('scm button committing to new branch and pushing tooltip', "Committing to New Branch & Pushing Changes...") :
localize('scm button commit to new branch and push tooltip', "Commit to New Branch & Push Changes");
} else {
tooltip = this.state.isCommitInProgress ?
localize('scm button committing and pushing tooltip', "Committing & Pushing Changes...") :
localize('scm button commit and push tooltip', "Commit & Push Changes");
}
break;
}
case 'sync': {
commandArg = 'git.sync';
title = localize('scm button commit and sync title', "{0} Commit & Sync", icon ?? '$(sync)');
if (alwaysCommitToNewBranch) {
tooltip = this.state.isCommitInProgress ?
localize('scm button committing to new branch and synching tooltip', "Committing to New Branch & Synching Changes...") :
localize('scm button commit to new branch and sync tooltip', "Commit to New Branch & Sync Changes");
} else {
tooltip = this.state.isCommitInProgress ?
localize('scm button committing and synching tooltip', "Committing & Synching Changes...") :
localize('scm button commit and sync tooltip', "Commit & Sync Changes");
}
break;
}
default: {
if (alwaysCommitToNewBranch) {
tooltip = this.state.isCommitInProgress ?
localize('scm button committing to new branch tooltip', "Committing Changes to New Branch...") :
localize('scm button commit to new branch tooltip', "Commit Changes to New Branch");
}
break;
}
}

return { command: 'git.commit', title, tooltip, arguments: [this.repository.sourceControl, commandArg] };
return this.postCommitCommandCenter.getPrimaryCommand();
}

private getCommitActionButtonSecondaryCommands(): Command[][] {
const commandGroups: Command[][] = [];

if (!this.state.isRebaseInProgress) {
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,
arguments: [this.repository.sourceControl, c.command]
};
}));
}
// Rebase Continue
if (this.state.isRebaseInProgress) {
return [];
}

if (commandGroups.length > 0) {
commandGroups[0].splice(0, 0, {
command: 'git.commit',
title: localize('scm secondary button commit', "Commit"),
arguments: [this.repository.sourceControl, '']
});
}
// Commit
const commandGroups: Command[][] = [];
for (const commands of this.postCommitCommandCenter.getSecondaryCommands()) {
commandGroups.push(commands.map(c => {
// Use the description as title if present
return { command: 'git.commit', title: c.description ?? c.title, tooltip: c.tooltip, arguments: c.arguments };
}));
}

return commandGroups;
Expand Down
4 changes: 3 additions & 1 deletion extensions/git/src/api/git.d.ts
Expand Up @@ -254,8 +254,10 @@ export interface CredentialsProvider {
getCredentials(host: Uri): ProviderResult<Credentials>;
}

export type CommitCommand = Command & { description?: string };

export interface PostCommitCommandsProvider {
getCommands(repository: Repository): Command[];
getCommands(repository: Repository): CommitCommand[];
}

export interface PushErrorHandler {
Expand Down
14 changes: 0 additions & 14 deletions extensions/git/src/commands.ts
Expand Up @@ -1634,20 +1634,6 @@ export class CommandCenter {

await repository.commit(message, opts);

// Execute post-commit command
let postCommitCommand = opts.postCommitCommand;

if (postCommitCommand === undefined) {
// Commit WAS NOT initiated using the action button (ex: keybinding, toolbar
// action, command palette) so we honour the `git.postCommitCommand` setting.
const postCommitCommandSetting = config.get<string>('postCommitCommand');
postCommitCommand = postCommitCommandSetting === 'push' || postCommitCommandSetting === 'sync' ? `git.${postCommitCommandSetting}` : '';
}

if (postCommitCommand.length) {
await commands.executeCommand(postCommitCommand, new ApiRepository(repository));
}

return true;
}

Expand Down