diff --git a/src/vs/workbench/parts/git/browser/gitActions.ts b/src/vs/workbench/parts/git/browser/gitActions.ts index 8917069d086..fedfd8ee312 100644 --- a/src/vs/workbench/parts/git/browser/gitActions.ts +++ b/src/vs/workbench/parts/git/browser/gitActions.ts @@ -736,6 +736,24 @@ export class CommitAction extends BaseCommitAction { } +export class CommitSignedOffAction extends BaseCommitAction { + + static ID = 'workbench.action.git.commitSignedOff'; + + constructor(commitState: ICommitState, @IGitService gitService: IGitService) { + super(commitState, CommitAction.ID, nls.localize('commitStagedSignedOff', "Commit Staged (Signed Off)"), 'git-action commit-signed-off', gitService); + } + + public run(context?: any):Promise { + if (!this.commitState.getCommitMessage()) { + this.commitState.onEmptyCommitMessage(); + return TPromise.as(null); + } + + return this.gitService.commit(this.commitState.getCommitMessage(), undefined, undefined, true); + } +} + export class InputCommitAction extends GitAction { static ID = 'workbench.action.git.input-commit'; @@ -809,6 +827,39 @@ export class StageAndCommitAction extends BaseCommitAction { } } +export class StageAndCommitSignedOffAction extends BaseCommitAction { + + static ID = 'workbench.action.git.stageAndCommitSignedOff'; + + constructor(commitState: ICommitState, @IGitService gitService: IGitService) { + super(commitState, StageAndCommitAction.ID, nls.localize('commitAllSignedOff', "Commit All (Signed Off)"), 'git-action stage-and-commit-signed-off', gitService); + } + + protected isEnabled():boolean { + if (!this.gitService) { + return false; + } + + if (!this.gitService.isIdle()) { + return false; + } + + var status = this.gitService.getModel().getStatus(); + + return status.getIndexStatus().all().length > 0 + || status.getWorkingTreeStatus().all().length > 0; + } + + public run(context?: any):Promise { + if (!this.commitState.getCommitMessage()) { + this.commitState.onEmptyCommitMessage(); + return TPromise.as(null); + } + + return this.gitService.commit(this.commitState.getCommitMessage(), false, true, true); + } +} + export class SmartCommitAction extends BaseCommitAction { static ID = 'workbench.action.git.commitAll'; diff --git a/src/vs/workbench/parts/git/browser/gitServices.ts b/src/vs/workbench/parts/git/browser/gitServices.ts index dc1e1fe6428..c5672b0e1a5 100644 --- a/src/vs/workbench/parts/git/browser/gitServices.ts +++ b/src/vs/workbench/parts/git/browser/gitServices.ts @@ -687,8 +687,8 @@ export class GitService extends ee.EventEmitter } } - public commit(message:string, amend: boolean = false, stage: boolean = false): winjs.Promise { - return this.run(git.ServiceOperations.COMMIT, () => this.raw.commit(message, amend, stage)); + public commit(message:string, amend: boolean = false, stage: boolean = false, signoff: boolean = false): winjs.Promise { + return this.run(git.ServiceOperations.COMMIT, () => this.raw.commit(message, amend, stage, signoff)); } public getCommitTemplate(): winjs.Promise { diff --git a/src/vs/workbench/parts/git/common/git.ts b/src/vs/workbench/parts/git/common/git.ts index 3bb7bfb6019..370b088e944 100644 --- a/src/vs/workbench/parts/git/common/git.ts +++ b/src/vs/workbench/parts/git/common/git.ts @@ -283,7 +283,7 @@ export interface IRawGitService { pull(rebase?: boolean): TPromise; push(remote?: string, name?: string, options?:IPushOptions): TPromise; sync(): TPromise; - commit(message:string, amend?: boolean, stage?: boolean): TPromise; + commit(message:string, amend?: boolean, stage?: boolean, signoff?: boolean): TPromise; detectMimetypes(path: string, treeish?: string): TPromise; show(path: string, treeish?: string): TPromise; getCommitTemplate(): TPromise; @@ -311,7 +311,7 @@ export interface IGitService extends IEventEmitter { pull(rebase?: boolean): TPromise; push(remote?: string, name?: string, options?:IPushOptions): TPromise; sync(): TPromise; - commit(message:string, amend?: boolean, stage?: boolean): TPromise; + commit(message:string, amend?: boolean, stage?: boolean, signoff?: boolean): TPromise; detectMimetypes(path: string, treeish?: string): TPromise; buffer(path: string, treeish?: string): TPromise; diff --git a/src/vs/workbench/parts/git/common/gitIpc.ts b/src/vs/workbench/parts/git/common/gitIpc.ts index b7e8caf9c56..0984e0a85f4 100644 --- a/src/vs/workbench/parts/git/common/gitIpc.ts +++ b/src/vs/workbench/parts/git/common/gitIpc.ts @@ -83,7 +83,7 @@ export interface IGitChannel extends IChannel { call(command: 'pull', rebase?: boolean): TPromise; call(command: 'push', args: [string, string, IPushOptions]): TPromise; call(command: 'sync'): TPromise; - call(command: 'commit', args: [string, boolean, boolean]): TPromise; + call(command: 'commit', args: [string, boolean, boolean, boolean]): TPromise; call(command: 'detectMimetypes', args: [string, string]): TPromise; call(command: 'show', args: [string, string]): TPromise; call(command: 'onOutput'): TPromise; @@ -114,7 +114,7 @@ export class GitChannel implements IGitChannel { case 'pull': return this.service.then(s => s.pull(args)).then(RawStatusSerializer.to); case 'push': return this.service.then(s => s.push(args[0], args[1], args[2])).then(RawStatusSerializer.to); case 'sync': return this.service.then(s => s.sync()).then(RawStatusSerializer.to); - case 'commit': return this.service.then(s => s.commit(args[0], args[1], args[2])).then(RawStatusSerializer.to); + case 'commit': return this.service.then(s => s.commit(args[0], args[1], args[2], args[3])).then(RawStatusSerializer.to); case 'detectMimetypes': return this.service.then(s => s.detectMimetypes(args[0], args[1])); case 'show': return this.service.then(s => s.show(args[0], args[1])); case 'onOutput': return this.service.then(s => eventToCall(s.onOutput)); @@ -208,8 +208,8 @@ export class GitChannelClient implements IRawGitService { return this.channel.call('sync').then(RawStatusSerializer.from); } - commit(message:string, amend?: boolean, stage?: boolean): TPromise { - return this.channel.call('commit', [message, amend, stage]).then(RawStatusSerializer.from); + commit(message:string, amend?: boolean, stage?: boolean, signoff?: boolean): TPromise { + return this.channel.call('commit', [message, amend, stage, signoff]).then(RawStatusSerializer.from); } detectMimetypes(path: string, treeish?: string): TPromise { diff --git a/src/vs/workbench/parts/git/common/noopGitService.ts b/src/vs/workbench/parts/git/common/noopGitService.ts index 572fe151c73..62ca30bd6ae 100644 --- a/src/vs/workbench/parts/git/common/noopGitService.ts +++ b/src/vs/workbench/parts/git/common/noopGitService.ts @@ -90,7 +90,7 @@ export class NoOpGitService implements IRawGitService { return TPromise.as(NoOpGitService.STATUS); } - commit(message: string, amend?: boolean, stage?: boolean): TPromise { + commit(message: string, amend?: boolean, stage?: boolean, signoff?: boolean): TPromise { return TPromise.as(NoOpGitService.STATUS); } diff --git a/src/vs/workbench/parts/git/node/git.lib.ts b/src/vs/workbench/parts/git/node/git.lib.ts index 25868a7d082..3492ae4d6dd 100644 --- a/src/vs/workbench/parts/git/node/git.lib.ts +++ b/src/vs/workbench/parts/git/node/git.lib.ts @@ -411,7 +411,7 @@ export class Repository { }); } - commit(message: string, all: boolean, amend: boolean): Promise { + commit(message: string, all: boolean, amend: boolean, signoff: boolean): Promise { const args = ['commit', '--quiet', '--allow-empty-message', '--file', '-']; if (all) { @@ -422,6 +422,10 @@ export class Repository { args.push('--amend'); } + if (signoff) { + args.push('--signoff'); + } + return this.run(args, { input: message || '' }).then(null, (commitErr: GitError) => { if (/not possible because you have unmerged files/.test(commitErr.stderr)) { commitErr.gitErrorCode = GitErrorCodes.UnmergedChanges; diff --git a/src/vs/workbench/parts/git/node/rawGitService.ts b/src/vs/workbench/parts/git/node/rawGitService.ts index 92514243b8b..4c3c4db373e 100644 --- a/src/vs/workbench/parts/git/node/rawGitService.ts +++ b/src/vs/workbench/parts/git/node/rawGitService.ts @@ -150,7 +150,7 @@ export class RawGitService implements IRawGitService { return this.repo.sync().then(() => this.status()); } - commit(message:string, amend?: boolean, stage?: boolean): TPromise { + commit(message:string, amend?: boolean, stage?: boolean, signoff?: boolean): TPromise { let promise: Promise = TPromise.as(null); if (stage) { @@ -158,7 +158,7 @@ export class RawGitService implements IRawGitService { } return promise - .then(() => this.repo.commit(message, stage, amend)) + .then(() => this.repo.commit(message, stage, amend, signoff)) .then(() => this.status()); } @@ -221,7 +221,7 @@ export class DelayedRawGitService implements IRawGitService { pull(rebase?: boolean): TPromise { return this.raw.then(r => r.pull(rebase)); } push(remote?: string, name?: string, options?:IPushOptions): TPromise { return this.raw.then(r => r.push(remote, name, options)); } sync(): TPromise { return this.raw.then(r => r.sync()); } - commit(message:string, amend?: boolean, stage?: boolean): TPromise { return this.raw.then(r => r.commit(message, amend, stage)); } + commit(message:string, amend?: boolean, stage?: boolean, signoff?: boolean): TPromise { return this.raw.then(r => r.commit(message, amend, stage, signoff)); } detectMimetypes(path: string, treeish?: string): TPromise { return this.raw.then(r => r.detectMimetypes(path, treeish)); } show(path: string, treeish?: string): TPromise { return this.raw.then(r => r.show(path, treeish)); } getCommitTemplate(): TPromise { return this.raw.then(r => r.getCommitTemplate()); }