-
Notifications
You must be signed in to change notification settings - Fork 933
Allow per-type scope-enum #395
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I can see how this might be useful, especially on larger projects. How about we take advantage of the fact values in We could pass in the currently parsed message to said function, implementing your example would then looks like this: const lernaConfig = require('@commitlint/config-lerna');
module.exports = {
rules: {
'scope-enum': async (ctx) => {
// ctx.message not passed yet
if (ctx.message.type === 'build') {
return [2, 'always', ['npm', 'babel', 'webpack']]
}
const pkgs = await lernaConfig.utils.getPackages();
return [2, 'always', ['all', ...pkgs]]
}
}
}; What do you think? |
I think that makes sense; are you saying that's achievable without any changes or are you proposing that support like this be added? |
An additional complication is the fact we need to (partially) resolve configuration before we can parse a message because We could work around this by introducing When |
I ran into the need for per-type scopes myself and after digging around a bit ended up implementing it as a local plugin. If there's interest, I can clean up the code and publish it on npmjs. In the meantime, here's my ugly working module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'scope-enums': [
2, 'always', {
feat: [/^frontend\/[^\/]+$/, 'backend'],
perf: [],
ci: [null, 'codebuild', 'jenkins']
}
]
},
plugins: [
{
rules: {
/**
* - If a type does not appear in the rule, do not enforce scope
* - If a type appears in the rule with an empty array,
* do not allow scope
* - If a type appears in the rule with an non-empty array,
* only allow the values in the array for scope.
* - If the array includes null, the scope is optional.
*
* E.g., {
* 'allowed-scopes': [2, "always", {
* feat: [/^frontend\/[^\/]+$/, 'backend'],
* perf: [],
* ci: [null, 'codebuild', 'jenkins']
* }]
* }
*
* In the above rules configuration,
* - if the type is 'feat', the scope must be either
* match the regex /frontend\/[^\/]+/ or be 'backend'
* - if the type if 'chore', the scope is optional and can
* be anything
* - if the type is 'perf', a scope is not allowed
* - if the type is 'ci', the scope must be 'codebuild' or
* 'jenkins' if present, but is not required
*/
'scope-enums': (ctx, applicable, rule) => {
if (applicable === 'never') {
return [false, 'the "allowed-scopes" rule does not support "never"'];
}
const allowedScopes = rule[ctx.type];
// If the type does not appear in the rule config, allow any scope or no scope
if (allowedScopes === undefined) {
return [true];
}
if (Array.isArray(allowedScopes)) {
// If the type maps to an empty array in the rule config, scope it not allowed
if (allowedScopes.length === 0) {
if (ctx.scope != null) {
return [false, `commit messages with type "${ctx.type}" must not specify a scope`];
}
return [true];
}
// Otherwise attempt to match against either null, a string literal, or a RegExp
if (
allowedScopes.findIndex((s) => {
if (
typeof ctx.scope === 'string' &&
Object.prototype.toString.call() === '[object RegExp]'
) {
return ctx.scope.match(s);
}
// Equality comparison works for both strings and null
return s === ctx.scope;
}) !== -1
) {
return [true];
} else if (allowedScopes.includes(null)) {
return [
false,
`commit message with type "${
ctx.type
}" may specify a scope, but if specified, it must be one of the following: ${allowedScopes
.filter((s) => s !== null)
.map((s) => `"${s}"`)
.join(', ')}`,
];
} else {
return [
false,
`commit message with type "${
ctx.type
}" must specify one of the following scopes: ${allowedScopes
.map((s) => `"${s}"`)
.join(', ')}`,
];
}
}
return [false, `invalid rule entry: { ${ctx.type}: ${JSON.stringify(allowedScopes)} }`];
},
},
},
],
}; |
Thank you @njlaw I converted it to an actual plugin, here: commitlint-plugin-selective-scope |
Expected Behavior
I'd like to limit the valid scopes on a per-type basis. For example, the
docs
type should acceptall
and each of my lerna packages as scopes, but thebuild
type should perhaps accept onlynpm
,webpack
,babel
.Current Behavior
I can specify valid types and valid scopes, but not tuples of which ones are valid together.
Affected packages
Possible Solution
Allow one (or both) of
scopes-enum
andtypes-enum
to accept an object instead of an array. Alternatively, introduce a new rule that accepts an object.The text was updated successfully, but these errors were encountered: