reslop 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -1
- package/README.md +33 -21
- package/lib/ansi.js +1 -0
- package/lib/cli.js +20 -16
- package/lib/detect.js +2 -40
- package/lib/files.js +38 -5
- package/lib/git.js +343 -18
- package/lib/highlight/bash.js +228 -0
- package/lib/highlight/core.js +194 -0
- package/lib/highlight/css.js +76 -0
- package/lib/highlight/csv.js +66 -0
- package/lib/highlight/dart.js +261 -0
- package/lib/highlight/dot.js +54 -0
- package/lib/highlight/html.js +90 -0
- package/lib/highlight/js.js +571 -0
- package/lib/highlight/json.js +54 -0
- package/lib/highlight/log.js +60 -0
- package/lib/highlight/txt.js +41 -0
- package/lib/highlight.js +32 -1299
- package/lib/keys.js +111 -31
- package/lib/render.js +578 -57
- package/lib/review.js +6 -63
- package/lib/session.js +843 -202
- package/lib/sys.js +4 -0
- package/lib/update.js +302 -0
- package/package.json +1 -1
package/lib/git.js
CHANGED
|
@@ -7,7 +7,7 @@ const path = require('node:path');
|
|
|
7
7
|
const diff = require('./diff.js');
|
|
8
8
|
const { parseDiff, synthesizeNewFile, itemsFromFiles } = diff;
|
|
9
9
|
const { itemPath, isPathInScope, REVIEW_DIR } = require('./files.js');
|
|
10
|
-
const { npmBin, spawnBase } = require('./sys.js');
|
|
10
|
+
const { npmBin, spawnBase, npmOpts } = require('./sys.js');
|
|
11
11
|
const deps = require('./deps.js');
|
|
12
12
|
const { foldDepItems, mergeDepFile, depFileMeta } = deps;
|
|
13
13
|
const { collectUsedNames, parseAuditReport, parseOutdatedReport } = deps;
|
|
@@ -25,6 +25,23 @@ const GIT_MAX_BUFFER = 32 * 1024 * 1024;
|
|
|
25
25
|
const BINARY_SIZE = 1000000;
|
|
26
26
|
const AUDIT_MS = 15000;
|
|
27
27
|
const INSTALL_MS = 120000;
|
|
28
|
+
const BRANCH_FORMAT = [
|
|
29
|
+
'%(HEAD)',
|
|
30
|
+
'%(refname:short)',
|
|
31
|
+
'%(objectname:short)',
|
|
32
|
+
'%(committerdate:relative)',
|
|
33
|
+
'%(upstream:track)',
|
|
34
|
+
'%(subject)',
|
|
35
|
+
].join('%09');
|
|
36
|
+
const TRACK_AHEAD = /ahead (\d+)/;
|
|
37
|
+
const TRACK_BEHIND = /behind (\d+)/;
|
|
38
|
+
const ORIGIN_HEAD = 'refs/remotes/origin/HEAD';
|
|
39
|
+
const DEFAULT_BRANCHES = ['main', 'master'];
|
|
40
|
+
const PUSH_REJECTED = [
|
|
41
|
+
'non-fast-forward',
|
|
42
|
+
'failed to push some refs',
|
|
43
|
+
'updates were rejected',
|
|
44
|
+
];
|
|
28
45
|
|
|
29
46
|
const oneLine = (text) => {
|
|
30
47
|
const line = text.trim().split('\n')[0];
|
|
@@ -77,7 +94,15 @@ const runProc = (cmd, args, options = {}) =>
|
|
|
77
94
|
let stderr = '';
|
|
78
95
|
let settled = false;
|
|
79
96
|
let timer = null;
|
|
80
|
-
const
|
|
97
|
+
const spawnOpts = { cwd, env };
|
|
98
|
+
if (options.shell) spawnOpts.shell = true;
|
|
99
|
+
let child;
|
|
100
|
+
try {
|
|
101
|
+
child = spawn(cmd, args, spawnBase(spawnOpts));
|
|
102
|
+
} catch (error) {
|
|
103
|
+
resolve({ status: null, error, stdout: '', stderr: '' });
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
81
106
|
const finish = (result) => {
|
|
82
107
|
if (settled) return;
|
|
83
108
|
settled = true;
|
|
@@ -284,7 +309,7 @@ const runNpmJson = (top, args, timeout) => {
|
|
|
284
309
|
const result = spawnSync(
|
|
285
310
|
npmBin(),
|
|
286
311
|
args,
|
|
287
|
-
|
|
312
|
+
npmOpts({
|
|
288
313
|
cwd: top,
|
|
289
314
|
encoding: GIT_ENCODING,
|
|
290
315
|
maxBuffer: GIT_MAX_BUFFER,
|
|
@@ -302,6 +327,7 @@ const runNpmJsonAsync = async (top, args, timeout, signal) => {
|
|
|
302
327
|
maxBuffer: GIT_MAX_BUFFER,
|
|
303
328
|
timeout,
|
|
304
329
|
signal,
|
|
330
|
+
shell: npmOpts().shell,
|
|
305
331
|
});
|
|
306
332
|
if (result.error) return '';
|
|
307
333
|
return result.stdout || '';
|
|
@@ -456,7 +482,7 @@ const runNpm = (cwd, args) =>
|
|
|
456
482
|
spawnSync(
|
|
457
483
|
npmBin(),
|
|
458
484
|
args,
|
|
459
|
-
|
|
485
|
+
npmOpts({
|
|
460
486
|
cwd,
|
|
461
487
|
encoding: GIT_ENCODING,
|
|
462
488
|
maxBuffer: GIT_MAX_BUFFER,
|
|
@@ -464,6 +490,15 @@ const runNpm = (cwd, args) =>
|
|
|
464
490
|
}),
|
|
465
491
|
);
|
|
466
492
|
|
|
493
|
+
const runNpmAsync = (cwd, args) =>
|
|
494
|
+
runProc(npmBin(), args, {
|
|
495
|
+
cwd,
|
|
496
|
+
encoding: GIT_ENCODING,
|
|
497
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
498
|
+
timeout: INSTALL_MS,
|
|
499
|
+
shell: npmOpts().shell,
|
|
500
|
+
});
|
|
501
|
+
|
|
467
502
|
const firstDepRel = (files, kind) => {
|
|
468
503
|
for (const rel of files) {
|
|
469
504
|
const meta = depFileMeta(rel);
|
|
@@ -472,7 +507,7 @@ const firstDepRel = (files, kind) => {
|
|
|
472
507
|
return '';
|
|
473
508
|
};
|
|
474
509
|
|
|
475
|
-
const
|
|
510
|
+
const proposedNpmPlan = (top, item) => {
|
|
476
511
|
const change = depChange(item);
|
|
477
512
|
const origin = item.origin;
|
|
478
513
|
const files = depPaths(item);
|
|
@@ -483,7 +518,7 @@ const applyProposedUpdate = (top, item) => {
|
|
|
483
518
|
const picked = lockOnly ? lockRel : manifest;
|
|
484
519
|
const target = picked || files[0] || '';
|
|
485
520
|
const meta = depFileMeta(target);
|
|
486
|
-
if (!meta) return;
|
|
521
|
+
if (!meta) return null;
|
|
487
522
|
let saved = '';
|
|
488
523
|
if (!lockOnly && !removing && manifest) {
|
|
489
524
|
const worktree = worktreeText(top, manifest);
|
|
@@ -503,9 +538,23 @@ const applyProposedUpdate = (top, item) => {
|
|
|
503
538
|
let npmArgs = ['i'];
|
|
504
539
|
if (removing) npmArgs = ['uninstall', change.name];
|
|
505
540
|
else if (lockOnly) npmArgs = ['audit', 'fix'];
|
|
506
|
-
const install = item.dep.install ?? ((dir) => runNpm(dir, npmArgs));
|
|
507
|
-
const result = install(cwd);
|
|
508
541
|
const fail = removing ? 'npm uninstall failed' : 'npm i failed';
|
|
542
|
+
const dirLock = meta.dir === '.' ? LOCKFILE : `${meta.dir}/${LOCKFILE}`;
|
|
543
|
+
const lockPath = lockRel || dirLock;
|
|
544
|
+
return {
|
|
545
|
+
cwd,
|
|
546
|
+
npmArgs,
|
|
547
|
+
saved,
|
|
548
|
+
manifest,
|
|
549
|
+
lockOnly,
|
|
550
|
+
lockPath,
|
|
551
|
+
fail,
|
|
552
|
+
runner: item.dep.install,
|
|
553
|
+
};
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
const finishProposedNpm = (top, plan, result) => {
|
|
557
|
+
const { saved, manifest, lockOnly, lockPath, fail } = plan;
|
|
509
558
|
if (result && (result.error || result.status !== 0)) {
|
|
510
559
|
if (saved && manifest) writeWorktreeFile(top, manifest, saved);
|
|
511
560
|
if (result.error) {
|
|
@@ -517,12 +566,26 @@ const applyProposedUpdate = (top, item) => {
|
|
|
517
566
|
}
|
|
518
567
|
const toAdd = [];
|
|
519
568
|
if (!lockOnly && manifest) toAdd.push(manifest);
|
|
520
|
-
const dirLock = meta.dir === '.' ? LOCKFILE : `${meta.dir}/${LOCKFILE}`;
|
|
521
|
-
const lockPath = lockRel || dirLock;
|
|
522
569
|
if (fs.existsSync(path.join(top, lockPath))) toAdd.push(lockPath);
|
|
523
570
|
if (toAdd.length) requireOk(runGit(['add', '--', ...toAdd], top));
|
|
524
571
|
};
|
|
525
572
|
|
|
573
|
+
const applyProposedUpdate = (top, item) => {
|
|
574
|
+
const plan = proposedNpmPlan(top, item);
|
|
575
|
+
if (!plan) return;
|
|
576
|
+
const install = plan.runner ?? ((dir) => runNpm(dir, plan.npmArgs));
|
|
577
|
+
finishProposedNpm(top, plan, install(plan.cwd));
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
const applyProposedUpdateAsync = async (top, item) => {
|
|
581
|
+
const plan = proposedNpmPlan(top, item);
|
|
582
|
+
if (!plan) return;
|
|
583
|
+
const run = plan.runner
|
|
584
|
+
? (dir) => Promise.resolve(plan.runner(dir))
|
|
585
|
+
: (dir) => runNpmAsync(dir, plan.npmArgs);
|
|
586
|
+
finishProposedNpm(top, plan, await run(plan.cwd));
|
|
587
|
+
};
|
|
588
|
+
|
|
526
589
|
const applyDepChange = (top, item, mode) => {
|
|
527
590
|
const change = depChange(item);
|
|
528
591
|
if (change && change.propose) {
|
|
@@ -579,6 +642,15 @@ const commitDiffArgs = (commit, parent, pathArgs) => {
|
|
|
579
642
|
|
|
580
643
|
const pathArgsOf = (paths) => (paths.length ? ['--', ...paths] : []);
|
|
581
644
|
|
|
645
|
+
const currentBranch = (top) => {
|
|
646
|
+
const args = ['rev-parse', '--abbrev-ref', 'HEAD'];
|
|
647
|
+
const result = runGit(args, top);
|
|
648
|
+
if (result.status !== 0) return '';
|
|
649
|
+
const name = result.stdout.trim();
|
|
650
|
+
if (!name || name === 'HEAD') return '';
|
|
651
|
+
return name;
|
|
652
|
+
};
|
|
653
|
+
|
|
582
654
|
const snapshotWorktree = (top, stagedOut, unstagedOut, names) => {
|
|
583
655
|
const stagedDiff = parseDiff(stagedOut);
|
|
584
656
|
const unstagedDiff = parseDiff(unstagedOut);
|
|
@@ -587,14 +659,16 @@ const snapshotWorktree = (top, stagedOut, unstagedOut, names) => {
|
|
|
587
659
|
const untracked = untrackedItemsFrom(top, names);
|
|
588
660
|
const combined = mergeItems([staged, unstaged, untracked]);
|
|
589
661
|
const parsed = dropReviewItems(combined);
|
|
590
|
-
|
|
662
|
+
const branch = currentBranch(top);
|
|
663
|
+
return { top, parsed, branch };
|
|
591
664
|
};
|
|
592
665
|
|
|
593
666
|
const snapshotCommit = (top, commit, files) => {
|
|
594
667
|
const commitItems = itemsFromFiles(files, 'commit');
|
|
595
668
|
const parsed = dropReviewItems(commitItems);
|
|
596
669
|
const revShort = shortRev(top, commit);
|
|
597
|
-
|
|
670
|
+
const branch = currentBranch(top);
|
|
671
|
+
return { top, parsed, rev: commit, revShort, branch };
|
|
598
672
|
};
|
|
599
673
|
|
|
600
674
|
const loadCommit = (top, commit, extra) => {
|
|
@@ -746,6 +820,16 @@ const addItem = (top, item) => {
|
|
|
746
820
|
applyPatch(top, item.patchAdd, ['--cached']);
|
|
747
821
|
};
|
|
748
822
|
|
|
823
|
+
const addItemAsync = async (top, item) => {
|
|
824
|
+
if (item.origin === 'staged' || item.origin === 'commit') return;
|
|
825
|
+
const change = depChange(item);
|
|
826
|
+
if (change && change.propose) {
|
|
827
|
+
await applyProposedUpdateAsync(top, item);
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
addItem(top, item);
|
|
831
|
+
};
|
|
832
|
+
|
|
749
833
|
const unstageItem = (top, item) => {
|
|
750
834
|
if (item.origin !== 'staged') return;
|
|
751
835
|
if (depChange(item)) {
|
|
@@ -851,20 +935,228 @@ const lastMessage = (top) => {
|
|
|
851
935
|
return (result.stdout ?? '').replace(/\s+$/, '');
|
|
852
936
|
};
|
|
853
937
|
|
|
854
|
-
const
|
|
938
|
+
const parseTrack = (text) => {
|
|
939
|
+
const raw = `${text ?? ''}`.trim().replace(/^\[|\]$/g, '');
|
|
940
|
+
if (!raw) return { ahead: 0, behind: 0, gone: false };
|
|
941
|
+
if (raw === 'gone') return { ahead: 0, behind: 0, gone: true };
|
|
942
|
+
const aheadMatch = TRACK_AHEAD.exec(raw);
|
|
943
|
+
const behindMatch = TRACK_BEHIND.exec(raw);
|
|
944
|
+
const ahead = aheadMatch ? Number(aheadMatch[1]) : 0;
|
|
945
|
+
const behind = behindMatch ? Number(behindMatch[1]) : 0;
|
|
946
|
+
return { ahead, behind, gone: false };
|
|
947
|
+
};
|
|
948
|
+
|
|
949
|
+
const parseBranchLine = (line) => {
|
|
950
|
+
const parts = line.split('\t');
|
|
951
|
+
if (parts.length < 2) return null;
|
|
952
|
+
const name = (parts[1] ?? '').trim();
|
|
953
|
+
if (!name) return null;
|
|
954
|
+
const mark = parts[0] ?? '';
|
|
955
|
+
const sha = (parts[2] ?? '').trim();
|
|
956
|
+
const date = (parts[3] ?? '').trim();
|
|
957
|
+
const track = parseTrack(parts[4]);
|
|
958
|
+
const subject = parts.slice(5).join('\t').trim();
|
|
959
|
+
return {
|
|
960
|
+
name,
|
|
961
|
+
current: mark.includes('*'),
|
|
962
|
+
isDefault: false,
|
|
963
|
+
sha,
|
|
964
|
+
date,
|
|
965
|
+
subject,
|
|
966
|
+
...track,
|
|
967
|
+
};
|
|
968
|
+
};
|
|
969
|
+
|
|
970
|
+
const originHead = (top) => {
|
|
971
|
+
const args = ['symbolic-ref', '--short', ORIGIN_HEAD];
|
|
972
|
+
const result = runGit(args, top);
|
|
973
|
+
if (result.status !== 0) return '';
|
|
974
|
+
const ref = result.stdout.trim();
|
|
975
|
+
const prefix = 'origin/';
|
|
976
|
+
if (ref.startsWith(prefix)) return ref.slice(prefix.length);
|
|
977
|
+
return ref;
|
|
978
|
+
};
|
|
979
|
+
|
|
980
|
+
const defaultBranch = (top, names) => {
|
|
981
|
+
const remote = originHead(top);
|
|
982
|
+
if (names.has(remote)) return remote;
|
|
983
|
+
for (const name of DEFAULT_BRANCHES) {
|
|
984
|
+
if (names.has(name)) return name;
|
|
985
|
+
}
|
|
986
|
+
return '';
|
|
987
|
+
};
|
|
988
|
+
|
|
989
|
+
const listBranches = (top) => {
|
|
990
|
+
const args = ['for-each-ref', `--format=${BRANCH_FORMAT}`, 'refs/heads'];
|
|
991
|
+
const result = requireOk(runGit(args, top), 'branch failed');
|
|
992
|
+
const branches = [];
|
|
993
|
+
for (const line of result.stdout.split('\n')) {
|
|
994
|
+
if (!line) continue;
|
|
995
|
+
const entry = parseBranchLine(line);
|
|
996
|
+
if (entry) branches.push(entry);
|
|
997
|
+
}
|
|
998
|
+
const names = new Set();
|
|
999
|
+
for (const entry of branches) names.add(entry.name);
|
|
1000
|
+
const primary = defaultBranch(top, names);
|
|
1001
|
+
for (const entry of branches) {
|
|
1002
|
+
entry.isDefault = entry.name === primary;
|
|
1003
|
+
}
|
|
1004
|
+
return branches;
|
|
1005
|
+
};
|
|
1006
|
+
|
|
1007
|
+
const namedBranch = (name) => {
|
|
1008
|
+
const branch = `${name ?? ''}`.trim();
|
|
1009
|
+
if (!branch) throw new Error('empty branch name');
|
|
1010
|
+
return branch;
|
|
1011
|
+
};
|
|
1012
|
+
|
|
1013
|
+
const checkoutBranch = (top, name) => {
|
|
1014
|
+
const branch = namedBranch(name);
|
|
1015
|
+
requireOk(runGit(['checkout', branch], top), 'checkout failed');
|
|
1016
|
+
};
|
|
1017
|
+
|
|
1018
|
+
const checkoutBranchAsync = async (top, name) => {
|
|
1019
|
+
const branch = namedBranch(name);
|
|
1020
|
+
requireOk(await runGitAsync(['checkout', branch], top), 'checkout failed');
|
|
1021
|
+
};
|
|
1022
|
+
|
|
1023
|
+
const createBranch = (top, name) => {
|
|
1024
|
+
const branch = namedBranch(name);
|
|
1025
|
+
const args = ['checkout', '-b', branch];
|
|
1026
|
+
requireOk(runGit(args, top), 'checkout failed');
|
|
1027
|
+
};
|
|
1028
|
+
|
|
1029
|
+
const createBranchAsync = async (top, name) => {
|
|
1030
|
+
const branch = namedBranch(name);
|
|
1031
|
+
const args = ['checkout', '-b', branch];
|
|
1032
|
+
requireOk(await runGitAsync(args, top), 'checkout failed');
|
|
1033
|
+
};
|
|
1034
|
+
|
|
1035
|
+
const rebaseFailed = (result) => {
|
|
1036
|
+
if (result.status === 0) return '';
|
|
1037
|
+
return result.stderr || result.stdout || 'rebase failed';
|
|
1038
|
+
};
|
|
1039
|
+
|
|
1040
|
+
const rebaseBranch = (top, onto) => {
|
|
1041
|
+
const branch = namedBranch(onto);
|
|
1042
|
+
const result = runGit(['rebase', branch], top);
|
|
1043
|
+
const failed = rebaseFailed(result);
|
|
1044
|
+
if (!failed) return;
|
|
1045
|
+
runGit(['rebase', '--abort'], top);
|
|
1046
|
+
throw new Error(oneLine(failed));
|
|
1047
|
+
};
|
|
1048
|
+
|
|
1049
|
+
const rebaseBranchAsync = async (top, onto) => {
|
|
1050
|
+
const branch = namedBranch(onto);
|
|
1051
|
+
const result = await runGitAsync(['rebase', branch], top);
|
|
1052
|
+
const failed = rebaseFailed(result);
|
|
1053
|
+
if (!failed) return;
|
|
1054
|
+
await runGitAsync(['rebase', '--abort'], top);
|
|
1055
|
+
throw new Error(oneLine(failed));
|
|
1056
|
+
};
|
|
1057
|
+
|
|
1058
|
+
const dropBranch = (top, name) => {
|
|
1059
|
+
const branch = namedBranch(name);
|
|
1060
|
+
requireOk(runGit(['branch', '-D', branch], top), 'drop failed');
|
|
1061
|
+
};
|
|
1062
|
+
|
|
1063
|
+
const dropBranchAsync = async (top, name) => {
|
|
1064
|
+
const branch = namedBranch(name);
|
|
1065
|
+
requireOk(await runGitAsync(['branch', '-D', branch], top), 'drop failed');
|
|
1066
|
+
};
|
|
1067
|
+
|
|
1068
|
+
const pullChanges = (top) => {
|
|
1069
|
+
requireOk(runGit(['pull'], top), 'pull failed');
|
|
1070
|
+
};
|
|
1071
|
+
|
|
1072
|
+
const pullChangesAsync = async (top) => {
|
|
1073
|
+
requireOk(await runGitAsync(['pull'], top), 'pull failed');
|
|
1074
|
+
};
|
|
1075
|
+
|
|
1076
|
+
const isRejectedPush = (msg) => {
|
|
1077
|
+
const text = `${msg ?? ''}`.toLowerCase();
|
|
1078
|
+
for (const token of PUSH_REJECTED) {
|
|
1079
|
+
if (text.includes(token)) return true;
|
|
1080
|
+
}
|
|
1081
|
+
return false;
|
|
1082
|
+
};
|
|
1083
|
+
|
|
1084
|
+
const pushError = (msg) => {
|
|
1085
|
+
const text = `${msg ?? ''}`;
|
|
1086
|
+
const rejected = isRejectedPush(text);
|
|
1087
|
+
const error = new Error(rejected ? 'push rejected' : oneLine(text));
|
|
1088
|
+
error.rejected = rejected;
|
|
1089
|
+
return error;
|
|
1090
|
+
};
|
|
1091
|
+
|
|
1092
|
+
const pushCmd = (force) => {
|
|
1093
|
+
if (force) return ['push', '--force-with-lease'];
|
|
1094
|
+
return ['push'];
|
|
1095
|
+
};
|
|
1096
|
+
|
|
1097
|
+
const pushUpstreamCmd = (force) => {
|
|
1098
|
+
if (force) return ['push', '--force-with-lease', '-u', 'origin', 'HEAD'];
|
|
1099
|
+
return ['push', '-u', 'origin', 'HEAD'];
|
|
1100
|
+
};
|
|
1101
|
+
|
|
1102
|
+
const finishPush = (result, force, run) => {
|
|
1103
|
+
if (result.status === 0) return;
|
|
1104
|
+
const msg = result.stderr || result.stdout || 'push failed';
|
|
1105
|
+
if (!msg.toLowerCase().includes('no upstream')) {
|
|
1106
|
+
throw pushError(msg);
|
|
1107
|
+
}
|
|
1108
|
+
const next = run(pushUpstreamCmd(force));
|
|
1109
|
+
if (next.status !== 0) {
|
|
1110
|
+
throw pushError(next.stderr || next.stdout || 'push failed');
|
|
1111
|
+
}
|
|
1112
|
+
};
|
|
1113
|
+
|
|
1114
|
+
const pushChanges = (top, force) => {
|
|
1115
|
+
const useForce = force === true;
|
|
1116
|
+
const result = runGit(pushCmd(useForce), top);
|
|
1117
|
+
finishPush(result, useForce, (args) => runGit(args, top));
|
|
1118
|
+
};
|
|
1119
|
+
|
|
1120
|
+
const pushChangesAsync = async (top, force) => {
|
|
1121
|
+
const useForce = force === true;
|
|
1122
|
+
const result = await runGitAsync(pushCmd(useForce), top);
|
|
1123
|
+
if (result.status === 0) return;
|
|
1124
|
+
const msg = result.stderr || result.stdout || 'push failed';
|
|
1125
|
+
if (!msg.toLowerCase().includes('no upstream')) {
|
|
1126
|
+
throw pushError(msg);
|
|
1127
|
+
}
|
|
1128
|
+
const next = await runGitAsync(pushUpstreamCmd(useForce), top);
|
|
1129
|
+
if (next.status !== 0) {
|
|
1130
|
+
throw pushError(next.stderr || next.stdout || 'push failed');
|
|
1131
|
+
}
|
|
1132
|
+
};
|
|
1133
|
+
|
|
1134
|
+
const hasStaged = (top) => {
|
|
1135
|
+
const result = runGit(['diff', '--cached', '--quiet'], top);
|
|
1136
|
+
return result.status === 1;
|
|
1137
|
+
};
|
|
1138
|
+
|
|
1139
|
+
const commitPlan = (kind, message) => {
|
|
855
1140
|
if (kind === 'fixup') {
|
|
856
1141
|
const target = (message ?? '').trim() || 'HEAD';
|
|
857
|
-
|
|
858
|
-
requireOk(result);
|
|
859
|
-
return;
|
|
1142
|
+
return { args: ['commit', `--fixup=${target}`], body: undefined };
|
|
860
1143
|
}
|
|
861
1144
|
const args = ['commit'];
|
|
862
1145
|
if (kind === 'amend') args.push('--amend');
|
|
863
1146
|
args.push('-F', '-');
|
|
864
1147
|
const text = message ?? '';
|
|
865
1148
|
const body = text.endsWith('\n') ? text : `${text}\n`;
|
|
866
|
-
|
|
867
|
-
|
|
1149
|
+
return { args, body };
|
|
1150
|
+
};
|
|
1151
|
+
|
|
1152
|
+
const commitChanges = (top, kind, message) => {
|
|
1153
|
+
const plan = commitPlan(kind, message);
|
|
1154
|
+
requireOk(runGit(plan.args, top, plan.body));
|
|
1155
|
+
};
|
|
1156
|
+
|
|
1157
|
+
const commitChangesAsync = async (top, kind, message) => {
|
|
1158
|
+
const plan = commitPlan(kind, message);
|
|
1159
|
+
requireOk(await runGitAsync(plan.args, top, { input: plan.body }));
|
|
868
1160
|
};
|
|
869
1161
|
|
|
870
1162
|
const revertFile = (top, rel, items) => {
|
|
@@ -886,11 +1178,28 @@ const createGitRepo = () => ({
|
|
|
886
1178
|
toplevel,
|
|
887
1179
|
resolveRev,
|
|
888
1180
|
add: addItem,
|
|
1181
|
+
addAsync: addItemAsync,
|
|
889
1182
|
unstage: unstageItem,
|
|
890
1183
|
revert: revertItem,
|
|
891
1184
|
revertFile,
|
|
892
1185
|
commit: commitChanges,
|
|
1186
|
+
commitAsync: commitChangesAsync,
|
|
1187
|
+
hasStaged,
|
|
893
1188
|
lastMessage,
|
|
1189
|
+
listBranches,
|
|
1190
|
+
currentBranch,
|
|
1191
|
+
checkout: checkoutBranch,
|
|
1192
|
+
checkoutAsync: checkoutBranchAsync,
|
|
1193
|
+
createBranch,
|
|
1194
|
+
createBranchAsync,
|
|
1195
|
+
rebase: rebaseBranch,
|
|
1196
|
+
rebaseAsync: rebaseBranchAsync,
|
|
1197
|
+
drop: dropBranch,
|
|
1198
|
+
dropAsync: dropBranchAsync,
|
|
1199
|
+
pull: pullChanges,
|
|
1200
|
+
pullAsync: pullChangesAsync,
|
|
1201
|
+
push: pushChanges,
|
|
1202
|
+
pushAsync: pushChangesAsync,
|
|
894
1203
|
});
|
|
895
1204
|
|
|
896
1205
|
module.exports = {
|
|
@@ -901,6 +1210,22 @@ module.exports = {
|
|
|
901
1210
|
unstageItem,
|
|
902
1211
|
revertItem,
|
|
903
1212
|
commitChanges,
|
|
1213
|
+
commitChangesAsync,
|
|
1214
|
+
hasStaged,
|
|
1215
|
+
currentBranch,
|
|
904
1216
|
lastMessage,
|
|
1217
|
+
listBranches,
|
|
1218
|
+
checkoutBranch,
|
|
1219
|
+
checkoutBranchAsync,
|
|
1220
|
+
createBranch,
|
|
1221
|
+
createBranchAsync,
|
|
1222
|
+
rebaseBranch,
|
|
1223
|
+
rebaseBranchAsync,
|
|
1224
|
+
dropBranch,
|
|
1225
|
+
dropBranchAsync,
|
|
1226
|
+
pullChanges,
|
|
1227
|
+
pullChangesAsync,
|
|
1228
|
+
pushChanges,
|
|
1229
|
+
pushChangesAsync,
|
|
905
1230
|
createGitRepo,
|
|
906
1231
|
};
|