git-stack-cli 0.5.1 → 0.6.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/dist/app/AutoUpdate.js +4 -29
- package/dist/app/DependencyCheck.js +42 -27
- package/dist/app/ManualRebase.js +15 -1
- package/dist/app/MultiSelect.js +1 -1
- package/dist/app/Table.js +2 -1
- package/dist/app/TextInput.js +14 -1
- package/dist/command.js +7 -1
- package/dist/core/Metadata copy.js +37 -0
- package/dist/core/Metadata.js +0 -1
- package/dist/core/StackSummaryTable.js +35 -0
- package/dist/core/StackTable.js +38 -0
- package/dist/core/SummaryTable.js +38 -0
- package/dist/core/fetch_json.js +24 -0
- package/dist/core/github.js +19 -4
- package/dist/core/semver_compare.js +26 -0
- package/package.json +1 -1
package/dist/app/AutoUpdate.js
CHANGED
|
@@ -3,7 +3,9 @@ import fs from "node:fs";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import * as Ink from "ink";
|
|
5
5
|
import { cli } from "../core/cli.js";
|
|
6
|
+
import { fetch_json } from "../core/fetch_json.js";
|
|
6
7
|
import { read_json } from "../core/read_json.js";
|
|
8
|
+
import { semver_compare } from "../core/semver_compare.js";
|
|
7
9
|
import { sleep } from "../core/sleep.js";
|
|
8
10
|
import { Brackets } from "./Brackets.js";
|
|
9
11
|
import { FormatText } from "./FormatText.js";
|
|
@@ -41,13 +43,12 @@ export function AutoUpdate(props) {
|
|
|
41
43
|
handle_output(React.createElement(Ink.Text, { key: "init", dimColor: true }, "Checking for latest version..."));
|
|
42
44
|
}
|
|
43
45
|
const timeout_ms = 2 * 1000;
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
+
const npm_json = await Promise.race([
|
|
47
|
+
fetch_json(`https://registry.npmjs.org/${props.name}`),
|
|
46
48
|
sleep(timeout_ms).then(() => {
|
|
47
49
|
throw new Error("timeout");
|
|
48
50
|
}),
|
|
49
51
|
]);
|
|
50
|
-
const npm_json = await npm_res.json();
|
|
51
52
|
latest_version = npm_json?.["dist-tags"]?.latest;
|
|
52
53
|
if (!latest_version) {
|
|
53
54
|
throw new Error("unable to retrieve latest version from npm");
|
|
@@ -119,29 +120,3 @@ export function AutoUpdate(props) {
|
|
|
119
120
|
output,
|
|
120
121
|
status));
|
|
121
122
|
}
|
|
122
|
-
// returns +1 if version_a is greater than version_b
|
|
123
|
-
// returns -1 if version_a is less than version_b
|
|
124
|
-
// returns +0 if version_a is exactly equal to version_b
|
|
125
|
-
//
|
|
126
|
-
// Examples
|
|
127
|
-
//
|
|
128
|
-
// semver_compare("0.1.1", "0.0.2"); // 1
|
|
129
|
-
// semver_compare("1.0.1", "0.0.2"); // 1
|
|
130
|
-
// semver_compare("0.0.1", "1.0.2"); // -1
|
|
131
|
-
// semver_compare("0.0.1", "0.1.2"); // -1
|
|
132
|
-
// semver_compare("1.0.1", "1.0.1"); // 0
|
|
133
|
-
//
|
|
134
|
-
function semver_compare(version_a, version_b) {
|
|
135
|
-
const split_a = version_a.split(".").map(Number);
|
|
136
|
-
const split_b = version_b.split(".").map(Number);
|
|
137
|
-
const max_split_parts = Math.max(split_a.length, split_b.length);
|
|
138
|
-
for (let i = 0; i < max_split_parts; i++) {
|
|
139
|
-
const num_a = split_a[i] || 0;
|
|
140
|
-
const num_b = split_b[i] || 0;
|
|
141
|
-
if (num_a > num_b)
|
|
142
|
-
return 1;
|
|
143
|
-
if (num_a < num_b)
|
|
144
|
-
return -1;
|
|
145
|
-
}
|
|
146
|
-
return 0;
|
|
147
|
-
}
|
|
@@ -3,6 +3,7 @@ import * as Ink from "ink";
|
|
|
3
3
|
import { cli } from "../core/cli.js";
|
|
4
4
|
import { is_command_available } from "../core/is_command_available.js";
|
|
5
5
|
import { match_group } from "../core/match_group.js";
|
|
6
|
+
import { semver_compare } from "../core/semver_compare.js";
|
|
6
7
|
import { Await } from "./Await.js";
|
|
7
8
|
import { Command } from "./Command.js";
|
|
8
9
|
import { Parens } from "./Parens.js";
|
|
@@ -23,45 +24,59 @@ export function DependencyCheck(props) {
|
|
|
23
24
|
actions.exit(2);
|
|
24
25
|
} },
|
|
25
26
|
React.createElement(Await, { fallback: React.createElement(Ink.Text, { color: "yellow" },
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
"Checking ",
|
|
28
|
+
React.createElement(Command, null, "node"),
|
|
29
|
+
" install..."), function: async () => {
|
|
30
|
+
const process_version = process.version.substring(1);
|
|
31
|
+
const semver_result = semver_compare(process_version, "14.0.0");
|
|
32
|
+
if (semver_result >= 0) {
|
|
31
33
|
return;
|
|
32
34
|
}
|
|
33
35
|
actions.output(React.createElement(Ink.Text, { color: "yellow" },
|
|
34
|
-
React.createElement(Command, null, "
|
|
36
|
+
React.createElement(Command, null, "node"),
|
|
35
37
|
" must be installed."));
|
|
36
|
-
actions.
|
|
37
|
-
React.createElement(Ink.Text, null, "Visit "),
|
|
38
|
-
React.createElement(Url, null, "https://cli.github.com"),
|
|
39
|
-
React.createElement(Ink.Text, null, " to install the github cli "),
|
|
40
|
-
React.createElement(Parens, null,
|
|
41
|
-
React.createElement(Command, null, "gh"))));
|
|
42
|
-
actions.exit(3);
|
|
38
|
+
actions.exit(2);
|
|
43
39
|
} },
|
|
44
40
|
React.createElement(Await, { fallback: React.createElement(Ink.Text, { color: "yellow" },
|
|
45
41
|
React.createElement(Ink.Text, null,
|
|
46
42
|
"Checking ",
|
|
47
|
-
React.createElement(Command, null, "gh
|
|
48
|
-
"...")), function: async () => {
|
|
49
|
-
|
|
50
|
-
ignoreExitCode: true,
|
|
51
|
-
});
|
|
52
|
-
if (auth_output.code === 0) {
|
|
53
|
-
const username = match_group(auth_output.stdout, RE.auth_username, "username");
|
|
54
|
-
actions.set((state) => {
|
|
55
|
-
state.username = username;
|
|
56
|
-
});
|
|
43
|
+
React.createElement(Command, null, "gh"),
|
|
44
|
+
" install...")), function: async () => {
|
|
45
|
+
if (is_command_available("gh")) {
|
|
57
46
|
return;
|
|
58
47
|
}
|
|
59
48
|
actions.output(React.createElement(Ink.Text, { color: "yellow" },
|
|
60
49
|
React.createElement(Command, null, "gh"),
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
50
|
+
" must be installed."));
|
|
51
|
+
actions.output(React.createElement(Ink.Text, { color: "yellow" },
|
|
52
|
+
React.createElement(Ink.Text, null, "Visit "),
|
|
53
|
+
React.createElement(Url, null, "https://cli.github.com"),
|
|
54
|
+
React.createElement(Ink.Text, null, " to install the github cli "),
|
|
55
|
+
React.createElement(Parens, null,
|
|
56
|
+
React.createElement(Command, null, "gh"))));
|
|
57
|
+
actions.exit(3);
|
|
58
|
+
} },
|
|
59
|
+
React.createElement(Await, { fallback: React.createElement(Ink.Text, { color: "yellow" },
|
|
60
|
+
React.createElement(Ink.Text, null,
|
|
61
|
+
"Checking ",
|
|
62
|
+
React.createElement(Command, null, "gh auth status"),
|
|
63
|
+
"...")), function: async () => {
|
|
64
|
+
const auth_status = await cli(`gh auth status`, {
|
|
65
|
+
ignoreExitCode: true,
|
|
66
|
+
});
|
|
67
|
+
if (auth_status.code === 0) {
|
|
68
|
+
const username = match_group(auth_status.stdout, RE.auth_username, "username");
|
|
69
|
+
actions.set((state) => {
|
|
70
|
+
state.username = username;
|
|
71
|
+
});
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
actions.output(React.createElement(Ink.Text, { color: "yellow" },
|
|
75
|
+
React.createElement(Command, null, "gh"),
|
|
76
|
+
React.createElement(Ink.Text, null, " requires login, please run "),
|
|
77
|
+
React.createElement(Command, null, "gh auth login")));
|
|
78
|
+
actions.exit(4);
|
|
79
|
+
} }, props.children)))));
|
|
65
80
|
}
|
|
66
81
|
const RE = {
|
|
67
82
|
// Logged in to github.com as magus
|
package/dist/app/ManualRebase.js
CHANGED
|
@@ -2,6 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import * as Ink from "ink";
|
|
3
3
|
import * as CommitMetadata from "../core/CommitMetadata.js";
|
|
4
4
|
import * as Metadata from "../core/Metadata.js";
|
|
5
|
+
import * as StackSummaryTable from "../core/StackSummaryTable.js";
|
|
5
6
|
import { cli } from "../core/cli.js";
|
|
6
7
|
import * as github from "../core/github.js";
|
|
7
8
|
import { invariant } from "../core/invariant.js";
|
|
@@ -71,7 +72,15 @@ async function run(props) {
|
|
|
71
72
|
await cli(git_push_command.join(" "));
|
|
72
73
|
if (group.pr) {
|
|
73
74
|
// ensure base matches pr in github
|
|
74
|
-
await github.
|
|
75
|
+
await github.pr_edit({
|
|
76
|
+
branch: group.id,
|
|
77
|
+
base: group.base,
|
|
78
|
+
body: StackSummaryTable.write({
|
|
79
|
+
body: group.pr.body,
|
|
80
|
+
commit_range,
|
|
81
|
+
selected_group_id: group.id,
|
|
82
|
+
}),
|
|
83
|
+
});
|
|
75
84
|
}
|
|
76
85
|
else {
|
|
77
86
|
// delete local group branch if leftover
|
|
@@ -83,6 +92,11 @@ async function run(props) {
|
|
|
83
92
|
branch: group.id,
|
|
84
93
|
base: group.base,
|
|
85
94
|
title: group.title,
|
|
95
|
+
body: StackSummaryTable.write({
|
|
96
|
+
body: "",
|
|
97
|
+
commit_range,
|
|
98
|
+
selected_group_id: group.id,
|
|
99
|
+
}),
|
|
86
100
|
});
|
|
87
101
|
// move back to temp branch
|
|
88
102
|
await cli(`git checkout ${temp_branch_name}`);
|
package/dist/app/MultiSelect.js
CHANGED
|
@@ -54,7 +54,7 @@ export function MultiSelect(props) {
|
|
|
54
54
|
}, [selected_set]);
|
|
55
55
|
Ink.useInput((_input, key) => {
|
|
56
56
|
if (props.disabled) {
|
|
57
|
-
console.debug("[MultiSelect] disabled, ignoring input");
|
|
57
|
+
// console.debug("[MultiSelect] disabled, ignoring input");
|
|
58
58
|
return;
|
|
59
59
|
}
|
|
60
60
|
if (key.return) {
|
package/dist/app/Table.js
CHANGED
|
@@ -26,7 +26,8 @@ export function Table(props) {
|
|
|
26
26
|
const { stdout } = Ink.useStdout();
|
|
27
27
|
const available_width = stdout.columns;
|
|
28
28
|
const columnGap = is_finite_value(props.columnGap) ? props.columnGap : 2;
|
|
29
|
-
|
|
29
|
+
// single character breathing room to prevent url including next line via overflow
|
|
30
|
+
const breathing_room = 1;
|
|
30
31
|
if (props.fillColumn) {
|
|
31
32
|
let remaining_space = available_width;
|
|
32
33
|
for (const col of RowColumnList) {
|
package/dist/app/TextInput.js
CHANGED
|
@@ -5,6 +5,18 @@ export function TextInput(props) {
|
|
|
5
5
|
React.useEffect(function sync_value_prop() {
|
|
6
6
|
set_value(get_value(props));
|
|
7
7
|
}, [props.value]);
|
|
8
|
+
const [caret_visible, set_caret_visible] = React.useState(false);
|
|
9
|
+
React.useEffect(function blink_caret() {
|
|
10
|
+
const interval_ms = 500;
|
|
11
|
+
let timeoutId = setTimeout(tick, interval_ms);
|
|
12
|
+
function tick() {
|
|
13
|
+
set_caret_visible((visible) => !visible);
|
|
14
|
+
timeoutId = setTimeout(tick, interval_ms);
|
|
15
|
+
}
|
|
16
|
+
return function cleanup() {
|
|
17
|
+
clearTimeout(timeoutId);
|
|
18
|
+
};
|
|
19
|
+
}, []);
|
|
8
20
|
Ink.useInput((input, key) => {
|
|
9
21
|
let next_value = value;
|
|
10
22
|
// console.debug("[useInput]", { input, key });
|
|
@@ -30,7 +42,8 @@ export function TextInput(props) {
|
|
|
30
42
|
});
|
|
31
43
|
// console.debug("[TextInput]", { value });
|
|
32
44
|
return (React.createElement(Ink.Box, { borderStyle: "single", minHeight: 1, borderColor: "yellow", borderDimColor: true },
|
|
33
|
-
React.createElement(Ink.Text, null, value || "")
|
|
45
|
+
React.createElement(Ink.Text, null, value || ""),
|
|
46
|
+
!caret_visible ? null : (React.createElement(Ink.Text, { color: "yellow", dimColor: true }, "|"))));
|
|
34
47
|
}
|
|
35
48
|
function get_value(props) {
|
|
36
49
|
return props.value || "";
|
package/dist/command.js
CHANGED
|
@@ -7,30 +7,36 @@ export async function command() {
|
|
|
7
7
|
.option("force", {
|
|
8
8
|
type: "boolean",
|
|
9
9
|
alias: ["f"],
|
|
10
|
+
default: false,
|
|
10
11
|
description: "Force sync even if no changes are detected",
|
|
11
12
|
})
|
|
12
13
|
.option("check", {
|
|
13
14
|
type: "boolean",
|
|
14
15
|
alias: ["c"],
|
|
16
|
+
default: false,
|
|
15
17
|
description: "Print status table without syncing",
|
|
16
18
|
})
|
|
17
|
-
.option("
|
|
19
|
+
.option("verify", {
|
|
18
20
|
type: "boolean",
|
|
21
|
+
default: true,
|
|
19
22
|
description: "Disable the pre-push hook, bypassing it completely",
|
|
20
23
|
})
|
|
21
24
|
.option("verbose", {
|
|
22
25
|
type: "boolean",
|
|
23
26
|
alias: ["v"],
|
|
27
|
+
default: false,
|
|
24
28
|
description: "Enable verbose mode with more detailed output for debugging",
|
|
25
29
|
})
|
|
26
30
|
.option("write-state-json", {
|
|
27
31
|
hidden: true,
|
|
28
32
|
type: "boolean",
|
|
33
|
+
default: false,
|
|
29
34
|
description: "Write state to local json file for debugging",
|
|
30
35
|
})
|
|
31
36
|
.option("mock-metadata", {
|
|
32
37
|
hidden: true,
|
|
33
38
|
type: "boolean",
|
|
39
|
+
default: false,
|
|
34
40
|
description: "Mock local store metadata for testing",
|
|
35
41
|
})
|
|
36
42
|
// do not wrap to 80 columns (yargs default)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { invariant } from "../core/invariant.js";
|
|
2
|
+
import { safe_quote } from "../core/safe_quote.js";
|
|
3
|
+
export function write(message, branch_id) {
|
|
4
|
+
let result = message;
|
|
5
|
+
// escape double-quote for cli
|
|
6
|
+
result = safe_quote(result);
|
|
7
|
+
// remove any previous metadata lines
|
|
8
|
+
result = remove(result);
|
|
9
|
+
const line_list = [result, "", TEMPLATE.branch_id(branch_id)];
|
|
10
|
+
const new_message = line_list.join("\n");
|
|
11
|
+
return new_message;
|
|
12
|
+
}
|
|
13
|
+
export function read(message) {
|
|
14
|
+
const match = message.match(RE.branch_id);
|
|
15
|
+
if (!match?.groups) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const id = match.groups["id"];
|
|
19
|
+
invariant(id, "id must exist");
|
|
20
|
+
return id;
|
|
21
|
+
}
|
|
22
|
+
export function remove(message) {
|
|
23
|
+
let result = message;
|
|
24
|
+
// remove metadata
|
|
25
|
+
result = result.replace(new RegExp(RE.branch_id, "g"), "");
|
|
26
|
+
result = result.trimEnd();
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
const TEMPLATE = {
|
|
30
|
+
branch_id(id) {
|
|
31
|
+
return `git-stack-id: ${id}`;
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
const RE = {
|
|
35
|
+
all_double_quote: /"/g,
|
|
36
|
+
branch_id: new RegExp(TEMPLATE.branch_id("(?<id>[a-z0-9-+]+)"), "i"),
|
|
37
|
+
};
|
package/dist/core/Metadata.js
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export function write(args) {
|
|
2
|
+
const group_list = args.commit_range?.group_list;
|
|
3
|
+
if (!Array.isArray(group_list) || group_list.length === 0) {
|
|
4
|
+
return "";
|
|
5
|
+
}
|
|
6
|
+
const stack_list = [];
|
|
7
|
+
for (const group of group_list) {
|
|
8
|
+
if (group.pr?.url) {
|
|
9
|
+
const selected = args.selected_group_id === group.id;
|
|
10
|
+
const icon = selected ? "👉" : "⏳";
|
|
11
|
+
stack_list.push(`- ${icon} ${group.pr.url}`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const stack_table = TEMPLATE.stack_table(["", ...stack_list, "", ""].join("\n"));
|
|
15
|
+
let result = args.body;
|
|
16
|
+
if (RE.stack_table.test(result)) {
|
|
17
|
+
// replace stack table
|
|
18
|
+
result = result.replace(new RegExp(RE.stack_table), stack_table);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
// append stack table
|
|
22
|
+
result = `${result}\n\n${stack_table}`;
|
|
23
|
+
}
|
|
24
|
+
result = result.trimEnd();
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
const TEMPLATE = {
|
|
28
|
+
stack_table(rows) {
|
|
29
|
+
return `#### git stack${rows}`;
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
const RE = {
|
|
33
|
+
// https://regex101.com/r/kqB9Ft/1
|
|
34
|
+
stack_table: new RegExp(TEMPLATE.stack_table("\\s+(?<rows>(?:- [^\r^\n]*(?:[\r\n]+)?)+)")),
|
|
35
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { invariant } from "./invariant.js";
|
|
2
|
+
import { safe_quote } from "./safe_quote.js";
|
|
3
|
+
export function write(message, branch_id) {
|
|
4
|
+
let result = message;
|
|
5
|
+
// escape double-quote for cli
|
|
6
|
+
result = safe_quote(result);
|
|
7
|
+
// remove any previous metadata lines
|
|
8
|
+
result = remove(result);
|
|
9
|
+
const line_list = [result, "", TEMPLATE.branch_id(branch_id)];
|
|
10
|
+
const new_message = line_list.join("\n");
|
|
11
|
+
return new_message;
|
|
12
|
+
}
|
|
13
|
+
export function read(message) {
|
|
14
|
+
const match = message.match(RE.branch_id);
|
|
15
|
+
if (!match?.groups) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const id = match.groups["id"];
|
|
19
|
+
invariant(id, "id must exist");
|
|
20
|
+
return id;
|
|
21
|
+
}
|
|
22
|
+
export function remove(message) {
|
|
23
|
+
let result = message;
|
|
24
|
+
// remove metadata
|
|
25
|
+
result = result.replace(new RegExp(RE.branch_id, "g"), "");
|
|
26
|
+
result = result.trimEnd();
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
const TEMPLATE = {
|
|
30
|
+
stack_table(rows) {
|
|
31
|
+
return `"#### git stack\n${rows}"`;
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
const RE = {
|
|
35
|
+
all_double_quote: /"/g,
|
|
36
|
+
// https://regex101.com/r/kqB9Ft/1
|
|
37
|
+
stack_table: new RegExp(TEMPLATE.branch_id("(?<id>[a-z0-9-+]+)"), "i"),
|
|
38
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { invariant } from "./invariant.js";
|
|
2
|
+
import { safe_quote } from "./safe_quote.js";
|
|
3
|
+
export function write(message, branch_id) {
|
|
4
|
+
let result = message;
|
|
5
|
+
// escape double-quote for cli
|
|
6
|
+
result = safe_quote(result);
|
|
7
|
+
// remove any previous metadata lines
|
|
8
|
+
result = remove(result);
|
|
9
|
+
const line_list = [result, "", TEMPLATE.branch_id(branch_id)];
|
|
10
|
+
const new_message = line_list.join("\n");
|
|
11
|
+
return new_message;
|
|
12
|
+
}
|
|
13
|
+
export function read(message) {
|
|
14
|
+
const match = message.match(RE.branch_id);
|
|
15
|
+
if (!match?.groups) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const id = match.groups["id"];
|
|
19
|
+
invariant(id, "id must exist");
|
|
20
|
+
return id;
|
|
21
|
+
}
|
|
22
|
+
export function remove(message) {
|
|
23
|
+
let result = message;
|
|
24
|
+
// remove metadata
|
|
25
|
+
result = result.replace(new RegExp(RE.branch_id, "g"), "");
|
|
26
|
+
result = result.trimEnd();
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
const TEMPLATE = {
|
|
30
|
+
stack_table(rows) {
|
|
31
|
+
return `"#### git stack\n${rows}"`;
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
const RE = {
|
|
35
|
+
all_double_quote: /"/g,
|
|
36
|
+
// https://regex101.com/r/kqB9Ft/1
|
|
37
|
+
stack_table: new RegExp(TEMPLATE.branch_id("(?<id>[a-z0-9-+]+)"), "i"),
|
|
38
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import https from "node:https";
|
|
2
|
+
export async function fetch_json(url) {
|
|
3
|
+
return new Promise((resolve, reject) => {
|
|
4
|
+
https
|
|
5
|
+
.get(url, (res) => {
|
|
6
|
+
let data = "";
|
|
7
|
+
res.on("data", (chunk) => {
|
|
8
|
+
data += chunk;
|
|
9
|
+
});
|
|
10
|
+
res.on("end", () => {
|
|
11
|
+
try {
|
|
12
|
+
const json = JSON.parse(data);
|
|
13
|
+
resolve(json);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
reject(error);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
})
|
|
20
|
+
.on("error", (error) => {
|
|
21
|
+
reject(error);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|
package/dist/core/github.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
2
5
|
import * as Ink from "ink";
|
|
3
6
|
import { Brackets } from "../app/Brackets.js";
|
|
4
7
|
import { Store } from "../app/Store.js";
|
|
@@ -6,7 +9,7 @@ import { cli } from "./cli.js";
|
|
|
6
9
|
import { invariant } from "./invariant.js";
|
|
7
10
|
import { safe_quote } from "./safe_quote.js";
|
|
8
11
|
// prettier-ignore
|
|
9
|
-
const JSON_FIELDS = "--json number,state,baseRefName,headRefName,commits,title,url";
|
|
12
|
+
const JSON_FIELDS = "--json number,state,baseRefName,headRefName,commits,title,body,url";
|
|
10
13
|
export async function pr_list() {
|
|
11
14
|
const state = Store.getState();
|
|
12
15
|
const actions = state.actions;
|
|
@@ -79,13 +82,15 @@ export async function pr_status(branch) {
|
|
|
79
82
|
}
|
|
80
83
|
export async function pr_create(args) {
|
|
81
84
|
const title = safe_quote(args.title);
|
|
82
|
-
const cli_result = await cli(`gh pr create --fill --head ${args.branch} --base ${args.base} --title="${title}"`);
|
|
85
|
+
const cli_result = await cli(`gh pr create --fill --head ${args.branch} --base ${args.base} --title="${title}" --body="${args.body}"`);
|
|
83
86
|
if (cli_result.code !== 0) {
|
|
84
87
|
handle_error(cli_result.output);
|
|
85
88
|
}
|
|
86
89
|
}
|
|
87
|
-
export async function
|
|
88
|
-
const cli_result = await cli(
|
|
90
|
+
export async function pr_edit(args) {
|
|
91
|
+
const cli_result = await cli(
|
|
92
|
+
// prettier-ignore
|
|
93
|
+
`gh pr edit ${args.branch} --base ${args.base} --body-file="${body_file(args.body)}"`);
|
|
89
94
|
if (cli_result.code !== 0) {
|
|
90
95
|
handle_error(cli_result.output);
|
|
91
96
|
}
|
|
@@ -98,3 +103,13 @@ function handle_error(output) {
|
|
|
98
103
|
});
|
|
99
104
|
throw new Error(output);
|
|
100
105
|
}
|
|
106
|
+
// convert a string to a file for use via github cli `--body-file`
|
|
107
|
+
function body_file(body) {
|
|
108
|
+
const temp_dir = os.tmpdir();
|
|
109
|
+
const temp_path = path.join(temp_dir, "git-stack-body");
|
|
110
|
+
if (fs.existsSync(temp_path)) {
|
|
111
|
+
fs.rmSync(temp_path);
|
|
112
|
+
}
|
|
113
|
+
fs.writeFileSync(temp_path, body);
|
|
114
|
+
return temp_path;
|
|
115
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// returns +1 if version_a is greater than version_b
|
|
2
|
+
// returns -1 if version_a is less than version_b
|
|
3
|
+
// returns +0 if version_a is exactly equal to version_b
|
|
4
|
+
//
|
|
5
|
+
// Examples
|
|
6
|
+
//
|
|
7
|
+
// semver_compare("0.1.1", "0.0.2"); // 1
|
|
8
|
+
// semver_compare("1.0.1", "0.0.2"); // 1
|
|
9
|
+
// semver_compare("0.0.1", "1.0.2"); // -1
|
|
10
|
+
// semver_compare("0.0.1", "0.1.2"); // -1
|
|
11
|
+
// semver_compare("1.0.1", "1.0.1"); // 0
|
|
12
|
+
//
|
|
13
|
+
export function semver_compare(version_a, version_b) {
|
|
14
|
+
const split_a = version_a.split(".").map(Number);
|
|
15
|
+
const split_b = version_b.split(".").map(Number);
|
|
16
|
+
const max_split_parts = Math.max(split_a.length, split_b.length);
|
|
17
|
+
for (let i = 0; i < max_split_parts; i++) {
|
|
18
|
+
const num_a = split_a[i] || 0;
|
|
19
|
+
const num_b = split_b[i] || 0;
|
|
20
|
+
if (num_a > num_b)
|
|
21
|
+
return 1;
|
|
22
|
+
if (num_a < num_b)
|
|
23
|
+
return -1;
|
|
24
|
+
}
|
|
25
|
+
return 0;
|
|
26
|
+
}
|