Skip to content

Commit a58c357

Browse files
pvdlgsbekrin
authored andcommitted
feat: set name/email of commit author and committer via Git env var
BREAKING CHANGE: the `GIT_USERNAME` and `GIT_EMAIL` environment variables are replaced by the [Git environment variables](https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables#_committing) `GIT_AUTHOR_NAME`, `GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME` and `GIT_COMMITTER_EMAIL`. Co-authored-by: Sergey Bekrin <sergey@bekrin.me>
1 parent 8fcb054 commit a58c357

File tree

10 files changed

+48
-65
lines changed

10 files changed

+48
-65
lines changed

README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ Create a release commit, including configurable files.
1919

2020
## Configuration
2121

22-
### Environment variables
23-
24-
| Variable | Description | Default |
25-
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
26-
| `GIT_USERNAME` | [Git username](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup#_your_identity) associated with the release commit. | @semantic-release-bot. |
27-
| `GIT_EMAIL` | [Git email address](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup#_your_identity) associated with the release commit. | @semantic-release-bot email address. |
22+
## Environment variables
23+
24+
| Variable | Description | Default |
25+
|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------|
26+
| `GIT_AUTHOR_NAME` | The author name associated with the release commit. See [Git environment variables](https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables#_committing). | @semantic-release-bot. |
27+
| `GIT_AUTHOR_EMAIL` | The author email associated with the release commit. See [Git environment variables](https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables#_committing). | @semantic-release-bot email address. |
28+
| `GIT_COMMITTER_NAME` | The committer name associated with the release commit. See [Git environment variables](https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables#_committing). | @semantic-release-bot. |
29+
| `GIT_COMMITTER_EMAIL` | The committer email associated with the release commit. See [Git environment variables](https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables#_committing). | @semantic-release-bot email address. |
2830

2931
### Options
3032

lib/git.js

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,6 @@ async function add(files) {
2424
debug('add file to git index', shell);
2525
}
2626

27-
/**
28-
* Set Git configuration.
29-
*
30-
* @param {String} name Config name.
31-
* @param {String} value Config value.
32-
*/
33-
async function config(name, value) {
34-
await execa('git', ['config', name, value]);
35-
}
36-
3727
/**
3828
* Commit to the local repository.
3929
*
@@ -62,4 +52,4 @@ async function gitHead() {
6252
return execa.stdout('git', ['rev-parse', 'HEAD']);
6353
}
6454

65-
module.exports = {getModifiedFiles, add, config, gitHead, commit, push};
55+
module.exports = {getModifiedFiles, add, gitHead, commit, push};

lib/prepare.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const dirGlob = require('dir-glob');
55
const pReduce = require('p-reduce');
66
const debug = require('debug')('semantic-release:git');
77
const resolveConfig = require('./resolve-config');
8-
const {getModifiedFiles, add, config, commit, push} = require('./git');
8+
const {getModifiedFiles, add, commit, push} = require('./git');
99

1010
const CHANGELOG = 'CHANGELOG.md';
1111
const PKG_JSON = 'package.json';
@@ -18,16 +18,14 @@ const SKW_JSON = 'npm-shrinkwrap.json';
1818
* @param {Object} pluginConfig The plugin configuration.
1919
* @param {String|Array<String>} [pluginConfig.assets] Files to include in the release commit. Can be files path or globs.
2020
* @param {String} [pluginConfig.message] The message for the release commit.
21-
* @param {String} [pluginConfig.gitUserName] The username to use for commiting (git `user.name` config).
22-
* @param {String} [pluginConfig.gitUserEmail] The email to use for commiting (git `user.email` config).
2321
* @param {Object} context semantic-release context.
2422
* @param {Object} context.options `semantic-release` configuration.
2523
* @param {Object} context.lastRelease The last release.
2624
* @param {Object} context.nextRelease The next release.
2725
* @param {Object} logger Global logger.
2826
*/
2927
module.exports = async (pluginConfig, {options: {branch, repositoryUrl}, lastRelease, nextRelease, logger}) => {
30-
const {gitUserEmail, gitUserName, message, assets} = resolveConfig(pluginConfig);
28+
const {message, assets} = resolveConfig(pluginConfig, logger);
3129
const patterns = [];
3230
const modifiedFiles = await getModifiedFiles();
3331

@@ -76,8 +74,6 @@ module.exports = async (pluginConfig, {options: {branch, repositoryUrl}, lastRel
7674
if (filesToCommit.length > 0) {
7775
logger.log('Found %d file(s) to commit', filesToCommit.length);
7876
await add(filesToCommit);
79-
await config('user.email', gitUserEmail);
80-
await config('user.name', gitUserName);
8177
debug('commited files: %o', filesToCommit);
8278
await commit(
8379
message

lib/resolve-config.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
11
const {castArray} = require('lodash');
22

3-
module.exports = ({message, assets}) => ({
4-
gitUserName: process.env.GIT_USERNAME || 'semantic-release-bot',
5-
gitUserEmail: process.env.GIT_EMAIL || 'semantic-release-bot@martynus.net',
6-
message,
7-
assets: assets ? castArray(assets) : assets,
8-
});
3+
module.exports = ({message, assets}) => ({message, assets: assets ? castArray(assets) : assets});

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
"all": true
7575
},
7676
"peerDependencies": {
77-
"semantic-release": ">=15.0.0 <16.0.0"
77+
"semantic-release": ">=15.4.0 <16.0.0"
7878
},
7979
"prettier": {
8080
"printWidth": 120,

test/git.test.js

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import test from 'ava';
22
import {outputFile, appendFile} from 'fs-extra';
3-
import {add, getModifiedFiles, config, commit, gitHead, push} from '../lib/git';
4-
import {gitRepo, gitCommits, gitGetCommits, gitGetConfig, gitStaged, gitRemoteHead} from './helpers/git-utils';
3+
import {add, getModifiedFiles, commit, gitHead, push} from '../lib/git';
4+
import {gitRepo, gitCommits, gitGetCommits, gitStaged, gitRemoteHead} from './helpers/git-utils';
55

66
// Save the current working diretory
77
const cwd = process.cwd();
@@ -50,15 +50,6 @@ test.serial('Returns [] if there is no modified files', async t => {
5050
await t.deepEqual(await getModifiedFiles(), []);
5151
});
5252

53-
test.serial('Set git config', async t => {
54-
// Create a git repository, set the current working directory at the root of the repo
55-
await gitRepo();
56-
// Add config
57-
await config('user.name', 'username');
58-
59-
await t.is(await gitGetConfig('user.name'), 'username');
60-
});
61-
6253
test.serial('Commit added files', async t => {
6354
// Create a git repository, set the current working directory at the root of the repo
6455
await gitRepo();

test/helpers/git-utils.js

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -110,17 +110,6 @@ export async function gitShallowClone(origin, branch = 'master', depth = 1) {
110110
return dir;
111111
}
112112

113-
/**
114-
* Get Git configuration.
115-
*
116-
* @param {String} name Config name.
117-
*
118-
* @returns {String} The config's value.
119-
*/
120-
export async function gitGetConfig(name) {
121-
return execa.stdout('git', ['config', '--get', name]);
122-
}
123-
124113
/**
125114
* @return {Array<String>} Array of staged files path.
126115
*/

test/integration.test.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ test.beforeEach(t => {
2323
delete process.env.GH_TOKEN;
2424
delete process.env.GITHUB_TOKEN;
2525
delete process.env.GIT_CREDENTIALS;
26-
delete process.env.GIT_EMAIL;
27-
delete process.env.GIT_USERNAME;
26+
delete process.env.GIT_AUTHOR_NAME;
27+
delete process.env.GIT_AUTHOR_EMAIL;
28+
delete process.env.GIT_COMMITTER_NAME;
29+
delete process.env.GIT_COMMITTER_EMAIL;
2830
// Clear npm cache to refresh the module state
2931
clearModule('..');
3032
t.context.m = require('..');
@@ -41,8 +43,6 @@ test.afterEach.always(() => {
4143
});
4244

4345
test.serial('Prepare from a shallow clone', async t => {
44-
process.env.GIT_EMAIL = 'user@email.com';
45-
process.env.GIT_USERNAME = 'user';
4646
const branch = 'master';
4747
const repositoryUrl = await gitRepo(true);
4848
await outputFile('package.json', "{name: 'test-package', version: '1.0.0'}");
@@ -69,8 +69,6 @@ test.serial('Prepare from a shallow clone', async t => {
6969
t.is(commit.subject, `Release version ${nextRelease.version} from branch ${branch}`);
7070
t.is(commit.body, `${nextRelease.notes}\n`);
7171
t.is(commit.gitTags, `(HEAD -> ${branch})`);
72-
t.is(commit.author.name, process.env.GIT_USERNAME);
73-
t.is(commit.author.email, process.env.GIT_EMAIL);
7472
});
7573

7674
test.serial('Prepare from a detached head repository', async t => {

test/prepare.test.js

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ test.beforeEach(async t => {
1212
delete process.env.GH_TOKEN;
1313
delete process.env.GITHUB_TOKEN;
1414
delete process.env.GIT_CREDENTIALS;
15-
delete process.env.GIT_EMAIL;
16-
delete process.env.GIT_USERNAME;
15+
delete process.env.GIT_AUTHOR_NAME;
16+
delete process.env.GIT_AUTHOR_EMAIL;
17+
delete process.env.GIT_COMMITTER_NAME;
18+
delete process.env.GIT_COMMITTER_EMAIL;
1719
// Stub the logger functions
1820
t.context.log = stub();
1921
t.context.logger = {log: t.context.log};
@@ -51,9 +53,6 @@ test.serial(
5153
t.is(commit.body, `${nextRelease.notes}\n`);
5254
t.is(commit.gitTags, `(HEAD -> ${t.context.branch})`);
5355

54-
t.is(commit.author.name, 'semantic-release-bot');
55-
t.is(commit.author.email, 'semantic-release-bot@martynus.net');
56-
5756
t.deepEqual(t.context.log.args[0], ['Add %s to the release commit', 'CHANGELOG.md']);
5857
t.deepEqual(t.context.log.args[1], ['Add %s to the release commit', 'package.json']);
5958
t.deepEqual(t.context.log.args[2], ['Add %s to the release commit', 'package-lock.json']);
@@ -191,6 +190,27 @@ test.serial('Commit files matching the patterns in "assets", including dot files
191190
t.deepEqual(t.context.log.args[0], ['Found %d file(s) to commit', 1]);
192191
});
193192

193+
test.serial('Set the commit author and committer name/email based on environment variables', async t => {
194+
process.env.GIT_AUTHOR_NAME = 'author name';
195+
process.env.GIT_AUTHOR_EMAIL = 'author email';
196+
process.env.GIT_COMMITTER_NAME = 'committer name';
197+
process.env.GIT_COMMITTER_EMAIL = 'committer email';
198+
const lastRelease = {version: 'v1.0.0'};
199+
const nextRelease = {version: '2.0.0', gitTag: 'v2.0.0', notes: 'Test release note'};
200+
await outputFile('CHANGELOG.md', 'Initial CHANGELOG');
201+
202+
await prepare({}, {options: t.context.options, lastRelease, nextRelease, logger: t.context.logger});
203+
204+
// Verify the files that have been commited
205+
t.deepEqual(await gitCommitedFiles(), ['CHANGELOG.md']);
206+
// Verify the commit message contains on the new release notes
207+
const [commit] = await gitGetCommits();
208+
t.is(commit.author.name, 'author name');
209+
t.is(commit.author.email, 'author email');
210+
t.is(commit.committer.name, 'committer name');
211+
t.is(commit.committer.email, 'committer email');
212+
});
213+
194214
test.serial('Skip negated pattern if its alone in its group', async t => {
195215
const pluginConfig = {assets: ['!**/*', 'file.js']};
196216
const lastRelease = {};

test/verify.test.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ test.beforeEach(t => {
1313
delete process.env.GH_TOKEN;
1414
delete process.env.git_TOKEN;
1515
delete process.env.GIT_CREDENTIALS;
16-
delete process.env.GIT_EMAIL;
17-
delete process.env.GIT_USERNAME;
16+
delete process.env.GIT_AUTHOR_NAME;
17+
delete process.env.GIT_AUTHOR_EMAIL;
18+
delete process.env.GIT_COMMITTER_NAME;
19+
delete process.env.GIT_COMMITTER_EMAIL;
1820
// Stub the logger functions
1921
t.context.log = stub();
2022
t.context.logger = {log: t.context.log};

0 commit comments

Comments
 (0)