git-stack-cli 1.7.0 → 1.8.1

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.
@@ -27273,8 +27273,6 @@ const RE$1 = {
27273
27273
  group_title: new RegExp(TEMPLATE$1.group_title("(?<title>[^\\n^\\r]+)"), "i"),
27274
27274
  };
27275
27275
 
27276
- // prettier-ignore
27277
- const JSON_FIELDS = "--json number,state,baseRefName,headRefName,commits,title,body,url";
27278
27276
  async function pr_list() {
27279
27277
  const state = Store.getState();
27280
27278
  const actions = state.actions;
@@ -27282,13 +27280,7 @@ async function pr_list() {
27282
27280
  const repo_path = state.repo_path;
27283
27281
  invariant(username, "username must exist");
27284
27282
  invariant(repo_path, "repo_path must exist");
27285
- const cli_result = await cli(`gh pr list --repo ${repo_path} --author ${username} --state open ${JSON_FIELDS}`, {
27286
- ignoreExitCode: true,
27287
- });
27288
- if (cli_result.code !== 0) {
27289
- handle_error(cli_result.output);
27290
- }
27291
- const result_pr_list = JSON.parse(cli_result.stdout);
27283
+ const result_pr_list = await gh_json(`pr list --repo ${repo_path} --author ${username} --state open ${JSON_FIELDS}`);
27292
27284
  if (actions.isDebug()) {
27293
27285
  actions.output(reactExports.createElement(Text, { dimColor: true },
27294
27286
  reactExports.createElement(Text, null, "Github cache "),
@@ -27332,14 +27324,7 @@ async function pr_status(branch) {
27332
27324
  reactExports.createElement(Text, null, " "),
27333
27325
  reactExports.createElement(Text, { dimColor: true }, branch)));
27334
27326
  }
27335
- const cli_result = await cli(`gh pr view ${branch} --repo ${repo_path} ${JSON_FIELDS}`, {
27336
- ignoreExitCode: true,
27337
- });
27338
- if (cli_result.code !== 0) {
27339
- // handle_error(cli_result.output);
27340
- return null;
27341
- }
27342
- const pr = JSON.parse(cli_result.stdout);
27327
+ const pr = await gh_json(`pr view ${branch} --repo ${repo_path} ${JSON_FIELDS}`);
27343
27328
  actions.set((state) => {
27344
27329
  state.pr[pr.headRefName] = pr;
27345
27330
  });
@@ -27347,7 +27332,11 @@ async function pr_status(branch) {
27347
27332
  }
27348
27333
  async function pr_create(args) {
27349
27334
  const title = safe_quote(args.title);
27350
- const cli_result = await cli(`gh pr create --fill --head ${args.branch} --base ${args.base} --title="${title}" --body="${args.body}"`);
27335
+ let command = `gh pr create --fill --head ${args.branch} --base ${args.base} --title="${title}" --body="${args.body}"`;
27336
+ if (args.draft) {
27337
+ command += " --draft";
27338
+ }
27339
+ const cli_result = await cli(command);
27351
27340
  if (cli_result.code !== 0) {
27352
27341
  handle_error(cli_result.output);
27353
27342
  return null;
@@ -27362,6 +27351,22 @@ async function pr_edit(args) {
27362
27351
  handle_error(cli_result.output);
27363
27352
  }
27364
27353
  }
27354
+ // prettier-ignore
27355
+ const JSON_FIELDS = "--json number,state,baseRefName,headRefName,commits,title,body,url";
27356
+ // consistent handle gh cli commands returning json
27357
+ // redirect to tmp file to avoid scrollback overflow causing scrollback to be cleared
27358
+ async function gh_json(command) {
27359
+ const tmp_pr_json = path.join(os.tmpdir(), "git-stack-gh.json");
27360
+ const options = { ignoreExitCode: true };
27361
+ const cli_result = await cli(`gh ${command} > ${tmp_pr_json}`, options);
27362
+ if (cli_result.code !== 0) {
27363
+ handle_error(cli_result.output);
27364
+ }
27365
+ // read from file
27366
+ const json_str = fs.readFileSync(tmp_pr_json, "utf-8");
27367
+ const json = JSON.parse(json_str);
27368
+ return json;
27369
+ }
27365
27370
  function handle_error(output) {
27366
27371
  const state = Store.getState();
27367
27372
  const actions = state.actions;
@@ -27654,7 +27659,7 @@ async function run$4() {
27654
27659
  process.once("SIGINT", handle_exit);
27655
27660
  const temp_branch_name = `${branch_name}_${short_id()}`;
27656
27661
  try {
27657
- actions.debug(`commit_range=${JSON.stringify(commit_range, null, 2)}`);
27662
+ // actions.debug(`commit_range=${JSON.stringify(commit_range, null, 2)}`);
27658
27663
  // must perform rebase from repo root for applying git patch
27659
27664
  process.chdir(repo_root);
27660
27665
  await cli(`pwd`);
@@ -27972,7 +27977,7 @@ async function run$3() {
27972
27977
  }
27973
27978
  actions.debug(`rebase_merge_base = ${rebase_merge_base}`);
27974
27979
  actions.debug(`rebase_group_index = ${rebase_group_index}`);
27975
- actions.debug(`commit_range=${JSON.stringify(commit_range, null, 2)}`);
27980
+ // actions.debug(`commit_range=${JSON.stringify(commit_range, null, 2)}`);
27976
27981
  try {
27977
27982
  // must perform rebase from repo root for applying git patch
27978
27983
  process.chdir(repo_root);
@@ -28058,7 +28063,7 @@ echo "$GIT_REVISE_TODO" > "$git_revise_todo_path"
28058
28063
  `GIT_REVISE_TODO="${git_revise_todo}"`,
28059
28064
  `git`,
28060
28065
  `revise --edit -i ${rebase_merge_base}`,
28061
- ]);
28066
+ ], { stdio: ["ignore", "ignore", "ignore"] });
28062
28067
  // early return since we do not need to sync
28063
28068
  if (!argv.sync) {
28064
28069
  return;
@@ -28175,6 +28180,7 @@ echo "$GIT_REVISE_TODO" > "$git_revise_todo_path"
28175
28180
  base: group.base,
28176
28181
  title: group.title,
28177
28182
  body: DEFAULT_PR_BODY,
28183
+ draft: argv.draft,
28178
28184
  });
28179
28185
  if (!pr_url) {
28180
28186
  throw new Error("unable to create pr");
@@ -28487,25 +28493,26 @@ async function run$1() {
28487
28493
  state.step = "manual-rebase";
28488
28494
  });
28489
28495
  }
28490
- // ./.github/PULL_REQUEST_TEMPLATE/*.md
28491
- let pr_templates = [];
28492
- if (fs.existsSync(template_pr_template(repo_root))) {
28493
- pr_templates = fs.readdirSync(template_pr_template(repo_root));
28494
- }
28496
+ let pr_template_body = null;
28495
28497
  // look for pull request template
28496
28498
  // https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository
28497
28499
  // ./.github/pull_request_template.md
28498
28500
  // ./pull_request_template.md
28499
28501
  // ./docs/pull_request_template.md
28500
- let pr_template_body = null;
28501
- if (fs.existsSync(github_pr_template(repo_root))) {
28502
- pr_template_body = fs.readFileSync(github_pr_template(repo_root), "utf-8");
28503
- }
28504
- else if (fs.existsSync(root_pr_template(repo_root))) {
28505
- pr_template_body = fs.readFileSync(root_pr_template(repo_root), "utf-8");
28502
+ for (const key of PR_TEMPLATE_KEY_LIST) {
28503
+ const pr_template_fn = PR_TEMPLATE[key];
28504
+ if (fs.existsSync(pr_template_fn(repo_root))) {
28505
+ pr_template_body = fs.readFileSync(pr_template_fn(repo_root), "utf-8");
28506
+ actions.output(reactExports.createElement(FormatText, { wrapper: reactExports.createElement(Text, { color: colors.yellow }), message: "Using PR template {pr_filepath}", values: {
28507
+ pr_filepath: reactExports.createElement(Brackets, null, pr_template_fn("")),
28508
+ } }));
28509
+ break;
28510
+ }
28506
28511
  }
28507
- else if (fs.existsSync(docs_pr_template(repo_root))) {
28508
- pr_template_body = fs.readFileSync(docs_pr_template(repo_root), "utf-8");
28512
+ // ./.github/PULL_REQUEST_TEMPLATE/*.md
28513
+ let pr_templates = [];
28514
+ if (fs.existsSync(PR_TEMPLATE.TemplateDir(repo_root))) {
28515
+ pr_templates = fs.readdirSync(PR_TEMPLATE.TemplateDir(repo_root));
28509
28516
  }
28510
28517
  // check if repo has multiple pr templates
28511
28518
  actions.set((state) => {
@@ -28514,24 +28521,21 @@ async function run$1() {
28514
28521
  if (pr_templates.length > 0) {
28515
28522
  actions.output(reactExports.createElement(FormatText, { wrapper: reactExports.createElement(Text, { color: colors.yellow }), message: "{count} queryable templates found under {dir}, but not supported.", values: {
28516
28523
  count: (reactExports.createElement(Text, { color: colors.blue }, pr_templates.length)),
28517
- dir: reactExports.createElement(Brackets, null, template_pr_template("")),
28524
+ dir: reactExports.createElement(Brackets, null, PR_TEMPLATE.TemplateDir("")),
28518
28525
  } }));
28519
28526
  }
28520
28527
  state.step = "manual-rebase";
28521
28528
  });
28522
28529
  }
28523
- function github_pr_template(repo_root) {
28524
- return path.join(repo_root, ".github", "pull_request_template.md");
28525
- }
28526
- function root_pr_template(repo_root) {
28527
- return path.join(repo_root, "pull_request_template.md");
28528
- }
28529
- function docs_pr_template(repo_root) {
28530
- return path.join(repo_root, "docs", "pull_request_template.md");
28531
- }
28532
- function template_pr_template(repo_root) {
28533
- return path.join(repo_root, ".github", "PULL_REQUEST_TEMPLATE");
28534
- }
28530
+ // prettier-ignore
28531
+ const PR_TEMPLATE = Object.freeze({
28532
+ Github: (root) => path.join(root, ".github", "pull_request_template.md"),
28533
+ Root: (root) => path.join(root, "pull_request_template.md"),
28534
+ Docs: (root) => path.join(root, "docs", "pull_request_template.md"),
28535
+ TemplateDir: (root) => path.join(root, ".github", "PULL_REQUEST_TEMPLATE"),
28536
+ });
28537
+ // prettier-ignore
28538
+ const PR_TEMPLATE_KEY_LIST = Object.keys(PR_TEMPLATE);
28535
28539
 
28536
28540
  function PreSelectCommitRanges() {
28537
28541
  const actions = Store.useActions();
@@ -34517,6 +34521,12 @@ async function command() {
34517
34521
  type: "string",
34518
34522
  alias: ["b"],
34519
34523
  description: 'Set the master branch name, defaults to "master" (or "main" if "master" is not found)',
34524
+ })
34525
+ .option("draft", {
34526
+ type: "boolean",
34527
+ alias: ["d"],
34528
+ default: false,
34529
+ description: "Open all PRs as drafts",
34520
34530
  })
34521
34531
  .option("write-state-json", {
34522
34532
  hidden: true,
@@ -34541,7 +34551,7 @@ async function command() {
34541
34551
  .wrap(123)
34542
34552
  // disallow unknown options
34543
34553
  .strict()
34544
- .version("1.7.0" )
34554
+ .version("1.8.1" )
34545
34555
  .showHidden("show-hidden", "Show hidden options via `git stack help --show-hidden`")
34546
34556
  .help("help", "Show usage via `git stack help`").argv);
34547
34557
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-stack-cli",
3
- "version": "1.7.0",
3
+ "version": "1.8.1",
4
4
  "description": "",
5
5
  "author": "magus",
6
6
  "license": "MIT",
@@ -43,7 +43,7 @@ async function run() {
43
43
  const temp_branch_name = `${branch_name}_${short_id()}`;
44
44
 
45
45
  try {
46
- actions.debug(`commit_range=${JSON.stringify(commit_range, null, 2)}`);
46
+ // actions.debug(`commit_range=${JSON.stringify(commit_range, null, 2)}`);
47
47
 
48
48
  // must perform rebase from repo root for applying git patch
49
49
  process.chdir(repo_root);
@@ -83,7 +83,8 @@ async function run() {
83
83
 
84
84
  actions.debug(`rebase_merge_base = ${rebase_merge_base}`);
85
85
  actions.debug(`rebase_group_index = ${rebase_group_index}`);
86
- actions.debug(`commit_range=${JSON.stringify(commit_range, null, 2)}`);
86
+
87
+ // actions.debug(`commit_range=${JSON.stringify(commit_range, null, 2)}`);
87
88
 
88
89
  try {
89
90
  // must perform rebase from repo root for applying git patch
@@ -153,12 +154,15 @@ async function run() {
153
154
 
154
155
  // execute cli with temporary git sequence editor script
155
156
  // revise from merge base to pick correct commits
156
- await cli([
157
- `GIT_EDITOR="${tmp_git_sequence_editor_path}"`,
158
- `GIT_REVISE_TODO="${git_revise_todo}"`,
159
- `git`,
160
- `revise --edit -i ${rebase_merge_base}`,
161
- ]);
157
+ await cli(
158
+ [
159
+ `GIT_EDITOR="${tmp_git_sequence_editor_path}"`,
160
+ `GIT_REVISE_TODO="${git_revise_todo}"`,
161
+ `git`,
162
+ `revise --edit -i ${rebase_merge_base}`,
163
+ ],
164
+ { stdio: ["ignore", "ignore", "ignore"] }
165
+ );
162
166
 
163
167
  // early return since we do not need to sync
164
168
  if (!argv.sync) {
@@ -334,6 +338,7 @@ async function run() {
334
338
  base: group.base,
335
339
  title: group.title,
336
340
  body: DEFAULT_PR_BODY,
341
+ draft: argv.draft,
337
342
  });
338
343
 
339
344
  if (!pr_url) {
@@ -31,24 +31,37 @@ async function run() {
31
31
  });
32
32
  }
33
33
 
34
- // ./.github/PULL_REQUEST_TEMPLATE/*.md
35
- let pr_templates: Array<string> = [];
36
- if (fs.existsSync(template_pr_template(repo_root))) {
37
- pr_templates = fs.readdirSync(template_pr_template(repo_root));
38
- }
34
+ let pr_template_body: null | string = null;
39
35
 
40
36
  // look for pull request template
41
37
  // https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository
42
38
  // ./.github/pull_request_template.md
43
39
  // ./pull_request_template.md
44
40
  // ./docs/pull_request_template.md
45
- let pr_template_body: null | string = null;
46
- if (fs.existsSync(github_pr_template(repo_root))) {
47
- pr_template_body = fs.readFileSync(github_pr_template(repo_root), "utf-8");
48
- } else if (fs.existsSync(root_pr_template(repo_root))) {
49
- pr_template_body = fs.readFileSync(root_pr_template(repo_root), "utf-8");
50
- } else if (fs.existsSync(docs_pr_template(repo_root))) {
51
- pr_template_body = fs.readFileSync(docs_pr_template(repo_root), "utf-8");
41
+ for (const key of PR_TEMPLATE_KEY_LIST) {
42
+ const pr_template_fn = PR_TEMPLATE[key as keyof typeof PR_TEMPLATE];
43
+
44
+ if (fs.existsSync(pr_template_fn(repo_root))) {
45
+ pr_template_body = fs.readFileSync(pr_template_fn(repo_root), "utf-8");
46
+
47
+ actions.output(
48
+ <FormatText
49
+ wrapper={<Ink.Text color={colors.yellow} />}
50
+ message="Using PR template {pr_filepath}"
51
+ values={{
52
+ pr_filepath: <Brackets>{pr_template_fn("")}</Brackets>,
53
+ }}
54
+ />
55
+ );
56
+
57
+ break;
58
+ }
59
+ }
60
+
61
+ // ./.github/PULL_REQUEST_TEMPLATE/*.md
62
+ let pr_templates: Array<string> = [];
63
+ if (fs.existsSync(PR_TEMPLATE.TemplateDir(repo_root))) {
64
+ pr_templates = fs.readdirSync(PR_TEMPLATE.TemplateDir(repo_root));
52
65
  }
53
66
 
54
67
  // check if repo has multiple pr templates
@@ -65,7 +78,7 @@ async function run() {
65
78
  count: (
66
79
  <Ink.Text color={colors.blue}>{pr_templates.length}</Ink.Text>
67
80
  ),
68
- dir: <Brackets>{template_pr_template("")}</Brackets>,
81
+ dir: <Brackets>{PR_TEMPLATE.TemplateDir("")}</Brackets>,
69
82
  }}
70
83
  />
71
84
  );
@@ -75,18 +88,13 @@ async function run() {
75
88
  });
76
89
  }
77
90
 
78
- function github_pr_template(repo_root: string) {
79
- return path.join(repo_root, ".github", "pull_request_template.md");
80
- }
81
-
82
- function root_pr_template(repo_root: string) {
83
- return path.join(repo_root, "pull_request_template.md");
84
- }
91
+ // prettier-ignore
92
+ const PR_TEMPLATE = Object.freeze({
93
+ Github: (root: string) => path.join(root, ".github", "pull_request_template.md"),
94
+ Root: (root: string) => path.join(root, "pull_request_template.md"),
95
+ Docs: (root: string) => path.join(root, "docs", "pull_request_template.md"),
96
+ TemplateDir: (root: string) => path.join(root, ".github", "PULL_REQUEST_TEMPLATE"),
97
+ });
85
98
 
86
- function docs_pr_template(repo_root: string) {
87
- return path.join(repo_root, "docs", "pull_request_template.md");
88
- }
89
-
90
- function template_pr_template(repo_root: string) {
91
- return path.join(repo_root, ".github", "PULL_REQUEST_TEMPLATE");
92
- }
99
+ // prettier-ignore
100
+ const PR_TEMPLATE_KEY_LIST = Object.keys(PR_TEMPLATE) as Array<keyof typeof PR_TEMPLATE>;
package/src/command.ts CHANGED
@@ -71,6 +71,13 @@ export async function command() {
71
71
  'Set the master branch name, defaults to "master" (or "main" if "master" is not found)',
72
72
  })
73
73
 
74
+ .option("draft", {
75
+ type: "boolean",
76
+ alias: ["d"],
77
+ default: false,
78
+ description: "Open all PRs as drafts",
79
+ })
80
+
74
81
  .option("write-state-json", {
75
82
  hidden: true,
76
83
  type: "boolean",
@@ -13,9 +13,6 @@ import { colors } from "~/core/colors";
13
13
  import { invariant } from "~/core/invariant";
14
14
  import { safe_quote } from "~/core/safe_quote";
15
15
 
16
- // prettier-ignore
17
- const JSON_FIELDS = "--json number,state,baseRefName,headRefName,commits,title,body,url";
18
-
19
16
  export async function pr_list(): Promise<Array<PullRequest>> {
20
17
  const state = Store.getState();
21
18
  const actions = state.actions;
@@ -25,19 +22,10 @@ export async function pr_list(): Promise<Array<PullRequest>> {
25
22
  invariant(username, "username must exist");
26
23
  invariant(repo_path, "repo_path must exist");
27
24
 
28
- const cli_result = await cli(
29
- `gh pr list --repo ${repo_path} --author ${username} --state open ${JSON_FIELDS}`,
30
- {
31
- ignoreExitCode: true,
32
- }
25
+ const result_pr_list: Array<PullRequest> = await gh_json(
26
+ `pr list --repo ${repo_path} --author ${username} --state open ${JSON_FIELDS}`
33
27
  );
34
28
 
35
- if (cli_result.code !== 0) {
36
- handle_error(cli_result.output);
37
- }
38
-
39
- const result_pr_list: Array<PullRequest> = JSON.parse(cli_result.stdout);
40
-
41
29
  if (actions.isDebug()) {
42
30
  actions.output(
43
31
  <Ink.Text dimColor>
@@ -105,20 +93,10 @@ export async function pr_status(branch: string): Promise<null | PullRequest> {
105
93
  );
106
94
  }
107
95
 
108
- const cli_result = await cli(
109
- `gh pr view ${branch} --repo ${repo_path} ${JSON_FIELDS}`,
110
- {
111
- ignoreExitCode: true,
112
- }
96
+ const pr: PullRequest = await gh_json(
97
+ `pr view ${branch} --repo ${repo_path} ${JSON_FIELDS}`
113
98
  );
114
99
 
115
- if (cli_result.code !== 0) {
116
- // handle_error(cli_result.output);
117
- return null;
118
- }
119
-
120
- const pr: PullRequest = JSON.parse(cli_result.stdout);
121
-
122
100
  actions.set((state) => {
123
101
  state.pr[pr.headRefName] = pr;
124
102
  });
@@ -131,14 +109,18 @@ type CreatePullRequestArgs = {
131
109
  base: string;
132
110
  title: string;
133
111
  body: string;
112
+ draft: boolean;
134
113
  };
135
114
 
136
115
  export async function pr_create(args: CreatePullRequestArgs) {
137
116
  const title = safe_quote(args.title);
117
+ let command = `gh pr create --fill --head ${args.branch} --base ${args.base} --title="${title}" --body="${args.body}"`;
138
118
 
139
- const cli_result = await cli(
140
- `gh pr create --fill --head ${args.branch} --base ${args.base} --title="${title}" --body="${args.body}"`
141
- );
119
+ if (args.draft) {
120
+ command += " --draft";
121
+ }
122
+
123
+ const cli_result = await cli(command);
142
124
 
143
125
  if (cli_result.code !== 0) {
144
126
  handle_error(cli_result.output);
@@ -165,6 +147,27 @@ export async function pr_edit(args: EditPullRequestArgs) {
165
147
  }
166
148
  }
167
149
 
150
+ // prettier-ignore
151
+ const JSON_FIELDS = "--json number,state,baseRefName,headRefName,commits,title,body,url";
152
+
153
+ // consistent handle gh cli commands returning json
154
+ // redirect to tmp file to avoid scrollback overflow causing scrollback to be cleared
155
+ async function gh_json(command: string) {
156
+ const tmp_pr_json = path.join(os.tmpdir(), "git-stack-gh.json");
157
+
158
+ const options = { ignoreExitCode: true };
159
+ const cli_result = await cli(`gh ${command} > ${tmp_pr_json}`, options);
160
+
161
+ if (cli_result.code !== 0) {
162
+ handle_error(cli_result.output);
163
+ }
164
+
165
+ // read from file
166
+ const json_str = fs.readFileSync(tmp_pr_json, "utf-8");
167
+ const json = JSON.parse(json_str);
168
+ return json;
169
+ }
170
+
168
171
  function handle_error(output: string): never {
169
172
  const state = Store.getState();
170
173
  const actions = state.actions;