zen-gitsync 1.4.0 → 1.5.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/package.json +7 -2
- package/src/config.js +21 -1
- package/src/gitCommit.js +193 -379
- package/src/utils/index.js +425 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zen-gitsync",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.2",
|
|
4
4
|
"description": "一个 git 自动查看差异并提交的工具",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -32,7 +32,10 @@
|
|
|
32
32
|
"type": "git",
|
|
33
33
|
"url": "git+https://github.com/xz333221/zen-gitsync.git"
|
|
34
34
|
},
|
|
35
|
-
"keywords": [
|
|
35
|
+
"keywords": [
|
|
36
|
+
"gitsync",
|
|
37
|
+
"git"
|
|
38
|
+
],
|
|
36
39
|
"author": "",
|
|
37
40
|
"license": "MIT",
|
|
38
41
|
"bugs": {
|
|
@@ -43,6 +46,8 @@
|
|
|
43
46
|
"boxen": "^8.0.1",
|
|
44
47
|
"chalk": "^5.4.1",
|
|
45
48
|
"cli-table3": "^0.6.5",
|
|
49
|
+
"date-fns": "^4.1.0",
|
|
50
|
+
"log-update": "^6.1.0",
|
|
46
51
|
"ora": "^8.1.1",
|
|
47
52
|
"string-width": "^7.2.0"
|
|
48
53
|
}
|
package/src/config.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { promises as fs } from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import os from 'os';
|
|
4
|
+
import chalk from 'chalk';
|
|
4
5
|
|
|
5
6
|
const configPath = path.join(os.homedir(), '.git-commit-tool.json');
|
|
6
7
|
|
|
@@ -23,8 +24,27 @@ async function loadConfig() {
|
|
|
23
24
|
async function saveConfig(config) {
|
|
24
25
|
await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
25
26
|
}
|
|
27
|
+
// 添加配置管理函数
|
|
28
|
+
async function handleConfigCommands() {
|
|
29
|
+
if (process.argv.includes('get-config')) {
|
|
30
|
+
const currentConfig = await loadConfig();
|
|
31
|
+
console.log('Current configuration:');
|
|
32
|
+
console.log(currentConfig);
|
|
33
|
+
process.exit();
|
|
34
|
+
}
|
|
26
35
|
|
|
36
|
+
const setMsgArg = process.argv.find(arg => arg.startsWith('--set-default-message='));
|
|
37
|
+
if (setMsgArg) {
|
|
38
|
+
const newMessage = setMsgArg.split('=')[1];
|
|
39
|
+
const currentConfig = await loadConfig();
|
|
40
|
+
currentConfig.defaultCommitMessage = newMessage;
|
|
41
|
+
await saveConfig(currentConfig);
|
|
42
|
+
console.log(chalk.green(`✓ 默认提交信息已设置为: "${newMessage}"`));
|
|
43
|
+
process.exit();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
27
46
|
export default {
|
|
28
47
|
loadConfig,
|
|
29
|
-
saveConfig
|
|
48
|
+
saveConfig,
|
|
49
|
+
handleConfigCommands
|
|
30
50
|
};
|
package/src/gitCommit.js
CHANGED
|
@@ -1,427 +1,241 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import {
|
|
3
|
+
coloredLog, errorLog, execGitCommand, execSyncGitCommand, showHelp,
|
|
4
|
+
getCwd, judgePlatform, judgeLog, judgeHelp, exec_exit, judgeUnmerged, formatDuration,
|
|
5
|
+
exec_push, execPull, judgeRemote, execDiff, execAddAndCommit, delay
|
|
6
|
+
} from './utils/index.js';
|
|
6
7
|
import readline from 'readline'
|
|
7
8
|
import ora from 'ora';
|
|
8
9
|
import chalk from 'chalk';
|
|
9
10
|
import boxen from 'boxen';
|
|
10
11
|
import config from './config.js';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
let timer = null
|
|
15
|
-
const showHelp = () => {
|
|
16
|
-
const helpMessage = `
|
|
17
|
-
Usage: g [options]
|
|
12
|
+
import dateFormat from 'date-fns/format';
|
|
13
|
+
import logUpdate from 'log-update';
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
-h, --help Show this help message
|
|
21
|
-
--set-default-message=<msg> Set default commit message
|
|
22
|
-
get-config Show current configuration
|
|
23
|
-
-y Auto commit with default message
|
|
24
|
-
-m <message> Commit message (use quotes if message contains spaces)
|
|
25
|
-
-m=<message> Commit message (use this form without spaces around '=')
|
|
26
|
-
--path=<path> Set custom working directory
|
|
27
|
-
--cwd=<path> Set custom working directory
|
|
28
|
-
--interval=<seconds> Set interval time for automatic commits (in seconds)
|
|
29
|
-
log Show git commit logs
|
|
30
|
-
--n=<number> Number of commits to show with --log
|
|
31
|
-
--no-diff Skip displaying git diff
|
|
15
|
+
let countdownInterval = null;
|
|
32
16
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
g -m=Fix-bug Commit with a custom message (no spaces around '=')
|
|
36
|
-
g -y Auto commit with the default message
|
|
37
|
-
g -y --interval=600 Commit every 10 minutes (600 seconds)
|
|
38
|
-
g --path=/path/to/repo Specify a custom working directory
|
|
39
|
-
g log Show recent commit logs
|
|
40
|
-
g log --n=5 Show the last 5 commits with --log
|
|
17
|
+
function startCountdown(interval) {
|
|
18
|
+
let remaining = interval;
|
|
41
19
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
20
|
+
// 清除旧的倒计时
|
|
21
|
+
if (countdownInterval) {
|
|
22
|
+
clearInterval(countdownInterval);
|
|
45
23
|
}
|
|
46
24
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
25
|
+
const render = () => {
|
|
26
|
+
const nextTime = Date.now() + remaining;
|
|
27
|
+
const formattedTime = dateFormat(nextTime, 'yyyy-MM-dd HH:mm:ss');
|
|
28
|
+
const duration = formatDuration(remaining);
|
|
50
29
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const currentConfig = await loadConfig();
|
|
58
|
-
console.log('Current configuration:');
|
|
59
|
-
console.log(currentConfig);
|
|
60
|
-
process.exit();
|
|
61
|
-
}
|
|
30
|
+
const message = [
|
|
31
|
+
chalk.green.bold('🕒 倒计时'),
|
|
32
|
+
chalk.cyan(`下次提交: ${formattedTime}`),
|
|
33
|
+
chalk.yellow(`剩余时间: ${duration}`),
|
|
34
|
+
chalk.dim('按 Ctrl+C 终止进程')
|
|
35
|
+
].join('\n');
|
|
62
36
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
await saveConfig(currentConfig);
|
|
69
|
-
console.log(chalk.green(`✓ 默认提交信息已设置为: "${newMessage}"`));
|
|
70
|
-
process.exit();
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
const judgePlatform = () => {
|
|
74
|
-
// 判断是否是 Windows 系统
|
|
75
|
-
if (os.platform() === 'win32') {
|
|
76
|
-
try {
|
|
77
|
-
// 设置终端字符编码为 UTF-8
|
|
78
|
-
execSync('chcp 65001');
|
|
79
|
-
} catch (e) {
|
|
80
|
-
console.error('设置字符编码失败:', e.message);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
const getCwd = () => {
|
|
85
|
-
const cwdArg = process.argv.find(arg => arg.startsWith('--path')) || process.argv.find(arg => arg.startsWith('--cwd'));
|
|
86
|
-
if (cwdArg) {
|
|
87
|
-
// console.log(`cwdArg ==> `, cwdArg)
|
|
88
|
-
const [, value] = cwdArg.split('=')
|
|
89
|
-
// console.log(`value ==> `, value)
|
|
90
|
-
return value || process.cwd()
|
|
91
|
-
}
|
|
92
|
-
return process.cwd()
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
class GitCommit {
|
|
96
|
-
constructor(options) {
|
|
97
|
-
this.statusOutput = null
|
|
98
|
-
this.exit = options.exit
|
|
99
|
-
// 从配置加载默认提交信息
|
|
100
|
-
loadConfig().then(config => {
|
|
101
|
-
this.commitMessage = config.defaultCommitMessage;
|
|
102
|
-
this.init();
|
|
37
|
+
const box = boxen(message, {
|
|
38
|
+
padding: 1,
|
|
39
|
+
margin: 1,
|
|
40
|
+
borderColor: 'cyan',
|
|
41
|
+
borderStyle: 'round'
|
|
103
42
|
});
|
|
104
|
-
}
|
|
105
43
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
judgeLog() {
|
|
113
|
-
const logArg = process.argv.find(arg => arg === 'log');
|
|
114
|
-
if (logArg) {
|
|
115
|
-
this.printGitLog(); // 如果有 log 参数,打印 Git 提交记录
|
|
116
|
-
return true;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
44
|
+
setTimeout(() => {
|
|
45
|
+
logUpdate(box);
|
|
46
|
+
}, 200);
|
|
47
|
+
// logUpdate(box);
|
|
48
|
+
};
|
|
119
49
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
showHelp();
|
|
123
|
-
return true;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
50
|
+
// 立即渲染一次
|
|
51
|
+
render();
|
|
126
52
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
this.execSyncGitCommand('git diff --color=always', {
|
|
131
|
-
head: `git diff`
|
|
132
|
-
})
|
|
133
|
-
}
|
|
134
|
-
}
|
|
53
|
+
// 每秒更新
|
|
54
|
+
countdownInterval = setInterval(() => {
|
|
55
|
+
remaining -= 1000;
|
|
135
56
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (commitMessageArg.includes('=')) {
|
|
141
|
-
// 处理 -m=<message> 的情况
|
|
142
|
-
this.commitMessage = commitMessageArg.split('=')[1]?.replace(/^['"]|['"]$/g, '') || defaultCommitMessage;
|
|
143
|
-
} else {
|
|
144
|
-
// 处理 -m <message> 的情况
|
|
145
|
-
const index = process.argv.indexOf(commitMessageArg);
|
|
146
|
-
if (index !== -1 && process.argv[index + 1]) {
|
|
147
|
-
this.commitMessage = process.argv[index + 1]?.replace(/^['"]|['"]$/g, '') || defaultCommitMessage;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
57
|
+
if (remaining <= 0) {
|
|
58
|
+
clearInterval(countdownInterval);
|
|
59
|
+
logUpdate.clear();
|
|
60
|
+
return;
|
|
150
61
|
}
|
|
151
62
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (!autoCommit && !commitMessageArg) {
|
|
156
|
-
// 如果没有 -y 参数,则等待用户输入提交信息
|
|
157
|
-
const rl = readline.createInterface({
|
|
158
|
-
input: process.stdin,
|
|
159
|
-
output: process.stdout
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
function rlPromisify(fn) {
|
|
163
|
-
return async (...args) => {
|
|
164
|
-
return new Promise((resolve, reject) => fn(...args, resolve, reject))
|
|
165
|
-
}
|
|
166
|
-
}
|
|
63
|
+
render();
|
|
64
|
+
}, 1000);
|
|
65
|
+
}
|
|
167
66
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
67
|
+
const {loadConfig, saveConfig, handleConfigCommands} = config;
|
|
68
|
+
const {defaultCommitMessage} = config
|
|
171
69
|
|
|
172
|
-
|
|
70
|
+
let timer = null
|
|
173
71
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
72
|
+
async function createGitCommit(options) {
|
|
73
|
+
// console.log(`自动提交流程开始=====================>`)
|
|
74
|
+
try {
|
|
75
|
+
let statusOutput = null
|
|
76
|
+
let exit = options ? !!options.exit : true
|
|
77
|
+
const config = await loadConfig()
|
|
78
|
+
let commitMessage = config.defaultCommitMessage
|
|
79
|
+
let {stdout} = await execGitCommand('git status')
|
|
80
|
+
statusOutput = stdout
|
|
81
|
+
judgeUnmerged(statusOutput)
|
|
82
|
+
// 先检查本地是否有未提交的更改
|
|
83
|
+
const hasLocalChanges = !statusOutput.includes('nothing to commit, working tree clean');
|
|
84
|
+
if (hasLocalChanges) {
|
|
85
|
+
// 检查是否有 --no-diff 参数
|
|
86
|
+
await execDiff()
|
|
87
|
+
await execAddAndCommit({statusOutput, commitMessage, exit})
|
|
88
|
+
statusOutput.includes('use "git pull') && await execPull()
|
|
179
89
|
|
|
180
|
-
async judgeRemote() {
|
|
181
|
-
try {
|
|
182
|
-
const spinner = ora('正在检查远程更新...').start();
|
|
183
90
|
// 检查是否有远程更新
|
|
184
|
-
//
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
log: false
|
|
193
|
-
});
|
|
194
|
-
const behindCount = res.stdout.trim()
|
|
195
|
-
// 如果本地落后于远程
|
|
196
|
-
if (parseInt(behindCount) > 0) {
|
|
197
|
-
try {
|
|
198
|
-
spinner.stop();
|
|
199
|
-
// const spinner_pull = ora('发现远程更新,正在拉取...').start();
|
|
200
|
-
await this.execPull()
|
|
201
|
-
|
|
202
|
-
// // 尝试使用 --ff-only 拉取更新
|
|
203
|
-
// const res = await this.execGitCommand('git pull --ff-only', {
|
|
204
|
-
// spinner: spinner_pull,
|
|
205
|
-
// head: 'Pulling updates'
|
|
206
|
-
// });
|
|
207
|
-
console.log(chalk.green('✓ 已成功同步远程更新'));
|
|
208
|
-
} catch (pullError) {
|
|
209
|
-
// // 如果 --ff-only 拉取失败,尝试普通的 git pull
|
|
210
|
-
// console.log(chalk.yellow('⚠️ 无法快进合并,尝试普通合并...'));
|
|
211
|
-
// await this.execPull()
|
|
212
|
-
throw new Error(pullError)
|
|
213
|
-
}
|
|
91
|
+
await judgeRemote() // 等待 judgeRemote 完成
|
|
92
|
+
|
|
93
|
+
await exec_push({exit, commitMessage})
|
|
94
|
+
} else {
|
|
95
|
+
if (statusOutput.includes('use "git push')) {
|
|
96
|
+
await exec_push({exit, commitMessage})
|
|
97
|
+
} else if (statusOutput.includes('use "git pull')) {
|
|
98
|
+
await execPull()
|
|
214
99
|
} else {
|
|
215
|
-
|
|
216
|
-
|
|
100
|
+
await judgeRemote() // 等待 judgeRemote 完成
|
|
101
|
+
exec_exit(exit);
|
|
217
102
|
}
|
|
218
|
-
} catch (e) {
|
|
219
|
-
// console.log(`e ==> `, e)
|
|
220
|
-
spinner.stop();
|
|
221
|
-
throw new Error(e)
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
async execPull() {
|
|
226
|
-
try {
|
|
227
|
-
// 检查是否需要拉取更新
|
|
228
|
-
const spinner = ora('正在拉取代码...').start();
|
|
229
|
-
await this.execGitCommand('git pull', {
|
|
230
|
-
spinner
|
|
231
|
-
})
|
|
232
|
-
} catch (e) {
|
|
233
|
-
console.log(chalk.yellow('⚠️ 拉取远程更新合并失败,可能存在冲突,请手动处理'));
|
|
234
|
-
throw Error(e)
|
|
235
103
|
}
|
|
104
|
+
} catch (e) {
|
|
105
|
+
console.error(chalk.red.bold('提交流程错误:'));
|
|
106
|
+
console.error(chalk.dim(e.stack)); // 打印完整错误堆栈
|
|
107
|
+
throw e; // 继续向上抛出错误
|
|
236
108
|
}
|
|
109
|
+
}
|
|
110
|
+
async function main() {
|
|
111
|
+
judgePlatform()
|
|
237
112
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
judgePlatform()
|
|
113
|
+
// 检查是否有 log 参数
|
|
114
|
+
judgeLog()
|
|
241
115
|
|
|
242
|
-
|
|
243
|
-
|
|
116
|
+
// 检查帮助参数
|
|
117
|
+
judgeHelp()
|
|
244
118
|
|
|
245
|
-
|
|
246
|
-
if (this.judgeHelp()) return
|
|
119
|
+
await handleConfigCommands();
|
|
247
120
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
if (hasUnmerged) {
|
|
251
|
-
errorLog('错误', '存在未合并的文件,请先解决冲突')
|
|
252
|
-
process.exit(1);
|
|
253
|
-
}
|
|
254
|
-
// 先检查本地是否有未提交的更改
|
|
255
|
-
const hasLocalChanges = !this.statusOutput.includes('nothing to commit, working tree clean');
|
|
256
|
-
if (hasLocalChanges) {
|
|
257
|
-
// 检查是否有 --no-diff 参数
|
|
258
|
-
this.execDiff()
|
|
121
|
+
judgeInterval();
|
|
122
|
+
}
|
|
259
123
|
|
|
260
|
-
|
|
124
|
+
const showStartInfo = (interval) => {
|
|
125
|
+
const cwd = getCwd();
|
|
126
|
+
const intervalSeconds = interval / 1000;
|
|
127
|
+
const startTime = new Date().toLocaleString();
|
|
261
128
|
|
|
262
|
-
|
|
129
|
+
const head = `⏰ 定时提交任务已启动`;
|
|
263
130
|
|
|
264
|
-
|
|
265
|
-
|
|
131
|
+
const message = chalk.green.bold([
|
|
132
|
+
`开始时间: ${chalk.yellow(startTime)}`,
|
|
133
|
+
`工作目录: ${chalk.cyan(cwd)}`,
|
|
134
|
+
`提交间隔: ${chalk.magenta(formatDuration(interval))}`,
|
|
135
|
+
].join("\n"));
|
|
266
136
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
errorLog('错误', '当前目录不是git仓库')
|
|
286
|
-
} else if (e.message.includes('Permission denied')) {
|
|
287
|
-
errorLog('错误', '权限不足,请检查git配置')
|
|
288
|
-
}
|
|
289
|
-
process.exit(1);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
async printGitLog() {
|
|
294
|
-
let n = 20;
|
|
295
|
-
let logArg = process.argv.find(arg => arg.startsWith('--n='));
|
|
296
|
-
if (logArg) {
|
|
297
|
-
n = parseInt(logArg.split('=')[1], 10);
|
|
298
|
-
}
|
|
299
|
-
const logCommand = `git log -n ${n} --pretty=format:"%C(green)%h%C(reset) | %C(cyan)%an%C(reset) | %C(yellow)%ad%C(reset) | %C(blue)%D%C(reset) | %C(magenta)%s%C(reset)" --date=format:"%Y-%m-%d %H:%M" --graph --decorate --color`
|
|
300
|
-
try {
|
|
301
|
-
const logOutput = this.execSyncGitCommand(logCommand, {
|
|
302
|
-
head: `git log`
|
|
303
|
-
});
|
|
304
|
-
// // 格式化输出 Git 提交记录
|
|
305
|
-
// const box = boxen(chalk.green.bold(logOutput), {
|
|
306
|
-
// borderStyle: 'round',
|
|
307
|
-
// borderColor: 'cyan',
|
|
308
|
-
// backgroundColor: 'black',
|
|
309
|
-
// });
|
|
310
|
-
// console.log(box); // 打印优雅的 Git 提交记录
|
|
311
|
-
} catch (error) {
|
|
312
|
-
console.error('无法获取 Git 提交记录:', error.message);
|
|
313
|
-
}
|
|
314
|
-
this.exec_exit(); // 打印完成后退出
|
|
137
|
+
coloredLog(head, message)
|
|
138
|
+
// console.log('\n'.repeat(6));
|
|
139
|
+
}
|
|
140
|
+
const commitAndSchedule = async (interval) => {
|
|
141
|
+
try {
|
|
142
|
+
await createGitCommit({exit: false});
|
|
143
|
+
// await delay(2000)
|
|
144
|
+
startCountdown(interval); // 启动倒计时
|
|
145
|
+
|
|
146
|
+
// 设置定时提交
|
|
147
|
+
timer = setTimeout(async () => {
|
|
148
|
+
await commitAndSchedule(interval);
|
|
149
|
+
}, interval + 100);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error('提交出错:', error.message);
|
|
152
|
+
clearTimeout(timer);
|
|
153
|
+
clearInterval(countdownInterval);
|
|
154
|
+
process.exit(1);
|
|
315
155
|
}
|
|
156
|
+
};
|
|
157
|
+
const judgeInterval = async () => {
|
|
158
|
+
const intervalArg = process.argv.find(arg => arg.startsWith('--interval'));
|
|
159
|
+
if (intervalArg) {
|
|
160
|
+
let interval = parseInt(intervalArg.split('=')[1] || '3600', 10) * 1000;
|
|
316
161
|
|
|
317
|
-
|
|
318
|
-
// 执行 git push
|
|
319
|
-
// this.execSyncGitCommand(`git push`);
|
|
320
|
-
const spinner = ora('正在推送代码...').start();
|
|
321
|
-
this.execGitCommand('git push', {
|
|
322
|
-
spinner
|
|
323
|
-
}, (error, stdout, stderr) => {
|
|
324
|
-
|
|
325
|
-
// 使用 boxen 绘制带边框的消息
|
|
326
|
-
let msg = ` SUCCESS: 提交完成
|
|
327
|
-
message: ${this.commitMessage || defaultCommitMessage}
|
|
328
|
-
time: ${new Date().toLocaleString()} `
|
|
329
|
-
const message = chalk.green.bold(msg);
|
|
330
|
-
const box = boxen(message, {
|
|
331
|
-
// borderStyle: 'round', // 方框的样式
|
|
332
|
-
// borderColor: 'whiteBright', // 边框颜色
|
|
333
|
-
// backgroundColor: 'black', // 背景颜色
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
console.log(box); // 打印带有边框的消息
|
|
337
|
-
// this.execSyncGitCommand(`git log -n 1 --pretty=format:"%B%n%h %d%n%ad" --date=iso`)
|
|
338
|
-
this.exec_exit();
|
|
339
|
-
})
|
|
340
|
-
}
|
|
162
|
+
showStartInfo(interval);
|
|
341
163
|
|
|
342
|
-
execSyncGitCommand(command, options = {}) {
|
|
343
|
-
let {encoding = 'utf-8', maxBuffer = 30 * 1024 * 1024, head = command, log = true} = options
|
|
344
164
|
try {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
options.spinner.stop();
|
|
349
|
-
}
|
|
350
|
-
let result = output.trim()
|
|
351
|
-
log && coloredLog(head, result)
|
|
352
|
-
return result
|
|
353
|
-
} catch (e) {
|
|
354
|
-
// console.log(`执行命令出错 ==> `, command, e)
|
|
355
|
-
log && coloredLog(command, e, 'error')
|
|
356
|
-
throw new Error(e)
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
execGitCommand(command, options = {}, callback) {
|
|
361
|
-
return new Promise((resolve, reject) => {
|
|
362
|
-
let {encoding = 'utf-8', maxBuffer = 30 * 1024 * 1024, head = command, log = true} = options
|
|
363
|
-
let cwd = getCwd()
|
|
364
|
-
exec(command, {env: { ...process.env, LANG: 'C.UTF-8' },encoding, maxBuffer, cwd}, (error, stdout, stderr) => {
|
|
365
|
-
if (options.spinner) {
|
|
366
|
-
options.spinner.stop();
|
|
367
|
-
}
|
|
368
|
-
if (error) {
|
|
369
|
-
log && coloredLog(head, error, 'error')
|
|
370
|
-
reject(error)
|
|
371
|
-
return
|
|
372
|
-
}
|
|
373
|
-
if (stdout) {
|
|
374
|
-
log && coloredLog(head, stdout)
|
|
375
|
-
}
|
|
376
|
-
if (stderr) {
|
|
377
|
-
log && coloredLog(head, stderr)
|
|
378
|
-
}
|
|
379
|
-
resolve({
|
|
380
|
-
stdout,
|
|
381
|
-
stderr
|
|
382
|
-
})
|
|
383
|
-
callback && callback(error, stdout, stderr)
|
|
384
|
-
})
|
|
385
|
-
})
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
// 在 judgeInterval 函数前添加配置命令处理
|
|
389
|
-
async function main() {
|
|
390
|
-
await handleConfigCommands();
|
|
391
|
-
judgeInterval();
|
|
392
|
-
}
|
|
393
|
-
const judgeInterval = () => {
|
|
394
|
-
// 判断是否有 --interval 参数
|
|
395
|
-
const intervalArg = process.argv.find(arg => arg.startsWith('--interval'));
|
|
396
|
-
if (intervalArg) {
|
|
397
|
-
// console.log(`intervalArg ==> `, intervalArg)
|
|
398
|
-
let interval = intervalArg.split('=')[1] || 60 * 60; // 默认间隔为1小时
|
|
399
|
-
// console.log(`interval ==> `, interval)
|
|
400
|
-
interval = parseInt(interval, 10) * 1000; // 将间隔时间转换为毫秒
|
|
401
|
-
// console.log(`interval ==> `, interval)
|
|
402
|
-
if (isNaN(interval)) {
|
|
403
|
-
console.log('无效的间隔时间,请使用 --interval=秒数');
|
|
165
|
+
await commitAndSchedule(interval);
|
|
166
|
+
} catch (error) {
|
|
167
|
+
console.error(chalk.red.bold('定时提交致命错误:'), error.message);
|
|
404
168
|
process.exit(1);
|
|
405
169
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
// console.log(`定时执行`)
|
|
416
|
-
new GitCommit({
|
|
417
|
-
exit: false
|
|
418
|
-
})
|
|
419
|
-
}, interval)
|
|
170
|
+
|
|
171
|
+
// 处理退出清理
|
|
172
|
+
process.on('SIGINT', () => {
|
|
173
|
+
logUpdate.clear();
|
|
174
|
+
clearTimeout(timer);
|
|
175
|
+
clearInterval(countdownInterval);
|
|
176
|
+
console.log(chalk.yellow('\n🛑 定时任务已终止'));
|
|
177
|
+
process.exit();
|
|
178
|
+
});
|
|
420
179
|
} else {
|
|
421
|
-
|
|
422
|
-
exit: true
|
|
423
|
-
})
|
|
180
|
+
createGitCommit({exit: false});
|
|
424
181
|
}
|
|
425
182
|
};
|
|
183
|
+
// const judgeInterval = async () => {
|
|
184
|
+
// // 判断是否有 --interval 参数
|
|
185
|
+
// const intervalArg = process.argv.find(arg => arg.startsWith('--interval'));
|
|
186
|
+
// if (intervalArg) {
|
|
187
|
+
// // // console.log(`intervalArg ==> `, intervalArg)
|
|
188
|
+
// // let interval = intervalArg.split('=')[1] || 60 * 60; // 默认间隔为1小时
|
|
189
|
+
// // // console.log(`interval ==> `, interval)
|
|
190
|
+
// // interval = parseInt(interval, 10) * 1000; // 将间隔时间转换为毫秒
|
|
191
|
+
// // // console.log(`interval ==> `, interval)
|
|
192
|
+
// // if (isNaN(interval)) {
|
|
193
|
+
// // console.log('无效的间隔时间,请使用 --interval=秒数');
|
|
194
|
+
// // process.exit(1);
|
|
195
|
+
// // }
|
|
196
|
+
// // if (timer) {
|
|
197
|
+
// // console.log(`清空定时器`)
|
|
198
|
+
// // clearInterval(timer);
|
|
199
|
+
// // timer = null;
|
|
200
|
+
// // }
|
|
201
|
+
// // showStartInfo(interval);
|
|
202
|
+
// // await createGitCommit({exit: false})
|
|
203
|
+
// //
|
|
204
|
+
// // timer = setInterval(() => {
|
|
205
|
+
// // // console.log(`定时执行`)
|
|
206
|
+
// // createGitCommit({exit: false})
|
|
207
|
+
// // }, interval)
|
|
208
|
+
//
|
|
209
|
+
// let interval = parseInt(intervalArg.split('=')[1] || '3600', 10) * 1000;
|
|
210
|
+
// // const showUpdates = () => {
|
|
211
|
+
// // showNextCommitTime(interval);
|
|
212
|
+
// // // 每小时更新一次时间显示
|
|
213
|
+
// // timer = setTimeout(() => {
|
|
214
|
+
// // showUpdates();
|
|
215
|
+
// // }, 20000); // 每小时更新一次
|
|
216
|
+
// // };
|
|
217
|
+
//
|
|
218
|
+
// const commitAndSchedule = async (interval) => {
|
|
219
|
+
// try {
|
|
220
|
+
// await createGitCommit({exit: false});
|
|
221
|
+
// startCountdown(interval); // 启动倒计时
|
|
222
|
+
//
|
|
223
|
+
// // 设置定时提交
|
|
224
|
+
// timer = setTimeout(async () => {
|
|
225
|
+
// await commitAndSchedule(interval);
|
|
226
|
+
// }, interval);
|
|
227
|
+
// } catch (error) {
|
|
228
|
+
// console.error('提交出错:', error.message);
|
|
229
|
+
// }
|
|
230
|
+
// };
|
|
231
|
+
//
|
|
232
|
+
// await commitAndSchedule();
|
|
233
|
+
//
|
|
234
|
+
// // 设置定时提交
|
|
235
|
+
// timer = setInterval(commitAndSchedule, interval);
|
|
236
|
+
// } else {
|
|
237
|
+
// createGitCommit({exit: false})
|
|
238
|
+
// }
|
|
239
|
+
// };
|
|
426
240
|
|
|
427
241
|
main()
|
package/src/utils/index.js
CHANGED
|
@@ -18,6 +18,12 @@ import stringWidth from 'string-width';
|
|
|
18
18
|
import Table from 'cli-table3';
|
|
19
19
|
import chalk from 'chalk';
|
|
20
20
|
import boxen from "boxen";
|
|
21
|
+
import {exec, execSync} from 'child_process'
|
|
22
|
+
import os from 'os'
|
|
23
|
+
import ora from "ora";
|
|
24
|
+
import readline from 'readline'
|
|
25
|
+
import path from 'path'
|
|
26
|
+
|
|
21
27
|
|
|
22
28
|
const printTableWithHeaderUnderline = (head, content, style) => {
|
|
23
29
|
// 获取终端的列数(宽度)
|
|
@@ -43,6 +49,14 @@ const printTableWithHeaderUnderline = (head, content, style) => {
|
|
|
43
49
|
style: style,
|
|
44
50
|
wordWrap: true, // 启用自动换行
|
|
45
51
|
// chars: {
|
|
52
|
+
// 'top': '─',
|
|
53
|
+
// 'top-mid': '┬',
|
|
54
|
+
// 'bottom': '─',
|
|
55
|
+
// 'mid': '─',
|
|
56
|
+
// 'left': '│',
|
|
57
|
+
// 'right': '│'
|
|
58
|
+
// },
|
|
59
|
+
// chars: {
|
|
46
60
|
// 'top': '═', // 顶部边框使用长横线
|
|
47
61
|
// 'top-mid': '╤', // 顶部连接符
|
|
48
62
|
// 'top-left': '╔', // 左上角
|
|
@@ -94,6 +108,7 @@ function getRandomColor() {
|
|
|
94
108
|
function resetColor() {
|
|
95
109
|
return '\x1b[0m';
|
|
96
110
|
}
|
|
111
|
+
|
|
97
112
|
const calcColor = (commandLine, str) => {
|
|
98
113
|
let color = 'reset'
|
|
99
114
|
switch (commandLine) {
|
|
@@ -159,6 +174,9 @@ const coloredLog = (...args) => {
|
|
|
159
174
|
const commandLine = args[0];
|
|
160
175
|
const content = args[1];
|
|
161
176
|
const type = args[2] || 'common';
|
|
177
|
+
// console.log(`commandLine ==> `, commandLine)
|
|
178
|
+
// console.log(`content ==> `, content)
|
|
179
|
+
// console.log(`type ==> `, type)
|
|
162
180
|
tableLog(commandLine, content, type);
|
|
163
181
|
}
|
|
164
182
|
const errorLog = (commandLine, content) => {
|
|
@@ -169,4 +187,410 @@ const errorLog = (commandLine, content) => {
|
|
|
169
187
|
const box = boxen(message);
|
|
170
188
|
console.log(box); // 打印带有边框的消息
|
|
171
189
|
}
|
|
172
|
-
|
|
190
|
+
|
|
191
|
+
function execSyncGitCommand(command, options = {}) {
|
|
192
|
+
let {encoding = 'utf-8', maxBuffer = 30 * 1024 * 1024, head = command, log = true} = options
|
|
193
|
+
try {
|
|
194
|
+
let cwd = getCwd()
|
|
195
|
+
const output = execSync(command, {
|
|
196
|
+
env: {
|
|
197
|
+
...process.env,
|
|
198
|
+
// LANG: 'en_US.UTF-8', // Linux/macOS
|
|
199
|
+
// LC_ALL: 'en_US.UTF-8', // Linux/macOS
|
|
200
|
+
GIT_CONFIG_PARAMETERS: "'core.quotepath=false'" // 关闭路径转义
|
|
201
|
+
}, encoding, maxBuffer, cwd
|
|
202
|
+
})
|
|
203
|
+
if (options.spinner) {
|
|
204
|
+
options.spinner.stop();
|
|
205
|
+
}
|
|
206
|
+
let result = output.trim()
|
|
207
|
+
log && coloredLog(head, result)
|
|
208
|
+
return result
|
|
209
|
+
} catch (e) {
|
|
210
|
+
// console.log(`执行命令出错 ==> `, command, e)
|
|
211
|
+
log && coloredLog(command, e, 'error')
|
|
212
|
+
throw new Error(e)
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function execGitCommand(command, options = {}) {
|
|
217
|
+
return new Promise((resolve, reject) => {
|
|
218
|
+
let {encoding = 'utf-8', maxBuffer = 30 * 1024 * 1024, head = command, log = true} = options
|
|
219
|
+
let cwd = getCwd()
|
|
220
|
+
|
|
221
|
+
// setTimeout(() => {
|
|
222
|
+
exec(command, {
|
|
223
|
+
env: {
|
|
224
|
+
...process.env,
|
|
225
|
+
// LANG: 'en_US.UTF-8', // Linux/macOS
|
|
226
|
+
// LC_ALL: 'en_US.UTF-8', // Linux/macOS
|
|
227
|
+
GIT_CONFIG_PARAMETERS: "'core.quotepath=false'" // 关闭路径转义
|
|
228
|
+
},
|
|
229
|
+
encoding,
|
|
230
|
+
maxBuffer,
|
|
231
|
+
cwd
|
|
232
|
+
}, (error, stdout, stderr) => {
|
|
233
|
+
if (options.spinner) {
|
|
234
|
+
options.spinner.stop();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (stdout) {
|
|
238
|
+
log && coloredLog(head, stdout)
|
|
239
|
+
}
|
|
240
|
+
if (stderr) {
|
|
241
|
+
log && coloredLog(head, stderr)
|
|
242
|
+
}
|
|
243
|
+
if (error) {
|
|
244
|
+
log && coloredLog(head, error, 'error')
|
|
245
|
+
reject(error)
|
|
246
|
+
return
|
|
247
|
+
}
|
|
248
|
+
resolve({
|
|
249
|
+
stdout,
|
|
250
|
+
stderr
|
|
251
|
+
})
|
|
252
|
+
})
|
|
253
|
+
// }, 1000)
|
|
254
|
+
|
|
255
|
+
})
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const getCwd = () => {
|
|
259
|
+
const cwdArg = process.argv.find(arg => arg.startsWith('--path')) || process.argv.find(arg => arg.startsWith('--cwd'));
|
|
260
|
+
if (cwdArg) {
|
|
261
|
+
// console.log(`cwdArg ==> `, cwdArg)
|
|
262
|
+
const [, value] = cwdArg.split('=')
|
|
263
|
+
// console.log(`value ==> `, value)
|
|
264
|
+
return value || process.cwd()
|
|
265
|
+
}
|
|
266
|
+
return process.cwd()
|
|
267
|
+
}
|
|
268
|
+
const judgePlatform = () => {
|
|
269
|
+
// 判断是否是 Windows 系统
|
|
270
|
+
if (os.platform() === 'win32') {
|
|
271
|
+
try {
|
|
272
|
+
// 设置终端字符编码为 UTF-8
|
|
273
|
+
execSync('chcp 65001');
|
|
274
|
+
} catch (e) {
|
|
275
|
+
console.error('设置字符编码失败:', e.message);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
const showHelp = () => {
|
|
280
|
+
const helpMessage = `
|
|
281
|
+
Usage: g [options]
|
|
282
|
+
|
|
283
|
+
Options:
|
|
284
|
+
-h, --help Show this help message
|
|
285
|
+
--set-default-message=<msg> Set default commit message
|
|
286
|
+
get-config Show current configuration
|
|
287
|
+
-y Auto commit with default message
|
|
288
|
+
-m <message> Commit message (use quotes if message contains spaces)
|
|
289
|
+
-m=<message> Commit message (use this form without spaces around '=')
|
|
290
|
+
--path=<path> Set custom working directory
|
|
291
|
+
--cwd=<path> Set custom working directory
|
|
292
|
+
--interval=<seconds> Set interval time for automatic commits (in seconds)
|
|
293
|
+
log Show git commit logs
|
|
294
|
+
--n=<number> Number of commits to show with --log
|
|
295
|
+
--no-diff Skip displaying git diff
|
|
296
|
+
|
|
297
|
+
Example:
|
|
298
|
+
g -m "Initial commit" Commit with a custom message
|
|
299
|
+
g -m=Fix-bug Commit with a custom message (no spaces around '=')
|
|
300
|
+
g -y Auto commit with the default message
|
|
301
|
+
g -y --interval=600 Commit every 10 minutes (600 seconds)
|
|
302
|
+
g --path=/path/to/repo Specify a custom working directory
|
|
303
|
+
g log Show recent commit logs
|
|
304
|
+
g log --n=5 Show the last 5 commits with --log
|
|
305
|
+
|
|
306
|
+
Add auto submit in package.json:
|
|
307
|
+
"scripts": {
|
|
308
|
+
"g:y": "g -y"
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
Run in the background across platforms:
|
|
312
|
+
Windows:
|
|
313
|
+
start /min cmd /k "g -y --path=your-folder --interval=600"
|
|
314
|
+
|
|
315
|
+
Linux/macOS:
|
|
316
|
+
nohup g -y --path=your-folder --interval=600 > git-autocommit.log 2>&1 &
|
|
317
|
+
|
|
318
|
+
Stop all monitoring processes:
|
|
319
|
+
Windows: Terminate the Node.js process in the Task Manager.
|
|
320
|
+
Linux/macOS:
|
|
321
|
+
pkill -f "g -y" # Terminate all auto-commit processes
|
|
322
|
+
ps aux | grep "g -y" # Find the specific process ID
|
|
323
|
+
kill [PID] # Terminate the specified process
|
|
324
|
+
`;
|
|
325
|
+
|
|
326
|
+
console.log(helpMessage);
|
|
327
|
+
process.exit();
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
function judgeLog() {
|
|
331
|
+
const logArg = process.argv.find(arg => arg === 'log');
|
|
332
|
+
if (logArg) {
|
|
333
|
+
printGitLog(); // 如果有 log 参数,打印 Git 提交记录
|
|
334
|
+
// 打印完成后退出
|
|
335
|
+
process.exit();
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function judgeHelp() {
|
|
340
|
+
if (process.argv.includes('-h') || process.argv.includes('--help')) {
|
|
341
|
+
showHelp();
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
async function printGitLog() {
|
|
346
|
+
let n = 20;
|
|
347
|
+
let logArg = process.argv.find(arg => arg.startsWith('--n='));
|
|
348
|
+
if (logArg) {
|
|
349
|
+
n = parseInt(logArg.split('=')[1], 10);
|
|
350
|
+
}
|
|
351
|
+
const logCommand = `git log -n ${n} --pretty=format:"%C(green)%h%C(reset) | %C(cyan)%an%C(reset) | %C(yellow)%ad%C(reset) | %C(blue)%D%C(reset) | %C(magenta)%s%C(reset)" --date=format:"%Y-%m-%d %H:%M" --graph --decorate --color`
|
|
352
|
+
try {
|
|
353
|
+
const logOutput = execSyncGitCommand(logCommand, {
|
|
354
|
+
head: `git log`
|
|
355
|
+
});
|
|
356
|
+
} catch (error) {
|
|
357
|
+
console.error('无法获取 Git 提交记录:', error.message);
|
|
358
|
+
}
|
|
359
|
+
// 打印完成后退出
|
|
360
|
+
process.exit();
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function exec_exit(exit) {
|
|
364
|
+
if (exit) {
|
|
365
|
+
process.exit()
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function judgeUnmerged(statusOutput) {
|
|
370
|
+
const hasUnmerged = statusOutput.includes('You have unmerged paths');
|
|
371
|
+
if (hasUnmerged) {
|
|
372
|
+
errorLog('错误', '存在未合并的文件,请先解决冲突')
|
|
373
|
+
process.exit(1);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function exec_push({exit, commitMessage}) {
|
|
378
|
+
// 执行 git push
|
|
379
|
+
// execSyncGitCommand(`git push`);
|
|
380
|
+
return new Promise((resolve, reject) => {
|
|
381
|
+
const spinner = ora('正在推送代码...').start();
|
|
382
|
+
execGitCommand('git push', {
|
|
383
|
+
spinner
|
|
384
|
+
}).then(({stdout, stderr}) => {
|
|
385
|
+
printCommitLog({commitMessage})
|
|
386
|
+
resolve({stdout, stderr})
|
|
387
|
+
})
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function printCommitLog({commitMessage}) {
|
|
392
|
+
try {
|
|
393
|
+
// 获取项目名称(取git仓库根目录名)
|
|
394
|
+
const projectRoot = execSyncGitCommand('git rev-parse --show-toplevel', {log: false});
|
|
395
|
+
const projectName = chalk.blueBright(path.basename(projectRoot.trim()));
|
|
396
|
+
|
|
397
|
+
// 获取当前提交hash(取前7位)
|
|
398
|
+
const commitHash = execSyncGitCommand('git rev-parse --short HEAD', {log: false}).trim();
|
|
399
|
+
const hashDisplay = chalk.yellow(commitHash);
|
|
400
|
+
|
|
401
|
+
// 获取分支信息
|
|
402
|
+
const branch = execSyncGitCommand('git branch --show-current', {log: false}).trim();
|
|
403
|
+
const branchDisplay = chalk.magenta(branch);
|
|
404
|
+
|
|
405
|
+
// 构建信息内容
|
|
406
|
+
const message = [
|
|
407
|
+
`${chalk.cyan.bold('Project:')} ${projectName}`,
|
|
408
|
+
`${chalk.cyan.bold('Commit:')} ${hashDisplay} ${chalk.dim('on')} ${branchDisplay}`,
|
|
409
|
+
`${chalk.cyan.bold('Message:')} ${chalk.reset(commitMessage)}`,
|
|
410
|
+
`${chalk.cyan.bold('Time:')} ${new Date().toLocaleString()}`
|
|
411
|
+
].join('\n');
|
|
412
|
+
|
|
413
|
+
// 使用boxen创建装饰框
|
|
414
|
+
const box = boxen(message, {
|
|
415
|
+
padding: 1,
|
|
416
|
+
margin: 1,
|
|
417
|
+
borderStyle: 'round',
|
|
418
|
+
borderColor: 'green',
|
|
419
|
+
title: chalk.bold.green('✅ COMMIT SUCCESS'),
|
|
420
|
+
titleAlignment: 'center',
|
|
421
|
+
float: 'left',
|
|
422
|
+
textAlignment: 'left'
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
console.log(box);
|
|
426
|
+
} catch (error) {
|
|
427
|
+
// 异常处理
|
|
428
|
+
const errorBox = boxen(chalk.red(`Failed to get commit details: ${error.message}`), {
|
|
429
|
+
borderColor: 'red',
|
|
430
|
+
padding: 1
|
|
431
|
+
});
|
|
432
|
+
console.log(errorBox);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
async function execPull() {
|
|
437
|
+
try {
|
|
438
|
+
// 检查是否需要拉取更新
|
|
439
|
+
const spinner = ora('正在拉取代码...').start();
|
|
440
|
+
await execGitCommand('git pull', {
|
|
441
|
+
spinner
|
|
442
|
+
})
|
|
443
|
+
} catch (e) {
|
|
444
|
+
console.log(chalk.yellow('⚠️ 拉取远程更新合并失败,可能存在冲突,请手动处理'));
|
|
445
|
+
throw Error(e)
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function delay(timeout) {
|
|
450
|
+
return new Promise(resolve => setTimeout(resolve, timeout));
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
async function judgeRemote() {
|
|
454
|
+
const spinner = ora('正在检查远程更新...').start();
|
|
455
|
+
try {
|
|
456
|
+
// 检查是否有远程更新
|
|
457
|
+
// 先获取远程最新状态
|
|
458
|
+
await execGitCommand('git remote update', {
|
|
459
|
+
head: 'Fetching remote updates',
|
|
460
|
+
log: false
|
|
461
|
+
});
|
|
462
|
+
// 检查是否需要 pull
|
|
463
|
+
const res = await execGitCommand('git rev-list HEAD..@{u} --count', {
|
|
464
|
+
head: 'Checking if behind remote',
|
|
465
|
+
log: false
|
|
466
|
+
});
|
|
467
|
+
const behindCount = res.stdout.trim()
|
|
468
|
+
const { green, black, bgGreen, white } = chalk;
|
|
469
|
+
// 如果本地落后于远程
|
|
470
|
+
if (parseInt(behindCount) > 0) {
|
|
471
|
+
try {
|
|
472
|
+
spinner.stop();
|
|
473
|
+
// const spinner_pull = ora('发现远程更新,正在拉取...').start();
|
|
474
|
+
await execPull()
|
|
475
|
+
|
|
476
|
+
// // 尝试使用 --ff-only 拉取更新
|
|
477
|
+
// const res = await execGitCommand('git pull --ff-only', {
|
|
478
|
+
// spinner: spinner_pull,
|
|
479
|
+
// head: 'Pulling updates'
|
|
480
|
+
// });
|
|
481
|
+
// console.log(
|
|
482
|
+
// bgGreen.white.bold(' SYNC ') +
|
|
483
|
+
// green` ➔ ` +
|
|
484
|
+
// chalk.blue.bold('远程仓库已同步') +
|
|
485
|
+
// green(' ✔')
|
|
486
|
+
// );
|
|
487
|
+
const message = '已成功同步远程更新'.split('').map((char, i) =>
|
|
488
|
+
chalk.rgb(0, 255 - i*10, 0)(char)
|
|
489
|
+
).join('');
|
|
490
|
+
|
|
491
|
+
console.log(chalk.bold(`✅ ${message}`));
|
|
492
|
+
} catch (pullError) {
|
|
493
|
+
// // 如果 --ff-only 拉取失败,尝试普通的 git pull
|
|
494
|
+
// console.log(chalk.yellow('⚠️ 无法快进合并,尝试普通合并...'));
|
|
495
|
+
// await this.execPull()
|
|
496
|
+
throw new Error(pullError)
|
|
497
|
+
}
|
|
498
|
+
} else {
|
|
499
|
+
spinner.stop();
|
|
500
|
+
const message = '本地已是最新'.split('').map((char, i) =>
|
|
501
|
+
chalk.rgb(0, 255 - i*10, 0)(char)
|
|
502
|
+
).join('');
|
|
503
|
+
console.log(chalk.bold(`✅ ${message}`));
|
|
504
|
+
}
|
|
505
|
+
} catch (e) {
|
|
506
|
+
// console.log(`e ==> `, e)
|
|
507
|
+
spinner.stop();
|
|
508
|
+
throw new Error(e)
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
async function execDiff() {
|
|
513
|
+
const no_diff = process.argv.find(arg => arg.startsWith('--no-diff'))
|
|
514
|
+
if (!no_diff) {
|
|
515
|
+
await execGitCommand('git diff --color=always', {
|
|
516
|
+
head: `git diff`
|
|
517
|
+
})
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
async function execAddAndCommit({statusOutput, commitMessage, exit}) {
|
|
522
|
+
// 检查 -m 参数(提交信息)
|
|
523
|
+
const commitMessageArg = process.argv.find(arg => arg.startsWith('-m'));
|
|
524
|
+
if (commitMessageArg) {
|
|
525
|
+
if (commitMessageArg.includes('=')) {
|
|
526
|
+
// 处理 -m=<message> 的情况
|
|
527
|
+
commitMessage = commitMessageArg.split('=')[1]?.replace(/^['"]|['"]$/g, '');
|
|
528
|
+
} else {
|
|
529
|
+
// 处理 -m <message> 的情况
|
|
530
|
+
const index = process.argv.indexOf(commitMessageArg);
|
|
531
|
+
if (index !== -1 && process.argv[index + 1]) {
|
|
532
|
+
commitMessage = process.argv[index + 1]?.replace(/^['"]|['"]$/g, '');
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// 检查命令行参数,判断是否有 -y 参数
|
|
538
|
+
const autoCommit = process.argv.includes('-y');
|
|
539
|
+
|
|
540
|
+
if (!autoCommit && !commitMessageArg) {
|
|
541
|
+
// 如果没有 -y 参数,则等待用户输入提交信息
|
|
542
|
+
const rl = readline.createInterface({
|
|
543
|
+
input: process.stdin,
|
|
544
|
+
output: process.stdout
|
|
545
|
+
})
|
|
546
|
+
|
|
547
|
+
function rlPromisify(fn) {
|
|
548
|
+
return async (...args) => {
|
|
549
|
+
return new Promise((resolve, reject) => fn(...args, resolve, reject))
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const question = rlPromisify(rl.question.bind(rl))
|
|
554
|
+
commitMessage = await question('请输入提交信息:') || commitMessage;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
statusOutput.includes('(use "git add') && await execGitCommand('git add .')
|
|
558
|
+
// 强制添加所有变更
|
|
559
|
+
// await execGitCommand('git add -A .');
|
|
560
|
+
|
|
561
|
+
// 提交前二次校验
|
|
562
|
+
const checkStatus = await execGitCommand('git status --porcelain', {log: false});
|
|
563
|
+
if (!checkStatus.stdout.trim()) {
|
|
564
|
+
console.log(chalk.yellow('⚠️ 没有检测到可提交的变更'));
|
|
565
|
+
// exec_exit(exit)
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// 执行 git commit
|
|
570
|
+
if (statusOutput.includes('Untracked files:') || statusOutput.includes('Changes not staged for commit') || statusOutput.includes('Changes to be committed')) {
|
|
571
|
+
await execGitCommand(`git commit -m "${commitMessage}"`)
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// 添加时间格式化函数
|
|
576
|
+
function formatDuration(ms) {
|
|
577
|
+
const totalSeconds = Math.floor(ms / 1000);
|
|
578
|
+
const days = Math.floor(totalSeconds / (3600 * 24));
|
|
579
|
+
const hours = Math.floor((totalSeconds % (3600 * 24)) / 3600);
|
|
580
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
581
|
+
const seconds = totalSeconds % 60;
|
|
582
|
+
|
|
583
|
+
return [
|
|
584
|
+
days && `${days}天`,
|
|
585
|
+
hours && `${hours}小时`,
|
|
586
|
+
minutes && `${minutes}分`,
|
|
587
|
+
`${seconds}秒`
|
|
588
|
+
].filter(Boolean).join('');
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
export {
|
|
592
|
+
coloredLog, errorLog, execSyncGitCommand,
|
|
593
|
+
execGitCommand, getCwd, judgePlatform, showHelp, judgeLog, printGitLog,
|
|
594
|
+
judgeHelp, exec_exit, judgeUnmerged, delay, formatDuration,
|
|
595
|
+
exec_push, execPull, judgeRemote, execDiff, execAddAndCommit
|
|
596
|
+
};
|