Skip to content

Commit

Permalink
feat: use globs instead of regexp for releases rules
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Regexp are not supported anymore for property matching in the `releaseRules` option.

Regex are replaced by [globs](https://github.com/micromatch/micromatch#matching-features). For example `/core-.*/` should be changed to `'core-*'`.
  • Loading branch information
pvdlg committed Nov 29, 2018
1 parent d6027fa commit fc9b28a
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 22 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ With this example:

#### releaseRules

Release rules are used when deciding if the commits since the last release warrant a new release. If you define custom release rules the [default rules](lib/default-release-rules.js) will be used if nothing matched. Those rules will be matched against the commit objects resulting of [conventional-commits-parser](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-commits-parser) parsing.
Release rules are used when deciding if the commits since the last release warrant a new release. If you define custom release rules the [default rules](lib/default-release-rules.js) will be used if nothing matched. Those rules will be matched against the commit objects resulting of [conventional-commits-parser](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-commits-parser) parsing. Each rule property can be defined as a [glob](https://github.com/micromatch/micromatch#matching-features).

##### Rules definition

Expand All @@ -79,7 +79,7 @@ This is an `Array` of rule objects. A rule object has a `release` property and 1
"preset": "angular",
"releaseRules": [
{"type": "docs", "scope": "README", "release": "patch"},
{"type": "refactor", "scope": "/core-.*/", "release": "minor"},
{"type": "refactor", "scope": "core-*", "release": "minor"},
{"type": "refactor", "release": "patch"}
]
}],
Expand All @@ -97,7 +97,7 @@ See [release types](lib/default-release-types.js) for the release types hierarch
With the previous example:
- Commits with `type` 'docs' and `scope` 'README' will be associated with a `patch` release.
- Commits with `type` 'refactor' and `scope` starting with 'core-' (i.e. 'core-ui', 'core-rules', ...) will be associated with a `minor` release.
- Other commits with `type` 'refactor' (without `scope` or with a `scope` not matching the regexp `/core-.*/`) will be associated with a `patch` release.
- Other commits with `type` 'refactor' (without `scope` or with a `scope` not matching the glob `core-*`) will be associated with a `patch` release.

##### Default rules matching

Expand Down Expand Up @@ -139,7 +139,7 @@ For example with `eslint` preset:
["semantic-release/commit-analyzer", {
"preset": "eslint",
"releaseRules": [
{"tag": "Docs", "message":"/README/", "release": "patch"},
{"tag": "Docs", "message":"*README*", "release": "patch"},
{"type": "New", "release": "patch"}
]
}],
Expand Down Expand Up @@ -174,7 +174,7 @@ With this configuration:
// File: config/release-rules.js
module.exports = [
{type: 'docs', scope: 'README', release: 'patch'},
{type: 'refactor', scope: /core-.*/, release: 'minor'},
{type: 'refactor', scope: 'core-*', release: 'minor'},
{type: 'refactor', release: 'patch'},
];
```
5 changes: 3 additions & 2 deletions lib/analyze-commit.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const {isMatchWith, isRegExp} = require('lodash');
const {isMatchWith, isString} = require('lodash');
const micromatch = require('micromatch');
const debug = require('debug')('semantic-release:commit-analyzer');
const RELEASE_TYPES = require('./default-release-types');
const compareReleaseTypes = require('./compare-release-types');
Expand All @@ -22,7 +23,7 @@ module.exports = (releaseRules, commit) => {
(!revert || commit.revert) &&
// Otherwise match the regular rules
isMatchWith(commit, rule, (obj, src) =>
/^\/.*\/$/.test(src) || isRegExp(src) ? new RegExp(/^\/(.*)\/$/.exec(src)[1]).test(obj) : undefined
isString(src) && isString(obj) ? micromatch.isMatch(obj, src) : undefined
)
)
.every(match => {
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"conventional-commits-parser": "^3.0.0",
"debug": "^4.0.0",
"import-from": "^2.1.0",
"lodash": "^4.17.4"
"lodash": "^4.17.4",
"micromatch": "^3.1.10"
},
"devDependencies": {
"ava": "^0.25.0",
Expand Down
23 changes: 11 additions & 12 deletions test/analyze-commit.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ test('Match multiple criteria with revert', t => {
});

test('Match multiple criteria', t => {
const commit = {type: 'feat', scope: 'test'};
const commit = {type: 'feat', scope: 1};

t.is(analyzeCommit([{type: 'feat', scope: 'test', release: 'major'}], commit), 'major');
t.is(analyzeCommit([{type: 'feat', scope: 1, release: 'major'}], commit), 'major');
});

test('Match only if all criteria are verified', t => {
Expand All @@ -62,21 +62,20 @@ test('Return undefined if there is no match', t => {
t.is(analyzeCommit([{type: 'feat', breaking: true, release: 'major'}], commit), undefined);
});

test('Match with regex', t => {
const rules = [{type: 'docs', scope: /test\(.*\)/, release: 'minor'}];
const match = {type: 'docs', scope: 'test(readme): message'};
const notMatch = {type: 'docs', scope: 'test2(readme): message'};
test('Return undefined for commit with falsy properties', t => {
const commit = {type: null};

t.is(analyzeCommit(rules, match), 'minor');
t.is(analyzeCommit(rules, notMatch), undefined);
t.is(analyzeCommit([{type: 'feat'}], commit), undefined);
});

test('Match with regex as string', t => {
const rules = [{type: 'docs', scope: '/test\\(.*\\)/', release: 'minor'}];
const match = {type: 'docs', scope: 'test(readme): message'};
const notMatch = {type: 'docs', scope: 'test2(readme): message'};
test('Match with glob', t => {
const rules = [{type: 'docs', scope: 'b*', release: 'minor'}];
const match = {type: 'docs', scope: 'bar'};
const match2 = {type: 'docs', scope: 'baz'};
const notMatch = {