Skip to content

Commit

Permalink
#399 Sign Commits and Tags created by actions in the Git Graph View.
Browse files Browse the repository at this point in the history
  • Loading branch information
mhutchie committed Nov 7, 2020
1 parent 25379ee commit fbff6a5
Show file tree
Hide file tree
Showing 5 changed files with 417 additions and 30 deletions.
10 changes: 10 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,16 @@
"default": true,
"description": "Show untracked files when viewing the uncommitted changes. If you work on large repositories, disabling this setting can reduce the load time of the Git Graph View."
},
"git-graph.repository.sign.commits": {
"type": "boolean",
"default": false,
"description": "Enables commit signing with GPG or X.509."
},
"git-graph.repository.sign.tags": {
"type": "boolean",
"default": false,
"description": "Enables tag signing with GPG or X.509."
},
"git-graph.repository.useMailmap": {
"type": "boolean",
"default": false,
Expand Down
14 changes: 14 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,20 @@ class Config {
return !!this.getRenamedExtensionSetting('repository.showUntrackedFiles', 'showUntrackedFiles', true);
}

/**
* Get the value of the `git-graph.repository.sign.commits` Extension Setting.
*/
get signCommits() {
return !!this.config.get('repository.sign.commits', false);
}

/**
* Get the value of the `git-graph.repository.sign.tags` Extension Setting.
*/
get signTags() {
return !!this.config.get('repository.sign.tags', false);
}

/**
* Get the value of the `git-graph.repository.useMailmap` Extension Setting.
*/
Expand Down
94 changes: 67 additions & 27 deletions src/dataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -633,8 +633,10 @@ export class DataSource extends Disposable {
* @returns The ErrorInfo from the executed command.
*/
public addTag(repo: string, tagName: string, commitHash: string, lightweight: boolean, message: string) {
let args = ['tag'];
if (lightweight) {
const args = ['tag'];
if (getConfig().signTags) {
args.push('-s', tagName, '-m', message);
} else if (lightweight) {
args.push(tagName);
} else {
args.push('-a', tagName, '-m', message);
Expand Down Expand Up @@ -848,13 +850,18 @@ export class DataSource extends Disposable {
* @returns The ErrorInfo from the executed command.
*/
public pullBranch(repo: string, branchName: string, remote: string, createNewCommit: boolean, squash: boolean) {
let args = ['pull', remote, branchName];
if (squash) args.push('--squash');
else if (createNewCommit) args.push('--no-ff');

const args = ['pull', remote, branchName], config = getConfig();
if (squash) {
args.push('--squash');
} else if (createNewCommit) {
args.push('--no-ff');
}
if (config.signCommits) {
args.push('-S');
}
return this.runGitCommand(args, repo).then((pullStatus) => {
return pullStatus === null && squash
? this.commitSquashIfStagedChangesExist(repo, remote + '/' + branchName, MergeActionOn.Branch, getConfig().squashPullMessageFormat)
? this.commitSquashIfStagedChangesExist(repo, remote + '/' + branchName, MergeActionOn.Branch, config.squashPullMessageFormat, config.signCommits)
: pullStatus;
});
}
Expand Down Expand Up @@ -884,16 +891,21 @@ export class DataSource extends Disposable {
* @returns The ErrorInfo from the executed command.
*/
public merge(repo: string, obj: string, actionOn: MergeActionOn, createNewCommit: boolean, squash: boolean, noCommit: boolean) {
let args = ['merge', obj];

if (squash) args.push('--squash');
else if (createNewCommit) args.push('--no-ff');

if (noCommit) args.push('--no-commit');

const args = ['merge', obj], config = getConfig();
if (squash) {
args.push('--squash');
} else if (createNewCommit) {
args.push('--no-ff');
}
if (noCommit) {
args.push('--no-commit');
}
if (config.signCommits) {
args.push('-S');
}
return this.runGitCommand(args, repo).then((mergeStatus) => {
return mergeStatus === null && squash && !noCommit
? this.commitSquashIfStagedChangesExist(repo, obj, actionOn, getConfig().squashMergeMessageFormat)
? this.commitSquashIfStagedChangesExist(repo, obj, actionOn, config.squashMergeMessageFormat, config.signCommits)
: mergeStatus;
});
}
Expand All @@ -911,12 +923,17 @@ export class DataSource extends Disposable {
if (interactive) {
return this.openGitTerminal(
repo,
'rebase --interactive ' + (actionOn === RebaseActionOn.Branch ? obj.replace(/'/g, '"\'"') : obj),
'rebase --interactive ' + (getConfig().signCommits ? '-S ' : '') + (actionOn === RebaseActionOn.Branch ? obj.replace(/'/g, '"\'"') : obj),
'Rebase on "' + (actionOn === RebaseActionOn.Branch ? obj : abbrevCommit(obj)) + '"'
);
} else {
let args = ['rebase', obj];
if (ignoreDate) args.push('--ignore-date');
const args = ['rebase', obj];
if (ignoreDate) {
args.push('--ignore-date');
}
if (getConfig().signCommits) {
args.push('-S');
}
return this.runGitCommand(args, repo);
}
}
Expand Down Expand Up @@ -959,10 +976,19 @@ export class DataSource extends Disposable {
* @returns The ErrorInfo from the executed command.
*/
public cherrypickCommit(repo: string, commitHash: string, parentIndex: number, recordOrigin: boolean, noCommit: boolean) {
let args = ['cherry-pick'];
if (noCommit) args.push('--no-commit');
if (recordOrigin) args.push('-x');
if (parentIndex > 0) args.push('-m', parentIndex.toString());
const args = ['cherry-pick'];
if (noCommit) {
args.push('--no-commit');
}
if (recordOrigin) {
args.push('-x');
}
if (getConfig().signCommits) {
args.push('-S');
}
if (parentIndex > 0) {
args.push('-m', parentIndex.toString());
}
args.push(commitHash);
return this.runGitCommand(args, repo);
}
Expand All @@ -974,7 +1000,12 @@ export class DataSource extends Disposable {
* @returns The ErrorInfo from the executed command.
*/
public dropCommit(repo: string, commitHash: string) {
return this.runGitCommand(['rebase', '--onto', commitHash + '^', commitHash], repo);
const args = ['rebase'];
if (getConfig().signCommits) {
args.push('-S');
}
args.push('--onto', commitHash + '^', commitHash);
return this.runGitCommand(args, repo);
}

/**
Expand All @@ -996,8 +1027,14 @@ export class DataSource extends Disposable {
* @returns The ErrorInfo from the executed command.
*/
public revertCommit(repo: string, commitHash: string, parentIndex: number) {
let args = ['revert', '--no-edit', commitHash];
if (parentIndex > 0) args.push('-m', parentIndex.toString());
const args = ['revert', '--no-edit'];
if (getConfig().signCommits) {
args.push('-S');
}
if (parentIndex > 0) {
args.push('-m', parentIndex.toString());
}
args.push(commitHash);
return this.runGitCommand(args, repo);
}

Expand Down Expand Up @@ -1468,10 +1505,13 @@ export class DataSource extends Disposable {
* @param squashMessageFormat The format to be used in the commit message of the squash.
* @returns The ErrorInfo from the executed command.
*/
private commitSquashIfStagedChangesExist(repo: string, obj: string, actionOn: MergeActionOn, squashMessageFormat: SquashMessageFormat): Promise<ErrorInfo> {
private commitSquashIfStagedChangesExist(repo: string, obj: string, actionOn: MergeActionOn, squashMessageFormat: SquashMessageFormat, signCommits: boolean): Promise<ErrorInfo> {
return this.areStagedChanges(repo).then((changes) => {
if (changes) {
let args = ['commit'];
const args = ['commit'];
if (signCommits) {
args.push('-S');
}
if (squashMessageFormat === SquashMessageFormat.Default) {
args.push('-m', 'Merge ' + actionOn.toLowerCase() + ' \'' + obj + '\'');
} else {
Expand Down
124 changes: 124 additions & 0 deletions tests/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3665,6 +3665,130 @@ describe('Config', () => {
});
});

describe('signCommits', () => {
it('Should return TRUE when the configuration value is TRUE', () => {
// Setup
workspaceConfiguration.get.mockReturnValueOnce(true);

// Run
const value = config.signCommits;

// Assert
expect(workspaceConfiguration.get).toBeCalledWith('repository.sign.commits', false);
expect(value).toBe(true);
});

it('Should return FALSE when the configuration value is FALSE', () => {
// Setup
workspaceConfiguration.get.mockReturnValueOnce(false);

// Run
const value = config.signCommits;

// Assert
expect(workspaceConfiguration.get).toBeCalledWith('repository.sign.commits', false);
expect(value).toBe(false);
});

it('Should return TRUE when the configuration value is truthy', () => {
// Setup
workspaceConfiguration.get.mockReturnValueOnce(5);

// Run
const value = config.signCommits;

// Assert
expect(workspaceConfiguration.get).toBeCalledWith('repository.sign.commits', false);
expect(value).toBe(true);
});

it('Should return FALSE when the configuration value is falsy', () => {
// Setup
workspaceConfiguration.get.mockReturnValueOnce(0);

// Run
const value = config.signCommits;

// Assert
expect(workspaceConfiguration.get).toBeCalledWith('repository.sign.commits', false);
expect(value).toBe(false);
});

it('Should return the default value (TRUE) when the configuration value is not set', () => {
// Setup
workspaceConfiguration.get.mockImplementationOnce((_, defaultValue) => defaultValue);

// Run
const value = config.signCommits;

// Assert
expect(workspaceConfiguration.get).toBeCalledWith('repository.sign.commits', false);
expect(value).toBe(false);
});
});

describe('signTags', () => {
it('Should return TRUE when the configuration value is TRUE', () => {
// Setup
workspaceConfiguration.get.mockReturnValueOnce(true);

// Run
const value = config.signTags;

// Assert
expect(workspaceConfiguration.get).toBeCalledWith('repository.sign.tags', false);
expect(value).toBe(true);
});

it('Should return FALSE when the configuration value is FALSE', () => {
// Setup
workspaceConfiguration.get.mockReturnValueOnce(false);

// Run
const value = config.signTags;

// Assert
expect(workspaceConfiguration.get).toBeCalledWith('repository.sign.tags', false);
expect(value).toBe(false);
});

it('Should return TRUE when the configuration value is truthy', () => {
// Setup
workspaceConfiguration.get.mockReturnValueOnce(5);

// Run
const value = config.signTags;

// Assert
expect(workspaceConfiguration.get).toBeCalledWith('repository.sign.tags', false);
expect(value).toBe(true);
});

it('Should return FALSE when the configuration value is falsy', () => {
// Setup
workspaceConfiguration.get.mockReturnValueOnce(0);

// Run
const value = config.signTags;

// Assert
expect(workspaceConfiguration.get).toBeCalledWith('repository.sign.tags', false);
expect(value).toBe(false);
});

it('Should return the default value (TRUE) when the configuration value is not set', () => {
// Setup
workspaceConfiguration.get.mockImplementationOnce((_, defaultValue) => defaultValue);

// Run
const value = config.signTags;

// Assert
expect(workspaceConfiguration.get).toBeCalledWith('repository.sign.tags', false);
expect(value).toBe(false);
});
});

describe('useMailmap', () => {
it('Should return TRUE when the configuration value is TRUE', () => {
// Setup
Expand Down

0 comments on commit fbff6a5

Please sign in to comment.