git-stack-cli 2.0.1-beta → 2.1.1-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.
- package/dist/js/index.js +75 -42
- package/package.json +2 -1
- package/scripts/release-brew.ts +3 -1
- package/src/app/DetectInitialPR.tsx +2 -2
- package/src/core/CommitMetadata.ts +20 -3
- package/src/core/GitReviseTodo.ts +2 -2
- package/src/core/get_tmp_dir.ts +12 -0
- package/src/core/github.tsx +21 -12
- package/src/index.tsx +7 -0
package/dist/js/index.js
CHANGED
|
@@ -28099,6 +28099,7 @@ var require_last = __commonJS((exports, module) => {
|
|
|
28099
28099
|
|
|
28100
28100
|
// src/index.tsx
|
|
28101
28101
|
var React55 = __toESM(require_react(), 1);
|
|
28102
|
+
import fs14 from "node:fs/promises";
|
|
28102
28103
|
|
|
28103
28104
|
// node_modules/.pnpm/ink-cjs@4.4.1_@types+react@18.2.33_react-devtools-core@4.19.1_react@18.2.0/node_modules/ink-cjs/build/render.js
|
|
28104
28105
|
import { Stream } from "node:stream";
|
|
@@ -37796,7 +37797,7 @@ function Url(props) {
|
|
|
37796
37797
|
import fs7 from "node:fs";
|
|
37797
37798
|
import path4 from "node:path";
|
|
37798
37799
|
function is_command_available(command) {
|
|
37799
|
-
const PATH = "/Users/noah/github/git-stack-cli/node_modules/.bin:/Users/noah/.cache/node/corepack/v1/pnpm/9.15.4/dist/node-gyp-bin:/Users/noah/github/git-stack-cli/node_modules/.bin:/Users/noah/.cache/node/corepack/v1/pnpm/9.15.4/dist/node-gyp-bin:/Users/noah/github/git-stack-cli/node_modules/.bin:/Users/noah/.cache/node/corepack/v1/pnpm/9.15.4/dist/node-gyp-bin:/Users/noah/.
|
|
37800
|
+
const PATH = "/Users/noah/github/git-stack-cli/node_modules/.bin:/Users/noah/.cache/node/corepack/v1/pnpm/9.15.4/dist/node-gyp-bin:/Users/noah/github/git-stack-cli/node_modules/.bin:/Users/noah/.cache/node/corepack/v1/pnpm/9.15.4/dist/node-gyp-bin:/Users/noah/github/git-stack-cli/node_modules/.bin:/Users/noah/.cache/node/corepack/v1/pnpm/9.15.4/dist/node-gyp-bin:/Users/noah/.rvm/gems/ruby-2.6.3/bin:/Users/noah/.rvm/gems/ruby-2.6.3@global/bin:/Users/noah/.rvm/rubies/ruby-2.6.3/bin:/Users/noah/Library/pnpm:/Users/noah/.bun/bin:/Users/noah/Library/Caches/fnm_multishells/45565_1737429645385/bin:/usr/local/sbin:/usr/local/bin:/usr/local/bin:/usr/local/sbin:/Users/noah/.dotfiles/bin:/usr/local/sbin:/usr/local/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/Library/Apple/usr/bin:/Applications/Postgres.app/Contents/Versions/latest/bin:/Users/noah/.cargo/bin:/Applications/iTerm.app/Contents/Resources/utilities:/Users/noah/google-cloud-sdk/bin:/Users/noah/.yarn/bin:/Users/noah/.fastlane/bin:/usr/local/opt/fzf/bin:/Users/noah/google-cloud-sdk/bin:/Users/noah/.yarn/bin:/Users/noah/.fastlane/bin:/Users/noah/.rvm/bin";
|
|
37800
37801
|
invariant(PATH, "PATH env must exist");
|
|
37801
37802
|
const path_list = PATH.split(path4.delimiter);
|
|
37802
37803
|
for (const dir of path_list) {
|
|
@@ -38015,9 +38016,21 @@ var RE3 = {
|
|
|
38015
38016
|
|
|
38016
38017
|
// src/core/github.tsx
|
|
38017
38018
|
var React24 = __toESM(require_react(), 1);
|
|
38019
|
+
import crypto from "node:crypto";
|
|
38020
|
+
import fs9 from "node:fs/promises";
|
|
38021
|
+
import path6 from "node:path";
|
|
38022
|
+
|
|
38023
|
+
// src/core/get_tmp_dir.ts
|
|
38018
38024
|
import fs8 from "node:fs/promises";
|
|
38019
38025
|
import os2 from "node:os";
|
|
38020
38026
|
import path5 from "node:path";
|
|
38027
|
+
async function get_tmp_dir() {
|
|
38028
|
+
const dir = path5.join(os2.tmpdir(), "git-stack-cli");
|
|
38029
|
+
await fs8.mkdir(dir, { recursive: true });
|
|
38030
|
+
return dir;
|
|
38031
|
+
}
|
|
38032
|
+
|
|
38033
|
+
// src/core/github.tsx
|
|
38021
38034
|
async function pr_list() {
|
|
38022
38035
|
const state = Store.getState();
|
|
38023
38036
|
const actions = state.actions;
|
|
@@ -38054,7 +38067,7 @@ async function pr_status(branch) {
|
|
|
38054
38067
|
const cache4 = state.pr[branch];
|
|
38055
38068
|
if (cache4) {
|
|
38056
38069
|
if (actions.isDebug()) {
|
|
38057
|
-
actions.
|
|
38070
|
+
actions.debug(/* @__PURE__ */ React24.createElement(Text, null, /* @__PURE__ */ React24.createElement(Text, {
|
|
38058
38071
|
dimColor: true
|
|
38059
38072
|
}, "Github pr_status cache"), /* @__PURE__ */ React24.createElement(Text, null, " "), /* @__PURE__ */ React24.createElement(Text, {
|
|
38060
38073
|
bold: true,
|
|
@@ -38066,7 +38079,7 @@ async function pr_status(branch) {
|
|
|
38066
38079
|
return cache4;
|
|
38067
38080
|
}
|
|
38068
38081
|
if (actions.isDebug()) {
|
|
38069
|
-
actions.
|
|
38082
|
+
actions.debug(/* @__PURE__ */ React24.createElement(Text, null, /* @__PURE__ */ React24.createElement(Text, {
|
|
38070
38083
|
dimColor: true
|
|
38071
38084
|
}, "Github pr_status cache"), /* @__PURE__ */ React24.createElement(Text, null, " "), /* @__PURE__ */ React24.createElement(Text, {
|
|
38072
38085
|
bold: true,
|
|
@@ -38146,15 +38159,21 @@ async function pr_draft(args) {
|
|
|
38146
38159
|
}
|
|
38147
38160
|
var JSON_FIELDS = "--json id,number,state,baseRefName,headRefName,commits,title,body,url,isDraft";
|
|
38148
38161
|
async function gh_json(command) {
|
|
38149
|
-
|
|
38162
|
+
let hash = crypto.createHash("md5").update(command).digest("hex");
|
|
38163
|
+
let tmp_filename = safe_filename(`gh_json-${hash}`);
|
|
38164
|
+
const tmp_pr_json = path6.join(await get_tmp_dir(), `${tmp_filename}.json`);
|
|
38150
38165
|
const options = { ignoreExitCode: true };
|
|
38151
38166
|
const cli_result = await cli(`gh ${command} > ${tmp_pr_json}`, options);
|
|
38152
38167
|
if (cli_result.code !== 0) {
|
|
38153
38168
|
return new Error(cli_result.output);
|
|
38154
38169
|
}
|
|
38155
|
-
const json_str = await
|
|
38156
|
-
|
|
38157
|
-
|
|
38170
|
+
const json_str = String(await fs9.readFile(tmp_pr_json));
|
|
38171
|
+
try {
|
|
38172
|
+
const json = JSON.parse(json_str);
|
|
38173
|
+
return json;
|
|
38174
|
+
} catch (error) {
|
|
38175
|
+
return new Error(`gh_json JSON.parse: ${error}`);
|
|
38176
|
+
}
|
|
38158
38177
|
}
|
|
38159
38178
|
function handle_error(output) {
|
|
38160
38179
|
const state = Store.getState();
|
|
@@ -38166,14 +38185,15 @@ function handle_error(output) {
|
|
|
38166
38185
|
}
|
|
38167
38186
|
async function write_body_file(args) {
|
|
38168
38187
|
invariant(args.body, "args.body must exist");
|
|
38169
|
-
|
|
38170
|
-
|
|
38171
|
-
temp_filename = temp_filename.replace(RE4.non_alphanumeric_dash, "-");
|
|
38172
|
-
const temp_path = path5.join(temp_dir, temp_filename);
|
|
38188
|
+
let tmp_filename = safe_filename(`git-stack-body-${args.base}`);
|
|
38189
|
+
const temp_path = path6.join(await get_tmp_dir(), tmp_filename);
|
|
38173
38190
|
await safe_rm(temp_path);
|
|
38174
|
-
await
|
|
38191
|
+
await fs9.writeFile(temp_path, args.body);
|
|
38175
38192
|
return temp_path;
|
|
38176
38193
|
}
|
|
38194
|
+
function safe_filename(value) {
|
|
38195
|
+
return value.replace(RE4.non_alphanumeric_dash, "-");
|
|
38196
|
+
}
|
|
38177
38197
|
var RE4 = {
|
|
38178
38198
|
non_alphanumeric_dash: /[^a-zA-Z0-9_-]+/g
|
|
38179
38199
|
};
|
|
@@ -38226,13 +38246,25 @@ async function range(commit_group_map) {
|
|
|
38226
38246
|
const group_value_list = Array.from(group_map.values());
|
|
38227
38247
|
const group_list = [];
|
|
38228
38248
|
let unassigned_group;
|
|
38249
|
+
const pr_status_promise_list = {};
|
|
38250
|
+
for (const group of group_value_list) {
|
|
38251
|
+
if (group.id !== UNASSIGNED) {
|
|
38252
|
+
pr_status_promise_list[group.id] = pr_status(group.id);
|
|
38253
|
+
}
|
|
38254
|
+
}
|
|
38255
|
+
await Promise.all(Array.from(Object.values(pr_status_promise_list)));
|
|
38256
|
+
for (const [group_id, pr_status_promise] of Object.entries(pr_status_promise_list)) {
|
|
38257
|
+
const pr_status2 = await pr_status_promise;
|
|
38258
|
+
if (pr_status2) {
|
|
38259
|
+
pr_lookup[group_id] = pr_status2;
|
|
38260
|
+
}
|
|
38261
|
+
}
|
|
38229
38262
|
for (let i2 = 0;i2 < group_value_list.length; i2++) {
|
|
38230
38263
|
const group = group_value_list[i2];
|
|
38231
38264
|
if (group.id !== UNASSIGNED) {
|
|
38232
|
-
|
|
38265
|
+
let pr_result = pr_lookup[group.id];
|
|
38233
38266
|
if (pr_result && pr_result.state !== "CLOSED") {
|
|
38234
38267
|
group.pr = pr_result;
|
|
38235
|
-
pr_lookup[group.id] = pr_result;
|
|
38236
38268
|
}
|
|
38237
38269
|
}
|
|
38238
38270
|
if (group.id === UNASSIGNED) {
|
|
@@ -38315,9 +38347,8 @@ function lines(value) {
|
|
|
38315
38347
|
var UNASSIGNED = "unassigned";
|
|
38316
38348
|
|
|
38317
38349
|
// src/core/GitReviseTodo.ts
|
|
38318
|
-
import
|
|
38319
|
-
import
|
|
38320
|
-
import path6 from "node:path";
|
|
38350
|
+
import fs10 from "node:fs/promises";
|
|
38351
|
+
import path7 from "node:path";
|
|
38321
38352
|
function GitReviseTodo(args) {
|
|
38322
38353
|
const commit_list = [];
|
|
38323
38354
|
const group_list = args.commit_range.group_list;
|
|
@@ -38353,7 +38384,7 @@ GitReviseTodo.todo = function todo(args) {
|
|
|
38353
38384
|
return todo2;
|
|
38354
38385
|
};
|
|
38355
38386
|
GitReviseTodo.execute = async function grt_execute(args) {
|
|
38356
|
-
const tmp_git_sequence_editor_path =
|
|
38387
|
+
const tmp_git_sequence_editor_path = path7.join(await get_tmp_dir(), "git-sequence-editor.sh");
|
|
38357
38388
|
const GIT_SEQUENCE_EDITOR_SCRIPT = `#!/bin/sh
|
|
38358
38389
|
|
|
38359
38390
|
# Example
|
|
@@ -38391,8 +38422,8 @@ echo "------ END ------"
|
|
|
38391
38422
|
echo "$GIT_REVISE_TODO" > "$git_revise_todo_path"
|
|
38392
38423
|
`;
|
|
38393
38424
|
invariant(GIT_SEQUENCE_EDITOR_SCRIPT, "GIT_SEQUENCE_EDITOR_SCRIPT must exist");
|
|
38394
|
-
await
|
|
38395
|
-
await
|
|
38425
|
+
await fs10.writeFile(tmp_git_sequence_editor_path, GIT_SEQUENCE_EDITOR_SCRIPT);
|
|
38426
|
+
await fs10.chmod(tmp_git_sequence_editor_path, "755");
|
|
38396
38427
|
const git_revise_todo = GitReviseTodo(args);
|
|
38397
38428
|
const command = [
|
|
38398
38429
|
`GIT_EDITOR="${tmp_git_sequence_editor_path}"`,
|
|
@@ -38469,7 +38500,7 @@ function DetectInitialPR(props) {
|
|
|
38469
38500
|
const branch_name2 = Store.getState().branch_name;
|
|
38470
38501
|
const commit_range = Store.getState().commit_range;
|
|
38471
38502
|
invariant(branch_name2, "branch_name must exist");
|
|
38472
|
-
invariant(commit_range, "
|
|
38503
|
+
invariant(commit_range, "commit_range must exist");
|
|
38473
38504
|
try {
|
|
38474
38505
|
let has_existing_metadata = false;
|
|
38475
38506
|
for (const commit2 of commit_range.commit_list) {
|
|
@@ -38501,7 +38532,7 @@ function DetectInitialPR(props) {
|
|
|
38501
38532
|
const branch_name2 = Store.getState().branch_name;
|
|
38502
38533
|
const commit_range = import_cloneDeep.default(Store.getState().commit_range);
|
|
38503
38534
|
invariant(branch_name2, "branch_name must exist");
|
|
38504
|
-
invariant(commit_range, "
|
|
38535
|
+
invariant(commit_range, "commit_range must exist");
|
|
38505
38536
|
for (const group of commit_range.group_list) {
|
|
38506
38537
|
group.id = branch_name2;
|
|
38507
38538
|
group.title = state.pr?.title || "-";
|
|
@@ -38833,16 +38864,16 @@ var React32 = __toESM(require_react(), 1);
|
|
|
38833
38864
|
|
|
38834
38865
|
// src/commands/Rebase.tsx
|
|
38835
38866
|
var React31 = __toESM(require_react(), 1);
|
|
38836
|
-
import
|
|
38867
|
+
import fs11 from "node:fs";
|
|
38837
38868
|
|
|
38838
38869
|
// src/core/short_id.ts
|
|
38839
|
-
import
|
|
38870
|
+
import crypto2 from "node:crypto";
|
|
38840
38871
|
function short_id() {
|
|
38841
38872
|
const timestamp = Date.now();
|
|
38842
38873
|
const js_max_bits = 53;
|
|
38843
38874
|
const timestamp_bits = Math.floor(Math.log2(timestamp)) + 1;
|
|
38844
38875
|
const padding_bits = js_max_bits - timestamp_bits;
|
|
38845
|
-
const random =
|
|
38876
|
+
const random = crypto2.randomInt(0, Math.pow(2, padding_bits));
|
|
38846
38877
|
const combined = interleave_bits(timestamp, random);
|
|
38847
38878
|
return encode(combined);
|
|
38848
38879
|
}
|
|
@@ -38986,7 +39017,7 @@ Rebase.run = async function run4() {
|
|
|
38986
39017
|
cli.sync(`git clean -df`, spawn_options);
|
|
38987
39018
|
cli.sync(`git checkout ${branch_name}`, spawn_options);
|
|
38988
39019
|
cli.sync(`git branch -D ${temp_branch_name}`, spawn_options);
|
|
38989
|
-
if (
|
|
39020
|
+
if (fs11.existsSync(cwd2)) {
|
|
38990
39021
|
process.chdir(cwd2);
|
|
38991
39022
|
}
|
|
38992
39023
|
cli.sync(`pwd`, spawn_options);
|
|
@@ -39009,7 +39040,7 @@ function LocalMergeRebase() {
|
|
|
39009
39040
|
|
|
39010
39041
|
// src/app/ManualRebase.tsx
|
|
39011
39042
|
var React33 = __toESM(require_react(), 1);
|
|
39012
|
-
import
|
|
39043
|
+
import fs12 from "node:fs";
|
|
39013
39044
|
function ManualRebase() {
|
|
39014
39045
|
return /* @__PURE__ */ React33.createElement(Await, {
|
|
39015
39046
|
fallback: /* @__PURE__ */ React33.createElement(Text, {
|
|
@@ -39109,7 +39140,7 @@ async function run5() {
|
|
|
39109
39140
|
cli.sync(`git clean -df`, spawn_options);
|
|
39110
39141
|
cli.sync(`git checkout ${branch_name}`, spawn_options);
|
|
39111
39142
|
cli.sync(`git branch -D ${temp_branch_name}`, spawn_options);
|
|
39112
|
-
if (
|
|
39143
|
+
if (fs12.existsSync(cwd2)) {
|
|
39113
39144
|
process.chdir(cwd2);
|
|
39114
39145
|
}
|
|
39115
39146
|
cli.sync(`pwd`, spawn_options);
|
|
@@ -39368,8 +39399,8 @@ function PreLocalMergeRebase() {
|
|
|
39368
39399
|
|
|
39369
39400
|
// src/app/PreManualRebase.tsx
|
|
39370
39401
|
var React38 = __toESM(require_react(), 1);
|
|
39371
|
-
import
|
|
39372
|
-
import
|
|
39402
|
+
import fs13 from "node:fs/promises";
|
|
39403
|
+
import path8 from "node:path";
|
|
39373
39404
|
function PreManualRebase() {
|
|
39374
39405
|
return /* @__PURE__ */ React38.createElement(Await, {
|
|
39375
39406
|
fallback: null,
|
|
@@ -39391,7 +39422,7 @@ async function run7() {
|
|
|
39391
39422
|
for (const key of PR_TEMPLATE_KEY_LIST) {
|
|
39392
39423
|
const pr_template_fn = PR_TEMPLATE[key];
|
|
39393
39424
|
if (await safe_exists(pr_template_fn(repo_root))) {
|
|
39394
|
-
pr_template_body = await
|
|
39425
|
+
pr_template_body = await fs13.readFile(pr_template_fn(repo_root), "utf-8");
|
|
39395
39426
|
actions.output(/* @__PURE__ */ React38.createElement(FormatText, {
|
|
39396
39427
|
wrapper: /* @__PURE__ */ React38.createElement(Text, {
|
|
39397
39428
|
color: colors.yellow
|
|
@@ -39406,7 +39437,7 @@ async function run7() {
|
|
|
39406
39437
|
}
|
|
39407
39438
|
let pr_templates = [];
|
|
39408
39439
|
if (await safe_exists(PR_TEMPLATE.TemplateDir(repo_root))) {
|
|
39409
|
-
pr_templates = await
|
|
39440
|
+
pr_templates = await fs13.readdir(PR_TEMPLATE.TemplateDir(repo_root));
|
|
39410
39441
|
}
|
|
39411
39442
|
actions.set((state2) => {
|
|
39412
39443
|
state2.pr_template_body = pr_template_body;
|
|
@@ -39429,10 +39460,10 @@ async function run7() {
|
|
|
39429
39460
|
});
|
|
39430
39461
|
}
|
|
39431
39462
|
var PR_TEMPLATE = Object.freeze({
|
|
39432
|
-
Github: (root) =>
|
|
39433
|
-
Root: (root) =>
|
|
39434
|
-
Docs: (root) =>
|
|
39435
|
-
TemplateDir: (root) =>
|
|
39463
|
+
Github: (root) => path8.join(root, ".github", "pull_request_template.md"),
|
|
39464
|
+
Root: (root) => path8.join(root, "pull_request_template.md"),
|
|
39465
|
+
Docs: (root) => path8.join(root, "docs", "pull_request_template.md"),
|
|
39466
|
+
TemplateDir: (root) => path8.join(root, ".github", "PULL_REQUEST_TEMPLATE")
|
|
39436
39467
|
});
|
|
39437
39468
|
var PR_TEMPLATE_KEY_LIST = Object.keys(PR_TEMPLATE);
|
|
39438
39469
|
|
|
@@ -40414,7 +40445,7 @@ function Providers(props) {
|
|
|
40414
40445
|
|
|
40415
40446
|
// src/app/RebaseCheck.tsx
|
|
40416
40447
|
var React48 = __toESM(require_react(), 1);
|
|
40417
|
-
import
|
|
40448
|
+
import path9 from "node:path";
|
|
40418
40449
|
function reducer5(state, patch) {
|
|
40419
40450
|
return { ...state, ...patch };
|
|
40420
40451
|
}
|
|
@@ -40452,8 +40483,8 @@ function RebaseCheck(props) {
|
|
|
40452
40483
|
try {
|
|
40453
40484
|
const git_dir = (await cli(`git rev-parse --absolute-git-dir`)).stdout;
|
|
40454
40485
|
let is_rebase = false;
|
|
40455
|
-
is_rebase ||= await safe_exists(
|
|
40456
|
-
is_rebase ||= await safe_exists(
|
|
40486
|
+
is_rebase ||= await safe_exists(path9.join(git_dir, "rebase-apply"));
|
|
40487
|
+
is_rebase ||= await safe_exists(path9.join(git_dir, "rebase-merge"));
|
|
40457
40488
|
const status = is_rebase ? "prompt" : "done";
|
|
40458
40489
|
patch({ status });
|
|
40459
40490
|
} catch (err) {
|
|
@@ -42009,9 +42040,9 @@ var parser = new YargsParser({
|
|
|
42009
42040
|
format,
|
|
42010
42041
|
normalize,
|
|
42011
42042
|
resolve: resolve2,
|
|
42012
|
-
require: (
|
|
42043
|
+
require: (path10) => {
|
|
42013
42044
|
if (true) {
|
|
42014
|
-
return __require(
|
|
42045
|
+
return __require(path10);
|
|
42015
42046
|
} else
|
|
42016
42047
|
;
|
|
42017
42048
|
}
|
|
@@ -45594,7 +45625,7 @@ var yargs_default = Yargs;
|
|
|
45594
45625
|
|
|
45595
45626
|
// src/command.ts
|
|
45596
45627
|
async function command2() {
|
|
45597
|
-
return yargs_default(hideBin(process.argv)).usage("Usage: git stack [command] [options]").command("$0", "Sync commit ranges to Github", (yargs) => yargs.options(DefaultOptions)).command("fixup [commit]", "Amend staged changes to a specific commit in history", (yargs) => yargs.positional("commit", FixupOptions.commit)).command("log [args...]", "Print an abbreviated log with numbered commits, useful for git stack fixup", (yargs) => yargs.strict(false)).command("rebase", "Update local branch via rebase with latest changes from origin master branch", (yargs) => yargs).option("verbose", GlobalOptions.verbose).wrap(123).strict().version("2.
|
|
45628
|
+
return yargs_default(hideBin(process.argv)).usage("Usage: git stack [command] [options]").command("$0", "Sync commit ranges to Github", (yargs) => yargs.options(DefaultOptions)).command("fixup [commit]", "Amend staged changes to a specific commit in history", (yargs) => yargs.positional("commit", FixupOptions.commit)).command("log [args...]", "Print an abbreviated log with numbered commits, useful for git stack fixup", (yargs) => yargs.strict(false)).command("rebase", "Update local branch via rebase with latest changes from origin master branch", (yargs) => yargs).option("verbose", GlobalOptions.verbose).wrap(123).strict().version("2.1.1-beta").showHidden("show-hidden", "Show hidden options via `git stack help --show-hidden`").help("help", "Show usage via `git stack help`").argv;
|
|
45598
45629
|
}
|
|
45599
45630
|
var GlobalOptions = {
|
|
45600
45631
|
verbose: {
|
|
@@ -45703,6 +45734,8 @@ var FixupOptions = {
|
|
|
45703
45734
|
maybe_verbose_help();
|
|
45704
45735
|
process.exit(238);
|
|
45705
45736
|
});
|
|
45737
|
+
const tmp_dir = await get_tmp_dir();
|
|
45738
|
+
await fs14.rm(tmp_dir, { recursive: true });
|
|
45706
45739
|
const ink = render_default(/* @__PURE__ */ React55.createElement(App2, null), {
|
|
45707
45740
|
exitOnCtrlC: false
|
|
45708
45741
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "git-stack-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1-beta",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "magus",
|
|
6
6
|
"license": "MIT",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"zustand": "^4.4.4"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
+
"@oven/bun-darwin-aarch64": "1.1.42",
|
|
55
56
|
"@types/chalk": "^2.2.0",
|
|
56
57
|
"@types/lodash": "^4.17.7",
|
|
57
58
|
"@types/luxon": "^3.4.2",
|
package/scripts/release-brew.ts
CHANGED
|
@@ -25,7 +25,9 @@ const previous_formula_path = path.join(HOMEBREW_DIR, "Formula", "git-stack.rb")
|
|
|
25
25
|
// version = "1.0.4"
|
|
26
26
|
//
|
|
27
27
|
let previous_formula = await file.read_text(previous_formula_path);
|
|
28
|
-
|
|
28
|
+
|
|
29
|
+
// https://regex101.com/r/BnvdqK/1
|
|
30
|
+
const re_version = /version(?: =)? "(?<version>\d+\.\d+\.\d+(?:-.+)?)"/m;
|
|
29
31
|
const previous_version_match = previous_formula.match(re_version);
|
|
30
32
|
|
|
31
33
|
if (!previous_version_match?.groups) {
|
|
@@ -108,7 +108,7 @@ export function DetectInitialPR(props: Props) {
|
|
|
108
108
|
const commit_range = Store.getState().commit_range;
|
|
109
109
|
|
|
110
110
|
invariant(branch_name, "branch_name must exist");
|
|
111
|
-
invariant(commit_range, "
|
|
111
|
+
invariant(commit_range, "commit_range must exist");
|
|
112
112
|
|
|
113
113
|
try {
|
|
114
114
|
let has_existing_metadata = false;
|
|
@@ -149,7 +149,7 @@ export function DetectInitialPR(props: Props) {
|
|
|
149
149
|
const commit_range = cloneDeep(Store.getState().commit_range);
|
|
150
150
|
|
|
151
151
|
invariant(branch_name, "branch_name must exist");
|
|
152
|
-
invariant(commit_range, "
|
|
152
|
+
invariant(commit_range, "commit_range must exist");
|
|
153
153
|
|
|
154
154
|
for (const group of commit_range.group_list) {
|
|
155
155
|
group.id = branch_name;
|
|
@@ -6,7 +6,8 @@ import * as github from "~/core/github";
|
|
|
6
6
|
export type CommitMetadata = Awaited<ReturnType<typeof commit>>;
|
|
7
7
|
export type CommitRange = Awaited<ReturnType<typeof range>>;
|
|
8
8
|
|
|
9
|
-
type
|
|
9
|
+
type GithubPRStatus = ReturnType<typeof github.pr_status>;
|
|
10
|
+
type PullRequest = NonNullable<Awaited<GithubPRStatus>>;
|
|
10
11
|
|
|
11
12
|
type CommitGroup = {
|
|
12
13
|
id: string;
|
|
@@ -93,15 +94,31 @@ export async function range(commit_group_map?: CommitGroupMap) {
|
|
|
93
94
|
const group_list = [];
|
|
94
95
|
let unassigned_group;
|
|
95
96
|
|
|
97
|
+
// collect github pr status in parallel
|
|
98
|
+
const pr_status_promise_list: Record<string, GithubPRStatus> = {};
|
|
99
|
+
for (const group of group_value_list) {
|
|
100
|
+
if (group.id !== UNASSIGNED) {
|
|
101
|
+
pr_status_promise_list[group.id] = github.pr_status(group.id);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
await Promise.all(Array.from(Object.values(pr_status_promise_list)));
|
|
106
|
+
|
|
107
|
+
for (const [group_id, pr_status_promise] of Object.entries(pr_status_promise_list)) {
|
|
108
|
+
const pr_status = await pr_status_promise;
|
|
109
|
+
if (pr_status) {
|
|
110
|
+
pr_lookup[group_id] = pr_status;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
96
114
|
for (let i = 0; i < group_value_list.length; i++) {
|
|
97
115
|
const group = group_value_list[i];
|
|
98
116
|
|
|
99
117
|
if (group.id !== UNASSIGNED) {
|
|
100
|
-
|
|
118
|
+
let pr_result = pr_lookup[group.id];
|
|
101
119
|
|
|
102
120
|
if (pr_result && pr_result.state !== "CLOSED") {
|
|
103
121
|
group.pr = pr_result;
|
|
104
|
-
pr_lookup[group.id] = pr_result;
|
|
105
122
|
}
|
|
106
123
|
}
|
|
107
124
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
|
-
import os from "node:os";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
|
|
5
4
|
import * as Metadata from "~/core/Metadata";
|
|
6
5
|
import { cli } from "~/core/cli";
|
|
6
|
+
import { get_tmp_dir } from "~/core/get_tmp_dir";
|
|
7
7
|
import { invariant } from "~/core/invariant";
|
|
8
8
|
import { safe_rm } from "~/core/safe_rm";
|
|
9
9
|
|
|
@@ -109,7 +109,7 @@ GitReviseTodo.todo = function todo(args: CommitListArgs) {
|
|
|
109
109
|
|
|
110
110
|
GitReviseTodo.execute = async function grt_execute(args: ExecuteArgs) {
|
|
111
111
|
// generate temporary directory and drop sequence editor script
|
|
112
|
-
const tmp_git_sequence_editor_path = path.join(
|
|
112
|
+
const tmp_git_sequence_editor_path = path.join(await get_tmp_dir(), "git-sequence-editor.sh");
|
|
113
113
|
|
|
114
114
|
// replaced at build time with literal contents of `scripts/git-sequence-editor.sh`
|
|
115
115
|
const GIT_SEQUENCE_EDITOR_SCRIPT = process.env.GIT_SEQUENCE_EDITOR_SCRIPT;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
export async function get_tmp_dir(): Promise<string> {
|
|
6
|
+
const dir = path.join(os.tmpdir(), "git-stack-cli");
|
|
7
|
+
|
|
8
|
+
// ensure tmp directory exists
|
|
9
|
+
await fs.mkdir(dir, { recursive: true });
|
|
10
|
+
|
|
11
|
+
return dir;
|
|
12
|
+
}
|
package/src/core/github.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
+
import crypto from "node:crypto";
|
|
3
4
|
import fs from "node:fs/promises";
|
|
4
|
-
import os from "node:os";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
|
|
7
7
|
import * as Ink from "ink-cjs";
|
|
@@ -10,6 +10,7 @@ import { Brackets } from "~/app/Brackets";
|
|
|
10
10
|
import { Store } from "~/app/Store";
|
|
11
11
|
import { cli } from "~/core/cli";
|
|
12
12
|
import { colors } from "~/core/colors";
|
|
13
|
+
import { get_tmp_dir } from "~/core/get_tmp_dir";
|
|
13
14
|
import { invariant } from "~/core/invariant";
|
|
14
15
|
import { safe_quote } from "~/core/safe_quote";
|
|
15
16
|
import { safe_rm } from "~/core/safe_rm";
|
|
@@ -68,7 +69,7 @@ export async function pr_status(branch: string): Promise<null | PullRequest> {
|
|
|
68
69
|
|
|
69
70
|
if (cache) {
|
|
70
71
|
if (actions.isDebug()) {
|
|
71
|
-
actions.
|
|
72
|
+
actions.debug(
|
|
72
73
|
<Ink.Text>
|
|
73
74
|
<Ink.Text dimColor>Github pr_status cache</Ink.Text>
|
|
74
75
|
<Ink.Text> </Ink.Text>
|
|
@@ -85,7 +86,7 @@ export async function pr_status(branch: string): Promise<null | PullRequest> {
|
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
if (actions.isDebug()) {
|
|
88
|
-
actions.
|
|
89
|
+
actions.debug(
|
|
89
90
|
<Ink.Text>
|
|
90
91
|
<Ink.Text dimColor>Github pr_status cache</Ink.Text>
|
|
91
92
|
<Ink.Text> </Ink.Text>
|
|
@@ -228,7 +229,10 @@ const JSON_FIELDS = "--json id,number,state,baseRefName,headRefName,commits,titl
|
|
|
228
229
|
// consistent handle gh cli commands returning json
|
|
229
230
|
// redirect to tmp file to avoid scrollback overflow causing scrollback to be cleared
|
|
230
231
|
async function gh_json<T>(command: string): Promise<T | Error> {
|
|
231
|
-
|
|
232
|
+
// hash command for unique short string
|
|
233
|
+
let hash = crypto.createHash("md5").update(command).digest("hex");
|
|
234
|
+
let tmp_filename = safe_filename(`gh_json-${hash}`);
|
|
235
|
+
const tmp_pr_json = path.join(await get_tmp_dir(), `${tmp_filename}.json`);
|
|
232
236
|
|
|
233
237
|
const options = { ignoreExitCode: true };
|
|
234
238
|
const cli_result = await cli(`gh ${command} > ${tmp_pr_json}`, options);
|
|
@@ -238,9 +242,13 @@ async function gh_json<T>(command: string): Promise<T | Error> {
|
|
|
238
242
|
}
|
|
239
243
|
|
|
240
244
|
// read from file
|
|
241
|
-
const json_str = await fs.readFile(tmp_pr_json
|
|
242
|
-
|
|
243
|
-
|
|
245
|
+
const json_str = String(await fs.readFile(tmp_pr_json));
|
|
246
|
+
try {
|
|
247
|
+
const json = JSON.parse(json_str);
|
|
248
|
+
return json;
|
|
249
|
+
} catch (error) {
|
|
250
|
+
return new Error(`gh_json JSON.parse: ${error}`);
|
|
251
|
+
}
|
|
244
252
|
}
|
|
245
253
|
|
|
246
254
|
function handle_error(output: string): never {
|
|
@@ -258,15 +266,12 @@ function handle_error(output: string): never {
|
|
|
258
266
|
async function write_body_file(args: EditPullRequestArgs) {
|
|
259
267
|
invariant(args.body, "args.body must exist");
|
|
260
268
|
|
|
261
|
-
const temp_dir = os.tmpdir();
|
|
262
|
-
|
|
263
269
|
// ensure unique filename is safe for filesystem
|
|
264
270
|
// base (group id) might contain slashes, e.g. dev/magus/gs-3cmrMBSUj
|
|
265
271
|
// the flashes would mess up the filesystem path to this file
|
|
266
|
-
let
|
|
267
|
-
temp_filename = temp_filename.replace(RE.non_alphanumeric_dash, "-");
|
|
272
|
+
let tmp_filename = safe_filename(`git-stack-body-${args.base}`);
|
|
268
273
|
|
|
269
|
-
const temp_path = path.join(
|
|
274
|
+
const temp_path = path.join(await get_tmp_dir(), tmp_filename);
|
|
270
275
|
|
|
271
276
|
await safe_rm(temp_path);
|
|
272
277
|
|
|
@@ -275,6 +280,10 @@ async function write_body_file(args: EditPullRequestArgs) {
|
|
|
275
280
|
return temp_path;
|
|
276
281
|
}
|
|
277
282
|
|
|
283
|
+
function safe_filename(value: string): string {
|
|
284
|
+
return value.replace(RE.non_alphanumeric_dash, "-");
|
|
285
|
+
}
|
|
286
|
+
|
|
278
287
|
type Commit = {
|
|
279
288
|
authoredDate: string; // "2023-10-22T23:13:35Z"
|
|
280
289
|
authors: [
|
package/src/index.tsx
CHANGED
|
@@ -4,11 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
import * as React from "react";
|
|
6
6
|
|
|
7
|
+
import fs from "node:fs/promises";
|
|
8
|
+
|
|
7
9
|
import * as Ink from "ink-cjs";
|
|
8
10
|
|
|
9
11
|
import { App } from "~/app/App";
|
|
10
12
|
import { Store } from "~/app/Store";
|
|
11
13
|
import { command } from "~/command";
|
|
14
|
+
import { get_tmp_dir } from "~/core/get_tmp_dir";
|
|
12
15
|
import { pretty_json } from "~/core/pretty_json";
|
|
13
16
|
|
|
14
17
|
(async function main() {
|
|
@@ -33,6 +36,10 @@ import { pretty_json } from "~/core/pretty_json";
|
|
|
33
36
|
process.exit(238);
|
|
34
37
|
});
|
|
35
38
|
|
|
39
|
+
// cleanup leftover temporary files from previous run
|
|
40
|
+
const tmp_dir = await get_tmp_dir();
|
|
41
|
+
await fs.rm(tmp_dir, { recursive: true });
|
|
42
|
+
|
|
36
43
|
const ink = Ink.render(<App />, {
|
|
37
44
|
// If true, each update will be rendered as a separate output, without replacing the previous one.
|
|
38
45
|
// debug: true,
|