Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,31 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "node dist/git-stacked-rebase.js origin/master",
"program": "${workspaceFolder}/dist/git-stacked-rebase.js",
"request": "launch",
"args": [
"origin/master" //
],
"skipFiles": [
"<node_internals>/**" //
],
"type": "node"
},
{
"name": "node dist/git-stacked-rebase.js origin/master --apply",
"program": "${workspaceFolder}/dist/git-stacked-rebase.js",
"request": "launch",
"args": [
"origin/master", //
"--apply"
],
"skipFiles": [
"<node_internals>/**" //
],
"type": "node"
},
{
"name": "ts-node tests",
"type": "node",
Expand Down
2 changes: 1 addition & 1 deletion git-stacked-rebase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export type OptionsForGitStackedRebase = {
/**
* editor name, or a function that opens the file inside some editor.
*/
editor: string | ((ctx: { filePath: string }) => Promise<void>);
editor: string | ((ctx: { filePath: string }) => void | Promise<void>);

/**
* for executing raw git commands
Expand Down
47 changes: 47 additions & 0 deletions humanOp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* initially extracted as test utils,
* but i feel like these could be used to automate things
* thru the CLI that would need to be done inside the
* interactive mode.
*/

import fs from "fs";

import { RegularRebaseCommand } from "./parse-todo-of-stacked-rebase/validator";

type CommonArgs = {
filePath: string; //
commitSHA: string;
};

/**
* TODO general "HumanOp" for `appendLineAfterNthCommit` & similar utils
*/
export function humanOpAppendLineAfterNthCommit(newLine: string, { filePath, commitSHA }: CommonArgs): void {
const file = fs.readFileSync(filePath, { encoding: "utf-8" });
const lines = file.split("\n");
const lineIdx: number = lines.findIndex((line) => line.startsWith(`pick ${commitSHA}`));

console.log("commitSHA: %s, lineIdx: %s, newLine: %s", commitSHA, lineIdx, newLine);

lines.splice(lineIdx, 0, newLine);

fs.writeFileSync(filePath, lines.join("\n"));
}

export function humanOpChangeCommandOfNthCommitInto(
newCommand: RegularRebaseCommand,
{ commitSHA, filePath }: CommonArgs
): void {
const file = fs.readFileSync(filePath, { encoding: "utf-8" });
const lines = file.split("\n");
const lineIdx: number = lines.findIndex((line) => line.startsWith(`pick ${commitSHA}`));

console.log("commitSHA: %s, lineIdx: %s, newCommand: %s", commitSHA, lineIdx, newCommand);

const parts = lines[lineIdx].split(" ");
parts[0] = newCommand;
lines[lineIdx] = parts.join(" ");

fs.writeFileSync(filePath, lines.join("\n"));
}
36 changes: 36 additions & 0 deletions parse-todo-of-stacked-rebase/parseNewGoodCommands.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* eslint-disable @typescript-eslint/camelcase */

import { gitStackedRebase } from "../git-stacked-rebase";
import { humanOpAppendLineAfterNthCommit } from "../humanOp";

import { setupRepoWithStackedBranches } from "../test/setupRepo";

export async function parseNewGoodCommandsSpec() {
await succeeds_to_apply_after_break_or_exec();

async function succeeds_to_apply_after_break_or_exec() {
const { initialBranch, commitOidsInLatestStacked, dir, config } = await setupRepoWithStackedBranches();

const branch = initialBranch.shorthand();
const common = {
gitDir: dir,
getGitConfig: () => config,
} as const;

await gitStackedRebase(branch, {
...common,
editor: ({ filePath }) => {
const commitSHA: string = commitOidsInLatestStacked[7].tostrS();
humanOpAppendLineAfterNthCommit("break", {
filePath,
commitSHA,
});
},
});

await gitStackedRebase(branch, {
...common,
apply: true,
});
}
}
18 changes: 16 additions & 2 deletions parse-todo-of-stacked-rebase/parseNewGoodCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import { filenames } from "../filenames";
import { readRewrittenListNotAppliedOrAppliedOrError } from "../apply";

import { parseTodoOfStackedRebase } from "./parseTodoOfStackedRebase";
import { GoodCommand, stackedRebaseCommands } from "./validator";
import {
GoodCommand, //
namesOfRebaseCommandsThatWillDisappearFromCommandList,
stackedRebaseCommands,
} from "./validator";

export function parseNewGoodCommands(
repo: Git.Repository,
Expand Down Expand Up @@ -95,6 +99,13 @@ export function parseNewGoodCommands(

const oldCommandAtIdx: GoodCommand = oldGoodCommands[goodCommandMinIndex];

if (namesOfRebaseCommandsThatWillDisappearFromCommandList.includes(oldCommandAtIdx.commandName)) {
goodCommandMinIndex++; // the command should disappear,
i--; // but the commit should not be lost.

continue;
}

if (oldCommandAtIdx.commandName in stackedRebaseCommands) {
goodNewCommands.push({
...oldCommandAtIdx,
Expand Down Expand Up @@ -184,7 +195,10 @@ export function parseNewGoodCommands(
["stackedRebaseCommandsNew.length"]: stackedRebaseCommandsNew.length,
});

assert(stackedRebaseCommandsOld.length === stackedRebaseCommandsNew.length);
const oldCommandCount: number = stackedRebaseCommandsOld.length;
const newCommandCount: number = stackedRebaseCommandsNew.length;

assert.equal(oldCommandCount, newCommandCount);

return stackedRebaseCommandsNew;
}
Expand Down
56 changes: 49 additions & 7 deletions parse-todo-of-stacked-rebase/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ type Command = {
parseTargets: ParseTargets;

makesGitRebaseExitToPause: boolean;
willDisappearFromCommandsListInNextGitRebaseTodoFile: boolean;
};

const createCommand = (
nameButNeverAlias: string,
{
makesGitRebaseExitToPause,
willDisappearFromCommandsListInNextGitRebaseTodoFile,
parseTargets = ({ split }) => {
assert(
split.length >= 2,
Expand All @@ -57,6 +59,11 @@ const createCommand = (
*/
makesGitRebaseExitToPause: boolean;

/**
* TODO RENAME
*/
willDisappearFromCommandsListInNextGitRebaseTodoFile: boolean;

// nameOrAlias: EitherRebaseEitherCommandOrAlias, //
parseTargets?: Command["parseTargets"];
maxUseCount?: number;
Expand All @@ -68,23 +75,33 @@ const createCommand = (
nameButNeverAlias: nameButNeverAlias as EitherRebaseCommand, // TODO: TS
parseTargets,
makesGitRebaseExitToPause,
willDisappearFromCommandsListInNextGitRebaseTodoFile,
});

export const regularRebaseCommands = {
pick: createCommand("pick", { makesGitRebaseExitToPause: false }),
pick: createCommand("pick", {
makesGitRebaseExitToPause: false,
willDisappearFromCommandsListInNextGitRebaseTodoFile: false, //
}),
// p: standardCommand,
reword: createCommand("reword", {
makesGitRebaseExitToPause: false /** opens editor & then continues, w/o exiting in between */,
willDisappearFromCommandsListInNextGitRebaseTodoFile: false,
}),
// r: standardCommand,
edit: createCommand("edit", { makesGitRebaseExitToPause: true }),
edit: createCommand("edit", {
makesGitRebaseExitToPause: true,
willDisappearFromCommandsListInNextGitRebaseTodoFile: false, //
}),
// e: standardCommand,
squash: createCommand("squash", {
makesGitRebaseExitToPause: false /** opens editor & then continues, w/o exiting in between */,
willDisappearFromCommandsListInNextGitRebaseTodoFile: false,
}),
// s: standardCommand,
fixup: createCommand("fixup", {
makesGitRebaseExitToPause: false /** opens editor & then continues, w/o exiting in between */,
willDisappearFromCommandsListInNextGitRebaseTodoFile: false,

parseTargets: ({ split }) => {
/**
Expand All @@ -102,20 +119,35 @@ export const regularRebaseCommands = {
// f: standardCommand,
exec: createCommand("exec", {
makesGitRebaseExitToPause: false, //
willDisappearFromCommandsListInNextGitRebaseTodoFile: true,

parseTargets: ({ rest }) => [rest],
}),
// x: standardCommand,
break: createCommand("break", { makesGitRebaseExitToPause: true, parseTargets: () => null }),
break: createCommand("break", {
makesGitRebaseExitToPause: true,
willDisappearFromCommandsListInNextGitRebaseTodoFile: true, //
parseTargets: () => null,
}),
// b: standardCommand,
drop: createCommand("drop", { makesGitRebaseExitToPause: false }),
drop: createCommand("drop", {
makesGitRebaseExitToPause: false,
willDisappearFromCommandsListInNextGitRebaseTodoFile: false, // TODO
}),
// d: standardCommand,
label: createCommand("label", { makesGitRebaseExitToPause: false /** TODO VERIFY */ }),
label: createCommand("label", {
makesGitRebaseExitToPause: false /** TODO VERIFY */,
willDisappearFromCommandsListInNextGitRebaseTodoFile: false, // TODO VERIFY
}),
// l: standardCommand,
reset: createCommand("reset", { makesGitRebaseExitToPause: false /** TODO VERIFY */ }),
reset: createCommand("reset", {
makesGitRebaseExitToPause: false /** TODO VERIFY */,
willDisappearFromCommandsListInNextGitRebaseTodoFile: false, // TODO VERIFY
}),
// t: standardCommand,
merge: createCommand("merge", {
makesGitRebaseExitToPause: false /** TODO VERIFY */,
willDisappearFromCommandsListInNextGitRebaseTodoFile: false, // TODO VERIFY

parseTargets: ({ split }) => {
if (["-C", "-c"].includes(split[1])) {
Expand Down Expand Up @@ -192,27 +224,31 @@ const branchValidator: Validator = ({ rest, reasonsIfBad: reasonsWhyInvalid }) =
export const stackedRebaseCommands = {
"branch-end": createCommand("branch-end", {
makesGitRebaseExitToPause: false,
willDisappearFromCommandsListInNextGitRebaseTodoFile: false,

maxUseCount: Infinity,
isRestValid: branchValidator,
parseTargets: ({ rest }) => [rest],
}),
"branch-end-new": createCommand("branch-end-new", {
makesGitRebaseExitToPause: false,
willDisappearFromCommandsListInNextGitRebaseTodoFile: false,

maxUseCount: Infinity,
isRestValid: branchValidator,
parseTargets: ({ rest }) => [rest],
}),
"branch-end-initial": createCommand("branch-end-initial", {
makesGitRebaseExitToPause: false,
willDisappearFromCommandsListInNextGitRebaseTodoFile: false,

maxUseCount: 1,
isRestValid: branchValidator,
parseTargets: ({ rest }) => [rest],
}),
"branch-end-last": createCommand("branch-end-last", {
makesGitRebaseExitToPause: false,
willDisappearFromCommandsListInNextGitRebaseTodoFile: false,

maxUseCount: 1,
isRestValid: branchValidator,
Expand Down Expand Up @@ -260,11 +296,17 @@ const allEitherRebaseCommandAliases = {
export const rebaseCommandsThatMakeRebaseExitToPause: Command[] = Object.values(allEitherRebaseCommands).filter(
(cmd) => cmd.makesGitRebaseExitToPause
);

export const namesOfRebaseCommandsThatMakeRebaseExitToPause: EitherRebaseCommand[] = rebaseCommandsThatMakeRebaseExitToPause.map(
(cmd) => cmd.nameButNeverAlias
);

export const rebaseCommandsThatWillDisappearFromCommandList: Command[] = Object.values(allEitherRebaseCommands).filter(
(cmd) => cmd.willDisappearFromCommandsListInNextGitRebaseTodoFile
);
export const namesOfRebaseCommandsThatWillDisappearFromCommandList: EitherRebaseCommand[] = rebaseCommandsThatWillDisappearFromCommandList.map(
(cmd) => cmd.nameButNeverAlias
);

type LineNr = {
/**
* indexed from 0.
Expand Down
1 change: 1 addition & 0 deletions test/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
folders-to-delete
.tmp
.tmp-*
Loading