diff --git a/package.json b/package.json index 1a46015..0bf0df3 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ }, "devDependencies": { "prettier": "^2.8.8", + "typescript": "^5.0.4", "vitest": "^0.31.0" } } diff --git a/src/changelord.js b/src/changelord.js index 7d23d56..a45c4ab 100755 --- a/src/changelord.js +++ b/src/changelord.js @@ -7,6 +7,7 @@ import yaml from "yaml"; import fs from "fs-extra"; import consola from "consola"; import u from "@yanick/updeep-remeda"; +import { once } from "remeda"; import print from "./command/print.js"; import init from "./command/init.js"; @@ -20,48 +21,53 @@ import git_gather from "./command/git-gather.js"; consola.raw = (...args) => console.log(...args); yargs(hideBin(process.argv)) - .middleware((config) => { - config.consola = consola; - config.changelog = () => - fs.readFile(config.source, "utf-8").then(yaml.parse); - config.next_release = next_release.bind(config); - config.latest_version = latest_version.bind(config); - return config; - }) - .middleware((argv) => { - argv.add_to_next = async (entry) => { - const changelog = yaml.parse(await fs.readFile(argv.source, "utf-8")); + .middleware((config) => { + config.consola = consola; + config.changelog = once(() => + fs.readFile(config.source, "utf-8").then(yaml.parse) + ); + config.save_changelog = async (changelog) => { + if (!changelog) changelog = await config.changelog(); + return fs.writeFile(config.source, yaml.stringify(changelog)); + }; + config.next_release = next_release.bind(config); + config.latest_version = latest_version.bind(config); + return config; + }) + .middleware((argv) => { + argv.add_to_next = async (entry) => { + const changelog = yaml.parse(await fs.readFile(argv.source, "utf-8")); - let next = changelog.releases.find(u.matches({ version: "NEXT" })); - if (!next) { - next = { version: "NEXT", changes: [] }; - changelog.releases.unshift(next); - } + let next = changelog.releases.find(u.matches({ version: "NEXT" })); + if (!next) { + next = { version: "NEXT", changes: [] }; + changelog.releases.unshift(next); + } - if (Object.keys(entry).length === 1) { - entry = entry.desc; - } + if (Object.keys(entry).length === 1) { + entry = entry.desc; + } - next.changes.push(entry); + next.changes.push(entry); - return fs.writeFile(argv.source, yaml.stringify(changelog)); - }; - }) - .default("source", join(process.cwd(), "CHANGELOG.yml")) - .describe("source", "changelog source") - .command(init) - .command(add) - .command(print) - .command(cut) - .command(schema) - .command(upcoming) - .command({ - ...upcoming, - command: "next", - desc: 'alias for "upcoming"', - }) - .command(latest) - .command(git_gather) - .strictCommands() - .help() - .parse(); + return fs.writeFile(argv.source, yaml.stringify(changelog)); + }; + }) + .default("source", join(process.cwd(), "CHANGELOG.yml")) + .describe("source", "changelog source") + .command(init) + .command(add) + .command(print) + .command(cut) + .command(schema) + .command(upcoming) + .command({ + ...upcoming, + command: "next", + desc: 'alias for "upcoming"', + }) + .command(latest) + .command(git_gather) + .strictCommands() + .help() + .parse(); diff --git a/src/command/cut.js b/src/command/cut.js index 6b9c4f3..a3669ed 100644 --- a/src/command/cut.js +++ b/src/command/cut.js @@ -4,6 +4,8 @@ import u from "@yanick/updeep-remeda"; import semverInc from "semver/functions/inc.js"; import { simpleGit } from "simple-git"; +import { base_next_version } from "../utils.js"; + const code_churn = async (previous_version) => { previous_version = previous_version ? "v" + previous_version.version @@ -14,7 +16,8 @@ const code_churn = async (previous_version) => { const handler = async (config) => { config.consola.start("cutting the next version..."); - const changelog = yaml.parse(await fs.readFile(config.source, "utf-8")); + + const changelog = await config.changelog(); const next = changelog.releases.find(u.matches({ version: "NEXT" })); @@ -40,7 +43,7 @@ const handler = async (config) => { next.changes.map(({ type }) => type_to_level(type)) ); - if (changelog.project.with_stats) { + if (changelog.project?.with_stats) { next.changes.push({ type: "stats", desc: "code churn:" + (await code_churn(previous_version)), @@ -52,10 +55,13 @@ const handler = async (config) => { bumper ); + // add a new NEXT + changelog.releases.unshift(base_next_version); + if (config.dry) { config.consola.info("running in dry mode, not saving\n", next); } else { - await fs.writeFile(config.source, yaml.stringify(changelog)); + await config.save_changelog(changelog); } config.consola.success(`version ${next.version} is cut!`); diff --git a/src/command/cut.test.js b/src/command/cut.test.js new file mode 100644 index 0000000..194c645 --- /dev/null +++ b/src/command/cut.test.js @@ -0,0 +1,23 @@ +import { test, expect, vi } from "vitest"; +import cut from "./cut.js"; + +test("add a new NEXT", async () => { + const changelog = { + releases: [{ version: "NEXT", changes: [] }, { version: "1.0.0" }], + }; + + const noop = () => {}; + const config = { + consola: { + start: noop, + success: noop, + }, + changelog: () => changelog, + save_changelog: noop, + }; + + await cut.handler(config); + + expect(changelog.releases[0].version).toBe("NEXT"); + expect(changelog.releases).toHaveLength(3); +}); diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..6a5dca1 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,6 @@ +export const base_next_version = { + version: "NEXT", + changes: [], +}; + +Object.freeze(base_next_version);