git-stack-cli 2.7.4 → 2.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -8
- package/dist/js/index.js +207 -45928
- package/package.json +2 -2
- package/scripts/bun-build.ts +21 -26
- package/scripts/bun-compile.ts +15 -2
- package/scripts/core/get_define.ts +21 -0
- package/scripts/npm-prepublishOnly.ts +1 -1
- package/src/app/App.tsx +2 -0
- package/src/app/Exit.tsx +9 -0
- package/src/app/GithubApiError.tsx +12 -4
- package/src/app/HandleCtrlCSigint.tsx +10 -1
- package/src/app/Store.tsx +6 -2
- package/src/app/SyncGithub.tsx +1 -1
- package/src/command.ts +8 -1
- package/src/commands/Config.tsx +1 -1
- package/src/commands/Rebase.tsx +1 -1
- package/src/components/ErrorBoundary.tsx +1 -1
- package/src/core/GitReviseTodo.ts +1 -1
- package/src/core/cache.ts +9 -11
- package/src/core/git.ts +14 -0
- package/src/index.tsx +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "git-stack-cli",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.6",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "magus",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"tsconfig.json"
|
|
23
23
|
],
|
|
24
24
|
"scripts": {
|
|
25
|
-
"dev": "pnpm run build --watch",
|
|
25
|
+
"dev": "pnpm run build --dev --watch",
|
|
26
26
|
"build": "bun run scripts/bun-build.ts",
|
|
27
27
|
"compile": "bun run scripts/bun-compile.ts",
|
|
28
28
|
"release:npm": "bun run scripts/release-npm.ts",
|
package/scripts/bun-build.ts
CHANGED
|
@@ -2,7 +2,10 @@ import * as fs from "node:fs/promises";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import * as util from "util";
|
|
4
4
|
|
|
5
|
+
import type { BuildConfig } from "bun";
|
|
6
|
+
|
|
5
7
|
import * as file from "~/core/file";
|
|
8
|
+
import { get_define } from "~/core/get_define";
|
|
6
9
|
import { get_local_iso } from "~/core/get_local_iso";
|
|
7
10
|
import { spawn } from "~/core/spawn";
|
|
8
11
|
|
|
@@ -13,6 +16,10 @@ const parsed_args = util.parseArgs({
|
|
|
13
16
|
type: "boolean",
|
|
14
17
|
default: false,
|
|
15
18
|
},
|
|
19
|
+
dev: {
|
|
20
|
+
type: "boolean",
|
|
21
|
+
default: false,
|
|
22
|
+
},
|
|
16
23
|
verbose: {
|
|
17
24
|
type: "boolean",
|
|
18
25
|
default: false,
|
|
@@ -24,6 +31,7 @@ const parsed_args = util.parseArgs({
|
|
|
24
31
|
|
|
25
32
|
const WATCH = parsed_args.values.watch;
|
|
26
33
|
const VERBOSE = parsed_args.values.verbose;
|
|
34
|
+
const DEV = parsed_args.values.dev;
|
|
27
35
|
|
|
28
36
|
function log(...args: any[]) {
|
|
29
37
|
const timestamp = get_local_iso(new Date());
|
|
@@ -38,38 +46,25 @@ if (VERBOSE) {
|
|
|
38
46
|
|
|
39
47
|
const REPO_ROOT = (await spawn.sync("git rev-parse --show-toplevel")).stdout;
|
|
40
48
|
|
|
41
|
-
|
|
42
|
-
const PACKAGE_JSON = await file.read_json(path.join(REPO_ROOT, "package.json"));
|
|
43
|
-
const GIT_SEQUENCE_EDITOR_SCRIPT_PATH = path.join(REPO_ROOT, "scripts", "git-sequence-editor.sh");
|
|
44
|
-
const UNSAFE_GIT_SEQUENCE_EDITOR_SCRIPT = await file.read_text(GIT_SEQUENCE_EDITOR_SCRIPT_PATH);
|
|
45
|
-
const GIT_SEQUENCE_EDITOR_SCRIPT = UNSAFE_GIT_SEQUENCE_EDITOR_SCRIPT.replace(/`/g, "\\`");
|
|
49
|
+
const define = await get_define();
|
|
46
50
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
const BUILD_CONFIG = {
|
|
52
|
+
entrypoints: ["./src/index.tsx"],
|
|
53
|
+
outdir: "./dist/js",
|
|
54
|
+
target: "node",
|
|
55
|
+
env: "inline",
|
|
56
|
+
format: "esm",
|
|
57
|
+
sourcemap: "inline",
|
|
58
|
+
define,
|
|
59
|
+
minify: !DEV,
|
|
60
|
+
} satisfies BuildConfig;
|
|
52
61
|
|
|
53
|
-
|
|
54
|
-
}
|
|
62
|
+
log({ BUILD_CONFIG });
|
|
55
63
|
|
|
56
64
|
async function run_build() {
|
|
57
65
|
const start = Date.now();
|
|
58
66
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
if (VERBOSE) {
|
|
62
|
-
log({ define });
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const result = await Bun.build({
|
|
66
|
-
entrypoints: ["./src/index.tsx"],
|
|
67
|
-
outdir: "./dist/js",
|
|
68
|
-
target: "node",
|
|
69
|
-
env: "inline",
|
|
70
|
-
format: "esm",
|
|
71
|
-
define,
|
|
72
|
-
});
|
|
67
|
+
const result = await Bun.build(BUILD_CONFIG);
|
|
73
68
|
|
|
74
69
|
const duration_ms = Date.now() - start;
|
|
75
70
|
|
package/scripts/bun-compile.ts
CHANGED
|
@@ -2,6 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
import * as util from "util";
|
|
3
3
|
|
|
4
4
|
import * as file from "~/core/file";
|
|
5
|
+
import { get_define } from "~/core/get_define";
|
|
5
6
|
import { spawn } from "~/core/spawn";
|
|
6
7
|
|
|
7
8
|
const parsed_args = util.parseArgs({
|
|
@@ -30,12 +31,12 @@ if (VERBOSE) {
|
|
|
30
31
|
|
|
31
32
|
const REPO_ROOT = (await spawn.sync("git rev-parse --show-toplevel")).stdout;
|
|
32
33
|
const DIST_DIR = path.join(REPO_ROOT, "dist");
|
|
33
|
-
const INPUT_JS = path.join(
|
|
34
|
+
const INPUT_JS = path.join(REPO_ROOT, "/src/index.tsx");
|
|
34
35
|
|
|
35
36
|
if (!(await file.exists(INPUT_JS))) {
|
|
36
37
|
console.error(`❌ Missing ${path.relative(REPO_ROOT, INPUT_JS)}`);
|
|
37
38
|
console.debug("Run `pnpm run build` first to generate the input file.");
|
|
38
|
-
process.exit(
|
|
39
|
+
process.exit(6);
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
if (TARGET) {
|
|
@@ -58,11 +59,23 @@ async function compile_target(args: CompileTargetArgs) {
|
|
|
58
59
|
|
|
59
60
|
const start = Date.now();
|
|
60
61
|
|
|
62
|
+
// https://bun.com/docs/bundler/executables#build-time-constants
|
|
63
|
+
const defines: Array<string> = [];
|
|
64
|
+
for (const [key, value] of Object.entries(await get_define())) {
|
|
65
|
+
// --define BUILD_VERSION='"1.2.3"'
|
|
66
|
+
defines.push("--define", `${key}=${value}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
61
69
|
// pnpm bun build --compile --target=bun-darwin-arm64 ./dist/js/index.js --outfile git-stack-bun-darwin-arm64
|
|
70
|
+
// https://bun.com/docs/bundler/executables
|
|
62
71
|
const bun_compile = await spawn.sync([
|
|
63
72
|
"bun",
|
|
64
73
|
"build",
|
|
65
74
|
"--compile",
|
|
75
|
+
"--minify",
|
|
76
|
+
"--sourcemap",
|
|
77
|
+
// "--bytecode",
|
|
78
|
+
...defines,
|
|
66
79
|
`--target=${args.target}`,
|
|
67
80
|
INPUT_JS,
|
|
68
81
|
`--outfile=${outfile}`,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
import * as file from "~/core/file";
|
|
4
|
+
import { spawn } from "~/core/spawn";
|
|
5
|
+
|
|
6
|
+
const REPO_ROOT = (await spawn.sync("git rev-parse --show-toplevel")).stdout;
|
|
7
|
+
|
|
8
|
+
export async function get_define() {
|
|
9
|
+
const PACKAGE_JSON = await file.read_json(path.join(REPO_ROOT, "package.json"));
|
|
10
|
+
const GIT_SEQUENCE_EDITOR_SCRIPT_PATH = path.join(REPO_ROOT, "scripts", "git-sequence-editor.sh");
|
|
11
|
+
const UNSAFE_GIT_SEQUENCE_EDITOR_SCRIPT = await file.read_text(GIT_SEQUENCE_EDITOR_SCRIPT_PATH);
|
|
12
|
+
const GIT_SEQUENCE_EDITOR_SCRIPT = UNSAFE_GIT_SEQUENCE_EDITOR_SCRIPT.replace(/`/g, "\\`");
|
|
13
|
+
|
|
14
|
+
const define = {
|
|
15
|
+
"process.env.NODE_ENV": JSON.stringify("production"),
|
|
16
|
+
"process.env.CLI_VERSION": JSON.stringify(String(PACKAGE_JSON.version)),
|
|
17
|
+
"process.env.GIT_SEQUENCE_EDITOR_SCRIPT": JSON.stringify(GIT_SEQUENCE_EDITOR_SCRIPT),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
return define;
|
|
21
|
+
}
|
package/src/app/App.tsx
CHANGED
|
@@ -95,6 +95,8 @@ function MaybeMain() {
|
|
|
95
95
|
return <Update />;
|
|
96
96
|
} else if (positional_list.has("config")) {
|
|
97
97
|
return <Config />;
|
|
98
|
+
} else if (positional_list.has("api")) {
|
|
99
|
+
return <GithubApiError exit />;
|
|
98
100
|
} else if (positional_list.has("rebase")) {
|
|
99
101
|
return (
|
|
100
102
|
<DependencyCheck>
|
package/src/app/Exit.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
|
|
3
3
|
import * as Ink from "ink-cjs";
|
|
4
4
|
|
|
5
|
+
import { FormatText } from "~/app/FormatText";
|
|
5
6
|
import { Store } from "~/app/Store";
|
|
6
7
|
import { cli } from "~/core/cli";
|
|
7
8
|
import { colors } from "~/core/colors";
|
|
@@ -37,6 +38,14 @@ Exit.handle_exit = async function handle_exit(props: Props) {
|
|
|
37
38
|
exit_code = await state.abort_handler();
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
if (!state.argv.verbose && props.code > 0) {
|
|
42
|
+
actions.output(
|
|
43
|
+
<Ink.Text color={colors.gray}>
|
|
44
|
+
<FormatText message="Try again with `--verbose` to see more information." />
|
|
45
|
+
</Ink.Text>,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
40
49
|
// restore git stash if necessary
|
|
41
50
|
if (state.is_dirty_check_stash) {
|
|
42
51
|
await cli("git stash pop");
|
|
@@ -10,11 +10,15 @@ import { cli } from "~/core/cli";
|
|
|
10
10
|
import { colors } from "~/core/colors";
|
|
11
11
|
import * as date from "~/core/date";
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
type Props = {
|
|
14
|
+
exit?: boolean;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function GithubApiError(props: Props) {
|
|
18
|
+
return <Await fallback={null} function={() => run(props)} />;
|
|
15
19
|
}
|
|
16
20
|
|
|
17
|
-
async function run() {
|
|
21
|
+
async function run(props: Props) {
|
|
18
22
|
const actions = Store.getState().actions;
|
|
19
23
|
|
|
20
24
|
const res = await cli(`gh api https://api.github.com/rate_limit`);
|
|
@@ -42,7 +46,7 @@ async function run() {
|
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
actions.output(
|
|
45
|
-
<Ink.Text
|
|
49
|
+
<Ink.Text>
|
|
46
50
|
<Ink.Text>{"Github "}</Ink.Text>
|
|
47
51
|
|
|
48
52
|
<Brackets>graphql</Brackets>
|
|
@@ -71,4 +75,8 @@ async function run() {
|
|
|
71
75
|
</Parens>
|
|
72
76
|
</Ink.Text>,
|
|
73
77
|
);
|
|
78
|
+
|
|
79
|
+
if (props.exit) {
|
|
80
|
+
actions.exit(0);
|
|
81
|
+
}
|
|
74
82
|
}
|
|
@@ -12,6 +12,8 @@ export function HandleCtrlCSigint() {
|
|
|
12
12
|
|
|
13
13
|
Ink.useInput((input, key) => {
|
|
14
14
|
handle_input().catch((err) => {
|
|
15
|
+
// eslint-disable-next-line no-console
|
|
16
|
+
console.error("🚨 HandleCtrlCSigint catch");
|
|
15
17
|
// eslint-disable-next-line no-console
|
|
16
18
|
console.error(err);
|
|
17
19
|
});
|
|
@@ -27,10 +29,17 @@ export function HandleCtrlCSigint() {
|
|
|
27
29
|
);
|
|
28
30
|
|
|
29
31
|
await sleep(1);
|
|
30
|
-
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
actions.exit(HandleCtrlCSigint.ExitCode);
|
|
35
|
+
} catch {
|
|
36
|
+
// ignore intentional throw from actions.exit
|
|
37
|
+
}
|
|
31
38
|
}
|
|
32
39
|
}
|
|
33
40
|
});
|
|
34
41
|
|
|
35
42
|
return null;
|
|
36
43
|
}
|
|
44
|
+
|
|
45
|
+
HandleCtrlCSigint.ExitCode = 235;
|
package/src/app/Store.tsx
CHANGED
|
@@ -141,6 +141,8 @@ const BaseStore = createStore<State>()(
|
|
|
141
141
|
|
|
142
142
|
actions: {
|
|
143
143
|
exit(code, args) {
|
|
144
|
+
const clear = args?.clear ?? true;
|
|
145
|
+
|
|
144
146
|
set((state) => {
|
|
145
147
|
if (args?.quiet ?? code === 0) {
|
|
146
148
|
state.exit_mode = "quiet";
|
|
@@ -148,11 +150,13 @@ const BaseStore = createStore<State>()(
|
|
|
148
150
|
state.exit_mode = "normal";
|
|
149
151
|
}
|
|
150
152
|
|
|
151
|
-
let clear = args?.clear ?? true;
|
|
152
|
-
|
|
153
153
|
const node = <Exit clear={clear} code={code} />;
|
|
154
154
|
state.mutate.output(state, { node });
|
|
155
155
|
});
|
|
156
|
+
|
|
157
|
+
if (code > 0) {
|
|
158
|
+
throw new Error(`exit(${JSON.stringify({ code, clear })})`);
|
|
159
|
+
}
|
|
156
160
|
},
|
|
157
161
|
|
|
158
162
|
clear() {
|
package/src/app/SyncGithub.tsx
CHANGED
package/src/command.ts
CHANGED
|
@@ -60,7 +60,14 @@ export async function command(argv: string[], options: CommandOptions = {}) {
|
|
|
60
60
|
.command(
|
|
61
61
|
"config",
|
|
62
62
|
"Generate a one-time configuration json based on the passed arguments",
|
|
63
|
-
(yargs) => yargs
|
|
63
|
+
(yargs) => yargs,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
.command(
|
|
67
|
+
//
|
|
68
|
+
"api",
|
|
69
|
+
"Check Github API quota and rate limits",
|
|
70
|
+
(yargs) => yargs,
|
|
64
71
|
)
|
|
65
72
|
|
|
66
73
|
.option("verbose", GlobalOptions.verbose)
|
package/src/commands/Config.tsx
CHANGED
|
@@ -69,7 +69,7 @@ function parse_env_config() {
|
|
|
69
69
|
console.error(`ERROR GIT_STACK_CONFIG=${GIT_STACK_CONFIG}`);
|
|
70
70
|
// eslint-disable-next-line no-console
|
|
71
71
|
console.error("ERROR GIT_STACK_CONFIG environment variable is not valid JSON");
|
|
72
|
-
process.exit(
|
|
72
|
+
process.exit(6);
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
package/src/commands/Rebase.tsx
CHANGED
|
@@ -38,7 +38,7 @@ export class ErrorBoundary extends React.Component<Props, State> {
|
|
|
38
38
|
// remove first line of component_stack
|
|
39
39
|
component_stack = component_stack.split("\n").slice(1).join("\n");
|
|
40
40
|
this.setState({ component_stack }, async () => {
|
|
41
|
-
await Exit.handle_exit({ code:
|
|
41
|
+
await Exit.handle_exit({ code: 5, clear: false });
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
}
|
|
@@ -154,7 +154,7 @@ GitReviseTodo.execute = async function grt_execute(args: ExecuteArgs) {
|
|
|
154
154
|
actions.error("🚨 git revise failed to sign commit");
|
|
155
155
|
actions.error("💡 Try again with `--no-revise-sign`?");
|
|
156
156
|
actions.error("\n\n");
|
|
157
|
-
actions.exit(
|
|
157
|
+
actions.exit(18);
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
}
|
package/src/core/cache.ts
CHANGED
|
@@ -22,17 +22,15 @@ export function cache<T, E>(cacheable: Cacheable<T>) {
|
|
|
22
22
|
// cacheable is a function to allow deferred reads
|
|
23
23
|
// this will call cacheable to kickoff async promise
|
|
24
24
|
if (!suspender) {
|
|
25
|
-
suspender =
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
});
|
|
35
|
-
});
|
|
25
|
+
suspender = cacheable()
|
|
26
|
+
.then((res: T) => {
|
|
27
|
+
status = "success";
|
|
28
|
+
response = res;
|
|
29
|
+
})
|
|
30
|
+
.catch((err: E) => {
|
|
31
|
+
status = "error";
|
|
32
|
+
response = err;
|
|
33
|
+
});
|
|
36
34
|
}
|
|
37
35
|
|
|
38
36
|
switch (status) {
|
package/src/core/git.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Store } from "~/app/Store";
|
|
1
2
|
import * as Metadata from "~/core/Metadata";
|
|
2
3
|
import { cli } from "~/core/cli";
|
|
3
4
|
|
|
@@ -20,6 +21,15 @@ export async function get_commits(dot_range: string) {
|
|
|
20
21
|
|
|
21
22
|
const [sha, full_message] = record.split(SEP.field);
|
|
22
23
|
|
|
24
|
+
// ensure sha is a hex string, otherwise we should throw an error
|
|
25
|
+
if (!RE.git_sha.test(sha)) {
|
|
26
|
+
const actions = Store.getState().actions;
|
|
27
|
+
const sep_values = JSON.stringify(Object.values(SEP));
|
|
28
|
+
const message = `unable to parse git commits, maybe commit message contained ${sep_values}`;
|
|
29
|
+
actions.error(message);
|
|
30
|
+
actions.exit(19);
|
|
31
|
+
}
|
|
32
|
+
|
|
23
33
|
const metadata = Metadata.read(full_message);
|
|
24
34
|
const branch_id = metadata.id;
|
|
25
35
|
const subject_line = metadata.subject || "";
|
|
@@ -53,3 +63,7 @@ const SEP = {
|
|
|
53
63
|
};
|
|
54
64
|
|
|
55
65
|
const FORMAT = `%H${SEP.field}%B${SEP.record}`;
|
|
66
|
+
|
|
67
|
+
const RE = {
|
|
68
|
+
git_sha: /^[0-9a-fA-F]{40}$/,
|
|
69
|
+
};
|
package/src/index.tsx
CHANGED
|
@@ -74,9 +74,11 @@ import { pretty_json } from "~/core/pretty_json";
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
} catch (err) {
|
|
77
|
+
console.error("🚨 main catch");
|
|
77
78
|
console.error(err);
|
|
78
79
|
process.exit(236);
|
|
79
80
|
}
|
|
80
81
|
})().catch((err) => {
|
|
82
|
+
console.error("🚨 index catch");
|
|
81
83
|
console.error(err);
|
|
82
84
|
});
|