git-stack-cli 1.11.7 → 1.13.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.
@@ -11,12 +11,13 @@ var node_events = require('node:events');
11
11
  var fs = require('node:fs');
12
12
  var require$$1 = require('module');
13
13
  var node_buffer = require('node:buffer');
14
+ var fs$1 = require('node:fs/promises');
14
15
  var path = require('node:path');
15
16
  var child = require('node:child_process');
16
17
  var https = require('node:https');
17
18
  var crypto = require('node:crypto');
18
19
  var path$1 = require('path');
19
- var fs$1 = require('fs');
20
+ var fs$2 = require('fs');
20
21
  var util = require('util');
21
22
  var url = require('url');
22
23
 
@@ -26520,9 +26521,9 @@ function is_finite_value(value) {
26520
26521
  return typeof value === "number" && Number.isFinite(value);
26521
26522
  }
26522
26523
 
26523
- function read_json(path) {
26524
+ async function read_json(path) {
26524
26525
  try {
26525
- const file_buffer = fs.readFileSync(path);
26526
+ const file_buffer = await fs$1.readFile(path);
26526
26527
  const json_str = String(file_buffer);
26527
26528
  const json = JSON.parse(json_str);
26528
26529
  return json;
@@ -26607,10 +26608,11 @@ function AutoUpdate(props) {
26607
26608
  if (!latest_version) {
26608
26609
  throw new Error("Unable to retrieve latest version from npm");
26609
26610
  }
26610
- const script_dir = path.dirname(fs.realpathSync(process.argv[1]));
26611
+ const script_path = await fs$1.realpath(process.argv[1]);
26612
+ const script_dir = path.dirname(script_path);
26611
26613
  // dist/ts/index.js
26612
26614
  const package_json_path = path.join(script_dir, "..", "..", "package.json");
26613
- const package_json = read_json(package_json_path);
26615
+ const package_json = await read_json(package_json_path);
26614
26616
  if (!package_json) {
26615
26617
  // unable to find read package.json, skip auto update
26616
26618
  throw new Error(`Unable to read package.json [${package_json_path}]`);
@@ -26773,6 +26775,16 @@ function Command(props) {
26773
26775
  return (reactExports.createElement(Text, { bold: true, color: text_color }, props.children));
26774
26776
  }
26775
26777
 
26778
+ async function safe_exists(filepath) {
26779
+ try {
26780
+ await fs$1.access(filepath);
26781
+ return true;
26782
+ }
26783
+ catch {
26784
+ return false;
26785
+ }
26786
+ }
26787
+
26776
26788
  function reducer$3(state, patch) {
26777
26789
  return { ...state, ...patch };
26778
26790
  }
@@ -26803,7 +26815,8 @@ function CherryPickCheck(props) {
26803
26815
  const actions = Store.getState().actions;
26804
26816
  try {
26805
26817
  const git_dir = (await cli(`git rev-parse --absolute-git-dir`)).stdout;
26806
- const is_cherry_pick = fs.existsSync(path.join(git_dir, "CHERRY_PICK_HEAD"));
26818
+ const cherry_pick_file = path.join(git_dir, "CHERRY_PICK_HEAD");
26819
+ const is_cherry_pick = await safe_exists(cherry_pick_file);
26807
26820
  const status = is_cherry_pick ? "prompt" : "done";
26808
26821
  patch({ status });
26809
26822
  }
@@ -26855,6 +26868,16 @@ function deserialize(obj) {
26855
26868
  return obj;
26856
26869
  }
26857
26870
 
26871
+ async function safe_rm(filepath) {
26872
+ try {
26873
+ await fs$1.access(filepath);
26874
+ await fs$1.rm(filepath);
26875
+ }
26876
+ catch {
26877
+ // if access fails there is no file to remove this is safe
26878
+ }
26879
+ }
26880
+
26858
26881
  function Debug() {
26859
26882
  const actions = Store.useActions();
26860
26883
  const state = Store.useState((state) => state);
@@ -26865,17 +26888,18 @@ function Debug() {
26865
26888
  actions.output(reactExports.createElement(Text, { color: colors.yellow }, "Debug mode enabled"));
26866
26889
  }
26867
26890
  }, [argv]);
26868
- reactExports.useEffect(function syncStateJson() {
26891
+ reactExports.useEffect(function sync_state_json() {
26869
26892
  if (!argv?.["write-state-json"]) {
26870
26893
  return;
26871
26894
  }
26872
- const output_file = path.join(state.cwd, "git-stack-state.json");
26873
- if (fs.existsSync(output_file)) {
26874
- fs.rmSync(output_file);
26895
+ sync().catch(actions.error);
26896
+ async function sync() {
26897
+ const output_file = path.join(state.cwd, "git-stack-state.json");
26898
+ await safe_rm(output_file);
26899
+ const serialized = serialize(state);
26900
+ const content = JSON.stringify(serialized, null, 2);
26901
+ await fs$1.writeFile(output_file, content);
26875
26902
  }
26876
- const serialized = serialize(state);
26877
- const content = JSON.stringify(serialized, null, 2);
26878
- fs.writeFileSync(output_file, content);
26879
26903
  }, [argv, state]);
26880
26904
  return null;
26881
26905
  }
@@ -27005,11 +27029,6 @@ function CheckGithubCliAuth(props) {
27005
27029
  }
27006
27030
  function CheckGitRevise(props) {
27007
27031
  const actions = Store.useActions();
27008
- const argv = Store.useState((state) => state.argv);
27009
- // skip git revise check when `rebase` is not git-revise
27010
- if (argv?.["rebase"] !== "git-revise") {
27011
- return props.children;
27012
- }
27013
27032
  return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow },
27014
27033
  reactExports.createElement(Text, null,
27015
27034
  "Checking ",
@@ -29776,8 +29795,43 @@ async function pr_create(args) {
29776
29795
  async function pr_edit(args) {
29777
29796
  const command_parts = [`gh pr edit ${args.branch} --base ${args.base}`];
29778
29797
  if (args.body) {
29779
- command_parts.push(`--body-file="${body_file(args.body)}"`);
29798
+ const body_file = await write_body_file(args);
29799
+ command_parts.push(`--body-file="${body_file}"`);
29800
+ }
29801
+ const command = command_parts.join(" ");
29802
+ const cli_result = await cli(command);
29803
+ if (cli_result.code !== 0) {
29804
+ handle_error(cli_result.output);
29805
+ }
29806
+ }
29807
+ async function pr_draft(args) {
29808
+ // https://cli.github.com/manual/gh_api
29809
+ // https://docs.github.com/en/graphql/reference/mutations#convertpullrequesttodraft
29810
+ // https://docs.github.com/en/graphql/reference/mutations#markpullrequestreadyforreview
29811
+ const mutation_name = args.draft
29812
+ ? "convertPullRequestToDraft"
29813
+ : "markPullRequestReadyForReview";
29814
+ let query = `
29815
+ mutation($id: ID!) {
29816
+ ${mutation_name}(input: { pullRequestId: $id }) {
29817
+ pullRequest {
29818
+ id
29819
+ number
29820
+ isDraft
29821
+ }
29822
+ }
29780
29823
  }
29824
+ `;
29825
+ query = query.replace(/\n/g, " ");
29826
+ query = query.replace(/\s+/g, " ");
29827
+ query = query.trim();
29828
+ // lookup id from pr cache using args.branch
29829
+ const state = Store.getState();
29830
+ const cache_pr = state.pr[args.branch];
29831
+ invariant(cache_pr, "cache_pr must exist");
29832
+ const command_parts = [
29833
+ `gh api graphql -F id="${cache_pr.id}" -f query='${query}'`,
29834
+ ];
29781
29835
  const command = command_parts.join(" ");
29782
29836
  const cli_result = await cli(command);
29783
29837
  if (cli_result.code !== 0) {
@@ -29785,7 +29839,7 @@ async function pr_edit(args) {
29785
29839
  }
29786
29840
  }
29787
29841
  // prettier-ignore
29788
- const JSON_FIELDS = "--json number,state,baseRefName,headRefName,commits,title,body,url";
29842
+ const JSON_FIELDS = "--json id,number,state,baseRefName,headRefName,commits,title,body,url,isDraft";
29789
29843
  // consistent handle gh cli commands returning json
29790
29844
  // redirect to tmp file to avoid scrollback overflow causing scrollback to be cleared
29791
29845
  async function gh_json(command) {
@@ -29796,7 +29850,7 @@ async function gh_json(command) {
29796
29850
  return new Error(cli_result.output);
29797
29851
  }
29798
29852
  // read from file
29799
- const json_str = fs.readFileSync(tmp_pr_json, "utf-8");
29853
+ const json_str = await fs$1.readFile(tmp_pr_json, "utf-8");
29800
29854
  const json = JSON.parse(json_str);
29801
29855
  return json;
29802
29856
  }
@@ -29809,13 +29863,12 @@ function handle_error(output) {
29809
29863
  throw new Error(output);
29810
29864
  }
29811
29865
  // convert a string to a file for use via github cli `--body-file`
29812
- function body_file(body) {
29866
+ async function write_body_file(args) {
29867
+ invariant(args.body, "args.body must exist");
29813
29868
  const temp_dir = os.tmpdir();
29814
- const temp_path = path.join(temp_dir, "git-stack-body");
29815
- if (fs.existsSync(temp_path)) {
29816
- fs.rmSync(temp_path);
29817
- }
29818
- fs.writeFileSync(temp_path, body);
29869
+ const temp_path = path.join(temp_dir, `git-stack-body-${args.base}`);
29870
+ await safe_rm(temp_path);
29871
+ await fs$1.writeFile(temp_path, args.body);
29819
29872
  return temp_path;
29820
29873
  }
29821
29874
 
@@ -30097,9 +30150,9 @@ echo "------ END ------"
30097
30150
  echo "$GIT_REVISE_TODO" > "$git_revise_todo_path"
30098
30151
  `;
30099
30152
  // write script to temporary path
30100
- fs.writeFileSync(tmp_git_sequence_editor_path, GIT_SEQUENCE_EDITOR_SCRIPT);
30153
+ await fs$1.writeFile(tmp_git_sequence_editor_path, GIT_SEQUENCE_EDITOR_SCRIPT);
30101
30154
  // ensure script is executable
30102
- fs.chmodSync(tmp_git_sequence_editor_path, "755");
30155
+ await fs$1.chmod(tmp_git_sequence_editor_path, "755");
30103
30156
  const git_revise_todo = GitReviseTodo(args);
30104
30157
  // execute cli with temporary git sequence editor script
30105
30158
  // revise from merge base to pick correct commits
@@ -30498,10 +30551,10 @@ function encode(value) {
30498
30551
  return result.padStart(max_char_size, "=");
30499
30552
  }
30500
30553
 
30501
- function Rebase$1() {
30502
- return (reactExports.createElement(Await, { function: Rebase$1.run, fallback: reactExports.createElement(Text, { color: colors.yellow }, "Rebasing commits\u2026") }));
30554
+ function Rebase() {
30555
+ return (reactExports.createElement(Await, { function: Rebase.run, fallback: reactExports.createElement(Text, { color: colors.yellow }, "Rebasing commits\u2026") }));
30503
30556
  }
30504
- Rebase$1.run = async function run() {
30557
+ Rebase.run = async function run() {
30505
30558
  const state = Store.getState();
30506
30559
  const actions = state.actions;
30507
30560
  const branch_name = state.branch_name;
@@ -30555,9 +30608,8 @@ Rebase$1.run = async function run() {
30555
30608
  const sha_list = picked_commit_list.map((commit) => commit.sha).join(" ");
30556
30609
  await cli(`git cherry-pick --keep-redundant-commits ${sha_list}`);
30557
30610
  }
30558
- // after all commits have been cherry-picked and amended
30559
- // move the branch pointer to the newly created temporary branch
30560
- // now we are locally in sync with github and on the original branch
30611
+ // after all commits have been cherry-picked move the pointer
30612
+ // of original branch to the newly created temporary branch
30561
30613
  await cli(`git branch -f ${branch_name} ${temp_branch_name}`);
30562
30614
  restore_git();
30563
30615
  const next_commit_range = await range();
@@ -30585,8 +30637,6 @@ Rebase$1.run = async function run() {
30585
30637
  // trying to use `await cli(...)` here will silently fail since
30586
30638
  // all children processes receive the SIGINT signal
30587
30639
  const spawn_options = { ignoreExitCode: true };
30588
- // always clean up any patch files
30589
- cli.sync(`rm ${PATCH_FILE$1}`, spawn_options);
30590
30640
  // always hard reset and clean to allow subsequent checkout
30591
30641
  // if there are files checkout will fail and cascade fail subsequent commands
30592
30642
  cli.sync(`git reset --hard`, spawn_options);
@@ -30595,12 +30645,6 @@ Rebase$1.run = async function run() {
30595
30645
  cli.sync(`git checkout ${branch_name}`, spawn_options);
30596
30646
  // ...and cleanup temporary branch
30597
30647
  cli.sync(`git branch -D ${temp_branch_name}`, spawn_options);
30598
- if (commit_range) {
30599
- // ...and cleanup pr group branches
30600
- for (const group of commit_range.group_list) {
30601
- cli.sync(`git branch -D ${group.id}`, spawn_options);
30602
- }
30603
- }
30604
30648
  // restore back to original dir
30605
30649
  if (fs.existsSync(cwd)) {
30606
30650
  process.chdir(cwd);
@@ -30620,10 +30664,9 @@ Rebase$1.run = async function run() {
30620
30664
  actions.exit(6);
30621
30665
  }
30622
30666
  };
30623
- const PATCH_FILE$1 = "git-stack-cli-patch.patch";
30624
30667
 
30625
30668
  function LocalMergeRebase() {
30626
- return reactExports.createElement(Rebase$1, null);
30669
+ return reactExports.createElement(Rebase, null);
30627
30670
  }
30628
30671
 
30629
30672
  function write(args) {
@@ -30796,44 +30839,36 @@ async function run$6() {
30796
30839
  // must perform rebase from repo root for applying git patch
30797
30840
  process.chdir(repo_root);
30798
30841
  await cli(`pwd`);
30799
- if (argv["rebase"] === "git-revise") {
30800
- await rebase_git_revise();
30801
- }
30802
- else {
30803
- await rebase_cherry_pick();
30804
- }
30805
- // after all commits have been cherry-picked and amended
30806
- // move the branch pointer to the newly created temporary branch
30807
- // now we are in locally in sync with github and on the original branch
30842
+ actions.output(reactExports.createElement(Text, { color: colors.yellow, wrap: "truncate-end" }, "Rebasing\u2026"));
30843
+ // create temporary branch
30844
+ await cli(`git checkout -b ${temp_branch_name}`);
30845
+ await GitReviseTodo.execute({
30846
+ rebase_group_index,
30847
+ rebase_merge_base,
30848
+ commit_range,
30849
+ });
30850
+ // after all commits have been modified move the pointer
30851
+ // of original branch to the newly created temporary branch
30808
30852
  await cli(`git branch -f ${branch_name} ${temp_branch_name}`);
30853
+ if (argv.sync) {
30854
+ await sync_github();
30855
+ }
30809
30856
  restore_git();
30810
30857
  actions.set((state) => {
30811
30858
  state.step = "post-rebase-status";
30812
30859
  });
30813
30860
  }
30814
30861
  catch (err) {
30815
- actions.error("Unable to rebase.");
30816
30862
  if (err instanceof Error) {
30817
- if (actions.isDebug()) {
30818
- actions.error(err.message);
30819
- }
30863
+ actions.error(err.message);
30864
+ }
30865
+ actions.error("Unable to rebase.");
30866
+ if (!argv.verbose) {
30867
+ actions.error("Try again with `--verbose` to see more information.");
30820
30868
  }
30821
30869
  handle_exit();
30822
30870
  }
30823
- async function rebase_git_revise() {
30824
- actions.debug(`rebase_git_revise`);
30825
- actions.output(reactExports.createElement(Text, { color: colors.yellow, wrap: "truncate-end" }, "Rebasing\u2026"));
30826
- // create temporary branch
30827
- await cli(`git checkout -b ${temp_branch_name}`);
30828
- await GitReviseTodo.execute({
30829
- rebase_group_index,
30830
- rebase_merge_base,
30831
- commit_range,
30832
- });
30833
- // early return since we do not need to sync
30834
- if (!argv.sync) {
30835
- return;
30836
- }
30871
+ async function sync_github() {
30837
30872
  // in order to sync we walk from rebase_group_index to HEAD
30838
30873
  // checking out each group and syncing to github
30839
30874
  // start from HEAD and work backward to rebase_group_index
@@ -30855,80 +30890,97 @@ async function run$6() {
30855
30890
  // push group and lookback_index onto front of push_group_list
30856
30891
  push_group_list.unshift({ group, lookback_index });
30857
30892
  }
30893
+ actions.output(reactExports.createElement(FormatText, { wrapper: reactExports.createElement(Text, { color: colors.yellow, wrap: "truncate-end" }), message: "Syncing {group_list}\u2026", values: {
30894
+ group_list: (reactExports.createElement(reactExports.Fragment, null, push_group_list.map((push_group) => {
30895
+ const group = push_group.group;
30896
+ return (reactExports.createElement(Brackets, { key: group.id }, group.pr?.title || group.title || group.id));
30897
+ }))),
30898
+ } }));
30899
+ // for all push targets in push_group_list
30900
+ // things that can be done in parallel are grouped by numbers
30901
+ //
30902
+ // -----------------------------------
30903
+ // 1 (before_push) temp mark draft
30904
+ // --------------------------------------
30905
+ // 2 push simultaneously to github
30906
+ // --------------------------------------
30907
+ // 2 create PR / edit PR
30908
+ // 2 (after_push) undo temp mark draft
30909
+ // --------------------------------------
30910
+ const before_push_tasks = [];
30911
+ for (const push_group of push_group_list) {
30912
+ before_push_tasks.push(before_push(push_group));
30913
+ }
30914
+ await Promise.all(before_push_tasks);
30915
+ const push_target_list = push_group_list.map((push_group) => {
30916
+ return `HEAD~${push_group.lookback_index}:${push_group.group.id}`;
30917
+ });
30918
+ const push_target_args = push_target_list.join(" ");
30919
+ const git_push_command = [`git push -f origin ${push_target_args}`];
30920
+ if (argv.verify === false) {
30921
+ git_push_command.push("--no-verify");
30922
+ }
30923
+ await cli(git_push_command);
30858
30924
  const pr_url_list = commit_range.group_list.map(get_group_url);
30859
- // use push_group_list to sync each group HEAD to github
30925
+ const after_push_tasks = [];
30860
30926
  for (const push_group of push_group_list) {
30861
- const { group } = push_group;
30862
- // move to temporary branch for resetting to lookback_index to create PR
30863
- await cli(`git checkout -b ${group.id}`);
30864
- // prepare branch for sync, reset to commit at lookback index
30865
- await cli(`git reset --hard HEAD~${push_group.lookback_index}`);
30866
- await sync_group_github({ group, pr_url_list, skip_checkout: true });
30867
- // done, remove temp push branch and move back to temp branch
30868
- await cli(`git checkout ${temp_branch_name}`);
30869
- await cli(`git branch -D ${group.id}`);
30927
+ const group = push_group.group;
30928
+ after_push_tasks.push(after_push({ group, pr_url_list }));
30870
30929
  }
30930
+ await Promise.all(after_push_tasks);
30871
30931
  // finally, ensure all prs have the updated stack table from updated pr_url_list
30872
- await update_pr_tables(pr_url_list);
30873
- }
30874
- async function rebase_cherry_pick() {
30875
- actions.debug("rebase_cherry_pick");
30876
- // create temporary branch based on merge base
30877
- await cli(`git checkout -b ${temp_branch_name} ${rebase_merge_base}`);
30878
- const pr_url_list = commit_range.group_list.map(get_group_url);
30879
- for (let i = rebase_group_index; i < commit_range.group_list.length; i++) {
30932
+ for (let i = 0; i < commit_range.group_list.length; i++) {
30880
30933
  const group = commit_range.group_list[i];
30934
+ // use the updated pr_url_list to get the actual selected_url
30935
+ const selected_url = pr_url_list[i];
30881
30936
  invariant(group.base, "group.base must exist");
30882
- actions.output(reactExports.createElement(FormatText, { wrapper: reactExports.createElement(Text, { color: colors.yellow, wrap: "truncate-end" }), message: "Rebasing {group}\u2026", values: {
30883
- group: (reactExports.createElement(Brackets, null, group.pr?.title || group.title || group.id)),
30884
- } }));
30885
- // cherry-pick and amend commits one by one
30886
- for (const commit of group.commits) {
30887
- // ensure clean base to avoid conflicts when applying patch
30888
- await cli(`git clean -fd`);
30889
- // create, apply and cleanup patch
30890
- await cli(`git format-patch -1 ${commit.sha} --stdout > ${PATCH_FILE}`);
30891
- await cli(`git apply ${PATCH_FILE}`);
30892
- await cli(`rm ${PATCH_FILE}`);
30893
- // add all changes to stage
30894
- await cli(`git add --all`);
30895
- const metadata = { id: group.id, title: group.title };
30896
- const new_message = write$1(commit.full_message, metadata);
30897
- const git_commit_comand = [`git commit -m "${new_message}"`];
30898
- if (argv.verify === false) {
30899
- git_commit_comand.push("--no-verify");
30900
- }
30901
- await cli(git_commit_comand);
30937
+ const body = group.pr?.body || DEFAULT_PR_BODY;
30938
+ const update_body = write({
30939
+ body,
30940
+ pr_url_list,
30941
+ selected_url,
30942
+ });
30943
+ if (update_body === body) {
30944
+ actions.debug(`Skipping body update for ${selected_url}`);
30945
+ }
30946
+ else {
30947
+ actions.debug(`Update body for ${selected_url}`);
30948
+ await pr_edit({
30949
+ branch: group.id,
30950
+ base: group.base,
30951
+ body: update_body,
30952
+ });
30902
30953
  }
30903
- await sync_group_github({ group, pr_url_list, skip_checkout: false });
30904
30954
  }
30905
- // finally, ensure all prs have the updated stack table from updated pr_url_list
30906
- await update_pr_tables(pr_url_list);
30907
30955
  }
30908
- async function sync_group_github(args) {
30909
- if (!argv.sync) {
30910
- return;
30911
- }
30912
- const { group, pr_url_list } = args;
30956
+ async function before_push(args) {
30957
+ const { group } = args;
30913
30958
  invariant(group.base, "group.base must exist");
30914
- actions.output(reactExports.createElement(FormatText, { wrapper: reactExports.createElement(Text, { color: colors.yellow, wrap: "truncate-end" }), message: "Syncing {group}\u2026", values: {
30915
- group: (reactExports.createElement(Brackets, null, group.pr?.title || group.title || group.id)),
30916
- } }));
30959
+ // we may temporarily mark PR as a draft before editing it
30960
+ // if it is not already a draft PR, to avoid notification spam
30961
+ let is_temp_draft = !group.pr?.isDraft;
30917
30962
  // before pushing reset base to master temporarily
30918
30963
  // avoid accidentally pointing to orphaned parent commit
30919
30964
  // should hopefully fix issues where a PR includes a bunch of commits after pushing
30920
30965
  if (group.pr) {
30966
+ if (!group.pr.isDraft) {
30967
+ is_temp_draft = true;
30968
+ }
30969
+ if (is_temp_draft) {
30970
+ await pr_draft({
30971
+ branch: group.id,
30972
+ draft: true,
30973
+ });
30974
+ }
30921
30975
  await pr_edit({
30922
30976
  branch: group.id,
30923
30977
  base: master_branch,
30924
30978
  });
30925
30979
  }
30926
- // push to origin since github requires commit shas to line up perfectly
30927
- const git_push_command = [`git push -f origin HEAD:${group.id}`];
30928
- if (argv.verify === false) {
30929
- git_push_command.push("--no-verify");
30930
- }
30931
- await cli(git_push_command);
30980
+ }
30981
+ async function after_push(args) {
30982
+ const { group, pr_url_list } = args;
30983
+ invariant(group.base, "group.base must exist");
30932
30984
  const selected_url = get_group_url(group);
30933
30985
  if (group.pr) {
30934
30986
  // ensure base matches pr in github
@@ -30941,14 +30993,18 @@ async function run$6() {
30941
30993
  selected_url,
30942
30994
  }),
30943
30995
  });
30996
+ // we may temporarily mark PR as a draft before editing it
30997
+ // if it is not already a draft PR, to avoid notification spam
30998
+ let is_temp_draft = !group.pr?.isDraft;
30999
+ if (is_temp_draft) {
31000
+ // mark pr as ready for review again
31001
+ await pr_draft({
31002
+ branch: group.id,
31003
+ draft: false,
31004
+ });
31005
+ }
30944
31006
  }
30945
31007
  else {
30946
- if (!args.skip_checkout) {
30947
- // delete local group branch if leftover
30948
- await cli(`git branch -D ${group.id}`, { ignoreExitCode: true });
30949
- // move to temporary branch for creating pr
30950
- await cli(`git checkout -b ${group.id}`);
30951
- }
30952
31008
  // create pr in github
30953
31009
  const pr_url = await pr_create({
30954
31010
  branch: group.id,
@@ -30967,38 +31023,6 @@ async function run$6() {
30967
31023
  pr_url_list[i] = pr_url;
30968
31024
  }
30969
31025
  }
30970
- // move back to temp branch
30971
- if (!args.skip_checkout) {
30972
- await cli(`git checkout ${temp_branch_name}`);
30973
- }
30974
- }
30975
- }
30976
- async function update_pr_tables(pr_url_list) {
30977
- if (!argv.sync) {
30978
- return;
30979
- }
30980
- for (let i = 0; i < commit_range.group_list.length; i++) {
30981
- const group = commit_range.group_list[i];
30982
- // use the updated pr_url_list to get the actual selected_url
30983
- const selected_url = pr_url_list[i];
30984
- invariant(group.base, "group.base must exist");
30985
- const body = group.pr?.body || DEFAULT_PR_BODY;
30986
- const update_body = write({
30987
- body,
30988
- pr_url_list,
30989
- selected_url,
30990
- });
30991
- if (update_body === body) {
30992
- actions.debug(`Skipping body update for ${selected_url}`);
30993
- }
30994
- else {
30995
- actions.debug(`Update body for ${selected_url}`);
30996
- await pr_edit({
30997
- branch: group.id,
30998
- base: group.base,
30999
- body: update_body,
31000
- });
31001
- }
31002
31026
  }
31003
31027
  }
31004
31028
  // cleanup git operations if cancelled during manual rebase
@@ -31007,8 +31031,6 @@ async function run$6() {
31007
31031
  // trying to use `await cli(...)` here will silently fail since
31008
31032
  // all children processes receive the SIGINT signal
31009
31033
  const spawn_options = { ignoreExitCode: true };
31010
- // always clean up any patch files
31011
- cli.sync(`rm ${PATCH_FILE}`, spawn_options);
31012
31034
  // always hard reset and clean to allow subsequent checkout
31013
31035
  // if there are files checkout will fail and cascade fail subsequent commands
31014
31036
  cli.sync(`git reset --hard`, spawn_options);
@@ -31017,12 +31039,6 @@ async function run$6() {
31017
31039
  cli.sync(`git checkout ${branch_name}`, spawn_options);
31018
31040
  // ...and cleanup temporary branch
31019
31041
  cli.sync(`git branch -D ${temp_branch_name}`, spawn_options);
31020
- if (commit_range) {
31021
- // ...and cleanup pr group branches
31022
- for (const group of commit_range.group_list) {
31023
- cli.sync(`git branch -D ${group.id}`, spawn_options);
31024
- }
31025
- }
31026
31042
  // restore back to original dir
31027
31043
  if (fs.existsSync(cwd)) {
31028
31044
  process.chdir(cwd);
@@ -31043,7 +31059,6 @@ async function run$6() {
31043
31059
  }
31044
31060
  }
31045
31061
  const get_group_url = (group) => group.pr?.url || group.id;
31046
- const PATCH_FILE = "git-stack-cli-patch.patch";
31047
31062
 
31048
31063
  function Table(props) {
31049
31064
  if (!props.data.length) {
@@ -31275,8 +31290,8 @@ async function run$4() {
31275
31290
  // ./docs/pull_request_template.md
31276
31291
  for (const key of PR_TEMPLATE_KEY_LIST) {
31277
31292
  const pr_template_fn = PR_TEMPLATE[key];
31278
- if (fs.existsSync(pr_template_fn(repo_root))) {
31279
- pr_template_body = fs.readFileSync(pr_template_fn(repo_root), "utf-8");
31293
+ if (await safe_exists(pr_template_fn(repo_root))) {
31294
+ pr_template_body = await fs$1.readFile(pr_template_fn(repo_root), "utf-8");
31280
31295
  actions.output(reactExports.createElement(FormatText, { wrapper: reactExports.createElement(Text, { color: colors.yellow }), message: "Using PR template {pr_filepath}", values: {
31281
31296
  pr_filepath: reactExports.createElement(Brackets, null, pr_template_fn("")),
31282
31297
  } }));
@@ -31285,8 +31300,8 @@ async function run$4() {
31285
31300
  }
31286
31301
  // ./.github/PULL_REQUEST_TEMPLATE/*.md
31287
31302
  let pr_templates = [];
31288
- if (fs.existsSync(PR_TEMPLATE.TemplateDir(repo_root))) {
31289
- pr_templates = fs.readdirSync(PR_TEMPLATE.TemplateDir(repo_root));
31303
+ if (await safe_exists(PR_TEMPLATE.TemplateDir(repo_root))) {
31304
+ pr_templates = await fs$1.readdir(PR_TEMPLATE.TemplateDir(repo_root));
31290
31305
  }
31291
31306
  // check if repo has multiple pr templates
31292
31307
  actions.set((state) => {
@@ -31893,8 +31908,8 @@ function RebaseCheck(props) {
31893
31908
  try {
31894
31909
  const git_dir = (await cli(`git rev-parse --absolute-git-dir`)).stdout;
31895
31910
  let is_rebase = false;
31896
- is_rebase ||= fs.existsSync(path.join(git_dir, "rebase-apply"));
31897
- is_rebase ||= fs.existsSync(path.join(git_dir, "rebase-merge"));
31911
+ is_rebase ||= await safe_exists(path.join(git_dir, "rebase-apply"));
31912
+ is_rebase ||= await safe_exists(path.join(git_dir, "rebase-merge"));
31898
31913
  const status = is_rebase ? "prompt" : "done";
31899
31914
  patch({ status });
31900
31915
  }
@@ -32101,7 +32116,7 @@ function MaybeMain() {
32101
32116
  else if (positional_list.has("rebase")) {
32102
32117
  return (reactExports.createElement(GatherMetadata, null,
32103
32118
  reactExports.createElement(LocalCommitStatus, null,
32104
- reactExports.createElement(Rebase$1, null))));
32119
+ reactExports.createElement(Rebase, null))));
32105
32120
  }
32106
32121
  return (reactExports.createElement(DirtyCheck, null,
32107
32122
  !argv.verbose ? null : reactExports.createElement(GithubApiError, null),
@@ -32440,14 +32455,14 @@ function ui (opts) {
32440
32455
 
32441
32456
  function escalade (start, callback) {
32442
32457
  let dir = path$1.resolve('.', start);
32443
- let tmp, stats = fs$1.statSync(dir);
32458
+ let tmp, stats = fs$2.statSync(dir);
32444
32459
 
32445
32460
  if (!stats.isDirectory()) {
32446
32461
  dir = path$1.dirname(dir);
32447
32462
  }
32448
32463
 
32449
32464
  while (true) {
32450
- tmp = callback(dir, fs$1.readdirSync(dir));
32465
+ tmp = callback(dir, fs$2.readdirSync(dir));
32451
32466
  if (tmp) return path$1.resolve(dir, tmp);
32452
32467
  dir = path$1.dirname(tmp = dir);
32453
32468
  if (tmp === dir) break;
@@ -33653,7 +33668,7 @@ const parser = new YargsParser({
33653
33668
  }
33654
33669
  else if (path.match(/\.json$/)) {
33655
33670
  // Addresses: https://github.com/yargs/yargs/issues/2040
33656
- return JSON.parse(fs$1.readFileSync(path, 'utf8'));
33671
+ return JSON.parse(fs$2.readFileSync(path, 'utf8'));
33657
33672
  }
33658
33673
  else {
33659
33674
  throw Error('only .json config files are supported in ESM');
@@ -33701,14 +33716,14 @@ class YError extends Error {
33701
33716
 
33702
33717
  var shim$3 = {
33703
33718
  fs: {
33704
- readFileSync: fs$1.readFileSync,
33705
- writeFile: fs$1.writeFile
33719
+ readFileSync: fs$2.readFileSync,
33720
+ writeFile: fs$2.writeFile
33706
33721
  },
33707
33722
  format: util.format,
33708
33723
  resolve: path$1.resolve,
33709
33724
  exists: (file) => {
33710
33725
  try {
33711
- return fs$1.statSync(file).isFile();
33726
+ return fs$2.statSync(file).isFile();
33712
33727
  }
33713
33728
  catch (err) {
33714
33729
  return false;
@@ -33939,7 +33954,7 @@ var shim$1 = {
33939
33954
  nextTick: process.nextTick,
33940
33955
  stdColumns: typeof process.stdout.columns !== 'undefined' ? process.stdout.columns : null
33941
33956
  },
33942
- readFileSync: fs$1.readFileSync,
33957
+ readFileSync: fs$2.readFileSync,
33943
33958
  require: () => {
33944
33959
  throw new YError(REQUIRE_ERROR)
33945
33960
  },
@@ -37429,15 +37444,11 @@ async function command() {
37429
37444
  .wrap(123)
37430
37445
  // disallow unknown options
37431
37446
  .strict()
37432
- .version("1.11.7" )
37447
+ .version("1.13.0" )
37433
37448
  .showHidden("show-hidden", "Show hidden options via `git stack help --show-hidden`")
37434
37449
  .help("help", "Show usage via `git stack help`")
37435
37450
  .argv;
37436
37451
  }
37437
- const Rebase = Object.freeze({
37438
- "git-revise": "git-revise",
37439
- "cherry-pick": "cherry-pick",
37440
- });
37441
37452
  const GlobalOptions = {
37442
37453
  verbose: {
37443
37454
  type: "boolean",
@@ -37470,16 +37481,6 @@ const DefaultOptions = {
37470
37481
  default: true,
37471
37482
  description: "Run git hooks such as pre-commit and pre-push, disable with --no-verify",
37472
37483
  },
37473
- "rebase": {
37474
- type: "string",
37475
- choices: [Rebase["git-revise"], Rebase["cherry-pick"]],
37476
- default: Rebase["git-revise"],
37477
- description: [
37478
- "Strategy used for syncing branches",
37479
- `${Rebase["git-revise"]}: perform faster in-memory rebase`,
37480
- `${Rebase["cherry-pick"]}: use disk and incrementally rebase each commit`,
37481
- ].join(" | "),
37482
- },
37483
37484
  "update": {
37484
37485
  type: "boolean",
37485
37486
  alias: ["u", "upgrade"],