git-stack-cli 1.15.0 → 2.0.0-beta

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.
Files changed (59) hide show
  1. package/README.md +15 -14
  2. package/dist/js/index.js +45709 -0
  3. package/package.json +17 -23
  4. package/scripts/bun-build.ts +109 -0
  5. package/scripts/bun-compile.ts +79 -0
  6. package/scripts/npm-prepublishOnly.ts +1 -1
  7. package/scripts/release-brew.ts +26 -48
  8. package/scripts/release-github.ts +21 -9
  9. package/scripts/release-npm.ts +8 -11
  10. package/src/app/App.tsx +39 -31
  11. package/src/app/AutoUpdate.tsx +9 -24
  12. package/src/app/CherryPickCheck.tsx +1 -2
  13. package/src/app/Debug.tsx +3 -5
  14. package/src/app/DependencyCheck.tsx +6 -6
  15. package/src/app/DetectInitialPR.tsx +2 -8
  16. package/src/app/DirtyCheck.tsx +15 -1
  17. package/src/app/Exit.tsx +1 -5
  18. package/src/app/FormatText.tsx +1 -5
  19. package/src/app/GatherMetadata.tsx +6 -13
  20. package/src/app/GithubApiError.tsx +1 -1
  21. package/src/app/HandleCtrlCSigint.tsx +1 -12
  22. package/src/app/LocalCommitStatus.tsx +1 -3
  23. package/src/app/LogTimestamp.tsx +1 -5
  24. package/src/app/ManualRebase.tsx +4 -8
  25. package/src/app/MultiSelect.tsx +2 -2
  26. package/src/app/PostRebaseStatus.tsx +2 -0
  27. package/src/app/PreManualRebase.tsx +3 -5
  28. package/src/app/RebaseCheck.tsx +1 -2
  29. package/src/app/SelectCommitRanges.tsx +6 -10
  30. package/src/app/Status.tsx +1 -1
  31. package/src/app/StatusTable.tsx +1 -4
  32. package/src/app/Store.tsx +5 -1
  33. package/src/app/SyncGithub.tsx +4 -16
  34. package/src/app/Table.tsx +4 -14
  35. package/src/app/TextInput.tsx +2 -7
  36. package/src/app/VerboseDebugInfo.tsx +1 -5
  37. package/src/app/YesNoPrompt.tsx +42 -31
  38. package/src/command.ts +8 -17
  39. package/src/commands/Fixup.tsx +15 -22
  40. package/src/commands/Log.tsx +3 -7
  41. package/src/commands/Rebase.tsx +6 -8
  42. package/src/components/ErrorBoundary.tsx +79 -0
  43. package/src/components/ExitingGate.tsx +27 -0
  44. package/src/core/CommitMetadata.ts +1 -1
  45. package/src/core/GitReviseTodo.test.ts +3 -3
  46. package/src/core/GitReviseTodo.ts +8 -12
  47. package/src/core/Metadata.test.ts +4 -4
  48. package/src/core/StackSummaryTable.ts +3 -3
  49. package/src/core/chalk.ts +1 -5
  50. package/src/core/cli.ts +2 -2
  51. package/src/core/github.tsx +7 -13
  52. package/src/core/pretty_json.ts +1 -6
  53. package/src/github/gh.auth_status.test.ts +2 -6
  54. package/src/index.tsx +28 -3
  55. package/src/types/global.d.ts +0 -1
  56. package/tsconfig.json +1 -1
  57. package/dist/cjs/index.cjs +0 -38461
  58. package/rollup.config.js +0 -54
  59. package/scripts/build-standalone.ts +0 -73
package/package.json CHANGED
@@ -1,41 +1,42 @@
1
1
  {
2
2
  "name": "git-stack-cli",
3
- "version": "1.15.0",
3
+ "version": "2.0.0-beta",
4
4
  "description": "",
5
5
  "author": "magus",
6
6
  "license": "MIT",
7
+ "packageManager": "pnpm@9.15.4+sha512.b2dc20e2fc72b3e18848459b37359a32064663e5627a51e4c74b2c29dd8e8e0491483c3abb40789cfd578bf362fb6ba8261b05f0387d76792ed6e23ea3b1b6a0",
7
8
  "repository": {
8
9
  "type": "git",
9
10
  "url": "git+https://github.com/magus/git-stack-cli.git"
10
11
  },
11
12
  "type": "module",
12
13
  "bin": {
13
- "git-stack": "dist/cjs/index.cjs"
14
+ "git-stack": "dist/js/index.js"
14
15
  },
15
16
  "files": [
16
- "dist/cjs",
17
+ "dist/js",
18
+ "package.json",
19
+ "pnpm-lock.yaml",
17
20
  "scripts",
18
21
  "src",
19
- "package-lock.json",
20
- "rollup.config.js",
21
22
  "tsconfig.json"
22
23
  ],
23
24
  "scripts": {
24
- "dev": "npm run build -- --watch",
25
- "build": "rollup -c rollup.config.js",
26
- "build:standalone": "GIT_STACK_STANDALONE=true bun run scripts/build-standalone.ts",
25
+ "dev": "pnpm run build --watch",
26
+ "build": "bun run scripts/bun-build.ts",
27
+ "compile": "bun run scripts/bun-compile.ts",
27
28
  "release:npm": "bun run scripts/release-npm.ts",
28
29
  "release:github": "bun run scripts/release-github.ts",
29
30
  "release:brew": "bun run scripts/release-brew.ts",
30
- "release": "npm run release:npm && npm run release:github && npm run release:brew",
31
+ "release": "pnpm run release:npm && pnpm run release:github && pnpm run release:brew",
31
32
  "lint:check": "eslint . --cache",
32
- "lint": "npm run lint:check -- --fix",
33
- "prettier:check": "prettier ./src --check --cache",
34
- "prettier": "npm run prettier:check -- --write",
33
+ "lint": "pnpm run lint:check --fix",
34
+ "prettier:check": "prettier src scripts config .eslintrc.cjs --check --cache",
35
+ "prettier": "pnpm run prettier:check --write",
35
36
  "test": "bun test",
36
- "test:watch": "npm run test -- --watch",
37
+ "test:watch": "pnpm run test --watch",
37
38
  "test:types": "tsc",
38
- "test:all": "npm run prettier:check && npm run lint:check && npm run test:types",
39
+ "test:all": "pnpm run prettier:check && pnpm run lint:check && pnpm run test:types",
39
40
  "prepublishOnly": "bun run scripts/npm-prepublishOnly.ts"
40
41
  },
41
42
  "dependencies": {
@@ -51,12 +52,6 @@
51
52
  "zustand": "^4.4.4"
52
53
  },
53
54
  "devDependencies": {
54
- "@rollup/plugin-alias": "^5.1.0",
55
- "@rollup/plugin-commonjs": "^25.0.7",
56
- "@rollup/plugin-json": "^6.1.0",
57
- "@rollup/plugin-node-resolve": "^15.2.3",
58
- "@rollup/plugin-replace": "^5.0.5",
59
- "@rollup/plugin-typescript": "^11.1.6",
60
55
  "@types/chalk": "^2.2.0",
61
56
  "@types/lodash": "^4.17.7",
62
57
  "@types/luxon": "^3.4.2",
@@ -65,14 +60,13 @@
65
60
  "@types/yargs": "^17.0.29",
66
61
  "@typescript-eslint/eslint-plugin": "^6.9.0",
67
62
  "@typescript-eslint/parser": "^6.9.0",
68
- "bun-types": "^1.0.21",
63
+ "bun": "1.1.44",
64
+ "bun-types": "1.1.44",
69
65
  "eslint": "^8.52.0",
70
66
  "eslint-import-resolver-typescript": "^3.6.1",
71
67
  "eslint-plugin-import": "^2.29.0",
72
68
  "eslint-plugin-react": "^7.33.2",
73
- "pkg": "^5.8.1",
74
69
  "prettier": "^3.0.3",
75
- "rollup": "^4.10.0",
76
70
  "typescript": "^5.2.2"
77
71
  }
78
72
  }
@@ -0,0 +1,109 @@
1
+ import * as fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import * as util from "util";
4
+
5
+ import * as file from "~/core/file";
6
+ import { spawn } from "~/core/spawn";
7
+
8
+ const parsed_args = util.parseArgs({
9
+ args: Bun.argv,
10
+ options: {
11
+ watch: {
12
+ type: "boolean",
13
+ default: false,
14
+ },
15
+ verbose: {
16
+ type: "boolean",
17
+ default: false,
18
+ },
19
+ },
20
+ strict: true,
21
+ allowPositionals: true,
22
+ });
23
+
24
+ const WATCH = parsed_args.values.watch;
25
+ const VERBOSE = parsed_args.values.verbose;
26
+
27
+ console.debug("📦 bundle", WATCH ? "watch" : "build");
28
+
29
+ if (VERBOSE) {
30
+ console.debug(parsed_args);
31
+ }
32
+
33
+ const REPO_ROOT = (await spawn.sync("git rev-parse --show-toplevel")).stdout;
34
+
35
+ const PACKAGE_JSON = await file.read_json(path.join(REPO_ROOT, "package.json"));
36
+ const GIT_SEQUENCE_EDITOR_SCRIPT_PATH = path.join(REPO_ROOT, "scripts", "git-sequence-editor.sh");
37
+ const UNSAFE_GIT_SEQUENCE_EDITOR_SCRIPT = await file.read_text(GIT_SEQUENCE_EDITOR_SCRIPT_PATH);
38
+ const GIT_SEQUENCE_EDITOR_SCRIPT = UNSAFE_GIT_SEQUENCE_EDITOR_SCRIPT.replace(/`/g, "\\`");
39
+
40
+ let GITIGNORE = (await file.read_text(path.join(REPO_ROOT, ".gitignore"))).split("\n");
41
+ GITIGNORE = GITIGNORE.filter((line) => line.trim() && !line.startsWith("#"));
42
+ GITIGNORE.push(".git");
43
+
44
+ const define = {
45
+ "process.env.NODE_ENV": JSON.stringify("production"),
46
+ "process.env.CLI_VERSION": JSON.stringify(String(PACKAGE_JSON.version)),
47
+ "process.env.GIT_SEQUENCE_EDITOR_SCRIPT": JSON.stringify(GIT_SEQUENCE_EDITOR_SCRIPT),
48
+ };
49
+
50
+ if (VERBOSE) {
51
+ console.debug({ define });
52
+ }
53
+
54
+ async function run_build() {
55
+ const start = Date.now();
56
+
57
+ const result = await Bun.build({
58
+ entrypoints: ["./src/index.tsx"],
59
+ outdir: "./dist/js",
60
+ target: "node",
61
+ env: "inline",
62
+ format: "esm",
63
+ define,
64
+ });
65
+
66
+ const duration_ms = Date.now() - start;
67
+
68
+ console.debug(`✅ Build (${duration_ms}ms)`);
69
+
70
+ if (VERBOSE) {
71
+ console.debug({ result });
72
+ }
73
+ }
74
+
75
+ if (!WATCH) {
76
+ await run_build();
77
+ } else {
78
+ console.debug("👀 Watching for changes…");
79
+
80
+ const { signal } = new AbortController();
81
+
82
+ const watcher = fs.watch(REPO_ROOT, { recursive: true, signal });
83
+ for await (const event of watcher) {
84
+ const filename = event.filename;
85
+
86
+ if (!filename) {
87
+ continue;
88
+ }
89
+
90
+ // ignore this file
91
+ if (import.meta.filename == path.join(REPO_ROOT, filename)) {
92
+ continue;
93
+ }
94
+
95
+ // ignore files in gitignore
96
+ const ignored = GITIGNORE.some((pattern) => filename.startsWith(pattern));
97
+ if (ignored) {
98
+ continue;
99
+ }
100
+
101
+ console.debug(`⚠️ Change ${filename}`);
102
+
103
+ if (VERBOSE) {
104
+ console.debug({ ignored, filename, event });
105
+ }
106
+
107
+ await run_build();
108
+ }
109
+ }
@@ -0,0 +1,79 @@
1
+ import path from "node:path";
2
+ import * as util from "util";
3
+
4
+ import * as file from "~/core/file";
5
+ import { spawn } from "~/core/spawn";
6
+
7
+ const parsed_args = util.parseArgs({
8
+ args: Bun.argv,
9
+ options: {
10
+ target: {
11
+ type: "string",
12
+ },
13
+ verbose: {
14
+ type: "boolean",
15
+ default: false,
16
+ },
17
+ },
18
+ strict: true,
19
+ allowPositionals: true,
20
+ });
21
+
22
+ const TARGET = parsed_args.values.target;
23
+ const VERBOSE = parsed_args.values.verbose;
24
+
25
+ console.debug("📦 compile");
26
+
27
+ if (VERBOSE) {
28
+ console.debug(parsed_args);
29
+ }
30
+
31
+ const REPO_ROOT = (await spawn.sync("git rev-parse --show-toplevel")).stdout;
32
+ const DIST_DIR = path.join(REPO_ROOT, "dist");
33
+ const INPUT_JS = path.join(DIST_DIR, "js", "index.js");
34
+
35
+ if (!(await file.exists(INPUT_JS))) {
36
+ console.error(`❌ Missing ${path.relative(REPO_ROOT, INPUT_JS)}`);
37
+ console.debug("Run `pnpm run build` first to generate the input file.");
38
+ process.exit(12);
39
+ }
40
+
41
+ if (TARGET) {
42
+ const target = TARGET;
43
+ await compile_target({ target });
44
+ process.exit(0);
45
+ }
46
+
47
+ const TARGET_LIST = ["bun-linux-x64", "bun-windows-x64", "bun-darwin-arm64", "bun-darwin-x64"];
48
+
49
+ for (const target of TARGET_LIST) {
50
+ await compile_target({ target });
51
+ }
52
+
53
+ type CompileTargetArgs = {
54
+ target: string;
55
+ };
56
+ async function compile_target(args: CompileTargetArgs) {
57
+ const outfile = path.join(DIST_DIR, "bin", `git-stack-${args.target}`);
58
+
59
+ const start = Date.now();
60
+
61
+ // bun build --compile --target=bun-darwin-x64 ./path/to/my/app.ts --outfile myapp
62
+ const bun_compile = await spawn.sync([
63
+ "bun",
64
+ "build",
65
+ "--compile",
66
+ `--target=${args.target}`,
67
+ INPUT_JS,
68
+ `--outfile=${outfile}`,
69
+ ]);
70
+
71
+ if (bun_compile.proc.exitCode) {
72
+ console.error(bun_compile.stderr);
73
+ process.exit(bun_compile.proc.exitCode);
74
+ }
75
+
76
+ const duration_ms = Date.now() - start;
77
+
78
+ console.debug(`✅ ${path.relative(REPO_ROOT, outfile)} (${duration_ms}ms)`);
79
+ }
@@ -2,7 +2,7 @@
2
2
  // ensure we are publishing through the custom script
3
3
 
4
4
  if (!process.env.GS_RELEASE_NPM) {
5
- console.error("Must publish using `npm run release:npm`");
5
+ console.error("Must publish using `pnpm run release:npm`");
6
6
  console.error();
7
7
  process.exit(10);
8
8
  }
@@ -5,26 +5,19 @@ import * as file from "~/core/file";
5
5
  import { spawn } from "~/core/spawn";
6
6
 
7
7
  // get paths relative to this script
8
- const SCRIPT_DIR = import.meta.dir;
9
- const PROJECT_DIR = path.join(SCRIPT_DIR, "..");
10
- const DIST_DIR = path.join(PROJECT_DIR, "dist");
11
- const STANDALONE_DIR = path.join(DIST_DIR, "standalone");
12
- const HOMEBREW_DIR = path.join(PROJECT_DIR, "homebrew");
13
-
14
- const package_json = await file.read_json(
15
- path.join(PROJECT_DIR, "package.json")
16
- );
8
+ const REPO_ROOT = (await spawn.sync("git rev-parse --show-toplevel")).stdout;
9
+ const DIST_DIR = path.join(REPO_ROOT, "dist");
10
+ const BIN_DIR = path.join(DIST_DIR, "bin");
11
+ const HOMEBREW_DIR = path.join(REPO_ROOT, "homebrew");
12
+
13
+ const package_json = await file.read_json(path.join(REPO_ROOT, "package.json"));
17
14
 
18
15
  const version = package_json.version;
19
16
 
20
17
  process.chdir(HOMEBREW_DIR);
21
18
 
22
19
  // before creating new formula, mv the previous into a versioned formula name
23
- const previous_formula_path = path.join(
24
- HOMEBREW_DIR,
25
- "Formula",
26
- "git-stack.rb"
27
- );
20
+ const previous_formula_path = path.join(HOMEBREW_DIR, "Formula", "git-stack.rb");
28
21
 
29
22
  // match either version format from core or tap formula
30
23
  //
@@ -44,34 +37,27 @@ const previous_version = previous_version_match.groups.version;
44
37
  // convert `1.0.4` to `104`
45
38
  const not_dot_version = previous_version.replace(/\./g, "");
46
39
  const previous_class = `GitStackAT${not_dot_version}`;
47
- previous_formula = previous_formula.replace(
48
- "class GitStack",
49
- `class ${previous_class}`
50
- );
40
+ previous_formula = previous_formula.replace("class GitStack", `class ${previous_class}`);
51
41
 
52
42
  await file.write_text(
53
43
  path.join(HOMEBREW_DIR, "Formula", `git-stack@${previous_version}.rb`),
54
- previous_formula
44
+ previous_formula,
55
45
  );
56
46
 
57
- process.chdir(PROJECT_DIR);
47
+ process.chdir(REPO_ROOT);
58
48
 
59
- // download github asset and calculate sha256
60
- // prettier-ignore
61
- await spawn.sync(["gh", "release", "download", version, "-p", `git-stack-cli-${version}.tgz`]);
62
- // prettier-ignore
63
49
  const tarball_asset = await create_asset(`git-stack-cli-${version}.tgz`, { version });
64
- await file.rm(tarball_asset.filepath);
65
50
 
66
- await spawn(`npm run build:standalone`);
51
+ await spawn(`pnpm run compile`);
67
52
 
68
- process.chdir(STANDALONE_DIR);
53
+ process.chdir(BIN_DIR);
69
54
 
70
- const linux_asset = await create_asset("git-stack-cli-linux", { version });
71
- const macos_asset = await create_asset("git-stack-cli-macos", { version });
72
- const win_asset = await create_asset("git-stack-cli-win.exe", { version });
55
+ const linux_x64_asset = await create_asset("git-stack-bun-linux-x64.zip", { version });
56
+ const macos_x64_asset = await create_asset("git-stack-bun-darwin-x64.zip", { version });
57
+ const macos_arm64_asset = await create_asset("git-stack-bun-darwin-arm64.zip", { version });
58
+ const win_x64_asset = await create_asset("git-stack-bun-windows-x64.exe.zip", { version });
73
59
 
74
- console.debug({ linux_asset, macos_asset, win_asset });
60
+ console.debug({ linux_x64_asset, macos_x64_asset, macos_arm64_asset, win_x64_asset });
75
61
 
76
62
  const re_token = (name: string) => new RegExp(`{{ ${name} }}`, "g");
77
63
 
@@ -79,35 +65,27 @@ process.chdir(HOMEBREW_DIR);
79
65
 
80
66
  // homebrew tap formula (binaries)
81
67
 
82
- let tap = await file.read_text(
83
- path.join("templates", "git-stack.tap.rb.template")
84
- );
68
+ let tap = await file.read_text(path.join("templates", "git-stack.tap.rb.template"));
85
69
 
86
70
  tap = tap.replace(re_token("version"), version);
87
- tap = tap.replace(re_token("mac_bin"), macos_asset.filepath);
88
- tap = tap.replace(re_token("mac_sha256"), macos_asset.sha256);
89
- tap = tap.replace(re_token("linux_bin"), linux_asset.filepath);
90
- tap = tap.replace(re_token("linux_sha256"), linux_asset.sha256);
71
+ tap = tap.replace(re_token("mac_x64_bin"), macos_x64_asset.filepath);
72
+ tap = tap.replace(re_token("mac_x64_sha256"), macos_x64_asset.sha256);
73
+ tap = tap.replace(re_token("mac_arm64_bin"), macos_arm64_asset.filepath);
74
+ tap = tap.replace(re_token("mac_arm64_sha256"), macos_arm64_asset.sha256);
75
+ tap = tap.replace(re_token("linux_x64_bin"), linux_x64_asset.filepath);
76
+ tap = tap.replace(re_token("linux_x64_sha256"), linux_x64_asset.sha256);
91
77
 
92
78
  await file.write_text(path.join("Formula", "git-stack.rb"), tap);
93
79
 
94
80
  // homebrew/core formula (build from source)
95
81
 
96
- let core = await file.read_text(
97
- path.join("templates", "git-stack.core.rb.template")
98
- );
82
+ let core = await file.read_text(path.join("templates", "git-stack.core.rb.template"));
99
83
 
100
84
  core = core.replace(re_token("version"), version);
101
85
  core = core.replace(re_token("tarball_sha256"), tarball_asset.sha256);
102
86
 
103
87
  await file.write_text(path.join("Formula", "git-stack.core.rb"), core);
104
88
 
105
- // finally upload the assets to the github release
106
- process.chdir(STANDALONE_DIR);
107
- await spawn.sync(`gh release upload ${version} ${linux_asset.filepath}`);
108
- await spawn.sync(`gh release upload ${version} ${macos_asset.filepath}`);
109
- await spawn.sync(`gh release upload ${version} ${win_asset.filepath}`);
110
-
111
89
  // commit homebrew repo changes
112
90
  process.chdir(HOMEBREW_DIR);
113
91
  await spawn.sync(`git add .`);
@@ -115,7 +93,7 @@ await spawn.sync(`git commit -m ${version}`);
115
93
  await spawn.sync(`git push`);
116
94
 
117
95
  // commmit changes to main repo
118
- process.chdir(PROJECT_DIR);
96
+ process.chdir(REPO_ROOT);
119
97
  // prettier-ignore
120
98
  await spawn.sync(["git", "commit", "-a", "-m", `homebrew-git-stack ${version}`]);
121
99
  await spawn.sync(`git push`);
@@ -5,29 +5,41 @@ import * as file from "~/core/file";
5
5
  import { spawn } from "~/core/spawn";
6
6
 
7
7
  // get paths relative to this script
8
- const SCRIPT_DIR = import.meta.dir;
9
- const PROJECT_DIR = path.join(SCRIPT_DIR, "..");
8
+ const REPO_ROOT = (await spawn.sync("git rev-parse --show-toplevel")).stdout;
9
+ const DIST_DIR = path.join(REPO_ROOT, "dist");
10
+ const BIN_DIR = path.join(DIST_DIR, "bin");
10
11
 
11
- const package_json = await file.read_json(
12
- path.join(PROJECT_DIR, "package.json")
13
- );
12
+ const package_json = await file.read_json(path.join(REPO_ROOT, "package.json"));
14
13
 
15
14
  const version = package_json.version;
16
15
 
17
16
  // generates local tarball e.g. git-stack-cli-1.2.0.tgz
18
- await spawn("npm pack");
17
+ await spawn("pnpm pack");
19
18
 
20
- // prettier-ignore
21
- const tarball_asset = await create_asset(`git-stack-cli-${version}.tgz`, { version });
19
+ // generate single file executables for all targets
20
+ await spawn(`pnpm run compile`);
22
21
 
23
22
  await spawn.sync(`gh release create ${version} -t ${version} --generate-notes`);
24
23
 
24
+ const tarball_asset = await create_asset(`git-stack-cli-${version}.tgz`, { version });
25
25
  await spawn.sync(`gh release upload ${version} ${tarball_asset.filepath}`);
26
26
 
27
- await file.rm(tarball_asset.filepath);
27
+ process.chdir(BIN_DIR);
28
+
29
+ await zip_upload("git-stack-bun-darwin-arm64");
30
+ await zip_upload("git-stack-bun-darwin-x64");
31
+ await zip_upload("git-stack-bun-linux-x64");
32
+ await zip_upload("git-stack-bun-windows-x64.exe");
28
33
 
29
34
  console.debug();
30
35
  console.debug("✅", "published", version);
31
36
  console.debug();
32
37
  console.debug("https://github.com/magus/git-stack-cli/releases");
33
38
  console.debug();
39
+
40
+ async function zip_upload(filepath: string) {
41
+ const zip_filepath = `${filepath}.zip`;
42
+ await spawn.sync(`zip -r ${zip_filepath} ${filepath}`);
43
+ const asset = await create_asset(zip_filepath, { version });
44
+ await spawn.sync(`gh release upload ${version} ${asset.filepath}`);
45
+ }
@@ -7,15 +7,14 @@ import { spawn } from "~/core/spawn";
7
7
  process.env.NODE_ENV = "production";
8
8
 
9
9
  // get paths relative to this script
10
- const SCRIPT_DIR = import.meta.dir;
11
- const PROJECT_DIR = path.join(SCRIPT_DIR, "..");
12
- const DIST_DIR = path.join(PROJECT_DIR, "dist");
10
+ const REPO_ROOT = (await spawn.sync("git rev-parse --show-toplevel")).stdout;
11
+ const DIST_DIR = path.join(REPO_ROOT, "dist");
13
12
 
14
13
  // clear entire dist output directory
15
14
  await fs.rmdir(DIST_DIR, { recursive: true });
16
15
  await fs.mkdir(DIST_DIR, { recursive: true });
17
16
 
18
- process.chdir(PROJECT_DIR);
17
+ process.chdir(REPO_ROOT);
19
18
 
20
19
  // require clean git status besides changes to package.json version
21
20
  const git_status = await spawn.sync("git status --porcelain");
@@ -24,9 +23,7 @@ if (!/^M\s+package.json/.test(git_status.stdout)) {
24
23
  process.exit(4);
25
24
  }
26
25
 
27
- const package_json = await file.read_json(
28
- path.join(PROJECT_DIR, "package.json")
29
- );
26
+ const package_json = await file.read_json(path.join(REPO_ROOT, "package.json"));
30
27
 
31
28
  const version = package_json.version;
32
29
 
@@ -40,11 +37,11 @@ if (git_tag.stdout) {
40
37
  }
41
38
 
42
39
  // install all dependencies even though we are NODE_ENV=production
43
- await spawn(`npm install --production=false`);
40
+ await spawn(`pnpm install --frozen-lockfile --production=false`);
44
41
 
45
- await spawn(`npm run test:all`);
42
+ await spawn(`pnpm run test:all`);
46
43
 
47
- await spawn(`npm run build`);
44
+ await spawn(`pnpm run build`);
48
45
 
49
46
  // confirm all files specified exist
50
47
  for (const filepath of package_json.files) {
@@ -61,7 +58,7 @@ console.info("Publishing to NPM requires a one-time password");
61
58
  const otp = await input("Enter OTP: ");
62
59
  await spawn(["npm", "publish", `--otp=${otp}`]);
63
60
 
64
- process.chdir(PROJECT_DIR);
61
+ process.chdir(REPO_ROOT);
65
62
 
66
63
  await spawn.sync(`git commit -a -m ${version}`);
67
64
  await spawn.sync(`git push`);
package/src/app/App.tsx CHANGED
@@ -19,6 +19,8 @@ import { VerboseDebugInfo } from "~/app/VerboseDebugInfo";
19
19
  import { Fixup } from "~/commands/Fixup";
20
20
  import { Log } from "~/commands/Log";
21
21
  import { Rebase } from "~/commands/Rebase";
22
+ import { ErrorBoundary } from "~/components/ErrorBoundary";
23
+ import { ExitingGate } from "~/components/ExitingGate";
22
24
 
23
25
  export function App() {
24
26
  const actions = Store.useActions();
@@ -42,32 +44,36 @@ export function App() {
42
44
 
43
45
  return (
44
46
  <Providers>
45
- <Debug />
46
- <Output />
47
+ <ErrorBoundary>
48
+ <Debug />
49
+ <Output />
47
50
 
48
- <AutoUpdate
49
- name="git-stack-cli"
50
- verbose={argv.verbose || argv.update}
51
- timeoutMs={argv.update ? 30 * 1000 : 2 * 1000}
52
- onOutput={actions.output}
53
- onDone={() => {
54
- if (argv.update) {
55
- actions.exit(0);
56
- }
57
- }}
58
- >
59
- <VerboseDebugInfo>
60
- <DependencyCheck>
61
- <RebaseCheck>
62
- <CherryPickCheck>
63
- <MaybeMain />
64
- </CherryPickCheck>
65
- </RebaseCheck>
66
- </DependencyCheck>
67
- </VerboseDebugInfo>
68
- </AutoUpdate>
51
+ <ExitingGate>
52
+ <AutoUpdate
53
+ name="git-stack-cli"
54
+ verbose={argv.verbose || argv.update}
55
+ timeoutMs={argv.update ? 30 * 1000 : 2 * 1000}
56
+ onOutput={actions.output}
57
+ onDone={() => {
58
+ if (argv.update) {
59
+ actions.exit(0);
60
+ }
61
+ }}
62
+ >
63
+ <VerboseDebugInfo>
64
+ <DependencyCheck>
65
+ <RebaseCheck>
66
+ <CherryPickCheck>
67
+ <MaybeMain />
68
+ </CherryPickCheck>
69
+ </RebaseCheck>
70
+ </DependencyCheck>
71
+ </VerboseDebugInfo>
72
+ </AutoUpdate>
69
73
 
70
- <HandleCtrlCSigint />
74
+ <HandleCtrlCSigint />
75
+ </ExitingGate>
76
+ </ErrorBoundary>
71
77
  </Providers>
72
78
  );
73
79
  }
@@ -91,16 +97,18 @@ function MaybeMain() {
91
97
  }
92
98
 
93
99
  return (
94
- <DirtyCheck>
100
+ <React.Fragment>
95
101
  {!argv.verbose ? null : <GithubApiError />}
96
102
 
97
103
  <GatherMetadata>
98
- <LocalCommitStatus>
99
- <DetectInitialPR>
100
- <Main />
101
- </DetectInitialPR>
102
- </LocalCommitStatus>
104
+ <DirtyCheck>
105
+ <LocalCommitStatus>
106
+ <DetectInitialPR>
107
+ <Main />
108
+ </DetectInitialPR>
109
+ </LocalCommitStatus>
110
+ </DirtyCheck>
103
111
  </GatherMetadata>
104
- </DirtyCheck>
112
+ </React.Fragment>
105
113
  );
106
114
  }