Branch Name Lint
Flexible git branch naming convention checker with some extra validating features
Usage
Globally
> npm install @b12k/branch-name-lint -g
> branch-name-lint
As development dependency
> npm install @b12k/branch-name-lint -D
> npm set-script lint:branch-name "branch-name-lint"
With custom branch names
> branch-name-lint --name=my-custom/branch-name
Git hook
Using simple-git-hooks
package.json
{
"simple-git-hooks": {
"pre-push": "branch-name-lint"
}
}
Alternatevly you can use it with husky.
Configuration
Config schema
interface Config {
pattern: string;
params: Record<string, string[]>;
prohibited: string[];
}
User provided configuration
Under the hood BranchNameLint uses cosmicconfig
to load its configuration.
You can create one of the following:
branchnamelint
property in the package.json
file
- Extensionless "rc file" in
.json
or .yaml
format
- "rc file" with
.json
or .yaml
extensions
.branchnamelintrc.json
.branchnamelintrc.yaml
- "rc file" with
.js
extension
- ".config.js" file
don't forget to do module.exports = {...}
in .js
config files
BranchNameLint will merge found configuration with its defaults.
Default configuration
module.exports = {
pattern: ':type/:name',
params: {
type: [
'fix',
'docs',
'misc',
'improve',
'introduce',
],
name: ['[a-z0-9-]+'],
},
prohibited: [
'ci',
'wip',
'main',
'test',
'build',
'master',
'release',
],
};
Linting
BranchNameLint uses path-to-regexp
to check if branch name matches the pattern
provided in config.
Firstly branch name will be checked if its prohibited
or not. On the next step,
if params
are provided, pattern
parts will be modified/populated using
respective keys. For example:
(default configuration)
:type/:name => :type(feature|fix|misc|docs)/:name([a-z0-9-]+)
Please refer to path-to-regexp
docs for advanced patterns.
Configuration recipes
Only check for protected branches
module.exports = {
pattern: '', // or other falsy value: undefined | 0 | null | false
params: {},
prohibited: [
'master',
'main',
'build',
'test',
'wip',
'ci',
'release',
],
};
Dot-separated username & issue id
b12k.fix/example-branch-description/lbn-12345
module.exports = {
pattern: ':username.:type/:desc/:issue',
params: {
type: [
'feature',
'fix',
'misc',
'docs',
],
issue: ['lbn-[a-z0-9-]+'],
},
prohibited: [
'master',
'main',
'build',
'test',
'wip',
'ci',
'release',
],
};
Scopes for monorepo
feature/my-awesome-app/yet-another-great-feature
(imaginary monorepo structure)
root/
apps/
my-awesome-app
another-great-app
libs/
very-useful-lib
shared-lib
.branchnamelintrc.js
const fs = require('fs');
const readDirectories = (path) => fs
.readdirSync(path, { withFileTypes: true })
.filter((file) => file.isDirectory())
.map(({ name }) => name);
module.exports = {
pattern: ':type/:scope/:description',
params: {
type: [
'feature',
'fix',
'misc',
'docs',
],
scope: readDirectories('./apps')
},
prohibited: [
'master',
'main',
'build',
'test',
'wip',
'ci',
'release',
],
};