git-stack-cli 1.13.2 → 1.15.0

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.
@@ -5,6 +5,7 @@ import path from "node:path";
5
5
  import * as Metadata from "~/core/Metadata";
6
6
  import { cli } from "~/core/cli";
7
7
  import { invariant } from "~/core/invariant";
8
+ import { safe_rm } from "~/core/safe_rm";
8
9
 
9
10
  import type * as CommitMetadata from "~/core/CommitMetadata";
10
11
 
@@ -140,6 +141,9 @@ GitReviseTodo.execute = async function grt_execute(args: ExecuteArgs) {
140
141
  // change to pipe to see output temporarily
141
142
  // https://github.com/magus/git-stack-cli/commit/f9f10e3ac3cd9a35ee75d3e0851a48391967a23f
142
143
  await cli(command, { stdio: ["ignore", "ignore", "ignore"] });
144
+
145
+ // cleanup tmp_git_sequence_editor_path
146
+ await safe_rm(tmp_git_sequence_editor_path);
143
147
  };
144
148
 
145
149
  type ExecuteArgs = {
@@ -130,13 +130,19 @@ export async function pr_create(args: CreatePullRequestArgs) {
130
130
  // pull request create failed: GraphQL: Head sha can't be blank, Base sha can't be blank, No commits between gs-6LAx-On45 and origin/gs-ED2etrzv2, Head ref must be a branch (createPullRequest)
131
131
  //
132
132
  // https://github.com/cli/cli/issues/5465
133
- let command = `gh pr create --head refs/heads/${args.branch} --base ${args.base} --title="${title}" --body="${args.body}"`;
133
+ let command_parts = [
134
+ "gh pr create",
135
+ `--head refs/heads/${args.branch}`,
136
+ `--base ${args.base}`,
137
+ `--title="${title}"`,
138
+ `--body="${args.body}"`,
139
+ ];
134
140
 
135
141
  if (args.draft) {
136
- command += " --draft";
142
+ command_parts.push("--draft");
137
143
  }
138
144
 
139
- const cli_result = await cli(command);
145
+ const cli_result = await cli(command_parts);
140
146
 
141
147
  if (cli_result.code !== 0) {
142
148
  handle_error(cli_result.output);
@@ -155,18 +161,23 @@ type EditPullRequestArgs = {
155
161
  export async function pr_edit(args: EditPullRequestArgs) {
156
162
  const command_parts = [`gh pr edit ${args.branch} --base ${args.base}`];
157
163
 
164
+ let body_file: string | undefined;
165
+
158
166
  if (args.body) {
159
- const body_file = await write_body_file(args);
167
+ body_file = await write_body_file(args);
160
168
  command_parts.push(`--body-file="${body_file}"`);
161
169
  }
162
170
 
163
- const command = command_parts.join(" ");
164
-
165
- const cli_result = await cli(command);
171
+ const cli_result = await cli(command_parts);
166
172
 
167
173
  if (cli_result.code !== 0) {
168
174
  handle_error(cli_result.output);
169
175
  }
176
+
177
+ // cleanup body_file
178
+ if (body_file) {
179
+ await safe_rm(body_file);
180
+ }
170
181
  }
171
182
 
172
183
  type DraftPullRequestArgs = {
@@ -254,7 +265,14 @@ async function write_body_file(args: EditPullRequestArgs) {
254
265
  invariant(args.body, "args.body must exist");
255
266
 
256
267
  const temp_dir = os.tmpdir();
257
- const temp_path = path.join(temp_dir, `git-stack-body-${args.base}`);
268
+
269
+ // ensure unique filename is safe for filesystem
270
+ // base (group id) might contain slashes, e.g. dev/magus/gs-3cmrMBSUj
271
+ // the flashes would mess up the filesystem path to this file
272
+ let temp_filename = `git-stack-body-${args.base}`;
273
+ temp_filename = temp_filename.replace(RE.non_alphanumeric_dash, "-");
274
+
275
+ const temp_path = path.join(temp_dir, temp_filename);
258
276
 
259
277
  await safe_rm(temp_path);
260
278
 
@@ -291,3 +309,7 @@ export type PullRequest = {
291
309
  url: string;
292
310
  isDraft: boolean;
293
311
  };
312
+
313
+ const RE = {
314
+ non_alphanumeric_dash: /[^a-zA-Z0-9_-]+/g,
315
+ };
@@ -0,0 +1,12 @@
1
+ export namespace pretty_json {
2
+ export type JSONValue =
3
+ | null
4
+ | number
5
+ | string
6
+ | boolean
7
+ | { [key: string]: JSONValue };
8
+ }
9
+
10
+ export function pretty_json<T extends pretty_json.JSONValue>(input: T): string {
11
+ return JSON.stringify(input, null, 2);
12
+ }
package/src/index.tsx CHANGED
@@ -7,12 +7,19 @@ import * as Ink from "ink-cjs";
7
7
  import { App } from "~/app/App";
8
8
  import { Store } from "~/app/Store";
9
9
  import { command } from "~/command";
10
+ import { pretty_json } from "~/core/pretty_json";
11
+
12
+ (async function main() {
13
+ try {
14
+ const argv = await command();
10
15
 
11
- command()
12
- .then((argv) => {
13
16
  const ink = Ink.render(<App />, {
14
17
  // If true, each update will be rendered as a separate output, without replacing the previous one.
15
18
  // debug: true,
19
+ //
20
+ // Configure whether Ink should listen to Ctrl+C keyboard input and exit the app.
21
+ // We intentionally handle this ourselves in `<Exit />`
22
+ exitOnCtrlC: false,
16
23
  });
17
24
 
18
25
  Store.setState((state) => {
@@ -22,7 +29,15 @@ command()
22
29
  state.cwd = process.cwd();
23
30
  });
24
31
 
25
- Store.getState().actions.debug(JSON.stringify(argv, null, 2));
26
- })
32
+ Store.getState().actions.debug(pretty_json(argv as any));
33
+
34
+ await ink.waitUntilExit();
35
+ } catch (err) {
36
+ // eslint-disable-next-line no-console
37
+ console.error(err);
38
+ process.exit(235);
39
+ }
40
+ })().catch((err) => {
27
41
  // eslint-disable-next-line no-console
28
- .catch(console.error);
42
+ console.error(err);
43
+ });
@@ -5,5 +5,6 @@ declare namespace NodeJS {
5
5
  CLI_VERSION?: string;
6
6
  GIT_STACK_STANDALONE?: "true" | "false";
7
7
  GIT_SEQUENCE_EDITOR_SCRIPT?: string;
8
+ GIT_STACK_BRANCH_PREFIX?: string;
8
9
  }
9
10
  }