git-stack-cli 0.8.2 → 0.8.3

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.
Files changed (45) hide show
  1. package/dist/__fixtures__/metadata.json +186 -0
  2. package/dist/app/App copy.js +30 -0
  3. package/dist/app/ArgCheck.js +21 -0
  4. package/dist/app/Brackets copy.js +10 -0
  5. package/dist/app/Counter.js +19 -0
  6. package/dist/app/GatherMetadata copy.js +91 -0
  7. package/dist/app/GatherMetadata.js +7 -0
  8. package/dist/app/InitMetadata.js +14 -0
  9. package/dist/app/Input.js +15 -0
  10. package/dist/app/KeepAlive.js +11 -0
  11. package/dist/app/LocalMergeRebase.js +5 -1
  12. package/dist/app/Main copy.js +200 -0
  13. package/dist/app/ManualRebase copy.js +127 -0
  14. package/dist/app/ManualRebase.js +5 -1
  15. package/dist/app/MultiSelect copy.js +76 -0
  16. package/dist/app/NPMAutoUpdate.js +34 -0
  17. package/dist/app/Parens copy.js +9 -0
  18. package/dist/app/PostRebaseStatus copy.js +23 -0
  19. package/dist/app/PreSelectCommitRanges copy.js +21 -0
  20. package/dist/app/SelectCommitRange.js +1 -0
  21. package/dist/app/Status copy.js +46 -0
  22. package/dist/app/Url copy.js +6 -0
  23. package/dist/app/YesNoPrompt copy.js +24 -0
  24. package/dist/cli.js +9 -0
  25. package/dist/core/Metadata copy.js +37 -0
  26. package/dist/core/StackTable.js +38 -0
  27. package/dist/core/SummaryTable.js +38 -0
  28. package/dist/core/ZustandStore.js +23 -0
  29. package/dist/core/cli copy.js +44 -0
  30. package/dist/core/color.js +83 -0
  31. package/dist/core/dependency_check.js +27 -0
  32. package/dist/core/exit.js +4 -0
  33. package/dist/core/get_commit_metadata.js +61 -0
  34. package/dist/core/id.js +61 -0
  35. package/dist/core/invariant copy.js +5 -0
  36. package/dist/core/isFiniteValue.js +3 -0
  37. package/dist/core/is_dev.js +1 -0
  38. package/dist/core/readJson.js +3 -0
  39. package/dist/core/serialize_json.js +17 -0
  40. package/dist/core/sleep copy.js +3 -0
  41. package/dist/main copy.js +266 -0
  42. package/dist/main.backup.js +266 -0
  43. package/dist/main.js +265 -0
  44. package/package.json +6 -4
  45. /package/dist/app/{Main.js → main.js} +0 -0
@@ -0,0 +1,186 @@
1
+ {
2
+ "head": "cc09b96b823d9dde77188e675d3090be7c1d625a",
3
+ "merge_base": "9528176b12abf81c779bc5244afc7d760f6fa422",
4
+ "branch_name": "dev/noah/a-test",
5
+ "commit_range": {
6
+ "invalid": true,
7
+ "group_map": {},
8
+ "commit_list": [
9
+ {
10
+ "sha": "a28f1ef080b56b56699bc420b200968e793702a9",
11
+ "message": "more remove",
12
+ "raw_message": "more remove\n\ngit-multi-diff-id: 14e097a1-fa9b-45af-8f7d-b77df9d91fe6",
13
+ "pr": {
14
+ "baseRefName": "master",
15
+ "commits": [
16
+ {
17
+ "authoredDate": "2023-10-22T23:13:20Z",
18
+ "authors": [
19
+ {
20
+ "email": "noah@iamnoah.com",
21
+ "id": "MDQ6VXNlcjI5MDA4NA==",
22
+ "login": "magus",
23
+ "name": "magus"
24
+ }
25
+ ],
26
+ "committedDate": "2023-10-28T19:16:29Z",
27
+ "messageBody": "git-multi-diff-id: 14e097a1-fa9b-45af-8f7d-b77df9d91fe6",
28
+ "messageHeadline": "more remove",
29
+ "oid": "a28f1ef080b56b56699bc420b200968e793702a9"
30
+ }
31
+ ],
32
+ "headRefName": "14e097a1-fa9b-45af-8f7d-b77df9d91fe6",
33
+ "number": 28,
34
+ "state": "OPEN",
35
+ "title": "more remove",
36
+ "url": "https://github.com/magus/git-multi-diff-playground/pull/28"
37
+ },
38
+ "metadata": {
39
+ "id": "14e097a1-fa9b-45af-8f7d-b77df9d91fe6"
40
+ }
41
+ },
42
+ {
43
+ "sha": "7454ce81940f2a0964ff06c7a98c7fa1892f82bf",
44
+ "message": "remove num",
45
+ "raw_message": "remove num\n\ngit-multi-diff-id: 3d1d890d-11c9-4569-83c3-e3aff6426e37",
46
+ "pr": {
47
+ "baseRefName": "14e097a1-fa9b-45af-8f7d-b77df9d91fe6",
48
+ "commits": [
49
+ {
50
+ "authoredDate": "2023-10-22T23:13:14Z",
51
+ "authors": [
52
+ {
53
+ "email": "noah@iamnoah.com",
54
+ "id": "MDQ6VXNlcjI5MDA4NA==",
55
+ "login": "magus",
56
+ "name": "magus"
57
+ }
58
+ ],
59
+ "committedDate": "2023-10-28T19:16:33Z",
60
+ "messageBody": "git-multi-diff-id: 3d1d890d-11c9-4569-83c3-e3aff6426e37",
61
+ "messageHeadline": "remove num",
62
+ "oid": "7454ce81940f2a0964ff06c7a98c7fa1892f82bf"
63
+ }
64
+ ],
65
+ "headRefName": "3d1d890d-11c9-4569-83c3-e3aff6426e37",
66
+ "number": 27,
67
+ "state": "OPEN",
68
+ "title": "remove num",
69
+ "url": "https://github.com/magus/git-multi-diff-playground/pull/27"
70
+ },
71
+ "metadata": {
72
+ "id": "3d1d890d-11c9-4569-83c3-e3aff6426e37"
73
+ }
74
+ },
75
+ {
76
+ "sha": "a339f9cc4d8c10b691fef2c2425bf4a67c8c70f0",
77
+ "message": "strawberry",
78
+ "raw_message": "strawberry\n\ngit-multi-diff-id: 53d15f9a-2451-492c-a831-642d41ad3ef4",
79
+ "pr": {
80
+ "baseRefName": "3d1d890d-11c9-4569-83c3-e3aff6426e37",
81
+ "commits": [
82
+ {
83
+ "authoredDate": "2023-10-25T09:29:30Z",
84
+ "authors": [
85
+ {
86
+ "email": "noah@iamnoah.com",
87
+ "id": "MDQ6VXNlcjI5MDA4NA==",
88
+ "login": "magus",
89
+ "name": "magus"
90
+ }
91
+ ],
92
+ "committedDate": "2023-10-28T19:16:37Z",
93
+ "messageBody": "git-multi-diff-id: 53d15f9a-2451-492c-a831-642d41ad3ef4",
94
+ "messageHeadline": "strawberry",
95
+ "oid": "a339f9cc4d8c10b691fef2c2425bf4a67c8c70f0"
96
+ }
97
+ ],
98
+ "headRefName": "53d15f9a-2451-492c-a831-642d41ad3ef4",
99
+ "number": 30,
100
+ "state": "OPEN",
101
+ "title": "strawberry",
102
+ "url": "https://github.com/magus/git-multi-diff-playground/pull/30"
103
+ },
104
+ "metadata": {
105
+ "id": "53d15f9a-2451-492c-a831-642d41ad3ef4"
106
+ }
107
+ },
108
+ {
109
+ "sha": "24fa3301563d40b42f698bff92b8a805412a4a69",
110
+ "message": "orange color",
111
+ "raw_message": "orange color",
112
+ "pr": null,
113
+ "metadata": {
114
+ "id": null
115
+ }
116
+ },
117
+ {
118
+ "sha": "dea1b85bdbcec0b27f1c5b2cc675e47fd9f51005",
119
+ "message": "cantaloupe",
120
+ "raw_message": "cantaloupe\nline2 changed\nline3 'abc'\nline4\nline5 \"hello world\"\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\ngit-multi-diff-id: 398c0ead-77ad-41a4-af6e-280f99998c28",
121
+ "pr": {
122
+ "baseRefName": "53d15f9a-2451-492c-a831-642d41ad3ef4",
123
+ "commits": [
124
+ {
125
+ "authoredDate": "2023-10-22T23:13:35Z",
126
+ "authors": [
127
+ {
128
+ "email": "noah@iamnoah.com",
129
+ "id": "MDQ6VXNlcjI5MDA4NA==",
130
+ "login": "magus",
131
+ "name": "magus"
132
+ }
133
+ ],
134
+ "committedDate": "2023-10-28T19:16:40Z",
135
+ "messageBody": "line2 changed\nline3 'abc'\nline4\nline5 \"hello world\"\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\ngit-multi-diff-id: 398c0ead-77ad-41a4-af6e-280f99998c28",
136
+ "messageHeadline": "cantaloupe",
137
+ "oid": "86d0b3cf5dcbd94963f2839818734c3b0e13d2fc"
138
+ }
139
+ ],
140
+ "headRefName": "398c0ead-77ad-41a4-af6e-280f99998c28",
141
+ "number": 29,
142
+ "state": "OPEN",
143
+ "title": "cantaloupe line2 line3 'abc' line4 line5 \"hello world\" Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
144
+ "url": "https://github.com/magus/git-multi-diff-playground/pull/29"
145
+ },
146
+ "metadata": {
147
+ "id": "398c0ead-77ad-41a4-af6e-280f99998c28"
148
+ }
149
+ },
150
+ {
151
+ "sha": "cc09b96b823d9dde77188e675d3090be7c1d625a",
152
+ "message": "pineapple",
153
+ "raw_message": "pineapple\n\ngit-multi-diff-id: 53d15f9a-2451-492c-a831-642d41ad3ef4",
154
+ "pr": {
155
+ "baseRefName": "3d1d890d-11c9-4569-83c3-e3aff6426e37",
156
+ "commits": [
157
+ {
158
+ "authoredDate": "2023-10-25T09:29:30Z",
159
+ "authors": [
160
+ {
161
+ "email": "noah@iamnoah.com",
162
+ "id": "MDQ6VXNlcjI5MDA4NA==",
163
+ "login": "magus",
164
+ "name": "magus"
165
+ }
166
+ ],
167
+ "committedDate": "2023-10-28T19:16:37Z",
168
+ "messageBody": "git-multi-diff-id: 53d15f9a-2451-492c-a831-642d41ad3ef4",
169
+ "messageHeadline": "strawberry",
170
+ "oid": "a339f9cc4d8c10b691fef2c2425bf4a67c8c70f0"
171
+ }
172
+ ],
173
+ "headRefName": "53d15f9a-2451-492c-a831-642d41ad3ef4",
174
+ "number": 30,
175
+ "state": "OPEN",
176
+ "title": "strawberry",
177
+ "url": "https://github.com/magus/git-multi-diff-playground/pull/30"
178
+ },
179
+ "metadata": {
180
+ "id": "53d15f9a-2451-492c-a831-642d41ad3ef4"
181
+ }
182
+ }
183
+ ],
184
+ "UNASSIGNED": "unassigned"
185
+ }
186
+ }
@@ -0,0 +1,30 @@
1
+ import * as React from "react";
2
+ import { Debug } from "./Debug.js";
3
+ import { DependencyCheck } from "./DependencyCheck.js";
4
+ import { GatherMetadata } from "./GatherMetadata.js";
5
+ import { GithubApiError } from "./GithubApiError.js";
6
+ import { Main } from "./Main.js";
7
+ import { Output } from "./Output.js";
8
+ import { Store } from "./Store.js";
9
+ export function App() {
10
+ const ink = Store.useState((state) => state.ink);
11
+ const argv = Store.useState((state) => state.argv);
12
+ if (!ink || !argv) {
13
+ return null;
14
+ }
15
+ // // debug component
16
+ // return (
17
+ // <React.Fragment>
18
+ // <Debug />
19
+ // <Output />
20
+ // <GithubApiError />
21
+ // </React.Fragment>
22
+ // );
23
+ return (React.createElement(Providers, null,
24
+ React.createElement(Debug, null),
25
+ React.createElement(Output, null),
26
+ !argv.debug ? null : React.createElement(GithubApiError, null),
27
+ React.createElement(DependencyCheck, null,
28
+ React.createElement(GatherMetadata, null,
29
+ React.createElement(Main, null)))));
30
+ }
@@ -0,0 +1,21 @@
1
+ import * as React from "react";
2
+ import { invariant } from "../core/invariant.js";
3
+ import { GithubApiError } from "./GithubApiError.js";
4
+ import { Store } from "./Store.js";
5
+ export function ArgCheck(props) {
6
+ const argv = Store.useState((state) => state.argv);
7
+ invariant(argv, "argv must exist");
8
+ // if (argv.debug) {
9
+ // return (
10
+ // <Await
11
+ // fallback={<Ink.Text>Checking Github API quota...</Ink.Text>}
12
+ // function={github_quota}
13
+ // >
14
+ // {props.children}
15
+ // </Await>
16
+ // );
17
+ // }
18
+ return (React.createElement(React.Fragment, null,
19
+ React.createElement(GithubApiError, null),
20
+ props.children));
21
+ }
@@ -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
+ }
@@ -0,0 +1,19 @@
1
+ import * as React from "react";
2
+ import * as Ink from "ink";
3
+ export function Counter() {
4
+ const { isFocused } = Ink.useFocus();
5
+ const [counter, setCounter] = React.useState(0);
6
+ React.useEffect(() => {
7
+ const timer = setInterval(() => {
8
+ setCounter((prevCounter) => prevCounter + 1);
9
+ }, 100);
10
+ return () => {
11
+ clearInterval(timer);
12
+ };
13
+ }, []);
14
+ return (React.createElement(Ink.Text, { color: "green" },
15
+ counter,
16
+ " tests passed (focus:",
17
+ String(isFocused),
18
+ ")"));
19
+ }
@@ -0,0 +1,91 @@
1
+ import * as React from "react";
2
+ import * as Ink from "ink";
3
+ import { cli } from "../core/cli.js";
4
+ import { colors } from "../core/colors.js";
5
+ import { invariant } from "../core/invariant.js";
6
+ import { match_group } from "../core/match_group.js";
7
+ import { Await } from "./Await.js";
8
+ import { Brackets } from "./Brackets.js";
9
+ import { FormatText } from "./FormatText.js";
10
+ import { Store } from "./Store.js";
11
+ export function GatherMetadata(props) {
12
+ const argv = Store.useState((state) => state.argv);
13
+ invariant(argv, "argv must exist");
14
+ const fallback = (React.createElement(Ink.Text, { color: colors.yellow }, "Gathering local git information..."));
15
+ return (React.createElement(Await, { fallback: fallback, function: gather_metadata }, props.children));
16
+ }
17
+ async function gather_metadata() {
18
+ const actions = Store.getState().actions;
19
+ const argv = Store.getState().argv;
20
+ invariant(argv, "argv must exist");
21
+ try {
22
+ // default to master branch, fallback to main
23
+ let master_branch;
24
+ if (argv.branch) {
25
+ actions.debug(React.createElement(FormatText, { message: "Setting master branch to {branch}", values: {
26
+ branch: React.createElement(Brackets, null, argv.branch),
27
+ } }));
28
+ master_branch = argv.branch;
29
+ }
30
+ else {
31
+ const detect_master = await cli(`git branch --list "${BRANCH.master}" --color=never`);
32
+ if (detect_master.stdout !== "") {
33
+ master_branch = BRANCH.master;
34
+ }
35
+ else {
36
+ actions.debug(React.createElement(FormatText, { message: "Could not find {master} branch, falling back to {main}", values: {
37
+ master: React.createElement(Brackets, null, BRANCH.master),
38
+ main: React.createElement(Brackets, null, BRANCH.main),
39
+ } }));
40
+ master_branch = BRANCH.main;
41
+ }
42
+ }
43
+ const branch_name = (await cli("git rev-parse --abbrev-ref HEAD")).stdout;
44
+ // handle when there are no detected changes
45
+ if (branch_name === master_branch) {
46
+ actions.newline();
47
+ actions.error("Must run within a branch.");
48
+ actions.exit(0);
49
+ return;
50
+ }
51
+ const head = (await cli("git rev-parse HEAD")).stdout;
52
+ const merge_base = (await cli(`git merge-base HEAD ${master_branch}`))
53
+ .stdout;
54
+ // handle when there are no detected changes
55
+ if (head === merge_base) {
56
+ actions.newline();
57
+ actions.output(React.createElement(Ink.Text, { color: colors.gray }, "No changes detected."));
58
+ actions.exit(0);
59
+ return;
60
+ }
61
+ // git@github.com:magus/git-multi-diff-playground.git
62
+ // https://github.com/magus/git-multi-diff-playground.git
63
+ const origin_url = (await cli(`git config --get remote.origin.url`)).stdout;
64
+ const repo_path = match_group(origin_url, RE.repo_path, "repo_path");
65
+ Store.setState((state) => {
66
+ state.repo_path = repo_path;
67
+ state.master_branch = master_branch;
68
+ state.head = head;
69
+ state.merge_base = merge_base;
70
+ state.branch_name = branch_name;
71
+ });
72
+ }
73
+ catch (err) {
74
+ actions.error("Unable to gather git metadata.");
75
+ if (err instanceof Error) {
76
+ if (actions.isDebug()) {
77
+ actions.error(err.message);
78
+ }
79
+ }
80
+ actions.exit(7);
81
+ }
82
+ }
83
+ const RE = {
84
+ // git@github.com:magus/git-multi-diff-playground.git
85
+ // https://github.com/magus/git-multi-diff-playground.git
86
+ repo_path: /(?<repo_path>[^:^/]+\/[^/]+)\.git/,
87
+ };
88
+ const BRANCH = {
89
+ master: "master",
90
+ main: "main",
91
+ };
@@ -41,6 +41,13 @@ async function gather_metadata() {
41
41
  }
42
42
  }
43
43
  const branch_name = (await cli("git rev-parse --abbrev-ref HEAD")).stdout;
44
+ // handle detahed head state
45
+ if (branch_name === "HEAD") {
46
+ actions.newline();
47
+ actions.error("Must run within a branch.");
48
+ actions.exit(0);
49
+ return;
50
+ }
44
51
  // handle when there are no detected changes
45
52
  if (branch_name === master_branch) {
46
53
  actions.newline();
@@ -0,0 +1,14 @@
1
+ import * as React from "react";
2
+ import { cli } from "../core/cli.js";
3
+ import { Await } from "./Await.js";
4
+ import { Store } from "./Store.js";
5
+ export function InitMetadata() {
6
+ return (React.createElement(Await, { function: async () => {
7
+ const head = (await cli("git rev-parse HEAD")).stdout;
8
+ const merge_base = (await cli("git merge-base HEAD master")).stdout;
9
+ Store.setState((state) => {
10
+ state.head = head;
11
+ state.merge_base = merge_base;
12
+ });
13
+ } }));
14
+ }
@@ -0,0 +1,15 @@
1
+ import * as React from "react";
2
+ import * as Ink from "ink";
3
+ export function Input(props) {
4
+ const [value, set_value] = React.useState(props.value || "");
5
+ Ink.useInput((input, key) => {
6
+ if (key.backspace) {
7
+ set_value((value) => value.slice(0, -1));
8
+ }
9
+ else {
10
+ set_value((value) => `${value}${input}`);
11
+ }
12
+ });
13
+ return (React.createElement(Ink.Box, { borderStyle: "single" },
14
+ React.createElement(Ink.Text, null, value)));
15
+ }
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+ export function KeepAlive() {
3
+ // Exit the app after 5 seconds
4
+ React.useEffect(() => {
5
+ const timer = setInterval(() => { }, 5 * 1000);
6
+ return function cleanup() {
7
+ clearInterval(timer);
8
+ };
9
+ }, []);
10
+ return null;
11
+ }
@@ -53,9 +53,13 @@ async function run() {
53
53
  commit_message: React.createElement(Brackets, null, commit.message),
54
54
  } }));
55
55
  }
56
+ // ensure clean base to avoid conflicts when applying patch
57
+ await cli(`git clean -fd`);
58
+ // create, apply and cleanup patch
56
59
  await cli(`git format-patch -1 ${commit.sha} --stdout > ${PATCH_FILE}`);
57
60
  await cli(`git apply ${PATCH_FILE}`);
58
61
  await cli(`rm ${PATCH_FILE}`);
62
+ // add all changes to stage
59
63
  await cli(`git add --all`);
60
64
  let new_message;
61
65
  if (commit.branch_id) {
@@ -136,4 +140,4 @@ async function run() {
136
140
  actions.exit(6);
137
141
  }
138
142
  }
139
- const PATCH_FILE = "mypatch.patch";
143
+ const PATCH_FILE = "git-stack-cli-patch.patch";
@@ -0,0 +1,200 @@
1
+ import * as React from "react";
2
+ import * as Ink from "ink";
3
+ import { v4 as uuid_v4 } from "uuid";
4
+ import * as CommitMetadata from "../core/CommitMetadata.js";
5
+ import * as Metadata from "../core/Metadata.js";
6
+ import { cli } from "../core/cli.js";
7
+ import * as github from "../core/github.js";
8
+ import { invariant } from "../core/invariant.js";
9
+ import { match_group } from "../core/match_group.js";
10
+ import { Await } from "./Await.js";
11
+ import { Exit } from "./Exit.js";
12
+ import { Store } from "./Store.js";
13
+ export function GatherMetadata(props) {
14
+ const argv = Store.useState((state) => state.argv);
15
+ invariant(argv, "argv must exist");
16
+ return (React.createElement(Await, { fallback: null, function: () => gather_metadata({ argv }) }, props.children));
17
+ }
18
+ async function gather_metadata(args) {
19
+ const actions = Store.getState().actions;
20
+ const head = (await cli("git rev-parse HEAD")).stdout;
21
+ const merge_base = (await cli("git merge-base HEAD master")).stdout;
22
+ // handle when there are no detected changes
23
+ if (head === merge_base) {
24
+ actions.newline();
25
+ actions.output(React.createElement(Ink.Text, { color: "gray" }, "No changes detected."));
26
+ actions.output(React.createElement(Exit, { clear: true, code: 0 }));
27
+ return;
28
+ }
29
+ const branch_name = (await cli("git rev-parse --abbrev-ref HEAD")).stdout;
30
+ // git@github.com:magus/git-multi-diff-playground.git
31
+ // https://github.com/magus/git-multi-diff-playground.git
32
+ const origin_url = (await cli(`git config --get remote.origin.url`)).stdout;
33
+ const repo_path = match_group(origin_url, RE.repo_path, "repo_path");
34
+ const commit_metadata_list = await CommitMetadata.all();
35
+ Store.setState((state) => {
36
+ state.head = head;
37
+ state.merge_base = merge_base;
38
+ state.branch_name = branch_name;
39
+ state.repo_path = repo_path;
40
+ state.commit_metadata_list = commit_metadata_list;
41
+ });
42
+ // print_table(repo_path, commit_metadata_list);
43
+ const needs_update = commit_metadata_list.some((meta) => !meta.pr_exists || meta.pr_dirty);
44
+ if (args.argv.check) {
45
+ actions.output(React.createElement(Exit, { clear: true, code: 0 }));
46
+ return;
47
+ }
48
+ if (!args.argv.force && !needs_update) {
49
+ actions.newline();
50
+ actions.output(React.createElement(Ink.Text, null, "\u2705 Everything up to date."));
51
+ actions.output(React.createElement(Ink.Text, { color: "gray" },
52
+ React.createElement(Ink.Text, null, "Run with"),
53
+ React.createElement(Ink.Text, { bold: true, color: "yellow" }, ` --force `),
54
+ React.createElement(Ink.Text, null, "to force update all pull requests.")));
55
+ actions.output(React.createElement(Exit, { clear: true, code: 0 }));
56
+ }
57
+ Store.setState((state) => {
58
+ state.step = "select-commit-ranges";
59
+ });
60
+ }
61
+ async function manual_rebase(args) {
62
+ const temp_branch_name = `${args.branch_name}_${uuid_v4()}`;
63
+ try {
64
+ // create temporary branch based on merge base
65
+ await cli(`git checkout -b ${temp_branch_name} ${args.merge_base}`);
66
+ const picked_commit_metadata_list = [];
67
+ // cherry-pick and amend commits one by one
68
+ for (let i = 0; i < args.commit_metadata_list.length; i++) {
69
+ const sha = args.commit_metadata_list[i].sha;
70
+ let base;
71
+ if (i === 0) {
72
+ base = "master";
73
+ }
74
+ else {
75
+ base = picked_commit_metadata_list[i - 1].metadata.id;
76
+ invariant(base, `metadata must be set on previous commit [${i}]`);
77
+ }
78
+ await cli(`git cherry-pick ${sha}`);
79
+ const commit = await CommitMetadata.commit(sha, base);
80
+ if (!commit.metadata.id) {
81
+ commit.metadata.id = uuid_v4();
82
+ await Metadata.write(commit);
83
+ }
84
+ picked_commit_metadata_list.push(commit);
85
+ // always push to origin since github requires commit shas to line up perfectly
86
+ console.debug();
87
+ console.debug(`Syncing [${commit.metadata.id}] ...`);
88
+ await cli(`git push -f origin HEAD:${commit.metadata.id}`);
89
+ if (commit.pr_exists) {
90
+ // ensure base matches pr in github
91
+ await github.pr_base(commit.metadata.id, base);
92
+ }
93
+ else {
94
+ try {
95
+ // delete metadata id branch if leftover
96
+ await cli(`git branch -D ${commit.metadata.id}`, {
97
+ ignoreExitCode: true,
98
+ });
99
+ // move to temporary branch for creating pr
100
+ await cli(`git checkout -b ${commit.metadata.id}`);
101
+ // create pr in github
102
+ await github.pr_create(commit.metadata.id, base);
103
+ }
104
+ catch (err) {
105
+ console.error("Moving back to temp branch...");
106
+ console.error(err);
107
+ }
108
+ finally {
109
+ // move back to temp branch
110
+ await cli(`git checkout ${temp_branch_name}`);
111
+ // delete metadata id branch if leftover
112
+ await cli(`git branch -D ${commit.metadata.id}`, {
113
+ ignoreExitCode: true,
114
+ });
115
+ }
116
+ }
117
+ }
118
+ // after all commits have been cherry-picked and amended
119
+ // move the branch pointer to the temporary branch (with the metadata)
120
+ await cli(`git branch -f ${args.branch_name} ${temp_branch_name}`);
121
+ }
122
+ catch (err) {
123
+ console.error("Restoring original branch...");
124
+ console.error(err);
125
+ }
126
+ finally {
127
+ // always put self back in original branch
128
+ await cli(`git checkout ${args.branch_name}`);
129
+ // ...and cleanup temporary branch
130
+ await cli(`git branch -D ${temp_branch_name}`, { ignoreExitCode: true });
131
+ }
132
+ // print_table(repo_path, await CommitMetadata.all());
133
+ }
134
+ const RE = {
135
+ // git@github.com:magus/git-multi-diff-playground.git
136
+ // https://github.com/magus/git-multi-diff-playground.git
137
+ repo_path: /(?<repo_path>[^:^/]+\/[^/]+)\.git/,
138
+ };
139
+ // function print_table(
140
+ // repo_path: string,
141
+ // commit_metadata_list: Array<Awaited<ReturnType<typeof CommitMetadata.commit>>>
142
+ // ) {
143
+ // console.debug();
144
+ // for (const args of commit_metadata_list) {
145
+ // print_table_row(repo_path, args);
146
+ // }
147
+ // }
148
+ // function print_table_row(
149
+ // repo_path: string,
150
+ // args: Awaited<ReturnType<typeof CommitMetadata.commit>>
151
+ // ) {
152
+ // let icon;
153
+ // let status;
154
+ // if (!args.pr_exists) {
155
+ // icon = "🌱";
156
+ // status = "NEW";
157
+ // } else if (args.pr_dirty) {
158
+ // icon = "⚠️";
159
+ // status = "OUTDATED";
160
+ // } else {
161
+ // icon = "✅";
162
+ // status = "SYNCED";
163
+ // }
164
+ // // print clean metadata about this commit / branch
165
+ // const parts = [
166
+ // icon,
167
+ // " ",
168
+ // col(status, 10, "left"),
169
+ // col(args.message, 80, "left"),
170
+ // ];
171
+ // if (args.pr?.number) {
172
+ // parts.push(` https://github.com/${repo_path}/pull/${args.pr.number}`);
173
+ // }
174
+ // console.debug(...parts);
175
+ // }
176
+ // const RE = {
177
+ // all_newline: /\n/g,
178
+ // // git@github.com:magus/git-multi-diff-playground.git
179
+ // // https://github.com/magus/git-multi-diff-playground.git
180
+ // repo_path: /(?<repo_path>[^:^/]+\/[^/]+)\.git/,
181
+ // };
182
+ // function trunc(value: string, length: number) {
183
+ // return value.substring(0, length);
184
+ // }
185
+ // function pad(value: string, length: number, align: "left" | "right") {
186
+ // const space_count = Math.max(0, length - value.length);
187
+ // const padding = " ".repeat(space_count);
188
+ // if (align === "left") {
189
+ // return `${value}${padding}`;
190
+ // } else {
191
+ // return `${padding}${value}`;
192
+ // }
193
+ // }
194
+ // function col(value: string, length: number, align: "left" | "right") {
195
+ // let column = value;
196
+ // column = column.replace(RE.all_newline, " ");
197
+ // column = trunc(column, length);
198
+ // column = pad(column, length, align);
199
+ // return column;
200
+ // }