diff --git a/.cz-config.js b/.cz-config.js index 0b05419..347f6b5 100644 --- a/.cz-config.js +++ b/.cz-config.js @@ -27,8 +27,11 @@ module.exports = { }, { value: 'ci', name: 'ci 👷: 修改 CI 配置、脚本' }, { value: 'revert', name: 'revert ⏪️: 回滚 commit' }, - { value: 'version', name: 'version 🎉: 发布新版本' }, - { value: 'init', name: 'init 🎉: 初始化' }, + + // 这里可以新增自定义的type,主要借助commitlint-config-cz工具包,已在.commitlintrc.js中进行配置 + // 不完美的是手动输入git commit -m "version: xxx" 才可以通过验证 + // { value: 'version', name: 'version 🎉: 发布新版本' }, + // { value: 'init', name: 'init 🎉: 初始化' }, ], // scope 类型(定义之后,可通过上下键选择) scopes: [ diff --git a/images/husky-demo.png b/images/husky-demo.png index 225dd6f..c16eded 100644 Binary files a/images/husky-demo.png and b/images/husky-demo.png differ diff --git a/packages/create-husky/index.mjs b/packages/create-husky/index.mjs index 7842fb7..93eb9da 100644 --- a/packages/create-husky/index.mjs +++ b/packages/create-husky/index.mjs @@ -1,4 +1,4 @@ -#!/usr/bin/env node +#!/usr/bin/env node import prompts from "prompts"; import beautify from "js-beautify"; import { red, cyan, green } from "kolorist"; @@ -21,6 +21,7 @@ const projectDirectory = cwd(), // 项目目录 lintStagedFile = resolve(projectDirectory, "lint-staged.config.js"), // 获取lint-staged配置模板 commitlintFile = resolve(projectDirectory, ".commitlintrc.js"), // 获取commitlint配置模板 czFile = resolve(projectDirectory, ".cz-config.js"), // 获取cz配置模板 + releaseItFile = resolve(projectDirectory, ".release-it.json"), // 获取release-it配置模板 // 获取相关配置的文件目录 commitlintFileTemplateDir = resolve( fileURLToPath(import.meta.url), @@ -32,18 +33,24 @@ const projectDirectory = cwd(), // 项目目录 "../src/template", ".cz-config.js" ), + releaseItFileTemplateDir = resolve( + fileURLToPath(import.meta.url), + "../src/template", + ".cz-config.js" + ), needDependencies = ["eslint", "prettier", "stylelint"], // pak包中需包含的依赖 // 命令枚举 commandMap = { npm: "npm install && npm install --save-dev ", yarn: "yarn && yarn add --dev ", - pnpm: "npm install && pnpm install --save-dev ", + pnpm: "pnpm install && pnpm install --save-dev ", }, // 需要安装的依赖 huskyPackages = "husky@8.0.3", preCommitPackages = "lint-staged@13.2.3", commitMsgPackages = - "@commitlint/cli@17.6.7 @commitlint/config-conventional@17.6.7 commitizen@4.3.0 commitlint-config-cz@0.13.3 cz-customizable@7.0.0"; + "@commitlint/cli@17.6.7 @commitlint/config-conventional@17.6.7 commitizen@4.3.0 commitlint-config-cz@0.13.3 cz-customizable@7.0.0", + releaseItPackages = "release-it@16.0.0 @release-it/conventional-changelog@7.0.0 auto-changelog@2.4.0" // husky输出的脚本内容 const createGitHook = `npx husky install`; const createCommitHook = `npx husky add .husky/pre-commit "npx lint-staged"`; @@ -77,6 +84,15 @@ const huskyQuestions = [ }, ]; +// release-it 询问 +const releaseItQuestions = [ + { + type: "confirm", + name: "releaseit", + message: "是否需要安装release-it和auto-changelog功能?", + }, +]; + // 终端没有eslint/prettier/stylelint的询问 const noLintQuestions = [ { @@ -166,7 +182,7 @@ async function init() { // 确定终端要询问的内容 const questions = pakHasLint.length === 0 - ? [...noLintQuestions, ...huskyQuestions] + ? [...noLintQuestions, ...huskyQuestions, ...releaseItQuestions] : huskyQuestions; // 同步检查.husky目录是否存在,如果存在,则在终端询问是否要覆盖 if (existsSync(huskyFile)) { @@ -187,12 +203,17 @@ async function init() { } // 读取操作结果 - const { selectLint, manager, commitlint } = result; + const { selectLint, manager, commitlint, releaseit } = result; + // 判断用户是否选择commitlint,安装不同的包 - const packages = commitlint + const commitlintPackages = commitlint ? `${huskyPackages} ${preCommitPackages} ${commitMsgPackages}` : `${huskyPackages} ${preCommitPackages}`; - // 判断用户是否选择commitlint,执行不同的操作 + + // 判断用户是否选择安装release-it,选择了则安装相关包 + const packages = releaseit ? `${commitlintPackages} ${releaseItPackages}` : `${commitMsgPackages}` + + // 判断用户是否选择commitlint,生成不同的git hook const createHookCommand = commitlint ? `${createGitHook} && ${createCommitHook} && ${createMsgHook}` : `${createGitHook} && ${createCommitHook}`; @@ -224,36 +245,64 @@ async function init() { } // 写入package.json let newPakContent = JSON.parse(readFileSync(pakFile)); - newPakContent.scripts = { - ...newPakContent.scripts, + + // commit-msg生成脚本 + const commitMsgScript = commitlint ? { prepare: "husky install", // install pkg时自动触发husky初始化 commit: "git add . && cz", // 快捷命令 - 暂存 push: "git add . && cz && git push", // 快捷命令 - 推送 + } : {} + + // release-it生成脚本 + const releaseitScript = releaseit ? { + "release:major": "release-it major", // 发布major版本 + "release:minor": "release-it minor", // 发布minor版本 + "release:patch": "release-it patch", // 发布patch版本 + } : {} + + // 写入脚本 + newPakContent.scripts = { + ...newPakContent.scripts, + ...commitMsgScript, + ...releaseitScript, }; - newPakContent.config = { - ...(newPakContent?.config || {}), + + // commit-msg生成配置 + const commitMsgConfig = commitlint ? { commitizen: { path: "./node_modules/cz-customizable", }, "cz-customizable": { config: "./.cz-config.js", }, + } : {} + + // 写入config配置 + newPakContent.config = { + ...(newPakContent?.config || {}), + ...commitMsgConfig, }; - // 考虑不帮用户做强制决定,由用户自己修复 - // delete newPakContent.type; // 默认删除package.json的type属性,项目一般都支持esmodule和commonjs + // 写入package.json文件,后面的参数用于美化json格式 writeFileSync(pakFile, JSON.stringify(newPakContent, null, "\t")); writeFileSync(lintStagedFile, lintStagedContent); - // 模板拷贝 - copyFileSync(commitlintFileTemplateDir, commitlintFile); - copyFileSync(czFileTemplateDir, czFile); + // commitlint配置模板 + if (commitlint) { + copyFileSync(commitlintFileTemplateDir, commitlintFile); + copyFileSync(czFileTemplateDir, czFile); + } + + // release-it配置模板 + if(releaseit) { + copyFileSync(releaseItFileTemplateDir, releaseItFile); + } // 安装成功提示 spinner.success({ text: green("安装成功~准备添加钩子! 🎉"), mark: "✔" }); // 创建添加hook进度提示 - const hookSpinner = createSpinner("生成husky钩子中...").start(); + const hookSpinner = createSpinner("生成配置中...").start(); // 执行添加hook命令 exec(`${createHookCommand}`, { cwd: projectDirectory }, (error) => { diff --git a/packages/create-husky/src/template/.cz-config.js b/packages/create-husky/src/template/.cz-config.js index 0b05419..dae2ace 100644 --- a/packages/create-husky/src/template/.cz-config.js +++ b/packages/create-husky/src/template/.cz-config.js @@ -27,8 +27,11 @@ module.exports = { }, { value: 'ci', name: 'ci 👷: 修改 CI 配置、脚本' }, { value: 'revert', name: 'revert ⏪️: 回滚 commit' }, - { value: 'version', name: 'version 🎉: 发布新版本' }, - { value: 'init', name: 'init 🎉: 初始化' }, + + // 这里可以新增自定义的type,主要借助commitlint-config-cz工具包,已在.commitlintrc.js中进行配置 + // 不完美的是手动输入git commit -m "version: xxx" 才可以通过验证 + // { value: 'version', name: 'version 🎉: 发布新版本' }, + // { value: 'init', name: 'init 🎉: 初始化' }, ], // scope 类型(定义之后,可通过上下键选择) scopes: [ diff --git a/packages/create-husky/src/template/.release-it.json b/packages/create-husky/src/template/.release-it.json new file mode 100644 index 0000000..dbdfa8c --- /dev/null +++ b/packages/create-husky/src/template/.release-it.json @@ -0,0 +1,51 @@ +{ + "hooks": { + "after:bump": "auto-changelog -p" + }, + "git": { + "changelog": "auto-changelog --stdout --commit-limit false", + "requireCleanWorkingDir": false, + "requireUpstream": true, + "requireCommits": false, + "addUntrackedFiles": false, + "commit": true, + "commitMessage": "chore: release v${version}", + "commitArgs": "", + "tag": true, + "tagName": "v${version}", + "tagAnnotation": "Release v${version}", + "tagArgs": "", + "push": true, + "pushArgs": "--follow-tags", + "pushRepo": "origin" + }, + "npm": { + "publish": false, + "publishPath": "", + "access": null, + "otp": null + }, + "plugins": { + "@release-it/conventional-changelog": { + "infile": "CHANGELOG.md", + "preset": { + "name": "conventionalcommits", + "header": "# 📋 更新历史 \n\n", + "types": [ + { "type": "feat", "section": "✨ Features | 新特性" }, + { "type": "fix", "section": "🐛 Bug Fixes | Bug 修复" }, + { "type": "perf", "section": "⚡ Performance Improvements | 性能优化" }, + { "type": "revert", "section": "⏪ Reverts | 代码回退" }, + { "type": "chore", "section": "📦 Chores | 其余更新" }, + { "type": "docs", "section": "📝 Documentation | 文档修改" }, + { "type": "style", "section": "💄 Styles | 代码格式调整", "hidden": true }, + { "type": "refactor", "section": "♻ Code Refactoring | 代码重构" }, + { "type": "test", "section": "✅ Tests | 测试用例" }, + { "type": "build", "section": "👷‍ Build System | 构建" }, + { "type": "ci", "section": "🔧 Continuous Integration | CI 配置" } + ], + "commitUrlFormat": "{{host}}/{{owner}}/{{repository}}/commit/{{hash}}" + } + } + } +}