Skip to content
This repository has been archived by the owner on Feb 5, 2018. It is now read-only.

Commit

Permalink
feat(lib): Add support for limiting allowed scopes
Browse files Browse the repository at this point in the history
  • Loading branch information
Garbee committed Jan 24, 2017
1 parent 04facc4 commit e05c627
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 1 deletion.
34 changes: 34 additions & 0 deletions README.md
Expand Up @@ -34,6 +34,12 @@ You can specify options in `.vcmrc`
```js
{
"types": ["feat", "fix", "docs", "style", "refactor", "perf", "test", "chore", "revert"], // default
"scopes": {
required: false, // default,
allowed: ['button', 'card'], // default is '*' for anything,
validate: false, // default,
multiple: false // default
},
"warnOnFail": false, // default
"maxSubjectLength": 100, // default
"subjectPattern": ".+", // default
Expand All @@ -50,6 +56,12 @@ or in `package.json`
"config": {
"validate-commit-msg": {
"types": ["feat", "fix", "docs", "style", "refactor", "perf", "test", "chore", "revert"], // default
"scopes": {
required: false, // default,
allowed: ['button', 'card'], // default is '*' for anything,
validate: false, // default,
multiple: false // default
},
"warnOnFail": false, // default
"maxSubjectLength": 100, // default
"subjectPattern": ".+", // default
Expand All @@ -73,6 +85,28 @@ Or you can specify the name of a module that exports types according to the
[conventional-commit-types](https://github.com/adjohnson916/conventional-commit-types)
spec, e.g. `"types": "conventional-commit-types"`.

#### scopes

This object defines scope requirements for the commit message. Possible properties are:

##### required

A boolean to define whether a scope is required for all commit messages.

##### allowed

An array of scopes that are allowed for your commit message.

You may also define it as `"*"` which is the default to allow any scope names.

##### validate

A boolean to define whether or not to validate the scope(s) provided.

##### multiple

A boolean to define whether or not to allow multiple scopes.

#### warnOnFail

If this is set to `true` errors will be logged to the console, however the commit will still pass.
Expand Down
35 changes: 34 additions & 1 deletion lib/validateMessage.js
Expand Up @@ -63,6 +63,21 @@ exports.validateMessage = function validateMessage(raw) {
var type = match[3];
var scope = match[4];
var subject = match[5];
config.scopes = config.scopes || {};
var validateScopes = config.scopes.validate || false;
var multipleScopesAllowed = config.scopes.multiple || false;
var allowedScopes = config.scopes.allowed || '*';
var scopeRequired = config.scopes.required || false;
var scopes = scope ? scope.split(',') : [];
var validateScope = (item) => {
if (allowedScopes[0] === '*') {
return;
}
if (allowedScopes.indexOf(item) === -1) {
error('"%s" is not an allowed scope ! Valid scopes are: %s', item, allowedScopes.join(', '));
isValid = false;
}
};

var SUBJECT_PATTERN = new RegExp(config.subjectPattern || '.+');
var SUBJECT_PATTERN_ERROR_MSG = config.subjectPatternErrorMsg || 'subject does not match subject pattern!';
Expand All @@ -82,6 +97,25 @@ exports.validateMessage = function validateMessage(raw) {
isValid = false;
}

if (validateScopes) {
if (scopeRequired && scopes.length === 0) {
error('a scope is required !');
isValid = false;
}
if (isValid && multipleScopesAllowed) {
scopes.forEach(validateScope);
}
if (isValid && !multipleScopesAllowed) {
if (scopes.length > 1) {
error('only one scope can be provided !');
isValid = false;
}
if (isValid) {
validateScope(scopes[0]);
}
}
}

if (config.autoFix) {
subject = lowercaseFirstLetter(subject);
}
Expand All @@ -94,7 +128,6 @@ exports.validateMessage = function validateMessage(raw) {

// Some more ideas, do want anything like this ?
// - Validate the rest of the message (body, footer, BREAKING CHANGE annotations)
// - allow only specific scopes (eg. fix(docs) should not be allowed ?
// - auto add empty line after subject ?
// - auto remove empty () ?
// - auto correct typos in type ?
Expand Down
62 changes: 62 additions & 0 deletions test/validateMessage.test.js
Expand Up @@ -157,6 +157,68 @@ describe('validate-commit-msg.js', function() {
expect(logs).to.deep.equal([msg]);
});

it('should require a scope', function() {
var msg = 'feat: Add new feature';

m.config.scopes = {
validate: true,
allowed: '*',
required: true
};

expect(m.validateMessage(msg)).to.equal(INVALID);
expect(errors[0]).to.equal('INVALID COMMIT MSG: a scope is required !');
expect(logs).to.deep.equal([msg]);

m.config.scopes = undefined;
});

it('should validate scope', function() {
var msg = 'feat(nonexistant): Add new feature';

m.config.scopes = {
validate: true,
allowed: ['button', 'card']
};

expect(m.validateMessage(msg)).to.equal(INVALID);
expect(errors[0]).to.equal('INVALID COMMIT MSG: "nonexistant" is not an allowed scope ! Valid scopes are: ' + m.config.scopes.allowed.join(', '));
expect(logs).to.deep.equal([msg]);

m.config.scopes = undefined;
});

it('should only allow a single scope when multiples is off', function() {
var msg = 'feat(button,card): Add new feature';

m.config.scopes = {
validate: true,
allowed: '*'
};

expect(m.validateMessage(msg)).to.equal(INVALID);
expect(errors[0]).to.equal('INVALID COMMIT MSG: only one scope can be provided !');
expect(logs).to.deep.equal([msg]);

m.config.scopes = undefined;
});

it('should catch an invalid scope among many', function() {
var msg = 'feat(button,card,ripple): Add new feature';

m.config.scopes = {
validate: true,
allowed: ['button', 'card'],
multiple: true
};

expect(m.validateMessage(msg)).to.equal(INVALID);
expect(errors[0]).to.equal('INVALID COMMIT MSG: "ripple" is not an allowed scope ! Valid scopes are: ' + m.config.scopes.allowed.join(', '));
expect(logs).to.deep.equal([msg]);

m.config.scopes = undefined;
});

it('should allow empty scope', function() {
expect(m.validateMessage('fix: blablabla')).to.equal(VALID);
expect(errors).to.deep.equal([]);
Expand Down

0 comments on commit e05c627

Please sign in to comment.