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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-stack-cli",
3
- "version": "2.7.6",
3
+ "version": "2.7.8",
4
4
  "description": "",
5
5
  "author": "magus",
6
6
  "license": "MIT",
@@ -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) => {
@@ -21,6 +21,10 @@ async function run() {
21
21
 
22
22
  invariant(commit_range, "commit_range must exist");
23
23
 
24
+ if (commit_range.group_list.length === 0) {
25
+ return actions.exit(0);
26
+ }
27
+
24
28
  actions.output(<StatusTable />);
25
29
 
26
30
  let needs_rebase = false;
@@ -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
- await github.pr_edit({
173
- branch: group.id,
174
- base: master_branch,
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
- // ensure base matches pr in github
188
- await github.pr_edit({
189
- branch: group.id,
190
- base: group.base,
191
- body: StackSummaryTable.write({
192
- body: group.pr.body,
193
- pr_url_list,
194
- selected_url,
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({
@@ -1,4 +1,3 @@
1
- /* eslint-disable no-console */
2
1
  import * as React from "react";
3
2
 
4
3
  import * as Ink from "ink-cjs";
@@ -162,13 +162,17 @@ export async function pr_create(args: CreatePullRequestArgs) {
162
162
 
163
163
  type EditPullRequestArgs = {
164
164
  branch: string;
165
- base: string;
165
+ base?: string;
166
166
  body?: string;
167
167
  };
168
168
 
169
169
  export async function pr_edit(args: EditPullRequestArgs) {
170
- const base = args.base.replace(/^origin\//, "");
171
- const command_parts = [`gh pr edit ${args.branch} --base ${base}`];
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
- const base = args.base.replace(/^origin\//, "");
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(237);
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(238);
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(236);
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
  });