使用commitizen格式化提交规范

2020/7/20 commitizen

# commitizen

# Adapter

npm install -g commitizen
1
  • 方式一:在全局安装适配器(Adapter)
npm install -g cz-conventional-changelog

# 项目根目录下添加 .czrc 配置文件
{ "path": "cz-conventional-changelog" }

# 使用 git commit 替换为 git cz
git cz
1
2
3
4
5
6
7
  • 方式二:在项目安装适配器(Adapter)
commitizen init cz-conventional-changelog --save-dev --save-exact --force

# commitizen 工具会自动在package.json中添加配置相应的配置

  "config": {
      "commitizen": {
          "path": "cz-conventional-changelog"
      }
  }

# 使用: package.json配置

  "script": {
      "commit": "git-cz",
  },
  "config": {
      "commitizen": {
        "path": "node_modules/cz-conventional-changelog"
      }
  }

# 命令运行
npm run commit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  • Adapter options
feat    # 新功能
fix Bug   # 修复
docs    # 文档更新
style     # 代码的格式,标点符号的更新
refactor  # 代码重构
perf    # 性能优化
test    # 测试更新
build   # 构建系统或者包依赖更新
ci CI   # 配置,脚本文件等更新
chore   # 非 src 或者 测试文件的更新
revert  # commit 回退
1
2
3
4
5
6
7
8
9
10
11

# 自定义 Adapter

  • 安装 cz-customizable
npm i -g cz-customizable / npm i -D cz-customizable
1
  • 修改 .czrcpackage.json 中的 config 为
# .czrc
{ "path": "cz-customizable" }

# package.json
"config": {
    "commitizen": {
      "path": "node_modules/cz-customizable"
    }
}
1
2
3
4
5
6
7
8
9
  • 同时在~/ 或项目目录下创建 .cz-config.js 文件
"use strict";

module.exports = {
  types: [
    {
      value: "feat",
      name: "✨  feat:     A new feature"
    },
    {
      value: "fix",
      name: "🐞  fix:      A bug fix"
    },
    {
      value: "refactor",
      name:
        "🛠  refactor: A code change that neither fixes a bug nor adds a feature"
    },
    {
      value: "docs",
      name: "📚  docs:     Documentation only changes"
    },
    {
      value: "test",
      name: "🏁  test:     Add missing tests or correcting existing tests"
    },
    {
      value: "chore",
      name:
        "🗯  chore:    Changes that don't modify src or test files. Such as updating build tasks, package manager"
    },
    {
      value: "style",
      name:
        "💅  style:    Code Style, Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)"
    },
    {
      value: "revert",
      name: "⏪  revert:   Revert to a commit"
    }
  ],
  scopes: [],
  allowCustomScopes: true,
  allowBreakingChanges: ["feat", "fix"]
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

# changelog

npm install -g conventional-changelog-cli
1
  • use
conventional-changelog -p angular -i CHANGELOG.md -s
conventional-changelog -p angular -i CHANGELOG.md -s -r 0
1
2

# standard-version

npm i --save-dev standard-version

{
  "scripts": {
    "release": "standard-version"
  }
}

npm run release
1
2
3
4
5
6
7
8
9
  • global
npm i -g standard-version

standard-version
1
2
3
  • release-as, -r 指定版本号
主版本(major),次版本( minor) or 修订版(patch)

$ standard-version -r minor
# output 1.1.0
$ standard-version -r 2.0.0
# output 2.0.0
$ standard-version -r 2.0.0-test
# output 2.0.0-test
1
2
3
4
5
6
7
8
  • prerelease, -p 预发版本命名
用来生成预发版本, 如果当期的版本号是 2.0.0,例如

$ standard-version --prerelease alpha
# output 2.0.0-alpha.0
1
2
3
4
  • tag-prefix, -t 版本 tag 前缀
用来给生成 tag 标签添加前缀,例如如果前版本号为 2.0.0,则:

$ standard-version --tag-prefix "stable-"
# output tag: stable-v2.0.0
1
2
3
4
  • example
"scripts": {
  "publish:release": "standard-version",
  "publish:minor": "standard-version --release-as minor",
  "publish:major": "standard-version --release-as major",
  "publish:beta": "standard-version --prerelease beta"
}
1
2
3
4
5
6

# 集成 npm

  • package
"scripts": {
    "release": "./scripts/release.sh",
    "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0 && git add CHANGELOG.md && npm run changeissueurl",
    "changeissueurl": "replace 'https://github.com/myproject/issues/' 'https://redmine.example.com/' CHANGELOG.md"
},
1
2
3
4
5
  • release.sh
#!/bin/bash

# Release branch
master="master"
prefix="DTinsight_v"

git pull origin $master
echo "Current pull origin $master."

# Auto generate version number and tag
standard-version -r $release --tag-prefix $prefix

git push --follow-tags origin $master

echo "Git push origin $master"
echo "Release finished."
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# Commitlint

npm i -D @commitlint/config-conventional @commitlint/cli
1
  • 在项目目录下创建配置文件 .commitlintrc.js
module.exports = {
  extends: ["@commitlint/config-conventional"],
  rules: {
    "body-leading-blank": [1, "always"],
    "footer-leading-blank": [1, "always"],
    "header-max-length": [2, "always", 72],
    "scope-case": [2, "always", "lower-case"],
    "subject-case": [
      2,
      "never",
      ["sentence-case", "start-case", "pascal-case", "upper-case"]
    ],
    "subject-empty": [2, "never"],
    "subject-full-stop": [2, "never", "."],
    "type-case": [2, "always", "lower-case"],
    "type-empty": [2, "never"],
    "type-enum": [
      2,
      "always",
      [
        "build",
        "chore",
        "ci",
        "docs",
        "feat",
        "fix",
        "perf",
        "refactor",
        "revert",
        "style",
        "test"
      ]
    ]
  }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  • 针对自定义的 Adapter 进行 Lint
npm i -D @commitlint/cli

# .commitlintrc.js 中写入
module.exports = {
	rules: {
		'body-leading-blank': [1, 'always'],
		'footer-leading-blank': [1, 'always'],
		'header-max-length': [2, 'always', 72],
		'scope-case': [2, 'always', 'lower-case'],
		'subject-case': [
			2,
			'never',
			['sentence-case', 'start-case', 'pascal-case', 'upper-case'],
		],
		'subject-empty': [2, 'never'],
		'subject-full-stop': [2, 'never', '.'],
		'type-case': [2, 'always', 'lower-case'],
		'type-empty': [2, 'never'],
		'type-enum': [
			2,
			'always',
			['feat', 'fix', 'refactor', 'docs', 'test', 'chore', 'style', 'revert'],
		],
	},
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# husky

// package.json
{
  "husky": {
    "hooks": {
      "pre-commit": "npm test",
      "pre-push": "npm test",
    }
  }
}

// 例如:
"husky": {
  "hooks": {
    "pre-commit": "lint-staged",
    "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 参考示例

# 默认Adapter

  • package.json
{
  "name": "demo",
  "version": "1.0.1",
  "main": "index.js",
  "scripts": {
    "lint": "eslint --debug src/**/*.js",
    "lint:write": "eslint src/**/*.js --fix",
    "prettier": "prettier --write src/**/*.js",
    "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0 && git add CHANGELOG.md",
    "release": "standard-version"
  },
  "devDependencies": {
    "@commitlint/cli": "^7.2.1",
    "@commitlint/config-conventional": "^7.1.2",
    "cz-conventional-changelog": "^2.1.0",
    "eslint": "^5.12.0",
    "eslint-config-standard": "^12.0.0",
    "eslint-plugin-import": "^2.14.0",
    "eslint-plugin-node": "^8.0.1",
    "eslint-plugin-promise": "^4.0.1",
    "eslint-plugin-standard": "^4.0.0",
    "prettier": "^1.15.3",
    "eslint-plugin-prettier": "^3.0.1",
    "eslint-config-prettier": "^3.5.0",
    "husky": "^1.3.1",
    "lint-staged": "^8.1.0"
  },
  "config": {
    "commitizen": {
      "path": "./node_modules/cz-conventional-changelog"
    }
  },
  "lint-staged": {
    "*.(js|jsx)": ["npm run lint:write", "git add"]
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged",
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
    }
  },
  "dependencies": {
    "standard-version": "^4.4.0"
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  • .commitlintrc.js
module.exports = {
  extends: ["@commitlint/config-conventional"],
  rules: {
    "body-leading-blank": [1, "always"],
    "footer-leading-blank": [1, "always"],
    "header-max-length": [2, "always", 72],
    "scope-case": [2, "always", "lower-case"],
    "subject-case": [
      2,
      "never",
      ["sentence-case", "start-case", "pascal-case", "upper-case"]
    ],
    "subject-empty": [2, "never"],
    "subject-full-stop": [2, "never", "."],
    "type-case": [2, "always", "lower-case"],
    "type-empty": [2, "never"],
    "type-enum": [
      2,
      "always",
      [
        "build",
        "chore",
        "ci",
        "docs",
        "feat",
        "fix",
        "perf",
        "refactor",
        "revert",
        "style",
        "test"
      ]
    ]
  }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 自定义校验

  • package.json
{
  "name": "demo",
  "version": "1.0.4",
  "main": "index.js",
  "scripts": {
    "test": "echo dev branch",
    "lint": "eslint --debug src/**/*.js",
    "lint:write": "eslint src/**/*.js --fix",
    "prettier": "prettier --write src/**/*.js",
    "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0 && git add CHANGELOG.md",
    "release": "standard-version"
  },
  "devDependencies": {
    "@commitlint/cli": "^7.2.1",
    "cz-customizable": "^5.3.0",
    "eslint": "^5.12.0",
    "eslint-config-prettier": "^3.5.0",
    "eslint-config-standard": "^12.0.0",
    "eslint-plugin-import": "^2.14.0",
    "eslint-plugin-node": "^8.0.1",
    "eslint-plugin-prettier": "^3.0.1",
    "eslint-plugin-promise": "^4.0.1",
    "eslint-plugin-standard": "^4.0.0",
    "husky": "^1.3.1",
    "lint-staged": "^8.1.0",
    "prettier": "^1.15.3"
  },
  "config": {
    "commitizen": {
      "path": "node_modules/cz-customizable"
    }
  },
  "lint-staged": {
    "*.(js|jsx)": ["npm run lint:write", "git add"]
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged",
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  • .cz-config.js
"use strict";

module.exports = {
  types: [
    {
      value: "feat",
      name: "✨  feat:     A new feature"
    },
    {
      value: "fix",
      name: "🐞  fix:      A bug fix"
    },
    {
      value: "refactor",
      name:
        "🛠  refactor: A code change that neither fixes a bug nor adds a feature"
    },
    {
      value: "docs",
      name: "📚  docs:     Documentation only changes"
    },
    {
      value: "test",
      name: "🏁  test:     Add missing tests or correcting existing tests"
    },
    {
      value: "chore",
      name:
        "🗯  chore:    Changes that don't modify src or test files. Such as updating build tasks, package manager"
    },
    {
      value: "style",
      name:
        "💅  style:    Code Style, Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)"
    },
    {
      value: "revert",
      name: "⏪  revert:   Revert to a commit"
    }
  ],
  allowCustomScopes: true
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  • .commitlintrc.js
module.exports = {
  rules: {
    "body-leading-blank": [1, "always"],
    "footer-leading-blank": [1, "always"],
    "header-max-length": [2, "always", 72],
    "scope-case": [2, "always", "lower-case"],
    "subject-case": [
      2,
      "never",
      ["sentence-case", "start-case", "pascal-case", "upper-case"]
    ],
    "subject-empty": [2, "never"],
    "subject-full-stop": [2, "never", "."],
    "type-case": [2, "always", "lower-case"],
    "type-empty": [2, "never"],
    "type-enum": [
      2,
      "always",
      ["feat", "fix", "refactor", "docs", "test", "chore", "style", "revert"]
    ]
  }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22