Skip to content

Commit

Permalink
feat: use conventionalcommits as the default preset
Browse files Browse the repository at this point in the history
Nowadays the `conventionalcommits` is the closest thing we have that
looks like a standard and neutral. Also, a new cli option was added:
`--preset`.

BREAKING CHANGE: Previously, the default preset was `angular`. Despite
the similarities, the new one has some differences, such as accepting
exclamation marks (e.g. `feat!:`) for identifying breaking changes. To
restore the previous behavior, use `preset: 'angular'` or the new cli
option, `--preset angular`.

Closes semantic-release#1652
  • Loading branch information
felipecrs committed Jan 17, 2022
1 parent dd7d664 commit ed083e7
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 16 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -49,7 +49,7 @@ This removes the immediate connection between human emotions and version numbers
**semantic-release** uses the commit messages to determine the consumer impact of changes in the codebase.
Following formalized conventions for commit messages, **semantic-release** automatically determines the next [semantic version](https://semver.org) number, generates a changelog and publishes the release.

By default, **semantic-release** uses [Angular Commit Message Conventions](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-format).
By default **semantic-release** uses the [Conventional Commits convention](https://www.conventionalcommits.org/).
The commit message format can be changed with the [`preset` or `config` options](docs/usage/configuration.md#options) of the [@semantic-release/commit-analyzer](https://github.com/semantic-release/commit-analyzer#options) and [@semantic-release/release-notes-generator](https://github.com/semantic-release/release-notes-generator#options) plugins.

Tools such as [commitizen](https://github.com/commitizen/cz-cli) or [commitlint](https://github.com/conventional-changelog/commitlint) can be used to help contributors and enforce valid commit messages.
Expand Down
1 change: 1 addition & 0 deletions cli.js
Expand Up @@ -23,6 +23,7 @@ Usage:
.option('r', {alias: 'repository-url', describe: 'Git repository URL', type: 'string', group: 'Options'})
.option('t', {alias: 'tag-format', describe: 'Git tag format', type: 'string', group: 'Options'})
.option('p', {alias: 'plugins', describe: 'Plugins', ...stringList, group: 'Options'})
.option('preset', {describe: 'Commit message format convention', type: 'string', group: 'Options'})
.option('e', {alias: 'extends', describe: 'Shareable configurations', ...stringList, group: 'Options'})
.option('ci', {describe: 'Toggle CI verifications', type: 'boolean', group: 'Options'})
.option('verify-conditions', {...stringList, group: 'Plugins'})
Expand Down
1 change: 1 addition & 0 deletions lib/get-config.js
Expand Up @@ -70,6 +70,7 @@ module.exports = async (context, cliOptions) => {
'@semantic-release/npm',
'@semantic-release/github',
],
preset: 'conventionalcommits',
// Remove `null` and `undefined` options so they can be replaced with default ones
...pickBy(options, (option) => !isNil(option)),
...(options.branches ? {branches: castArray(options.branches)} : {}),
Expand Down
24 changes: 24 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Expand Up @@ -26,6 +26,7 @@
"@semantic-release/npm": "^8.0.0",
"@semantic-release/release-notes-generator": "^10.0.0",
"aggregate-error": "^3.0.0",
"conventional-changelog-conventionalcommits": "^4.6.3",
"cosmiconfig": "^7.0.0",
"debug": "^4.0.0",
"env-ci": "^5.0.0",
Expand Down
69 changes: 56 additions & 13 deletions test/get-config.test.js
Expand Up @@ -118,7 +118,7 @@ test('Read options from package.json', async (t) => {

const {options: result} = await t.context.getConfig({cwd});

const expected = {...options, branches: ['test_branch']};
const expected = {...options, branches: ['test_branch'], preset: 'conventionalcommits'};
// Verify the options contains the plugin config from package.json
t.deepEqual(result, expected);
// Verify the plugins module is called with the plugin options from package.json
Expand All @@ -140,7 +140,7 @@ test('Read options from .releaserc.yml', async (t) => {

const {options: result} = await t.context.getConfig({cwd});

const expected = {...options, branches: ['test_branch']};
const expected = {...options, branches: ['test_branch'], preset: 'conventionalcommits'};
// Verify the options contains the plugin config from package.json
t.deepEqual(result, expected);
// Verify the plugins module is called with the plugin options from package.json
Expand All @@ -162,7 +162,7 @@ test('Read options from .releaserc.json', async (t) => {

const {options: result} = await t.context.getConfig({cwd});

const expected = {...options, branches: ['test_branch']};
const expected = {...options, branches: ['test_branch'], preset: 'conventionalcommits'};
// Verify the options contains the plugin config from package.json
t.deepEqual(result, expected);
// Verify the plugins module is called with the plugin options from package.json
Expand All @@ -184,7 +184,7 @@ test('Read options from .releaserc.js', async (t) => {

const {options: result} = await t.context.getConfig({cwd});

const expected = {...options, branches: ['test_branch']};
const expected = {...options, branches: ['test_branch'], preset: 'conventionalcommits'};
// Verify the options contains the plugin config from package.json
t.deepEqual(result, expected);
// Verify the plugins module is called with the plugin options from package.json
Expand All @@ -206,7 +206,7 @@ test('Read options from .releaserc.cjs', async (t) => {

const {options: result} = await t.context.getConfig({cwd});

const expected = {...options, branches: ['test_branch']};
const expected = {...options, branches: ['test_branch'], preset: 'conventionalcommits'};
// Verify the options contains the plugin config from .releaserc.cjs
t.deepEqual(result, expected);
// Verify the plugins module is called with the plugin options from .releaserc.cjs
Expand All @@ -228,7 +228,7 @@ test('Read options from release.config.js', async (t) => {

const {options: result} = await t.context.getConfig({cwd});

const expected = {...options, branches: ['test_branch']};
const expected = {...options, branches: ['test_branch'], preset: 'conventionalcommits'};
// Verify the options contains the plugin config from package.json
t.deepEqual(result, expected);
// Verify the plugins module is called with the plugin options from package.json
Expand All @@ -250,7 +250,7 @@ test('Read options from release.config.cjs', async (t) => {

const {options: result} = await t.context.getConfig({cwd});

const expected = {...options, branches: ['test_branch']};
const expected = {...options, branches: ['test_branch'], preset: 'conventionalcommits'};
// Verify the options contains the plugin config from release.config.cjs
t.deepEqual(result, expected);
// Verify the plugins module is called with the plugin options from release.config.cjs
Expand Down Expand Up @@ -280,7 +280,7 @@ test('Prioritise CLI/API parameters over file configuration and git repo', async

const result = await t.context.getConfig({cwd}, options);

const expected = {...options, branches: ['branch_cli']};
const expected = {...options, branches: ['branch_cli'], preset: 'conventionalcommits'};
// Verify the options contains the plugin config from CLI/API
t.deepEqual(result.options, expected);
// Verify the plugins module is called with the plugin options from CLI/API
Expand All @@ -305,7 +305,7 @@ test('Read configuration from file path in "extends"', async (t) => {

const {options: result} = await t.context.getConfig({cwd});

const expected = {...options, branches: ['test_branch']};
const expected = {...options, branches: ['test_branch'], preset: 'conventionalcommits'};
// Verify the options contains the plugin config from shareable.json
t.deepEqual(result, expected);
// Verify the plugins module is called with the plugin options from shareable.json
Expand Down Expand Up @@ -336,7 +336,7 @@ test('Read configuration from module path in "extends"', async (t) => {

const {options: result} = await t.context.getConfig({cwd});

const expected = {...options, branches: ['test_branch']};
const expected = {...options, branches: ['test_branch'], preset: 'conventionalcommits'};
// Verify the options contains the plugin config from shareable.json
t.deepEqual(result, expected);
// Verify the plugins module is called with the plugin options from shareable.json
Expand Down Expand Up @@ -372,7 +372,7 @@ test('Read configuration from an array of paths in "extends"', async (t) => {

const {options: result} = await t.context.getConfig({cwd});

const expected = {...options1, ...options2, branches: ['test_branch']};
const expected = {...options1, ...options2, branches: ['test_branch'], preset: 'conventionalcommits'};
// Verify the options contains the plugin config from shareable1.json and shareable2.json
t.deepEqual(result, expected);
// Verify the plugins module is called with the plugin options from shareable1.json and shareable2.json
Expand Down Expand Up @@ -410,7 +410,7 @@ test('Prioritize configuration from config file over "extends"', async (t) => {

const {options: result} = await t.context.getConfig({cwd});

const expected = omit({...options1, ...pkgOptions, branches: ['test_pkg']}, 'extends');
const expected = omit({...options1, ...pkgOptions, branches: ['test_pkg'], preset: 'conventionalcommits'}, 'extends');
// Verify the options contains the plugin config from package.json and shareable.json
t.deepEqual(result, expected);
// Verify the plugins module is called with the plugin options from package.json and shareable.json
Expand Down Expand Up @@ -458,7 +458,10 @@ test('Prioritize configuration from cli/API options over "extends"', async (t) =

const {options: result} = await t.context.getConfig({cwd}, cliOptions);

const expected = omit({...options2, ...pkgOptions, ...cliOptions, branches: ['branch_opts']}, 'extends');
const expected = omit(
{...options2, ...pkgOptions, ...cliOptions, branches: ['branch_opts'], preset: 'conventionalcommits'},
'extends'
);
// Verify the options contains the plugin config from package.json and shareable2.json
t.deepEqual(result, expected);
// Verify the plugins module is called with the plugin options from package.json and shareable2.json
Expand Down Expand Up @@ -492,13 +495,15 @@ test('Allow to unset properties defined in shareable config with "null"', async
...omit(options1, ['analyzeCommits']),
...omit(pkgOptions, ['extends', 'analyzeCommits']),
plugins: DEFAULT_PLUGINS,
preset: 'conventionalcommits',
});
// Verify the plugins module is called with the plugin options from shareable.json and the default `plugins`
t.deepEqual(t.context.plugins.args[0][0], {
options: {
...omit(options1, 'analyzeCommits'),
...omit(pkgOptions, ['extends', 'analyzeCommits']),
plugins: DEFAULT_PLUGINS,
preset: 'conventionalcommits',
},
cwd,
});
Expand Down Expand Up @@ -535,6 +540,7 @@ test('Allow to unset properties defined in shareable config with "undefined"', a
...omit(options1, 'analyzeCommits'),
...omit(pkgOptions, ['extends', 'analyzeCommits']),
branches: ['test_branch'],
preset: 'conventionalcommits',
};
// Verify the options contains the plugin config from shareable.json
t.deepEqual(result, expected);
Expand Down Expand Up @@ -577,3 +583,40 @@ test('Convert "ci" option to "noCi" when set from extended config', async (t) =>
t.is(result.ci, false);
t.is(result.noCi, true);
});

test('Allow to override preset', async (t) => {
// Create a git repository, set the current working directory at the root of the repo
const {cwd} = await gitRepo();
const pkgOptions = {
preset: '1',
};
// Create package.json in repository root
await outputJson(path.resolve(cwd, 'package.json'), {release: pkgOptions});

const {
options: {preset: result},
} = await t.context.getConfig({cwd});

// Verify the preset contains the config from CLI/API
t.deepEqual(result, pkgOptions.preset);
});

test('Allow to override preset through CLI option --preset', async (t) => {
// Create a git repository, set the current working directory at the root of the repo
const {cwd} = await gitRepo();
const pkgOptions = {
preset: '1',
};
const cliOptions = {
preset: '2',
};
// Create package.json in repository root
await outputJson(path.resolve(cwd, 'package.json'), {release: pkgOptions});

const {
options: {preset: result},
} = await t.context.getConfig({cwd}, cliOptions);

// Verify the preset contains the config from CLI/API
t.deepEqual(result, cliOptions.preset);
});
16 changes: 14 additions & 2 deletions test/index.test.js
Expand Up @@ -92,6 +92,7 @@ test('Plugins are called with expected values', async (t) => {
repositoryUrl,
globalOpt: 'global',
tagFormat: `v\${version}`,
preset: 'conventionalcommits',
};
const branches = [
{
Expand Down Expand Up @@ -883,6 +884,7 @@ test('Call all "success" plugins even if one errors out', async (t) => {
repositoryUrl,
globalOpt: 'global',
tagFormat: `v\${version}`,
preset: 'conventionalcommits',
};
const options = {
...config,
Expand Down Expand Up @@ -927,7 +929,12 @@ test('Log all "verifyConditions" errors', async (t) => {
const error2 = new SemanticReleaseError('error 2', 'ERR2');
const error3 = new SemanticReleaseError('error 3', 'ERR3');
const fail = stub().resolves();
const config = {branches: [{name: 'master'}], repositoryUrl, tagFormat: `v\${version}`};
const config = {
branches: [{name: 'master'}],
repositoryUrl,
tagFormat: `v\${version}`,
preset: 'conventionalcommits',
};
const options = {
...config,
plugins: false,
Expand Down Expand Up @@ -971,7 +978,12 @@ test('Log all "verifyRelease" errors', async (t) => {
const error1 = new SemanticReleaseError('error 1', 'ERR1');
const error2 = new SemanticReleaseError('error 2', 'ERR2');
const fail = stub().resolves();
const config = {branches: [{name: 'master'}], repositoryUrl, tagFormat: `v\${version}`};
const config = {
branches: [{name: 'master'}],
repositoryUrl,
tagFormat: `v\${version}`,
preset: 'conventionalcommits',
};
const options = {
...config,
verifyConditions: stub().resolves(),
Expand Down

0 comments on commit ed083e7

Please sign in to comment.