git-stack-cli 2.5.2 → 2.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-stack-cli",
3
- "version": "2.5.2",
3
+ "version": "2.6.0",
4
4
  "description": "",
5
5
  "author": "magus",
6
6
  "license": "MIT",
@@ -36,7 +36,7 @@
36
36
  "test": "bun test",
37
37
  "test:watch": "pnpm run test --watch",
38
38
  "test:types": "tsc",
39
- "test:all": "pnpm run prettier:check && pnpm run lint:check && pnpm run test:types",
39
+ "test:all": "pnpm run prettier:check && pnpm run lint:check && pnpm run test:types && pnpm run test",
40
40
  "prepublishOnly": "bun run scripts/npm-prepublishOnly.ts"
41
41
  },
42
42
  "dependencies": {
package/src/app/App.tsx CHANGED
@@ -19,6 +19,7 @@ import { VerboseDebugInfo } from "~/app/VerboseDebugInfo";
19
19
  import { Fixup } from "~/commands/Fixup";
20
20
  import { Log } from "~/commands/Log";
21
21
  import { Rebase } from "~/commands/Rebase";
22
+ import { Update } from "~/commands/Update";
22
23
  import { ErrorBoundary } from "~/components/ErrorBoundary";
23
24
  import { ExitingGate } from "~/components/ExitingGate";
24
25
 
@@ -28,7 +29,7 @@ export function App() {
28
29
  const ink = Store.useState((state) => state.ink);
29
30
  const argv = Store.useState((state) => state.argv);
30
31
 
31
- if (!ink || !argv) {
32
+ if (!ink || !argv || !argv.$0) {
32
33
  return null;
33
34
  }
34
35
 
@@ -42,6 +43,9 @@ export function App() {
42
43
  // </React.Fragment>
43
44
  // );
44
45
 
46
+ const positional_list = new Set(argv["_"]);
47
+ const is_update = positional_list.has("update") || positional_list.has("upgrade");
48
+
45
49
  return (
46
50
  <Providers>
47
51
  <ErrorBoundary>
@@ -51,11 +55,12 @@ export function App() {
51
55
  <ExitingGate>
52
56
  <AutoUpdate
53
57
  name="git-stack-cli"
54
- verbose={argv.verbose || argv.update}
55
- timeoutMs={argv.update ? 30 * 1000 : 2 * 1000}
58
+ verbose={argv.verbose}
59
+ force={is_update}
60
+ timeoutMs={is_update ? 30 * 1000 : 2 * 1000}
56
61
  onOutput={actions.output}
57
62
  onDone={() => {
58
- if (argv.update) {
63
+ if (is_update) {
59
64
  actions.exit(0);
60
65
  }
61
66
  }}
@@ -84,6 +89,8 @@ function MaybeMain() {
84
89
  return <Fixup />;
85
90
  } else if (positional_list.has("log")) {
86
91
  return <Log />;
92
+ } else if (positional_list.has("update")) {
93
+ return <Update />;
87
94
  } else if (positional_list.has("rebase")) {
88
95
  return (
89
96
  <DependencyCheck>
@@ -17,6 +17,7 @@ type Props = {
17
17
  name: string;
18
18
  children: React.ReactNode;
19
19
  verbose?: boolean;
20
+ force?: boolean;
20
21
  timeoutMs?: number;
21
22
  onError?: (error: Error) => void;
22
23
  onOutput?: (output: React.ReactNode) => void;
@@ -65,13 +66,14 @@ export function AutoUpdate(props: Props) {
65
66
  let is_brew_bun_standalone = false;
66
67
 
67
68
  const local_version = process.env.CLI_VERSION;
69
+ const is_output = props_ref.current.verbose || props_ref.current.force;
68
70
 
69
71
  async function auto_update() {
70
72
  if (!local_version) {
71
73
  throw new Error("Auto update requires process.env.CLI_VERSION to be set");
72
74
  }
73
75
 
74
- if (props_ref.current.verbose) {
76
+ if (is_output) {
75
77
  handle_output(<Ink.Text key="init">Checking for latest version...</Ink.Text>);
76
78
  }
77
79
 
@@ -125,9 +127,14 @@ export function AutoUpdate(props: Props) {
125
127
 
126
128
  const semver_result = semver_compare(latest_version, local_version);
127
129
 
128
- status = "prompt";
129
-
130
130
  if (semver_result === 0) {
131
+ if (is_output) {
132
+ handle_output(
133
+ <Ink.Text>
134
+ ✅ Everything up to date. <Brackets>{latest_version}</Brackets>
135
+ </Ink.Text>,
136
+ );
137
+ }
131
138
  return;
132
139
  }
133
140
 
@@ -175,7 +182,7 @@ export function AutoUpdate(props: Props) {
175
182
  if (state.is_brew_bun_standalone) {
176
183
  install_command = `npm install -g ${props.name}@latest`;
177
184
  } else {
178
- install_command = `HOMEBREW_NO_AUTO_UPDATE=1 brew upgrade magus/git-stack/git-stack`;
185
+ install_command = "brew upgrade magus/git-stack/git-stack";
179
186
  }
180
187
 
181
188
  return (
@@ -183,7 +190,14 @@ export function AutoUpdate(props: Props) {
183
190
  message={
184
191
  <Ink.Box flexDirection="column">
185
192
  <Ink.Text color={colors.yellow}>
186
- New version available, would you like to update?
193
+ <FormatText
194
+ wrapper={<Ink.Text />}
195
+ message="New version available {latest_version}, would you like to update?"
196
+ values={{
197
+ latest_version: <Brackets>{state.latest_version}</Brackets>,
198
+ }}
199
+ />
200
+ ,
187
201
  </Ink.Text>
188
202
  <Ink.Text> </Ink.Text>
189
203
  <Command>{install_command}</Command>
@@ -59,6 +59,11 @@ async function run() {
59
59
  commit.title = group_from_map.title;
60
60
  }
61
61
 
62
+ // // capture commit_range for GitReviseTodo test
63
+ // // doc-link capture-git-revise-todo
64
+ // console.debug(JSON.stringify(commit_range, null, 2));
65
+ // throw new Error("STOP");
66
+
62
67
  await GitReviseTodo.execute({
63
68
  rebase_group_index: 0,
64
69
  rebase_merge_base: merge_base,
@@ -14,6 +14,7 @@ type Props<T> = {
14
14
  disabled?: boolean;
15
15
  disableSelect?: boolean;
16
16
  maxWidth?: number;
17
+ startIndex?: number;
17
18
  };
18
19
 
19
20
  type Item<T> = {
@@ -67,11 +68,13 @@ export function MultiSelect<T>(props: Props<T>) {
67
68
  for (let i = props.items.length - 1; i >= 0; i--) {
68
69
  const item = props.items[i];
69
70
 
70
- if (!item.disabled) {
71
- last_enabled = i;
71
+ if (item.disabled) {
72
+ continue;
72
73
  }
73
74
 
74
- if (!item.selected && !item.disabled) {
75
+ last_enabled = i;
76
+
77
+ if (!item.selected) {
75
78
  return i;
76
79
  }
77
80
  }
@@ -80,7 +83,7 @@ export function MultiSelect<T>(props: Props<T>) {
80
83
  return last_enabled;
81
84
  }
82
85
 
83
- return 0;
86
+ return props.startIndex || 0;
84
87
  },
85
88
  );
86
89
 
@@ -3,6 +3,7 @@ import * as React from "react";
3
3
  import * as Ink from "ink-cjs";
4
4
 
5
5
  import { Brackets } from "~/app/Brackets";
6
+ import { Command } from "~/app/Command";
6
7
  import { FormatText } from "~/app/FormatText";
7
8
  import { MultiSelect } from "~/app/MultiSelect";
8
9
  import { Parens } from "~/app/Parens";
@@ -78,10 +79,13 @@ function SelectCommitRangesInternal(props: Props) {
78
79
 
79
80
  // detect if there are unassigned commits
80
81
  let unassigned_count = 0;
82
+ let assigned_count = 0;
81
83
  for (const [, group_id] of commit_map.entries()) {
82
84
  if (group_id === null) {
83
85
  // console.debug("unassigned commit detected", sha);
84
86
  unassigned_count++;
87
+ } else {
88
+ assigned_count++;
85
89
  }
86
90
  }
87
91
 
@@ -118,36 +122,54 @@ function SelectCommitRangesInternal(props: Props) {
118
122
  current_index = 0;
119
123
  }
120
124
 
125
+ const has_unassigned_commits = unassigned_count > 0;
126
+ const has_assigned_commits = assigned_count > 0;
127
+
128
+ const sync_status = detect_sync_status();
129
+ // console.debug({ sync_status });
130
+
121
131
  Ink.useInput((input, key) => {
122
- const inputLower = input.toLowerCase();
132
+ const input_lower = input.toLowerCase();
123
133
 
124
- const hasUnassignedCommits = unassigned_count > 0;
134
+ if (input_lower === SYMBOL.s) {
135
+ // do not allow sync when inputting group title
136
+ if (group_input) {
137
+ return;
138
+ }
139
+
140
+ if (sync_status === "disabled") {
141
+ return;
142
+ }
125
143
 
126
- if (!hasUnassignedCommits && inputLower === "s") {
127
144
  actions.set((state) => {
128
- state.commit_map = {};
129
-
130
- for (const [sha, id] of commit_map.entries()) {
131
- if (id) {
132
- const group = group_list.find((g) => g.id === id);
133
- // console.debug({ sha, id, group });
134
- if (group) {
135
- state.commit_map[sha] = group;
136
- }
145
+ const state_commit_map: Record<string, SimpleGroup> = {};
146
+
147
+ for (let [sha, id] of commit_map.entries()) {
148
+ // console.debug({ sha, id });
149
+
150
+ // handle allow_unassigned case
151
+ if (!id) {
152
+ id = props.commit_range.UNASSIGNED;
153
+ const title = "allow_unassigned";
154
+ state_commit_map[sha] = { id, title };
155
+ continue;
137
156
  }
138
- }
139
157
 
140
- switch (inputLower) {
141
- case "s":
142
- state.step = "pre-manual-rebase";
143
- break;
158
+ const group = group_list.find((g) => g.id === id);
159
+ invariant(group, "group must exist");
160
+ // console.debug({ group });
161
+ state_commit_map[sha] = group;
144
162
  }
163
+
164
+ state.commit_map = state_commit_map;
165
+ state.step = "pre-manual-rebase";
145
166
  });
167
+
146
168
  return;
147
169
  }
148
170
 
149
171
  // only allow create when on unassigned group
150
- if (hasUnassignedCommits && inputLower === "c") {
172
+ if (has_unassigned_commits && input_lower === SYMBOL.c) {
151
173
  set_group_input(true);
152
174
  return;
153
175
  }
@@ -170,6 +192,10 @@ function SelectCommitRangesInternal(props: Props) {
170
192
  const multiselect_disabled = group_input;
171
193
  const multiselect_disableSelect = group.id === props.commit_range.UNASSIGNED;
172
194
 
195
+ const max_width = 80;
196
+ const [focused, set_focused] = React.useState("");
197
+ const has_groups = group.id !== props.commit_range.UNASSIGNED;
198
+
173
199
  const items = props.commit_range.commit_list.map((commit) => {
174
200
  const commit_metadata_id = commit_map.get(commit.sha);
175
201
 
@@ -179,6 +205,8 @@ function SelectCommitRangesInternal(props: Props) {
179
205
 
180
206
  if (group_input) {
181
207
  disabled = true;
208
+ } else if (!has_groups) {
209
+ disabled = true;
182
210
  } else {
183
211
  disabled = Boolean(selected && commit_metadata_id !== group.id);
184
212
  }
@@ -193,30 +221,102 @@ function SelectCommitRangesInternal(props: Props) {
193
221
 
194
222
  items.reverse();
195
223
 
196
- // <- (2/4) #742 Title A ->
224
+ return (
225
+ <Ink.Box flexDirection="column">
226
+ <Ink.Box height={1} />
227
+
228
+ {has_groups || group_input ? null : (
229
+ <Ink.Box flexDirection="column">
230
+ <Ink.Text bold color={colors.blue}>
231
+ 👋 Welcome to <Command>git stack</Command>!
232
+ </Ink.Text>
233
+ <Ink.Text color={colors.blue}>
234
+ <FormatText
235
+ message="Press {c} to {create} a new PR group"
236
+ values={{
237
+ c: (
238
+ <Ink.Text bold color={colors.green}>
239
+ c
240
+ </Ink.Text>
241
+ ),
242
+ create: (
243
+ <Ink.Text bold color={colors.green}>
244
+ <Parens>c</Parens>reate
245
+ </Ink.Text>
246
+ ),
247
+ }}
248
+ />
249
+ </Ink.Text>
250
+ </Ink.Box>
251
+ )}
197
252
 
198
- const left_arrow = `${SYMBOL.left} `;
199
- const right_arrow = ` ${SYMBOL.right}`;
200
- const group_position = `(${current_index + 1}/${group_list.length}) `;
253
+ {!has_groups || group_input ? null : (
254
+ <React.Fragment>
255
+ <Ink.Box width={max_width} flexDirection="row">
256
+ <Ink.Box flexDirection="row">
257
+ <Ink.Text bold color={colors.green}>
258
+ {SYMBOL.left}
259
+ </Ink.Text>
260
+ <Ink.Box width={1} />
261
+ <Ink.Text color={colors.gray}>Pull request</Ink.Text>
262
+ <Ink.Box width={1} />
263
+ <Ink.Text color={colors.gray}>
264
+ {`(${current_index + 1}/${group_list.length})`}
265
+ </Ink.Text>
266
+ <Ink.Box width={1} />
267
+ <Ink.Text bold color={colors.green}>
268
+ {SYMBOL.right}
269
+ </Ink.Text>
270
+ </Ink.Box>
271
+ </Ink.Box>
272
+
273
+ <Ink.Box width={max_width}>
274
+ <Ink.Text wrap="truncate-end" bold color={colors.green}>
275
+ {group.title}
276
+ </Ink.Text>
277
+ </Ink.Box>
278
+ </React.Fragment>
279
+ )}
201
280
 
202
- const max_group_label_width = 80;
203
- let group_title_width = max_group_label_width;
204
- group_title_width -= group_position.length;
205
- group_title_width -= left_arrow.length + right_arrow.length;
206
- group_title_width = Math.min(group.title.length, group_title_width);
281
+ {!group_input ? null : (
282
+ <React.Fragment>
283
+ <Ink.Box height={1} />
207
284
 
208
- let max_item_width = max_group_label_width;
209
- max_item_width -= left_arrow.length + right_arrow.length;
285
+ <FormatText
286
+ wrapper={<Ink.Text color={colors.gray} />}
287
+ message="Enter a title for the PR {note}"
288
+ values={{
289
+ note: (
290
+ <Parens>
291
+ <FormatText
292
+ message="press {enter} to submit"
293
+ values={{
294
+ enter: (
295
+ <Ink.Text bold color={colors.green}>
296
+ {SYMBOL.enter}
297
+ </Ink.Text>
298
+ ),
299
+ }}
300
+ />
301
+ </Parens>
302
+ ),
303
+ }}
304
+ />
210
305
 
211
- const [focused, set_focused] = React.useState("");
306
+ <TextInput
307
+ defaultValue={focused}
308
+ onSubmit={submit_group_input}
309
+ onCancel={() => set_group_input(false)}
310
+ />
311
+ </React.Fragment>
312
+ )}
212
313
 
213
- return (
214
- <Ink.Box flexDirection="column">
215
314
  <Ink.Box height={1} />
216
315
 
217
316
  <MultiSelect
317
+ startIndex={items.length - 1}
218
318
  items={items}
219
- maxWidth={max_item_width}
319
+ maxWidth={max_width}
220
320
  disabled={multiselect_disabled}
221
321
  disableSelect={multiselect_disableSelect}
222
322
  onFocus={(args) => {
@@ -242,109 +342,69 @@ function SelectCommitRangesInternal(props: Props) {
242
342
 
243
343
  <Ink.Box height={1} />
244
344
 
245
- <Ink.Box width={max_group_label_width} flexDirection="row">
246
- <Ink.Text>{left_arrow}</Ink.Text>
247
- <Ink.Text>{group_position}</Ink.Text>
248
-
249
- <Ink.Box width={group_title_width} justifyContent="center">
250
- <Ink.Text wrap="truncate-end">{group.title}</Ink.Text>
251
- </Ink.Box>
252
-
253
- <Ink.Text>{right_arrow}</Ink.Text>
254
- </Ink.Box>
255
-
256
- <Ink.Box height={1} />
257
-
258
- {unassigned_count > 0 ? (
259
- <FormatText
260
- wrapper={<Ink.Text color={colors.gray} />}
261
- message="{count} unassigned commits, press {c} to {create} a new group"
262
- values={{
263
- count: (
264
- <Ink.Text color={colors.yellow} bold>
265
- {unassigned_count}
266
- </Ink.Text>
267
- ),
268
- c: (
269
- <Ink.Text bold color={colors.green}>
270
- c
271
- </Ink.Text>
272
- ),
273
- create: (
274
- <Ink.Text bold color={colors.green}>
275
- <Parens>c</Parens>reate
276
- </Ink.Text>
277
- ),
278
- }}
279
- />
280
- ) : (
345
+ {has_unassigned_commits ? (
281
346
  <React.Fragment>
282
- {argv.sync ? (
347
+ <FormatText
348
+ wrapper={<Ink.Text color={colors.gray} />}
349
+ message="{count} unassigned commits"
350
+ values={{
351
+ count: (
352
+ <Ink.Text color={colors.yellow} bold>
353
+ {unassigned_count}
354
+ </Ink.Text>
355
+ ),
356
+ }}
357
+ />
358
+
359
+ {group_input ? null : (
283
360
  <FormatText
284
- wrapper={<Ink.Text />}
285
- message="🎉 Done! Press {s} to {sync} the commits to Github"
361
+ wrapper={<Ink.Text color={colors.gray} />}
362
+ message="Press {c} to {create} a new PR group"
286
363
  values={{
287
- s: (
364
+ c: (
288
365
  <Ink.Text bold color={colors.green}>
289
- s
366
+ c
290
367
  </Ink.Text>
291
368
  ),
292
- sync: (
369
+ create: (
293
370
  <Ink.Text bold color={colors.green}>
294
- <Parens>s</Parens>ync
371
+ <Parens>c</Parens>reate
295
372
  </Ink.Text>
296
373
  ),
297
374
  }}
298
375
  />
299
- ) : (
376
+ )}
377
+
378
+ {sync_status !== "allow_unassigned" ? null : (
300
379
  <FormatText
301
- wrapper={<Ink.Text />}
302
- message="🎉 Done! Press {s} to {save} the commits locally"
380
+ wrapper={<Ink.Text color={colors.gray} />}
381
+ message="Press {s} to {sync} the {count} assigned commits to Github"
303
382
  values={{
304
- s: (
305
- <Ink.Text bold color={colors.green}>
306
- s
307
- </Ink.Text>
308
- ),
309
- save: (
310
- <Ink.Text bold color={colors.green}>
311
- <Parens>s</Parens>save
383
+ ...S_TO_SYNC_VALUES,
384
+ count: (
385
+ <Ink.Text color={colors.yellow} bold>
386
+ {assigned_count}
312
387
  </Ink.Text>
313
388
  ),
314
389
  }}
315
390
  />
316
391
  )}
317
392
  </React.Fragment>
318
- )}
319
-
320
- {!group_input ? null : (
393
+ ) : (
321
394
  <React.Fragment>
322
- <Ink.Box height={1} />
323
-
324
- <FormatText
325
- wrapper={<Ink.Text color={colors.gray} />}
326
- message="Enter a title for the PR {note}"
327
- values={{
328
- note: (
329
- <Parens>
330
- <FormatText
331
- message="press {enter} to submit"
332
- values={{
333
- enter: (
334
- <Ink.Text bold color={colors.green}>
335
- {SYMBOL.enter}
336
- </Ink.Text>
337
- ),
338
- }}
339
- />
340
- </Parens>
341
- ),
342
- }}
343
- />
344
-
345
- <TextInput defaultValue={focused} onSubmit={submit_group_input} />
346
-
347
- <Ink.Box height={1} />
395
+ {argv.sync ? (
396
+ <FormatText
397
+ wrapper={<Ink.Text />}
398
+ message="🎉 Done! Press {s} to {sync} the commits to Github"
399
+ values={S_TO_SYNC_VALUES}
400
+ />
401
+ ) : (
402
+ <FormatText
403
+ wrapper={<Ink.Text />}
404
+ message="🎉 Done! Press {s} to {save} the commits locally"
405
+ values={S_TO_SYNC_VALUES}
406
+ />
407
+ )}
348
408
  </React.Fragment>
349
409
  )}
350
410
 
@@ -396,13 +456,14 @@ function SelectCommitRangesInternal(props: Props) {
396
456
 
397
457
  return `${branch_prefix}${gs_short_id()}`;
398
458
  }
459
+
399
460
  function submit_group_input(title: string) {
400
461
  const id = get_group_id();
401
462
 
402
463
  actions.output(
403
464
  <FormatText
404
465
  wrapper={<Ink.Text dimColor />}
405
- message="Created new group {group} {note}"
466
+ message="Created new PR group {group} {note}"
406
467
  values={{
407
468
  group: <Brackets>{title}</Brackets>,
408
469
  note: <Parens>{id}</Parens>,
@@ -415,10 +476,64 @@ function SelectCommitRangesInternal(props: Props) {
415
476
  set_selected_group_id(id);
416
477
  set_group_input(false);
417
478
  }
479
+
480
+ function detect_sync_status() {
481
+ if (!has_unassigned_commits) {
482
+ return "allow";
483
+ }
484
+
485
+ if (!has_assigned_commits) {
486
+ return "disabled";
487
+ }
488
+
489
+ let allow_unassigned_sync = null;
490
+
491
+ for (let i = 0; i < props.commit_range.commit_list.length; i++) {
492
+ const commit = props.commit_range.commit_list[i];
493
+ const group_id = commit_map.get(commit.sha);
494
+ // console.debug(commit.sha, group_id);
495
+
496
+ // before detecting unassigned we are null
497
+ if (allow_unassigned_sync === null) {
498
+ if (group_id === null) {
499
+ // console.debug("allow_unassigned_sync TRUE", { i });
500
+ allow_unassigned_sync = true;
501
+ }
502
+ } else {
503
+ // after detecting unassigned we assume we can unassigned sync
504
+ // unless we detect an invariant violation, i.e. commit assigned to group
505
+ if (group_id) {
506
+ // console.debug("allow_unassigned_sync FALSE", { i });
507
+ allow_unassigned_sync = false;
508
+ }
509
+ }
510
+ }
511
+
512
+ if (allow_unassigned_sync) {
513
+ return "allow_unassigned";
514
+ }
515
+
516
+ return "disabled";
517
+ }
418
518
  }
419
519
 
420
520
  const SYMBOL = {
421
521
  left: "←",
422
522
  right: "→",
423
523
  enter: "Enter",
524
+ c: "c",
525
+ s: "s",
526
+ };
527
+
528
+ const S_TO_SYNC_VALUES = {
529
+ s: (
530
+ <Ink.Text bold color={colors.green}>
531
+ s
532
+ </Ink.Text>
533
+ ),
534
+ sync: (
535
+ <Ink.Text bold color={colors.green}>
536
+ <Parens>s</Parens>ync
537
+ </Ink.Text>
538
+ ),
424
539
  };
@@ -42,6 +42,9 @@ async function run() {
42
42
 
43
43
  const push_group_list = get_push_group_list();
44
44
 
45
+ // console.debug({ push_group_list });
46
+ // throw new Error("STOP");
47
+
45
48
  // for all push targets in push_group_list
46
49
  // things that can be done in parallel are grouped by numbers
47
50
  //
@@ -92,7 +95,7 @@ async function run() {
92
95
 
93
96
  await cli(git_push_command);
94
97
 
95
- const pr_url_list = commit_range.group_list.map(get_group_url);
98
+ const pr_url_list = push_group_list.map(get_group_url);
96
99
 
97
100
  const after_push_tasks = [];
98
101
  for (const group of push_group_list) {
@@ -105,8 +108,8 @@ async function run() {
105
108
  // this step must come after the after_push since that step may create new PRs
106
109
  // we need the urls for all prs at this step so we run it after the after_push
107
110
  const update_pr_body_tasks = [];
108
- for (let i = 0; i < commit_range.group_list.length; i++) {
109
- const group = commit_range.group_list[i];
111
+ for (let i = 0; i < push_group_list.length; i++) {
112
+ const group = push_group_list[i];
110
113
 
111
114
  // use the updated pr_url_list to get the actual selected_url
112
115
  const selected_url = pr_url_list[i];
@@ -149,7 +152,9 @@ async function run() {
149
152
 
150
153
  const group = commit_range.group_list[index];
151
154
 
152
- push_group_list.unshift(group);
155
+ if (group.id !== commit_range.UNASSIGNED) {
156
+ push_group_list.unshift(group);
157
+ }
153
158
  }
154
159
 
155
160
  return push_group_list;