diff --git a/src/prepare.ts b/src/prepare.ts index dbaa9f7..5f59d6a 100644 --- a/src/prepare.ts +++ b/src/prepare.ts @@ -7,7 +7,7 @@ import { lookupCabalFilename } from "./utils/prepare"; import { readFile, writeFile } from "fs/promises"; import { resolve } from "path"; -export const VERSION_PATTERN = /version:\s+(\S+)/; +export const VERSION_PATTERN = /^\s*version:\s+(\S+)/m; export const readAndWriteNewCabal = async (fullCabalPath: string, newVersion: string): Promise => { const versionContents = await readFile(fullCabalPath, "utf8"); diff --git a/src/publish.ts b/src/publish.ts index 2441c13..5feec22 100644 --- a/src/publish.ts +++ b/src/publish.ts @@ -8,6 +8,8 @@ import fs from "fs"; export const HACKAGE_CANDIDATES_URL = "https://hackage.haskell.org/packages/candidates"; +const V2_HADDOCK_COMMAND = "cabal v2-haddock --haddock-for-hackage --enable-documentation"; + export const postReleaseCandidate = async (sdistPath: string, hackageToken?: string): Promise => { try { const headers = { @@ -70,7 +72,7 @@ export const publish = async ( logger.log("Checking publishDocumentation plugin configuration: ", publishDocumentation); if (publishDocumentation) { logger.log("Generating documentation"); - const { error, output } = await runExecCommand("cabal haddock --haddock-for-hackage --enable-documentation"); + const { error, output } = await runExecCommand(V2_HADDOCK_COMMAND); if (error) { logger.error(error); @@ -82,6 +84,7 @@ export const publish = async ( const docsSdistPath = `${realCwd}/dist-newstyle/${docsFilename}`; const docsUrl = `https://hackage.haskell.org/package/${packageName}-${versionPrefix}${version}/candidate/docs`; + logger.log("Publishing file: ", docsFilename, " from: ", docsSdistPath); const docStatus = await publishRCDocumentation(docsSdistPath, docsUrl, process.env.HACKAGE_TOKEN); if (docStatus !== 200) { diff --git a/test/fixtures/test-2-package.cabal b/test/fixtures/test-2-package.cabal new file mode 100644 index 0000000..1b59e47 --- /dev/null +++ b/test/fixtures/test-2-package.cabal @@ -0,0 +1,2 @@ +cabal-version: 1.12 +version: 0.0.1 \ No newline at end of file diff --git a/test/unit/prepare.test.ts b/test/unit/prepare.test.ts index 989b6e6..12bb05e 100644 --- a/test/unit/prepare.test.ts +++ b/test/unit/prepare.test.ts @@ -1,45 +1,113 @@ import { expect } from "@assertive-ts/core"; -import { readAndWriteNewCabal } from "../../src/prepare"; +import { readAndWriteNewCabal, VERSION_PATTERN } from "../../src/prepare"; import { readFile, writeFile } from "fs/promises"; const fakeCabalPath = "./test/fixtures/test-1-package.cabal"; const fakeNewVersion = "0.0.7"; const cabalContent = "name: test-1-package\nversion: 0.0.1"; +const fakeVersionCabalPath = "./test/fixtures/test-2-package.cabal"; +const cabalVersionContent = "cabal-version: 1.12\nversion: 0.0.1"; describe("readAndWriteNewCabal", () => { - afterEach(async () => { - await writeFile(fakeCabalPath, cabalContent, "utf8"); - }); + context("when cabal file has name and version", () => { + afterEach(async () => { + await writeFile(fakeCabalPath, cabalContent, "utf8"); + }); - context("when version is semantic", () => { - it("updates the version in the cabal file fixture", async () => { - await readAndWriteNewCabal(fakeCabalPath, fakeNewVersion); + context("when version is semantic", () => { + it("updates the version in the cabal file fixture", async () => { + await readAndWriteNewCabal(fakeCabalPath, fakeNewVersion); - const modifiedContents = await readFile(fakeCabalPath, "utf8"); + const modifiedContents = await readFile(fakeCabalPath, "utf8"); - expect(modifiedContents).toBeEqual("name: test-1-package\nversion: 0.0.7"); + expect(modifiedContents).toBeEqual("name: test-1-package\nversion: 0.0.7"); + }); + }); + + context("when version is not semantic", () => { + it("updates the version in the cabal file fixture", async () => { + const versionPrefix = "0."; + await readAndWriteNewCabal(fakeCabalPath, versionPrefix + fakeNewVersion); + + const modifiedContents = await readFile(fakeCabalPath, "utf8"); + + expect(modifiedContents).toBeEqual("name: test-1-package\nversion: 0.0.0.7"); + }); }); }); - context("when version is not semantic", () => { - it("updates the version in the cabal file fixture", async () => { + context("when cabal file has cabal-version and version", () => { + afterEach(async () => { + await writeFile(fakeVersionCabalPath, cabalVersionContent, "utf8"); + }); + + it("updates the right version in the cabal file fixture", async () => { + await readAndWriteNewCabal(fakeVersionCabalPath, fakeNewVersion); + + const modifiedContents = await readFile(fakeVersionCabalPath, "utf8"); + + expect(modifiedContents).toBeEqual("cabal-version: 1.12\nversion: 0.0.7"); + }); + + it("updates the version in the cabal file fixture when version is not semantic", async () => { const versionPrefix = "0."; - await readAndWriteNewCabal(fakeCabalPath, versionPrefix + fakeNewVersion); + await readAndWriteNewCabal(fakeVersionCabalPath, versionPrefix + fakeNewVersion); - const modifiedContents = await readFile(fakeCabalPath, "utf8"); + const modifiedContents = await readFile(fakeVersionCabalPath, "utf8"); - expect(modifiedContents).toBeEqual("name: test-1-package\nversion: 0.0.0.7"); + expect(modifiedContents).toBeEqual("cabal-version: 1.12\nversion: 0.0.0.7"); }); }); +}); - it("updates the version in the cabal file fixture when version is not semantic", async () => { - const versionPrefix = "0."; - await readAndWriteNewCabal(fakeCabalPath, versionPrefix + fakeNewVersion); +describe("VERSION_PATTERN", () => { + it("matches a valid version of strings", () => { + const validStrings = ["version: 1.0.0", " version: 2.3.4", "version: 3.0.0-alpha", "version: 4.2.0-beta.1"]; - const modifiedContents = await readFile(fakeCabalPath, "utf8"); + validStrings.forEach(str => { + const match = str.match(VERSION_PATTERN); + expect(match).not.toBeNull(); + if (match && match[1]) { + expect(match[1]).not.toBeUndefined(); + } + }); + }); + + it("does not match invalid version strings", () => { + const invalidStrings = ["version 1.0.0", "ver: 2.3.4", "version:", "version:"]; + + invalidStrings.forEach(str => { + const match = str.match(VERSION_PATTERN); + expect(match).toBeNull(); + }); + }); - expect(modifiedContents).toBeEqual("name: test-1-package\nversion: 0.0.0.7"); + it("matches version strings with extra spaces", () => { + const validStrings = [" version: 1.0.0", "\tversion: 2.3.4", " \t version: 3.0.0-alpha"]; + + validStrings.forEach(str => { + const match = str.match(VERSION_PATTERN); + expect(match).not.toBeNull(); + if (match && match[1]) { + expect(match[1]).not.toBeUndefined(); + } + }); + }); + + it("captures the correct version value", () => { + const testCases = [ + { expected: "1.0.0", input: "version: 1.0.0" }, + { expected: "2.3.4", input: " version: 2.3.4" }, + ]; + + testCases.forEach(({ expected, input }) => { + const match = input.match(VERSION_PATTERN); + expect(match).not.toBeNull(); + if (match && match[1]) { + expect(match[1]).toBeEqual(expected); + } + }); }); });