git-stack-cli 1.3.6 → 1.4.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/dist/cjs/index.cjs +183 -85
- package/package.json +1 -1
- package/src/app/App.tsx +16 -10
- package/src/app/CherryPickCheck.tsx +94 -0
- package/src/app/DependencyCheck.tsx +4 -4
- package/src/app/DirtyCheck.tsx +91 -0
- package/src/app/GatherMetadata.tsx +1 -3
- package/src/app/LocalCommitStatus.tsx +1 -1
- package/src/app/LocalMergeRebase.tsx +2 -2
- package/src/app/ManualRebase.tsx +2 -2
- package/src/app/RebaseCheck.tsx +9 -5
package/dist/cjs/index.cjs
CHANGED
|
@@ -26560,14 +26560,14 @@ async function sleep(time) {
|
|
|
26560
26560
|
return new Promise((resolve) => setTimeout(resolve, time));
|
|
26561
26561
|
}
|
|
26562
26562
|
|
|
26563
|
-
function reducer$
|
|
26563
|
+
function reducer$3(state, patch) {
|
|
26564
26564
|
return { ...state, ...patch };
|
|
26565
26565
|
}
|
|
26566
26566
|
function AutoUpdate(props) {
|
|
26567
26567
|
const props_ref = reactExports.useRef(props);
|
|
26568
26568
|
props_ref.current = props;
|
|
26569
26569
|
const [output, set_output] = reactExports.useState([]);
|
|
26570
|
-
const [state, patch] = reactExports.useReducer(reducer$
|
|
26570
|
+
const [state, patch] = reactExports.useReducer(reducer$3, {
|
|
26571
26571
|
error: null,
|
|
26572
26572
|
local_version: null,
|
|
26573
26573
|
latest_version: null,
|
|
@@ -26676,67 +26676,6 @@ function AutoUpdate(props) {
|
|
|
26676
26676
|
status));
|
|
26677
26677
|
}
|
|
26678
26678
|
|
|
26679
|
-
function serialize(obj) {
|
|
26680
|
-
if (obj instanceof Map) {
|
|
26681
|
-
return {
|
|
26682
|
-
_type: "Map",
|
|
26683
|
-
_value: Array.from(obj.entries()).map(([k, v]) => [k, serialize(v)]),
|
|
26684
|
-
};
|
|
26685
|
-
}
|
|
26686
|
-
else if (Array.isArray(obj)) {
|
|
26687
|
-
return obj.map(serialize);
|
|
26688
|
-
}
|
|
26689
|
-
else if (obj !== null && typeof obj === "object") {
|
|
26690
|
-
const serializedObj = {};
|
|
26691
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
26692
|
-
serializedObj[key] = serialize(value);
|
|
26693
|
-
}
|
|
26694
|
-
return serializedObj;
|
|
26695
|
-
}
|
|
26696
|
-
return obj;
|
|
26697
|
-
}
|
|
26698
|
-
function deserialize(obj) {
|
|
26699
|
-
if (obj && obj._type === "Map") {
|
|
26700
|
-
return new Map(obj._value.map(([k, v]) => [k, deserialize(v)]));
|
|
26701
|
-
}
|
|
26702
|
-
else if (Array.isArray(obj)) {
|
|
26703
|
-
return obj.map(deserialize);
|
|
26704
|
-
}
|
|
26705
|
-
else if (obj !== null && typeof obj === "object") {
|
|
26706
|
-
const deserializedObj = {};
|
|
26707
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
26708
|
-
deserializedObj[key] = deserialize(value);
|
|
26709
|
-
}
|
|
26710
|
-
return deserializedObj;
|
|
26711
|
-
}
|
|
26712
|
-
return obj;
|
|
26713
|
-
}
|
|
26714
|
-
|
|
26715
|
-
function Debug() {
|
|
26716
|
-
const actions = Store.useActions();
|
|
26717
|
-
const state = Store.useState((state) => state);
|
|
26718
|
-
const argv = Store.useState((state) => state.argv);
|
|
26719
|
-
const debug = Store.useState((state) => state.select.debug(state));
|
|
26720
|
-
reactExports.useEffect(function debugMessageOnce() {
|
|
26721
|
-
if (debug) {
|
|
26722
|
-
actions.output(reactExports.createElement(Text, { color: colors.yellow }, "Debug mode enabled"));
|
|
26723
|
-
}
|
|
26724
|
-
}, [argv]);
|
|
26725
|
-
reactExports.useEffect(function syncStateJson() {
|
|
26726
|
-
if (!argv?.["write-state-json"]) {
|
|
26727
|
-
return;
|
|
26728
|
-
}
|
|
26729
|
-
const output_file = path.join(state.cwd, "git-stack-state.json");
|
|
26730
|
-
if (fs.existsSync(output_file)) {
|
|
26731
|
-
fs.rmSync(output_file);
|
|
26732
|
-
}
|
|
26733
|
-
const serialized = serialize(state);
|
|
26734
|
-
const content = JSON.stringify(serialized, null, 2);
|
|
26735
|
-
fs.writeFileSync(output_file, content);
|
|
26736
|
-
}, [argv, state]);
|
|
26737
|
-
return null;
|
|
26738
|
-
}
|
|
26739
|
-
|
|
26740
26679
|
function cache(cacheable) {
|
|
26741
26680
|
let status = "pending";
|
|
26742
26681
|
let response;
|
|
@@ -26831,6 +26770,113 @@ function Command(props) {
|
|
|
26831
26770
|
return (reactExports.createElement(Text, { bold: true, color: text_color }, props.children));
|
|
26832
26771
|
}
|
|
26833
26772
|
|
|
26773
|
+
function reducer$2(state, patch) {
|
|
26774
|
+
return { ...state, ...patch };
|
|
26775
|
+
}
|
|
26776
|
+
function CherryPickCheck(props) {
|
|
26777
|
+
const actions = Store.useActions();
|
|
26778
|
+
const [state, patch] = reactExports.useReducer(reducer$2, {
|
|
26779
|
+
status: "init",
|
|
26780
|
+
});
|
|
26781
|
+
switch (state.status) {
|
|
26782
|
+
case "done":
|
|
26783
|
+
return props.children;
|
|
26784
|
+
case "prompt":
|
|
26785
|
+
return (reactExports.createElement(YesNoPrompt, { message: reactExports.createElement(Text, { color: colors.yellow },
|
|
26786
|
+
reactExports.createElement(Command, null, "git cherry-pick"),
|
|
26787
|
+
" detected, would you like to abort it?"), onYes: async () => {
|
|
26788
|
+
await cli(`git cherry-pick --abort`);
|
|
26789
|
+
patch({ status: "done" });
|
|
26790
|
+
}, onNo: async () => {
|
|
26791
|
+
actions.exit(0);
|
|
26792
|
+
} }));
|
|
26793
|
+
default:
|
|
26794
|
+
return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow },
|
|
26795
|
+
"Checking for ",
|
|
26796
|
+
reactExports.createElement(Command, null, "git cherry-pick"),
|
|
26797
|
+
"\u2026"), function: cherry_pick_check }));
|
|
26798
|
+
}
|
|
26799
|
+
async function cherry_pick_check() {
|
|
26800
|
+
const actions = Store.getState().actions;
|
|
26801
|
+
try {
|
|
26802
|
+
const git_dir = (await cli(`git rev-parse --absolute-git-dir`)).stdout;
|
|
26803
|
+
const is_cherry_pick = fs.existsSync(path.join(git_dir, "CHERRY_PICK_HEAD"));
|
|
26804
|
+
const status = is_cherry_pick ? "prompt" : "done";
|
|
26805
|
+
patch({ status });
|
|
26806
|
+
}
|
|
26807
|
+
catch (err) {
|
|
26808
|
+
actions.error("Must be run from within a git repository.");
|
|
26809
|
+
if (err instanceof Error) {
|
|
26810
|
+
if (actions.isDebug()) {
|
|
26811
|
+
actions.error(err.message);
|
|
26812
|
+
}
|
|
26813
|
+
}
|
|
26814
|
+
actions.exit(9);
|
|
26815
|
+
}
|
|
26816
|
+
}
|
|
26817
|
+
}
|
|
26818
|
+
|
|
26819
|
+
function serialize(obj) {
|
|
26820
|
+
if (obj instanceof Map) {
|
|
26821
|
+
return {
|
|
26822
|
+
_type: "Map",
|
|
26823
|
+
_value: Array.from(obj.entries()).map(([k, v]) => [k, serialize(v)]),
|
|
26824
|
+
};
|
|
26825
|
+
}
|
|
26826
|
+
else if (Array.isArray(obj)) {
|
|
26827
|
+
return obj.map(serialize);
|
|
26828
|
+
}
|
|
26829
|
+
else if (obj !== null && typeof obj === "object") {
|
|
26830
|
+
const serializedObj = {};
|
|
26831
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
26832
|
+
serializedObj[key] = serialize(value);
|
|
26833
|
+
}
|
|
26834
|
+
return serializedObj;
|
|
26835
|
+
}
|
|
26836
|
+
return obj;
|
|
26837
|
+
}
|
|
26838
|
+
function deserialize(obj) {
|
|
26839
|
+
if (obj && obj._type === "Map") {
|
|
26840
|
+
return new Map(obj._value.map(([k, v]) => [k, deserialize(v)]));
|
|
26841
|
+
}
|
|
26842
|
+
else if (Array.isArray(obj)) {
|
|
26843
|
+
return obj.map(deserialize);
|
|
26844
|
+
}
|
|
26845
|
+
else if (obj !== null && typeof obj === "object") {
|
|
26846
|
+
const deserializedObj = {};
|
|
26847
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
26848
|
+
deserializedObj[key] = deserialize(value);
|
|
26849
|
+
}
|
|
26850
|
+
return deserializedObj;
|
|
26851
|
+
}
|
|
26852
|
+
return obj;
|
|
26853
|
+
}
|
|
26854
|
+
|
|
26855
|
+
function Debug() {
|
|
26856
|
+
const actions = Store.useActions();
|
|
26857
|
+
const state = Store.useState((state) => state);
|
|
26858
|
+
const argv = Store.useState((state) => state.argv);
|
|
26859
|
+
const debug = Store.useState((state) => state.select.debug(state));
|
|
26860
|
+
reactExports.useEffect(function debugMessageOnce() {
|
|
26861
|
+
if (debug) {
|
|
26862
|
+
actions.output(reactExports.createElement(Text, { color: colors.yellow }, "Debug mode enabled"));
|
|
26863
|
+
}
|
|
26864
|
+
}, [argv]);
|
|
26865
|
+
reactExports.useEffect(function syncStateJson() {
|
|
26866
|
+
if (!argv?.["write-state-json"]) {
|
|
26867
|
+
return;
|
|
26868
|
+
}
|
|
26869
|
+
const output_file = path.join(state.cwd, "git-stack-state.json");
|
|
26870
|
+
if (fs.existsSync(output_file)) {
|
|
26871
|
+
fs.rmSync(output_file);
|
|
26872
|
+
}
|
|
26873
|
+
const serialized = serialize(state);
|
|
26874
|
+
const content = JSON.stringify(serialized, null, 2);
|
|
26875
|
+
fs.writeFileSync(output_file, content);
|
|
26876
|
+
}, [argv, state]);
|
|
26877
|
+
return null;
|
|
26878
|
+
}
|
|
26879
|
+
|
|
26834
26880
|
function Url(props) {
|
|
26835
26881
|
return (reactExports.createElement(Text, { bold: true, color: colors.blue, ...props }, props.children));
|
|
26836
26882
|
}
|
|
@@ -26892,7 +26938,7 @@ function CheckGit(props) {
|
|
|
26892
26938
|
return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow },
|
|
26893
26939
|
"Checking ",
|
|
26894
26940
|
reactExports.createElement(Command, null, "git"),
|
|
26895
|
-
" install
|
|
26941
|
+
" install\u2026"), function: async () => {
|
|
26896
26942
|
// await Promise.all([
|
|
26897
26943
|
// cli(`for i in $(seq 1 5); do echo $i; sleep 1; done`),
|
|
26898
26944
|
// cli(`for i in $(seq 5 1); do printf "$i "; sleep 1; done; echo`),
|
|
@@ -26912,7 +26958,7 @@ function CheckGithubCli(props) {
|
|
|
26912
26958
|
reactExports.createElement(Text, null,
|
|
26913
26959
|
"Checking ",
|
|
26914
26960
|
reactExports.createElement(Command, null, "gh"),
|
|
26915
|
-
" install
|
|
26961
|
+
" install\u2026")), function: async () => {
|
|
26916
26962
|
if (is_command_available("gh")) {
|
|
26917
26963
|
return;
|
|
26918
26964
|
}
|
|
@@ -26932,7 +26978,7 @@ function CheckGithubCliAuth(props) {
|
|
|
26932
26978
|
reactExports.createElement(Text, null,
|
|
26933
26979
|
"Checking ",
|
|
26934
26980
|
reactExports.createElement(Command, null, "gh auth status"),
|
|
26935
|
-
"
|
|
26981
|
+
"\u2026")), function: async () => {
|
|
26936
26982
|
const options = { ignoreExitCode: true };
|
|
26937
26983
|
const auth_status$1 = await cli(`gh auth status`, options);
|
|
26938
26984
|
if (auth_status$1.code === 0) {
|
|
@@ -26965,7 +27011,7 @@ function CheckGitRevise(props) {
|
|
|
26965
27011
|
reactExports.createElement(Text, null,
|
|
26966
27012
|
"Checking ",
|
|
26967
27013
|
reactExports.createElement(Command, null, "git revise"),
|
|
26968
|
-
" install
|
|
27014
|
+
" install\u2026")), function: async () => {
|
|
26969
27015
|
if (is_command_available("git-revise")) {
|
|
26970
27016
|
return;
|
|
26971
27017
|
}
|
|
@@ -26982,8 +27028,53 @@ function CheckGitRevise(props) {
|
|
|
26982
27028
|
} }, props.children));
|
|
26983
27029
|
}
|
|
26984
27030
|
|
|
27031
|
+
function reducer$1(state, patch) {
|
|
27032
|
+
return { ...state, ...patch };
|
|
27033
|
+
}
|
|
27034
|
+
function DirtyCheck(props) {
|
|
27035
|
+
const actions = Store.useActions();
|
|
27036
|
+
const [state, patch] = reactExports.useReducer(reducer$1, {
|
|
27037
|
+
status: "init",
|
|
27038
|
+
});
|
|
27039
|
+
switch (state.status) {
|
|
27040
|
+
case "done":
|
|
27041
|
+
return props.children;
|
|
27042
|
+
case "prompt":
|
|
27043
|
+
return (reactExports.createElement(YesNoPrompt, { message: reactExports.createElement(FormatText, { wrapper: reactExports.createElement(Text, { color: colors.yellow }), message: "{git} repo is dirty, changed may be lost during {git_stack}, are you sure you wannt to proceed?", values: {
|
|
27044
|
+
git: reactExports.createElement(Command, null, "git"),
|
|
27045
|
+
git_stack: reactExports.createElement(Command, null, "git stack"),
|
|
27046
|
+
} }), onYes: async () => {
|
|
27047
|
+
patch({ status: "done" });
|
|
27048
|
+
}, onNo: async () => {
|
|
27049
|
+
actions.exit(0);
|
|
27050
|
+
} }));
|
|
27051
|
+
default:
|
|
27052
|
+
return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow },
|
|
27053
|
+
"Ensuring ",
|
|
27054
|
+
reactExports.createElement(Command, null, "git status --porcelain"),
|
|
27055
|
+
"\u2026"), function: rebase_check }));
|
|
27056
|
+
}
|
|
27057
|
+
async function rebase_check() {
|
|
27058
|
+
const actions = Store.getState().actions;
|
|
27059
|
+
try {
|
|
27060
|
+
const git_dirty = (await cli(`git status --porcelain`)).stdout;
|
|
27061
|
+
const status = git_dirty ? "prompt" : "done";
|
|
27062
|
+
patch({ status });
|
|
27063
|
+
}
|
|
27064
|
+
catch (err) {
|
|
27065
|
+
actions.error("Must be run from within a git repository.");
|
|
27066
|
+
if (err instanceof Error) {
|
|
27067
|
+
if (actions.isDebug()) {
|
|
27068
|
+
actions.error(err.message);
|
|
27069
|
+
}
|
|
27070
|
+
}
|
|
27071
|
+
actions.exit(9);
|
|
27072
|
+
}
|
|
27073
|
+
}
|
|
27074
|
+
}
|
|
27075
|
+
|
|
26985
27076
|
function GatherMetadata(props) {
|
|
26986
|
-
const fallback = (reactExports.createElement(Text, { color: colors.yellow }, "Gathering local git information
|
|
27077
|
+
const fallback = (reactExports.createElement(Text, { color: colors.yellow }, "Gathering local git information\u2026"));
|
|
26987
27078
|
return (reactExports.createElement(Await, { fallback: fallback, function: gather_metadata$1 }, props.children));
|
|
26988
27079
|
}
|
|
26989
27080
|
async function gather_metadata$1() {
|
|
@@ -27445,7 +27536,7 @@ const UNASSIGNED = "unassigned";
|
|
|
27445
27536
|
|
|
27446
27537
|
function LocalCommitStatus(props) {
|
|
27447
27538
|
const argv = Store.useState((state) => state.argv);
|
|
27448
|
-
const fallback = (reactExports.createElement(Text, { color: colors.yellow }, "Fetching PR status from Github
|
|
27539
|
+
const fallback = (reactExports.createElement(Text, { color: colors.yellow }, "Fetching PR status from Github\u2026"));
|
|
27449
27540
|
if (argv["mock-metadata"]) {
|
|
27450
27541
|
return (reactExports.createElement(Await, { fallback: fallback, function: mock_metadata }, props.children));
|
|
27451
27542
|
}
|
|
@@ -27539,7 +27630,7 @@ function encode(value) {
|
|
|
27539
27630
|
}
|
|
27540
27631
|
|
|
27541
27632
|
function LocalMergeRebase() {
|
|
27542
|
-
return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow }, "Rebasing commits
|
|
27633
|
+
return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow }, "Rebasing commits\u2026"), function: run$3 }));
|
|
27543
27634
|
}
|
|
27544
27635
|
async function run$3() {
|
|
27545
27636
|
const state = Store.getState();
|
|
@@ -27647,7 +27738,7 @@ async function run$3() {
|
|
|
27647
27738
|
actions.output(reactExports.createElement(Text, { color: colors.yellow },
|
|
27648
27739
|
"Restoring ",
|
|
27649
27740
|
reactExports.createElement(Brackets, null, branch_name),
|
|
27650
|
-
"
|
|
27741
|
+
"\u2026"));
|
|
27651
27742
|
restore_git();
|
|
27652
27743
|
actions.output(reactExports.createElement(Text, { color: colors.yellow },
|
|
27653
27744
|
"Restored ",
|
|
@@ -27810,7 +27901,7 @@ const RE = {
|
|
|
27810
27901
|
};
|
|
27811
27902
|
|
|
27812
27903
|
function ManualRebase() {
|
|
27813
|
-
return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow }, "Rebasing commits
|
|
27904
|
+
return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow }, "Rebasing commits\u2026"), function: run$2 }));
|
|
27814
27905
|
}
|
|
27815
27906
|
async function run$2() {
|
|
27816
27907
|
const state = Store.getState();
|
|
@@ -28129,7 +28220,7 @@ echo "$GIT_REVISE_TODO" > "$git_revise_todo_path"
|
|
|
28129
28220
|
actions.output(reactExports.createElement(Text, { color: colors.yellow },
|
|
28130
28221
|
"Restoring ",
|
|
28131
28222
|
reactExports.createElement(Brackets, null, branch_name),
|
|
28132
|
-
"
|
|
28223
|
+
"\u2026"));
|
|
28133
28224
|
restore_git();
|
|
28134
28225
|
actions.output(reactExports.createElement(Text, { color: colors.yellow },
|
|
28135
28226
|
"Restored ",
|
|
@@ -28883,22 +28974,27 @@ function RebaseCheck(props) {
|
|
|
28883
28974
|
case "done":
|
|
28884
28975
|
return props.children;
|
|
28885
28976
|
case "prompt":
|
|
28886
|
-
return (reactExports.createElement(YesNoPrompt, { message: reactExports.createElement(Text, { color: colors.yellow },
|
|
28977
|
+
return (reactExports.createElement(YesNoPrompt, { message: reactExports.createElement(Text, { color: colors.yellow },
|
|
28978
|
+
reactExports.createElement(Command, null, "git rebase"),
|
|
28979
|
+
" detected, would you like to abort it?"), onYes: async () => {
|
|
28887
28980
|
await cli(`git rebase --abort`);
|
|
28888
28981
|
patch({ status: "done" });
|
|
28889
28982
|
}, onNo: async () => {
|
|
28890
28983
|
actions.exit(0);
|
|
28891
28984
|
} }));
|
|
28892
28985
|
default:
|
|
28893
|
-
return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow },
|
|
28986
|
+
return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow },
|
|
28987
|
+
"Checking for ",
|
|
28988
|
+
reactExports.createElement(Command, null, "git rebase"),
|
|
28989
|
+
"\u2026"), function: rebase_check }));
|
|
28894
28990
|
}
|
|
28895
28991
|
async function rebase_check() {
|
|
28896
28992
|
const actions = Store.getState().actions;
|
|
28897
28993
|
try {
|
|
28898
|
-
const
|
|
28994
|
+
const git_dir = (await cli(`git rev-parse --absolute-git-dir`)).stdout;
|
|
28899
28995
|
let is_rebase = false;
|
|
28900
|
-
is_rebase ||= fs.existsSync(path.join(
|
|
28901
|
-
is_rebase ||= fs.existsSync(path.join(
|
|
28996
|
+
is_rebase ||= fs.existsSync(path.join(git_dir, "rebase-apply"));
|
|
28997
|
+
is_rebase ||= fs.existsSync(path.join(git_dir, "rebase-merge"));
|
|
28902
28998
|
const status = is_rebase ? "prompt" : "done";
|
|
28903
28999
|
patch({ status });
|
|
28904
29000
|
}
|
|
@@ -28937,12 +29033,14 @@ function App() {
|
|
|
28937
29033
|
actions.exit(0);
|
|
28938
29034
|
}
|
|
28939
29035
|
} },
|
|
28940
|
-
reactExports.createElement(
|
|
28941
|
-
reactExports.createElement(
|
|
28942
|
-
|
|
28943
|
-
|
|
28944
|
-
|
|
28945
|
-
reactExports.createElement(
|
|
29036
|
+
reactExports.createElement(DependencyCheck, null,
|
|
29037
|
+
reactExports.createElement(DirtyCheck, null,
|
|
29038
|
+
reactExports.createElement(RebaseCheck, null,
|
|
29039
|
+
reactExports.createElement(CherryPickCheck, null,
|
|
29040
|
+
!argv.verbose ? null : reactExports.createElement(GithubApiError, null),
|
|
29041
|
+
reactExports.createElement(GatherMetadata, null,
|
|
29042
|
+
reactExports.createElement(LocalCommitStatus, null,
|
|
29043
|
+
reactExports.createElement(Main, null))))))))));
|
|
28946
29044
|
}
|
|
28947
29045
|
|
|
28948
29046
|
const align = {
|
|
@@ -34320,7 +34418,7 @@ async function command() {
|
|
|
34320
34418
|
.wrap(123)
|
|
34321
34419
|
// disallow unknown options
|
|
34322
34420
|
.strict()
|
|
34323
|
-
.version("1.
|
|
34421
|
+
.version("1.4.0" )
|
|
34324
34422
|
.showHidden("show-hidden", "Show hidden options via `git stack help --show-hidden`")
|
|
34325
34423
|
.help("help", "Show usage via `git stack help`").argv);
|
|
34326
34424
|
}
|
package/package.json
CHANGED
package/src/app/App.tsx
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
3
|
import { AutoUpdate } from "~/app/AutoUpdate";
|
|
4
|
+
import { CherryPickCheck } from "~/app/CherryPickCheck";
|
|
4
5
|
import { Debug } from "~/app/Debug";
|
|
5
6
|
import { DependencyCheck } from "~/app/DependencyCheck";
|
|
7
|
+
import { DirtyCheck } from "~/app/DirtyCheck";
|
|
6
8
|
import { GatherMetadata } from "~/app/GatherMetadata";
|
|
7
9
|
import { GithubApiError } from "~/app/GithubApiError";
|
|
8
10
|
import { LocalCommitStatus } from "~/app/LocalCommitStatus";
|
|
@@ -48,17 +50,21 @@ export function App() {
|
|
|
48
50
|
}
|
|
49
51
|
}}
|
|
50
52
|
>
|
|
51
|
-
<
|
|
52
|
-
<
|
|
53
|
-
|
|
53
|
+
<DependencyCheck>
|
|
54
|
+
<DirtyCheck>
|
|
55
|
+
<RebaseCheck>
|
|
56
|
+
<CherryPickCheck>
|
|
57
|
+
{!argv.verbose ? null : <GithubApiError />}
|
|
54
58
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
<GatherMetadata>
|
|
60
|
+
<LocalCommitStatus>
|
|
61
|
+
<Main />
|
|
62
|
+
</LocalCommitStatus>
|
|
63
|
+
</GatherMetadata>
|
|
64
|
+
</CherryPickCheck>
|
|
65
|
+
</RebaseCheck>
|
|
66
|
+
</DirtyCheck>
|
|
67
|
+
</DependencyCheck>
|
|
62
68
|
</AutoUpdate>
|
|
63
69
|
</Providers>
|
|
64
70
|
);
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
|
|
6
|
+
import * as Ink from "ink-cjs";
|
|
7
|
+
|
|
8
|
+
import { Await } from "~/app/Await";
|
|
9
|
+
import { Command } from "~/app/Command";
|
|
10
|
+
import { Store } from "~/app/Store";
|
|
11
|
+
import { YesNoPrompt } from "~/app/YesNoPrompt";
|
|
12
|
+
import { cli } from "~/core/cli";
|
|
13
|
+
import { colors } from "~/core/colors";
|
|
14
|
+
|
|
15
|
+
type Props = {
|
|
16
|
+
children: React.ReactNode;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type State = {
|
|
20
|
+
status: "init" | "prompt" | "done";
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function reducer(state: State, patch: Partial<State>) {
|
|
24
|
+
return { ...state, ...patch };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function CherryPickCheck(props: Props) {
|
|
28
|
+
const actions = Store.useActions();
|
|
29
|
+
|
|
30
|
+
const [state, patch] = React.useReducer(reducer, {
|
|
31
|
+
status: "init",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
switch (state.status) {
|
|
35
|
+
case "done":
|
|
36
|
+
return props.children;
|
|
37
|
+
|
|
38
|
+
case "prompt":
|
|
39
|
+
return (
|
|
40
|
+
<YesNoPrompt
|
|
41
|
+
message={
|
|
42
|
+
<Ink.Text color={colors.yellow}>
|
|
43
|
+
<Command>git cherry-pick</Command> detected, would you like to
|
|
44
|
+
abort it?
|
|
45
|
+
</Ink.Text>
|
|
46
|
+
}
|
|
47
|
+
onYes={async () => {
|
|
48
|
+
await cli(`git cherry-pick --abort`);
|
|
49
|
+
patch({ status: "done" });
|
|
50
|
+
}}
|
|
51
|
+
onNo={async () => {
|
|
52
|
+
actions.exit(0);
|
|
53
|
+
}}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
default:
|
|
58
|
+
return (
|
|
59
|
+
<Await
|
|
60
|
+
fallback={
|
|
61
|
+
<Ink.Text color={colors.yellow}>
|
|
62
|
+
Checking for <Command>git cherry-pick</Command>…
|
|
63
|
+
</Ink.Text>
|
|
64
|
+
}
|
|
65
|
+
function={cherry_pick_check}
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function cherry_pick_check() {
|
|
71
|
+
const actions = Store.getState().actions;
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const git_dir = (await cli(`git rev-parse --absolute-git-dir`)).stdout;
|
|
75
|
+
|
|
76
|
+
const is_cherry_pick = fs.existsSync(
|
|
77
|
+
path.join(git_dir, "CHERRY_PICK_HEAD")
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const status = is_cherry_pick ? "prompt" : "done";
|
|
81
|
+
patch({ status });
|
|
82
|
+
} catch (err) {
|
|
83
|
+
actions.error("Must be run from within a git repository.");
|
|
84
|
+
|
|
85
|
+
if (err instanceof Error) {
|
|
86
|
+
if (actions.isDebug()) {
|
|
87
|
+
actions.error(err.message);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
actions.exit(9);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -39,7 +39,7 @@ function CheckGit(props: Props) {
|
|
|
39
39
|
<Await
|
|
40
40
|
fallback={
|
|
41
41
|
<Ink.Text color={colors.yellow}>
|
|
42
|
-
Checking <Command>git</Command> install
|
|
42
|
+
Checking <Command>git</Command> install…
|
|
43
43
|
</Ink.Text>
|
|
44
44
|
}
|
|
45
45
|
function={async () => {
|
|
@@ -74,7 +74,7 @@ function CheckGithubCli(props: Props) {
|
|
|
74
74
|
fallback={
|
|
75
75
|
<Ink.Text color={colors.yellow}>
|
|
76
76
|
<Ink.Text>
|
|
77
|
-
Checking <Command>gh</Command> install
|
|
77
|
+
Checking <Command>gh</Command> install…
|
|
78
78
|
</Ink.Text>
|
|
79
79
|
</Ink.Text>
|
|
80
80
|
}
|
|
@@ -117,7 +117,7 @@ function CheckGithubCliAuth(props: Props) {
|
|
|
117
117
|
fallback={
|
|
118
118
|
<Ink.Text color={colors.yellow}>
|
|
119
119
|
<Ink.Text>
|
|
120
|
-
Checking <Command>gh auth status</Command
|
|
120
|
+
Checking <Command>gh auth status</Command>…
|
|
121
121
|
</Ink.Text>
|
|
122
122
|
</Ink.Text>
|
|
123
123
|
}
|
|
@@ -175,7 +175,7 @@ function CheckGitRevise(props: Props) {
|
|
|
175
175
|
fallback={
|
|
176
176
|
<Ink.Text color={colors.yellow}>
|
|
177
177
|
<Ink.Text>
|
|
178
|
-
Checking <Command>git revise</Command> install
|
|
178
|
+
Checking <Command>git revise</Command> install…
|
|
179
179
|
</Ink.Text>
|
|
180
180
|
</Ink.Text>
|
|
181
181
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import * as Ink from "ink-cjs";
|
|
4
|
+
|
|
5
|
+
import { Await } from "~/app/Await";
|
|
6
|
+
import { Command } from "~/app/Command";
|
|
7
|
+
import { FormatText } from "~/app/FormatText";
|
|
8
|
+
import { Store } from "~/app/Store";
|
|
9
|
+
import { YesNoPrompt } from "~/app/YesNoPrompt";
|
|
10
|
+
import { cli } from "~/core/cli";
|
|
11
|
+
import { colors } from "~/core/colors";
|
|
12
|
+
|
|
13
|
+
type Props = {
|
|
14
|
+
children: React.ReactNode;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type State = {
|
|
18
|
+
status: "init" | "prompt" | "done";
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function reducer(state: State, patch: Partial<State>) {
|
|
22
|
+
return { ...state, ...patch };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function DirtyCheck(props: Props) {
|
|
26
|
+
const actions = Store.useActions();
|
|
27
|
+
|
|
28
|
+
const [state, patch] = React.useReducer(reducer, {
|
|
29
|
+
status: "init",
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
switch (state.status) {
|
|
33
|
+
case "done":
|
|
34
|
+
return props.children;
|
|
35
|
+
|
|
36
|
+
case "prompt":
|
|
37
|
+
return (
|
|
38
|
+
<YesNoPrompt
|
|
39
|
+
message={
|
|
40
|
+
<FormatText
|
|
41
|
+
wrapper={<Ink.Text color={colors.yellow} />}
|
|
42
|
+
message="{git} repo is dirty, changed may be lost during {git_stack}, are you sure you wannt to proceed?"
|
|
43
|
+
values={{
|
|
44
|
+
git: <Command>git</Command>,
|
|
45
|
+
git_stack: <Command>git stack</Command>,
|
|
46
|
+
}}
|
|
47
|
+
/>
|
|
48
|
+
}
|
|
49
|
+
onYes={async () => {
|
|
50
|
+
patch({ status: "done" });
|
|
51
|
+
}}
|
|
52
|
+
onNo={async () => {
|
|
53
|
+
actions.exit(0);
|
|
54
|
+
}}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
default:
|
|
59
|
+
return (
|
|
60
|
+
<Await
|
|
61
|
+
fallback={
|
|
62
|
+
<Ink.Text color={colors.yellow}>
|
|
63
|
+
Ensuring <Command>git status --porcelain</Command>…
|
|
64
|
+
</Ink.Text>
|
|
65
|
+
}
|
|
66
|
+
function={rebase_check}
|
|
67
|
+
/>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function rebase_check() {
|
|
72
|
+
const actions = Store.getState().actions;
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const git_dirty = (await cli(`git status --porcelain`)).stdout;
|
|
76
|
+
|
|
77
|
+
const status = git_dirty ? "prompt" : "done";
|
|
78
|
+
patch({ status });
|
|
79
|
+
} catch (err) {
|
|
80
|
+
actions.error("Must be run from within a git repository.");
|
|
81
|
+
|
|
82
|
+
if (err instanceof Error) {
|
|
83
|
+
if (actions.isDebug()) {
|
|
84
|
+
actions.error(err.message);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
actions.exit(9);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -16,9 +16,7 @@ type Props = {
|
|
|
16
16
|
|
|
17
17
|
export function GatherMetadata(props: Props) {
|
|
18
18
|
const fallback = (
|
|
19
|
-
<Ink.Text color={colors.yellow}>
|
|
20
|
-
Gathering local git information...
|
|
21
|
-
</Ink.Text>
|
|
19
|
+
<Ink.Text color={colors.yellow}>Gathering local git information…</Ink.Text>
|
|
22
20
|
);
|
|
23
21
|
|
|
24
22
|
return (
|
|
@@ -16,7 +16,7 @@ export function LocalCommitStatus(props: Props) {
|
|
|
16
16
|
const argv = Store.useState((state) => state.argv);
|
|
17
17
|
|
|
18
18
|
const fallback = (
|
|
19
|
-
<Ink.Text color={colors.yellow}>Fetching PR status from Github
|
|
19
|
+
<Ink.Text color={colors.yellow}>Fetching PR status from Github…</Ink.Text>
|
|
20
20
|
);
|
|
21
21
|
|
|
22
22
|
if (argv["mock-metadata"]) {
|
|
@@ -18,7 +18,7 @@ import { short_id } from "~/core/short_id";
|
|
|
18
18
|
export function LocalMergeRebase() {
|
|
19
19
|
return (
|
|
20
20
|
<Await
|
|
21
|
-
fallback={<Ink.Text color={colors.yellow}>Rebasing commits
|
|
21
|
+
fallback={<Ink.Text color={colors.yellow}>Rebasing commits…</Ink.Text>}
|
|
22
22
|
function={run}
|
|
23
23
|
/>
|
|
24
24
|
);
|
|
@@ -174,7 +174,7 @@ async function run() {
|
|
|
174
174
|
function handle_exit() {
|
|
175
175
|
actions.output(
|
|
176
176
|
<Ink.Text color={colors.yellow}>
|
|
177
|
-
Restoring <Brackets>{branch_name}</Brackets
|
|
177
|
+
Restoring <Brackets>{branch_name}</Brackets>…
|
|
178
178
|
</Ink.Text>
|
|
179
179
|
);
|
|
180
180
|
|
package/src/app/ManualRebase.tsx
CHANGED
|
@@ -23,7 +23,7 @@ import { short_id } from "~/core/short_id";
|
|
|
23
23
|
export function ManualRebase() {
|
|
24
24
|
return (
|
|
25
25
|
<Await
|
|
26
|
-
fallback={<Ink.Text color={colors.yellow}>Rebasing commits
|
|
26
|
+
fallback={<Ink.Text color={colors.yellow}>Rebasing commits…</Ink.Text>}
|
|
27
27
|
function={run}
|
|
28
28
|
/>
|
|
29
29
|
);
|
|
@@ -423,7 +423,7 @@ async function run() {
|
|
|
423
423
|
function handle_exit() {
|
|
424
424
|
actions.output(
|
|
425
425
|
<Ink.Text color={colors.yellow}>
|
|
426
|
-
Restoring <Brackets>{branch_name}</Brackets
|
|
426
|
+
Restoring <Brackets>{branch_name}</Brackets>…
|
|
427
427
|
</Ink.Text>
|
|
428
428
|
);
|
|
429
429
|
|
package/src/app/RebaseCheck.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import path from "node:path";
|
|
|
6
6
|
import * as Ink from "ink-cjs";
|
|
7
7
|
|
|
8
8
|
import { Await } from "~/app/Await";
|
|
9
|
+
import { Command } from "~/app/Command";
|
|
9
10
|
import { Store } from "~/app/Store";
|
|
10
11
|
import { YesNoPrompt } from "~/app/YesNoPrompt";
|
|
11
12
|
import { cli } from "~/core/cli";
|
|
@@ -39,7 +40,8 @@ export function RebaseCheck(props: Props) {
|
|
|
39
40
|
<YesNoPrompt
|
|
40
41
|
message={
|
|
41
42
|
<Ink.Text color={colors.yellow}>
|
|
42
|
-
|
|
43
|
+
<Command>git rebase</Command> detected, would you like to abort
|
|
44
|
+
it?
|
|
43
45
|
</Ink.Text>
|
|
44
46
|
}
|
|
45
47
|
onYes={async () => {
|
|
@@ -56,7 +58,9 @@ export function RebaseCheck(props: Props) {
|
|
|
56
58
|
return (
|
|
57
59
|
<Await
|
|
58
60
|
fallback={
|
|
59
|
-
<Ink.Text color={colors.yellow}>
|
|
61
|
+
<Ink.Text color={colors.yellow}>
|
|
62
|
+
Checking for <Command>git rebase</Command>…
|
|
63
|
+
</Ink.Text>
|
|
60
64
|
}
|
|
61
65
|
function={rebase_check}
|
|
62
66
|
/>
|
|
@@ -67,11 +71,11 @@ export function RebaseCheck(props: Props) {
|
|
|
67
71
|
const actions = Store.getState().actions;
|
|
68
72
|
|
|
69
73
|
try {
|
|
70
|
-
const
|
|
74
|
+
const git_dir = (await cli(`git rev-parse --absolute-git-dir`)).stdout;
|
|
71
75
|
|
|
72
76
|
let is_rebase = false;
|
|
73
|
-
is_rebase ||= fs.existsSync(path.join(
|
|
74
|
-
is_rebase ||= fs.existsSync(path.join(
|
|
77
|
+
is_rebase ||= fs.existsSync(path.join(git_dir, "rebase-apply"));
|
|
78
|
+
is_rebase ||= fs.existsSync(path.join(git_dir, "rebase-merge"));
|
|
75
79
|
|
|
76
80
|
const status = is_rebase ? "prompt" : "done";
|
|
77
81
|
patch({ status });
|