git-stack-cli 1.12.0 → 1.13.1
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 +11 -1
- package/dist/cjs/index.cjs +543 -460
- package/package.json +1 -1
- package/src/app/AutoUpdate.tsx +5 -3
- package/src/app/CherryPickCheck.tsx +4 -4
- package/src/app/Debug.tsx +12 -9
- package/src/app/DependencyCheck.tsx +0 -6
- package/src/app/Main.tsx +4 -0
- package/src/app/ManualRebase.tsx +85 -357
- package/src/app/PreManualRebase.tsx +6 -5
- package/src/app/RebaseCheck.tsx +3 -3
- package/src/app/Store.tsx +8 -0
- package/src/app/SyncGithub.tsx +322 -0
- package/src/command.ts +0 -16
- package/src/commands/Rebase.tsx +31 -21
- package/src/core/GitReviseTodo.ts +3 -3
- package/src/core/github.tsx +18 -9
- package/src/core/read_json.ts +3 -3
- package/src/core/safe_exists.ts +10 -0
- package/src/core/safe_rm.ts +10 -0
- package/src/index.tsx +4 -1
package/package.json
CHANGED
package/src/app/AutoUpdate.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
-
import fs from "node:fs";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
|
|
6
6
|
import * as Ink from "ink-cjs";
|
|
@@ -90,7 +90,8 @@ export function AutoUpdate(props: Props) {
|
|
|
90
90
|
throw new Error("Unable to retrieve latest version from npm");
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
const
|
|
93
|
+
const script_path = await fs.realpath(process.argv[1]);
|
|
94
|
+
const script_dir = path.dirname(script_path);
|
|
94
95
|
|
|
95
96
|
// dist/ts/index.js
|
|
96
97
|
const package_json_path = path.join(
|
|
@@ -100,7 +101,8 @@ export function AutoUpdate(props: Props) {
|
|
|
100
101
|
"package.json"
|
|
101
102
|
);
|
|
102
103
|
|
|
103
|
-
|
|
104
|
+
type PackageJson = { version: string };
|
|
105
|
+
const package_json = await read_json<PackageJson>(package_json_path);
|
|
104
106
|
|
|
105
107
|
if (!package_json) {
|
|
106
108
|
// unable to find read package.json, skip auto update
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
-
import fs from "node:fs";
|
|
4
3
|
import path from "node:path";
|
|
5
4
|
|
|
6
5
|
import * as Ink from "ink-cjs";
|
|
@@ -11,6 +10,7 @@ import { Store } from "~/app/Store";
|
|
|
11
10
|
import { YesNoPrompt } from "~/app/YesNoPrompt";
|
|
12
11
|
import { cli } from "~/core/cli";
|
|
13
12
|
import { colors } from "~/core/colors";
|
|
13
|
+
import { safe_exists } from "~/core/safe_exists";
|
|
14
14
|
|
|
15
15
|
type Props = {
|
|
16
16
|
children: React.ReactNode;
|
|
@@ -73,11 +73,11 @@ export function CherryPickCheck(props: Props) {
|
|
|
73
73
|
try {
|
|
74
74
|
const git_dir = (await cli(`git rev-parse --absolute-git-dir`)).stdout;
|
|
75
75
|
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
);
|
|
76
|
+
const cherry_pick_file = path.join(git_dir, "CHERRY_PICK_HEAD");
|
|
77
|
+
const is_cherry_pick = await safe_exists(cherry_pick_file);
|
|
79
78
|
|
|
80
79
|
const status = is_cherry_pick ? "prompt" : "done";
|
|
80
|
+
|
|
81
81
|
patch({ status });
|
|
82
82
|
} catch (err) {
|
|
83
83
|
actions.error("Must be run from within a git repository.");
|
package/src/app/Debug.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
-
import fs from "node:fs";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
|
|
6
6
|
import * as Ink from "ink-cjs";
|
|
@@ -8,6 +8,7 @@ import * as Ink from "ink-cjs";
|
|
|
8
8
|
import { Store } from "~/app/Store";
|
|
9
9
|
import { colors } from "~/core/colors";
|
|
10
10
|
import * as json from "~/core/json";
|
|
11
|
+
import { safe_rm } from "~/core/safe_rm";
|
|
11
12
|
|
|
12
13
|
export function Debug() {
|
|
13
14
|
const actions = Store.useActions();
|
|
@@ -27,20 +28,22 @@ export function Debug() {
|
|
|
27
28
|
);
|
|
28
29
|
|
|
29
30
|
React.useEffect(
|
|
30
|
-
function
|
|
31
|
+
function sync_state_json() {
|
|
31
32
|
if (!argv?.["write-state-json"]) {
|
|
32
33
|
return;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
sync().catch(actions.error);
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
async function sync() {
|
|
39
|
+
const output_file = path.join(state.cwd, "git-stack-state.json");
|
|
40
|
+
|
|
41
|
+
await safe_rm(output_file);
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
const serialized = json.serialize(state);
|
|
44
|
+
const content = JSON.stringify(serialized, null, 2);
|
|
45
|
+
await fs.writeFile(output_file, content);
|
|
46
|
+
}
|
|
44
47
|
},
|
|
45
48
|
[argv, state]
|
|
46
49
|
);
|
|
@@ -163,12 +163,6 @@ function CheckGithubCliAuth(props: Props) {
|
|
|
163
163
|
|
|
164
164
|
function CheckGitRevise(props: Props) {
|
|
165
165
|
const actions = Store.useActions();
|
|
166
|
-
const argv = Store.useState((state) => state.argv);
|
|
167
|
-
|
|
168
|
-
// skip git revise check when `rebase` is not git-revise
|
|
169
|
-
if (argv?.["rebase"] !== "git-revise") {
|
|
170
|
-
return props.children;
|
|
171
|
-
}
|
|
172
166
|
|
|
173
167
|
return (
|
|
174
168
|
<Await
|
package/src/app/Main.tsx
CHANGED
|
@@ -10,6 +10,7 @@ import { PreSelectCommitRanges } from "~/app/PreSelectCommitRanges";
|
|
|
10
10
|
import { SelectCommitRanges } from "~/app/SelectCommitRanges";
|
|
11
11
|
import { Status } from "~/app/Status";
|
|
12
12
|
import { Store } from "~/app/Store";
|
|
13
|
+
import { SyncGithub } from "~/app/SyncGithub";
|
|
13
14
|
import { assertNever } from "~/core/assertNever";
|
|
14
15
|
|
|
15
16
|
export function Main() {
|
|
@@ -43,6 +44,9 @@ export function Main() {
|
|
|
43
44
|
case "manual-rebase":
|
|
44
45
|
return <ManualRebase />;
|
|
45
46
|
|
|
47
|
+
case "sync-github":
|
|
48
|
+
return <SyncGithub />;
|
|
49
|
+
|
|
46
50
|
case "post-rebase-status":
|
|
47
51
|
return <PostRebaseStatus />;
|
|
48
52
|
|
package/src/app/ManualRebase.tsx
CHANGED
|
@@ -6,28 +6,44 @@ import * as Ink from "ink-cjs";
|
|
|
6
6
|
|
|
7
7
|
import { Await } from "~/app/Await";
|
|
8
8
|
import { Brackets } from "~/app/Brackets";
|
|
9
|
-
import { FormatText } from "~/app/FormatText";
|
|
10
9
|
import { Store } from "~/app/Store";
|
|
11
10
|
import * as CommitMetadata from "~/core/CommitMetadata";
|
|
12
11
|
import { GitReviseTodo } from "~/core/GitReviseTodo";
|
|
13
|
-
import * as Metadata from "~/core/Metadata";
|
|
14
|
-
import * as StackSummaryTable from "~/core/StackSummaryTable";
|
|
15
12
|
import { cli } from "~/core/cli";
|
|
16
13
|
import { colors } from "~/core/colors";
|
|
17
|
-
import * as github from "~/core/github";
|
|
18
14
|
import { invariant } from "~/core/invariant";
|
|
19
15
|
import { short_id } from "~/core/short_id";
|
|
20
16
|
|
|
21
17
|
export function ManualRebase() {
|
|
18
|
+
const abort_handler = React.useRef(() => {});
|
|
19
|
+
|
|
20
|
+
React.useEffect(function listen_sigint() {
|
|
21
|
+
process.once("SIGINT", sigint_handler);
|
|
22
|
+
|
|
23
|
+
return function cleanup() {
|
|
24
|
+
process.removeListener("SIGINT", sigint_handler);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
async function sigint_handler() {
|
|
28
|
+
abort_handler.current();
|
|
29
|
+
}
|
|
30
|
+
}, []);
|
|
31
|
+
|
|
22
32
|
return (
|
|
23
33
|
<Await
|
|
24
34
|
fallback={<Ink.Text color={colors.yellow}>Rebasing commits…</Ink.Text>}
|
|
25
|
-
function={
|
|
35
|
+
function={async function () {
|
|
36
|
+
await run({ abort_handler });
|
|
37
|
+
}}
|
|
26
38
|
/>
|
|
27
39
|
);
|
|
28
40
|
}
|
|
29
41
|
|
|
30
|
-
|
|
42
|
+
type Args = {
|
|
43
|
+
abort_handler: React.MutableRefObject<() => void>;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
async function run(args: Args) {
|
|
31
47
|
const state = Store.getState();
|
|
32
48
|
const actions = state.actions;
|
|
33
49
|
const argv = state.argv;
|
|
@@ -42,108 +58,70 @@ async function run() {
|
|
|
42
58
|
invariant(repo_root, "repo_root must exist");
|
|
43
59
|
|
|
44
60
|
// always listen for SIGINT event and restore git state
|
|
45
|
-
|
|
61
|
+
args.abort_handler.current = function sigint_handler() {
|
|
62
|
+
actions.output(<Ink.Text color={colors.red}>🚨 Abort</Ink.Text>);
|
|
63
|
+
handle_exit(15);
|
|
64
|
+
};
|
|
46
65
|
|
|
47
|
-
|
|
48
|
-
const merge_base = (await cli(`git merge-base HEAD ${master_branch}`)).stdout;
|
|
66
|
+
const temp_branch_name = `${branch_name}_${short_id()}`;
|
|
49
67
|
|
|
50
|
-
|
|
51
|
-
|
|
68
|
+
try {
|
|
69
|
+
// get latest merge_base relative to local master
|
|
70
|
+
const merge_base = (await cli(`git merge-base HEAD ${master_branch}`))
|
|
71
|
+
.stdout;
|
|
52
72
|
|
|
53
|
-
|
|
54
|
-
|
|
73
|
+
// immediately paint all commit to preserve selected commit ranges
|
|
74
|
+
let commit_range = await CommitMetadata.range(commit_map);
|
|
55
75
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
commit.branch_id = group_from_map.id;
|
|
59
|
-
commit.title = group_from_map.title;
|
|
60
|
-
}
|
|
76
|
+
// reverse group list to ensure we create git revise in correct order
|
|
77
|
+
commit_range.group_list.reverse();
|
|
61
78
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
79
|
+
for (const commit of commit_range.commit_list) {
|
|
80
|
+
const group_from_map = commit_map[commit.sha];
|
|
81
|
+
commit.branch_id = group_from_map.id;
|
|
82
|
+
commit.title = group_from_map.title;
|
|
83
|
+
}
|
|
67
84
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
85
|
+
await GitReviseTodo.execute({
|
|
86
|
+
rebase_group_index: 0,
|
|
87
|
+
rebase_merge_base: merge_base,
|
|
88
|
+
commit_range,
|
|
89
|
+
});
|
|
72
90
|
|
|
73
|
-
|
|
91
|
+
commit_range = await CommitMetadata.range(commit_map);
|
|
74
92
|
|
|
75
|
-
|
|
93
|
+
// reverse commit list so that we can cherry-pick in order
|
|
94
|
+
commit_range.group_list.reverse();
|
|
76
95
|
|
|
77
|
-
|
|
78
|
-
|
|
96
|
+
let rebase_merge_base = merge_base;
|
|
97
|
+
let rebase_group_index = 0;
|
|
79
98
|
|
|
80
|
-
|
|
81
|
-
|
|
99
|
+
for (let i = 0; i < commit_range.group_list.length; i++) {
|
|
100
|
+
const group = commit_range.group_list[i];
|
|
82
101
|
|
|
83
|
-
|
|
84
|
-
|
|
102
|
+
if (!group.dirty) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
85
105
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
106
|
+
if (i > 0) {
|
|
107
|
+
const prev_group = commit_range.group_list[i - 1];
|
|
108
|
+
const prev_commit = prev_group.commits[prev_group.commits.length - 1];
|
|
109
|
+
rebase_merge_base = prev_commit.sha;
|
|
110
|
+
rebase_group_index = i;
|
|
111
|
+
}
|
|
89
112
|
|
|
90
|
-
|
|
91
|
-
const prev_group = commit_range.group_list[i - 1];
|
|
92
|
-
const prev_commit = prev_group.commits[prev_group.commits.length - 1];
|
|
93
|
-
rebase_merge_base = prev_commit.sha;
|
|
94
|
-
rebase_group_index = i;
|
|
113
|
+
break;
|
|
95
114
|
}
|
|
96
115
|
|
|
97
|
-
|
|
98
|
-
|
|
116
|
+
actions.debug(`rebase_merge_base = ${rebase_merge_base}`);
|
|
117
|
+
actions.debug(`rebase_group_index = ${rebase_group_index}`);
|
|
99
118
|
|
|
100
|
-
|
|
101
|
-
actions.debug(`rebase_group_index = ${rebase_group_index}`);
|
|
119
|
+
// actions.debug(`commit_range=${JSON.stringify(commit_range, null, 2)}`);
|
|
102
120
|
|
|
103
|
-
// actions.debug(`commit_range=${JSON.stringify(commit_range, null, 2)}`);
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
121
|
// must perform rebase from repo root for applying git patch
|
|
107
122
|
process.chdir(repo_root);
|
|
108
123
|
await cli(`pwd`);
|
|
109
124
|
|
|
110
|
-
if (argv["rebase"] === "git-revise") {
|
|
111
|
-
await rebase_git_revise();
|
|
112
|
-
} else {
|
|
113
|
-
await rebase_cherry_pick();
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// after all commits have been cherry-picked and amended
|
|
117
|
-
// move the branch pointer to the newly created temporary branch
|
|
118
|
-
// now we are in locally in sync with github and on the original branch
|
|
119
|
-
await cli(`git branch -f ${branch_name} ${temp_branch_name}`);
|
|
120
|
-
|
|
121
|
-
restore_git();
|
|
122
|
-
|
|
123
|
-
actions.set((state) => {
|
|
124
|
-
state.step = "post-rebase-status";
|
|
125
|
-
});
|
|
126
|
-
} catch (err) {
|
|
127
|
-
actions.error("Unable to rebase.");
|
|
128
|
-
|
|
129
|
-
if (err instanceof Error) {
|
|
130
|
-
if (actions.isDebug()) {
|
|
131
|
-
actions.error(err.message);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
handle_exit();
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async function rebase_git_revise() {
|
|
139
|
-
actions.debug(`rebase_git_revise`);
|
|
140
|
-
|
|
141
|
-
actions.output(
|
|
142
|
-
<Ink.Text color={colors.yellow} wrap="truncate-end">
|
|
143
|
-
Rebasing…
|
|
144
|
-
</Ink.Text>
|
|
145
|
-
);
|
|
146
|
-
|
|
147
125
|
// create temporary branch
|
|
148
126
|
await cli(`git checkout -b ${temp_branch_name}`);
|
|
149
127
|
|
|
@@ -153,268 +131,33 @@ async function run() {
|
|
|
153
131
|
commit_range,
|
|
154
132
|
});
|
|
155
133
|
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// in order to sync we walk from rebase_group_index to HEAD
|
|
162
|
-
// checking out each group and syncing to github
|
|
163
|
-
|
|
164
|
-
// start from HEAD and work backward to rebase_group_index
|
|
165
|
-
const push_group_list = [];
|
|
166
|
-
let lookback_index = 0;
|
|
167
|
-
for (let i = 0; i < commit_range.group_list.length; i++) {
|
|
168
|
-
const index = commit_range.group_list.length - 1 - i;
|
|
169
|
-
|
|
170
|
-
// do not go past rebase_group_index
|
|
171
|
-
if (index < rebase_group_index) {
|
|
172
|
-
break;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const group = commit_range.group_list[index];
|
|
176
|
-
// console.debug({ i, index, group });
|
|
177
|
-
|
|
178
|
-
if (i > 0) {
|
|
179
|
-
const prev_group = commit_range.group_list[index + 1];
|
|
180
|
-
lookback_index += prev_group.commits.length;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// console.debug(`git show head~${lookback_index}`);
|
|
184
|
-
|
|
185
|
-
// push group and lookback_index onto front of push_group_list
|
|
186
|
-
push_group_list.unshift({ group, lookback_index });
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const pr_url_list = commit_range.group_list.map(get_group_url);
|
|
190
|
-
|
|
191
|
-
// use push_group_list to sync each group HEAD to github
|
|
192
|
-
for (const push_group of push_group_list) {
|
|
193
|
-
const { group } = push_group;
|
|
194
|
-
|
|
195
|
-
// move to temporary branch for resetting to lookback_index to create PR
|
|
196
|
-
await cli(`git checkout -b ${group.id}`);
|
|
197
|
-
|
|
198
|
-
// prepare branch for sync, reset to commit at lookback index
|
|
199
|
-
await cli(`git reset --hard HEAD~${push_group.lookback_index}`);
|
|
200
|
-
|
|
201
|
-
await sync_group_github({ group, pr_url_list, skip_checkout: true });
|
|
202
|
-
|
|
203
|
-
// done, remove temp push branch and move back to temp branch
|
|
204
|
-
await cli(`git checkout ${temp_branch_name}`);
|
|
205
|
-
await cli(`git branch -D ${group.id}`);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// finally, ensure all prs have the updated stack table from updated pr_url_list
|
|
209
|
-
await update_pr_tables(pr_url_list);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
async function rebase_cherry_pick() {
|
|
213
|
-
actions.debug("rebase_cherry_pick");
|
|
214
|
-
|
|
215
|
-
// create temporary branch based on merge base
|
|
216
|
-
await cli(`git checkout -b ${temp_branch_name} ${rebase_merge_base}`);
|
|
217
|
-
|
|
218
|
-
const pr_url_list = commit_range.group_list.map(get_group_url);
|
|
219
|
-
|
|
220
|
-
for (let i = rebase_group_index; i < commit_range.group_list.length; i++) {
|
|
221
|
-
const group = commit_range.group_list[i];
|
|
222
|
-
|
|
223
|
-
invariant(group.base, "group.base must exist");
|
|
224
|
-
|
|
225
|
-
actions.output(
|
|
226
|
-
<FormatText
|
|
227
|
-
wrapper={<Ink.Text color={colors.yellow} wrap="truncate-end" />}
|
|
228
|
-
message="Rebasing {group}…"
|
|
229
|
-
values={{
|
|
230
|
-
group: (
|
|
231
|
-
<Brackets>{group.pr?.title || group.title || group.id}</Brackets>
|
|
232
|
-
),
|
|
233
|
-
}}
|
|
234
|
-
/>
|
|
235
|
-
);
|
|
236
|
-
|
|
237
|
-
// cherry-pick and amend commits one by one
|
|
238
|
-
for (const commit of group.commits) {
|
|
239
|
-
// ensure clean base to avoid conflicts when applying patch
|
|
240
|
-
await cli(`git clean -fd`);
|
|
241
|
-
|
|
242
|
-
// create, apply and cleanup patch
|
|
243
|
-
await cli(`git format-patch -1 ${commit.sha} --stdout > ${PATCH_FILE}`);
|
|
244
|
-
await cli(`git apply ${PATCH_FILE}`);
|
|
245
|
-
await cli(`rm ${PATCH_FILE}`);
|
|
246
|
-
|
|
247
|
-
// add all changes to stage
|
|
248
|
-
await cli(`git add --all`);
|
|
249
|
-
|
|
250
|
-
const metadata = { id: group.id, title: group.title };
|
|
251
|
-
const new_message = Metadata.write(commit.full_message, metadata);
|
|
252
|
-
const git_commit_comand = [`git commit -m "${new_message}"`];
|
|
253
|
-
|
|
254
|
-
if (argv.verify === false) {
|
|
255
|
-
git_commit_comand.push("--no-verify");
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
await cli(git_commit_comand);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
await sync_group_github({ group, pr_url_list, skip_checkout: false });
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// finally, ensure all prs have the updated stack table from updated pr_url_list
|
|
265
|
-
await update_pr_tables(pr_url_list);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
async function sync_group_github(args: {
|
|
269
|
-
group: CommitMetadataGroup;
|
|
270
|
-
pr_url_list: Array<string>;
|
|
271
|
-
skip_checkout: boolean;
|
|
272
|
-
}) {
|
|
273
|
-
if (!argv.sync) {
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
const { group, pr_url_list } = args;
|
|
278
|
-
|
|
279
|
-
invariant(group.base, "group.base must exist");
|
|
280
|
-
|
|
281
|
-
actions.output(
|
|
282
|
-
<FormatText
|
|
283
|
-
wrapper={<Ink.Text color={colors.yellow} wrap="truncate-end" />}
|
|
284
|
-
message="Syncing {group}…"
|
|
285
|
-
values={{
|
|
286
|
-
group: (
|
|
287
|
-
<Brackets>{group.pr?.title || group.title || group.id}</Brackets>
|
|
288
|
-
),
|
|
289
|
-
}}
|
|
290
|
-
/>
|
|
291
|
-
);
|
|
292
|
-
|
|
293
|
-
// we may temporarily mark PR as a draft before editing it
|
|
294
|
-
// if it is not already a draft PR, to avoid notification spam
|
|
295
|
-
let is_temp_draft = false;
|
|
296
|
-
|
|
297
|
-
// before pushing reset base to master temporarily
|
|
298
|
-
// avoid accidentally pointing to orphaned parent commit
|
|
299
|
-
// should hopefully fix issues where a PR includes a bunch of commits after pushing
|
|
300
|
-
if (group.pr) {
|
|
301
|
-
if (!group.pr.isDraft) {
|
|
302
|
-
is_temp_draft = true;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
if (is_temp_draft) {
|
|
306
|
-
await github.pr_draft({
|
|
307
|
-
branch: group.id,
|
|
308
|
-
draft: true,
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
await github.pr_edit({
|
|
313
|
-
branch: group.id,
|
|
314
|
-
base: master_branch,
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// push to origin since github requires commit shas to line up perfectly
|
|
319
|
-
const git_push_command = [`git push -f origin HEAD:${group.id}`];
|
|
320
|
-
|
|
321
|
-
if (argv.verify === false) {
|
|
322
|
-
git_push_command.push("--no-verify");
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
await cli(git_push_command);
|
|
134
|
+
// after all commits have been modified move the pointer
|
|
135
|
+
// of original branch to the newly created temporary branch
|
|
136
|
+
await cli(`git branch -f ${branch_name} ${temp_branch_name}`);
|
|
326
137
|
|
|
327
|
-
|
|
138
|
+
restore_git();
|
|
328
139
|
|
|
329
|
-
if (
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
base: group.base,
|
|
334
|
-
body: StackSummaryTable.write({
|
|
335
|
-
body: group.pr.body,
|
|
336
|
-
pr_url_list,
|
|
337
|
-
selected_url,
|
|
338
|
-
}),
|
|
140
|
+
if (argv.sync) {
|
|
141
|
+
actions.set((state) => {
|
|
142
|
+
state.step = "sync-github";
|
|
143
|
+
state.sync_github = { commit_range, rebase_group_index };
|
|
339
144
|
});
|
|
340
|
-
|
|
341
|
-
if (is_temp_draft) {
|
|
342
|
-
// mark pr as ready for review again
|
|
343
|
-
await github.pr_draft({
|
|
344
|
-
branch: group.id,
|
|
345
|
-
draft: false,
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
145
|
} else {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
await cli(`git branch -D ${group.id}`, { ignoreExitCode: true });
|
|
352
|
-
|
|
353
|
-
// move to temporary branch for creating pr
|
|
354
|
-
await cli(`git checkout -b ${group.id}`);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// create pr in github
|
|
358
|
-
const pr_url = await github.pr_create({
|
|
359
|
-
branch: group.id,
|
|
360
|
-
base: group.base,
|
|
361
|
-
title: group.title,
|
|
362
|
-
body: DEFAULT_PR_BODY,
|
|
363
|
-
draft: argv.draft,
|
|
146
|
+
actions.set((state) => {
|
|
147
|
+
state.step = "post-rebase-status";
|
|
364
148
|
});
|
|
365
|
-
|
|
366
|
-
if (!pr_url) {
|
|
367
|
-
throw new Error("unable to create pr");
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// update pr_url_list with created pr_url
|
|
371
|
-
for (let i = 0; i < pr_url_list.length; i++) {
|
|
372
|
-
const url = pr_url_list[i];
|
|
373
|
-
if (url === selected_url) {
|
|
374
|
-
pr_url_list[i] = pr_url;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// move back to temp branch
|
|
379
|
-
if (!args.skip_checkout) {
|
|
380
|
-
await cli(`git checkout ${temp_branch_name}`);
|
|
381
|
-
}
|
|
382
149
|
}
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
if (!argv.sync) {
|
|
387
|
-
return;
|
|
150
|
+
} catch (err) {
|
|
151
|
+
if (err instanceof Error) {
|
|
152
|
+
actions.error(err.message);
|
|
388
153
|
}
|
|
389
154
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
// use the updated pr_url_list to get the actual selected_url
|
|
394
|
-
const selected_url = pr_url_list[i];
|
|
395
|
-
|
|
396
|
-
invariant(group.base, "group.base must exist");
|
|
397
|
-
|
|
398
|
-
const body = group.pr?.body || DEFAULT_PR_BODY;
|
|
399
|
-
|
|
400
|
-
const update_body = StackSummaryTable.write({
|
|
401
|
-
body,
|
|
402
|
-
pr_url_list,
|
|
403
|
-
selected_url,
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
if (update_body === body) {
|
|
407
|
-
actions.debug(`Skipping body update for ${selected_url}`);
|
|
408
|
-
} else {
|
|
409
|
-
actions.debug(`Update body for ${selected_url}`);
|
|
410
|
-
|
|
411
|
-
await github.pr_edit({
|
|
412
|
-
branch: group.id,
|
|
413
|
-
base: group.base,
|
|
414
|
-
body: update_body,
|
|
415
|
-
});
|
|
416
|
-
}
|
|
155
|
+
actions.error("Unable to rebase.");
|
|
156
|
+
if (!argv.verbose) {
|
|
157
|
+
actions.error("Try again with `--verbose` to see more information.");
|
|
417
158
|
}
|
|
159
|
+
|
|
160
|
+
handle_exit(16);
|
|
418
161
|
}
|
|
419
162
|
|
|
420
163
|
// cleanup git operations if cancelled during manual rebase
|
|
@@ -424,9 +167,6 @@ async function run() {
|
|
|
424
167
|
// all children processes receive the SIGINT signal
|
|
425
168
|
const spawn_options = { ignoreExitCode: true };
|
|
426
169
|
|
|
427
|
-
// always clean up any patch files
|
|
428
|
-
cli.sync(`rm ${PATCH_FILE}`, spawn_options);
|
|
429
|
-
|
|
430
170
|
// always hard reset and clean to allow subsequent checkout
|
|
431
171
|
// if there are files checkout will fail and cascade fail subsequent commands
|
|
432
172
|
cli.sync(`git reset --hard`, spawn_options);
|
|
@@ -438,13 +178,6 @@ async function run() {
|
|
|
438
178
|
// ...and cleanup temporary branch
|
|
439
179
|
cli.sync(`git branch -D ${temp_branch_name}`, spawn_options);
|
|
440
180
|
|
|
441
|
-
if (commit_range) {
|
|
442
|
-
// ...and cleanup pr group branches
|
|
443
|
-
for (const group of commit_range.group_list) {
|
|
444
|
-
cli.sync(`git branch -D ${group.id}`, spawn_options);
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
|
|
448
181
|
// restore back to original dir
|
|
449
182
|
if (fs.existsSync(cwd)) {
|
|
450
183
|
process.chdir(cwd);
|
|
@@ -452,7 +185,7 @@ async function run() {
|
|
|
452
185
|
cli.sync(`pwd`, spawn_options);
|
|
453
186
|
}
|
|
454
187
|
|
|
455
|
-
function handle_exit() {
|
|
188
|
+
function handle_exit(code: number) {
|
|
456
189
|
actions.output(
|
|
457
190
|
<Ink.Text color={colors.yellow}>
|
|
458
191
|
Restoring <Brackets>{branch_name}</Brackets>…
|
|
@@ -467,11 +200,6 @@ async function run() {
|
|
|
467
200
|
</Ink.Text>
|
|
468
201
|
);
|
|
469
202
|
|
|
470
|
-
actions.exit(
|
|
203
|
+
actions.exit(code);
|
|
471
204
|
}
|
|
472
205
|
}
|
|
473
|
-
|
|
474
|
-
type CommitMetadataGroup = CommitMetadata.CommitRange["group_list"][number];
|
|
475
|
-
const get_group_url = (group: CommitMetadataGroup) => group.pr?.url || group.id;
|
|
476
|
-
|
|
477
|
-
const PATCH_FILE = "git-stack-cli-patch.patch";
|