@huaiyou/hooks-git 1.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +72 -9
- package/dist/cli.cjs +198 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.mjs +190 -0
- package/dist/commitlint.cjs +208 -0
- package/dist/commitlint.d.cts +5 -0
- package/dist/commitlint.d.mts +5 -0
- package/dist/commitlint.d.ts +5 -0
- package/dist/commitlint.mjs +206 -0
- package/dist/index.cjs +7 -68
- package/dist/index.d.cts +3 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.mjs +4 -0
- package/dist/lint-staged.cjs +48 -0
- package/dist/lint-staged.d.cts +6 -0
- package/dist/lint-staged.d.mts +4 -0
- package/dist/lint-staged.d.ts +6 -0
- package/dist/lint-staged.mjs +43 -0
- package/package.json +46 -23
- package/.husky/commit-msg +0 -4
- package/.husky/pre-commit +0 -4
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -5,12 +5,42 @@
|
|
|
5
5
|
## 📦 安装
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
pnpm add -D @huaiyou/hooks-git
|
|
8
|
+
pnpm add -D @huaiyou/hooks-git
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
> 注意:该包会自动处理所有依赖关系,无需手动安装 husky、@commitlint/cli 和 lint-staged。
|
|
12
|
+
|
|
11
13
|
## 🚀 快速开始
|
|
12
14
|
|
|
13
|
-
###
|
|
15
|
+
### 一键初始化(推荐)
|
|
16
|
+
|
|
17
|
+
使用以下命令一键完成所有配置:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx hy-hooks-git init
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
该命令将自动:
|
|
24
|
+
|
|
25
|
+
- 检查并初始化 Git 仓库(如果尚未初始化)
|
|
26
|
+
- 安装并配置 Husky
|
|
27
|
+
- 添加 commit-msg 和 pre-commit 钩子
|
|
28
|
+
- 创建 commitlint.config.js 和 lint-staged.config.js 配置文件
|
|
29
|
+
- 更新 package.json 脚本
|
|
30
|
+
|
|
31
|
+
### 交互式初始化
|
|
32
|
+
|
|
33
|
+
如需自定义配置,可以使用交互式模式:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx hy-hooks-git init --interactive
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 手动配置(不推荐)
|
|
40
|
+
|
|
41
|
+
如果需要手动配置,可以按照以下步骤进行:
|
|
42
|
+
|
|
43
|
+
#### 1. 安装 Husky
|
|
14
44
|
|
|
15
45
|
在项目根目录运行:
|
|
16
46
|
|
|
@@ -18,23 +48,24 @@ pnpm add -D @huaiyou/hooks-git husky @commitlint/cli lint-staged
|
|
|
18
48
|
pnpm prepare
|
|
19
49
|
```
|
|
20
50
|
|
|
21
|
-
|
|
51
|
+
#### 2. 复制配置文件
|
|
22
52
|
|
|
23
53
|
将以下文件复制到项目根目录:
|
|
24
54
|
|
|
25
55
|
**commitlint.config.js**:
|
|
26
56
|
|
|
27
57
|
```javascript
|
|
28
|
-
module.exports = require('@huaiyou/hooks-git/commitlint
|
|
58
|
+
module.exports = require('@huaiyou/hooks-git/commitlint');
|
|
29
59
|
```
|
|
30
60
|
|
|
31
61
|
**lint-staged.config.js**:
|
|
32
62
|
|
|
33
63
|
```javascript
|
|
34
|
-
|
|
64
|
+
const { createLintStagedConfig } = require('@huaiyou/hooks-git/lint-staged');
|
|
65
|
+
module.exports = createLintStagedConfig();
|
|
35
66
|
```
|
|
36
67
|
|
|
37
|
-
|
|
68
|
+
#### 3. 配置 Husky 钩子
|
|
38
69
|
|
|
39
70
|
**创建 .husky/pre-commit**:
|
|
40
71
|
|
|
@@ -54,7 +85,7 @@ pnpm lint-staged
|
|
|
54
85
|
pnpm commitlint --edit $1
|
|
55
86
|
```
|
|
56
87
|
|
|
57
|
-
|
|
88
|
+
#### 4. 添加脚本
|
|
58
89
|
|
|
59
90
|
在 `package.json` 中:
|
|
60
91
|
|
|
@@ -66,6 +97,20 @@ pnpm commitlint --edit $1
|
|
|
66
97
|
}
|
|
67
98
|
```
|
|
68
99
|
|
|
100
|
+
### 回滚初始化
|
|
101
|
+
|
|
102
|
+
如果需要回滚所有配置,可以使用以下命令:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npx hy-hooks-git rollback
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
该命令将自动:
|
|
109
|
+
|
|
110
|
+
- 删除 .husky 目录及其包含的钩子
|
|
111
|
+
- 删除配置文件(commitlint.config.js 和 lint-staged.config.js)
|
|
112
|
+
- 从 package.json 中移除 prepare 脚本
|
|
113
|
+
|
|
69
114
|
## ✨ 特性
|
|
70
115
|
|
|
71
116
|
### Commitlint
|
|
@@ -136,7 +181,7 @@ Closes #123
|
|
|
136
181
|
创建 `commitlint.config.js`:
|
|
137
182
|
|
|
138
183
|
```javascript
|
|
139
|
-
const baseConfig = require('@huaiyou/hooks-git/commitlint
|
|
184
|
+
const baseConfig = require('@huaiyou/hooks-git/commitlint');
|
|
140
185
|
|
|
141
186
|
module.exports = {
|
|
142
187
|
...baseConfig,
|
|
@@ -152,7 +197,10 @@ module.exports = {
|
|
|
152
197
|
创建 `lint-staged.config.js`:
|
|
153
198
|
|
|
154
199
|
```javascript
|
|
155
|
-
const
|
|
200
|
+
const { createLintStagedConfig } = require('@huaiyou/hooks-git/lint-staged');
|
|
201
|
+
|
|
202
|
+
// 获取基础配置
|
|
203
|
+
const baseConfig = createLintStagedConfig();
|
|
156
204
|
|
|
157
205
|
module.exports = {
|
|
158
206
|
...baseConfig,
|
|
@@ -164,6 +212,21 @@ module.exports = {
|
|
|
164
212
|
};
|
|
165
213
|
```
|
|
166
214
|
|
|
215
|
+
或者直接扩展配置函数:
|
|
216
|
+
|
|
217
|
+
```javascript
|
|
218
|
+
const { createLintStagedConfig } = require('@huaiyou/hooks-git/lint-staged');
|
|
219
|
+
|
|
220
|
+
module.exports = {
|
|
221
|
+
...createLintStagedConfig(),
|
|
222
|
+
'*.{ts,tsx}': [
|
|
223
|
+
'eslint --fix',
|
|
224
|
+
'prettier --write',
|
|
225
|
+
'vitest related --run', // 添加测试
|
|
226
|
+
],
|
|
227
|
+
};
|
|
228
|
+
```
|
|
229
|
+
|
|
167
230
|
## 🚫 跳过钩子
|
|
168
231
|
|
|
169
232
|
### 临时跳过(不推荐)
|
package/dist/cli.cjs
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const cac = require('cac');
|
|
5
|
+
const fs = require('fs-extra');
|
|
6
|
+
const node_path = require('node:path');
|
|
7
|
+
const consola = require('consola');
|
|
8
|
+
const execa = require('execa');
|
|
9
|
+
const picocolors = require('picocolors');
|
|
10
|
+
|
|
11
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
12
|
+
|
|
13
|
+
const cac__default = /*#__PURE__*/_interopDefaultCompat(cac);
|
|
14
|
+
const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
|
15
|
+
const picocolors__default = /*#__PURE__*/_interopDefaultCompat(picocolors);
|
|
16
|
+
|
|
17
|
+
const version = "2.1.0";
|
|
18
|
+
|
|
19
|
+
const logger = {
|
|
20
|
+
/**
|
|
21
|
+
* 输出信息日志
|
|
22
|
+
* @param {string} msg - 日志消息
|
|
23
|
+
*/
|
|
24
|
+
info: (msg) => consola.consola.info(msg),
|
|
25
|
+
/**
|
|
26
|
+
* 输出成功日志
|
|
27
|
+
* @param {string} msg - 日志消息
|
|
28
|
+
*/
|
|
29
|
+
success: (msg) => consola.consola.success(msg),
|
|
30
|
+
/**
|
|
31
|
+
* 输出警告日志
|
|
32
|
+
* @param {string} msg - 日志消息
|
|
33
|
+
*/
|
|
34
|
+
warn: (msg) => consola.consola.warn(msg),
|
|
35
|
+
/**
|
|
36
|
+
* 输出错误日志
|
|
37
|
+
* @param {string} msg - 日志消息
|
|
38
|
+
*/
|
|
39
|
+
error: (msg) => consola.consola.error(msg),
|
|
40
|
+
/**
|
|
41
|
+
* 输出带边框的日志
|
|
42
|
+
* @param {string} msg - 日志消息
|
|
43
|
+
*/
|
|
44
|
+
box: (msg) => {
|
|
45
|
+
console.log(
|
|
46
|
+
picocolors__default.cyan("\u250C" + "\u2500".repeat(msg.length + 2) + "\u2510") + "\n" + picocolors__default.cyan("\u2502 ") + msg + picocolors__default.cyan(" \u2502") + "\n" + picocolors__default.cyan("\u2514" + "\u2500".repeat(msg.length + 2) + "\u2518")
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const runCommand = async (command, args) => {
|
|
51
|
+
try {
|
|
52
|
+
await execa.execa(command, args, { stdio: "inherit" });
|
|
53
|
+
} catch (error) {
|
|
54
|
+
logger.error(`Failed to run command: ${command} ${args.join(" ")}`);
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const updatePackageJson = async (callback) => {
|
|
59
|
+
const pkgPath = node_path.resolve(process.cwd(), "package.json");
|
|
60
|
+
if (!fs__default.existsSync(pkgPath)) {
|
|
61
|
+
throw new Error("package.json not found");
|
|
62
|
+
}
|
|
63
|
+
const pkg = await fs__default.readJson(pkgPath);
|
|
64
|
+
const newPkg = callback(pkg);
|
|
65
|
+
await fs__default.writeJson(pkgPath, newPkg, { spaces: 2 });
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const init = async () => {
|
|
69
|
+
logger.box("Initializing @huaiyou/hooks-git");
|
|
70
|
+
const gitDirPath = node_path.resolve(process.cwd(), ".git");
|
|
71
|
+
if (!fs__default.existsSync(gitDirPath)) {
|
|
72
|
+
logger.warn("Not a git repository. Initializing...");
|
|
73
|
+
await runCommand("git", ["init"]);
|
|
74
|
+
}
|
|
75
|
+
logger.info("Installing Husky...");
|
|
76
|
+
try {
|
|
77
|
+
await runCommand("npx", ["husky", "install"]);
|
|
78
|
+
} catch (e) {
|
|
79
|
+
logger.error("Failed to install husky. Make sure dependencies are installed.");
|
|
80
|
+
}
|
|
81
|
+
logger.info("Adding hooks...");
|
|
82
|
+
const huskyDir = node_path.resolve(process.cwd(), ".husky");
|
|
83
|
+
const commitMsgPath = node_path.resolve(huskyDir, "commit-msg");
|
|
84
|
+
const commitMsgContent = `npx --no -- commitlint --edit \${1}
|
|
85
|
+
`;
|
|
86
|
+
await fs__default.outputFile(commitMsgPath, commitMsgContent, { mode: 493 });
|
|
87
|
+
const preCommitPath = node_path.resolve(huskyDir, "pre-commit");
|
|
88
|
+
const preCommitContent = `npx lint-staged
|
|
89
|
+
`;
|
|
90
|
+
await fs__default.outputFile(preCommitPath, preCommitContent, { mode: 493 });
|
|
91
|
+
logger.info("Creating configuration files...");
|
|
92
|
+
const pkgPath = node_path.resolve(process.cwd(), "package.json");
|
|
93
|
+
const pkg = await fs__default.readJson(pkgPath);
|
|
94
|
+
const isModule = pkg.type === "module";
|
|
95
|
+
const isTsProject = fs__default.existsSync(node_path.resolve(process.cwd(), "tsconfig.json"));
|
|
96
|
+
const commitlintFile = isTsProject ? "commitlint.config.ts" : isModule ? "commitlint.config.cjs" : "commitlint.config.js";
|
|
97
|
+
if (!fs__default.existsSync(node_path.resolve(process.cwd(), commitlintFile))) {
|
|
98
|
+
let content = "";
|
|
99
|
+
if (isTsProject) {
|
|
100
|
+
content = `import { commitlintConfig } from '@huaiyou/hooks-git';
|
|
101
|
+
export default commitlintConfig;
|
|
102
|
+
`;
|
|
103
|
+
} else {
|
|
104
|
+
content = `module.exports = require('@huaiyou/hooks-git/commitlint');
|
|
105
|
+
`;
|
|
106
|
+
}
|
|
107
|
+
await fs__default.writeFile(node_path.resolve(process.cwd(), commitlintFile), content);
|
|
108
|
+
logger.success(`Created ${commitlintFile}`);
|
|
109
|
+
} else {
|
|
110
|
+
logger.warn("commitlint config already exists. Skipping...");
|
|
111
|
+
}
|
|
112
|
+
const lintStagedFile = isTsProject ? "lint-staged.config.ts" : isModule ? "lint-staged.config.cjs" : "lint-staged.config.js";
|
|
113
|
+
if (!fs__default.existsSync(node_path.resolve(process.cwd(), lintStagedFile))) {
|
|
114
|
+
let content = "";
|
|
115
|
+
if (isTsProject) {
|
|
116
|
+
content = `import { createLintStagedConfig } from '@huaiyou/hooks-git';
|
|
117
|
+
export default createLintStagedConfig();
|
|
118
|
+
`;
|
|
119
|
+
} else {
|
|
120
|
+
content = `const { createLintStagedConfig } = require('@huaiyou/hooks-git/lint-staged');
|
|
121
|
+
module.exports = createLintStagedConfig();
|
|
122
|
+
`;
|
|
123
|
+
}
|
|
124
|
+
await fs__default.writeFile(node_path.resolve(process.cwd(), lintStagedFile), content);
|
|
125
|
+
logger.success(`Created ${lintStagedFile}`);
|
|
126
|
+
} else {
|
|
127
|
+
logger.warn("lint-staged config already exists. Skipping...");
|
|
128
|
+
}
|
|
129
|
+
if (isTsProject) {
|
|
130
|
+
const hasTsNode = pkg.devDependencies && pkg.devDependencies["ts-node"] || pkg.dependencies && pkg.dependencies["ts-node"];
|
|
131
|
+
if (!hasTsNode) {
|
|
132
|
+
logger.info("Detected TypeScript project. Installing ts-node...");
|
|
133
|
+
await runCommand("pnpm", ["add", "-D", "ts-node"]);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
logger.info("Updating package.json scripts...");
|
|
137
|
+
await updatePackageJson((pkg2) => {
|
|
138
|
+
pkg2.scripts = pkg2.scripts || {};
|
|
139
|
+
if (!pkg2.scripts.prepare || !pkg2.scripts.prepare.includes("husky")) {
|
|
140
|
+
pkg2.scripts.prepare = "husky install";
|
|
141
|
+
}
|
|
142
|
+
return pkg2;
|
|
143
|
+
});
|
|
144
|
+
logger.box("Initialization complete! \u{1F389}");
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const rollback = async () => {
|
|
148
|
+
logger.box("Rolling back @huaiyou/hooks-git initialization");
|
|
149
|
+
const huskyDir = node_path.resolve(process.cwd(), ".husky");
|
|
150
|
+
if (fs__default.existsSync(huskyDir)) {
|
|
151
|
+
await fs__default.remove(huskyDir);
|
|
152
|
+
logger.success("Removed .husky directory");
|
|
153
|
+
}
|
|
154
|
+
const configFiles = [
|
|
155
|
+
"commitlint.config.js",
|
|
156
|
+
"commitlint.config.cjs",
|
|
157
|
+
"lint-staged.config.js",
|
|
158
|
+
"lint-staged.config.cjs"
|
|
159
|
+
];
|
|
160
|
+
for (const file of configFiles) {
|
|
161
|
+
const filePath = node_path.resolve(process.cwd(), file);
|
|
162
|
+
if (fs__default.existsSync(filePath)) {
|
|
163
|
+
await fs__default.remove(filePath);
|
|
164
|
+
logger.success(`Removed ${file}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
await updatePackageJson((pkg) => {
|
|
168
|
+
if (pkg.scripts && pkg.scripts.prepare === "husky install") {
|
|
169
|
+
delete pkg.scripts.prepare;
|
|
170
|
+
logger.success("Removed prepare script from package.json");
|
|
171
|
+
}
|
|
172
|
+
return pkg;
|
|
173
|
+
});
|
|
174
|
+
logger.box("Rollback complete! \u{1F519}");
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const cli = cac__default("hy-hooks-git");
|
|
178
|
+
cli.command("init", "Initialize git hooks and configuration").action(async () => {
|
|
179
|
+
try {
|
|
180
|
+
await init();
|
|
181
|
+
} catch (error) {
|
|
182
|
+
logger.error("Initialization failed.");
|
|
183
|
+
console.error(error);
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
cli.command("rollback", "Rollback initialization").action(async () => {
|
|
188
|
+
try {
|
|
189
|
+
await rollback();
|
|
190
|
+
} catch (error) {
|
|
191
|
+
logger.error("Rollback failed.");
|
|
192
|
+
console.error(error);
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
cli.help();
|
|
197
|
+
cli.version(version);
|
|
198
|
+
cli.parse();
|
package/dist/cli.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
package/dist/cli.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import cac from 'cac';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import { resolve } from 'node:path';
|
|
5
|
+
import { consola } from 'consola';
|
|
6
|
+
import { execa } from 'execa';
|
|
7
|
+
import picocolors from 'picocolors';
|
|
8
|
+
|
|
9
|
+
const version = "2.1.0";
|
|
10
|
+
|
|
11
|
+
const logger = {
|
|
12
|
+
/**
|
|
13
|
+
* 输出信息日志
|
|
14
|
+
* @param {string} msg - 日志消息
|
|
15
|
+
*/
|
|
16
|
+
info: (msg) => consola.info(msg),
|
|
17
|
+
/**
|
|
18
|
+
* 输出成功日志
|
|
19
|
+
* @param {string} msg - 日志消息
|
|
20
|
+
*/
|
|
21
|
+
success: (msg) => consola.success(msg),
|
|
22
|
+
/**
|
|
23
|
+
* 输出警告日志
|
|
24
|
+
* @param {string} msg - 日志消息
|
|
25
|
+
*/
|
|
26
|
+
warn: (msg) => consola.warn(msg),
|
|
27
|
+
/**
|
|
28
|
+
* 输出错误日志
|
|
29
|
+
* @param {string} msg - 日志消息
|
|
30
|
+
*/
|
|
31
|
+
error: (msg) => consola.error(msg),
|
|
32
|
+
/**
|
|
33
|
+
* 输出带边框的日志
|
|
34
|
+
* @param {string} msg - 日志消息
|
|
35
|
+
*/
|
|
36
|
+
box: (msg) => {
|
|
37
|
+
console.log(
|
|
38
|
+
picocolors.cyan("\u250C" + "\u2500".repeat(msg.length + 2) + "\u2510") + "\n" + picocolors.cyan("\u2502 ") + msg + picocolors.cyan(" \u2502") + "\n" + picocolors.cyan("\u2514" + "\u2500".repeat(msg.length + 2) + "\u2518")
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const runCommand = async (command, args) => {
|
|
43
|
+
try {
|
|
44
|
+
await execa(command, args, { stdio: "inherit" });
|
|
45
|
+
} catch (error) {
|
|
46
|
+
logger.error(`Failed to run command: ${command} ${args.join(" ")}`);
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const updatePackageJson = async (callback) => {
|
|
51
|
+
const pkgPath = resolve(process.cwd(), "package.json");
|
|
52
|
+
if (!fs.existsSync(pkgPath)) {
|
|
53
|
+
throw new Error("package.json not found");
|
|
54
|
+
}
|
|
55
|
+
const pkg = await fs.readJson(pkgPath);
|
|
56
|
+
const newPkg = callback(pkg);
|
|
57
|
+
await fs.writeJson(pkgPath, newPkg, { spaces: 2 });
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const init = async () => {
|
|
61
|
+
logger.box("Initializing @huaiyou/hooks-git");
|
|
62
|
+
const gitDirPath = resolve(process.cwd(), ".git");
|
|
63
|
+
if (!fs.existsSync(gitDirPath)) {
|
|
64
|
+
logger.warn("Not a git repository. Initializing...");
|
|
65
|
+
await runCommand("git", ["init"]);
|
|
66
|
+
}
|
|
67
|
+
logger.info("Installing Husky...");
|
|
68
|
+
try {
|
|
69
|
+
await runCommand("npx", ["husky", "install"]);
|
|
70
|
+
} catch (e) {
|
|
71
|
+
logger.error("Failed to install husky. Make sure dependencies are installed.");
|
|
72
|
+
}
|
|
73
|
+
logger.info("Adding hooks...");
|
|
74
|
+
const huskyDir = resolve(process.cwd(), ".husky");
|
|
75
|
+
const commitMsgPath = resolve(huskyDir, "commit-msg");
|
|
76
|
+
const commitMsgContent = `npx --no -- commitlint --edit \${1}
|
|
77
|
+
`;
|
|
78
|
+
await fs.outputFile(commitMsgPath, commitMsgContent, { mode: 493 });
|
|
79
|
+
const preCommitPath = resolve(huskyDir, "pre-commit");
|
|
80
|
+
const preCommitContent = `npx lint-staged
|
|
81
|
+
`;
|
|
82
|
+
await fs.outputFile(preCommitPath, preCommitContent, { mode: 493 });
|
|
83
|
+
logger.info("Creating configuration files...");
|
|
84
|
+
const pkgPath = resolve(process.cwd(), "package.json");
|
|
85
|
+
const pkg = await fs.readJson(pkgPath);
|
|
86
|
+
const isModule = pkg.type === "module";
|
|
87
|
+
const isTsProject = fs.existsSync(resolve(process.cwd(), "tsconfig.json"));
|
|
88
|
+
const commitlintFile = isTsProject ? "commitlint.config.ts" : isModule ? "commitlint.config.cjs" : "commitlint.config.js";
|
|
89
|
+
if (!fs.existsSync(resolve(process.cwd(), commitlintFile))) {
|
|
90
|
+
let content = "";
|
|
91
|
+
if (isTsProject) {
|
|
92
|
+
content = `import { commitlintConfig } from '@huaiyou/hooks-git';
|
|
93
|
+
export default commitlintConfig;
|
|
94
|
+
`;
|
|
95
|
+
} else {
|
|
96
|
+
content = `module.exports = require('@huaiyou/hooks-git/commitlint');
|
|
97
|
+
`;
|
|
98
|
+
}
|
|
99
|
+
await fs.writeFile(resolve(process.cwd(), commitlintFile), content);
|
|
100
|
+
logger.success(`Created ${commitlintFile}`);
|
|
101
|
+
} else {
|
|
102
|
+
logger.warn("commitlint config already exists. Skipping...");
|
|
103
|
+
}
|
|
104
|
+
const lintStagedFile = isTsProject ? "lint-staged.config.ts" : isModule ? "lint-staged.config.cjs" : "lint-staged.config.js";
|
|
105
|
+
if (!fs.existsSync(resolve(process.cwd(), lintStagedFile))) {
|
|
106
|
+
let content = "";
|
|
107
|
+
if (isTsProject) {
|
|
108
|
+
content = `import { createLintStagedConfig } from '@huaiyou/hooks-git';
|
|
109
|
+
export default createLintStagedConfig();
|
|
110
|
+
`;
|
|
111
|
+
} else {
|
|
112
|
+
content = `const { createLintStagedConfig } = require('@huaiyou/hooks-git/lint-staged');
|
|
113
|
+
module.exports = createLintStagedConfig();
|
|
114
|
+
`;
|
|
115
|
+
}
|
|
116
|
+
await fs.writeFile(resolve(process.cwd(), lintStagedFile), content);
|
|
117
|
+
logger.success(`Created ${lintStagedFile}`);
|
|
118
|
+
} else {
|
|
119
|
+
logger.warn("lint-staged config already exists. Skipping...");
|
|
120
|
+
}
|
|
121
|
+
if (isTsProject) {
|
|
122
|
+
const hasTsNode = pkg.devDependencies && pkg.devDependencies["ts-node"] || pkg.dependencies && pkg.dependencies["ts-node"];
|
|
123
|
+
if (!hasTsNode) {
|
|
124
|
+
logger.info("Detected TypeScript project. Installing ts-node...");
|
|
125
|
+
await runCommand("pnpm", ["add", "-D", "ts-node"]);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
logger.info("Updating package.json scripts...");
|
|
129
|
+
await updatePackageJson((pkg2) => {
|
|
130
|
+
pkg2.scripts = pkg2.scripts || {};
|
|
131
|
+
if (!pkg2.scripts.prepare || !pkg2.scripts.prepare.includes("husky")) {
|
|
132
|
+
pkg2.scripts.prepare = "husky install";
|
|
133
|
+
}
|
|
134
|
+
return pkg2;
|
|
135
|
+
});
|
|
136
|
+
logger.box("Initialization complete! \u{1F389}");
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const rollback = async () => {
|
|
140
|
+
logger.box("Rolling back @huaiyou/hooks-git initialization");
|
|
141
|
+
const huskyDir = resolve(process.cwd(), ".husky");
|
|
142
|
+
if (fs.existsSync(huskyDir)) {
|
|
143
|
+
await fs.remove(huskyDir);
|
|
144
|
+
logger.success("Removed .husky directory");
|
|
145
|
+
}
|
|
146
|
+
const configFiles = [
|
|
147
|
+
"commitlint.config.js",
|
|
148
|
+
"commitlint.config.cjs",
|
|
149
|
+
"lint-staged.config.js",
|
|
150
|
+
"lint-staged.config.cjs"
|
|
151
|
+
];
|
|
152
|
+
for (const file of configFiles) {
|
|
153
|
+
const filePath = resolve(process.cwd(), file);
|
|
154
|
+
if (fs.existsSync(filePath)) {
|
|
155
|
+
await fs.remove(filePath);
|
|
156
|
+
logger.success(`Removed ${file}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
await updatePackageJson((pkg) => {
|
|
160
|
+
if (pkg.scripts && pkg.scripts.prepare === "husky install") {
|
|
161
|
+
delete pkg.scripts.prepare;
|
|
162
|
+
logger.success("Removed prepare script from package.json");
|
|
163
|
+
}
|
|
164
|
+
return pkg;
|
|
165
|
+
});
|
|
166
|
+
logger.box("Rollback complete! \u{1F519}");
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const cli = cac("hy-hooks-git");
|
|
170
|
+
cli.command("init", "Initialize git hooks and configuration").action(async () => {
|
|
171
|
+
try {
|
|
172
|
+
await init();
|
|
173
|
+
} catch (error) {
|
|
174
|
+
logger.error("Initialization failed.");
|
|
175
|
+
console.error(error);
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
cli.command("rollback", "Rollback initialization").action(async () => {
|
|
180
|
+
try {
|
|
181
|
+
await rollback();
|
|
182
|
+
} catch (error) {
|
|
183
|
+
logger.error("Rollback failed.");
|
|
184
|
+
console.error(error);
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
cli.help();
|
|
189
|
+
cli.version(version);
|
|
190
|
+
cli.parse();
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Configuration = {
|
|
4
|
+
/**
|
|
5
|
+
* 继承的配置
|
|
6
|
+
* 使用 @commitlint/config-conventional 作为基础配置
|
|
7
|
+
*/
|
|
8
|
+
extends: ["@commitlint/config-conventional"],
|
|
9
|
+
/**
|
|
10
|
+
* 提交信息规则配置
|
|
11
|
+
*/
|
|
12
|
+
rules: {
|
|
13
|
+
/**
|
|
14
|
+
* P0: 提交主题必须以小写字母开头
|
|
15
|
+
*/
|
|
16
|
+
"subject-case": [2, "always", "lower-case"],
|
|
17
|
+
/**
|
|
18
|
+
* P0: 提交头信息最大长度为 72 个字符
|
|
19
|
+
*/
|
|
20
|
+
"header-max-length": [2, "always", 72],
|
|
21
|
+
/**
|
|
22
|
+
* P0: 提交主题结尾不能有句号
|
|
23
|
+
*/
|
|
24
|
+
"subject-full-stop": [2, "never", "."],
|
|
25
|
+
/**
|
|
26
|
+
* P0: 提交正文每行最大长度为 72 个字符
|
|
27
|
+
*/
|
|
28
|
+
"body-max-line-length": [2, "always", 72],
|
|
29
|
+
/**
|
|
30
|
+
* P0: 提交脚注每行最大长度为 72 个字符
|
|
31
|
+
*/
|
|
32
|
+
"footer-max-line-length": [2, "always", 72],
|
|
33
|
+
/**
|
|
34
|
+
* 标准提交类型枚举
|
|
35
|
+
* 定义了允许的提交类型及其语义
|
|
36
|
+
*/
|
|
37
|
+
"type-enum": [
|
|
38
|
+
2,
|
|
39
|
+
"always",
|
|
40
|
+
[
|
|
41
|
+
"feat",
|
|
42
|
+
// 新功能
|
|
43
|
+
"fix",
|
|
44
|
+
// Bug 修复
|
|
45
|
+
"docs",
|
|
46
|
+
// 文档更新
|
|
47
|
+
"style",
|
|
48
|
+
// 代码格式(不影响代码运行的变更)
|
|
49
|
+
"refactor",
|
|
50
|
+
// 代码重构(既不是修复也不是新功能)
|
|
51
|
+
"perf",
|
|
52
|
+
// 性能优化
|
|
53
|
+
"test",
|
|
54
|
+
// 添加或修正测试
|
|
55
|
+
"build",
|
|
56
|
+
// 构建系统或外部依赖变更
|
|
57
|
+
"ci",
|
|
58
|
+
// CI 配置文件和脚本变更
|
|
59
|
+
"chore",
|
|
60
|
+
// 其他不修改 src 或 test 文件的变更
|
|
61
|
+
"revert"
|
|
62
|
+
// 回退之前的提交
|
|
63
|
+
]
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
/**
|
|
67
|
+
* 交互式提交提示配置
|
|
68
|
+
* 用于配置 commitizen 等工具的提示信息
|
|
69
|
+
*/
|
|
70
|
+
prompt: {
|
|
71
|
+
/**
|
|
72
|
+
* 提示消息配置
|
|
73
|
+
*/
|
|
74
|
+
messages: {
|
|
75
|
+
skip: "(\u6309\u56DE\u8F66\u8DF3\u8FC7)",
|
|
76
|
+
max: "\u6700\u591A %d \u4E2A\u5B57\u7B26",
|
|
77
|
+
min: "\u81F3\u5C11 %d \u4E2A\u5B57\u7B26",
|
|
78
|
+
empty: "\u4E0D\u80FD\u4E3A\u7A7A",
|
|
79
|
+
upper: "\u5927\u5199",
|
|
80
|
+
lower: "\u5C0F\u5199",
|
|
81
|
+
title: "\u63D0\u4EA4\u4FE1\u606F"
|
|
82
|
+
},
|
|
83
|
+
/**
|
|
84
|
+
* 提示问题配置
|
|
85
|
+
*/
|
|
86
|
+
questions: {
|
|
87
|
+
/**
|
|
88
|
+
* 提交类型选择
|
|
89
|
+
*/
|
|
90
|
+
type: {
|
|
91
|
+
description: "\u9009\u62E9\u63D0\u4EA4\u7C7B\u578B:",
|
|
92
|
+
enum: {
|
|
93
|
+
feat: {
|
|
94
|
+
description: "\u65B0\u529F\u80FD",
|
|
95
|
+
title: "\u529F\u80FD",
|
|
96
|
+
emoji: "\u2728"
|
|
97
|
+
},
|
|
98
|
+
fix: {
|
|
99
|
+
description: "Bug \u4FEE\u590D",
|
|
100
|
+
title: "\u4FEE\u590D",
|
|
101
|
+
emoji: "\u{1F41B}"
|
|
102
|
+
},
|
|
103
|
+
docs: {
|
|
104
|
+
description: "\u4EC5\u6587\u6863\u53D8\u66F4",
|
|
105
|
+
title: "\u6587\u6863",
|
|
106
|
+
emoji: "\u{1F4DA}"
|
|
107
|
+
},
|
|
108
|
+
style: {
|
|
109
|
+
description: "\u4E0D\u5F71\u54CD\u4EE3\u7801\u542B\u4E49\u7684\u53D8\u66F4\uFF08\u7A7A\u767D\u3001\u683C\u5F0F\u3001\u7F3A\u5C11\u5206\u53F7\u7B49\uFF09",
|
|
110
|
+
title: "\u683C\u5F0F",
|
|
111
|
+
emoji: "\u{1F48E}"
|
|
112
|
+
},
|
|
113
|
+
refactor: {
|
|
114
|
+
description: "\u65E2\u4E0D\u662F\u4FEE\u590D\u4E5F\u4E0D\u662F\u65B0\u529F\u80FD\u7684\u4EE3\u7801\u53D8\u66F4",
|
|
115
|
+
title: "\u91CD\u6784",
|
|
116
|
+
emoji: "\u{1F4E6}"
|
|
117
|
+
},
|
|
118
|
+
perf: {
|
|
119
|
+
description: "\u6027\u80FD\u4F18\u5316\u7684\u4EE3\u7801\u53D8\u66F4",
|
|
120
|
+
title: "\u6027\u80FD",
|
|
121
|
+
emoji: "\u{1F680}"
|
|
122
|
+
},
|
|
123
|
+
test: {
|
|
124
|
+
description: "\u6DFB\u52A0\u7F3A\u5931\u7684\u6D4B\u8BD5\u6216\u4FEE\u6B63\u73B0\u6709\u6D4B\u8BD5",
|
|
125
|
+
title: "\u6D4B\u8BD5",
|
|
126
|
+
emoji: "\u{1F6A8}"
|
|
127
|
+
},
|
|
128
|
+
build: {
|
|
129
|
+
description: "\u5F71\u54CD\u6784\u5EFA\u7CFB\u7EDF\u6216\u5916\u90E8\u4F9D\u8D56\u7684\u53D8\u66F4\uFF08\u4F8B\u5982\uFF1Agulp\u3001broccoli\u3001npm\uFF09",
|
|
130
|
+
title: "\u6784\u5EFA",
|
|
131
|
+
emoji: "\u{1F6E0}"
|
|
132
|
+
},
|
|
133
|
+
ci: {
|
|
134
|
+
description: "CI \u914D\u7F6E\u6587\u4EF6\u548C\u811A\u672C\u7684\u53D8\u66F4\uFF08\u4F8B\u5982\uFF1ATravis\u3001Circle\u3001BrowserStack\u3001SauceLabs\uFF09",
|
|
135
|
+
title: "CI",
|
|
136
|
+
emoji: "\u2699\uFE0F"
|
|
137
|
+
},
|
|
138
|
+
chore: {
|
|
139
|
+
description: "\u4E0D\u4FEE\u6539 src \u6216 test \u6587\u4EF6\u7684\u5176\u4ED6\u53D8\u66F4",
|
|
140
|
+
title: "\u6742\u9879",
|
|
141
|
+
emoji: "\u267B\uFE0F"
|
|
142
|
+
},
|
|
143
|
+
revert: {
|
|
144
|
+
description: "\u56DE\u9000\u4E4B\u524D\u7684\u63D0\u4EA4",
|
|
145
|
+
title: "\u56DE\u9000",
|
|
146
|
+
emoji: "\u{1F5D1}"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
/**
|
|
151
|
+
* 提交范围输入
|
|
152
|
+
*/
|
|
153
|
+
scope: {
|
|
154
|
+
description: "\u63D0\u4EA4\u7684\u5F71\u54CD\u8303\u56F4\uFF08\u4F8B\u5982\uFF1A\u7EC4\u4EF6\u6216\u6587\u4EF6\u540D\uFF09:"
|
|
155
|
+
},
|
|
156
|
+
/**
|
|
157
|
+
* 提交主题输入
|
|
158
|
+
*/
|
|
159
|
+
subject: {
|
|
160
|
+
description: "\u7B80\u77ED\u63CF\u8FF0\u53D8\u66F4\u5185\u5BB9\uFF08\u7948\u4F7F\u53E5\uFF09:"
|
|
161
|
+
},
|
|
162
|
+
/**
|
|
163
|
+
* 提交正文输入
|
|
164
|
+
*/
|
|
165
|
+
body: {
|
|
166
|
+
description: "\u63D0\u4F9B\u53D8\u66F4\u7684\u8BE6\u7EC6\u63CF\u8FF0:"
|
|
167
|
+
},
|
|
168
|
+
/**
|
|
169
|
+
* 是否有重大变更
|
|
170
|
+
*/
|
|
171
|
+
isBreaking: {
|
|
172
|
+
description: "\u662F\u5426\u6709\u91CD\u5927\u53D8\u66F4\uFF1F"
|
|
173
|
+
},
|
|
174
|
+
/**
|
|
175
|
+
* 重大变更正文输入
|
|
176
|
+
*/
|
|
177
|
+
breakingBody: {
|
|
178
|
+
description: "\u91CD\u5927\u53D8\u66F4\u63D0\u4EA4\u9700\u8981\u6B63\u6587\u3002\u8BF7\u8F93\u5165\u63D0\u4EA4\u7684\u8BE6\u7EC6\u63CF\u8FF0:"
|
|
179
|
+
},
|
|
180
|
+
/**
|
|
181
|
+
* 重大变更描述输入
|
|
182
|
+
*/
|
|
183
|
+
breaking: {
|
|
184
|
+
description: "\u63CF\u8FF0\u91CD\u5927\u53D8\u66F4:"
|
|
185
|
+
},
|
|
186
|
+
/**
|
|
187
|
+
* 是否影响未解决的问题
|
|
188
|
+
*/
|
|
189
|
+
isIssueAffected: {
|
|
190
|
+
description: "\u6B64\u53D8\u66F4\u662F\u5426\u5F71\u54CD\u672A\u89E3\u51B3\u7684\u95EE\u9898\uFF1F"
|
|
191
|
+
},
|
|
192
|
+
/**
|
|
193
|
+
* 问题关联正文输入
|
|
194
|
+
*/
|
|
195
|
+
issuesBody: {
|
|
196
|
+
description: "\u5982\u679C\u5173\u95ED\u4E86\u95EE\u9898\uFF0C\u63D0\u4EA4\u9700\u8981\u6B63\u6587\u3002\u8BF7\u8F93\u5165\u63D0\u4EA4\u7684\u8BE6\u7EC6\u63CF\u8FF0:"
|
|
197
|
+
},
|
|
198
|
+
/**
|
|
199
|
+
* 问题关联输入
|
|
200
|
+
*/
|
|
201
|
+
issues: {
|
|
202
|
+
description: '\u6DFB\u52A0\u95EE\u9898\u5F15\u7528\uFF08\u4F8B\u5982\uFF1A"fix #123"\u3001"re #123"\uFF09:'
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
module.exports = Configuration;
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
const Configuration = {
|
|
2
|
+
/**
|
|
3
|
+
* 继承的配置
|
|
4
|
+
* 使用 @commitlint/config-conventional 作为基础配置
|
|
5
|
+
*/
|
|
6
|
+
extends: ["@commitlint/config-conventional"],
|
|
7
|
+
/**
|
|
8
|
+
* 提交信息规则配置
|
|
9
|
+
*/
|
|
10
|
+
rules: {
|
|
11
|
+
/**
|
|
12
|
+
* P0: 提交主题必须以小写字母开头
|
|
13
|
+
*/
|
|
14
|
+
"subject-case": [2, "always", "lower-case"],
|
|
15
|
+
/**
|
|
16
|
+
* P0: 提交头信息最大长度为 72 个字符
|
|
17
|
+
*/
|
|
18
|
+
"header-max-length": [2, "always", 72],
|
|
19
|
+
/**
|
|
20
|
+
* P0: 提交主题结尾不能有句号
|
|
21
|
+
*/
|
|
22
|
+
"subject-full-stop": [2, "never", "."],
|
|
23
|
+
/**
|
|
24
|
+
* P0: 提交正文每行最大长度为 72 个字符
|
|
25
|
+
*/
|
|
26
|
+
"body-max-line-length": [2, "always", 72],
|
|
27
|
+
/**
|
|
28
|
+
* P0: 提交脚注每行最大长度为 72 个字符
|
|
29
|
+
*/
|
|
30
|
+
"footer-max-line-length": [2, "always", 72],
|
|
31
|
+
/**
|
|
32
|
+
* 标准提交类型枚举
|
|
33
|
+
* 定义了允许的提交类型及其语义
|
|
34
|
+
*/
|
|
35
|
+
"type-enum": [
|
|
36
|
+
2,
|
|
37
|
+
"always",
|
|
38
|
+
[
|
|
39
|
+
"feat",
|
|
40
|
+
// 新功能
|
|
41
|
+
"fix",
|
|
42
|
+
// Bug 修复
|
|
43
|
+
"docs",
|
|
44
|
+
// 文档更新
|
|
45
|
+
"style",
|
|
46
|
+
// 代码格式(不影响代码运行的变更)
|
|
47
|
+
"refactor",
|
|
48
|
+
// 代码重构(既不是修复也不是新功能)
|
|
49
|
+
"perf",
|
|
50
|
+
// 性能优化
|
|
51
|
+
"test",
|
|
52
|
+
// 添加或修正测试
|
|
53
|
+
"build",
|
|
54
|
+
// 构建系统或外部依赖变更
|
|
55
|
+
"ci",
|
|
56
|
+
// CI 配置文件和脚本变更
|
|
57
|
+
"chore",
|
|
58
|
+
// 其他不修改 src 或 test 文件的变更
|
|
59
|
+
"revert"
|
|
60
|
+
// 回退之前的提交
|
|
61
|
+
]
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
/**
|
|
65
|
+
* 交互式提交提示配置
|
|
66
|
+
* 用于配置 commitizen 等工具的提示信息
|
|
67
|
+
*/
|
|
68
|
+
prompt: {
|
|
69
|
+
/**
|
|
70
|
+
* 提示消息配置
|
|
71
|
+
*/
|
|
72
|
+
messages: {
|
|
73
|
+
skip: "(\u6309\u56DE\u8F66\u8DF3\u8FC7)",
|
|
74
|
+
max: "\u6700\u591A %d \u4E2A\u5B57\u7B26",
|
|
75
|
+
min: "\u81F3\u5C11 %d \u4E2A\u5B57\u7B26",
|
|
76
|
+
empty: "\u4E0D\u80FD\u4E3A\u7A7A",
|
|
77
|
+
upper: "\u5927\u5199",
|
|
78
|
+
lower: "\u5C0F\u5199",
|
|
79
|
+
title: "\u63D0\u4EA4\u4FE1\u606F"
|
|
80
|
+
},
|
|
81
|
+
/**
|
|
82
|
+
* 提示问题配置
|
|
83
|
+
*/
|
|
84
|
+
questions: {
|
|
85
|
+
/**
|
|
86
|
+
* 提交类型选择
|
|
87
|
+
*/
|
|
88
|
+
type: {
|
|
89
|
+
description: "\u9009\u62E9\u63D0\u4EA4\u7C7B\u578B:",
|
|
90
|
+
enum: {
|
|
91
|
+
feat: {
|
|
92
|
+
description: "\u65B0\u529F\u80FD",
|
|
93
|
+
title: "\u529F\u80FD",
|
|
94
|
+
emoji: "\u2728"
|
|
95
|
+
},
|
|
96
|
+
fix: {
|
|
97
|
+
description: "Bug \u4FEE\u590D",
|
|
98
|
+
title: "\u4FEE\u590D",
|
|
99
|
+
emoji: "\u{1F41B}"
|
|
100
|
+
},
|
|
101
|
+
docs: {
|
|
102
|
+
description: "\u4EC5\u6587\u6863\u53D8\u66F4",
|
|
103
|
+
title: "\u6587\u6863",
|
|
104
|
+
emoji: "\u{1F4DA}"
|
|
105
|
+
},
|
|
106
|
+
style: {
|
|
107
|
+
description: "\u4E0D\u5F71\u54CD\u4EE3\u7801\u542B\u4E49\u7684\u53D8\u66F4\uFF08\u7A7A\u767D\u3001\u683C\u5F0F\u3001\u7F3A\u5C11\u5206\u53F7\u7B49\uFF09",
|
|
108
|
+
title: "\u683C\u5F0F",
|
|
109
|
+
emoji: "\u{1F48E}"
|
|
110
|
+
},
|
|
111
|
+
refactor: {
|
|
112
|
+
description: "\u65E2\u4E0D\u662F\u4FEE\u590D\u4E5F\u4E0D\u662F\u65B0\u529F\u80FD\u7684\u4EE3\u7801\u53D8\u66F4",
|
|
113
|
+
title: "\u91CD\u6784",
|
|
114
|
+
emoji: "\u{1F4E6}"
|
|
115
|
+
},
|
|
116
|
+
perf: {
|
|
117
|
+
description: "\u6027\u80FD\u4F18\u5316\u7684\u4EE3\u7801\u53D8\u66F4",
|
|
118
|
+
title: "\u6027\u80FD",
|
|
119
|
+
emoji: "\u{1F680}"
|
|
120
|
+
},
|
|
121
|
+
test: {
|
|
122
|
+
description: "\u6DFB\u52A0\u7F3A\u5931\u7684\u6D4B\u8BD5\u6216\u4FEE\u6B63\u73B0\u6709\u6D4B\u8BD5",
|
|
123
|
+
title: "\u6D4B\u8BD5",
|
|
124
|
+
emoji: "\u{1F6A8}"
|
|
125
|
+
},
|
|
126
|
+
build: {
|
|
127
|
+
description: "\u5F71\u54CD\u6784\u5EFA\u7CFB\u7EDF\u6216\u5916\u90E8\u4F9D\u8D56\u7684\u53D8\u66F4\uFF08\u4F8B\u5982\uFF1Agulp\u3001broccoli\u3001npm\uFF09",
|
|
128
|
+
title: "\u6784\u5EFA",
|
|
129
|
+
emoji: "\u{1F6E0}"
|
|
130
|
+
},
|
|
131
|
+
ci: {
|
|
132
|
+
description: "CI \u914D\u7F6E\u6587\u4EF6\u548C\u811A\u672C\u7684\u53D8\u66F4\uFF08\u4F8B\u5982\uFF1ATravis\u3001Circle\u3001BrowserStack\u3001SauceLabs\uFF09",
|
|
133
|
+
title: "CI",
|
|
134
|
+
emoji: "\u2699\uFE0F"
|
|
135
|
+
},
|
|
136
|
+
chore: {
|
|
137
|
+
description: "\u4E0D\u4FEE\u6539 src \u6216 test \u6587\u4EF6\u7684\u5176\u4ED6\u53D8\u66F4",
|
|
138
|
+
title: "\u6742\u9879",
|
|
139
|
+
emoji: "\u267B\uFE0F"
|
|
140
|
+
},
|
|
141
|
+
revert: {
|
|
142
|
+
description: "\u56DE\u9000\u4E4B\u524D\u7684\u63D0\u4EA4",
|
|
143
|
+
title: "\u56DE\u9000",
|
|
144
|
+
emoji: "\u{1F5D1}"
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
/**
|
|
149
|
+
* 提交范围输入
|
|
150
|
+
*/
|
|
151
|
+
scope: {
|
|
152
|
+
description: "\u63D0\u4EA4\u7684\u5F71\u54CD\u8303\u56F4\uFF08\u4F8B\u5982\uFF1A\u7EC4\u4EF6\u6216\u6587\u4EF6\u540D\uFF09:"
|
|
153
|
+
},
|
|
154
|
+
/**
|
|
155
|
+
* 提交主题输入
|
|
156
|
+
*/
|
|
157
|
+
subject: {
|
|
158
|
+
description: "\u7B80\u77ED\u63CF\u8FF0\u53D8\u66F4\u5185\u5BB9\uFF08\u7948\u4F7F\u53E5\uFF09:"
|
|
159
|
+
},
|
|
160
|
+
/**
|
|
161
|
+
* 提交正文输入
|
|
162
|
+
*/
|
|
163
|
+
body: {
|
|
164
|
+
description: "\u63D0\u4F9B\u53D8\u66F4\u7684\u8BE6\u7EC6\u63CF\u8FF0:"
|
|
165
|
+
},
|
|
166
|
+
/**
|
|
167
|
+
* 是否有重大变更
|
|
168
|
+
*/
|
|
169
|
+
isBreaking: {
|
|
170
|
+
description: "\u662F\u5426\u6709\u91CD\u5927\u53D8\u66F4\uFF1F"
|
|
171
|
+
},
|
|
172
|
+
/**
|
|
173
|
+
* 重大变更正文输入
|
|
174
|
+
*/
|
|
175
|
+
breakingBody: {
|
|
176
|
+
description: "\u91CD\u5927\u53D8\u66F4\u63D0\u4EA4\u9700\u8981\u6B63\u6587\u3002\u8BF7\u8F93\u5165\u63D0\u4EA4\u7684\u8BE6\u7EC6\u63CF\u8FF0:"
|
|
177
|
+
},
|
|
178
|
+
/**
|
|
179
|
+
* 重大变更描述输入
|
|
180
|
+
*/
|
|
181
|
+
breaking: {
|
|
182
|
+
description: "\u63CF\u8FF0\u91CD\u5927\u53D8\u66F4:"
|
|
183
|
+
},
|
|
184
|
+
/**
|
|
185
|
+
* 是否影响未解决的问题
|
|
186
|
+
*/
|
|
187
|
+
isIssueAffected: {
|
|
188
|
+
description: "\u6B64\u53D8\u66F4\u662F\u5426\u5F71\u54CD\u672A\u89E3\u51B3\u7684\u95EE\u9898\uFF1F"
|
|
189
|
+
},
|
|
190
|
+
/**
|
|
191
|
+
* 问题关联正文输入
|
|
192
|
+
*/
|
|
193
|
+
issuesBody: {
|
|
194
|
+
description: "\u5982\u679C\u5173\u95ED\u4E86\u95EE\u9898\uFF0C\u63D0\u4EA4\u9700\u8981\u6B63\u6587\u3002\u8BF7\u8F93\u5165\u63D0\u4EA4\u7684\u8BE6\u7EC6\u63CF\u8FF0:"
|
|
195
|
+
},
|
|
196
|
+
/**
|
|
197
|
+
* 问题关联输入
|
|
198
|
+
*/
|
|
199
|
+
issues: {
|
|
200
|
+
description: '\u6DFB\u52A0\u95EE\u9898\u5F15\u7528\uFF08\u4F8B\u5982\uFF1A"fix #123"\u3001"re #123"\uFF09:'
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
export { Configuration as default };
|
package/dist/index.cjs
CHANGED
|
@@ -1,73 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const lintStaged = require('./lint-staged.cjs');
|
|
4
|
+
const commitlint = require('./commitlint.cjs');
|
|
5
|
+
require('node:fs');
|
|
6
|
+
require('node:path');
|
|
4
7
|
|
|
5
|
-
const types = {
|
|
6
|
-
feat: "\u2728 \u65B0\u529F\u80FD",
|
|
7
|
-
fix: "\u{1F41B} \u4FEE\u590D Bug",
|
|
8
|
-
docs: "\u{1F4DA} \u6587\u6863\u66F4\u65B0",
|
|
9
|
-
style: "\u{1F484} \u4EE3\u7801\u683C\u5F0F\uFF08\u4E0D\u5F71\u54CD\u903B\u8F91\uFF09",
|
|
10
|
-
refactor: "\u267B\uFE0F \u91CD\u6784\u4EE3\u7801\uFF08\u4E0D\u5F71\u54CD\u529F\u80FD\uFF09",
|
|
11
|
-
perf: "\u26A1 \u6027\u80FD\u4F18\u5316",
|
|
12
|
-
test: "\u{1F9EA} \u6D4B\u8BD5\u76F8\u5173",
|
|
13
|
-
chore: "\u{1F527} \u5DE5\u5177\u6216\u811A\u624B\u67B6\u53D8\u66F4",
|
|
14
|
-
ci: "\u2699\uFE0F CI/CD \u76F8\u5173",
|
|
15
|
-
build: "\u{1F6E0} \u6784\u5EFA\u7CFB\u7EDF\u6216\u5916\u90E8\u4F9D\u8D56\u53D8\u66F4",
|
|
16
|
-
revert: "\u23EA \u56DE\u6EDA\u63D0\u4EA4",
|
|
17
|
-
update: "\u2B06\uFE0F \u66F4\u65B0\u67D0\u529F\u80FD\uFF08\u975E\u65B0\u529F\u80FD/\u975E\u4FEE\u590D\uFF09"
|
|
18
|
-
};
|
|
19
|
-
const allowTypes = Object.keys(types);
|
|
20
|
-
const rule$2 = (parsed, when, value) => {
|
|
21
|
-
const type = parsed.type;
|
|
22
|
-
if (!type) {
|
|
23
|
-
return [false, "\u2716 \u8BF7\u586B\u5199\u63D0\u4EA4\u7C7B\u578B\uFF08\u5982 feat / fix / docs\uFF09"];
|
|
24
|
-
}
|
|
25
|
-
if (!allowTypes.includes(type)) {
|
|
26
|
-
const list = allowTypes.map((k) => `- ${k}: ${types[k]}`).join("\n");
|
|
27
|
-
return [false, `\u2716 \u63D0\u4EA4\u7C7B\u578B\u4E0D\u5408\u6CD5\uFF0C\u8BF7\u4ECE\u4EE5\u4E0B\u7C7B\u578B\u4E2D\u9009\u62E9\uFF1A
|
|
28
|
-
${list}`];
|
|
29
|
-
}
|
|
30
|
-
return [true];
|
|
31
|
-
};
|
|
32
8
|
|
|
33
|
-
const rule$1 = (parsed) => {
|
|
34
|
-
const subject = parsed.subject?.trim();
|
|
35
|
-
if (!subject) {
|
|
36
|
-
return [false, "\u2716 \u63D0\u4EA4\u63CF\u8FF0\uFF08subject\uFF09\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8BF7\u8865\u5145\u4E00\u53E5\u6E05\u6670\u63CF\u8FF0"];
|
|
37
|
-
}
|
|
38
|
-
return [true];
|
|
39
|
-
};
|
|
40
9
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return [false, `\u2716 \u63D0\u4EA4\u4FE1\u606F\u8FC7\u957F\uFF08\u5F53\u524D ${header.length} \u5B57\u7B26\uFF09\uFF0C\u6700\u5927\u5141\u8BB8 ${value} \u5B57\u7B26`];
|
|
45
|
-
}
|
|
46
|
-
return [true];
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const rules = {
|
|
50
|
-
"zh-type-enum": rule$2,
|
|
51
|
-
"zh-subject-empty": rule$1,
|
|
52
|
-
"zh-header-max-length": rule
|
|
53
|
-
};
|
|
54
|
-
const plugin = {
|
|
55
|
-
rules
|
|
56
|
-
};
|
|
57
|
-
const config = {
|
|
58
|
-
plugins: ["@huaiyou/hooks-git"],
|
|
59
|
-
rules: {
|
|
60
|
-
"zh-type-enum": [2, "always"],
|
|
61
|
-
"zh-subject-empty": [2, "always"],
|
|
62
|
-
"zh-header-max-length": [2, "always", 72],
|
|
63
|
-
// Disable standard rules that we are replacing or don't need
|
|
64
|
-
"type-enum": [0],
|
|
65
|
-
"type-empty": [0],
|
|
66
|
-
"subject-empty": [0],
|
|
67
|
-
"header-max-length": [0]
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
exports.config = config;
|
|
72
|
-
exports.default = plugin;
|
|
73
|
-
exports.rules = rules;
|
|
10
|
+
exports.createLintStagedConfig = lintStaged.createLintStagedConfig;
|
|
11
|
+
exports.lintStagedConfig = lintStaged.default;
|
|
12
|
+
exports.commitlintConfig = commitlint;
|
package/dist/index.d.cts
ADDED
package/dist/index.d.mts
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
const node_fs = require('node:fs');
|
|
6
|
+
const node_path = require('node:path');
|
|
7
|
+
|
|
8
|
+
const isPackageExists = (name) => {
|
|
9
|
+
try {
|
|
10
|
+
const packageJsonPath = node_path.resolve(process.cwd(), "package.json");
|
|
11
|
+
if (!node_fs.existsSync(packageJsonPath)) return false;
|
|
12
|
+
const packageJson = JSON.parse(node_fs.readFileSync(packageJsonPath, "utf-8"));
|
|
13
|
+
return packageJson.dependencies && packageJson.dependencies[name] || packageJson.devDependencies && packageJson.devDependencies[name];
|
|
14
|
+
} catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const createLintStagedConfig = () => {
|
|
19
|
+
const hasEslint = isPackageExists("eslint");
|
|
20
|
+
const hasPrettier = isPackageExists("prettier");
|
|
21
|
+
const hasStylelint = isPackageExists("stylelint");
|
|
22
|
+
const config = {};
|
|
23
|
+
const scripts = [];
|
|
24
|
+
if (hasEslint) scripts.push("eslint --fix");
|
|
25
|
+
if (hasPrettier) scripts.push("prettier --write");
|
|
26
|
+
if (scripts.length > 0) {
|
|
27
|
+
config["*.{js,jsx,ts,tsx}"] = scripts;
|
|
28
|
+
}
|
|
29
|
+
const vueScripts = [...scripts];
|
|
30
|
+
if (hasStylelint) vueScripts.push("stylelint --fix");
|
|
31
|
+
if (vueScripts.length > 0) {
|
|
32
|
+
config["*.vue"] = vueScripts;
|
|
33
|
+
}
|
|
34
|
+
const styleScripts = [];
|
|
35
|
+
if (hasStylelint) styleScripts.push("stylelint --fix");
|
|
36
|
+
if (hasPrettier) styleScripts.push("prettier --write");
|
|
37
|
+
if (styleScripts.length > 0) {
|
|
38
|
+
config["*.{css,scss,less}"] = styleScripts;
|
|
39
|
+
}
|
|
40
|
+
if (hasPrettier) {
|
|
41
|
+
config["*.{html,json,md,yml,yaml}"] = ["prettier --write"];
|
|
42
|
+
}
|
|
43
|
+
return config;
|
|
44
|
+
};
|
|
45
|
+
const lintStaged = createLintStagedConfig();
|
|
46
|
+
|
|
47
|
+
exports.createLintStagedConfig = createLintStagedConfig;
|
|
48
|
+
exports.default = lintStaged;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
|
|
4
|
+
const isPackageExists = (name) => {
|
|
5
|
+
try {
|
|
6
|
+
const packageJsonPath = resolve(process.cwd(), "package.json");
|
|
7
|
+
if (!existsSync(packageJsonPath)) return false;
|
|
8
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
9
|
+
return packageJson.dependencies && packageJson.dependencies[name] || packageJson.devDependencies && packageJson.devDependencies[name];
|
|
10
|
+
} catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const createLintStagedConfig = () => {
|
|
15
|
+
const hasEslint = isPackageExists("eslint");
|
|
16
|
+
const hasPrettier = isPackageExists("prettier");
|
|
17
|
+
const hasStylelint = isPackageExists("stylelint");
|
|
18
|
+
const config = {};
|
|
19
|
+
const scripts = [];
|
|
20
|
+
if (hasEslint) scripts.push("eslint --fix");
|
|
21
|
+
if (hasPrettier) scripts.push("prettier --write");
|
|
22
|
+
if (scripts.length > 0) {
|
|
23
|
+
config["*.{js,jsx,ts,tsx}"] = scripts;
|
|
24
|
+
}
|
|
25
|
+
const vueScripts = [...scripts];
|
|
26
|
+
if (hasStylelint) vueScripts.push("stylelint --fix");
|
|
27
|
+
if (vueScripts.length > 0) {
|
|
28
|
+
config["*.vue"] = vueScripts;
|
|
29
|
+
}
|
|
30
|
+
const styleScripts = [];
|
|
31
|
+
if (hasStylelint) styleScripts.push("stylelint --fix");
|
|
32
|
+
if (hasPrettier) styleScripts.push("prettier --write");
|
|
33
|
+
if (styleScripts.length > 0) {
|
|
34
|
+
config["*.{css,scss,less}"] = styleScripts;
|
|
35
|
+
}
|
|
36
|
+
if (hasPrettier) {
|
|
37
|
+
config["*.{html,json,md,yml,yaml}"] = ["prettier --write"];
|
|
38
|
+
}
|
|
39
|
+
return config;
|
|
40
|
+
};
|
|
41
|
+
const lintStaged = createLintStagedConfig();
|
|
42
|
+
|
|
43
|
+
export { createLintStagedConfig, lintStaged as default };
|
package/package.json
CHANGED
|
@@ -1,45 +1,68 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@huaiyou/hooks-git",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Git hooks configuration with Husky, Commitlint and Lint-staged",
|
|
5
|
+
"bin": {
|
|
6
|
+
"hy-hooks-git": "./dist/cli.mjs"
|
|
7
|
+
},
|
|
5
8
|
"files": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
9
|
+
"dist",
|
|
10
|
+
"bin",
|
|
8
11
|
"README.md",
|
|
9
12
|
"CHANGELOG.md"
|
|
10
13
|
],
|
|
11
14
|
"main": "./dist/index.cjs",
|
|
12
15
|
"module": "./dist/index.mjs",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
13
17
|
"exports": {
|
|
14
18
|
".": {
|
|
15
19
|
"require": "./dist/index.cjs",
|
|
16
|
-
"import": "./dist/index.mjs"
|
|
20
|
+
"import": "./dist/index.mjs",
|
|
21
|
+
"types": "./dist/index.d.ts"
|
|
22
|
+
},
|
|
23
|
+
"./commitlint": {
|
|
24
|
+
"require": "./dist/commitlint.cjs",
|
|
25
|
+
"import": "./dist/commitlint.mjs",
|
|
26
|
+
"types": "./dist/commitlint.d.ts"
|
|
27
|
+
},
|
|
28
|
+
"./lint-staged": {
|
|
29
|
+
"require": "./dist/lint-staged.cjs",
|
|
30
|
+
"import": "./dist/lint-staged.mjs",
|
|
31
|
+
"types": "./dist/lint-staged.d.ts"
|
|
17
32
|
}
|
|
18
33
|
},
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"@huaiyou/config-ts": "^1.0.0"
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "unbuild",
|
|
36
|
+
"dev": "unbuild --stub",
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"test:watch": "vitest",
|
|
39
|
+
"test:ui": "vitest --ui",
|
|
40
|
+
"prepublishOnly": "npm run build"
|
|
27
41
|
},
|
|
28
42
|
"dependencies": {
|
|
29
|
-
"
|
|
43
|
+
"@commitlint/cli": "^19.3.0",
|
|
44
|
+
"@commitlint/config-conventional": "^19.2.2",
|
|
45
|
+
"cac": "^6.7.14",
|
|
46
|
+
"consola": "^3.2.3",
|
|
47
|
+
"execa": "^8.0.1",
|
|
48
|
+
"fs-extra": "^11.2.0",
|
|
49
|
+
"husky": "^9.0.11",
|
|
50
|
+
"lint-staged": "^15.2.2",
|
|
51
|
+
"minimatch": "^10.1.1",
|
|
52
|
+
"picocolors": "^1.0.0"
|
|
30
53
|
},
|
|
31
|
-
"
|
|
32
|
-
"@commitlint/
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@commitlint/types": "^19.0.3",
|
|
56
|
+
"@huaiyou/config-ts": "workspace:^",
|
|
57
|
+
"@types/fs-extra": "^11.0.4",
|
|
58
|
+
"@types/minimatch": "^6.0.0",
|
|
59
|
+
"@types/node": "^20.12.7",
|
|
60
|
+
"typescript": "^5.4.5",
|
|
61
|
+
"unbuild": "^3.6.1",
|
|
62
|
+
"vitest": "catalog:"
|
|
33
63
|
},
|
|
34
64
|
"publishConfig": {
|
|
35
65
|
"access": "public",
|
|
36
66
|
"registry": "https://registry.npmjs.org/"
|
|
37
|
-
},
|
|
38
|
-
"scripts": {
|
|
39
|
-
"build": "unbuild",
|
|
40
|
-
"dev": "unbuild --stub",
|
|
41
|
-
"test": "vitest run",
|
|
42
|
-
"test:watch": "vitest",
|
|
43
|
-
"test:ui": "vitest --ui"
|
|
44
67
|
}
|
|
45
|
-
}
|
|
68
|
+
}
|
package/.husky/commit-msg
DELETED
package/.husky/pre-commit
DELETED