diff --git a/.gitignore b/.gitignore index 1744973..f4b45a0 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,8 @@ yarn-error.log* .vscode +packages/automatic-versioning/tmp + p*/**/dist/ p*/**/.npmignore diff --git a/packages/automatic-versioning/package.json b/packages/automatic-versioning/package.json index b34fafd..afdbe2c 100644 --- a/packages/automatic-versioning/package.json +++ b/packages/automatic-versioning/package.json @@ -1,6 +1,6 @@ { "name": "@sliit-foss/automatic-versioning", - "version": "2.0.0-blizzard.0", + "version": "2.0.0", "description": "A script which will automatically increment your app package version in accordance with conventional commits", "main": "dist/index.js", "bin": "dist/index.js", @@ -10,7 +10,7 @@ "bump-version": "bash ../../scripts/bump-version.sh", "lint": "bash ../../scripts/lint.sh", "release": "bash ../../scripts/release.sh", - "test": "dotenv -- jest --coverage --verbose --runInBand --forceExit" + "test": "bash ../../scripts/test/test.sh" }, "dependencies": { "@actions/exec": "1.1.1", diff --git a/packages/automatic-versioning/src/index.js b/packages/automatic-versioning/src/index.js index 607988b..19e56e2 100644 --- a/packages/automatic-versioning/src/index.js +++ b/packages/automatic-versioning/src/index.js @@ -24,7 +24,7 @@ program [ new Option("--recursive", "recursively search for a matching commit prefix"), - new Option("--prerelease-tag ", "prerelease tag to use when running on a prerelease branch"), + new Option("--prerelease-tag ", "prerelease identifier to use when creating a prerelease"), new Option("--prerelease-branch ", "run prereleases on this branch"), new Option( "--ignore-prefixes ", @@ -46,15 +46,23 @@ if (opts.root !== defaultRootDir) { process.chdir(parentDir); } -if (opts.tagBased) { - tagBasedRunner(opts.name, opts.skipCommit); -} else { - defaultRunner( - opts.name, - opts.skipCommit, - opts.recursive, - opts.prereleaseTag, - opts.prereleaseBranch, - opts.ignorePrefixes - ); +const run = async () => { + if (opts.tagBased) { + await tagBasedRunner(opts.name, opts.skipCommit); + } else { + await defaultRunner( + opts.name, + opts.skipCommit, + opts.recursive, + opts.prereleaseTag, + opts.prereleaseBranch, + opts.ignorePrefixes + ); + } +}; + +if (!process.env.AUTOMATIC_VERSIONING_IS_TEST) { + run(); } + +export default run; diff --git a/packages/automatic-versioning/src/types/default.js b/packages/automatic-versioning/src/types/default.js index 4724081..c1eabce 100644 --- a/packages/automatic-versioning/src/types/default.js +++ b/packages/automatic-versioning/src/types/default.js @@ -20,7 +20,7 @@ const getCommitPrefix = async (recursive, ignorePrefixes, n = 1) => { }; const runner = (name, noCommit, recursive = false, prereleaseTag, prereleaseBranch, ignorePrefixes) => { - run("git show --first-parent ./").then(async (diff) => { + return run("git show --first-parent ./").then(async (diff) => { if (diff) { console.info(`Diff found, running versioning for ${name}`.green); const { commitMessage, commitPrefix, noBump } = await getCommitPrefix(recursive, ignorePrefixes); @@ -73,30 +73,28 @@ const runner = (name, noCommit, recursive = false, prereleaseTag, prereleaseBran versionUpdate = prerelease ? "prerelease" : `pre${versionUpdate}`; } } - run( + await run( `npm --workspaces-update=false --no-git-tag-version version ${versionUpdate} ${ prereleaseTag ? `--preid=${prereleaseTag}` : "" }` - ).then(() => { + ).then(async () => { if (!noCommit) { const successMsg = `"CI: ${name} - ${ versionUpdate === "prerelease" ? versionUpdate : `${versionUpdate} release` }"`; - run("git add .").then(() => { - run(`git commit -m ${successMsg} --no-verify`).then(() => { - console.info(successMsg.green); - }); + await run("git add .").then(async () => { + await run(`git commit -m ${successMsg} --no-verify`).then(() => console.info(successMsg.green)); }); } }); } else { - console.info(`No bump found in commit message, skipping version bump and editing commit message`.yellow); - run(`git commit --amend -m "${commitMessage.replace(/--no-bump/g, "")}"`).then(() => { - console.info("Successfully edited commit message".green); - }); + console.info(`No bump found in commit message, skipping versioning and editing commit message`.yellow); + await run(`git commit --amend -m "${commitMessage.replace(/--no-bump/g, "")}"`).then(() => + console.info("Successfully edited commit message".green) + ); } } else { - console.info(`No diff found, skipping version bump for ${name}`.yellow); + console.info(`No diff found, skipping versioning for ${name}`.yellow); } }); }; diff --git a/packages/automatic-versioning/src/types/tag-based.js b/packages/automatic-versioning/src/types/tag-based.js index 3b792ad..8ba5d48 100644 --- a/packages/automatic-versioning/src/types/tag-based.js +++ b/packages/automatic-versioning/src/types/tag-based.js @@ -3,29 +3,27 @@ import run from "../utils/runner"; const runner = (name, noCommit) => { - run(`npm pkg get version`).then((initialVersion) => { + return run(`npm pkg get version`).then(async (initialVersion) => { initialVersion = initialVersion.replace(/\n/g, "")?.replace(/"/g, "")?.trim(); - run("git tag --sort=committerdate").then((tags) => { + await run("git tag --sort=committerdate").then(async (tags) => { let latest = tags.split("\n")?.reverse()[1]?.trim()?.replace("v", "")?.replace(/_/g, "-"); if (latest && /[0-9]{1,4}.[0-9]{1,2}.[0-9]{1,2}.rc/.test(latest)) { latest = latest?.split("."); latest = `${parseInt(latest[0])}.${parseInt(latest[1])}.${parseInt(latest[2])}-${latest[3]}`; } if (latest && latest !== initialVersion) { - run(`npm version ${latest} --no-git-tag-version --workspaces-update=false`) - .then(() => { + await run(`npm version ${latest} --no-git-tag-version --workspaces-update=false`) + .then(async () => { if (!noCommit) { - const successMsg = `"CI: Bumped version of ${name} from ${initialVersion} to ${latest}"`; - run("git add .").then(() => { - run(`git commit -m ${successMsg}`).then(() => { - console.info(successMsg.green); - }); + const successMsg = `"CI: bumped version of ${name} from ${initialVersion} to ${latest}"`; + await run("git add .").then(async () => { + await run(`git commit -m ${successMsg}`).then(() => console.info(successMsg.green)); }); } }) - .catch(() => {}); + .catch(); } else { - console.info(`No tag diff found, skipping version bump for ${name}`.yellow); + console.info(`No tag diff found, skipping versioning for ${name}`.yellow); } }); }); diff --git a/packages/automatic-versioning/test/index.test.js b/packages/automatic-versioning/test/index.test.js index e1c19f2..a4b0fdb 100644 --- a/packages/automatic-versioning/test/index.test.js +++ b/packages/automatic-versioning/test/index.test.js @@ -1,5 +1,152 @@ -describe("automatic-versioning", () => { - it("should work", () => { - expect(true).toBe(true); +import * as fs from "fs"; +import run from "../src/utils/runner"; +import { + commit, + getLastCommitMessage, + getPackageVersion, + executeVersionScript, + setPackageVersion, + getCurrentBranch +} from "./util"; + +import "./setup"; + +describe("default", () => { + it("bump patch version", async () => { + await commit("Fix: test commit"); + await executeVersionScript(); + expect(getPackageVersion()).toBe("0.0.1"); + expect(await getLastCommitMessage()).toBe("CI: @sliit-foss/automatic-versioning - patch release"); + }); + it("bump minor version", async () => { + await commit("Feat: test commit"); + await executeVersionScript(); + expect(getPackageVersion()).toBe("0.1.0"); + expect(await getLastCommitMessage()).toBe("CI: @sliit-foss/automatic-versioning - minor release"); + }); + it("bump major version", async () => { + await commit("Feat!: test commit"); + await executeVersionScript(); + expect(getPackageVersion()).toBe("1.0.0"); + expect(await getLastCommitMessage()).toBe("CI: @sliit-foss/automatic-versioning - major release"); + }); + it("bump patch version (with scope)", async () => { + await commit("Fix(automatic-versioning): test commit"); + await executeVersionScript(); + expect(getPackageVersion()).toBe("0.0.1"); + expect(await getLastCommitMessage()).toBe("CI: @sliit-foss/automatic-versioning - patch release"); + }); + it("should not bump any version", async () => { + await commit("Chore: something which doesn't affect the version"); + await executeVersionScript(); + expect(getPackageVersion()).toBe("0.0.0"); + }); + it("no diff", async () => { + await commit("Feat!: test commit"); + await commit("Patch: empty commit", true); + await executeVersionScript(); + expect(getPackageVersion()).toBe("0.0.0"); + }); + it("recursive", async () => { + await commit("Feat!: test commit"); + fs.writeFileSync("./test.txt", "something which doesn't affect the version"); + await commit("Merge branch 'main' of https://github.com/sliit-foss/npm-catalogue"); + await executeVersionScript("--recursive"); + expect(getPackageVersion()).toBe("1.0.0"); + }); + it("ignore prefixes", async () => { + await commit("Feat: test commit"); + fs.writeFileSync("./test.txt", "some automated commit"); + await commit("CI: automated commit"); + await executeVersionScript("--ignore-prefixes=ci --recursive"); + expect(getPackageVersion()).toBe("0.1.0"); + }); + it("no bump in commit", async () => { + await commit("Fix: test commit --no-bump"); + await executeVersionScript(); + expect(getPackageVersion()).toBe("0.0.0"); + expect(await getLastCommitMessage()).toBe("Fix: test commit"); + }); + it("no commit", async () => { + const commitMsg = "Fix: testing versioning without commit"; + await commit(commitMsg); + await executeVersionScript("--skip-commit"); + expect(getPackageVersion()).toBe("0.0.1"); + expect(await getLastCommitMessage()).toBe(commitMsg); + }); + describe("prerelease", () => { + it("direct prefix", async () => { + await commit("Prerelease: test commit"); + await executeVersionScript(); + expect(getPackageVersion()).toBe("0.0.1-0"); + }); + it("with custom tag", async () => { + await commit("Prerelease: test commit"); + await executeVersionScript("--prerelease-tag=blizzard"); + expect(getPackageVersion()).toBe("0.0.1-blizzard.0"); + }); + describe("with prerelease branch", () => { + const executePreleaseVersionScript = async () => + executeVersionScript(`--prerelease-branch=${await getCurrentBranch()} --prerelease-tag=blizzard`); + it("single prerelease", async () => { + await commit("Feat: test commit"); + await executePreleaseVersionScript(); + expect(getPackageVersion()).toBe("0.1.0-blizzard.0"); + }); + it("multiple prereleases", async () => { + await commit("Feat: test commit"); + await executePreleaseVersionScript(); + fs.writeFileSync("./test.txt", "some fix"); + await commit("Feat: test commit"); + await executePreleaseVersionScript(); + expect(getPackageVersion()).toBe("0.2.0-blizzard.0"); + }); + it("multiple prereleases with patch", async () => { + await commit("Feat: test commit"); + await executePreleaseVersionScript(); + fs.writeFileSync("./test.txt", "some fix"); + await commit("Fix: test commit"); + await executePreleaseVersionScript(); + expect(getPackageVersion()).toBe("0.1.1-blizzard.0"); + }); + it("promote prerelease", async () => { + await commit("Feat: test commit"); + setPackageVersion("0.1.0-blizzard.5"); + await executeVersionScript("--prerelease-tag=blizzard"); + expect(getPackageVersion()).toBe("0.1.0"); + }); + }); + }); +}); + +describe("tag-based", () => { + it("default", async () => { + await commit("Fix: test tag"); + await run("git tag v0.0.2-alpha.0"); + await executeVersionScript("--tag-based"); + expect(getPackageVersion()).toBe("0.0.2-alpha.0"); + expect(await getLastCommitMessage()).toBe( + "CI: bumped version of @sliit-foss/automatic-versioning from 0.0.0 to 0.0.2-alpha.0" + ); + }); + it("no commit", async () => { + const commitMsg = "Fix: test tag without commit"; + await commit(commitMsg); + await run("git tag v1.2.3-beta.1"); + await executeVersionScript("--tag-based --skip-commit"); + expect(getPackageVersion()).toBe("1.2.3-beta.1"); + expect(await getLastCommitMessage()).toBe(commitMsg); + }); + it("rc tag", async () => { + await commit("Fix: test tag rc"); + await run("git tag v2022.07.18.rc6"); + await executeVersionScript("--tag-based"); + expect(getPackageVersion()).toBe("2022.7.18-rc6"); + }); + it("no tag diff", async () => { + setPackageVersion("2023.7.18-rc6"); + await run("git tag v2023.07.18.rc6"); + await executeVersionScript("--tag-based"); + expect(getPackageVersion()).toBe("2023.7.18-rc6"); }); }); diff --git a/packages/automatic-versioning/test/setup.js b/packages/automatic-versioning/test/setup.js new file mode 100644 index 0000000..0718ec8 --- /dev/null +++ b/packages/automatic-versioning/test/setup.js @@ -0,0 +1,34 @@ +import * as fs from "fs"; +import * as crypto from "crypto"; +import run from "../src/utils/runner"; +import { resetPackageJson } from "./util"; + +jest.setTimeout(60000); + +const initialDir = process.cwd(); + +beforeAll(async () => { + if (fs.existsSync("./tmp")) fs.rmdirSync("./tmp", { recursive: true }); + fs.mkdirSync("./tmp"); + process.chdir("./tmp"); + await run("git init"); + await run("git config user.email 'infosliitfoss@gmail.com'"); + await run("git config user.name 'SLIIT FOSS'"); + resetPackageJson(); + process.env.AUTOMATIC_VERSIONING_IS_TEST = "true"; +}); + +afterAll(() => { + process.chdir(initialDir); + fs.rmdirSync("./tmp", { recursive: true }); +}); + +beforeEach(() => { + jest.resetModules(); + fs.writeFileSync("./test.txt", crypto.randomBytes(16).toString("hex")); +}); + +afterEach(async () => { + await run("git reset --hard"); + resetPackageJson(); +}); diff --git a/packages/automatic-versioning/test/util.js b/packages/automatic-versioning/test/util.js new file mode 100644 index 0000000..53a9b8e --- /dev/null +++ b/packages/automatic-versioning/test/util.js @@ -0,0 +1,28 @@ +import * as fs from "fs"; +import run from "../src/utils/runner"; + +export const commit = async (message, empty) => { + await run(`git add .`); + await run(`git commit -m "${message}" ${empty ? "--allow-empty" : ""}`); +}; + +export const getLastCommitMessage = async () => (await run("git log -1 --pretty=%B"))?.trim(); + +export const getCurrentBranch = async () => (await run("git rev-parse --abbrev-ref HEAD"))?.trim(); + +export const getPackageVersion = () => JSON.parse(fs.readFileSync("./package.json").toString()).version; + +export const setPackageVersion = (version) => { + const packageJson = JSON.parse(fs.readFileSync("./package.json").toString()); + packageJson.version = version; + fs.writeFileSync("./package.json", JSON.stringify(packageJson, null, 2)); +}; + +export const resetPackageJson = () => { + fs.writeFileSync("./package.json", JSON.stringify({ name: "test", version: "0.0.0" }, null, 2)); +}; + +export const executeVersionScript = async (args) => { + process.argv = ["", "", ...(args?.split(" ") ?? [])]; + await require("../src/index").default(); +}; diff --git a/turbo.json b/turbo.json index fb4df80..eeafd06 100644 --- a/turbo.json +++ b/turbo.json @@ -21,5 +21,5 @@ "outputs": ["coverage/**"] } }, - "globalEnv": ["DISABLE_FUNCTION_TRACING", "npm_package_version"] + "globalEnv": ["DISABLE_FUNCTION_TRACING", "AUTOMATIC_VERSIONING_IS_TEST", "npm_package_version"] }