diff --git a/src/commands/inc/major.ts b/src/commands/inc/major.ts index 238a094..90b7d4c 100644 --- a/src/commands/inc/major.ts +++ b/src/commands/inc/major.ts @@ -1,5 +1,4 @@ import { Arguments } from "../../../deps/yargs.ts"; -import { format } from "../../../deps/semver.ts"; import { increment, IncrementKind } from "../../util/increment.ts"; import { printVersion, @@ -25,8 +24,8 @@ export const major = { await writeVersionFile(current); await postVersionHook( args, - format(previous), - format(current), + previous, + current, ); await printVersion(args, current); }, diff --git a/src/commands/inc/minor.ts b/src/commands/inc/minor.ts index c385ae5..898e5ba 100644 --- a/src/commands/inc/minor.ts +++ b/src/commands/inc/minor.ts @@ -1,5 +1,4 @@ import { Arguments } from "../../../deps/yargs.ts"; -import { format } from "../../../deps/semver.ts"; import { increment, IncrementKind } from "../../util/increment.ts"; import { printVersion, @@ -25,8 +24,8 @@ export const minor = { await writeVersionFile(current); await postVersionHook( args, - format(previous), - format(current), + previous, + current, ); await printVersion(args, current); }, diff --git a/src/commands/inc/none.ts b/src/commands/inc/none.ts index 4ded9bb..c68fe91 100644 --- a/src/commands/inc/none.ts +++ b/src/commands/inc/none.ts @@ -1,5 +1,4 @@ import { Arguments } from "../../../deps/yargs.ts"; -import { format } from "../../../deps/semver.ts"; import { increment, IncrementKind } from "../../util/increment.ts"; import { printVersion, @@ -25,8 +24,8 @@ export const none = { await writeVersionFile(current); await postVersionHook( args, - format(previous), - format(current), + previous, + current, ); await printVersion(args, current); }, diff --git a/src/commands/inc/patch.ts b/src/commands/inc/patch.ts index 500c36e..12c6c9f 100644 --- a/src/commands/inc/patch.ts +++ b/src/commands/inc/patch.ts @@ -1,5 +1,4 @@ import { Arguments } from "../../../deps/yargs.ts"; -import { format } from "../../../deps/semver.ts"; import { increment, IncrementKind } from "../../util/increment.ts"; import { printVersion, @@ -25,8 +24,8 @@ export const patch = { await writeVersionFile(current); await postVersionHook( args, - format(previous), - format(current), + previous, + current, ); await printVersion(args, current); }, diff --git a/src/commands/set.test.ts b/src/commands/set.test.ts index ab37e60..4e1552b 100644 --- a/src/commands/set.test.ts +++ b/src/commands/set.test.ts @@ -12,6 +12,7 @@ import { Arguments } from "../../deps/yargs.ts"; import { set } from "./set.ts"; import { testContext } from "../util/testContext.ts"; import { IContext } from "../context.ts"; +import { parse } from "../../deps/semver.ts"; describe("set", () => { const hooks = { @@ -160,7 +161,7 @@ describe("set", () => { assertSpyCall(ctx1.patch, 0, { args: [ "src/test.csproj", - "1.2.3", + parse("1.2.3"), ], }); }); @@ -183,7 +184,7 @@ describe("set", () => { assertSpyCall(ctx1.patch, 0, { args: [ "src/test.csproj", - "1.0.0", + parse("1.0.0"), ], }); }); @@ -227,8 +228,8 @@ describe("set", () => { assertSpyCall(ctx1.replace, 0, { args: [ "src/info.ts", - "1.0.0", - "1.2.3", + parse("1.0.0"), + parse("1.2.3"), ], }); }); @@ -251,8 +252,8 @@ describe("set", () => { assertSpyCall(ctx1.replace, 0, { args: [ "src/info.ts", - "1.0.0", - "1.0.0", + parse("1.0.0"), + parse("1.0.0"), ], }); }); diff --git a/src/commands/set.ts b/src/commands/set.ts index 770fcf2..007f1a6 100644 --- a/src/commands/set.ts +++ b/src/commands/set.ts @@ -1,5 +1,4 @@ import { Arguments, YargsInstance } from "../../deps/yargs.ts"; -import { format } from "../../deps/semver.ts"; import { parse } from "../../deps/semver.ts"; import { increment, IncrementKind } from "../util/increment.ts"; import { @@ -37,8 +36,8 @@ export const set = { await writeVersionFile(current); await postVersionHook( args, - format(previous), - format(current), + previous, + current, ); await printVersion(args, current); }, diff --git a/src/context.ts b/src/context.ts index e31992c..281c2ea 100644 --- a/src/context.ts +++ b/src/context.ts @@ -1,23 +1,25 @@ +import { SemVer } from "../deps/semver.ts"; import { patch, regexp, replace } from "./hooks/mod.ts"; -import { VariantKey } from "./util/variant.ts"; +import { FormatKind } from "./util/variant.ts"; export interface IContext { output?: string; config?: string; githubDir: string; hooks: { - patch: (file: string, version: string) => Promise; + patch: (file: string, current: SemVer) => Promise; replace: ( file: string, - previous: string, - current: string, + previous: SemVer, + current: SemVer, ) => Promise; regexp: ( file: string, - current: string, + current: SemVer, pattern: string, flags?: string, - variant?: VariantKey, + format?: FormatKind, + prefix?: string, ) => Promise; }; } diff --git a/src/hooks/hooks.interfaces.ts b/src/hooks/hooks.interfaces.ts index 9382b23..fd7c9c9 100644 --- a/src/hooks/hooks.interfaces.ts +++ b/src/hooks/hooks.interfaces.ts @@ -1,4 +1,4 @@ -import { VariantKey } from "../util/variant.ts"; +import { FormatKind } from "../util/variant.ts"; export enum PostHookKind { Replace = "replace", @@ -19,7 +19,8 @@ export type RegExpPostHook = { file: string; pattern: string; flags?: string; - variant?: VariantKey; + format?: FormatKind; + prefix?: string; }; export type PostHook = diff --git a/src/hooks/patch.ts b/src/hooks/patch.ts index 3cc37b9..db650cb 100644 --- a/src/hooks/patch.ts +++ b/src/hooks/patch.ts @@ -2,12 +2,13 @@ import { path } from "../../deps/std.ts"; import { Node, xml } from "../../deps/xml.ts"; import { JSONC } from "../../deps/jsonc.ts"; import { UnsupportedFileKindError } from "../errors/mod.ts"; -import { variants } from "../util/version.ts"; +import { semverFormats } from "../util/variant.ts"; import { exists } from "../util/exists.ts"; +import { SemVer } from "../../deps/semver.ts"; export async function patch( file: string, - version: string, + version: SemVer, ) { console.log(`patching ${version} in ${file}`); const ext = path.extname(file); @@ -26,8 +27,8 @@ export async function patch( } } -async function patchCsproj(file: string, version: string) { - const { version_dotnet } = variants(version); +async function patchCsproj(file: string, version: SemVer) { + const { dotnet } = semverFormats(version); const contents = await Deno.readTextFile(file); const document = xml.parse(contents, { captureSpacesBetweenElements: true, @@ -48,7 +49,7 @@ async function patchCsproj(file: string, version: string) { if (property.type === "element" && property.name === "Version") { const value = property.elements[0]; if (value.type === "text") { - value.text = version_dotnet; + value.text = dotnet; isVersionSet = true; break; } @@ -71,7 +72,8 @@ async function patchCsproj(file: string, version: string) { await Deno.writeTextFile(file, updated); } -async function patchPomXml(file: string, version: string) { +async function patchPomXml(file: string, version: SemVer) { + const { def } = semverFormats(version); const contents = await Deno.readTextFile(file); const document = xml.parse(contents, { captureSpacesBetweenElements: true, @@ -92,7 +94,7 @@ async function patchPomXml(file: string, version: string) { } else if (el.type === "element" && el.name === "version") { const value = el.elements[0]; if (value.type === "text") { - value.text = version; + value.text = def; isVersionSet = true; break; } @@ -113,23 +115,25 @@ async function patchPomXml(file: string, version: string) { await Deno.writeTextFile(file, updated); } -async function patchPackageJson(file: string, version: string) { +async function patchPackageJson(file: string, version: SemVer) { + const { def } = semverFormats(version); const contents = await Deno.readTextFile(file); - const edits = JSONC.modify(contents, ["version"], version, {}); + const edits = JSONC.modify(contents, ["version"], def, {}); const result = JSONC.applyEdits(contents, edits); await Deno.writeTextFile(file, result); } -async function patchPackageLockJson(packageJsonPath: string, version: string) { +async function patchPackageLockJson(packageJsonPath: string, version: SemVer) { + const { def } = semverFormats(version); const dir = path.dirname(packageJsonPath); const packageLockJsonPath = path.resolve(dir, "package-lock.json"); if (await exists(packageLockJsonPath)) { const contents = await Deno.readTextFile(packageLockJsonPath); - const versionEdits = JSONC.modify(contents, ["version"], version, {}); + const versionEdits = JSONC.modify(contents, ["version"], def, {}); const moduleVersionEdits = JSONC.modify( contents, ["packages", "", "version"], - version, + def, {}, ); const edits = [...versionEdits, ...moduleVersionEdits]; @@ -138,11 +142,12 @@ async function patchPackageLockJson(packageJsonPath: string, version: string) { } } -async function patchChartYaml(file: string, version: string) { +async function patchChartYaml(file: string, version: SemVer) { + const { def } = semverFormats(version); const contents = await Deno.readTextFile(file); const result = contents.replace( /^version:\s*(.*)$/m, - `version: ${version}`, + `version: ${def}`, ); await Deno.writeTextFile(file, result); } diff --git a/src/hooks/post.test.ts b/src/hooks/post.test.ts index 108c9cb..0f01e6d 100644 --- a/src/hooks/post.test.ts +++ b/src/hooks/post.test.ts @@ -1,3 +1,4 @@ +import { parse } from "../../deps/semver.ts"; import { resolvesNext, stub } from "../../deps/std.ts"; import { YAML } from "../../deps/yaml.ts"; import { IContext } from "../context.ts"; @@ -34,5 +35,5 @@ Deno.test("yml or yaml", async () => { ); stub(context.hooks, "patch"); stub(context.hooks, "replace"); - await postVersionHook(context, "1.0.0", "1.2.3"); + await postVersionHook(context, parse("1.0.0"), parse("1.2.3")); }); diff --git a/src/hooks/post.ts b/src/hooks/post.ts index fb8bb68..9ded12b 100644 --- a/src/hooks/post.ts +++ b/src/hooks/post.ts @@ -3,6 +3,7 @@ import { HookError } from "../errors/mod.ts"; import { exists } from "../util/exists.ts"; import { PostHookKind, VersionConfig } from "./hooks.interfaces.ts"; import { IContext } from "../context.ts"; +import { SemVer } from "../../deps/semver.ts"; // Post hooks are a set of per-repo configurable actions that can be taken // after the version is updated. @@ -12,8 +13,8 @@ import { IContext } from "../context.ts"; // See ../.github/version.yml for an example. export async function postVersionHook( context: IContext, - previous: string, - current: string, + previous: SemVer, + current: SemVer, ) { const versionConfig = await getVersionConfig(context); if (versionConfig) { @@ -42,7 +43,8 @@ export async function postVersionHook( current, hook.pattern, hook.flags, - hook.variant, + hook.format, + hook.prefix, ); break; default: diff --git a/src/hooks/regexp.ts b/src/hooks/regexp.ts index f53803f..fd11a16 100644 --- a/src/hooks/regexp.ts +++ b/src/hooks/regexp.ts @@ -1,17 +1,18 @@ -import { variantByKey } from "../util/version.ts"; -import { VariantKey } from "../util/variant.ts"; +import { SemVer } from "../../deps/semver.ts"; +import { FormatKind, semverFormatByKey } from "../util/variant.ts"; export async function regexp( file: string, - current: string, + current: SemVer, pattern: string, flags?: string, - variant?: VariantKey, + format?: FormatKind, + prefix?: string, ) { const regexp = new RegExp(pattern, flags); const contents = await Deno.readTextFile(file); const match = contents.match(regexp); - const applicableVersion = variantByKey(current, variant); + const applicableVersion = semverFormatByKey(current, prefix, format); console.log( `replacing [${match?.[0] || ""}] -> ${applicableVersion} in ${file}`, ); diff --git a/src/hooks/replace.ts b/src/hooks/replace.ts index 019f36c..5c579b7 100644 --- a/src/hooks/replace.ts +++ b/src/hooks/replace.ts @@ -1,10 +1,14 @@ +import { format, SemVer } from "../../deps/semver.ts"; + export async function replace( file: string, - previous: string, - current: string, + previous: SemVer, + current: SemVer, ) { console.log(`replacing ${previous} -> ${current} in ${file}`); const contents = await Deno.readTextFile(file); - const updated = contents.replaceAll(previous, current); + const previousString = format(previous); + const currentString = format(current); + const updated = contents.replaceAll(previousString, currentString); await Deno.writeTextFile(file, updated); } diff --git a/src/util/variant.ts b/src/util/variant.ts index 0bce872..e396633 100644 --- a/src/util/variant.ts +++ b/src/util/variant.ts @@ -1,5 +1,28 @@ -export enum VariantKey { - Default = "version_default", - Dotnet = "version_dotnet", - Docker = "version_docker", +import { format, SemVer } from "../../deps/semver.ts"; + +export enum FormatKind { + Default = "def", + Dotnet = "dotnet", + Docker = "docker", + Major = "major", +} + +export function semverFormats(semver: SemVer, prefix = "") { + const formattedVersion = format(semver); + const kebabVersion = formattedVersion.replace(/[+]/g, "-"); + const cleanedPrefix = prefix.trim(); + return { + def: `${cleanedPrefix}${formattedVersion}`, + dotnet: `${cleanedPrefix}${kebabVersion}`, + docker: `${cleanedPrefix}${kebabVersion}`, + major: `${cleanedPrefix}${semver.major}`, + }; +} + +export function semverFormatByKey( + semver: SemVer, + prefix = "", + variantKey: FormatKind = FormatKind.Default, +) { + return semverFormats(semver, prefix)[variantKey]; } diff --git a/src/util/version.test.ts b/src/util/version.test.ts index c8dc11b..db3d0ac 100644 --- a/src/util/version.test.ts +++ b/src/util/version.test.ts @@ -151,7 +151,7 @@ Deno.test({ const appendTextFile = stub( Deno, "writeTextFile", - resolvesNext(new Array(9)), + resolvesNext(new Array(10)), ); try { const version = parse("1.2.3-pre.0+1"); @@ -166,7 +166,7 @@ Deno.test({ assertSpyCall(appendTextFile, 1, { args: [ "/test/output", - "major=1\n", + "sv_major=1\n", { create: true, append: true }, ], }); @@ -201,21 +201,21 @@ Deno.test({ assertSpyCall(appendTextFile, 6, { args: [ "/test/output", - "version_default=1.2.3-pre.0+1\n", + "def=1.2.3-pre.0+1\n", { create: true, append: true }, ], }); assertSpyCall(appendTextFile, 7, { args: [ "/test/output", - "version_dotnet=1.2.3-pre.0-1\n", + "dotnet=1.2.3-pre.0-1\n", { create: true, append: true }, ], }); assertSpyCall(appendTextFile, 8, { args: [ "/test/output", - "version_docker=1.2.3-pre.0-1\n", + "docker=1.2.3-pre.0-1\n", { create: true, append: true }, ], }); diff --git a/src/util/version.ts b/src/util/version.ts index 9a272a4..4496aa5 100644 --- a/src/util/version.ts +++ b/src/util/version.ts @@ -1,7 +1,7 @@ import { path } from "../../deps/std.ts"; import { format, parse, SemVer } from "../../deps/semver.ts"; import { IContext } from "../context.ts"; -import { VariantKey } from "./variant.ts"; +import { semverFormats } from "./variant.ts"; export const DEFAULT_VERSION = parse("0.1.0"); @@ -25,15 +25,17 @@ export async function printVersion( context: IContext, semver: SemVer, full = false, + prefix = "", ) { const formatted = format(semver); - const { major, minor, patch, prerelease, build } = semver; - const other = variants(formatted); + const sv_major = semver.major; + const { minor, patch, prerelease, build } = semver; const pre = prerelease.join("."); const b = build.join("."); + const other = semverFormats(semver, prefix); await writeGithubOutput(context, { version: formatted, - major, + sv_major, minor, patch, prerelease: pre, @@ -43,7 +45,7 @@ export async function printVersion( if (full) { console.log(JSON.stringify({ version: formatted, - major, + sv_major, minor, patch, prerelease: pre, @@ -55,23 +57,6 @@ export async function printVersion( } } -export function variants(version: string) { - const kabobBuild = version.replace(/[+]/g, "-"); - // todo: add any other platform specific variants here. - return { - version_default: version, - version_dotnet: kabobBuild, - version_docker: kabobBuild, - }; -} - -export function variantByKey( - version: string, - variantKey: VariantKey = VariantKey.Default, -) { - return variants(version)[variantKey]; -} - /** * This reads the current version file found at $CWD/VERSION and parses it as a * valid SemVer. If the file is not found, is empty, or contains an invalid