From 1b46e13ec88163c255691015b7e7afec7535b06a Mon Sep 17 00:00:00 2001 From: Kevin Stillhammer Date: Mon, 1 Sep 2025 16:12:49 +0200 Subject: [PATCH] Fix exclusions in cache-dependency-glob (#546) Fixes: #537 --- __tests__/utils/inputs.test.ts | 86 ++++++++++++++++++++++++++++++++++ dist/save-cache/index.js | 15 ++---- dist/setup/index.js | 15 ++---- src/utils/inputs.ts | 19 ++++---- 4 files changed, 105 insertions(+), 30 deletions(-) create mode 100644 __tests__/utils/inputs.test.ts diff --git a/__tests__/utils/inputs.test.ts b/__tests__/utils/inputs.test.ts new file mode 100644 index 0000000..d43aa8c --- /dev/null +++ b/__tests__/utils/inputs.test.ts @@ -0,0 +1,86 @@ +jest.mock("@actions/core", () => { + return { + debug: jest.fn(), + getBooleanInput: jest.fn( + (name: string) => (mockInputs[name] ?? "") === "true", + ), + getInput: jest.fn((name: string) => mockInputs[name] ?? ""), + }; +}); + +import { + afterEach, + beforeEach, + describe, + expect, + it, + jest, +} from "@jest/globals"; + +// Will be mutated per test before (re-)importing the module under test +let mockInputs: Record = {}; +const ORIGINAL_HOME = process.env.HOME; + +describe("cacheDependencyGlob", () => { + beforeEach(() => { + jest.resetModules(); + mockInputs = {}; + process.env.HOME = "/home/testuser"; + }); + + afterEach(() => { + process.env.HOME = ORIGINAL_HOME; + }); + + it("returns empty string when input not provided", async () => { + mockInputs["working-directory"] = "/workspace"; + const { cacheDependencyGlob } = await import("../../src/utils/inputs"); + expect(cacheDependencyGlob).toBe(""); + }); + + it("resolves a single relative path", async () => { + mockInputs["working-directory"] = "/workspace"; + mockInputs["cache-dependency-glob"] = "requirements.txt"; + const { cacheDependencyGlob } = await import("../../src/utils/inputs"); + expect(cacheDependencyGlob).toBe("/workspace/requirements.txt"); + }); + + it("strips leading ./ from relative path", async () => { + mockInputs["working-directory"] = "/workspace"; + mockInputs["cache-dependency-glob"] = "./uv.lock"; + const { cacheDependencyGlob } = await import("../../src/utils/inputs"); + expect(cacheDependencyGlob).toBe("/workspace/uv.lock"); + }); + + it("handles multiple lines, trimming whitespace, tilde expansion and absolute paths", async () => { + mockInputs["working-directory"] = "/workspace"; + mockInputs["cache-dependency-glob"] = + " ~/.cache/file1\n ./rel/file2 \nfile3.txt"; + const { cacheDependencyGlob } = await import("../../src/utils/inputs"); + expect(cacheDependencyGlob).toBe( + [ + "/home/testuser/.cache/file1", // expanded tilde, absolute path unchanged + "/workspace/rel/file2", // ./ stripped and resolved + "/workspace/file3.txt", // relative path resolved + ].join("\n"), + ); + }); + + it("keeps absolute path unchanged in multiline input", async () => { + mockInputs["working-directory"] = "/workspace"; + mockInputs["cache-dependency-glob"] = "/abs/path.lock\nrelative.lock"; + const { cacheDependencyGlob } = await import("../../src/utils/inputs"); + expect(cacheDependencyGlob).toBe( + ["/abs/path.lock", "/workspace/relative.lock"].join("\n"), + ); + }); + + it("handles exclusions in relative paths correct", async () => { + mockInputs["working-directory"] = "/workspace"; + mockInputs["cache-dependency-glob"] = "!/abs/path.lock\n!relative.lock"; + const { cacheDependencyGlob } = await import("../../src/utils/inputs"); + expect(cacheDependencyGlob).toBe( + ["!/abs/path.lock", "!/workspace/relative.lock"].join("\n"), + ); + }); +}); diff --git a/dist/save-cache/index.js b/dist/save-cache/index.js index fb820d2..7c5f042 100644 --- a/dist/save-cache/index.js +++ b/dist/save-cache/index.js @@ -90169,16 +90169,11 @@ function expandTilde(input) { return input; } function resolveRelativePath(inputPath) { - if (node_path_1.default.isAbsolute(inputPath)) { - return inputPath; - } - let absolutePath = inputPath; - if (absolutePath.startsWith("./")) { - absolutePath = absolutePath.substring(2); - } - absolutePath = `${exports.workingDirectory}${node_path_1.default.sep}${absolutePath}`; - core.debug(`Resolving relative path ${inputPath} to ${absolutePath}`); - return absolutePath; + const hasNegation = inputPath.startsWith("!"); + const pathWithoutNegation = hasNegation ? inputPath.substring(1) : inputPath; + const resolvedPath = node_path_1.default.resolve(exports.workingDirectory, pathWithoutNegation); + core.debug(`Resolving relative path ${inputPath} to ${hasNegation ? "!" : ""}${resolvedPath}`); + return hasNegation ? `!${resolvedPath}` : resolvedPath; } function getManifestFile() { const manifestFileInput = core.getInput("manifest-file"); diff --git a/dist/setup/index.js b/dist/setup/index.js index e07b43c..2c1c91b 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -128214,16 +128214,11 @@ function expandTilde(input) { return input; } function resolveRelativePath(inputPath) { - if (node_path_1.default.isAbsolute(inputPath)) { - return inputPath; - } - let absolutePath = inputPath; - if (absolutePath.startsWith("./")) { - absolutePath = absolutePath.substring(2); - } - absolutePath = `${exports.workingDirectory}${node_path_1.default.sep}${absolutePath}`; - core.debug(`Resolving relative path ${inputPath} to ${absolutePath}`); - return absolutePath; + const hasNegation = inputPath.startsWith("!"); + const pathWithoutNegation = hasNegation ? inputPath.substring(1) : inputPath; + const resolvedPath = node_path_1.default.resolve(exports.workingDirectory, pathWithoutNegation); + core.debug(`Resolving relative path ${inputPath} to ${hasNegation ? "!" : ""}${resolvedPath}`); + return hasNegation ? `!${resolvedPath}` : resolvedPath; } function getManifestFile() { const manifestFileInput = core.getInput("manifest-file"); diff --git a/src/utils/inputs.ts b/src/utils/inputs.ts index 8467d72..10904d4 100644 --- a/src/utils/inputs.ts +++ b/src/utils/inputs.ts @@ -116,16 +116,15 @@ function expandTilde(input: string): string { } function resolveRelativePath(inputPath: string): string { - if (path.isAbsolute(inputPath)) { - return inputPath; - } - let absolutePath = inputPath; - if (absolutePath.startsWith("./")) { - absolutePath = absolutePath.substring(2); - } - absolutePath = `${workingDirectory}${path.sep}${absolutePath}`; - core.debug(`Resolving relative path ${inputPath} to ${absolutePath}`); - return absolutePath; + const hasNegation = inputPath.startsWith("!"); + const pathWithoutNegation = hasNegation ? inputPath.substring(1) : inputPath; + + const resolvedPath = path.resolve(workingDirectory, pathWithoutNegation); + + core.debug( + `Resolving relative path ${inputPath} to ${hasNegation ? "!" : ""}${resolvedPath}`, + ); + return hasNegation ? `!${resolvedPath}` : resolvedPath; } function getManifestFile(): string | undefined {