git-stack-cli 2.5.3 → 2.6.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/dist/js/index.js +437 -321
- package/package.json +2 -2
- package/scripts/bun-build.ts +5 -0
- package/src/app/App.tsx +8 -5
- package/src/app/AutoUpdate.tsx +72 -54
- package/src/app/GatherMetadata.tsx +2 -24
- package/src/app/Main.tsx +0 -4
- package/src/app/ManualRebase.tsx +5 -0
- package/src/app/MultiSelect.tsx +8 -12
- package/src/app/RequireBranch.tsx +67 -0
- package/src/app/SelectCommitRanges.tsx +233 -118
- package/src/app/Status.tsx +1 -5
- package/src/app/Store.tsx +2 -1
- package/src/app/SyncGithub.tsx +9 -4
- package/src/app/TextInput.tsx +8 -1
- package/src/commands/Rebase.tsx +50 -36
- package/src/components/ColorTest.tsx +49 -0
- package/src/core/CommitMetadata.ts +6 -5
- package/src/core/GitReviseTodo.test.ts +195 -0
- package/src/core/GitReviseTodo.ts +20 -17
- package/src/core/cli.ts +2 -0
- package/src/core/colors.ts +4 -2
- package/src/app/PreSelectCommitRanges.tsx +0 -29
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import { colors } from "~/core/colors";
|
|
4
|
+
|
|
5
|
+
type RenderOptions = {
|
|
6
|
+
color: string;
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type Props = {
|
|
11
|
+
children: (render_options: RenderOptions) => React.ReactNode;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function ColorTest(props: Props) {
|
|
15
|
+
return (
|
|
16
|
+
<React.Fragment>
|
|
17
|
+
{Object.entries(colors).map(([key, color]) => {
|
|
18
|
+
const name = `colors:${key}`;
|
|
19
|
+
return props.children({ color, name });
|
|
20
|
+
})}
|
|
21
|
+
|
|
22
|
+
{INK_COLORS.map((color) => {
|
|
23
|
+
const name = `ink:${color}`;
|
|
24
|
+
return props.children({ color, name });
|
|
25
|
+
})}
|
|
26
|
+
</React.Fragment>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ForegroundColor
|
|
31
|
+
// https://github.com/magus/git-stack-cli/blob/master/node_modules/.pnpm/chalk@5.3.0/node_modules/chalk/source/vendor/ansi-styles/index.d.ts#L75
|
|
32
|
+
const INK_COLORS = [
|
|
33
|
+
"black",
|
|
34
|
+
"red",
|
|
35
|
+
"green",
|
|
36
|
+
"yellow",
|
|
37
|
+
"blue",
|
|
38
|
+
"cyan",
|
|
39
|
+
"magenta",
|
|
40
|
+
"white",
|
|
41
|
+
"blackBright",
|
|
42
|
+
"redBright",
|
|
43
|
+
"greenBright",
|
|
44
|
+
"yellowBright",
|
|
45
|
+
"blueBright",
|
|
46
|
+
"cyanBright",
|
|
47
|
+
"magentaBright",
|
|
48
|
+
"whiteBright",
|
|
49
|
+
];
|
|
@@ -39,6 +39,8 @@ export async function range(commit_group_map?: CommitGroupMap) {
|
|
|
39
39
|
let id = commit.branch_id;
|
|
40
40
|
let title = commit.title || id;
|
|
41
41
|
|
|
42
|
+
// console.debug({ commit, id });
|
|
43
|
+
|
|
42
44
|
// use commit map if provided (via select commit ranges)
|
|
43
45
|
if (commit_group_map) {
|
|
44
46
|
const group = commit_group_map[commit.sha];
|
|
@@ -50,7 +52,7 @@ export async function range(commit_group_map?: CommitGroupMap) {
|
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
if (!id) {
|
|
53
|
-
// console.debug("INVALID", "MISSING ID"
|
|
55
|
+
// console.debug("INVALID", "MISSING ID");
|
|
54
56
|
invalid = true;
|
|
55
57
|
}
|
|
56
58
|
|
|
@@ -61,13 +63,12 @@ export async function range(commit_group_map?: CommitGroupMap) {
|
|
|
61
63
|
if (group_map.has(id) && last_key !== id) {
|
|
62
64
|
// if we've seen this id before and it's not
|
|
63
65
|
// the last added key then we are out of order
|
|
64
|
-
// console.debug("INVALID", "OUT OF ORDER"
|
|
66
|
+
// console.debug("INVALID", "OUT OF ORDER");
|
|
65
67
|
invalid = true;
|
|
66
68
|
}
|
|
67
69
|
} else {
|
|
68
|
-
// console.debug("INVALID", "NEW COMMIT"
|
|
70
|
+
// console.debug("INVALID", "NEW COMMIT");
|
|
69
71
|
invalid = true;
|
|
70
|
-
|
|
71
72
|
id = UNASSIGNED;
|
|
72
73
|
}
|
|
73
74
|
|
|
@@ -231,4 +232,4 @@ function lines(value: string) {
|
|
|
231
232
|
return value.split("\n");
|
|
232
233
|
}
|
|
233
234
|
|
|
234
|
-
const UNASSIGNED = "unassigned";
|
|
235
|
+
export const UNASSIGNED = "unassigned";
|
|
@@ -75,6 +75,59 @@ test("git-revise-todo handles double quotes in commit message", () => {
|
|
|
75
75
|
);
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
+
test("git-revise-todo from commit range with single new commit", () => {
|
|
79
|
+
const rebase_group_index = 0;
|
|
80
|
+
const commit_range = SYNC_WITH_UNASSIGNED;
|
|
81
|
+
|
|
82
|
+
const git_revise_todo = GitReviseTodo({ rebase_group_index, commit_range });
|
|
83
|
+
|
|
84
|
+
const expected = [
|
|
85
|
+
"++ pick 55771391b49e",
|
|
86
|
+
"head~7",
|
|
87
|
+
"",
|
|
88
|
+
"git-stack-id: gs---4gvxa-5v-2mx26",
|
|
89
|
+
"git-stack-title: pr-title",
|
|
90
|
+
"",
|
|
91
|
+
"++ pick 391476bbfc6b",
|
|
92
|
+
"head~6",
|
|
93
|
+
"",
|
|
94
|
+
"git-stack-id: gs---4gvxa-5v-2mx26",
|
|
95
|
+
"git-stack-title: pr-title",
|
|
96
|
+
"",
|
|
97
|
+
"++ pick 5a98cf8f0406",
|
|
98
|
+
"head~5",
|
|
99
|
+
"",
|
|
100
|
+
"git-stack-id: gs---4gvxa-5v-2mx26",
|
|
101
|
+
"git-stack-title: pr-title",
|
|
102
|
+
"",
|
|
103
|
+
"++ pick e820018cb370",
|
|
104
|
+
"head~4",
|
|
105
|
+
"",
|
|
106
|
+
"git-stack-id: gs---4gvxa-5v-2mx26",
|
|
107
|
+
"git-stack-title: pr-title",
|
|
108
|
+
"",
|
|
109
|
+
"++ pick e6d1dfc7ec00",
|
|
110
|
+
"head~3",
|
|
111
|
+
"",
|
|
112
|
+
"git-stack-id: gs---4gvxa-5v-2mx26",
|
|
113
|
+
"git-stack-title: pr-title",
|
|
114
|
+
"",
|
|
115
|
+
"++ pick a26f21025a55",
|
|
116
|
+
"head~2",
|
|
117
|
+
"",
|
|
118
|
+
"git-stack-id: gs---4gvxa-5v-2mx26",
|
|
119
|
+
"git-stack-title: pr-title",
|
|
120
|
+
"",
|
|
121
|
+
"++ pick 90667fe97e05",
|
|
122
|
+
"head~1",
|
|
123
|
+
"",
|
|
124
|
+
"++ pick b61c5b09a4b7",
|
|
125
|
+
"head",
|
|
126
|
+
].join("\n");
|
|
127
|
+
|
|
128
|
+
expect(git_revise_todo).toBe(expected);
|
|
129
|
+
});
|
|
130
|
+
|
|
78
131
|
const SINGLE_COMMIT_EXISTING_GROUP: CommitMetadata.CommitRange = {
|
|
79
132
|
invalid: false,
|
|
80
133
|
group_list: [
|
|
@@ -654,3 +707,145 @@ const COMMIT_MESSAGE_WITH_QUOTES: CommitMetadata.CommitRange = {
|
|
|
654
707
|
pr_lookup: {},
|
|
655
708
|
UNASSIGNED: "unassigned",
|
|
656
709
|
};
|
|
710
|
+
|
|
711
|
+
// capture via `throw new Error` in `ManualRebase`
|
|
712
|
+
// doc-link capture-git-revise-todo
|
|
713
|
+
const SYNC_WITH_UNASSIGNED: CommitMetadata.CommitRange = {
|
|
714
|
+
invalid: false,
|
|
715
|
+
group_list: [
|
|
716
|
+
{
|
|
717
|
+
id: "gs---4gvxa-5v-2mx26",
|
|
718
|
+
title: "pr-title",
|
|
719
|
+
pr: null,
|
|
720
|
+
base: "master",
|
|
721
|
+
dirty: true,
|
|
722
|
+
commits: [
|
|
723
|
+
{
|
|
724
|
+
sha: "55771391b49e301f51b22cbc2b745e8d3e4a357a",
|
|
725
|
+
full_message: "head~7",
|
|
726
|
+
subject_line: "head~7",
|
|
727
|
+
branch_id: "gs---4gvxa-5v-2mx26",
|
|
728
|
+
title: "pr-title",
|
|
729
|
+
},
|
|
730
|
+
{
|
|
731
|
+
sha: "391476bbfc6b77b60a3ef7fa97155496a9f8f27f",
|
|
732
|
+
full_message: "head~6",
|
|
733
|
+
subject_line: "head~6",
|
|
734
|
+
branch_id: "gs---4gvxa-5v-2mx26",
|
|
735
|
+
title: "pr-title",
|
|
736
|
+
},
|
|
737
|
+
{
|
|
738
|
+
sha: "5a98cf8f0406712405d41af07c3a012f72ad36fa",
|
|
739
|
+
full_message: "head~5",
|
|
740
|
+
subject_line: "head~5",
|
|
741
|
+
branch_id: "gs---4gvxa-5v-2mx26",
|
|
742
|
+
title: "pr-title",
|
|
743
|
+
},
|
|
744
|
+
{
|
|
745
|
+
sha: "e820018cb370bb6cda118dc649e841c75d797188",
|
|
746
|
+
full_message: "head~4",
|
|
747
|
+
subject_line: "head~4",
|
|
748
|
+
branch_id: "gs---4gvxa-5v-2mx26",
|
|
749
|
+
title: "pr-title",
|
|
750
|
+
},
|
|
751
|
+
{
|
|
752
|
+
sha: "e6d1dfc7ec007468712bfc015884cc22bfa79e1d",
|
|
753
|
+
full_message: "head~3",
|
|
754
|
+
subject_line: "head~3",
|
|
755
|
+
branch_id: "gs---4gvxa-5v-2mx26",
|
|
756
|
+
title: "pr-title",
|
|
757
|
+
},
|
|
758
|
+
{
|
|
759
|
+
sha: "a26f21025a558968554c439ab9b942d5fe84bccb",
|
|
760
|
+
full_message: "head~2",
|
|
761
|
+
subject_line: "head~2",
|
|
762
|
+
branch_id: "gs---4gvxa-5v-2mx26",
|
|
763
|
+
title: "pr-title",
|
|
764
|
+
},
|
|
765
|
+
],
|
|
766
|
+
},
|
|
767
|
+
{
|
|
768
|
+
id: "unassigned",
|
|
769
|
+
title: "allow_unassigned",
|
|
770
|
+
pr: null,
|
|
771
|
+
base: null,
|
|
772
|
+
dirty: true,
|
|
773
|
+
commits: [
|
|
774
|
+
{
|
|
775
|
+
sha: "90667fe97e059e8285e070d6268f2b4035b2ebd4",
|
|
776
|
+
full_message: "head~1",
|
|
777
|
+
subject_line: "head~1",
|
|
778
|
+
branch_id: "unassigned",
|
|
779
|
+
title: "allow_unassigned",
|
|
780
|
+
},
|
|
781
|
+
{
|
|
782
|
+
sha: "b61c5b09a4b7c9dcff9a9071386b134997569a01",
|
|
783
|
+
full_message: "head",
|
|
784
|
+
subject_line: "head",
|
|
785
|
+
branch_id: "unassigned",
|
|
786
|
+
title: "allow_unassigned",
|
|
787
|
+
},
|
|
788
|
+
],
|
|
789
|
+
},
|
|
790
|
+
],
|
|
791
|
+
commit_list: [
|
|
792
|
+
{
|
|
793
|
+
sha: "55771391b49e301f51b22cbc2b745e8d3e4a357a",
|
|
794
|
+
full_message: "head~7",
|
|
795
|
+
subject_line: "head~7",
|
|
796
|
+
branch_id: "gs---4gvxa-5v-2mx26",
|
|
797
|
+
title: "pr-title",
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
sha: "391476bbfc6b77b60a3ef7fa97155496a9f8f27f",
|
|
801
|
+
full_message: "head~6",
|
|
802
|
+
subject_line: "head~6",
|
|
803
|
+
branch_id: "gs---4gvxa-5v-2mx26",
|
|
804
|
+
title: "pr-title",
|
|
805
|
+
},
|
|
806
|
+
{
|
|
807
|
+
sha: "5a98cf8f0406712405d41af07c3a012f72ad36fa",
|
|
808
|
+
full_message: "head~5",
|
|
809
|
+
subject_line: "head~5",
|
|
810
|
+
branch_id: "gs---4gvxa-5v-2mx26",
|
|
811
|
+
title: "pr-title",
|
|
812
|
+
},
|
|
813
|
+
{
|
|
814
|
+
sha: "e820018cb370bb6cda118dc649e841c75d797188",
|
|
815
|
+
full_message: "head~4",
|
|
816
|
+
subject_line: "head~4",
|
|
817
|
+
branch_id: "gs---4gvxa-5v-2mx26",
|
|
818
|
+
title: "pr-title",
|
|
819
|
+
},
|
|
820
|
+
{
|
|
821
|
+
sha: "e6d1dfc7ec007468712bfc015884cc22bfa79e1d",
|
|
822
|
+
full_message: "head~3",
|
|
823
|
+
subject_line: "head~3",
|
|
824
|
+
branch_id: "gs---4gvxa-5v-2mx26",
|
|
825
|
+
title: "pr-title",
|
|
826
|
+
},
|
|
827
|
+
{
|
|
828
|
+
sha: "a26f21025a558968554c439ab9b942d5fe84bccb",
|
|
829
|
+
full_message: "head~2",
|
|
830
|
+
subject_line: "head~2",
|
|
831
|
+
branch_id: "gs---4gvxa-5v-2mx26",
|
|
832
|
+
title: "pr-title",
|
|
833
|
+
},
|
|
834
|
+
{
|
|
835
|
+
sha: "90667fe97e059e8285e070d6268f2b4035b2ebd4",
|
|
836
|
+
full_message: "head~1",
|
|
837
|
+
subject_line: "head~1",
|
|
838
|
+
branch_id: "unassigned",
|
|
839
|
+
title: "allow_unassigned",
|
|
840
|
+
},
|
|
841
|
+
{
|
|
842
|
+
sha: "b61c5b09a4b7c9dcff9a9071386b134997569a01",
|
|
843
|
+
full_message: "head",
|
|
844
|
+
subject_line: "head",
|
|
845
|
+
branch_id: "unassigned",
|
|
846
|
+
title: "allow_unassigned",
|
|
847
|
+
},
|
|
848
|
+
],
|
|
849
|
+
pr_lookup: {},
|
|
850
|
+
UNASSIGNED: "unassigned",
|
|
851
|
+
};
|
|
@@ -2,14 +2,13 @@ import fs from "node:fs/promises";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
4
|
import { Store } from "~/app/Store";
|
|
5
|
+
import * as CommitMetadata from "~/core/CommitMetadata";
|
|
5
6
|
import * as Metadata from "~/core/Metadata";
|
|
6
7
|
import { cli } from "~/core/cli";
|
|
7
8
|
import { get_tmp_dir } from "~/core/get_tmp_dir";
|
|
8
9
|
import { invariant } from "~/core/invariant";
|
|
9
10
|
import { safe_rm } from "~/core/safe_rm";
|
|
10
11
|
|
|
11
|
-
import type * as CommitMetadata from "~/core/CommitMetadata";
|
|
12
|
-
|
|
13
12
|
// https://git-revise.readthedocs.io/en/latest/man.html#interactive-mode
|
|
14
13
|
//
|
|
15
14
|
// # Interactive Revise Todos(4 commands)
|
|
@@ -58,6 +57,7 @@ export function GitReviseTodo(args: Args): string {
|
|
|
58
57
|
const commit_list = [];
|
|
59
58
|
|
|
60
59
|
const group_list = args.commit_range.group_list;
|
|
60
|
+
// console.debug({ group_list });
|
|
61
61
|
|
|
62
62
|
for (let i = args.rebase_group_index; i < group_list.length; i++) {
|
|
63
63
|
const group = group_list[i];
|
|
@@ -67,6 +67,7 @@ export function GitReviseTodo(args: Args): string {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
// console.debug({ commit_list });
|
|
70
71
|
const todo = GitReviseTodo.todo({ commit_list });
|
|
71
72
|
return todo;
|
|
72
73
|
}
|
|
@@ -79,26 +80,28 @@ GitReviseTodo.todo = function todo(args: CommitListArgs) {
|
|
|
79
80
|
const entry_list = [];
|
|
80
81
|
|
|
81
82
|
for (const commit of args.commit_list) {
|
|
82
|
-
// update git commit message with stack id
|
|
83
|
-
const id = commit.branch_id;
|
|
84
|
-
const title = commit.title;
|
|
85
|
-
|
|
86
|
-
invariant(id, "commit.branch_id must exist");
|
|
87
|
-
invariant(title, "commit.title must exist");
|
|
88
|
-
|
|
89
|
-
const metadata = { id, title };
|
|
90
|
-
|
|
91
|
-
const unsafe_message_with_id = Metadata.write(commit.full_message, metadata);
|
|
92
|
-
|
|
93
|
-
let message_with_id = unsafe_message_with_id;
|
|
94
|
-
|
|
95
83
|
// get first 12 characters of commit sha
|
|
96
84
|
const sha = commit.sha.slice(0, 12);
|
|
97
85
|
|
|
98
86
|
// generate git revise entry
|
|
99
|
-
const entry_lines = [`++ pick ${sha}
|
|
100
|
-
const entry = entry_lines.join("\n");
|
|
87
|
+
const entry_lines = [`++ pick ${sha}`];
|
|
101
88
|
|
|
89
|
+
// update git commit message with stack id
|
|
90
|
+
const id = commit.branch_id;
|
|
91
|
+
if (id == null || id === CommitMetadata.UNASSIGNED) {
|
|
92
|
+
entry_lines.push(commit.full_message);
|
|
93
|
+
} else {
|
|
94
|
+
// console.debug({ commit });
|
|
95
|
+
const title = commit.title;
|
|
96
|
+
invariant(title, "commit.title must exist");
|
|
97
|
+
|
|
98
|
+
const metadata = { id, title };
|
|
99
|
+
const unsafe_message_with_id = Metadata.write(commit.full_message, metadata);
|
|
100
|
+
const message_with_id = unsafe_message_with_id;
|
|
101
|
+
entry_lines.push(message_with_id);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const entry = entry_lines.join("\n");
|
|
102
105
|
entry_list.push(entry);
|
|
103
106
|
}
|
|
104
107
|
|
package/src/core/cli.ts
CHANGED
|
@@ -7,6 +7,7 @@ type SpawnOptions = Parameters<typeof child.spawn>[2];
|
|
|
7
7
|
|
|
8
8
|
type Options = SpawnOptions & {
|
|
9
9
|
ignoreExitCode?: boolean;
|
|
10
|
+
onOutput?: (data: string) => void;
|
|
10
11
|
};
|
|
11
12
|
|
|
12
13
|
type Return = {
|
|
@@ -51,6 +52,7 @@ export async function cli(
|
|
|
51
52
|
function write_output(value: string) {
|
|
52
53
|
output += value;
|
|
53
54
|
state.actions.debug(value, id);
|
|
55
|
+
options.onOutput?.(value);
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
childProcess.stdout?.on("data", (data: Buffer) => {
|
package/src/core/colors.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// ink uses chalk internally
|
|
2
2
|
// https://github.com/vadimdemedes/ink#color
|
|
3
3
|
|
|
4
|
-
export const colors = {
|
|
4
|
+
export const colors = Object.freeze({
|
|
5
5
|
red: "rgb(248, 81, 73)",
|
|
6
6
|
// red-emphasis rgb(218, 54, 51)
|
|
7
7
|
|
|
@@ -20,4 +20,6 @@ export const colors = {
|
|
|
20
20
|
gray: "rgb(110, 118, 129)",
|
|
21
21
|
|
|
22
22
|
lightGray: "rgb(125, 133, 144)",
|
|
23
|
-
|
|
23
|
+
|
|
24
|
+
white: "whiteBright",
|
|
25
|
+
});
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
import { Store } from "~/app/Store";
|
|
4
|
-
import { YesNoPrompt } from "~/app/YesNoPrompt";
|
|
5
|
-
|
|
6
|
-
export function PreSelectCommitRanges() {
|
|
7
|
-
const actions = Store.useActions();
|
|
8
|
-
const argv = Store.useState((state) => state.argv);
|
|
9
|
-
|
|
10
|
-
React.useEffect(() => {
|
|
11
|
-
if (argv.force) {
|
|
12
|
-
Store.setState((state) => {
|
|
13
|
-
state.step = "select-commit-ranges";
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
}, [argv]);
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<YesNoPrompt
|
|
20
|
-
message="Some commits are new or outdated, would you like to select new commit ranges?"
|
|
21
|
-
onYes={() => {
|
|
22
|
-
actions.set((state) => {
|
|
23
|
-
state.step = "select-commit-ranges";
|
|
24
|
-
});
|
|
25
|
-
}}
|
|
26
|
-
onNo={() => actions.exit(0)}
|
|
27
|
-
/>
|
|
28
|
-
);
|
|
29
|
-
}
|