git-stack-cli 2.7.6 → 2.7.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/js/index.js +60 -60
- package/package.json +1 -1
- package/src/app/SelectCommitRanges.tsx +57 -52
- package/src/app/Status.tsx +4 -0
- package/src/app/SyncGithub.tsx +41 -14
- package/src/components/ErrorBoundary.tsx +0 -1
- package/src/core/github.tsx +9 -4
- package/src/index.tsx +4 -3
package/package.json
CHANGED
|
@@ -38,6 +38,8 @@ function SelectCommitRangesInternal(props: Props) {
|
|
|
38
38
|
const branch_name = Store.useState((state) => state.branch_name);
|
|
39
39
|
invariant(branch_name, "branch_name must exist");
|
|
40
40
|
|
|
41
|
+
const [focused, set_focused] = React.useState("");
|
|
42
|
+
|
|
41
43
|
const [selected_group_id, set_selected_group_id] = React.useState(() => {
|
|
42
44
|
const first_group = props.commit_range.group_list.find(
|
|
43
45
|
(g) => g.id !== props.commit_range.UNASSIGNED,
|
|
@@ -79,57 +81,6 @@ function SelectCommitRangesInternal(props: Props) {
|
|
|
79
81
|
|
|
80
82
|
const group_list: Array<SimpleGroup> = [];
|
|
81
83
|
|
|
82
|
-
// detect if there are unassigned commits
|
|
83
|
-
let unassigned_count = 0;
|
|
84
|
-
let assigned_count = 0;
|
|
85
|
-
for (const [, group_id] of commit_map.entries()) {
|
|
86
|
-
if (group_id === null) {
|
|
87
|
-
// console.debug("unassigned commit detected", sha);
|
|
88
|
-
unassigned_count++;
|
|
89
|
-
} else {
|
|
90
|
-
assigned_count++;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const total_group_count = new_group_list.length + props.commit_range.group_list.length;
|
|
95
|
-
|
|
96
|
-
for (let i = 0; i < props.commit_range.group_list.length; i++) {
|
|
97
|
-
const index = props.commit_range.group_list.length - i - 1;
|
|
98
|
-
const group = props.commit_range.group_list[index];
|
|
99
|
-
|
|
100
|
-
if (group.pr?.state === "MERGED") continue;
|
|
101
|
-
|
|
102
|
-
if (group.id === props.commit_range.UNASSIGNED) {
|
|
103
|
-
// only include unassigned group when there are no other groups
|
|
104
|
-
if (total_group_count === 1) {
|
|
105
|
-
group_list.push({
|
|
106
|
-
id: group.id,
|
|
107
|
-
title: "Unassigned",
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
group_list.push({
|
|
115
|
-
id: group.id,
|
|
116
|
-
title: group.pr?.title || group.title || group.id,
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
group_list.push(...new_group_list);
|
|
121
|
-
|
|
122
|
-
let current_index = group_list.findIndex((g) => g.id === selected_group_id);
|
|
123
|
-
if (current_index === -1) {
|
|
124
|
-
current_index = 0;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const has_unassigned_commits = unassigned_count > 0;
|
|
128
|
-
const has_assigned_commits = assigned_count > 0;
|
|
129
|
-
|
|
130
|
-
const sync_status = detect_sync_status();
|
|
131
|
-
// console.debug({ sync_status });
|
|
132
|
-
|
|
133
84
|
Ink.useInput((input, key) => {
|
|
134
85
|
const input_lower = input.toLowerCase();
|
|
135
86
|
|
|
@@ -189,13 +140,67 @@ function SelectCommitRangesInternal(props: Props) {
|
|
|
189
140
|
}
|
|
190
141
|
});
|
|
191
142
|
|
|
143
|
+
// detect if there are unassigned commits
|
|
144
|
+
let unassigned_count = 0;
|
|
145
|
+
let assigned_count = 0;
|
|
146
|
+
for (const [, group_id] of commit_map.entries()) {
|
|
147
|
+
if (group_id === null) {
|
|
148
|
+
// console.debug("unassigned commit detected", sha);
|
|
149
|
+
unassigned_count++;
|
|
150
|
+
} else {
|
|
151
|
+
assigned_count++;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (!props.commit_range.group_list.length) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const total_group_count = new_group_list.length + props.commit_range.group_list.length;
|
|
160
|
+
|
|
161
|
+
for (let i = 0; i < props.commit_range.group_list.length; i++) {
|
|
162
|
+
const index = props.commit_range.group_list.length - i - 1;
|
|
163
|
+
const group = props.commit_range.group_list[index];
|
|
164
|
+
|
|
165
|
+
if (group.pr?.state === "MERGED") continue;
|
|
166
|
+
|
|
167
|
+
if (group.id === props.commit_range.UNASSIGNED) {
|
|
168
|
+
// only include unassigned group when there are no other groups
|
|
169
|
+
if (total_group_count === 1) {
|
|
170
|
+
group_list.push({
|
|
171
|
+
id: group.id,
|
|
172
|
+
title: "Unassigned",
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
group_list.push({
|
|
180
|
+
id: group.id,
|
|
181
|
+
title: group.pr?.title || group.title || group.id,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
group_list.push(...new_group_list);
|
|
186
|
+
|
|
187
|
+
let current_index = group_list.findIndex((g) => g.id === selected_group_id);
|
|
188
|
+
if (current_index === -1) {
|
|
189
|
+
current_index = 0;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const has_unassigned_commits = unassigned_count > 0;
|
|
193
|
+
const has_assigned_commits = assigned_count > 0;
|
|
194
|
+
|
|
195
|
+
const sync_status = detect_sync_status();
|
|
196
|
+
// console.debug({ sync_status });
|
|
197
|
+
|
|
192
198
|
const group = group_list[current_index];
|
|
193
199
|
|
|
194
200
|
const multiselect_disabled = group_input;
|
|
195
201
|
const multiselect_disableSelect = group.id === props.commit_range.UNASSIGNED;
|
|
196
202
|
|
|
197
203
|
const max_width = 80;
|
|
198
|
-
const [focused, set_focused] = React.useState("");
|
|
199
204
|
const has_groups = group.id !== props.commit_range.UNASSIGNED;
|
|
200
205
|
|
|
201
206
|
const items = props.commit_range.commit_list.map((commit) => {
|
package/src/app/Status.tsx
CHANGED
package/src/app/SyncGithub.tsx
CHANGED
|
@@ -169,10 +169,26 @@ async function run() {
|
|
|
169
169
|
// avoid accidentally pointing to orphaned parent commit
|
|
170
170
|
// should hopefully fix issues where a PR includes a bunch of commits after pushing
|
|
171
171
|
if (group.pr) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
172
|
+
// only update base if it is different
|
|
173
|
+
// github api started returning errors here on 2025-12-08
|
|
174
|
+
//
|
|
175
|
+
// ```
|
|
176
|
+
// [2025-12-08 17:54:44.114] [start] gh pr edit noah/cua-images-chatgpt-prod-tags---4h0tk3liqmmplu --base master
|
|
177
|
+
// [2025-12-08 17:54:45.935] [end] gh pr edit noah/cua-images-chatgpt-prod-tags---4h0tk3liqmmplu --base master (exit_code=1 duration=1.8s)
|
|
178
|
+
// [2025-12-08 17:54:45.937] GraphQL: A pull request already exists for base branch 'master' and head branch 'noah/cua-images-chatgpt-prod-tags---4h0tk3liqmmplu' (updatePullRequest)
|
|
179
|
+
//
|
|
180
|
+
// [2025-12-08 17:54:45.938] gh pr edit noah/cua-images-chatgpt-prod-tags---4h0tk3liqmmplu --base master (exit_code=1 duration=1.8s)
|
|
181
|
+
// GraphQL: A pull request already exists for base branch 'master' and head branch 'noah/cua-images-chatgpt-prod-tags---4h0tk3liqmmplu' (updatePullRequest)
|
|
182
|
+
// gh pr edit noah/cua-images-chatgpt-prod-tags---4h0tk3liqmmplu --base master (exit_code=1 duration=1.8s)
|
|
183
|
+
// Unable to sync.
|
|
184
|
+
// ```
|
|
185
|
+
//
|
|
186
|
+
if (`origin/${group.pr.baseRefName}` !== master_branch) {
|
|
187
|
+
await github.pr_edit({
|
|
188
|
+
branch: group.id,
|
|
189
|
+
base: master_branch,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
176
192
|
}
|
|
177
193
|
}
|
|
178
194
|
|
|
@@ -184,16 +200,27 @@ async function run() {
|
|
|
184
200
|
const selected_url = get_group_url(group);
|
|
185
201
|
|
|
186
202
|
if (group.pr) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
body:
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
203
|
+
if (`origin/${group.pr.baseRefName}` !== master_branch) {
|
|
204
|
+
// ensure base matches pr in github
|
|
205
|
+
await github.pr_edit({
|
|
206
|
+
branch: group.id,
|
|
207
|
+
base: group.base,
|
|
208
|
+
body: StackSummaryTable.write({
|
|
209
|
+
body: group.pr.body,
|
|
210
|
+
pr_url_list,
|
|
211
|
+
selected_url,
|
|
212
|
+
}),
|
|
213
|
+
});
|
|
214
|
+
} else {
|
|
215
|
+
await github.pr_edit({
|
|
216
|
+
branch: group.id,
|
|
217
|
+
body: StackSummaryTable.write({
|
|
218
|
+
body: group.pr.body,
|
|
219
|
+
pr_url_list,
|
|
220
|
+
selected_url,
|
|
221
|
+
}),
|
|
222
|
+
});
|
|
223
|
+
}
|
|
197
224
|
} else {
|
|
198
225
|
// create pr in github
|
|
199
226
|
const pr_url = await github.pr_create({
|
package/src/core/github.tsx
CHANGED
|
@@ -162,13 +162,17 @@ export async function pr_create(args: CreatePullRequestArgs) {
|
|
|
162
162
|
|
|
163
163
|
type EditPullRequestArgs = {
|
|
164
164
|
branch: string;
|
|
165
|
-
base
|
|
165
|
+
base?: string;
|
|
166
166
|
body?: string;
|
|
167
167
|
};
|
|
168
168
|
|
|
169
169
|
export async function pr_edit(args: EditPullRequestArgs) {
|
|
170
|
-
const
|
|
171
|
-
|
|
170
|
+
const command_parts = [`gh pr edit ${args.branch}`];
|
|
171
|
+
|
|
172
|
+
if (args.base) {
|
|
173
|
+
const base = args.base.replace(/^origin\//, "");
|
|
174
|
+
command_parts.push(`--base ${base}`);
|
|
175
|
+
}
|
|
172
176
|
|
|
173
177
|
let body_file: string | undefined;
|
|
174
178
|
|
|
@@ -279,7 +283,8 @@ async function write_body_file(args: EditPullRequestArgs) {
|
|
|
279
283
|
// ensure unique filename is safe for filesystem
|
|
280
284
|
// base (group id) might contain slashes, e.g. dev/magus/gs-3cmrMBSUj
|
|
281
285
|
// the flashes would mess up the filesystem path to this file
|
|
282
|
-
|
|
286
|
+
let base = args.base || "master";
|
|
287
|
+
base = base.replace(/^origin\//, "");
|
|
283
288
|
let tmp_filename = safe_filename(`git-stack-body-${base}`);
|
|
284
289
|
|
|
285
290
|
const temp_path = path.join(await get_tmp_dir(), tmp_filename);
|
package/src/index.tsx
CHANGED
|
@@ -27,14 +27,14 @@ import { pretty_json } from "~/core/pretty_json";
|
|
|
27
27
|
console.error("🚨 uncaughtException");
|
|
28
28
|
console.error(error);
|
|
29
29
|
maybe_verbose_help();
|
|
30
|
-
process.exit(
|
|
30
|
+
process.exit(20);
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
process.on("unhandledRejection", (reason, _promise) => {
|
|
34
34
|
console.error("🚨 unhandledRejection");
|
|
35
35
|
console.error(reason);
|
|
36
36
|
maybe_verbose_help();
|
|
37
|
-
process.exit(
|
|
37
|
+
process.exit(21);
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
// cleanup leftover temporary files from previous run
|
|
@@ -76,9 +76,10 @@ import { pretty_json } from "~/core/pretty_json";
|
|
|
76
76
|
} catch (err) {
|
|
77
77
|
console.error("🚨 main catch");
|
|
78
78
|
console.error(err);
|
|
79
|
-
process.exit(
|
|
79
|
+
process.exit(22);
|
|
80
80
|
}
|
|
81
81
|
})().catch((err) => {
|
|
82
82
|
console.error("🚨 index catch");
|
|
83
83
|
console.error(err);
|
|
84
|
+
process.exit(23);
|
|
84
85
|
});
|