long-git-cli 1.0.0 → 1.0.2
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/README.md +63 -45
- package/dist/commands/commit.d.ts +5 -0
- package/dist/commands/commit.d.ts.map +1 -0
- package/dist/commands/commit.js +133 -0
- package/dist/commands/commit.js.map +1 -0
- package/dist/commands/tag.d.ts +3 -3
- package/dist/commands/tag.d.ts.map +1 -1
- package/dist/commands/tag.js +76 -276
- package/dist/commands/tag.js.map +1 -1
- package/dist/constants.d.ts +6 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +16 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/error.d.ts +7 -0
- package/dist/utils/error.d.ts.map +1 -0
- package/dist/utils/error.js +21 -0
- package/dist/utils/error.js.map +1 -0
- package/dist/utils/git-remote.d.ts +22 -0
- package/dist/utils/git-remote.d.ts.map +1 -0
- package/dist/utils/git-remote.js +77 -0
- package/dist/utils/git-remote.js.map +1 -0
- package/dist/utils/git.d.ts +29 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +129 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/loading.d.ts +14 -0
- package/dist/utils/loading.d.ts.map +1 -0
- package/dist/utils/loading.js +33 -0
- package/dist/utils/loading.js.map +1 -0
- package/dist/utils/message.d.ts +8 -0
- package/dist/utils/message.d.ts.map +1 -0
- package/dist/utils/message.js +36 -0
- package/dist/utils/message.js.map +1 -0
- package/dist/utils/prompt.d.ts +22 -0
- package/dist/utils/prompt.d.ts.map +1 -0
- package/dist/utils/prompt.js +63 -0
- package/dist/utils/prompt.js.map +1 -0
- package/dist/utils/tag.d.ts +10 -0
- package/dist/utils/tag.d.ts.map +1 -0
- package/dist/utils/tag.js +41 -0
- package/dist/utils/tag.js.map +1 -0
- package/package.json +18 -6
package/dist/commands/tag.js
CHANGED
|
@@ -1,248 +1,111 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
5
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
36
|
exports.tagCommand = tagCommand;
|
|
7
37
|
const simple_git_1 = require("simple-git");
|
|
8
|
-
const
|
|
9
|
-
const
|
|
38
|
+
const git_remote_1 = require("../utils/git-remote");
|
|
39
|
+
const git_1 = require("../utils/git");
|
|
40
|
+
const tag_1 = require("../utils/tag");
|
|
41
|
+
const constants_1 = require("../constants");
|
|
42
|
+
const prompt = __importStar(require("../utils/prompt"));
|
|
43
|
+
const message_1 = require("../utils/message");
|
|
10
44
|
// Git 操作实例
|
|
11
45
|
const git = (0, simple_git_1.simpleGit)();
|
|
12
|
-
// 受保护的分支列表(不允许在这些分支上打 tag)
|
|
13
|
-
const PROTECTED_BRANCHES = ['master', 'main', 'release'];
|
|
14
|
-
// 支持的远程仓库类型
|
|
15
|
-
const REMOTE_TYPES = {
|
|
16
|
-
GITHUB: 'github',
|
|
17
|
-
BITBUCKET: 'bitbucket',
|
|
18
|
-
GITLAB: 'gitlab',
|
|
19
|
-
UNKNOWN: 'unknown'
|
|
20
|
-
};
|
|
21
46
|
/**
|
|
22
47
|
* 主要的 tag 命令处理函数
|
|
23
|
-
* 执行完整的 tag 创建流程:检查分支 -> 检测仓库 -> 拉取最新信息 -> 创建新 tag -> 推送
|
|
24
|
-
* @param skipPrompt 是否跳过确认,直接推送
|
|
25
48
|
*/
|
|
26
|
-
async function tagCommand(
|
|
27
|
-
|
|
49
|
+
async function tagCommand(options) {
|
|
50
|
+
(0, message_1.printInfo)('🚀 开始自动打 tag...');
|
|
28
51
|
try {
|
|
29
52
|
// 0. 检查当前分支是否受保护
|
|
30
|
-
const branch = await getCurrentBranch();
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
|
|
53
|
+
const branch = await (0, git_1.getCurrentBranch)();
|
|
54
|
+
if (constants_1.PROTECTED_BRANCHES.includes(branch)) {
|
|
55
|
+
(0, message_1.printError)(`当前分支为 "${branch}",禁止在主分支(${constants_1.PROTECTED_BRANCHES.join('、')})上打 tag!`);
|
|
56
|
+
(0, message_1.printWarning)('💡 请切换到 feature、dev 或其他非主分支后再执行打 tag 操作。');
|
|
34
57
|
return;
|
|
35
58
|
}
|
|
36
59
|
// 1. 检查是否在 Git 仓库中
|
|
37
|
-
await checkGitRepository();
|
|
60
|
+
await (0, git_1.checkGitRepository)();
|
|
38
61
|
// 2. 检测远程仓库类型
|
|
39
|
-
const remoteInfo = await detectRemoteType();
|
|
62
|
+
const remoteInfo = await (0, git_remote_1.detectRemoteType)();
|
|
40
63
|
if (remoteInfo) {
|
|
41
|
-
|
|
64
|
+
(0, message_1.printInfo)(`🌐 检测到远程仓库: ${remoteInfo.type} (${remoteInfo.url})`);
|
|
42
65
|
}
|
|
43
66
|
// 3. 拉取最新的远程信息
|
|
44
|
-
await fetchLatestTags(
|
|
45
|
-
// 4.
|
|
46
|
-
const latestTag = await
|
|
67
|
+
await (0, git_1.fetchLatestTags)();
|
|
68
|
+
// 4. 获取最新的 tag
|
|
69
|
+
const latestTag = await (0, git_1.getLatestTag)();
|
|
47
70
|
if (!latestTag) {
|
|
48
|
-
|
|
71
|
+
(0, message_1.printWarning)('⚠️ 没有找到现有的 tag,将创建初始 tag: test-v00.00.0001');
|
|
72
|
+
await createInitialTag(remoteInfo);
|
|
49
73
|
return;
|
|
50
74
|
}
|
|
51
|
-
// 5. 解析当前 tag
|
|
52
|
-
const currentTagInfo = parseTag(latestTag);
|
|
53
|
-
|
|
75
|
+
// 5. 解析当前 tag
|
|
76
|
+
const currentTagInfo = (0, tag_1.parseTag)(latestTag);
|
|
77
|
+
(0, message_1.printSuccess)(`📋 当前最新 tag: ${latestTag}`);
|
|
54
78
|
// 6. 生成新版本号
|
|
55
|
-
const newTagInfo = incrementVersion(currentTagInfo);
|
|
56
|
-
const newTag = formatTag(newTagInfo);
|
|
57
|
-
|
|
58
|
-
// 7.
|
|
59
|
-
if (!
|
|
60
|
-
const confirmed = await
|
|
79
|
+
const newTagInfo = (0, tag_1.incrementVersion)(currentTagInfo);
|
|
80
|
+
const newTag = (0, tag_1.formatTag)(newTagInfo);
|
|
81
|
+
(0, message_1.printInfo)(`🆕 新 tag: ${newTag}`);
|
|
82
|
+
// 7. 询问用户是否确认
|
|
83
|
+
if (!(options && options.pass)) {
|
|
84
|
+
const confirmed = await prompt.confirm(`是否确认创建并推送新 tag: ${newTag}?`);
|
|
61
85
|
if (!confirmed) {
|
|
62
|
-
|
|
86
|
+
(0, message_1.printWarning)('🚫 已取消 tag 创建与推送。');
|
|
63
87
|
return;
|
|
64
88
|
}
|
|
65
89
|
}
|
|
66
90
|
// 8. 创建并推送新 tag
|
|
67
91
|
await createAndPushTag(newTag, remoteInfo);
|
|
68
|
-
|
|
92
|
+
(0, message_1.printSuccess)('✅ Tag 创建并推送成功!');
|
|
69
93
|
}
|
|
70
94
|
catch (error) {
|
|
71
95
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
72
96
|
throw new Error(`Tag 操作失败: ${errorMessage}`);
|
|
73
97
|
}
|
|
74
98
|
}
|
|
75
|
-
/**
|
|
76
|
-
* 检查当前目录是否为有效的 Git 仓库
|
|
77
|
-
* @throws {Error} 如果不是 Git 仓库则抛出错误
|
|
78
|
-
*/
|
|
79
|
-
async function checkGitRepository() {
|
|
80
|
-
try {
|
|
81
|
-
await git.status();
|
|
82
|
-
}
|
|
83
|
-
catch (error) {
|
|
84
|
-
throw new Error('当前目录不是 Git 仓库,请先初始化 Git 仓库');
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* 检测远程仓库类型(GitHub、Bitbucket、GitLab 等)
|
|
89
|
-
* @returns {Promise<RemoteInfo | null>} 远程仓库信息,如果没有配置远程仓库则返回 null
|
|
90
|
-
*/
|
|
91
|
-
async function detectRemoteType() {
|
|
92
|
-
try {
|
|
93
|
-
const remotes = await git.getRemotes(true);
|
|
94
|
-
if (remotes.length === 0) {
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
const origin = remotes.find(remote => remote.name === 'origin');
|
|
98
|
-
if (!origin) {
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
const url = origin.refs.push || origin.refs.fetch;
|
|
102
|
-
if (!url) {
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
let type = REMOTE_TYPES.UNKNOWN;
|
|
106
|
-
if (url.includes('github.com')) {
|
|
107
|
-
type = REMOTE_TYPES.GITHUB;
|
|
108
|
-
}
|
|
109
|
-
else if (url.includes('bitbucket.org') || url.includes('bitbucket.com')) {
|
|
110
|
-
type = REMOTE_TYPES.BITBUCKET;
|
|
111
|
-
}
|
|
112
|
-
else if (url.includes('gitlab.com')) {
|
|
113
|
-
type = REMOTE_TYPES.GITLAB;
|
|
114
|
-
}
|
|
115
|
-
return {
|
|
116
|
-
name: origin.name,
|
|
117
|
-
url,
|
|
118
|
-
type
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
catch (error) {
|
|
122
|
-
console.log(chalk_1.default.yellow('⚠️ 无法检测远程仓库类型'));
|
|
123
|
-
return null;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* 拉取最新的远程 tag 信息
|
|
128
|
-
* 如果拉取失败,会继续使用本地 tag 信息
|
|
129
|
-
* @param {RemoteInfo | null} remoteInfo - 远程仓库信息
|
|
130
|
-
*/
|
|
131
|
-
async function fetchLatestTags(remoteInfo) {
|
|
132
|
-
console.log(chalk_1.default.blue('📥 拉取最新的远程信息...'));
|
|
133
|
-
try {
|
|
134
|
-
if (remoteInfo?.type === REMOTE_TYPES.BITBUCKET) {
|
|
135
|
-
// Bitbucket 推荐指定 origin
|
|
136
|
-
await git.fetch('origin', '--tags');
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
await git.fetch(['--tags']);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
catch (error) {
|
|
143
|
-
console.log(chalk_1.default.yellow('⚠️ 拉取远程信息失败,将使用本地 tag'));
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* 获取最新的有效 tag
|
|
148
|
-
* 只返回格式正确的 test-v00.00.0000 tag,按版本号排序返回最新的
|
|
149
|
-
* @returns {Promise<string | null>} 最新的有效 tag,如果没有则返回 null
|
|
150
|
-
*/
|
|
151
|
-
async function getLatestValidTag() {
|
|
152
|
-
try {
|
|
153
|
-
const tags = await git.tags();
|
|
154
|
-
if (!tags || !Array.isArray(tags.all)) {
|
|
155
|
-
console.log(chalk_1.default.yellow('⚠️ 未能正确获取 tag 列表,tags:', tags));
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
// 只保留格式正确的 tag
|
|
159
|
-
const validTags = tags.all.filter(tag => {
|
|
160
|
-
try {
|
|
161
|
-
return !!parseTag(tag);
|
|
162
|
-
}
|
|
163
|
-
catch {
|
|
164
|
-
return false;
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
if (validTags.length === 0) {
|
|
168
|
-
return null;
|
|
169
|
-
}
|
|
170
|
-
validTags.sort((a, b) => {
|
|
171
|
-
const aInfo = parseTag(a);
|
|
172
|
-
const bInfo = parseTag(b);
|
|
173
|
-
return compareVersions(aInfo, bInfo);
|
|
174
|
-
});
|
|
175
|
-
return validTags[validTags.length - 1];
|
|
176
|
-
}
|
|
177
|
-
catch (error) {
|
|
178
|
-
console.log(chalk_1.default.red('❌ 获取 tag 列表失败,错误信息:'), error);
|
|
179
|
-
return null;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* 解析 tag 字符串,提取版本号信息
|
|
184
|
-
* @param {string} tag - 要解析的 tag 字符串,格式为 test-v00.00.0000
|
|
185
|
-
* @returns {TagInfo} 解析后的 tag 信息对象
|
|
186
|
-
* @throws {Error} 如果 tag 格式不正确则抛出错误
|
|
187
|
-
*/
|
|
188
|
-
function parseTag(tag) {
|
|
189
|
-
const match = tag.match(/^test-v(\d+)\.(\d+)\.(\d{4})$/);
|
|
190
|
-
if (!match) {
|
|
191
|
-
throw new Error(`无效的 tag 格式: ${tag},期望格式: test-v00.00.0000`);
|
|
192
|
-
}
|
|
193
|
-
return {
|
|
194
|
-
version: tag,
|
|
195
|
-
major: parseInt(match[1], 10),
|
|
196
|
-
minor: parseInt(match[2], 10),
|
|
197
|
-
patch: parseInt(match[3], 10),
|
|
198
|
-
build: parseInt(match[3], 10)
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* 递增版本号,将 build 和 patch 版本号加 1
|
|
203
|
-
* @param {TagInfo} tagInfo - 当前版本信息
|
|
204
|
-
* @returns {TagInfo} 递增后的版本信息
|
|
205
|
-
*/
|
|
206
|
-
function incrementVersion(tagInfo) {
|
|
207
|
-
return {
|
|
208
|
-
...tagInfo,
|
|
209
|
-
build: tagInfo.build + 1,
|
|
210
|
-
patch: tagInfo.build + 1
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* 格式化版本信息为 tag 字符串
|
|
215
|
-
* @param {TagInfo} tagInfo - 版本信息对象
|
|
216
|
-
* @returns {string} 格式化后的 tag 字符串
|
|
217
|
-
*/
|
|
218
|
-
function formatTag(tagInfo) {
|
|
219
|
-
return `test-v${tagInfo.major.toString().padStart(2, '0')}.${tagInfo.minor.toString().padStart(2, '0')}.${tagInfo.build.toString().padStart(4, '0')}`;
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* 比较两个版本号的大小
|
|
223
|
-
* @param {TagInfo} a - 第一个版本信息
|
|
224
|
-
* @param {TagInfo} b - 第二个版本信息
|
|
225
|
-
* @returns {number} 比较结果:负数表示 a < b,0 表示相等,正数表示 a > b
|
|
226
|
-
*/
|
|
227
|
-
function compareVersions(a, b) {
|
|
228
|
-
if (a.major !== b.major)
|
|
229
|
-
return a.major - b.major;
|
|
230
|
-
if (a.minor !== b.minor)
|
|
231
|
-
return a.minor - b.minor;
|
|
232
|
-
return a.build - b.build;
|
|
233
|
-
}
|
|
234
99
|
/**
|
|
235
100
|
* 创建初始 tag(当没有现有 tag 时调用)
|
|
236
|
-
* 创建 test-v00.00.0001 作为第一个 tag
|
|
237
101
|
*/
|
|
238
|
-
async function createInitialTag() {
|
|
102
|
+
async function createInitialTag(remoteInfo) {
|
|
239
103
|
const initialTag = 'test-v00.00.0001';
|
|
240
|
-
|
|
104
|
+
(0, message_1.printInfo)(`🏷️ 创建初始 tag: ${initialTag}`);
|
|
241
105
|
try {
|
|
242
106
|
await git.addTag(initialTag);
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
await pushTagWithFallback();
|
|
107
|
+
(0, message_1.printSuccess)('✅ 初始 tag 创建成功');
|
|
108
|
+
await pushTagWithFallback(remoteInfo);
|
|
246
109
|
}
|
|
247
110
|
catch (error) {
|
|
248
111
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -251,17 +114,12 @@ async function createInitialTag() {
|
|
|
251
114
|
}
|
|
252
115
|
/**
|
|
253
116
|
* 创建并推送 tag
|
|
254
|
-
* @param {string} tag - 要创建的 tag 名称
|
|
255
|
-
* @param {RemoteInfo | null} remoteInfo - 远程仓库信息
|
|
256
117
|
*/
|
|
257
118
|
async function createAndPushTag(tag, remoteInfo) {
|
|
258
|
-
|
|
119
|
+
(0, message_1.printInfo)(`🏷️ 创建 tag: ${tag}`);
|
|
259
120
|
try {
|
|
260
|
-
// 创建 tag
|
|
261
121
|
await git.addTag(tag);
|
|
262
|
-
|
|
263
|
-
// 尝试推送 tag
|
|
264
|
-
console.log(chalk_1.default.blue('📤 推送 tag 到远程仓库...'));
|
|
122
|
+
(0, message_1.printSuccess)(`✅ Tag ${tag} 创建成功`);
|
|
265
123
|
await pushTagWithFallback(remoteInfo);
|
|
266
124
|
}
|
|
267
125
|
catch (error) {
|
|
@@ -271,79 +129,21 @@ async function createAndPushTag(tag, remoteInfo) {
|
|
|
271
129
|
}
|
|
272
130
|
/**
|
|
273
131
|
* 推送 tag 到远程仓库,如果失败则给出友好提示
|
|
274
|
-
* @param {RemoteInfo | null} remoteInfo - 远程仓库信息
|
|
275
132
|
*/
|
|
276
133
|
async function pushTagWithFallback(remoteInfo) {
|
|
277
134
|
try {
|
|
278
|
-
await
|
|
279
|
-
|
|
280
|
-
// 根据远程仓库类型提供特定提示
|
|
135
|
+
await (0, git_1.pushTags)();
|
|
136
|
+
(0, message_1.printSuccess)('✅ Tag 推送成功');
|
|
281
137
|
if (remoteInfo) {
|
|
282
|
-
showRemoteSpecificTips(remoteInfo.type);
|
|
138
|
+
(0, git_remote_1.showRemoteSpecificTips)(remoteInfo.type);
|
|
283
139
|
}
|
|
284
140
|
}
|
|
285
141
|
catch (pushError) {
|
|
286
|
-
|
|
287
|
-
|
|
142
|
+
(0, message_1.printWarning)('⚠️ Tag 推送失败,但本地 tag 已创建成功');
|
|
143
|
+
(0, message_1.printInfo)('💡 提示:如果需要推送到远程仓库,请先配置远程仓库');
|
|
288
144
|
if (remoteInfo) {
|
|
289
|
-
|
|
145
|
+
(0, message_1.printInfo)(`🔧 当前远程仓库: ${remoteInfo.type} (${remoteInfo.url})`);
|
|
290
146
|
}
|
|
291
147
|
}
|
|
292
148
|
}
|
|
293
|
-
/**
|
|
294
|
-
* 根据远程仓库类型显示特定的提示信息
|
|
295
|
-
* @param {RemoteInfo['type']} remoteType - 远程仓库类型
|
|
296
|
-
*/
|
|
297
|
-
function showRemoteSpecificTips(remoteType) {
|
|
298
|
-
switch (remoteType) {
|
|
299
|
-
case REMOTE_TYPES.BITBUCKET:
|
|
300
|
-
console.log(chalk_1.default.blue('🔗 你可以在 Bitbucket 上查看新创建的 tag'));
|
|
301
|
-
console.log(chalk_1.default.blue('💡 提示:在 Bitbucket 中,你可以在 "Tags" 页面查看所有 tag'));
|
|
302
|
-
break;
|
|
303
|
-
case REMOTE_TYPES.GITHUB:
|
|
304
|
-
console.log(chalk_1.default.blue('🔗 你可以在 GitHub 上查看新创建的 tag'));
|
|
305
|
-
console.log(chalk_1.default.blue('💡 提示:在 GitHub 中,你可以在 "Releases" 页面查看所有 tag'));
|
|
306
|
-
break;
|
|
307
|
-
case REMOTE_TYPES.GITLAB:
|
|
308
|
-
console.log(chalk_1.default.blue('🔗 你可以在 GitLab 上查看新创建的 tag'));
|
|
309
|
-
console.log(chalk_1.default.blue('💡 提示:在 GitLab 中,你可以在 "Repository > Tags" 页面查看所有 tag'));
|
|
310
|
-
break;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
/**
|
|
314
|
-
* 获取当前分支名称
|
|
315
|
-
* @returns {Promise<string>} 当前分支名称
|
|
316
|
-
* @throws {Error} 如果无法获取分支名称则抛出错误
|
|
317
|
-
*/
|
|
318
|
-
async function getCurrentBranch() {
|
|
319
|
-
const status = await git.status();
|
|
320
|
-
// status.current 可能为 null,做兼容处理
|
|
321
|
-
if (!status.current) {
|
|
322
|
-
throw new Error('无法获取当前分支名称,请确认已在有效的 git 分支上');
|
|
323
|
-
}
|
|
324
|
-
return status.current;
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* 检查分支是否为受保护分支
|
|
328
|
-
* @param {string} branch - 分支名称
|
|
329
|
-
* @returns {boolean} 如果是受保护分支则返回 true,否则返回 false
|
|
330
|
-
*/
|
|
331
|
-
function isProtectedBranch(branch) {
|
|
332
|
-
return PROTECTED_BRANCHES.includes(branch);
|
|
333
|
-
}
|
|
334
|
-
/**
|
|
335
|
-
* 命令行确认
|
|
336
|
-
*/
|
|
337
|
-
function promptConfirm(question) {
|
|
338
|
-
return new Promise((resolve) => {
|
|
339
|
-
const rl = readline_1.default.createInterface({
|
|
340
|
-
input: process.stdin,
|
|
341
|
-
output: process.stdout
|
|
342
|
-
});
|
|
343
|
-
rl.question(question, (answer) => {
|
|
344
|
-
rl.close();
|
|
345
|
-
resolve(answer.trim().toLowerCase() === 'y');
|
|
346
|
-
});
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
149
|
//# sourceMappingURL=tag.js.map
|
package/dist/commands/tag.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tag.js","sourceRoot":"","sources":["../../src/commands/tag.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tag.js","sourceRoot":"","sources":["../../src/commands/tag.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,wCAAyC,CAAC;AAEzE,eAAO,MAAM,WAAW;;;GAUvB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.commitTypes = exports.PROTECTED_BRANCHES = void 0;
|
|
4
|
+
exports.PROTECTED_BRANCHES = ['master', 'main', 'release'];
|
|
5
|
+
exports.commitTypes = [
|
|
6
|
+
{ name: 'feat: 新功能', value: 'feat' },
|
|
7
|
+
{ name: 'fix: 修复 bug', value: 'fix' },
|
|
8
|
+
{ name: 'docs: 文档变更', value: 'docs' },
|
|
9
|
+
{ name: 'style: 代码格式(不影响功能,如空格、分号等)', value: 'style' },
|
|
10
|
+
{ name: 'refactor: 代码重构(不包括 bug 修复、功能新增)', value: 'refactor' },
|
|
11
|
+
{ name: 'perf: 性能优化', value: 'perf' },
|
|
12
|
+
{ name: 'test: 增加/修改测试', value: 'test' },
|
|
13
|
+
{ name: 'chore: 构建流程/工具变更', value: 'chore' },
|
|
14
|
+
{ name: 'revert: 回滚提交', value: 'revert' }
|
|
15
|
+
];
|
|
16
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,kBAAkB,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAU,CAAC;AAE5D,QAAA,WAAW,GAAG;IACzB,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE;IACxC,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,KAAK,EAAE;IAC1C,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,EAAE;IACzC,EAAE,IAAI,EAAE,+BAA+B,EAAE,KAAK,EAAE,OAAO,EAAE;IACzD,EAAE,IAAI,EAAE,iCAAiC,EAAE,KAAK,EAAE,UAAU,EAAE;IAC9D,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,EAAE;IACzC,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,EAAE;IAC5C,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE;IAC/C,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,QAAQ,EAAE;CAC5C,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
const commander_1 = require("commander");
|
|
8
8
|
const tag_1 = require("./commands/tag");
|
|
9
|
+
const commit_1 = require("./commands/commit");
|
|
9
10
|
const chalk_1 = __importDefault(require("chalk"));
|
|
10
11
|
const program = new commander_1.Command();
|
|
11
12
|
program
|
|
@@ -19,12 +20,19 @@ program
|
|
|
19
20
|
.option('-p, --pass', '跳过 tag 号确认,直接创建并推送')
|
|
20
21
|
.action(async (options) => {
|
|
21
22
|
try {
|
|
22
|
-
await (0, tag_1.tagCommand)(options
|
|
23
|
+
await (0, tag_1.tagCommand)(options);
|
|
23
24
|
}
|
|
24
25
|
catch (error) {
|
|
25
26
|
console.error(chalk_1.default.red('错误:'), error instanceof Error ? error.message : String(error));
|
|
26
27
|
process.exit(1);
|
|
27
28
|
}
|
|
28
29
|
});
|
|
30
|
+
// 注册 commit 命令
|
|
31
|
+
program
|
|
32
|
+
.command('commit')
|
|
33
|
+
.description('交互式规范化 commit 并 push')
|
|
34
|
+
.action(async () => {
|
|
35
|
+
await (0, commit_1.commitCommand)();
|
|
36
|
+
});
|
|
29
37
|
program.parse();
|
|
30
38
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAEA,yCAAoC;AACpC,wCAA4C;AAC5C,kDAA0B;AAE1B,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,MAAM,CAAC;KACZ,WAAW,CAAC,uBAAuB,CAAC;KACpC,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,YAAY;AACZ,OAAO;KACJ,OAAO,CAAC,KAAK,CAAC;KACd,WAAW,CAAC,mCAAmC,CAAC;KAChD,MAAM,CAAC,YAAY,EAAE,oBAAoB,CAAC;KAC1C,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,IAAI,CAAC;QACH,MAAM,IAAA,gBAAU,EAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAEA,yCAAoC;AACpC,wCAA4C;AAC5C,8CAAkD;AAClD,kDAA0B;AAE1B,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,MAAM,CAAC;KACZ,WAAW,CAAC,uBAAuB,CAAC;KACpC,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,YAAY;AACZ,OAAO;KACJ,OAAO,CAAC,KAAK,CAAC;KACd,WAAW,CAAC,mCAAmC,CAAC;KAChD,MAAM,CAAC,YAAY,EAAE,oBAAoB,CAAC;KAC1C,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,IAAI,CAAC;QACH,MAAM,IAAA,gBAAU,EAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACxF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,eAAe;AACf,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,sBAAsB,CAAC;KACnC,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,IAAA,sBAAa,GAAE,CAAC;AACxB,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/utils/error.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,SAAS,GAAG,IAAI,CAMlE"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleError = handleError;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
/**
|
|
9
|
+
* 统一错误处理
|
|
10
|
+
* @param error 错误对象
|
|
11
|
+
* @param context 上下文提示
|
|
12
|
+
*/
|
|
13
|
+
function handleError(error, context = '发生错误') {
|
|
14
|
+
if (error instanceof Error) {
|
|
15
|
+
console.error(chalk_1.default.red(`${context}: ${error.message}`));
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
console.error(chalk_1.default.red(`${context}: ${String(error)}`));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/utils/error.ts"],"names":[],"mappings":";;;;;AAOA,kCAMC;AAbD,kDAA0B;AAE1B;;;;GAIG;AACH,SAAgB,WAAW,CAAC,KAAc,EAAE,OAAO,GAAG,MAAM;IAC1D,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,GAAG,OAAO,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC3D,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,GAAG,OAAO,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare const REMOTE_TYPES: {
|
|
2
|
+
readonly GITHUB: "github";
|
|
3
|
+
readonly BITBUCKET: "bitbucket";
|
|
4
|
+
readonly GITLAB: "gitlab";
|
|
5
|
+
readonly UNKNOWN: "unknown";
|
|
6
|
+
};
|
|
7
|
+
export interface RemoteInfo {
|
|
8
|
+
name: string;
|
|
9
|
+
url: string;
|
|
10
|
+
type: typeof REMOTE_TYPES[keyof typeof REMOTE_TYPES];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 检测远程仓库类型(GitHub、Bitbucket、GitLab 等)
|
|
14
|
+
* @returns {Promise<RemoteInfo | null>} 远程仓库信息,如果没有配置远程仓库则返回 null
|
|
15
|
+
*/
|
|
16
|
+
export declare function detectRemoteType(): Promise<RemoteInfo | null>;
|
|
17
|
+
/**
|
|
18
|
+
* 根据远程仓库类型显示特定的提示信息
|
|
19
|
+
* @param {RemoteInfo['type']} remoteType - 远程仓库类型
|
|
20
|
+
*/
|
|
21
|
+
export declare function showRemoteSpecificTips(remoteType: RemoteInfo['type']): void;
|
|
22
|
+
//# sourceMappingURL=git-remote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-remote.d.ts","sourceRoot":"","sources":["../../src/utils/git-remote.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,YAAY;;;;;CAKf,CAAC;AAEX,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,OAAO,YAAY,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;CACtD;AAID;;;GAGG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA+BnE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,UAAU,CAAC,MAAM,CAAC,GAAG,IAAI,CAe3E"}
|