Skip to content

Commit 5006863

Browse files
committed
feat: define branch boundary parser behaviors, use more adaptive one in "--sequencer --exec"
Signed-off-by: Kipras Melnikovas <kipras@kipras.org>
1 parent 7ede561 commit 5006863

File tree

4 files changed

+133
-30
lines changed

4 files changed

+133
-30
lines changed

apply.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
branchSequencer,
1414
ActionInsideEachCheckedOutBranch,
1515
BranchSequencerArgsBase,
16+
BehaviorOfGetBranchBoundaries,
1617
} from "./branchSequencer";
1718
import { combineRewrittenLists } from "./reducePath";
1819

@@ -22,6 +23,7 @@ export const apply: BranchSequencerBase = (args) =>
2223
actionInsideEachCheckedOutBranch: defaultApplyAction,
2324
// callbackAfterDone: defaultApplyCallback,
2425
delayMsBetweenCheckouts: 0,
26+
behaviorOfGetBranchBoundaries: BehaviorOfGetBranchBoundaries["parse-from-not-yet-applied-state"],
2527
}).then(
2628
(ret) => (markThatApplied(args.pathToStackedRebaseDirInsideDotGit), ret) //
2729
);

branchSequencer.ts

Lines changed: 118 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,21 @@ import assert from "assert";
33

44
import Git from "nodegit";
55

6+
import { getWantedCommitsWithBranchBoundariesOurCustomImpl } from "./git-stacked-rebase";
7+
68
import { createExecSyncInRepo } from "./util/execSyncInRepo";
79
import { Termination } from "./util/error";
10+
import { assertNever } from "./util/assertNever";
811

912
import { parseNewGoodCommands } from "./parse-todo-of-stacked-rebase/parseNewGoodCommands";
1013
import { GoodCommand, GoodCommandStacked } from "./parse-todo-of-stacked-rebase/validator";
1114

12-
export type GetBranchesCtx = {
15+
export type BranchRefs = {
16+
initialBranch: Git.Reference;
17+
currentBranch: Git.Reference;
18+
};
19+
20+
export type GetBranchesCtx = BranchRefs & {
1321
pathToStackedRebaseDirInsideDotGit: string;
1422
rootLevelCommandName: string;
1523
repo: Git.Repository;
@@ -24,7 +32,13 @@ export type GetBoundariesInclInitial = (
2432
ctx: GetBranchesCtx //
2533
) => SimpleBranchAndCommit[] | Promise<SimpleBranchAndCommit[]>;
2634

27-
const defautlGetBoundariesInclInitial: GetBoundariesInclInitial = ({
35+
export const isStackedRebaseInProgress = ({
36+
pathToStackedRebaseDirInsideDotGit,
37+
}: {
38+
pathToStackedRebaseDirInsideDotGit: string;
39+
}): boolean => fs.existsSync(pathToStackedRebaseDirInsideDotGit);
40+
41+
const getBoundariesInclInitialByParsingNotYetAppliedState: GetBoundariesInclInitial = ({
2842
pathToStackedRebaseDirInsideDotGit, //
2943
rootLevelCommandName,
3044
repo,
@@ -33,7 +47,7 @@ const defautlGetBoundariesInclInitial: GetBoundariesInclInitial = ({
3347
/**
3448
* TODO REMOVE / modify this logic (see next comment)
3549
*/
36-
if (!fs.existsSync(pathToStackedRebaseDirInsideDotGit)) {
50+
if (!isStackedRebaseInProgress({ pathToStackedRebaseDirInsideDotGit })) {
3751
throw new Termination(`\n\nno stacked-rebase in progress? (nothing to ${rootLevelCommandName})\n\n`);
3852
}
3953
// const hasPostRewriteHookInstalledWithLatestVersion = false;
@@ -98,6 +112,94 @@ const defautlGetBoundariesInclInitial: GetBoundariesInclInitial = ({
98112
);
99113
};
100114

115+
const getBoundariesInclInitialWithSipleBranchTraversal: GetBoundariesInclInitial = (argsBase) =>
116+
getWantedCommitsWithBranchBoundariesOurCustomImpl(
117+
argsBase.repo, //
118+
argsBase.initialBranch,
119+
argsBase.currentBranch
120+
).then((boundaries) =>
121+
boundaries
122+
.filter((b) => !!b.branchEnd)
123+
.map(
124+
(boundary): SimpleBranchAndCommit => ({
125+
branchEndFullName: boundary.branchEnd!.name(), // TS ok because of the filter
126+
commitSHA: boundary.commit.sha(),
127+
})
128+
)
129+
);
130+
131+
/**
132+
* not sure if i'm a fan of this indirection tbh..
133+
*/
134+
export enum BehaviorOfGetBranchBoundaries {
135+
/**
136+
* the default one.
137+
*/
138+
"parse-from-not-yet-applied-state",
139+
/**
140+
* originally used by `--push` - since it wouldn't be allowed to run
141+
* before `--apply` was used,
142+
* having to sync from applied state was more confusion & limiting.
143+
*
144+
* further, we later got rid of the state after `--apply`ing,
145+
* so this became the only option anyway.
146+
*/
147+
"ignore-unapplied-state-and-use-simple-branch-traversal",
148+
/**
149+
* this is the adaptive of the other 2.
150+
* originally intended for `branchSequencerExec` (`--exec`) -
151+
* we don't know what's coming from the user,
152+
* so we cannot make any assumptions.
153+
*
154+
* instead, we simply check if a stacked rebase (our) is in progress,
155+
* if so - we use the 1st option (because we have to),
156+
* otherwise - the 2nd option (because we have to, too!).
157+
*/
158+
"if-stacked-rebase-in-progress-then-parse-not-applied-state-otherwise-simple-branch-traverse",
159+
}
160+
export const defaultGetBranchBoundariesBehavior = BehaviorOfGetBranchBoundaries["parse-from-not-yet-applied-state"];
161+
162+
const pickBoundaryParser = ({
163+
behaviorOfGetBranchBoundaries,
164+
pathToStackedRebaseDirInsideDotGit,
165+
}: {
166+
/**
167+
* can provide one of the predefined behaviors,
168+
* whom will decide which parser to pick,
169+
*
170+
* or can provide a custom parser function.
171+
*/
172+
behaviorOfGetBranchBoundaries: BehaviorOfGetBranchBoundaries | GetBoundariesInclInitial;
173+
pathToStackedRebaseDirInsideDotGit: string;
174+
}): GetBoundariesInclInitial => {
175+
if (typeof behaviorOfGetBranchBoundaries === "function") {
176+
/**
177+
* custom fn
178+
*/
179+
return behaviorOfGetBranchBoundaries;
180+
} else if (behaviorOfGetBranchBoundaries === BehaviorOfGetBranchBoundaries["parse-from-not-yet-applied-state"]) {
181+
return getBoundariesInclInitialByParsingNotYetAppliedState;
182+
} else if (
183+
behaviorOfGetBranchBoundaries ===
184+
BehaviorOfGetBranchBoundaries["ignore-unapplied-state-and-use-simple-branch-traversal"]
185+
) {
186+
return getBoundariesInclInitialWithSipleBranchTraversal;
187+
} else if (
188+
behaviorOfGetBranchBoundaries ===
189+
BehaviorOfGetBranchBoundaries[
190+
"if-stacked-rebase-in-progress-then-parse-not-applied-state-otherwise-simple-branch-traverse"
191+
]
192+
) {
193+
if (isStackedRebaseInProgress({ pathToStackedRebaseDirInsideDotGit })) {
194+
return getBoundariesInclInitialByParsingNotYetAppliedState;
195+
} else {
196+
return getBoundariesInclInitialWithSipleBranchTraversal;
197+
}
198+
} else {
199+
assertNever(behaviorOfGetBranchBoundaries);
200+
}
201+
};
202+
101203
/**
102204
*
103205
*/
@@ -111,25 +213,20 @@ export type ActionInsideEachCheckedOutBranchCtx = {
111213
};
112214
export type ActionInsideEachCheckedOutBranch = (ctx: ActionInsideEachCheckedOutBranchCtx) => void | Promise<void>;
113215

114-
export type BranchSequencerArgsBase = {
216+
export type BranchSequencerArgsBase = BranchRefs & {
115217
pathToStackedRebaseDirInsideDotGit: string; //
116218
// goodCommands: GoodCommand[];
117219
pathToStackedRebaseTodoFile: string;
118220
repo: Git.Repository;
119221
rootLevelCommandName: string;
120222
gitCmd: string;
121-
//
122-
initialBranch: Git.Reference;
123-
currentBranch: Git.Reference;
124223
};
224+
125225
export type BranchSequencerArgs = BranchSequencerArgsBase & {
126226
// callbackBeforeBegin?: CallbackAfterDone; // TODO
127227
actionInsideEachCheckedOutBranch: ActionInsideEachCheckedOutBranch;
128228
delayMsBetweenCheckouts?: number;
129-
/**
130-
*
131-
*/
132-
getBoundariesInclInitial?: GetBoundariesInclInitial;
229+
behaviorOfGetBranchBoundaries?: Parameters<typeof pickBoundaryParser>[0]["behaviorOfGetBranchBoundaries"];
133230
};
134231

135232
export type BranchSequencerBase = (args: BranchSequencerArgsBase) => Promise<void>;
@@ -145,15 +242,24 @@ export const branchSequencer: BranchSequencer = async ({
145242
actionInsideEachCheckedOutBranch,
146243
gitCmd,
147244
//
148-
getBoundariesInclInitial = defautlGetBoundariesInclInitial,
245+
behaviorOfGetBranchBoundaries = defaultGetBranchBoundariesBehavior,
246+
initialBranch,
247+
currentBranch,
149248
}) => {
150249
const execSyncInRepo = createExecSyncInRepo(repo);
151250

251+
const getBoundariesInclInitial: GetBoundariesInclInitial = pickBoundaryParser({
252+
behaviorOfGetBranchBoundaries,
253+
pathToStackedRebaseDirInsideDotGit,
254+
});
255+
152256
const branchesAndCommits: SimpleBranchAndCommit[] = await getBoundariesInclInitial({
153257
pathToStackedRebaseDirInsideDotGit,
154258
pathToStackedRebaseTodoFile,
155259
repo,
156260
rootLevelCommandName,
261+
initialBranch,
262+
currentBranch,
157263
});
158264

159265
return checkout(branchesAndCommits.slice(1) as any); // TODO TS

forcePush.ts

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44

55
import Git from "nodegit";
66

7-
import { getWantedCommitsWithBranchBoundariesOurCustomImpl } from "./git-stacked-rebase";
87
import {
8+
BehaviorOfGetBranchBoundaries,
99
branchSequencer, //
1010
BranchSequencerBase,
11-
SimpleBranchAndCommit,
1211
// getBackupPathOfPreviousStackedRebase,
1312
} from "./branchSequencer";
1413

@@ -115,19 +114,11 @@ export const forcePush: BranchSequencerBase = (argsBase) =>
115114
}
116115
},
117116
delayMsBetweenCheckouts: 0,
118-
getBoundariesInclInitial: () =>
119-
getWantedCommitsWithBranchBoundariesOurCustomImpl(
120-
argsBase.repo, //
121-
argsBase.initialBranch,
122-
argsBase.currentBranch
123-
).then((boundaries) =>
124-
boundaries
125-
.filter((b) => !!b.branchEnd)
126-
.map(
127-
(boundary): SimpleBranchAndCommit => ({
128-
branchEndFullName: boundary.branchEnd!.name(), // TS ok because of the filter
129-
commitSHA: boundary.commit.sha(),
130-
})
131-
)
132-
),
117+
118+
/**
119+
* `--push` should not be allowed if `--apply` has not ran yet,
120+
* thus this is the desired behavior.
121+
*/
122+
behaviorOfGetBranchBoundaries:
123+
BehaviorOfGetBranchBoundaries["ignore-unapplied-state-and-use-simple-branch-traversal"],
133124
});

git-stacked-rebase.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { filenames } from "./filenames";
1313
import { configKeys } from "./configKeys";
1414
import { apply, applyIfNeedsToApply, markThatNeedsToApply as _markThatNeedsToApply } from "./apply";
1515
import { forcePush } from "./forcePush";
16-
import { branchSequencer } from "./branchSequencer";
16+
import { BehaviorOfGetBranchBoundaries, branchSequencer } from "./branchSequencer";
1717

1818
import { createExecSyncInRepo } from "./util/execSyncInRepo";
1919
import { noop } from "./util/noop";
@@ -403,6 +403,10 @@ export const gitStackedRebase = async (
403403
pathToStackedRebaseTodoFile,
404404
initialBranch,
405405
currentBranch,
406+
behaviorOfGetBranchBoundaries:
407+
BehaviorOfGetBranchBoundaries[
408+
"if-stacked-rebase-in-progress-then-parse-not-applied-state-otherwise-simple-branch-traverse"
409+
],
406410
});
407411
} else {
408412
/**

0 commit comments

Comments
 (0)