git-stack-cli 0.2.1 → 0.3.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 +4 -2
- package/dist/__fixtures__/metadata.js +2 -0
- package/dist/app/Brackets copy.js +10 -0
- package/dist/app/Brackets.js +1 -1
- package/dist/app/Command.js +6 -0
- package/dist/app/Debug.js +7 -6
- package/dist/app/DependencyCheck.js +42 -25
- package/dist/app/GatherMetadata.js +16 -3
- package/dist/app/ManualRebase.js +20 -18
- package/dist/app/Parens.js +1 -1
- package/dist/app/SelectCommitRanges.js +25 -10
- package/dist/app/StatusTable.js +10 -4
- package/dist/app/Store.js +2 -0
- package/dist/app/Url copy.js +6 -0
- package/dist/app/Url.js +6 -0
- package/dist/app/YesNoPrompt.js +5 -3
- package/dist/app/main.js +2 -0
- package/dist/command.js +46 -6
- package/dist/core/CommitMetadata.js +12 -12
- package/dist/core/cli.js +2 -1
- package/dist/core/env.js +4 -0
- package/dist/core/github.js +58 -11
- package/dist/core/is_dev.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,13 +15,15 @@ git multi-diff
|
|
|
15
15
|
npm run dev
|
|
16
16
|
npm link
|
|
17
17
|
|
|
18
|
-
git stack
|
|
19
|
-
git multi-diff
|
|
18
|
+
git stack --debug
|
|
19
|
+
git multi-diff --debug
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
## TODO
|
|
24
24
|
|
|
25
|
+
- point value for querying all pr for user vs individual pr status (current)?
|
|
26
|
+
|
|
25
27
|
- select commit ranges
|
|
26
28
|
- capture PR title when creating new group
|
|
27
29
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// prettier-ignore
|
|
2
2
|
export const METADATA = {
|
|
3
|
+
"username": "magus",
|
|
4
|
+
"repo_path": "magus/git-multi-diff-playground",
|
|
3
5
|
"head": "1a50c5fe3cd129547c5c34a54d1611ec06ab213e",
|
|
4
6
|
"merge_base": "9528176b12abf81c779bc5244afc7d760f6fa422",
|
|
5
7
|
"branch_name": "dev/noah/a-test",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as Ink from "ink";
|
|
3
|
+
export function Brackets(props) {
|
|
4
|
+
const color = "#f97316";
|
|
5
|
+
const text_color = "#06b6d4";
|
|
6
|
+
return (React.createElement(Ink.Text, { color: text_color },
|
|
7
|
+
React.createElement(Ink.Text, { color: color }, "["),
|
|
8
|
+
props.children,
|
|
9
|
+
React.createElement(Ink.Text, { color: color }, "]")));
|
|
10
|
+
}
|
package/dist/app/Brackets.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import * as Ink from "ink";
|
|
3
3
|
export function Brackets(props) {
|
|
4
4
|
const color = "#f97316";
|
|
5
|
-
const text_color = "#
|
|
5
|
+
const text_color = "#38bdf8";
|
|
6
6
|
return (React.createElement(Ink.Text, { color: text_color },
|
|
7
7
|
React.createElement(Ink.Text, { color: color }, "["),
|
|
8
8
|
props.children,
|
package/dist/app/Debug.js
CHANGED
|
@@ -8,15 +8,16 @@ import { Store } from "./Store.js";
|
|
|
8
8
|
export function Debug() {
|
|
9
9
|
const actions = Store.useActions();
|
|
10
10
|
const state = Store.useState((state) => state);
|
|
11
|
-
const
|
|
11
|
+
const argv = Store.useState((state) => state.argv);
|
|
12
12
|
React.useEffect(function debugMessageOnce() {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
actions.debug(React.createElement(Ink.Text, { color: "yellow" }, "Debug mode enabled"));
|
|
14
|
+
if (argv?.verbose) {
|
|
15
|
+
actions.debug(React.createElement(Ink.Text, { dimColor: true }, JSON.stringify(argv, null, 2)));
|
|
15
16
|
}
|
|
16
|
-
}, [
|
|
17
|
+
}, [argv]);
|
|
17
18
|
React.useEffect(function syncStateJson() {
|
|
18
19
|
invariant(state.cwd, "state.cwd must exist");
|
|
19
|
-
if (!
|
|
20
|
+
if (!argv?.["write-state-json"]) {
|
|
20
21
|
return;
|
|
21
22
|
}
|
|
22
23
|
const output_file = path.join(state.cwd, "git-multi-diff-state.json");
|
|
@@ -26,6 +27,6 @@ export function Debug() {
|
|
|
26
27
|
const serialized = json.serialize(state);
|
|
27
28
|
const content = JSON.stringify(serialized, null, 2);
|
|
28
29
|
fs.writeFileSync(output_file, content);
|
|
29
|
-
}, [
|
|
30
|
+
}, [argv, state]);
|
|
30
31
|
return null;
|
|
31
32
|
}
|
|
@@ -2,51 +2,68 @@ import * as React from "react";
|
|
|
2
2
|
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
|
+
import { match_group } from "../core/match_group.js";
|
|
5
6
|
import { Await } from "./Await.js";
|
|
7
|
+
import { Command } from "./Command.js";
|
|
8
|
+
import { Parens } from "./Parens.js";
|
|
6
9
|
import { Store } from "./Store.js";
|
|
10
|
+
import { Url } from "./Url.js";
|
|
7
11
|
export function DependencyCheck(props) {
|
|
8
12
|
const actions = Store.useActions();
|
|
9
|
-
return (React.createElement(Await, { fallback: React.createElement(Ink.
|
|
10
|
-
|
|
13
|
+
return (React.createElement(Await, { fallback: React.createElement(Ink.Text, { color: "yellow" },
|
|
14
|
+
"Checking ",
|
|
15
|
+
React.createElement(Command, null, "git"),
|
|
16
|
+
" install..."), function: async () => {
|
|
11
17
|
if (is_command_available("git")) {
|
|
12
18
|
return;
|
|
13
19
|
}
|
|
14
|
-
actions.output(React.createElement(Ink.Text,
|
|
15
|
-
React.createElement(
|
|
20
|
+
actions.output(React.createElement(Ink.Text, { color: "yellow" },
|
|
21
|
+
React.createElement(Command, null, "git"),
|
|
16
22
|
" must be installed."));
|
|
17
23
|
actions.exit(2);
|
|
18
24
|
} },
|
|
19
|
-
React.createElement(Await, { fallback: React.createElement(Ink.
|
|
20
|
-
React.createElement(Ink.Text, null,
|
|
25
|
+
React.createElement(Await, { fallback: React.createElement(Ink.Text, { color: "yellow" },
|
|
26
|
+
React.createElement(Ink.Text, null,
|
|
27
|
+
"Checking ",
|
|
28
|
+
React.createElement(Command, null, "gh"),
|
|
29
|
+
" install...")), function: async () => {
|
|
21
30
|
if (is_command_available("gh")) {
|
|
22
31
|
return;
|
|
23
32
|
}
|
|
24
|
-
actions.output(React.createElement(Ink.Text,
|
|
25
|
-
React.createElement(
|
|
33
|
+
actions.output(React.createElement(Ink.Text, { color: "yellow" },
|
|
34
|
+
React.createElement(Command, null, "gh"),
|
|
26
35
|
" must be installed."));
|
|
27
|
-
actions.output(React.createElement(Ink.
|
|
28
|
-
React.createElement(Ink.Text, null, "Visit"),
|
|
29
|
-
React.createElement(
|
|
30
|
-
React.createElement(Ink.Text, null, "to install the github cli"),
|
|
31
|
-
React.createElement(
|
|
32
|
-
|
|
33
|
-
React.createElement(Ink.Text, { color: "yellow" }, "gh"),
|
|
34
|
-
")")));
|
|
36
|
+
actions.output(React.createElement(Ink.Text, { color: "yellow" },
|
|
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"))));
|
|
35
42
|
actions.exit(3);
|
|
36
43
|
} },
|
|
37
|
-
React.createElement(Await, { fallback: React.createElement(Ink.
|
|
38
|
-
React.createElement(Ink.Text, null,
|
|
39
|
-
|
|
44
|
+
React.createElement(Await, { fallback: React.createElement(Ink.Text, { color: "yellow" },
|
|
45
|
+
React.createElement(Ink.Text, null,
|
|
46
|
+
"Checking ",
|
|
47
|
+
React.createElement(Command, null, "gh auth status"),
|
|
48
|
+
"...")), function: async () => {
|
|
49
|
+
const auth_output = await cli(`gh auth status`, {
|
|
40
50
|
ignoreExitCode: true,
|
|
41
51
|
});
|
|
42
|
-
if (
|
|
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
57
|
return;
|
|
44
58
|
}
|
|
45
|
-
actions.output(React.createElement(Ink.
|
|
46
|
-
React.createElement(
|
|
47
|
-
React.createElement(Ink.Text, null, "requires login, please run"),
|
|
48
|
-
React.createElement(
|
|
49
|
-
React.createElement(Ink.Text, { color: "yellow" }, "gh auth login"))));
|
|
59
|
+
actions.output(React.createElement(Ink.Text, { color: "yellow" },
|
|
60
|
+
React.createElement(Command, null, "gh"),
|
|
61
|
+
React.createElement(Ink.Text, null, " requires login, please run "),
|
|
62
|
+
React.createElement(Command, null, "gh auth login")));
|
|
50
63
|
actions.exit(4);
|
|
51
64
|
} }, props.children))));
|
|
52
65
|
}
|
|
66
|
+
const RE = {
|
|
67
|
+
// Logged in to github.com as magus
|
|
68
|
+
auth_username: /Logged in to github.com as (?<username>[^\s]+)/,
|
|
69
|
+
};
|
|
@@ -4,6 +4,7 @@ import * as CommitMetadata from "../core/CommitMetadata.js";
|
|
|
4
4
|
import { cli } from "../core/cli.js";
|
|
5
5
|
import { invariant } from "../core/invariant.js";
|
|
6
6
|
import * as json from "../core/json.js";
|
|
7
|
+
import { match_group } from "../core/match_group.js";
|
|
7
8
|
import { Await } from "./Await.js";
|
|
8
9
|
import { Store } from "./Store.js";
|
|
9
10
|
export function GatherMetadata(props) {
|
|
@@ -34,13 +35,20 @@ async function gather_metadata() {
|
|
|
34
35
|
actions.exit(0);
|
|
35
36
|
return;
|
|
36
37
|
}
|
|
38
|
+
// git@github.com:magus/git-multi-diff-playground.git
|
|
39
|
+
// https://github.com/magus/git-multi-diff-playground.git
|
|
40
|
+
const origin_url = (await cli(`git config --get remote.origin.url`)).stdout;
|
|
41
|
+
const repo_path = match_group(origin_url, RE.repo_path, "repo_path");
|
|
37
42
|
const branch_name = (await cli("git rev-parse --abbrev-ref HEAD")).stdout;
|
|
43
|
+
Store.setState((state) => {
|
|
44
|
+
state.repo_path = repo_path;
|
|
45
|
+
state.head = head;
|
|
46
|
+
state.merge_base = merge_base;
|
|
47
|
+
state.branch_name = branch_name;
|
|
48
|
+
});
|
|
38
49
|
try {
|
|
39
50
|
const commit_range = await CommitMetadata.range();
|
|
40
51
|
Store.setState((state) => {
|
|
41
|
-
state.head = head;
|
|
42
|
-
state.merge_base = merge_base;
|
|
43
|
-
state.branch_name = branch_name;
|
|
44
52
|
state.commit_range = commit_range;
|
|
45
53
|
state.step = "status";
|
|
46
54
|
});
|
|
@@ -52,3 +60,8 @@ async function gather_metadata() {
|
|
|
52
60
|
}
|
|
53
61
|
}
|
|
54
62
|
}
|
|
63
|
+
const RE = {
|
|
64
|
+
// git@github.com:magus/git-multi-diff-playground.git
|
|
65
|
+
// https://github.com/magus/git-multi-diff-playground.git
|
|
66
|
+
repo_path: /(?<repo_path>[^:^/]+\/[^/]+)\.git/,
|
|
67
|
+
};
|
package/dist/app/ManualRebase.js
CHANGED
|
@@ -9,10 +9,10 @@ import { invariant } from "../core/invariant.js";
|
|
|
9
9
|
import { Await } from "./Await.js";
|
|
10
10
|
import { Brackets } from "./Brackets.js";
|
|
11
11
|
import { Store } from "./Store.js";
|
|
12
|
-
export function ManualRebase() {
|
|
13
|
-
return (React.createElement(Await, { fallback: React.createElement(Ink.Text, { color: "yellow" }, "Rebasing commits..."), function: run }));
|
|
12
|
+
export function ManualRebase(props) {
|
|
13
|
+
return (React.createElement(Await, { fallback: React.createElement(Ink.Text, { color: "yellow" }, "Rebasing commits..."), function: () => run(props) }));
|
|
14
14
|
}
|
|
15
|
-
async function run() {
|
|
15
|
+
async function run(props) {
|
|
16
16
|
const state = Store.getState();
|
|
17
17
|
const actions = state.actions;
|
|
18
18
|
const branch_name = state.branch_name;
|
|
@@ -61,21 +61,23 @@ async function run() {
|
|
|
61
61
|
"Syncing ",
|
|
62
62
|
React.createElement(Brackets, null, group.pr?.title || group.id),
|
|
63
63
|
"..."));
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
64
|
+
if (!props.skipSync) {
|
|
65
|
+
// push to origin since github requires commit shas to line up perfectly
|
|
66
|
+
await cli(`git push -f origin HEAD:${group.id}`);
|
|
67
|
+
if (group.pr) {
|
|
68
|
+
// ensure base matches pr in github
|
|
69
|
+
await github.pr_base(group.id, group.base);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// delete local group branch if leftover
|
|
73
|
+
await cli(`git branch -D ${group.id}`, { ignoreExitCode: true });
|
|
74
|
+
// move to temporary branch for creating pr
|
|
75
|
+
await cli(`git checkout -b ${group.id}`);
|
|
76
|
+
// create pr in github
|
|
77
|
+
await github.pr_create(group.id, group.base);
|
|
78
|
+
// move back to temp branch
|
|
79
|
+
await cli(`git checkout ${temp_branch_name}`);
|
|
80
|
+
}
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
83
|
// after all commits have been cherry-picked and amended
|
package/dist/app/Parens.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as Ink from "ink";
|
|
3
3
|
export function Parens(props) {
|
|
4
|
-
const color = "#
|
|
4
|
+
const color = "#38bdf8";
|
|
5
5
|
return (React.createElement(Ink.Text, null,
|
|
6
6
|
React.createElement(Ink.Text, { color: color }, "("),
|
|
7
7
|
props.children,
|
|
@@ -59,7 +59,7 @@ function SelectCommitRangesInternal(props) {
|
|
|
59
59
|
const current_index = group_list.findIndex((g) => g.id === selected_group_id);
|
|
60
60
|
Ink.useInput((input, key) => {
|
|
61
61
|
const inputLower = input.toLowerCase();
|
|
62
|
-
if (unassigned_count === 0 && inputLower === "s") {
|
|
62
|
+
if (unassigned_count === 0 && (inputLower === "r" || inputLower === "s")) {
|
|
63
63
|
actions.set((state) => {
|
|
64
64
|
state.commit_map = {};
|
|
65
65
|
for (const [sha, id] of commit_map.entries()) {
|
|
@@ -67,7 +67,13 @@ function SelectCommitRangesInternal(props) {
|
|
|
67
67
|
state.commit_map[sha] = id;
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
-
|
|
70
|
+
switch (inputLower) {
|
|
71
|
+
case "s":
|
|
72
|
+
state.step = "manual-rebase";
|
|
73
|
+
break;
|
|
74
|
+
case "r":
|
|
75
|
+
state.step = "manual-rebase-no-sync";
|
|
76
|
+
}
|
|
71
77
|
});
|
|
72
78
|
return;
|
|
73
79
|
}
|
|
@@ -154,14 +160,23 @@ function SelectCommitRangesInternal(props) {
|
|
|
154
160
|
React.createElement(Ink.Text, { bold: true, color: "#22c55e" },
|
|
155
161
|
React.createElement(Parens, null, "c"),
|
|
156
162
|
"reate"),
|
|
157
|
-
" a new group")))) : (React.createElement(
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
React.createElement(
|
|
163
|
-
|
|
164
|
-
|
|
163
|
+
" a new group")))) : (React.createElement(React.Fragment, null,
|
|
164
|
+
React.createElement(Ink.Text, null,
|
|
165
|
+
"🎉 Done! Press ",
|
|
166
|
+
React.createElement(Ink.Text, { bold: true, color: "#22c55e" }, "s"),
|
|
167
|
+
" to ",
|
|
168
|
+
React.createElement(Ink.Text, { bold: true, color: "#22c55e" },
|
|
169
|
+
React.createElement(Parens, null, "s"),
|
|
170
|
+
"ync"),
|
|
171
|
+
" the commits to Github"),
|
|
172
|
+
React.createElement(Ink.Text, { color: "gray" },
|
|
173
|
+
React.createElement(Ink.Text, null, "Press "),
|
|
174
|
+
React.createElement(Ink.Text, { bold: true, color: "#22c55e" }, "r"),
|
|
175
|
+
" to locally ",
|
|
176
|
+
React.createElement(Ink.Text, { bold: true, color: "#22c55e" },
|
|
177
|
+
React.createElement(Parens, null, "r"),
|
|
178
|
+
"ebase"),
|
|
179
|
+
" only"))),
|
|
165
180
|
React.createElement(Ink.Box, null,
|
|
166
181
|
React.createElement(Ink.Text, { color: "gray" },
|
|
167
182
|
React.createElement(Ink.Text, null, "Press "),
|
package/dist/app/StatusTable.js
CHANGED
|
@@ -15,7 +15,7 @@ export function StatusTable() {
|
|
|
15
15
|
title: "",
|
|
16
16
|
url: "",
|
|
17
17
|
};
|
|
18
|
-
if (
|
|
18
|
+
if (group.id === commit_range.UNASSIGNED) {
|
|
19
19
|
row.icon = "⭑";
|
|
20
20
|
row.status = "NEW";
|
|
21
21
|
row.title = "Unassigned";
|
|
@@ -31,9 +31,15 @@ export function StatusTable() {
|
|
|
31
31
|
row.icon = "✔";
|
|
32
32
|
row.status = "SYNCED";
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
if (group.pr) {
|
|
35
|
+
row.title = group.pr.title;
|
|
36
|
+
row.count = `${group.pr.commits.length}/${group.commits.length}`;
|
|
37
|
+
row.url = group.pr.url;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
row.title = group.id;
|
|
41
|
+
row.count = `0/${group.commits.length}`;
|
|
42
|
+
}
|
|
37
43
|
}
|
|
38
44
|
row_list.push(row);
|
|
39
45
|
}
|
package/dist/app/Store.js
CHANGED
package/dist/app/Url.js
ADDED
package/dist/app/YesNoPrompt.js
CHANGED
|
@@ -2,8 +2,10 @@ import * as React from "react";
|
|
|
2
2
|
import * as Ink from "ink";
|
|
3
3
|
import { Parens } from "./Parens.js";
|
|
4
4
|
export function YesNoPrompt(props) {
|
|
5
|
+
const [answer, set_answer] = React.useState("");
|
|
5
6
|
Ink.useInput((input) => {
|
|
6
7
|
const inputLower = input.toLowerCase();
|
|
8
|
+
set_answer(inputLower);
|
|
7
9
|
switch (inputLower) {
|
|
8
10
|
case "n":
|
|
9
11
|
return props.onNo();
|
|
@@ -17,7 +19,7 @@ export function YesNoPrompt(props) {
|
|
|
17
19
|
React.createElement(Ink.Text, null, " "),
|
|
18
20
|
React.createElement(Parens, null,
|
|
19
21
|
React.createElement(Ink.Text, { color: "gray" },
|
|
20
|
-
React.createElement(Ink.Text, { bold: true, color: "#22c55e" }, "Y"),
|
|
21
|
-
"/",
|
|
22
|
-
React.createElement(Ink.Text, { color: "#ef4444" }, "n"))))));
|
|
22
|
+
answer && answer !== "y" ? null : (React.createElement(Ink.Text, { bold: true, color: "#22c55e" }, "Y")),
|
|
23
|
+
answer ? null : React.createElement(Ink.Text, null, "/"),
|
|
24
|
+
answer && answer !== "n" ? null : (React.createElement(Ink.Text, { color: "#ef4444" }, "n")))))));
|
|
23
25
|
}
|
package/dist/app/main.js
CHANGED
|
@@ -22,6 +22,8 @@ export function Main() {
|
|
|
22
22
|
return React.createElement(SelectCommitRanges, null);
|
|
23
23
|
case "manual-rebase":
|
|
24
24
|
return React.createElement(ManualRebase, null);
|
|
25
|
+
case "manual-rebase-no-sync":
|
|
26
|
+
return React.createElement(ManualRebase, { skipSync: true });
|
|
25
27
|
case "post-rebase-status":
|
|
26
28
|
return React.createElement(PostRebaseStatus, null);
|
|
27
29
|
default:
|
package/dist/command.js
CHANGED
|
@@ -1,22 +1,62 @@
|
|
|
1
1
|
import yargs from "yargs";
|
|
2
2
|
import { hideBin } from "yargs/helpers";
|
|
3
3
|
export async function command() {
|
|
4
|
-
|
|
4
|
+
const debug_argv = await yargs(hideBin(process.argv))
|
|
5
|
+
.option("debug", {
|
|
6
|
+
type: "boolean",
|
|
7
|
+
description: "Enable debug mode with more options for debugging",
|
|
8
|
+
})
|
|
9
|
+
.help(false).argv;
|
|
10
|
+
if (!debug_argv.debug) {
|
|
11
|
+
return NormalMode();
|
|
12
|
+
}
|
|
13
|
+
return DebugMode();
|
|
14
|
+
}
|
|
15
|
+
function NormalMode() {
|
|
16
|
+
return (yargs(hideBin(process.argv))
|
|
17
|
+
.option("force", {
|
|
18
|
+
type: "boolean",
|
|
19
|
+
description: "Force sync even if no changes are detected",
|
|
20
|
+
})
|
|
21
|
+
.option("check", {
|
|
22
|
+
type: "boolean",
|
|
23
|
+
description: "Print status table without syncing",
|
|
24
|
+
})
|
|
25
|
+
.option("debug", {
|
|
26
|
+
type: "boolean",
|
|
27
|
+
description: "Enable debug mode with more options for debugging",
|
|
28
|
+
})
|
|
29
|
+
// disallow unknown options
|
|
30
|
+
.strict()
|
|
31
|
+
.help().argv);
|
|
32
|
+
}
|
|
33
|
+
function DebugMode() {
|
|
34
|
+
return (yargs(hideBin(process.argv))
|
|
5
35
|
.option("force", {
|
|
6
36
|
type: "boolean",
|
|
7
|
-
description: "
|
|
37
|
+
description: "Force sync even if no changes are detected",
|
|
8
38
|
})
|
|
9
39
|
.option("check", {
|
|
10
40
|
type: "boolean",
|
|
11
|
-
description: "
|
|
41
|
+
description: "Print status table without syncing",
|
|
12
42
|
})
|
|
13
43
|
.option("debug", {
|
|
14
44
|
type: "boolean",
|
|
15
|
-
description: "debug",
|
|
45
|
+
description: "Enable debug mode with more options for debugging",
|
|
46
|
+
})
|
|
47
|
+
.option("verbose", {
|
|
48
|
+
type: "boolean",
|
|
49
|
+
description: "Log extra information during execution",
|
|
50
|
+
})
|
|
51
|
+
.option("write-state-json", {
|
|
52
|
+
type: "boolean",
|
|
53
|
+
description: "Write state to local json file for debugging",
|
|
16
54
|
})
|
|
17
55
|
.option("mock-metadata", {
|
|
18
56
|
type: "boolean",
|
|
19
|
-
description: "
|
|
57
|
+
description: "Mock local store metadata for testing",
|
|
20
58
|
})
|
|
21
|
-
|
|
59
|
+
// disallow unknown options
|
|
60
|
+
.strict()
|
|
61
|
+
.help().argv);
|
|
22
62
|
}
|
|
@@ -2,6 +2,9 @@ import * as Metadata from "./Metadata.js";
|
|
|
2
2
|
import { cli } from "./cli.js";
|
|
3
3
|
import * as github from "./github.js";
|
|
4
4
|
export async function range(commit_map) {
|
|
5
|
+
// gather all open prs in repo first
|
|
6
|
+
// cheaper query to populate cache
|
|
7
|
+
await github.pr_list();
|
|
5
8
|
const commit_list = await get_commit_list();
|
|
6
9
|
let invalid = false;
|
|
7
10
|
const group_map = new Map();
|
|
@@ -11,9 +14,8 @@ export async function range(commit_map) {
|
|
|
11
14
|
if (commit_map) {
|
|
12
15
|
id = commit_map[commit.sha];
|
|
13
16
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// console.debug("INVALID", "MISSING PR", commit.message);
|
|
17
|
+
if (!id) {
|
|
18
|
+
// console.debug("INVALID", "MISSING ID", commit.message);
|
|
17
19
|
invalid = true;
|
|
18
20
|
}
|
|
19
21
|
if (id) {
|
|
@@ -33,7 +35,7 @@ export async function range(commit_map) {
|
|
|
33
35
|
}
|
|
34
36
|
const group = group_map.get(id) || {
|
|
35
37
|
id,
|
|
36
|
-
pr,
|
|
38
|
+
pr: null,
|
|
37
39
|
base: null,
|
|
38
40
|
dirty: false,
|
|
39
41
|
commits: [],
|
|
@@ -47,6 +49,12 @@ export async function range(commit_map) {
|
|
|
47
49
|
let unassigned_group;
|
|
48
50
|
for (let i = 0; i < group_value_list.length; i++) {
|
|
49
51
|
const group = group_value_list[i];
|
|
52
|
+
if (group.id !== UNASSIGNED) {
|
|
53
|
+
const pr_result = await github.pr_status(group.id);
|
|
54
|
+
if (pr_result && pr_result.state === "OPEN") {
|
|
55
|
+
group.pr = pr_result;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
50
58
|
// console.debug("group", group.pr?.title.substring(0, 40));
|
|
51
59
|
// console.debug(" ", "id", group.id);
|
|
52
60
|
if (group.id === UNASSIGNED) {
|
|
@@ -117,18 +125,10 @@ export async function commit(sha) {
|
|
|
117
125
|
const raw_message = (await cli(`git show -s --format=%B ${sha}`)).stdout;
|
|
118
126
|
const branch_id = await Metadata.read(raw_message);
|
|
119
127
|
const message = display_message(raw_message);
|
|
120
|
-
let pr = null;
|
|
121
|
-
if (branch_id) {
|
|
122
|
-
const pr_result = await github.pr_status(branch_id);
|
|
123
|
-
if (pr_result && pr_result.state === "OPEN") {
|
|
124
|
-
pr = pr_result;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
128
|
return {
|
|
128
129
|
sha,
|
|
129
130
|
message,
|
|
130
131
|
raw_message,
|
|
131
|
-
pr,
|
|
132
132
|
branch_id,
|
|
133
133
|
};
|
|
134
134
|
}
|
package/dist/core/cli.js
CHANGED
|
@@ -20,6 +20,7 @@ export async function cli(command, unsafe_options) {
|
|
|
20
20
|
}
|
|
21
21
|
else {
|
|
22
22
|
const result = {
|
|
23
|
+
command,
|
|
23
24
|
code: code || 0,
|
|
24
25
|
stdout: stdout.trimEnd(),
|
|
25
26
|
stderr: stderr.trimEnd(),
|
|
@@ -40,5 +41,5 @@ cli.sync = function cli_sync(command, unsafe_options) {
|
|
|
40
41
|
const stderr = String(spawn_return.stderr);
|
|
41
42
|
const output = String(spawn_return.output);
|
|
42
43
|
const code = spawn_return.status || 0;
|
|
43
|
-
return { code, stdout, stderr, output };
|
|
44
|
+
return { command, code, stdout, stderr, output };
|
|
44
45
|
};
|
package/dist/core/env.js
ADDED
package/dist/core/github.js
CHANGED
|
@@ -1,20 +1,46 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as Ink from "ink";
|
|
3
|
+
import { Brackets } from "../app/Brackets.js";
|
|
3
4
|
import { Store } from "../app/Store.js";
|
|
4
5
|
import { cli } from "./cli.js";
|
|
5
|
-
|
|
6
|
+
import { invariant } from "./invariant.js";
|
|
7
|
+
// prettier-ignore
|
|
8
|
+
const JSON_FIELDS = "--json number,state,baseRefName,headRefName,commits,title,url";
|
|
9
|
+
export async function pr_list() {
|
|
6
10
|
const state = Store.getState();
|
|
7
11
|
const actions = state.actions;
|
|
8
|
-
const
|
|
12
|
+
const username = state.username;
|
|
13
|
+
const repo_path = state.repo_path;
|
|
14
|
+
invariant(username, "username must exist");
|
|
15
|
+
invariant(repo_path, "repo_path must exist");
|
|
16
|
+
const cli_result = await cli(`gh pr list --repo ${repo_path} --author ${username} --state open ${JSON_FIELDS}`, {
|
|
9
17
|
ignoreExitCode: true,
|
|
10
18
|
});
|
|
11
|
-
if (
|
|
12
|
-
|
|
13
|
-
actions.set((state) => {
|
|
14
|
-
state.step = "github-api-error";
|
|
15
|
-
});
|
|
16
|
-
throw new Error("Unable to fetch PR status");
|
|
19
|
+
if (cli_result.code !== 0) {
|
|
20
|
+
handle_error(cli_result.output);
|
|
17
21
|
}
|
|
22
|
+
const result_pr_list = JSON.parse(cli_result.stdout);
|
|
23
|
+
actions.debug(React.createElement(Ink.Text, { dimColor: true },
|
|
24
|
+
React.createElement(Ink.Text, null, "Github cache "),
|
|
25
|
+
React.createElement(Ink.Text, { bold: true, color: "yellow" }, result_pr_list.length),
|
|
26
|
+
React.createElement(Ink.Text, null, " open PRs from "),
|
|
27
|
+
React.createElement(Brackets, null, repo_path),
|
|
28
|
+
React.createElement(Ink.Text, null, " authored by "),
|
|
29
|
+
React.createElement(Brackets, null, username)));
|
|
30
|
+
actions.set((state) => {
|
|
31
|
+
for (const pr of result_pr_list) {
|
|
32
|
+
state.pr[pr.headRefName] = pr;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return result_pr_list;
|
|
36
|
+
}
|
|
37
|
+
export async function pr_status(branch) {
|
|
38
|
+
const state = Store.getState();
|
|
39
|
+
const actions = state.actions;
|
|
40
|
+
const username = state.username;
|
|
41
|
+
const repo_path = state.repo_path;
|
|
42
|
+
invariant(username, "username must exist");
|
|
43
|
+
invariant(repo_path, "repo_path must exist");
|
|
18
44
|
const cache = state.pr[branch];
|
|
19
45
|
if (cache) {
|
|
20
46
|
actions.debug(React.createElement(Ink.Text, null,
|
|
@@ -31,15 +57,36 @@ export async function pr_status(branch) {
|
|
|
31
57
|
React.createElement(Ink.Text, { bold: true, color: "#ef4444" }, "MISS"),
|
|
32
58
|
React.createElement(Ink.Text, null, " "),
|
|
33
59
|
React.createElement(Ink.Text, { dimColor: true }, branch)));
|
|
34
|
-
const
|
|
60
|
+
const cli_result = await cli(`gh pr view ${branch} --repo ${repo_path} ${JSON_FIELDS}`, {
|
|
61
|
+
ignoreExitCode: true,
|
|
62
|
+
});
|
|
63
|
+
if (cli_result.code !== 0) {
|
|
64
|
+
// handle_error(cli_result.output);
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const pr = JSON.parse(cli_result.stdout);
|
|
35
68
|
actions.set((state) => {
|
|
36
69
|
state.pr[pr.headRefName] = pr;
|
|
37
70
|
});
|
|
38
71
|
return pr;
|
|
39
72
|
}
|
|
40
73
|
export async function pr_create(branch, base) {
|
|
41
|
-
await cli(`gh pr create --fill --head ${branch} --base ${base}`);
|
|
74
|
+
const cli_result = await cli(`gh pr create --fill --head ${branch} --base ${base}`);
|
|
75
|
+
if (cli_result.code !== 0) {
|
|
76
|
+
handle_error(cli_result.output);
|
|
77
|
+
}
|
|
42
78
|
}
|
|
43
79
|
export async function pr_base(branch, base) {
|
|
44
|
-
await cli(`gh pr edit ${branch} --base ${base}`);
|
|
80
|
+
const cli_result = await cli(`gh pr edit ${branch} --base ${base}`);
|
|
81
|
+
if (cli_result.code !== 0) {
|
|
82
|
+
handle_error(cli_result.output);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function handle_error(output) {
|
|
86
|
+
const state = Store.getState();
|
|
87
|
+
const actions = state.actions;
|
|
88
|
+
actions.set((state) => {
|
|
89
|
+
state.step = "github-api-error";
|
|
90
|
+
});
|
|
91
|
+
throw new Error(output);
|
|
45
92
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|