From 174ca586af797a402fa76d4cb5e113db9de813cc Mon Sep 17 00:00:00 2001 From: Kipras Melnikovas Date: Sun, 10 Apr 2022 03:14:01 +0300 Subject: [PATCH 1/9] setup first test case experiment.spec.ts Signed-off-by: Kipras Melnikovas --- package.json | 1 + parse-todo-of-stacked-rebase/validator.ts | 10 +- test/.gitignore | 2 + test/experiment.spec.ts | 248 ++++++++++++++++++++++ test/run.ts | 13 ++ 5 files changed, 269 insertions(+), 5 deletions(-) create mode 100644 test/.gitignore create mode 100755 test/experiment.spec.ts create mode 100644 test/run.ts diff --git a/package.json b/package.json index 9d1a5dcd..d25ab2d3 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ }, "scripts": { "prebuild": "node ./script/prebuild.js", + "test": "ts-node-dev ./test/run.ts", "build": "yarn tsc -b", "postbuild": "node ./script/postbuild.js", "prepack": "yarn build" diff --git a/parse-todo-of-stacked-rebase/validator.ts b/parse-todo-of-stacked-rebase/validator.ts index 3a542211..26b903f4 100644 --- a/parse-todo-of-stacked-rebase/validator.ts +++ b/parse-todo-of-stacked-rebase/validator.ts @@ -143,7 +143,7 @@ export const regularRebaseCommands = { // m: standardCommand, } as const; -type RegularRebaseCommand = keyof typeof regularRebaseCommands; +export type RegularRebaseCommand = keyof typeof regularRebaseCommands; /** * TODO: assert each value is `RegularRebaseCommand`, @@ -219,7 +219,7 @@ export const stackedRebaseCommands = { }), } as const; -type StackedRebaseCommand = keyof typeof stackedRebaseCommands; +export type StackedRebaseCommand = keyof typeof stackedRebaseCommands; // const allowedCommandAliasesFromGitStackedRebase: { [key: string]: AllowedGitStackedRebaseCommand } = { const stackedRebaseCommandAliases = { @@ -229,10 +229,10 @@ const stackedRebaseCommandAliases = { type StackedRebaseCommandAlias = keyof typeof stackedRebaseCommandAliases; -type EitherRebaseCommand = RegularRebaseCommand | StackedRebaseCommand; -type EitherRebaseCommandAlias = RegularRebaseCommandAlias | StackedRebaseCommandAlias; +export type EitherRebaseCommand = RegularRebaseCommand | StackedRebaseCommand; +export type EitherRebaseCommandAlias = RegularRebaseCommandAlias | StackedRebaseCommandAlias; -type EitherRebaseEitherCommandOrAlias = EitherRebaseCommand | EitherRebaseCommandAlias; +export type EitherRebaseEitherCommandOrAlias = EitherRebaseCommand | EitherRebaseCommandAlias; type MapOfAllowedRebaseCommands = { [key in EitherRebaseCommand]: Command; diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 00000000..5deb4c5a --- /dev/null +++ b/test/.gitignore @@ -0,0 +1,2 @@ +folders-to-delete +.tmp diff --git a/test/experiment.spec.ts b/test/experiment.spec.ts new file mode 100755 index 00000000..81406ecb --- /dev/null +++ b/test/experiment.spec.ts @@ -0,0 +1,248 @@ +#!/usr/bin/env ts-node-dev + +import fs from "fs"; +import path from "path"; +import assert from "assert"; + +import Git from "nodegit"; + +import { gitStackedRebase, defaultGitCmd } from "../git-stacked-rebase"; + +import { RegularRebaseCommand } from "../parse-todo-of-stacked-rebase/validator"; +import { createExecSyncInRepo } from "../util/execSyncInRepo"; +import { configKeys } from "../configKeys"; + +export async function testCase() { + const { + repo, // + config, + sig, + dir, + } = await setupRepo(); + + const commitOidsInInitial: Git.Oid[] = []; + const initialBranch: Git.Reference = await appendCommitsTo(commitOidsInInitial, 3, repo, sig); + + const latestStackedBranch: Git.Reference = await Git.Branch.create( + repo, + "stack-latest", + await repo.getHeadCommit(), + 0 + ); + await repo.checkoutBranch(latestStackedBranch); + + const execSyncInRepo = createExecSyncInRepo(repo); + + // const read = () => execSyncInRepo("read"); + const read = () => void 0; + + read(); + + const commitOidsInLatestStacked: Git.Oid[] = []; + await appendCommitsTo(commitOidsInLatestStacked, 12, repo, sig); + + const newPartialBranches = [ + ["partial-1", 4], + ["partial-2", 6], + ["partial-3", 8], + ] as const; + + console.log("launching 1st rebase to create partial branches"); + await gitStackedRebase(initialBranch.shorthand(), { + gitDir: dir, + getGitConfig: () => config, + editor: async ({ filePath }) => { + console.log("filePath %s", filePath); + + for (const [newPartial, nthCommit] of newPartialBranches) { + await humanOpAppendLineAfterNthCommit( + filePath, + commitOidsInLatestStacked[nthCommit].tostrS(), + `branch-end-new ${newPartial}` + ); + } + + console.log("finished editor"); + + read(); + }, + }); + + console.log("looking up branches to make sure they were created successfully"); + read(); + for (const [newPartial] of newPartialBranches) { + /** + * will throw if branch does not exist + * TODO "properly" expect to not throw + */ + await Git.Branch.lookup(repo, newPartial, Git.Branch.BRANCH.LOCAL); + } + + /** + * + */ + console.log("launching 2nd rebase to change command of nth commit"); + read(); + + const nthCommit2ndRebase = 5; + + await gitStackedRebase(initialBranch.shorthand(), { + gitDir: dir, + getGitConfig: () => config, + editor: async ({ filePath }) => { + const SHA = commitOidsInLatestStacked[nthCommit2ndRebase].tostrS(); + + humanOpChangeCommandOfNthCommitInto("edit", SHA, filePath); + }, + }); + /** + * rebase will now exit because of the "edit" command, + * and so will our stacked rebase, + * allowing us to edit. + */ + + fs.writeFileSync(nthCommit2ndRebase.toString(), "new data from 2nd rebase\n"); + + execSyncInRepo(`${defaultGitCmd} add .`); + execSyncInRepo(`${defaultGitCmd} -c commit.gpgSign=false commit --amend --no-edit`); + + execSyncInRepo(`${defaultGitCmd} rebase --continue`); + + execSyncInRepo(`${defaultGitCmd} status`); + read(); + + /** + * now some partial branches will be "gone" from the POV of the latestBranch<->initialBranch. + * + * TODO verify they are gone (history got modified successfully) + */ + + // TODO + + /** + * TODO continue with --apply + * TODO and then verify that partial branches are "back" in our POV properly. + */ + + console.log("attempting early 3rd rebase to --apply"); + read(); + + await gitStackedRebase(initialBranch.shorthand(), { + gitDir: dir, + getGitConfig: () => config, + apply: true, + }); +} + +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export async function setupRepo() { + const dir: string = path.join(__dirname, ".tmp"); + if (fs.existsSync(dir)) { + fs.rmdirSync(dir, { recursive: true }); + } + fs.mkdirSync(dir); + console.log("tmpdir path %s", dir); + + const foldersToDeletePath: string = path.join(__dirname, "folders-to-delete"); + fs.appendFileSync(foldersToDeletePath, dir + "\n", { encoding: "utf-8" }); + + process.chdir(dir); + console.log("chdir to tmpdir"); + + const isBare = 0; + const repo: Git.Repository = await Git.Repository.init(dir, isBare); + + const config: Git.Config = await repo.config(); + + await config.setBool(configKeys.autoApplyIfNeeded, Git.Config.MAP.FALSE); + await config.setString("user.email", "tester@test.com"); + await config.setString("user.name", "tester"); + + /** + * fixups / not implemented in libgit2. + * though, would be better if received empty/minimal config by default.. + */ + await config.setString("merge.conflictStyle", "diff3"); // zdiff3 + + const sig: Git.Signature = await Git.Signature.default(repo); + console.log("sig %s", sig); + + const inicialCommitId = "Initial commit (from setupRepo)"; + const initialCommit: Git.Oid = await fs.promises + .writeFile(inicialCommitId, inicialCommitId) // + .then(() => repo.createCommitOnHead([inicialCommitId], sig, sig, inicialCommitId)); + + return { + dir, + repo, + config, + sig, + initialCommit, + } as const; +} + +async function appendCommitsTo( + alreadyExistingCommits: Git.Oid[], + n: number, + repo: Git.Repository, // + sig: Git.Signature +): Promise { + assert(n > 0, "cannot append <= 0 commits"); + + const commits: string[] = new Array(n) + .fill(0) // + .map((_, i) => "a".charCodeAt(0) + i + alreadyExistingCommits.length) + .map((ascii) => String.fromCharCode(ascii)); + + for (const c of commits) { + const branchName: string = repo.isEmpty() ? "" : (await repo.getCurrentBranch()).shorthand(); + const cInBranch: string = c + " in " + branchName; + + const oid: Git.Oid = await fs.promises + .writeFile(c, cInBranch) // + .then(() => repo.createCommitOnHead([c], sig, sig, cInBranch)); + + alreadyExistingCommits.push(oid); + + console.log(`oid of commit "%s" in branch "%s": %s`, c, branchName, oid); + } + + return repo.getCurrentBranch(); +} + +/** + * TODO general "HumanOp" for `appendLineAfterNthCommit` & similar utils + */ +async function humanOpAppendLineAfterNthCommit( + filePath: string, // + commitSHA: string, + newLine: string +): Promise { + const file = await fs.promises.readFile(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); + + await fs.promises.writeFile(filePath, lines.join("\n")); +} + +function humanOpChangeCommandOfNthCommitInto( + newCommand: RegularRebaseCommand, // + commitSHA: string, + filePath: string +): 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")); +} diff --git a/test/run.ts b/test/run.ts new file mode 100644 index 00000000..7ffd3882 --- /dev/null +++ b/test/run.ts @@ -0,0 +1,13 @@ +#!/usr/bin/env ts-node-dev + +import { testCase } from "./experiment.spec"; + +main(); +function main() { + testCase() + .then(() => process.stdout.write("\nsuccess\n\n")) + .catch((e) => { + process.stderr.write("\nfailure: " + e + "\n\n"); + process.exit(1); + }); +} From 3b7ccfd18d3d87116135081634b09690a7b08af1 Mon Sep 17 00:00:00 2001 From: Kipras Melnikovas Date: Sun, 10 Apr 2022 02:59:51 +0300 Subject: [PATCH 2/9] setup .vscode/launch.json for debugging tests Signed-off-by: Kipras Melnikovas --- .vscode/launch.json | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..196629e7 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,27 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "ts-node tests", + "type": "node", + "request": "launch", + "args": [ + // "${relativeFile}" // + "test/run.ts" + ], + "runtimeArgs": [ + "-r", // + "ts-node/register" + ], + "cwd": "${workspaceRoot}", + "protocol": "inspector", + "internalConsoleOptions": "openOnSessionStart", + "env": { + "DEBUG": "gsr:*" + } + } + ] +} From bc9e0d13005a57c4b95b6303bec283bd029aa14a Mon Sep 17 00:00:00 2001 From: Kipras Melnikovas Date: Sun, 23 Jan 2022 04:24:25 +0200 Subject: [PATCH 3/9] feat(ci): add the simplest test.yml workflow for CI Signed-off-by: Kipras Melnikovas --- .github/workflows/test.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..aff5d996 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,16 @@ +name: "tests" + +on: [push, workflow_dispatch] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: "12" + - run: yarn --frozen-lockfile + - run: yarn test + \ No newline at end of file From 76f22d114e5597461c807ff10e20f27e01569d85 Mon Sep 17 00:00:00 2001 From: Kipras Melnikovas Date: Sat, 9 Apr 2022 15:57:23 +0300 Subject: [PATCH 4/9] ci: run with multiple node versions Signed-off-by: Kipras Melnikovas --- .github/workflows/test.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index aff5d996..a38e06ab 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,12 +5,15 @@ on: [push, workflow_dispatch] jobs: test: runs-on: ubuntu-latest + strategy: + matrix: + node: [12, 14, 16] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: "12" + node-version: ${{ matrix.node }} - run: yarn --frozen-lockfile - run: yarn test \ No newline at end of file From 72064daf941cbf6b471ef66035d613bb5c7a2baf Mon Sep 17 00:00:00 2001 From: Kipras Melnikovas Date: Sat, 9 Apr 2022 17:25:07 +0300 Subject: [PATCH 5/9] ci: do not `fail-fast`; use node v10, v18 & v16 as experimental (won't fail workflow) Signed-off-by: Kipras Melnikovas --- .github/workflows/test.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a38e06ab..7f72975e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,9 +5,22 @@ on: [push, workflow_dispatch] jobs: test: runs-on: ubuntu-latest + + # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#example-preventing-a-specific-failing-matrix-job-from-failing-a-workflow-run + continue-on-error: ${{ matrix.experimental }} strategy: + fail-fast: false matrix: - node: [12, 14, 16] + node: [12, 14] + experimental: [false] + include: + - node: 10 + experimental: true + # v16 should work fine; there're some issues in CI with `krb5-config` + - node: 16 + experimental: true + - node: 18 + experimental: true steps: - uses: actions/checkout@v2 From f5704e1de118bf8775aaadf8af5895118ca828c4 Mon Sep 17 00:00:00 2001 From: Kipras Melnikovas Date: Sat, 9 Apr 2022 17:40:32 +0300 Subject: [PATCH 6/9] ci: add matrix.os Signed-off-by: Kipras Melnikovas --- .github/workflows/test.yml | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7f72975e..56e8c434 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,22 +4,39 @@ on: [push, workflow_dispatch] jobs: test: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#example-preventing-a-specific-failing-matrix-job-from-failing-a-workflow-run continue-on-error: ${{ matrix.experimental }} strategy: fail-fast: false matrix: + os: [ubuntu-latest, macos-latest] node: [12, 14] experimental: [false] include: - - node: 10 + - os: ubuntu-latest + node: 10 experimental: true - # v16 should work fine; there're some issues in CI with `krb5-config` - - node: 16 + - os: ubuntu-latest + # v16 should work fine; there're some issues in CI with `krb5-config` + node: 16 experimental: true - - node: 18 + - os: ubuntu-latest + node: 18 + experimental: true + + # test windows, w/ wanted versions + - os: windows-latest + node: 12 + experimental: true + - os: windows-latest + node: 14 + experimental: true + + # test macos - for some reason, internet conn fails @ github actions + - os: macos-latest + node: 12 experimental: true steps: From 0208f88f8deab67e4ad07f74d6bcd201f965b5d5 Mon Sep 17 00:00:00 2001 From: Kipras Melnikovas Date: Sat, 9 Apr 2022 17:57:42 +0300 Subject: [PATCH 7/9] ci: reduce amount of configurations - gotta preserve the runner a bit lol Signed-off-by: Kipras Melnikovas --- .github/workflows/test.yml | 41 ++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 56e8c434..ec32d2d3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,31 +14,34 @@ jobs: os: [ubuntu-latest, macos-latest] node: [12, 14] experimental: [false] - include: - - os: ubuntu-latest - node: 10 - experimental: true - - os: ubuntu-latest - # v16 should work fine; there're some issues in CI with `krb5-config` - node: 16 - experimental: true - - os: ubuntu-latest - node: 18 - experimental: true - - # test windows, w/ wanted versions - - os: windows-latest + exclude: + - os: macos-latest node: 12 - experimental: true - - os: windows-latest - node: 14 - experimental: true - + include: # test macos - for some reason, internet conn fails @ github actions - os: macos-latest node: 12 experimental: true + # - os: ubuntu-latest + # node: 10 + # experimental: true + # - os: ubuntu-latest + # # v16 should work fine; there're some issues in CI with `krb5-config` + # node: 16 + # experimental: true + # - os: ubuntu-latest + # node: 18 + # experimental: true + + # # test windows, w/ wanted versions + # - os: windows-latest + # node: 12 + # experimental: true + # - os: windows-latest + # node: 14 + # experimental: true + steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 From fcee2112993bd6474a2b17e8578bc8272f9f66db Mon Sep 17 00:00:00 2001 From: Kipras Melnikovas Date: Sat, 9 Apr 2022 18:10:36 +0300 Subject: [PATCH 8/9] ci: upgrade setup-node to v3 to more easily setup caching Signed-off-by: Kipras Melnikovas --- .github/workflows/test.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ec32d2d3..de8958ed 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,9 +44,11 @@ jobs: steps: - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} + cache: 'yarn' + cache-dependency-path: '**/yarn.lock' - run: yarn --frozen-lockfile - run: yarn test \ No newline at end of file From e509a55b919a6342a863e6b311b719df238c12c3 Mon Sep 17 00:00:00 2001 From: Kipras Melnikovas Date: Sat, 2 Apr 2022 16:24:26 +0300 Subject: [PATCH 9/9] chore: run "test" script in "build" script Signed-off-by: Kipras Melnikovas --- package.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index d25ab2d3..06c6e78a 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,11 @@ "git-stacked-rebase": "./dist/git-stacked-rebase.js" }, "scripts": { - "prebuild": "node ./script/prebuild.js", + "prebuild:lean": "node ./script/prebuild.js", "test": "ts-node-dev ./test/run.ts", - "build": "yarn tsc -b", - "postbuild": "node ./script/postbuild.js", + "build": "yarn test && yarn build:lean", + "build:lean": "yarn tsc -b", + "postbuild:lean": "node ./script/postbuild.js", "prepack": "yarn build" }, "devDependencies": {