@zjex/git-workflow 0.0.1 → 0.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.
@@ -0,0 +1,363 @@
1
+ #!/bin/bash
2
+
3
+ set -e
4
+
5
+ # 颜色定义
6
+ RED='\033[0;31m'
7
+ GREEN='\033[0;32m'
8
+ YELLOW='\033[1;33m'
9
+ BLUE='\033[0;34m'
10
+ CYAN='\033[0;36m'
11
+ NC='\033[0m' # No Color
12
+
13
+ # 打印带颜色的消息
14
+ print_info() {
15
+ echo -e "${BLUE}ℹ ${1}${NC}"
16
+ }
17
+
18
+ print_success() {
19
+ echo -e "${GREEN}✔ ${1}${NC}"
20
+ }
21
+
22
+ print_error() {
23
+ echo -e "${RED}✖ ${1}${NC}"
24
+ }
25
+
26
+ print_warning() {
27
+ echo -e "${YELLOW}⚠ ${1}${NC}"
28
+ }
29
+
30
+ print_step() {
31
+ echo -e "${CYAN}▶ ${1}${NC}"
32
+ }
33
+
34
+ # 错误处理
35
+ trap 'handle_error $? $LINENO' ERR
36
+
37
+ handle_error() {
38
+ print_error "发布失败 (退出码: $1, 行号: $2)"
39
+
40
+ if [[ -n "$NEW_VERSION" ]]; then
41
+ print_warning "正在回滚更改..."
42
+
43
+ # 回滚 package.json
44
+ if [[ -f "package.json.backup" ]]; then
45
+ mv package.json.backup package.json
46
+ print_info "已恢复 package.json"
47
+ fi
48
+
49
+ # 删除本地 tag
50
+ if git tag -l "v${NEW_VERSION}" | grep -q "v${NEW_VERSION}"; then
51
+ git tag -d "v${NEW_VERSION}" 2>/dev/null || true
52
+ print_info "已删除本地 tag"
53
+ fi
54
+
55
+ # 回滚 commit
56
+ if git log -1 --pretty=%B | grep -q "chore(release): v${NEW_VERSION}"; then
57
+ git reset --hard HEAD~1 2>/dev/null || true
58
+ print_info "已回滚 commit"
59
+ fi
60
+ fi
61
+
62
+ exit 1
63
+ }
64
+
65
+ # 检查命令是否存在
66
+ check_command() {
67
+ if ! command -v "$1" &> /dev/null; then
68
+ print_error "未找到命令: $1"
69
+ exit 1
70
+ fi
71
+ }
72
+
73
+ # 检查必要的命令
74
+ check_command git
75
+ check_command node
76
+ check_command npm
77
+
78
+ # Dry-run 模式
79
+ DRY_RUN=false
80
+ if [[ "$1" == "--dry-run" ]]; then
81
+ DRY_RUN=true
82
+ print_warning "Dry-run 模式:仅预览,不会实际执行"
83
+ echo ""
84
+ fi
85
+
86
+ # 检查是否在 git 仓库中
87
+ if ! git rev-parse --git-dir > /dev/null 2>&1; then
88
+ print_error "当前目录不是 git 仓库"
89
+ exit 1
90
+ fi
91
+
92
+ # 检查是否有未提交的更改
93
+ if [[ -n $(git status --porcelain) ]]; then
94
+ print_error "有未提交的更改,请先提交或暂存"
95
+ git status --short
96
+ exit 1
97
+ fi
98
+
99
+ # 检查当前分支
100
+ CURRENT_BRANCH=$(git branch --show-current)
101
+ if [[ "$CURRENT_BRANCH" != "main" && "$CURRENT_BRANCH" != "master" ]]; then
102
+ print_warning "当前分支是 ${CURRENT_BRANCH},建议在 main/master 分支发布"
103
+ read -p "是否继续? (y/N) " -n 1 -r
104
+ echo
105
+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
106
+ print_info "已取消"
107
+ exit 0
108
+ fi
109
+ fi
110
+
111
+ # 检查 npm 登录状态
112
+ print_step "检查 npm 登录状态..."
113
+ if ! npm whoami &> /dev/null; then
114
+ print_error "未登录 npm,请先执行: npm login"
115
+ exit 1
116
+ fi
117
+ NPM_USER=$(npm whoami)
118
+ print_success "已登录 npm (用户: ${NPM_USER})"
119
+
120
+ # 拉取最新代码
121
+ print_step "拉取最新代码..."
122
+ if [[ "$DRY_RUN" == false ]]; then
123
+ git pull origin "$CURRENT_BRANCH"
124
+ fi
125
+ print_success "代码已更新"
126
+
127
+ # 获取当前版本
128
+ CURRENT_VERSION=$(node -p "require('./package.json').version")
129
+ print_info "当前版本: ${CURRENT_VERSION}"
130
+
131
+ # 检查远程是否已存在该版本的 tag
132
+ check_tag_exists() {
133
+ local tag="v$1"
134
+ if git ls-remote --tags origin | grep -q "refs/tags/${tag}$"; then
135
+ return 0
136
+ else
137
+ return 1
138
+ fi
139
+ }
140
+
141
+ # 计算下一个版本号
142
+ calculate_next_version() {
143
+ local current=$1
144
+ local type=$2
145
+
146
+ IFS='.' read -r major minor patch <<< "$current"
147
+
148
+ case $type in
149
+ patch)
150
+ echo "${major}.${minor}.$((patch + 1))"
151
+ ;;
152
+ minor)
153
+ echo "${major}.$((minor + 1)).0"
154
+ ;;
155
+ major)
156
+ echo "$((major + 1)).0.0"
157
+ ;;
158
+ esac
159
+ }
160
+
161
+ # 验证版本号格式
162
+ validate_version() {
163
+ if [[ ! $1 =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$ ]]; then
164
+ return 1
165
+ fi
166
+ return 0
167
+ }
168
+
169
+ # 选择版本类型
170
+ echo ""
171
+ print_step "选择新版本号"
172
+ echo ""
173
+
174
+ PATCH_VERSION=$(calculate_next_version "$CURRENT_VERSION" "patch")
175
+ MINOR_VERSION=$(calculate_next_version "$CURRENT_VERSION" "minor")
176
+ MAJOR_VERSION=$(calculate_next_version "$CURRENT_VERSION" "major")
177
+
178
+ echo -e " ${GREEN}1)${NC} patch ${CYAN}${CURRENT_VERSION}${NC} → ${GREEN}${PATCH_VERSION}${NC} (bug 修复)"
179
+ echo -e " ${GREEN}2)${NC} minor ${CYAN}${CURRENT_VERSION}${NC} → ${GREEN}${MINOR_VERSION}${NC} (新功能)"
180
+ echo -e " ${GREEN}3)${NC} major ${CYAN}${CURRENT_VERSION}${NC} → ${GREEN}${MAJOR_VERSION}${NC} (破坏性更新)"
181
+ echo -e " ${GREEN}4)${NC} custom (自定义版本号)"
182
+ echo -e " ${RED}5)${NC} cancel (取消发布)"
183
+ echo ""
184
+
185
+ while true; do
186
+ read -p "请选择 (1-5): " -n 1 -r VERSION_TYPE
187
+ echo ""
188
+
189
+ if [[ "$VERSION_TYPE" =~ ^[1-5]$ ]]; then
190
+ break
191
+ else
192
+ print_error "无效的选择,请输入 1-5"
193
+ fi
194
+ done
195
+
196
+ # 备份 package.json
197
+ cp package.json package.json.backup
198
+
199
+ case $VERSION_TYPE in
200
+ 1)
201
+ NEW_VERSION=$PATCH_VERSION
202
+ ;;
203
+ 2)
204
+ NEW_VERSION=$MINOR_VERSION
205
+ ;;
206
+ 3)
207
+ NEW_VERSION=$MAJOR_VERSION
208
+ ;;
209
+ 4)
210
+ while true; do
211
+ read -p "请输入版本号 (如 1.0.0 或 1.0.0-beta.1): " CUSTOM_VERSION
212
+
213
+ if [[ -z "$CUSTOM_VERSION" ]]; then
214
+ print_error "版本号不能为空"
215
+ continue
216
+ fi
217
+
218
+ if ! validate_version "$CUSTOM_VERSION"; then
219
+ print_error "版本号格式无效,请使用语义化版本格式 (如 1.0.0 或 1.0.0-beta.1)"
220
+ continue
221
+ fi
222
+
223
+ NEW_VERSION=$CUSTOM_VERSION
224
+ break
225
+ done
226
+ ;;
227
+ 5)
228
+ rm package.json.backup
229
+ print_info "已取消发布"
230
+ exit 0
231
+ ;;
232
+ esac
233
+
234
+ # 更新 package.json 中的版本号
235
+ if [[ "$DRY_RUN" == false ]]; then
236
+ npm version "$NEW_VERSION" --no-git-tag-version > /dev/null 2>&1 || {
237
+ print_error "更新版本号失败"
238
+ mv package.json.backup package.json
239
+ exit 1
240
+ }
241
+ fi
242
+
243
+ print_success "版本号已更新: ${CURRENT_VERSION} → ${NEW_VERSION}"
244
+
245
+ # 检查版本号是否已存在
246
+ if check_tag_exists "$NEW_VERSION"; then
247
+ print_error "版本 v${NEW_VERSION} 已存在于远程仓库"
248
+ mv package.json.backup package.json
249
+ exit 1
250
+ fi
251
+
252
+ # 运行测试(如果有)
253
+ if grep -q '"test"' package.json; then
254
+ print_step "运行测试..."
255
+ if [[ "$DRY_RUN" == false ]]; then
256
+ npm test || {
257
+ print_error "测试失败"
258
+ mv package.json.backup package.json
259
+ exit 1
260
+ }
261
+ fi
262
+ print_success "测试通过"
263
+ fi
264
+
265
+ # 构建项目
266
+ print_step "构建项目..."
267
+ if [[ "$DRY_RUN" == false ]]; then
268
+ npm run build
269
+ fi
270
+ print_success "构建完成"
271
+
272
+ # 检查构建产物
273
+ if [[ "$DRY_RUN" == false ]]; then
274
+ if [[ ! -f "dist/index.js" ]]; then
275
+ print_error "构建产物不存在: dist/index.js"
276
+ mv package.json.backup package.json
277
+ exit 1
278
+ fi
279
+ print_success "构建产物验证通过"
280
+ fi
281
+
282
+ # 生成 changelog
283
+ print_step "生成 CHANGELOG..."
284
+ if [[ "$DRY_RUN" == false ]]; then
285
+ npm run changelog
286
+ fi
287
+ print_success "CHANGELOG 已更新"
288
+
289
+ # 预览 changelog
290
+ if [[ "$DRY_RUN" == false ]]; then
291
+ echo ""
292
+ print_info "最新的 CHANGELOG 内容:"
293
+ echo "----------------------------------------"
294
+ head -n 30 CHANGELOG.md
295
+ echo "----------------------------------------"
296
+ echo ""
297
+ read -p "是否继续发布? (y/N) " -n 1 -r
298
+ echo
299
+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
300
+ print_info "已取消"
301
+ mv package.json.backup package.json
302
+ exit 0
303
+ fi
304
+ fi
305
+
306
+ # 删除备份
307
+ rm package.json.backup
308
+
309
+ if [[ "$DRY_RUN" == true ]]; then
310
+ echo ""
311
+ print_success "Dry-run 完成!以下是将要执行的操作:"
312
+ echo ""
313
+ echo " 1. 提交更改: package.json, package-lock.json, CHANGELOG.md"
314
+ echo " 2. Commit 信息: 🔖 chore(release): v${NEW_VERSION}"
315
+ echo " 3. 创建 tag: v${NEW_VERSION}"
316
+ echo " 4. 推送到 GitHub: ${CURRENT_BRANCH} + v${NEW_VERSION}"
317
+ echo " 5. 发布到 npm: @zjex/git-workflow@${NEW_VERSION}"
318
+ echo ""
319
+ print_info "执行 'npm run release' 进行实际发布"
320
+ exit 0
321
+ fi
322
+
323
+ # 最终确认
324
+ echo ""
325
+ print_warning "即将发布版本 v${NEW_VERSION} 到 npm 和 GitHub"
326
+ read -p "确认发布? (y/N) " -n 1 -r
327
+ echo
328
+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
329
+ print_info "已取消"
330
+ exit 0
331
+ fi
332
+
333
+ # 提交更改
334
+ print_step "提交更改..."
335
+ git add package.json package-lock.json CHANGELOG.md
336
+ git commit -m "🔖 chore(release): v${NEW_VERSION}"
337
+ print_success "更改已提交"
338
+
339
+ # 创建 tag
340
+ print_step "创建 tag: v${NEW_VERSION}..."
341
+ git tag -a "v${NEW_VERSION}" -m "Release v${NEW_VERSION}"
342
+ print_success "Tag 已创建"
343
+
344
+ # 推送到 GitHub
345
+ print_step "推送到 GitHub..."
346
+ git push origin "$CURRENT_BRANCH"
347
+ git push origin "v${NEW_VERSION}"
348
+ print_success "已推送到 GitHub"
349
+
350
+ # 发布到 npm
351
+ print_step "发布到 npm..."
352
+ npm publish
353
+ print_success "已发布到 npm"
354
+
355
+ echo ""
356
+ print_success "🎉 发布成功!"
357
+ echo ""
358
+ echo "版本: v${NEW_VERSION}"
359
+ echo "GitHub: https://github.com/iamzjt-front-end/git-workflow/releases/tag/v${NEW_VERSION}"
360
+ echo "npm: https://www.npmjs.com/package/@zjex/git-workflow/v/${NEW_VERSION}"
361
+ echo ""
362
+ print_info "提示: 可以在 GitHub 上创建 Release 并添加发布说明"
363
+ echo " https://github.com/iamzjt-front-end/git-workflow/releases/new?tag=v${NEW_VERSION}"
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { select, input } from "@inquirer/prompts";
4
+ import { readFileSync, writeFileSync } from "fs";
5
+ import { fileURLToPath } from "url";
6
+ import { dirname, join } from "path";
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = dirname(__filename);
10
+
11
+ // 颜色定义
12
+ const colors = {
13
+ reset: "\x1b[0m",
14
+ green: "\x1b[32m",
15
+ cyan: "\x1b[36m",
16
+ yellow: "\x1b[33m",
17
+ red: "\x1b[31m",
18
+ };
19
+
20
+ const log = {
21
+ info: (msg) => console.log(`${colors.cyan}ℹ ${msg}${colors.reset}`),
22
+ success: (msg) => console.log(`${colors.green}✔ ${msg}${colors.reset}`),
23
+ error: (msg) => console.log(`${colors.red}✖ ${msg}${colors.reset}`),
24
+ warning: (msg) => console.log(`${colors.yellow}⚠ ${msg}${colors.reset}`),
25
+ };
26
+
27
+ // 读取 package.json
28
+ const packagePath = join(__dirname, "../package.json");
29
+ const packageJson = JSON.parse(readFileSync(packagePath, "utf-8"));
30
+ const currentVersion = packageJson.version;
31
+
32
+ // 计算下一个版本号
33
+ function calculateNextVersion(current, type) {
34
+ const [major, minor, patch] = current.split(".").map(Number);
35
+
36
+ switch (type) {
37
+ case "patch":
38
+ return `${major}.${minor}.${patch + 1}`;
39
+ case "minor":
40
+ return `${major}.${minor + 1}.0`;
41
+ case "major":
42
+ return `${major + 1}.0.0`;
43
+ default:
44
+ return current;
45
+ }
46
+ }
47
+
48
+ // 验证版本号格式
49
+ function validateVersion(version) {
50
+ const semverRegex =
51
+ /^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/;
52
+ return semverRegex.test(version);
53
+ }
54
+
55
+ async function main() {
56
+ console.log("");
57
+ log.info(`当前版本: ${colors.cyan}${currentVersion}${colors.reset}`);
58
+ console.log("");
59
+
60
+ const patchVersion = calculateNextVersion(currentVersion, "patch");
61
+ const minorVersion = calculateNextVersion(currentVersion, "minor");
62
+ const majorVersion = calculateNextVersion(currentVersion, "major");
63
+
64
+ const choices = [
65
+ {
66
+ name: `patch ${currentVersion} → ${patchVersion} (bug 修复)`,
67
+ value: { type: "patch", version: patchVersion },
68
+ description: "向后兼容的 bug 修复",
69
+ },
70
+ {
71
+ name: `minor ${currentVersion} → ${minorVersion} (新功能)`,
72
+ value: { type: "minor", version: minorVersion },
73
+ description: "向后兼容的新功能",
74
+ },
75
+ {
76
+ name: `major ${currentVersion} → ${majorVersion} (破坏性更新)`,
77
+ value: { type: "major", version: majorVersion },
78
+ description: "不向后兼容的重大更改",
79
+ },
80
+ {
81
+ name: "custom (自定义版本号)",
82
+ value: { type: "custom", version: null },
83
+ description: "输入自定义版本号",
84
+ },
85
+ ];
86
+
87
+ try {
88
+ const answer = await select({
89
+ message: "选择新版本号:",
90
+ choices,
91
+ });
92
+
93
+ let newVersion = answer.version;
94
+
95
+ // 如果选择自定义版本号
96
+ if (answer.type === "custom") {
97
+ newVersion = await input({
98
+ message: "请输入版本号:",
99
+ default: currentVersion,
100
+ validate: (value) => {
101
+ if (!value) {
102
+ return "版本号不能为空";
103
+ }
104
+ if (!validateVersion(value)) {
105
+ return "版本号格式无效,请使用语义化版本格式 (如 1.0.0 或 1.0.0-beta.1)";
106
+ }
107
+ return true;
108
+ },
109
+ });
110
+ }
111
+
112
+ // 更新 package.json
113
+ console.log("");
114
+ log.info(`正在更新版本号到 ${newVersion}...`);
115
+
116
+ packageJson.version = newVersion;
117
+ writeFileSync(
118
+ packagePath,
119
+ JSON.stringify(packageJson, null, "\t") + "\n",
120
+ "utf-8"
121
+ );
122
+
123
+ log.success(`版本号已更新: ${currentVersion} → ${newVersion}`);
124
+ console.log("");
125
+
126
+ process.exit(0);
127
+ } catch (error) {
128
+ if (error.name === "ExitPromptError") {
129
+ console.log("");
130
+ log.info("已取消");
131
+ process.exit(0);
132
+ }
133
+ log.error(`发生错误: ${error.message}`);
134
+ process.exit(1);
135
+ }
136
+ }
137
+
138
+ main();
@@ -0,0 +1,133 @@
1
+ #!/bin/bash
2
+
3
+ set -e
4
+
5
+ # 颜色定义
6
+ RED='\033[0;31m'
7
+ GREEN='\033[0;32m'
8
+ YELLOW='\033[1;33m'
9
+ CYAN='\033[0;36m'
10
+ NC='\033[0m' # No Color
11
+
12
+ # 打印带颜色的消息
13
+ print_info() {
14
+ echo -e "${CYAN}ℹ ${1}${NC}"
15
+ }
16
+
17
+ print_success() {
18
+ echo -e "${GREEN}✔ ${1}${NC}"
19
+ }
20
+
21
+ print_error() {
22
+ echo -e "${RED}✖ ${1}${NC}"
23
+ }
24
+
25
+ # 获取当前版本
26
+ CURRENT_VERSION=$(node -p "require('./package.json').version")
27
+
28
+ # 计算下一个版本号
29
+ calculate_next_version() {
30
+ local current=$1
31
+ local type=$2
32
+
33
+ IFS='.' read -r major minor patch <<< "$current"
34
+
35
+ case $type in
36
+ patch)
37
+ echo "${major}.${minor}.$((patch + 1))"
38
+ ;;
39
+ minor)
40
+ echo "${major}.$((minor + 1)).0"
41
+ ;;
42
+ major)
43
+ echo "$((major + 1)).0.0"
44
+ ;;
45
+ esac
46
+ }
47
+
48
+ # 验证版本号格式
49
+ validate_version() {
50
+ if [[ ! $1 =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$ ]]; then
51
+ return 1
52
+ fi
53
+ return 0
54
+ }
55
+
56
+ # 显示当前版本
57
+ echo ""
58
+ print_info "当前版本: ${CURRENT_VERSION}"
59
+ echo ""
60
+
61
+ # 计算版本选项
62
+ PATCH_VERSION=$(calculate_next_version "$CURRENT_VERSION" "patch")
63
+ MINOR_VERSION=$(calculate_next_version "$CURRENT_VERSION" "minor")
64
+ MAJOR_VERSION=$(calculate_next_version "$CURRENT_VERSION" "major")
65
+
66
+ # 显示选项
67
+ echo "选择新版本号:"
68
+ echo ""
69
+ echo -e " ${GREEN}1)${NC} patch ${CYAN}${CURRENT_VERSION}${NC} → ${GREEN}${PATCH_VERSION}${NC} (bug 修复)"
70
+ echo -e " ${GREEN}2)${NC} minor ${CYAN}${CURRENT_VERSION}${NC} → ${GREEN}${MINOR_VERSION}${NC} (新功能)"
71
+ echo -e " ${GREEN}3)${NC} major ${CYAN}${CURRENT_VERSION}${NC} → ${GREEN}${MAJOR_VERSION}${NC} (破坏性更新)"
72
+ echo -e " ${GREEN}4)${NC} custom (自定义版本号)"
73
+ echo -e " ${RED}5)${NC} cancel (取消)"
74
+ echo ""
75
+
76
+ # 读取用户选择
77
+ while true; do
78
+ read -p "请选择 (1-5): " -n 1 -r VERSION_TYPE
79
+ echo ""
80
+
81
+ if [[ "$VERSION_TYPE" =~ ^[1-5]$ ]]; then
82
+ break
83
+ else
84
+ print_error "无效的选择,请输入 1-5"
85
+ fi
86
+ done
87
+
88
+ # 处理选择
89
+ case $VERSION_TYPE in
90
+ 1)
91
+ NEW_VERSION=$PATCH_VERSION
92
+ ;;
93
+ 2)
94
+ NEW_VERSION=$MINOR_VERSION
95
+ ;;
96
+ 3)
97
+ NEW_VERSION=$MAJOR_VERSION
98
+ ;;
99
+ 4)
100
+ while true; do
101
+ read -p "请输入版本号 (如 1.0.0 或 1.0.0-beta.1): " CUSTOM_VERSION
102
+
103
+ if [[ -z "$CUSTOM_VERSION" ]]; then
104
+ print_error "版本号不能为空"
105
+ continue
106
+ fi
107
+
108
+ if ! validate_version "$CUSTOM_VERSION"; then
109
+ print_error "版本号格式无效,请使用语义化版本格式 (如 1.0.0 或 1.0.0-beta.1)"
110
+ continue
111
+ fi
112
+
113
+ NEW_VERSION=$CUSTOM_VERSION
114
+ break
115
+ done
116
+ ;;
117
+ 5)
118
+ print_info "已取消"
119
+ exit 0
120
+ ;;
121
+ esac
122
+
123
+ # 更新版本号
124
+ echo ""
125
+ print_info "正在更新版本号到 ${NEW_VERSION}..."
126
+
127
+ npm version "$NEW_VERSION" --no-git-tag-version > /dev/null 2>&1 || {
128
+ print_error "更新版本号失败"
129
+ exit 1
130
+ }
131
+
132
+ print_success "版本号已更新: ${CURRENT_VERSION} → ${NEW_VERSION}"
133
+ echo ""