1
mirror of https://github.com/jakejarvis/hugo-extended.git synced 2026-06-24 11:35:58 -04:00

feat: allow environment variable overrides of default behaviors (#182)

This commit is contained in:
2026-01-08 21:23:53 -05:00
committed by GitHub
parent d14ea4dbd9
commit b409823e55
15 changed files with 1288 additions and 188 deletions
+239
View File
@@ -0,0 +1,239 @@
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { ENV_VAR_DOCS, getEnvConfig } from "../../src/lib/env";
describe("env", () => {
// Store original env vars to restore after each test
const originalEnv: Record<string, string | undefined> = {};
// List of all env vars we might set during tests
const envVars = [
"HUGO_OVERRIDE_VERSION",
"HUGO_NO_EXTENDED",
"HUGO_FORCE_STANDARD",
"HUGO_SKIP_DOWNLOAD",
"HUGO_BIN_PATH",
"HUGO_MIRROR_BASE_URL",
"HUGO_SKIP_CHECKSUM",
"HUGO_SKIP_VERIFY",
"HUGO_QUIET",
"HUGO_SILENT",
];
beforeEach(() => {
// Save original values
for (const key of envVars) {
originalEnv[key] = process.env[key];
delete process.env[key];
}
});
afterEach(() => {
// Restore original values
for (const key of envVars) {
if (originalEnv[key] === undefined) {
delete process.env[key];
} else {
process.env[key] = originalEnv[key];
}
}
});
describe("getEnvConfig", () => {
describe("overrideVersion", () => {
it("should return undefined when not set", () => {
const config = getEnvConfig();
expect(config.overrideVersion).toBeUndefined();
});
it("should return the value from HUGO_OVERRIDE_VERSION", () => {
process.env.HUGO_OVERRIDE_VERSION = "0.139.0";
const config = getEnvConfig();
expect(config.overrideVersion).toBe("0.139.0");
});
it("should strip v prefix from version", () => {
process.env.HUGO_OVERRIDE_VERSION = "v0.139.0";
const config = getEnvConfig();
expect(config.overrideVersion).toBe("0.139.0");
});
it("should return undefined for empty string", () => {
process.env.HUGO_OVERRIDE_VERSION = "";
const config = getEnvConfig();
expect(config.overrideVersion).toBeUndefined();
});
it("should return undefined for whitespace-only string", () => {
process.env.HUGO_OVERRIDE_VERSION = " ";
const config = getEnvConfig();
expect(config.overrideVersion).toBeUndefined();
});
});
describe("forceStandard", () => {
it("should return false when not set", () => {
const config = getEnvConfig();
expect(config.forceStandard).toBe(false);
});
it.each([
"1",
"true",
"yes",
"on",
"TRUE",
"True",
"YES",
"ON",
])('should return true for "%s"', (value) => {
process.env.HUGO_NO_EXTENDED = value;
const config = getEnvConfig();
expect(config.forceStandard).toBe(true);
});
it.each([
"0",
"false",
"no",
"off",
"",
"invalid",
])('should return false for "%s"', (value) => {
process.env.HUGO_NO_EXTENDED = value;
const config = getEnvConfig();
expect(config.forceStandard).toBe(false);
});
it("should work with HUGO_FORCE_STANDARD alias", () => {
process.env.HUGO_FORCE_STANDARD = "1";
const config = getEnvConfig();
expect(config.forceStandard).toBe(true);
});
});
describe("skipInstall", () => {
it("should return false when not set", () => {
const config = getEnvConfig();
expect(config.skipInstall).toBe(false);
});
it("should return true when HUGO_SKIP_DOWNLOAD is truthy", () => {
process.env.HUGO_SKIP_DOWNLOAD = "1";
const config = getEnvConfig();
expect(config.skipInstall).toBe(true);
});
it("should work with HUGO_SKIP_DOWNLOAD alias", () => {
process.env.HUGO_SKIP_DOWNLOAD = "true";
const config = getEnvConfig();
expect(config.skipInstall).toBe(true);
});
});
describe("binPath", () => {
it("should return undefined when not set", () => {
const config = getEnvConfig();
expect(config.binPath).toBeUndefined();
});
it("should return the value from HUGO_BIN_PATH", () => {
process.env.HUGO_BIN_PATH = "/usr/local/bin/hugo";
const config = getEnvConfig();
expect(config.binPath).toBe("/usr/local/bin/hugo");
});
it("should trim whitespace", () => {
process.env.HUGO_BIN_PATH = " /usr/local/bin/hugo ";
const config = getEnvConfig();
expect(config.binPath).toBe("/usr/local/bin/hugo");
});
});
describe("downloadBaseUrl", () => {
it("should return undefined when not set", () => {
const config = getEnvConfig();
expect(config.downloadBaseUrl).toBeUndefined();
});
it("should return the value from HUGO_MIRROR_BASE_URL", () => {
process.env.HUGO_MIRROR_BASE_URL = "https://mirror.example.com/hugo";
const config = getEnvConfig();
expect(config.downloadBaseUrl).toBe("https://mirror.example.com/hugo");
});
});
describe("skipChecksum", () => {
it("should return false when not set", () => {
const config = getEnvConfig();
expect(config.skipChecksum).toBe(false);
});
it("should return true when HUGO_SKIP_CHECKSUM is truthy", () => {
process.env.HUGO_SKIP_CHECKSUM = "1";
const config = getEnvConfig();
expect(config.skipChecksum).toBe(true);
});
it("should work with HUGO_SKIP_VERIFY alias", () => {
process.env.HUGO_SKIP_VERIFY = "true";
const config = getEnvConfig();
expect(config.skipChecksum).toBe(true);
});
});
describe("quiet", () => {
it("should return false when not set", () => {
const config = getEnvConfig();
expect(config.quiet).toBe(false);
});
it("should return true when HUGO_QUIET is truthy", () => {
process.env.HUGO_QUIET = "1";
const config = getEnvConfig();
expect(config.quiet).toBe(true);
});
it("should work with HUGO_SILENT alias", () => {
process.env.HUGO_SILENT = "true";
const config = getEnvConfig();
expect(config.quiet).toBe(true);
});
});
});
describe("ENV_VAR_DOCS", () => {
it("should export documentation for all env vars", () => {
expect(ENV_VAR_DOCS).toBeDefined();
expect(Array.isArray(ENV_VAR_DOCS)).toBe(true);
expect(ENV_VAR_DOCS.length).toBeGreaterThan(0);
});
it("should have required fields for each entry", () => {
for (const doc of ENV_VAR_DOCS) {
expect(doc.key).toBeDefined();
expect(doc.name).toBeDefined();
expect(doc.name).toMatch(/^HUGO_/);
expect(doc.description).toBeDefined();
expect(Array.isArray(doc.aliases)).toBe(true);
expect(["string", "boolean"]).toContain(doc.type);
}
});
it("should document all expected env vars", () => {
const expectedKeys = [
"overrideVersion",
"forceStandard",
"skipInstall",
"binPath",
"downloadBaseUrl",
"skipChecksum",
"quiet",
];
const actualKeys = ENV_VAR_DOCS.map((doc) => doc.key);
for (const key of expectedKeys) {
expect(actualKeys).toContain(key);
}
});
});
});
+277 -3
View File
@@ -1,13 +1,58 @@
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import {
compareVersions,
getBinFilename,
getBinPath,
getChecksumFilename,
getReleaseFilename,
getReleaseUrl,
isExtended,
logger,
usesMacOSPkg,
} from "../../src/lib/utils";
describe("utils", () => {
describe("compareVersions", () => {
it("should return 0 for equal versions", () => {
expect(compareVersions("0.153.0", "0.153.0")).toBe(0);
expect(compareVersions("1.0.0", "1.0.0")).toBe(0);
});
it("should return -1 when first version is less", () => {
expect(compareVersions("0.152.0", "0.153.0")).toBe(-1);
expect(compareVersions("0.152.9", "0.153.0")).toBe(-1);
expect(compareVersions("0.100.0", "0.153.0")).toBe(-1);
expect(compareVersions("0.153.0", "1.0.0")).toBe(-1);
});
it("should return 1 when first version is greater", () => {
expect(compareVersions("0.154.0", "0.153.0")).toBe(1);
expect(compareVersions("0.153.1", "0.153.0")).toBe(1);
expect(compareVersions("1.0.0", "0.153.0")).toBe(1);
});
it("should handle versions with different segment counts", () => {
expect(compareVersions("0.153", "0.153.0")).toBe(0);
expect(compareVersions("0.153.0.1", "0.153.0")).toBe(1);
});
});
describe("usesMacOSPkg", () => {
it("should return true for v0.153.0 and later", () => {
expect(usesMacOSPkg("0.153.0")).toBe(true);
expect(usesMacOSPkg("0.154.0")).toBe(true);
expect(usesMacOSPkg("0.154.3")).toBe(true);
expect(usesMacOSPkg("1.0.0")).toBe(true);
});
it("should return false for versions before v0.153.0", () => {
expect(usesMacOSPkg("0.152.0")).toBe(false);
expect(usesMacOSPkg("0.152.9")).toBe(false);
expect(usesMacOSPkg("0.100.0")).toBe(false);
expect(usesMacOSPkg("0.102.3")).toBe(false);
});
});
describe("getBinFilename", () => {
let originalPlatform: NodeJS.Platform;
@@ -55,7 +100,7 @@ describe("utils", () => {
});
describe("macOS", () => {
it("should return universal pkg for darwin x64", () => {
it("should return universal pkg for darwin x64 (v0.153.0+)", () => {
Object.defineProperty(process, "platform", { value: "darwin" });
Object.defineProperty(process, "arch", { value: "x64" });
expect(getReleaseFilename("0.154.3")).toBe(
@@ -63,13 +108,37 @@ describe("utils", () => {
);
});
it("should return universal pkg for darwin arm64", () => {
it("should return universal pkg for darwin arm64 (v0.153.0+)", () => {
Object.defineProperty(process, "platform", { value: "darwin" });
Object.defineProperty(process, "arch", { value: "arm64" });
expect(getReleaseFilename("0.154.3")).toBe(
"hugo_extended_0.154.3_darwin-universal.pkg",
);
});
it("should return universal tar.gz for darwin x64 (pre-v0.153.0)", () => {
Object.defineProperty(process, "platform", { value: "darwin" });
Object.defineProperty(process, "arch", { value: "x64" });
expect(getReleaseFilename("0.152.0")).toBe(
"hugo_extended_0.152.0_darwin-universal.tar.gz",
);
});
it("should return universal tar.gz for darwin arm64 (pre-v0.153.0)", () => {
Object.defineProperty(process, "platform", { value: "darwin" });
Object.defineProperty(process, "arch", { value: "arm64" });
expect(getReleaseFilename("0.139.0")).toBe(
"hugo_extended_0.139.0_darwin-universal.tar.gz",
);
});
it("should return pkg at version boundary (v0.153.0)", () => {
Object.defineProperty(process, "platform", { value: "darwin" });
Object.defineProperty(process, "arch", { value: "arm64" });
expect(getReleaseFilename("0.153.0")).toBe(
"hugo_extended_0.153.0_darwin-universal.pkg",
);
});
});
describe("Windows", () => {
@@ -175,6 +244,21 @@ describe("utils", () => {
});
describe("getReleaseUrl", () => {
let originalMirrorBaseUrl: string | undefined;
beforeEach(() => {
originalMirrorBaseUrl = process.env.HUGO_MIRROR_BASE_URL;
delete process.env.HUGO_MIRROR_BASE_URL;
});
afterEach(() => {
if (originalMirrorBaseUrl === undefined) {
delete process.env.HUGO_MIRROR_BASE_URL;
} else {
process.env.HUGO_MIRROR_BASE_URL = originalMirrorBaseUrl;
}
});
it("should return correct GitHub release URL", () => {
expect(
getReleaseUrl("0.154.3", "hugo_extended_0.154.3_linux-amd64.tar.gz"),
@@ -188,5 +272,195 @@ describe("utils", () => {
"https://github.com/gohugoio/hugo/releases/download/v0.154.3/hugo_0.154.3_checksums.txt",
);
});
it("should use custom base URL when HUGO_MIRROR_BASE_URL is set", () => {
process.env.HUGO_MIRROR_BASE_URL = "https://mirror.example.com/hugo";
expect(
getReleaseUrl("0.154.3", "hugo_extended_0.154.3_linux-amd64.tar.gz"),
).toBe(
"https://mirror.example.com/hugo/hugo_extended_0.154.3_linux-amd64.tar.gz",
);
});
it("should strip trailing slash from custom base URL", () => {
process.env.HUGO_MIRROR_BASE_URL = "https://mirror.example.com/hugo/";
expect(
getReleaseUrl("0.154.3", "hugo_extended_0.154.3_linux-amd64.tar.gz"),
).toBe(
"https://mirror.example.com/hugo/hugo_extended_0.154.3_linux-amd64.tar.gz",
);
});
});
describe("getReleaseFilename with HUGO_NO_EXTENDED", () => {
let originalPlatform: NodeJS.Platform;
let originalArch: NodeJS.Architecture;
let originalNoExtended: string | undefined;
let originalForceStandard: string | undefined;
beforeEach(() => {
originalPlatform = process.platform;
originalArch = process.arch;
originalNoExtended = process.env.HUGO_NO_EXTENDED;
originalForceStandard = process.env.HUGO_FORCE_STANDARD;
delete process.env.HUGO_NO_EXTENDED;
delete process.env.HUGO_FORCE_STANDARD;
});
afterEach(() => {
Object.defineProperty(process, "platform", { value: originalPlatform });
Object.defineProperty(process, "arch", { value: originalArch });
if (originalNoExtended === undefined) {
delete process.env.HUGO_NO_EXTENDED;
} else {
process.env.HUGO_NO_EXTENDED = originalNoExtended;
}
if (originalForceStandard === undefined) {
delete process.env.HUGO_FORCE_STANDARD;
} else {
process.env.HUGO_FORCE_STANDARD = originalForceStandard;
}
});
it("should return vanilla Hugo pkg when HUGO_NO_EXTENDED is set on macOS (v0.153.0+)", () => {
Object.defineProperty(process, "platform", { value: "darwin" });
Object.defineProperty(process, "arch", { value: "arm64" });
process.env.HUGO_NO_EXTENDED = "1";
expect(getReleaseFilename("0.154.3")).toBe(
"hugo_0.154.3_darwin-universal.pkg",
);
});
it("should return vanilla Hugo tar.gz when HUGO_NO_EXTENDED is set on macOS (pre-v0.153.0)", () => {
Object.defineProperty(process, "platform", { value: "darwin" });
Object.defineProperty(process, "arch", { value: "arm64" });
process.env.HUGO_NO_EXTENDED = "1";
expect(getReleaseFilename("0.152.0")).toBe(
"hugo_0.152.0_darwin-universal.tar.gz",
);
});
it("should return vanilla Hugo when HUGO_NO_EXTENDED is set on Linux", () => {
Object.defineProperty(process, "platform", { value: "linux" });
Object.defineProperty(process, "arch", { value: "x64" });
process.env.HUGO_NO_EXTENDED = "1";
expect(getReleaseFilename("0.154.3")).toBe(
"hugo_0.154.3_linux-amd64.tar.gz",
);
});
it("should return vanilla Hugo when HUGO_NO_EXTENDED is set on Windows", () => {
Object.defineProperty(process, "platform", { value: "win32" });
Object.defineProperty(process, "arch", { value: "x64" });
process.env.HUGO_NO_EXTENDED = "1";
expect(getReleaseFilename("0.154.3")).toBe(
"hugo_0.154.3_windows-amd64.zip",
);
});
it("should work with HUGO_FORCE_STANDARD alias", () => {
Object.defineProperty(process, "platform", { value: "linux" });
Object.defineProperty(process, "arch", { value: "arm64" });
process.env.HUGO_FORCE_STANDARD = "true";
expect(getReleaseFilename("0.154.3")).toBe(
"hugo_0.154.3_linux-arm64.tar.gz",
);
});
});
describe("getBinPath with HUGO_BIN_PATH", () => {
let originalBinPath: string | undefined;
beforeEach(() => {
originalBinPath = process.env.HUGO_BIN_PATH;
delete process.env.HUGO_BIN_PATH;
});
afterEach(() => {
if (originalBinPath === undefined) {
delete process.env.HUGO_BIN_PATH;
} else {
process.env.HUGO_BIN_PATH = originalBinPath;
}
});
it("should return custom path when HUGO_BIN_PATH is set", () => {
process.env.HUGO_BIN_PATH = "/custom/path/to/hugo";
expect(getBinPath()).toBe("/custom/path/to/hugo");
});
it("should return default path when HUGO_BIN_PATH is not set", () => {
const binPath = getBinPath();
expect(binPath).toContain("bin");
expect(binPath).toMatch(/hugo(\.exe)?$/);
});
});
describe("logger", () => {
let originalQuiet: string | undefined;
let originalSilent: string | undefined;
beforeEach(() => {
originalQuiet = process.env.HUGO_QUIET;
originalSilent = process.env.HUGO_SILENT;
delete process.env.HUGO_QUIET;
delete process.env.HUGO_SILENT;
vi.spyOn(console, "info").mockImplementation(() => {});
vi.spyOn(console, "warn").mockImplementation(() => {});
vi.spyOn(console, "error").mockImplementation(() => {});
});
afterEach(() => {
if (originalQuiet === undefined) {
delete process.env.HUGO_QUIET;
} else {
process.env.HUGO_QUIET = originalQuiet;
}
if (originalSilent === undefined) {
delete process.env.HUGO_SILENT;
} else {
process.env.HUGO_SILENT = originalSilent;
}
vi.restoreAllMocks();
});
describe("info", () => {
it("should log when not quiet", () => {
logger.info("test message");
expect(console.info).toHaveBeenCalledWith("test message");
});
it("should not log when HUGO_QUIET is set", () => {
process.env.HUGO_QUIET = "1";
logger.info("test message");
expect(console.info).not.toHaveBeenCalled();
});
});
describe("warn", () => {
it("should log when not quiet", () => {
logger.warn("warning message");
expect(console.warn).toHaveBeenCalledWith("warning message");
});
it("should not log when HUGO_SILENT is set", () => {
process.env.HUGO_SILENT = "1";
logger.warn("warning message");
expect(console.warn).not.toHaveBeenCalled();
});
});
describe("error", () => {
it("should always log errors", () => {
logger.error("error message");
expect(console.error).toHaveBeenCalledWith("error message");
});
it("should log errors even when quiet", () => {
process.env.HUGO_QUIET = "1";
logger.error("error message");
expect(console.error).toHaveBeenCalledWith("error message");
});
});
});
});