git-push-time 1.1.2 → 1.1.4
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/.github/workflows/npm-publish.yml +59 -32
- package/README.md +110 -112
- package/bin/index.js +321 -339
- package/lib/commands/edit-time.js +141 -141
- package/lib/commands/fix.js +113 -113
- package/lib/commands/github.js +429 -445
- package/lib/commands/pull.js +90 -90
- package/lib/commands/push.js +720 -720
- package/lib/config.js +220 -220
- package/lib/fix.js +286 -286
- package/lib/git.js +525 -516
- package/lib/github.js +322 -322
- package/lib/prompt-helpers.js +19 -20
- package/lib/secrets.js +92 -92
- package/lib/ui.js +1057 -1063
- package/lib/utils.js +120 -120
- package/package.json +36 -36
package/bin/index.js
CHANGED
|
@@ -1,339 +1,321 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { Command } from 'commander';
|
|
4
|
-
import chalk from 'chalk';
|
|
5
|
-
import fs from 'fs';
|
|
6
|
-
import path from 'path';
|
|
7
|
-
import { fileURLToPath } from 'url';
|
|
8
|
-
import { checkGitInstalled, getCurrentBranch, getDashboardGitStatus } from '../lib/git.js';
|
|
9
|
-
import { getCurrentGitHubUser } from '../lib/github.js';
|
|
10
|
-
import { runPushWizard } from '../lib/commands/push.js';
|
|
11
|
-
import { runPullCommand } from '../lib/commands/pull.js';
|
|
12
|
-
import { runEditCommitTimeCommand } from '../lib/commands/edit-time.js';
|
|
13
|
-
import { runFixCommand } from '../lib/commands/fix.js';
|
|
14
|
-
import {
|
|
15
|
-
runGitHubMenu,
|
|
16
|
-
promptCreateRepo,
|
|
17
|
-
showUserRepos,
|
|
18
|
-
} from '../lib/commands/github.js';
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
printBanner,
|
|
22
|
-
printDashboardStatus,
|
|
23
|
-
printGitMissing,
|
|
24
|
-
printCancelled,
|
|
25
|
-
styleCliHelp
|
|
26
|
-
} from '../lib/ui.js';
|
|
27
|
-
|
|
28
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
29
|
-
const __dirname = path.dirname(__filename);
|
|
30
|
-
|
|
31
|
-
function getPackageVersion() {
|
|
32
|
-
try {
|
|
33
|
-
const raw = fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8');
|
|
34
|
-
return JSON.parse(raw).version || '1.1.0';
|
|
35
|
-
} catch {
|
|
36
|
-
return '1.1.0';
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const VERSION = getPackageVersion();
|
|
41
|
-
|
|
42
|
-
function isExitPromptError(err) {
|
|
43
|
-
const msg = String(err?.message || '');
|
|
44
|
-
return (
|
|
45
|
-
err?.name === 'ExitPromptError' ||
|
|
46
|
-
msg.includes('User force closed the prompt') ||
|
|
47
|
-
msg.includes('SIGINT')
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
*
|
|
53
|
-
*/
|
|
54
|
-
function isBareInvocation(options = {}) {
|
|
55
|
-
return (
|
|
56
|
-
!options.repo &&
|
|
57
|
-
!options.message &&
|
|
58
|
-
!options.date &&
|
|
59
|
-
!options.branch &&
|
|
60
|
-
!options.dir &&
|
|
61
|
-
!options.force &&
|
|
62
|
-
!options.fix
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
*
|
|
68
|
-
*/
|
|
69
|
-
async function promptMainMenu() {
|
|
70
|
-
return await selectBox({
|
|
71
|
-
message: '
|
|
72
|
-
hint: '↑↓
|
|
73
|
-
pageSize: 10,
|
|
74
|
-
choices: [
|
|
75
|
-
{
|
|
76
|
-
name: `${chalk.hex('#38BDF8').bold('
|
|
77
|
-
value: 'push',
|
|
78
|
-
description: '
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
name: `${chalk.hex('#A78BFA').bold('
|
|
82
|
-
value: 'github',
|
|
83
|
-
description: '
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
name: `${chalk.hex('#34D399').bold('
|
|
87
|
-
value: 'pull',
|
|
88
|
-
description: 'Pull
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
name: `${chalk.hex('#FBBF24').bold('
|
|
92
|
-
value: 'edit-time',
|
|
93
|
-
description: '
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
name: `${chalk.hex('#F43F5E').bold('
|
|
97
|
-
value: 'fix',
|
|
98
|
-
description: '
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
name: `${chalk.hex('#64748B').bold('
|
|
102
|
-
value: 'exit',
|
|
103
|
-
},
|
|
104
|
-
],
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
*
|
|
110
|
-
*/
|
|
111
|
-
async function runMainMenuLoop(initialOptions = {}) {
|
|
112
|
-
while (true) {
|
|
113
|
-
const cwd = process.cwd();
|
|
114
|
-
let branch = 'main';
|
|
115
|
-
try {
|
|
116
|
-
branch = getCurrentBranch(cwd);
|
|
117
|
-
} catch {}
|
|
118
|
-
let ghStatus = { authenticated: false };
|
|
119
|
-
try {
|
|
120
|
-
ghStatus = await getCurrentGitHubUser();
|
|
121
|
-
} catch {
|
|
122
|
-
ghStatus = { authenticated: false };
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const gitStatus = getDashboardGitStatus(cwd);
|
|
126
|
-
printDashboardStatus({
|
|
127
|
-
targetDir: cwd,
|
|
128
|
-
currentBranch: branch,
|
|
129
|
-
githubUser: ghStatus.authenticated ? ghStatus.user : null,
|
|
130
|
-
remoteUrl: gitStatus.remoteUrl,
|
|
131
|
-
changes: gitStatus.changes,
|
|
132
|
-
lastCommit: gitStatus.lastCommit,
|
|
133
|
-
version: VERSION,
|
|
134
|
-
});
|
|
135
|
-
let action;
|
|
136
|
-
try {
|
|
137
|
-
action = await promptMainMenu();
|
|
138
|
-
} catch (err) {
|
|
139
|
-
if (isExitPromptError(err)) {
|
|
140
|
-
printCancelled();
|
|
141
|
-
process.exit(0);
|
|
142
|
-
}
|
|
143
|
-
throw err;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (action === 'exit') {
|
|
147
|
-
printCancelled();
|
|
148
|
-
process.exit(0);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
try {
|
|
152
|
-
if (action === 'push') {
|
|
153
|
-
const res = await runPushWizard(initialOptions, async () => 'back');
|
|
154
|
-
// 'back'
|
|
155
|
-
if (res === 'back') continue;
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (action === 'github') {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
.
|
|
242
|
-
.
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
.
|
|
249
|
-
.
|
|
250
|
-
.option('-
|
|
251
|
-
.
|
|
252
|
-
|
|
253
|
-
await
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
.
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
.
|
|
269
|
-
.
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
.
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
.
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
.
|
|
295
|
-
.
|
|
296
|
-
.action(async () => {
|
|
297
|
-
printBanner(VERSION);
|
|
298
|
-
await
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
.
|
|
304
|
-
.
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
.
|
|
314
|
-
.
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
.description('Cập nhật code từ remote bằng fast-forward --ff-only hoặc --rebase')
|
|
323
|
-
.option('-C, --dir <path>', 'Thư mục repo cần pull (Mặc định: thư mục hiện tại)')
|
|
324
|
-
.action(async (remote, branch, opts) => {
|
|
325
|
-
printBanner(VERSION);
|
|
326
|
-
await runPullCommand(remote || 'origin', branch, opts || {});
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
// LỆNH EDIT-TIME
|
|
330
|
-
program
|
|
331
|
-
.command('edit-time')
|
|
332
|
-
.description('Sửa thời gian của commit lịch sử (Backdate commit hash)')
|
|
333
|
-
.option('-C, --dir <path>', 'Thư mục repo (Mặc định: thư mục hiện tại)')
|
|
334
|
-
.action(async (opts) => {
|
|
335
|
-
printBanner(VERSION);
|
|
336
|
-
await runEditCommitTimeCommand(opts);
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
program.parse(process.argv);
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
import { checkGitInstalled, getCurrentBranch, getDashboardGitStatus } from '../lib/git.js';
|
|
9
|
+
import { getCurrentGitHubUser } from '../lib/github.js';
|
|
10
|
+
import { runPushWizard } from '../lib/commands/push.js';
|
|
11
|
+
import { runPullCommand } from '../lib/commands/pull.js';
|
|
12
|
+
import { runEditCommitTimeCommand } from '../lib/commands/edit-time.js';
|
|
13
|
+
import { runFixCommand } from '../lib/commands/fix.js';
|
|
14
|
+
import {
|
|
15
|
+
runGitHubMenu,
|
|
16
|
+
promptCreateRepo,
|
|
17
|
+
showUserRepos,
|
|
18
|
+
} from '../lib/commands/github.js';
|
|
19
|
+
import { selectBox } from '../lib/prompt-helpers.js';
|
|
20
|
+
import {
|
|
21
|
+
printBanner,
|
|
22
|
+
printDashboardStatus,
|
|
23
|
+
printGitMissing,
|
|
24
|
+
printCancelled,
|
|
25
|
+
styleCliHelp
|
|
26
|
+
} from '../lib/ui.js';
|
|
27
|
+
|
|
28
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
29
|
+
const __dirname = path.dirname(__filename);
|
|
30
|
+
|
|
31
|
+
function getPackageVersion() {
|
|
32
|
+
try {
|
|
33
|
+
const raw = fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8');
|
|
34
|
+
return JSON.parse(raw).version || '1.1.0';
|
|
35
|
+
} catch {
|
|
36
|
+
return '1.1.0';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const VERSION = getPackageVersion();
|
|
41
|
+
|
|
42
|
+
function isExitPromptError(err) {
|
|
43
|
+
const msg = String(err?.message || '');
|
|
44
|
+
return (
|
|
45
|
+
err?.name === 'ExitPromptError' ||
|
|
46
|
+
msg.includes('User force closed the prompt') ||
|
|
47
|
+
msg.includes('SIGINT')
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Check whether the command was invoked without flags or subcommands.
|
|
53
|
+
*/
|
|
54
|
+
function isBareInvocation(options = {}) {
|
|
55
|
+
return (
|
|
56
|
+
!options.repo &&
|
|
57
|
+
!options.message &&
|
|
58
|
+
!options.date &&
|
|
59
|
+
!options.branch &&
|
|
60
|
+
!options.dir &&
|
|
61
|
+
!options.force &&
|
|
62
|
+
!options.fix
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Main menu shown when `git-push-time` is run without flags.
|
|
68
|
+
*/
|
|
69
|
+
async function promptMainMenu() {
|
|
70
|
+
return await selectBox({
|
|
71
|
+
message: 'Main dashboard',
|
|
72
|
+
hint: '↑↓ move · Enter select · Esc exit',
|
|
73
|
+
pageSize: 10,
|
|
74
|
+
choices: [
|
|
75
|
+
{
|
|
76
|
+
name: `${chalk.hex('#38BDF8').bold('PUSH')} ${chalk.hex('#334155')('·')} ${chalk.hex('#F1F5F9')('Push a project to a repository')}`,
|
|
77
|
+
value: 'push',
|
|
78
|
+
description: 'Choose or create a repository, scan for secrets, and push',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: `${chalk.hex('#A78BFA').bold('GITHUB')} ${chalk.hex('#334155')('·')} ${chalk.hex('#CBD5E1')('Accounts and repositories')}`,
|
|
82
|
+
value: 'github',
|
|
83
|
+
description: 'Sign in, switch accounts, and browse GitHub repositories',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: `${chalk.hex('#34D399').bold('PULL')} ${chalk.hex('#334155')('·')} ${chalk.hex('#CBD5E1')('Get updates from a remote')}`,
|
|
87
|
+
value: 'pull',
|
|
88
|
+
description: 'Pull safely with fast-forward or rebase',
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: `${chalk.hex('#FBBF24').bold('EDIT TIME')} ${chalk.hex('#334155')('·')} ${chalk.hex('#CBD5E1')('Change a commit timestamp')}`,
|
|
92
|
+
value: 'edit-time',
|
|
93
|
+
description: 'Rewrite the timestamp of an existing commit',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: `${chalk.hex('#F43F5E').bold('SECURITY')} ${chalk.hex('#334155')('·')} ${chalk.hex('#CBD5E1')('Scan for secrets')}`,
|
|
97
|
+
value: 'fix',
|
|
98
|
+
description: 'Scan for secrets, unstage them, and update .gitignore',
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: `${chalk.hex('#64748B').bold('EXIT')} ${chalk.hex('#334155')('·')} ${chalk.hex('#64748B')('Close the program')}`,
|
|
102
|
+
value: 'exit',
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Main menu loop; back callbacks return a sentinel instead of recursing.
|
|
110
|
+
*/
|
|
111
|
+
async function runMainMenuLoop(initialOptions = {}) {
|
|
112
|
+
while (true) {
|
|
113
|
+
const cwd = process.cwd();
|
|
114
|
+
let branch = 'main';
|
|
115
|
+
try {
|
|
116
|
+
branch = getCurrentBranch(cwd);
|
|
117
|
+
} catch {}
|
|
118
|
+
let ghStatus = { authenticated: false };
|
|
119
|
+
try {
|
|
120
|
+
ghStatus = await getCurrentGitHubUser();
|
|
121
|
+
} catch {
|
|
122
|
+
ghStatus = { authenticated: false };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const gitStatus = getDashboardGitStatus(cwd);
|
|
126
|
+
printDashboardStatus({
|
|
127
|
+
targetDir: cwd,
|
|
128
|
+
currentBranch: branch,
|
|
129
|
+
githubUser: ghStatus.authenticated ? ghStatus.user : null,
|
|
130
|
+
remoteUrl: gitStatus.remoteUrl,
|
|
131
|
+
changes: gitStatus.changes,
|
|
132
|
+
lastCommit: gitStatus.lastCommit,
|
|
133
|
+
version: VERSION,
|
|
134
|
+
});
|
|
135
|
+
let action;
|
|
136
|
+
try {
|
|
137
|
+
action = await promptMainMenu();
|
|
138
|
+
} catch (err) {
|
|
139
|
+
if (isExitPromptError(err)) {
|
|
140
|
+
printCancelled();
|
|
141
|
+
process.exit(0);
|
|
142
|
+
}
|
|
143
|
+
throw err;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (action === 'exit') {
|
|
147
|
+
printCancelled();
|
|
148
|
+
process.exit(0);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
if (action === 'push') {
|
|
153
|
+
const res = await runPushWizard(initialOptions, async () => 'back');
|
|
154
|
+
// 'back' returns to the dashboard; otherwise the completed push exits.
|
|
155
|
+
if (res === 'back') continue;
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (action === 'github') {
|
|
160
|
+
await runGitHubMenu();
|
|
161
|
+
} else if (action === 'pull') {
|
|
162
|
+
await runPullCommand('origin', undefined, { fromMenu: true });
|
|
163
|
+
} else if (action === 'edit-time') {
|
|
164
|
+
await runEditCommitTimeCommand({ fromMenu: true });
|
|
165
|
+
} else if (action === 'fix') {
|
|
166
|
+
await runFixCommand({ fromMenu: true });
|
|
167
|
+
}
|
|
168
|
+
} catch (err) {
|
|
169
|
+
if (isExitPromptError(err)) {
|
|
170
|
+
printCancelled();
|
|
171
|
+
process.exit(0);
|
|
172
|
+
}
|
|
173
|
+
throw err;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Each action returns to the dashboard, so no extra continue/back prompt is needed.
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async function main(options = {}) {
|
|
181
|
+
printBanner(VERSION);
|
|
182
|
+
|
|
183
|
+
if (!checkGitInstalled()) {
|
|
184
|
+
printGitMissing();
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const isInteractive = !options.yes;
|
|
189
|
+
|
|
190
|
+
if (isInteractive && isBareInvocation(options)) {
|
|
191
|
+
try {
|
|
192
|
+
await runMainMenuLoop(options);
|
|
193
|
+
} catch (err) {
|
|
194
|
+
if (isExitPromptError(err)) {
|
|
195
|
+
printCancelled();
|
|
196
|
+
process.exit(0);
|
|
197
|
+
}
|
|
198
|
+
throw err;
|
|
199
|
+
}
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Run the push wizard directly with the supplied options.
|
|
204
|
+
try {
|
|
205
|
+
await runPushWizard(options);
|
|
206
|
+
} catch (err) {
|
|
207
|
+
if (isExitPromptError(err)) {
|
|
208
|
+
printCancelled();
|
|
209
|
+
process.exit(0);
|
|
210
|
+
}
|
|
211
|
+
throw err;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/* ==========================================================================
|
|
216
|
+
COMMANDER CLI CONFIGURATION
|
|
217
|
+
========================================================================== */
|
|
218
|
+
|
|
219
|
+
const program = new Command();
|
|
220
|
+
styleCliHelp(program);
|
|
221
|
+
|
|
222
|
+
program
|
|
223
|
+
.name('git-push-time')
|
|
224
|
+
.description('Git and GitHub CLI for pushing, repository management, commit timestamps, and secret protection')
|
|
225
|
+
.version(VERSION)
|
|
226
|
+
.option('-r, --repo <url>', 'Git repository URL, or leave empty to choose or create one')
|
|
227
|
+
.option('-d, --date <datetime>', 'Commit time (e.g. "2024-01-15 14:30:00", "-2d", "-5h", "now")')
|
|
228
|
+
.option('-m, --message <msg>', 'Commit message')
|
|
229
|
+
.option('-b, --branch <branch>', 'Remote branch name (default: main)')
|
|
230
|
+
.option('-C, --dir <path>', 'Source folder to push (default: current folder)')
|
|
231
|
+
.option('-f, --force', 'Force push (--force)', false)
|
|
232
|
+
.option('-y, --yes', 'Skip prompts and use the provided values or defaults', false)
|
|
233
|
+
.option('--fix', 'Unstage secret files and update .gitignore (keeps local files)', false)
|
|
234
|
+
.action(async (opts) => {
|
|
235
|
+
await main(opts);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// GITHUB COMMANDS
|
|
239
|
+
const ghCmd = program
|
|
240
|
+
.command('github')
|
|
241
|
+
.description('Manage GitHub accounts and repositories')
|
|
242
|
+
.action(async () => {
|
|
243
|
+
printBanner(VERSION);
|
|
244
|
+
await runGitHubMenu();
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
ghCmd
|
|
248
|
+
.command('create')
|
|
249
|
+
.description('Create a GitHub repository (public or private)')
|
|
250
|
+
.option('-C, --dir <path>', 'Source folder used to suggest a repository name')
|
|
251
|
+
.action(async (opts) => {
|
|
252
|
+
printBanner(VERSION);
|
|
253
|
+
const res = await promptCreateRepo({ targetDir: opts.dir || process.cwd() });
|
|
254
|
+
if (res.ok && res.repo) {
|
|
255
|
+
console.log(`\n » Repo URL: ${res.repo.cloneUrl}\n`);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
ghCmd
|
|
260
|
+
.command('whoami')
|
|
261
|
+
.description('Show the connected GitHub account')
|
|
262
|
+
.action(async () => {
|
|
263
|
+
printBanner(VERSION);
|
|
264
|
+
await showGitHubStatus();
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
ghCmd
|
|
268
|
+
.command('repos')
|
|
269
|
+
.description('List your GitHub repositories')
|
|
270
|
+
.action(async () => {
|
|
271
|
+
printBanner(VERSION);
|
|
272
|
+
await showUserRepos();
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
ghCmd
|
|
276
|
+
.command('login')
|
|
277
|
+
.description('Sign in to GitHub with OAuth Device Flow or a token')
|
|
278
|
+
.action(async () => {
|
|
279
|
+
printBanner(VERSION);
|
|
280
|
+
await promptGitHubLogin();
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
ghCmd
|
|
284
|
+
.command('logout')
|
|
285
|
+
.description('Sign out of GitHub on this machine')
|
|
286
|
+
.action(async () => {
|
|
287
|
+
printBanner(VERSION);
|
|
288
|
+
logoutGitHub();
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
// FIX COMMAND
|
|
292
|
+
program
|
|
293
|
+
.command('fix')
|
|
294
|
+
.description('Scan for secrets, unstage files, update .gitignore, and clean unpushed commits')
|
|
295
|
+
.option('-C, --dir <path>', 'Folder to scan (default: current folder)')
|
|
296
|
+
.action(async (opts) => {
|
|
297
|
+
printBanner(VERSION);
|
|
298
|
+
await runFixCommand(opts);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
// PULL COMMAND
|
|
302
|
+
program
|
|
303
|
+
.command('pull [remote] [branch]')
|
|
304
|
+
.description('Pull from a remote with fast-forward (--ff-only) or rebase')
|
|
305
|
+
.option('-C, --dir <path>', 'Repository folder (default: current folder)')
|
|
306
|
+
.action(async (remote, branch, opts) => {
|
|
307
|
+
printBanner(VERSION);
|
|
308
|
+
await runPullCommand(remote || 'origin', branch, opts || {});
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// EDIT-TIME COMMAND
|
|
312
|
+
program
|
|
313
|
+
.command('edit-time')
|
|
314
|
+
.description('Change the timestamp of an existing commit')
|
|
315
|
+
.option('-C, --dir <path>', 'Repository folder (default: current folder)')
|
|
316
|
+
.action(async (opts) => {
|
|
317
|
+
printBanner(VERSION);
|
|
318
|
+
await runEditCommitTimeCommand(opts);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
program.parse(process.argv);
|