git-stack-cli 1.13.1 → 1.14.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.
- package/README.md +13 -0
- package/dist/cjs/index.cjs +80 -28
- package/package.json +1 -1
- package/src/app/SelectCommitRanges.tsx +14 -1
- package/src/app/SyncGithub.tsx +19 -3
- package/src/command.ts +11 -5
- package/src/core/github.tsx +29 -7
- package/src/types/global.d.ts +1 -0
package/README.md
CHANGED
|
@@ -83,6 +83,19 @@ To update your local branch with the latest changes in the remote branch (e.g. `
|
|
|
83
83
|
git stack rebase
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
+
### Customizing branch name
|
|
87
|
+
|
|
88
|
+
By default `git stack` generates a unique branch name such as `gs-3cmrMBSUj`.
|
|
89
|
+
|
|
90
|
+
You can specify a prefix for the generated branch name by using either the environment variable or the command line option.
|
|
91
|
+
In the example below branches would be generated such as `dev/magus/gs-3cmrMBSUj`.
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
GIT_STACK_BRANCH_PREFIX="dev/magus/" git stack
|
|
95
|
+
|
|
96
|
+
git stack --branch-prefix="dev/magus/"
|
|
97
|
+
```
|
|
98
|
+
|
|
86
99
|
## Why?
|
|
87
100
|
|
|
88
101
|
The goal of `git stack` is to combine the **simplicity of developing in a single branch** in order to **preserve your commit history** while also **grouping commits into pull requests for code review**.
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -14912,7 +14912,7 @@ var isSafeInteger = hasNativeIsSafeInteger
|
|
|
14912
14912
|
// IE11 does not support y and u.
|
|
14913
14913
|
var REGEX_SUPPORTS_U_AND_Y = true;
|
|
14914
14914
|
try {
|
|
14915
|
-
var re = RE$
|
|
14915
|
+
var re = RE$6('([^\\p{White_Space}\\p{Pattern_Syntax}]*)', 'yu');
|
|
14916
14916
|
/**
|
|
14917
14917
|
* legacy Edge or Xbox One browser
|
|
14918
14918
|
* Unicode flag support: supported
|
|
@@ -15009,14 +15009,14 @@ var trimEnd = hasTrimEnd
|
|
|
15009
15009
|
return s.replace(SPACE_SEPARATOR_END_REGEX, '');
|
|
15010
15010
|
};
|
|
15011
15011
|
// Prevent minifier to translate new RegExp to literal form that might cause syntax error on IE11.
|
|
15012
|
-
function RE$
|
|
15012
|
+
function RE$6(s, flag) {
|
|
15013
15013
|
return new RegExp(s, flag);
|
|
15014
15014
|
}
|
|
15015
15015
|
// #endregion
|
|
15016
15016
|
var matchIdentifierAtIndex;
|
|
15017
15017
|
if (REGEX_SUPPORTS_U_AND_Y) {
|
|
15018
15018
|
// Native
|
|
15019
|
-
var IDENTIFIER_PREFIX_RE_1 = RE$
|
|
15019
|
+
var IDENTIFIER_PREFIX_RE_1 = RE$6('([^\\p{White_Space}\\p{Pattern_Syntax}]*)', 'yu');
|
|
15020
15020
|
matchIdentifierAtIndex = function matchIdentifierAtIndex(s, index) {
|
|
15021
15021
|
var _a;
|
|
15022
15022
|
IDENTIFIER_PREFIX_RE_1.lastIndex = index;
|
|
@@ -26941,15 +26941,15 @@ match_group.safe = (value, re, group) => {
|
|
|
26941
26941
|
|
|
26942
26942
|
function auth_status(output) {
|
|
26943
26943
|
let username;
|
|
26944
|
-
username = match_group.safe(output, RE$
|
|
26944
|
+
username = match_group.safe(output, RE$5.logged_in_as, "username");
|
|
26945
26945
|
if (username)
|
|
26946
26946
|
return username;
|
|
26947
|
-
username = match_group.safe(output, RE$
|
|
26947
|
+
username = match_group.safe(output, RE$5.logged_in_account, "username");
|
|
26948
26948
|
if (username)
|
|
26949
26949
|
return username;
|
|
26950
26950
|
return null;
|
|
26951
26951
|
}
|
|
26952
|
-
const RE$
|
|
26952
|
+
const RE$5 = {
|
|
26953
26953
|
// Logged in to github.com as magus
|
|
26954
26954
|
logged_in_as: /Logged in to github.com as (?<username>[^\s]+)/,
|
|
26955
26955
|
logged_in_account: /Logged in to github.com account (?<username>[^\s]+)/,
|
|
@@ -29663,10 +29663,10 @@ var cloneDeep$1 = /*@__PURE__*/getDefaultExportFromCjs(cloneDeep_1);
|
|
|
29663
29663
|
// escape double-quote for cli
|
|
29664
29664
|
function safe_quote(value) {
|
|
29665
29665
|
let result = value;
|
|
29666
|
-
result = result.replace(RE$
|
|
29666
|
+
result = result.replace(RE$4.all_double_quote, '\\"');
|
|
29667
29667
|
return result;
|
|
29668
29668
|
}
|
|
29669
|
-
const RE$
|
|
29669
|
+
const RE$4 = {
|
|
29670
29670
|
all_double_quote: /"/g,
|
|
29671
29671
|
};
|
|
29672
29672
|
|
|
@@ -29684,12 +29684,12 @@ function write$1(message, values) {
|
|
|
29684
29684
|
}
|
|
29685
29685
|
function read(message) {
|
|
29686
29686
|
const values = { id: null, title: null };
|
|
29687
|
-
const match_id = message.match(RE$
|
|
29687
|
+
const match_id = message.match(RE$3.stack_id);
|
|
29688
29688
|
if (match_id?.groups) {
|
|
29689
29689
|
values.id = match_id.groups["id"];
|
|
29690
29690
|
invariant(values.id, "id must exist");
|
|
29691
29691
|
}
|
|
29692
|
-
const match_title = message.match(RE$
|
|
29692
|
+
const match_title = message.match(RE$3.group_title);
|
|
29693
29693
|
if (match_title?.groups) {
|
|
29694
29694
|
values.title = match_title.groups["title"];
|
|
29695
29695
|
}
|
|
@@ -29698,8 +29698,8 @@ function read(message) {
|
|
|
29698
29698
|
function remove(message) {
|
|
29699
29699
|
let result = message;
|
|
29700
29700
|
// remove metadata
|
|
29701
|
-
result = result.replace(new RegExp(RE$
|
|
29702
|
-
result = result.replace(new RegExp(RE$
|
|
29701
|
+
result = result.replace(new RegExp(RE$3.stack_id, "gmi"), "");
|
|
29702
|
+
result = result.replace(new RegExp(RE$3.group_title, "gmi"), "");
|
|
29703
29703
|
result = result.trimEnd();
|
|
29704
29704
|
return result;
|
|
29705
29705
|
}
|
|
@@ -29711,7 +29711,7 @@ const TEMPLATE$1 = {
|
|
|
29711
29711
|
return `git-stack-title: ${title}`;
|
|
29712
29712
|
},
|
|
29713
29713
|
};
|
|
29714
|
-
const RE$
|
|
29714
|
+
const RE$3 = {
|
|
29715
29715
|
// https://regex101.com/r/wLmGVq/1
|
|
29716
29716
|
stack_id: new RegExp(`${TEMPLATE$1.stack_id("(?<id>[^\\s]+)")}`, "i"),
|
|
29717
29717
|
group_title: new RegExp(TEMPLATE$1.group_title("(?<title>[^\\n^\\r]+)"), "i"),
|
|
@@ -29782,11 +29782,23 @@ async function pr_status(branch) {
|
|
|
29782
29782
|
}
|
|
29783
29783
|
async function pr_create(args) {
|
|
29784
29784
|
const title = safe_quote(args.title);
|
|
29785
|
-
|
|
29785
|
+
// explicit refs/heads head branch to avoid creation failing
|
|
29786
|
+
//
|
|
29787
|
+
// ❯ gh pr create --head origin/gs-ED2etrzv2 --base gs-6LAx-On45 --title="2024-01-05 test" --body=""
|
|
29788
|
+
// 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)
|
|
29789
|
+
//
|
|
29790
|
+
// https://github.com/cli/cli/issues/5465
|
|
29791
|
+
let command_parts = [
|
|
29792
|
+
"gh pr create",
|
|
29793
|
+
`--head refs/heads/${args.branch}`,
|
|
29794
|
+
`--base ${args.base}`,
|
|
29795
|
+
`--title="${title}"`,
|
|
29796
|
+
`--body="${args.body}"`,
|
|
29797
|
+
];
|
|
29786
29798
|
if (args.draft) {
|
|
29787
|
-
|
|
29799
|
+
command_parts.push("--draft");
|
|
29788
29800
|
}
|
|
29789
|
-
const cli_result = await cli(
|
|
29801
|
+
const cli_result = await cli(command_parts);
|
|
29790
29802
|
if (cli_result.code !== 0) {
|
|
29791
29803
|
handle_error(cli_result.output);
|
|
29792
29804
|
return null;
|
|
@@ -29799,8 +29811,7 @@ async function pr_edit(args) {
|
|
|
29799
29811
|
const body_file = await write_body_file(args);
|
|
29800
29812
|
command_parts.push(`--body-file="${body_file}"`);
|
|
29801
29813
|
}
|
|
29802
|
-
const
|
|
29803
|
-
const cli_result = await cli(command);
|
|
29814
|
+
const cli_result = await cli(command_parts);
|
|
29804
29815
|
if (cli_result.code !== 0) {
|
|
29805
29816
|
handle_error(cli_result.output);
|
|
29806
29817
|
}
|
|
@@ -29867,11 +29878,19 @@ function handle_error(output) {
|
|
|
29867
29878
|
async function write_body_file(args) {
|
|
29868
29879
|
invariant(args.body, "args.body must exist");
|
|
29869
29880
|
const temp_dir = os.tmpdir();
|
|
29870
|
-
|
|
29881
|
+
// ensure unique filename is safe for filesystem
|
|
29882
|
+
// base (group id) might contain slashes, e.g. dev/magus/gs-3cmrMBSUj
|
|
29883
|
+
// the flashes would mess up the filesystem path to this file
|
|
29884
|
+
let temp_filename = `git-stack-body-${args.base}`;
|
|
29885
|
+
temp_filename = temp_filename.replace(RE$2.non_alphanumeric_dash, "-");
|
|
29886
|
+
const temp_path = path.join(temp_dir, temp_filename);
|
|
29871
29887
|
await safe_rm(temp_path);
|
|
29872
29888
|
await fs$1.writeFile(temp_path, args.body);
|
|
29873
29889
|
return temp_path;
|
|
29874
29890
|
}
|
|
29891
|
+
const RE$2 = {
|
|
29892
|
+
non_alphanumeric_dash: /[^a-zA-Z0-9_-]+/g,
|
|
29893
|
+
};
|
|
29875
29894
|
|
|
29876
29895
|
async function range(commit_group_map) {
|
|
29877
29896
|
const master_branch = Store.getState().master_branch;
|
|
@@ -31528,8 +31547,20 @@ function SelectCommitRangesInternal(props) {
|
|
|
31528
31547
|
reactExports.createElement(FormatText, { wrapper: reactExports.createElement(Text, { color: colors.gray }), message: "Press {enter} to toggle commit selection", values: {
|
|
31529
31548
|
enter: (reactExports.createElement(Text, { bold: true, color: colors.green }, SYMBOL.enter)),
|
|
31530
31549
|
} }))));
|
|
31550
|
+
function get_group_id() {
|
|
31551
|
+
let branch_prefix = "";
|
|
31552
|
+
// branch prefix via cli flag or env var
|
|
31553
|
+
// cli flag takes precedence since it is more explicit
|
|
31554
|
+
if (argv["branch-prefix"]) {
|
|
31555
|
+
branch_prefix = argv["branch-prefix"];
|
|
31556
|
+
}
|
|
31557
|
+
else if (process.env.GIT_STACK_BRANCH_PREFIX) {
|
|
31558
|
+
branch_prefix = process.env.GIT_STACK_BRANCH_PREFIX;
|
|
31559
|
+
}
|
|
31560
|
+
return `${branch_prefix}${gs_short_id()}`;
|
|
31561
|
+
}
|
|
31531
31562
|
function submit_group_input(title) {
|
|
31532
|
-
const id =
|
|
31563
|
+
const id = get_group_id();
|
|
31533
31564
|
actions.output(reactExports.createElement(FormatText, { wrapper: reactExports.createElement(Text, { dimColor: true }), message: "Created new group {group} {note}", values: {
|
|
31534
31565
|
group: reactExports.createElement(Brackets, null, title),
|
|
31535
31566
|
note: reactExports.createElement(Parens, null, id),
|
|
@@ -31782,7 +31813,6 @@ async function run$3(args) {
|
|
|
31782
31813
|
before_push_tasks.push(before_push({ group }));
|
|
31783
31814
|
}
|
|
31784
31815
|
await Promise.all(before_push_tasks);
|
|
31785
|
-
// git push -f origin HEAD~6:OtVX7Qvrw HEAD~3:E63ytp5dj HEAD~2:gs-NBabNSjXA HEAD~1:gs-UGVJdKNoD HEAD~0:gs-6LAx-On4
|
|
31786
31816
|
const git_push_command = [`git push -f origin`];
|
|
31787
31817
|
if (argv.verify === false) {
|
|
31788
31818
|
git_push_command.push("--no-verify");
|
|
@@ -31790,7 +31820,24 @@ async function run$3(args) {
|
|
|
31790
31820
|
for (const group of push_group_list) {
|
|
31791
31821
|
const last_commit = last$1(group.commits);
|
|
31792
31822
|
invariant(last_commit, "last_commit must exist");
|
|
31793
|
-
|
|
31823
|
+
// explicit refs/heads head branch to avoid push failing
|
|
31824
|
+
//
|
|
31825
|
+
// ❯ git push -f origin --no-verify f6e249051b4820a03deb957ddebc19acfd7dfd7c:gs-ED2etrzv2
|
|
31826
|
+
// error: The destination you provided is not a full refname (i.e.,
|
|
31827
|
+
// starting with "refs/"). We tried to guess what you meant by:
|
|
31828
|
+
//
|
|
31829
|
+
// - Looking for a ref that matches 'gs-ED2etrzv2' on the remote side.
|
|
31830
|
+
// - Checking if the <src> being pushed ('f6e249051b4820a03deb957ddebc19acfd7dfd7c')
|
|
31831
|
+
// is a ref in "refs/{heads,tags}/". If so we add a corresponding
|
|
31832
|
+
// refs/{heads,tags}/ prefix on the remote side.
|
|
31833
|
+
//
|
|
31834
|
+
// Neither worked, so we gave up. You must fully qualify the ref.
|
|
31835
|
+
// hint: The <src> part of the refspec is a commit object.
|
|
31836
|
+
// hint: Did you mean to create a new branch by pushing to
|
|
31837
|
+
// hint: 'f6e249051b4820a03deb957ddebc19acfd7dfd7c:refs/heads/gs-ED2etrzv2'?
|
|
31838
|
+
// error: failed to push some refs to 'github.com:magus/git-multi-diff-playground.git'
|
|
31839
|
+
//
|
|
31840
|
+
const target = `${last_commit.sha}:refs/heads/${group.id}`;
|
|
31794
31841
|
git_push_command.push(target);
|
|
31795
31842
|
}
|
|
31796
31843
|
await cli(git_push_command);
|
|
@@ -37573,7 +37620,7 @@ async function command() {
|
|
|
37573
37620
|
.wrap(123)
|
|
37574
37621
|
// disallow unknown options
|
|
37575
37622
|
.strict()
|
|
37576
|
-
.version("1.
|
|
37623
|
+
.version("1.14.0" )
|
|
37577
37624
|
.showHidden("show-hidden", "Show hidden options via `git stack help --show-hidden`")
|
|
37578
37625
|
.help("help", "Show usage via `git stack help`")
|
|
37579
37626
|
.argv;
|
|
@@ -37627,17 +37674,22 @@ const DefaultOptions = {
|
|
|
37627
37674
|
default: false,
|
|
37628
37675
|
description: "Open all PRs as drafts",
|
|
37629
37676
|
},
|
|
37630
|
-
"
|
|
37631
|
-
|
|
37632
|
-
|
|
37633
|
-
|
|
37634
|
-
description: "Write state to local json file for debugging",
|
|
37677
|
+
"branch-prefix": {
|
|
37678
|
+
type: "string",
|
|
37679
|
+
default: "",
|
|
37680
|
+
description: "Prefix for generated branch names, e.g. dev/magus/",
|
|
37635
37681
|
},
|
|
37636
37682
|
"template": {
|
|
37637
37683
|
type: "boolean",
|
|
37638
37684
|
default: true,
|
|
37639
37685
|
description: "Use automatic Github PR template, e.g. .github/pull_request_template.md, disable with --no-template",
|
|
37640
37686
|
},
|
|
37687
|
+
"write-state-json": {
|
|
37688
|
+
hidden: true,
|
|
37689
|
+
type: "boolean",
|
|
37690
|
+
default: false,
|
|
37691
|
+
description: "Write state to local json file for debugging",
|
|
37692
|
+
},
|
|
37641
37693
|
"mock-metadata": {
|
|
37642
37694
|
hidden: true,
|
|
37643
37695
|
type: "boolean",
|
package/package.json
CHANGED
|
@@ -387,8 +387,21 @@ function SelectCommitRangesInternal(props: Props) {
|
|
|
387
387
|
</Ink.Box>
|
|
388
388
|
);
|
|
389
389
|
|
|
390
|
+
function get_group_id() {
|
|
391
|
+
let branch_prefix = "";
|
|
392
|
+
|
|
393
|
+
// branch prefix via cli flag or env var
|
|
394
|
+
// cli flag takes precedence since it is more explicit
|
|
395
|
+
if (argv["branch-prefix"]) {
|
|
396
|
+
branch_prefix = argv["branch-prefix"];
|
|
397
|
+
} else if (process.env.GIT_STACK_BRANCH_PREFIX) {
|
|
398
|
+
branch_prefix = process.env.GIT_STACK_BRANCH_PREFIX;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return `${branch_prefix}${gs_short_id()}`;
|
|
402
|
+
}
|
|
390
403
|
function submit_group_input(title: string) {
|
|
391
|
-
const id =
|
|
404
|
+
const id = get_group_id();
|
|
392
405
|
|
|
393
406
|
actions.output(
|
|
394
407
|
<FormatText
|
package/src/app/SyncGithub.tsx
CHANGED
|
@@ -93,8 +93,6 @@ async function run(args: Args) {
|
|
|
93
93
|
|
|
94
94
|
await Promise.all(before_push_tasks);
|
|
95
95
|
|
|
96
|
-
// git push -f origin HEAD~6:OtVX7Qvrw HEAD~3:E63ytp5dj HEAD~2:gs-NBabNSjXA HEAD~1:gs-UGVJdKNoD HEAD~0:gs-6LAx-On4
|
|
97
|
-
|
|
98
96
|
const git_push_command = [`git push -f origin`];
|
|
99
97
|
|
|
100
98
|
if (argv.verify === false) {
|
|
@@ -104,7 +102,25 @@ async function run(args: Args) {
|
|
|
104
102
|
for (const group of push_group_list) {
|
|
105
103
|
const last_commit = last(group.commits);
|
|
106
104
|
invariant(last_commit, "last_commit must exist");
|
|
107
|
-
|
|
105
|
+
|
|
106
|
+
// explicit refs/heads head branch to avoid push failing
|
|
107
|
+
//
|
|
108
|
+
// ❯ git push -f origin --no-verify f6e249051b4820a03deb957ddebc19acfd7dfd7c:gs-ED2etrzv2
|
|
109
|
+
// error: The destination you provided is not a full refname (i.e.,
|
|
110
|
+
// starting with "refs/"). We tried to guess what you meant by:
|
|
111
|
+
//
|
|
112
|
+
// - Looking for a ref that matches 'gs-ED2etrzv2' on the remote side.
|
|
113
|
+
// - Checking if the <src> being pushed ('f6e249051b4820a03deb957ddebc19acfd7dfd7c')
|
|
114
|
+
// is a ref in "refs/{heads,tags}/". If so we add a corresponding
|
|
115
|
+
// refs/{heads,tags}/ prefix on the remote side.
|
|
116
|
+
//
|
|
117
|
+
// Neither worked, so we gave up. You must fully qualify the ref.
|
|
118
|
+
// hint: The <src> part of the refspec is a commit object.
|
|
119
|
+
// hint: Did you mean to create a new branch by pushing to
|
|
120
|
+
// hint: 'f6e249051b4820a03deb957ddebc19acfd7dfd7c:refs/heads/gs-ED2etrzv2'?
|
|
121
|
+
// error: failed to push some refs to 'github.com:magus/git-multi-diff-playground.git'
|
|
122
|
+
//
|
|
123
|
+
const target = `${last_commit.sha}:refs/heads/${group.id}`;
|
|
108
124
|
git_push_command.push(target);
|
|
109
125
|
}
|
|
110
126
|
|
package/src/command.ts
CHANGED
|
@@ -111,11 +111,10 @@ const DefaultOptions = {
|
|
|
111
111
|
description: "Open all PRs as drafts",
|
|
112
112
|
},
|
|
113
113
|
|
|
114
|
-
"
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
description: "Write state to local json file for debugging",
|
|
114
|
+
"branch-prefix": {
|
|
115
|
+
type: "string",
|
|
116
|
+
default: "",
|
|
117
|
+
description: "Prefix for generated branch names, e.g. dev/magus/",
|
|
119
118
|
},
|
|
120
119
|
|
|
121
120
|
"template": {
|
|
@@ -125,6 +124,13 @@ const DefaultOptions = {
|
|
|
125
124
|
"Use automatic Github PR template, e.g. .github/pull_request_template.md, disable with --no-template",
|
|
126
125
|
},
|
|
127
126
|
|
|
127
|
+
"write-state-json": {
|
|
128
|
+
hidden: true,
|
|
129
|
+
type: "boolean",
|
|
130
|
+
default: false,
|
|
131
|
+
description: "Write state to local json file for debugging",
|
|
132
|
+
},
|
|
133
|
+
|
|
128
134
|
"mock-metadata": {
|
|
129
135
|
hidden: true,
|
|
130
136
|
type: "boolean",
|
package/src/core/github.tsx
CHANGED
|
@@ -123,13 +123,26 @@ type CreatePullRequestArgs = {
|
|
|
123
123
|
|
|
124
124
|
export async function pr_create(args: CreatePullRequestArgs) {
|
|
125
125
|
const title = safe_quote(args.title);
|
|
126
|
-
|
|
126
|
+
|
|
127
|
+
// explicit refs/heads head branch to avoid creation failing
|
|
128
|
+
//
|
|
129
|
+
// ❯ gh pr create --head origin/gs-ED2etrzv2 --base gs-6LAx-On45 --title="2024-01-05 test" --body=""
|
|
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
|
+
//
|
|
132
|
+
// https://github.com/cli/cli/issues/5465
|
|
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
|
+
];
|
|
127
140
|
|
|
128
141
|
if (args.draft) {
|
|
129
|
-
|
|
142
|
+
command_parts.push("--draft");
|
|
130
143
|
}
|
|
131
144
|
|
|
132
|
-
const cli_result = await cli(
|
|
145
|
+
const cli_result = await cli(command_parts);
|
|
133
146
|
|
|
134
147
|
if (cli_result.code !== 0) {
|
|
135
148
|
handle_error(cli_result.output);
|
|
@@ -153,9 +166,7 @@ export async function pr_edit(args: EditPullRequestArgs) {
|
|
|
153
166
|
command_parts.push(`--body-file="${body_file}"`);
|
|
154
167
|
}
|
|
155
168
|
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
const cli_result = await cli(command);
|
|
169
|
+
const cli_result = await cli(command_parts);
|
|
159
170
|
|
|
160
171
|
if (cli_result.code !== 0) {
|
|
161
172
|
handle_error(cli_result.output);
|
|
@@ -247,7 +258,14 @@ async function write_body_file(args: EditPullRequestArgs) {
|
|
|
247
258
|
invariant(args.body, "args.body must exist");
|
|
248
259
|
|
|
249
260
|
const temp_dir = os.tmpdir();
|
|
250
|
-
|
|
261
|
+
|
|
262
|
+
// ensure unique filename is safe for filesystem
|
|
263
|
+
// base (group id) might contain slashes, e.g. dev/magus/gs-3cmrMBSUj
|
|
264
|
+
// the flashes would mess up the filesystem path to this file
|
|
265
|
+
let temp_filename = `git-stack-body-${args.base}`;
|
|
266
|
+
temp_filename = temp_filename.replace(RE.non_alphanumeric_dash, "-");
|
|
267
|
+
|
|
268
|
+
const temp_path = path.join(temp_dir, temp_filename);
|
|
251
269
|
|
|
252
270
|
await safe_rm(temp_path);
|
|
253
271
|
|
|
@@ -284,3 +302,7 @@ export type PullRequest = {
|
|
|
284
302
|
url: string;
|
|
285
303
|
isDraft: boolean;
|
|
286
304
|
};
|
|
305
|
+
|
|
306
|
+
const RE = {
|
|
307
|
+
non_alphanumeric_dash: /[^a-zA-Z0-9_-]+/g,
|
|
308
|
+
};
|