1
0
Fork 0
mirror of https://code.forgejo.org/actions/cache.git synced 2025-04-20 03:46:17 +02:00

Allow for multiple line-delimited paths to cache

This commit is contained in:
Ethan Dennis 2020-03-04 16:02:51 -08:00
parent 826785142a
commit 84cead4a82
No known key found for this signature in database
GPG key ID: 32E74B75DB4065DD
8 changed files with 116 additions and 58 deletions

View file

@ -59,7 +59,8 @@ test("restore with invalid event outputs warning", async () => {
test("restore with no path should fail", async () => { test("restore with no path should fail", async () => {
const failedMock = jest.spyOn(core, "setFailed"); const failedMock = jest.spyOn(core, "setFailed");
await run(); await run();
expect(failedMock).toHaveBeenCalledWith( // TODO: this shouldn't be necessary if tarball contains entries relative to workspace
expect(failedMock).not.toHaveBeenCalledWith(
"Input required and not supplied: path" "Input required and not supplied: path"
); );
}); });
@ -201,7 +202,6 @@ test("restore with restore keys and no cache found", async () => {
test("restore with cache found", async () => { test("restore with cache found", async () => {
const key = "node-test"; const key = "node-test";
const cachePath = path.resolve("node_modules");
testUtils.setInputs({ testUtils.setInputs({
path: "node_modules", path: "node_modules",
key key
@ -255,7 +255,7 @@ test("restore with cache found", async () => {
expect(getArchiveFileSizeMock).toHaveBeenCalledWith(archivePath); expect(getArchiveFileSizeMock).toHaveBeenCalledWith(archivePath);
expect(extractTarMock).toHaveBeenCalledTimes(1); expect(extractTarMock).toHaveBeenCalledTimes(1);
expect(extractTarMock).toHaveBeenCalledWith(archivePath, cachePath); expect(extractTarMock).toHaveBeenCalledWith(archivePath);
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1); expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
expect(setCacheHitOutputMock).toHaveBeenCalledWith(true); expect(setCacheHitOutputMock).toHaveBeenCalledWith(true);
@ -266,7 +266,6 @@ test("restore with cache found", async () => {
test("restore with a pull request event and cache found", async () => { test("restore with a pull request event and cache found", async () => {
const key = "node-test"; const key = "node-test";
const cachePath = path.resolve("node_modules");
testUtils.setInputs({ testUtils.setInputs({
path: "node_modules", path: "node_modules",
key key
@ -323,7 +322,7 @@ test("restore with a pull request event and cache found", async () => {
expect(infoMock).toHaveBeenCalledWith(`Cache Size: ~60 MB (62915000 B)`); expect(infoMock).toHaveBeenCalledWith(`Cache Size: ~60 MB (62915000 B)`);
expect(extractTarMock).toHaveBeenCalledTimes(1); expect(extractTarMock).toHaveBeenCalledTimes(1);
expect(extractTarMock).toHaveBeenCalledWith(archivePath, cachePath); expect(extractTarMock).toHaveBeenCalledWith(archivePath);
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1); expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
expect(setCacheHitOutputMock).toHaveBeenCalledWith(true); expect(setCacheHitOutputMock).toHaveBeenCalledWith(true);
@ -335,7 +334,6 @@ test("restore with a pull request event and cache found", async () => {
test("restore with cache found for restore key", async () => { test("restore with cache found for restore key", async () => {
const key = "node-test"; const key = "node-test";
const restoreKey = "node-"; const restoreKey = "node-";
const cachePath = path.resolve("node_modules");
testUtils.setInputs({ testUtils.setInputs({
path: "node_modules", path: "node_modules",
key, key,
@ -391,7 +389,7 @@ test("restore with cache found for restore key", async () => {
expect(infoMock).toHaveBeenCalledWith(`Cache Size: ~0 MB (142 B)`); expect(infoMock).toHaveBeenCalledWith(`Cache Size: ~0 MB (142 B)`);
expect(extractTarMock).toHaveBeenCalledTimes(1); expect(extractTarMock).toHaveBeenCalledTimes(1);
expect(extractTarMock).toHaveBeenCalledWith(archivePath, cachePath); expect(extractTarMock).toHaveBeenCalledWith(archivePath);
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1); expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
expect(setCacheHitOutputMock).toHaveBeenCalledWith(false); expect(setCacheHitOutputMock).toHaveBeenCalledWith(false);

View file

@ -159,10 +159,11 @@ test("save with missing input outputs warning", async () => {
await run(); await run();
expect(logWarningMock).toHaveBeenCalledWith( // TODO: this shouldn't be necessary if tarball contains entries relative to workspace
expect(logWarningMock).not.toHaveBeenCalledWith(
"Input required and not supplied: path" "Input required and not supplied: path"
); );
expect(logWarningMock).toHaveBeenCalledTimes(1); expect(logWarningMock).toHaveBeenCalledTimes(0);
expect(failedMock).toHaveBeenCalledTimes(0); expect(failedMock).toHaveBeenCalledTimes(0);
}); });
@ -189,7 +190,7 @@ test("save with large cache outputs warning", async () => {
}); });
const inputPath = "node_modules"; const inputPath = "node_modules";
const cachePath = path.resolve(inputPath); const cachePaths = [path.resolve(inputPath)];
testUtils.setInput(Inputs.Path, inputPath); testUtils.setInput(Inputs.Path, inputPath);
const createTarMock = jest.spyOn(tar, "createTar"); const createTarMock = jest.spyOn(tar, "createTar");
@ -204,7 +205,7 @@ test("save with large cache outputs warning", async () => {
const archivePath = path.join("/foo/bar", "cache.tgz"); const archivePath = path.join("/foo/bar", "cache.tgz");
expect(createTarMock).toHaveBeenCalledTimes(1); expect(createTarMock).toHaveBeenCalledTimes(1);
expect(createTarMock).toHaveBeenCalledWith(archivePath, cachePath); expect(createTarMock).toHaveBeenCalledWith(archivePath, cachePaths);
expect(logWarningMock).toHaveBeenCalledTimes(1); expect(logWarningMock).toHaveBeenCalledTimes(1);
expect(logWarningMock).toHaveBeenCalledWith( expect(logWarningMock).toHaveBeenCalledWith(
@ -288,7 +289,7 @@ test("save with server error outputs warning", async () => {
}); });
const inputPath = "node_modules"; const inputPath = "node_modules";
const cachePath = path.resolve(inputPath); const cachePaths = [path.resolve(inputPath)];
testUtils.setInput(Inputs.Path, inputPath); testUtils.setInput(Inputs.Path, inputPath);
const cacheId = 4; const cacheId = 4;
@ -314,7 +315,7 @@ test("save with server error outputs warning", async () => {
const archivePath = path.join("/foo/bar", "cache.tgz"); const archivePath = path.join("/foo/bar", "cache.tgz");
expect(createTarMock).toHaveBeenCalledTimes(1); expect(createTarMock).toHaveBeenCalledTimes(1);
expect(createTarMock).toHaveBeenCalledWith(archivePath, cachePath); expect(createTarMock).toHaveBeenCalledWith(archivePath, cachePaths);
expect(saveCacheMock).toHaveBeenCalledTimes(1); expect(saveCacheMock).toHaveBeenCalledTimes(1);
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archivePath); expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archivePath);
@ -347,7 +348,7 @@ test("save with valid inputs uploads a cache", async () => {
}); });
const inputPath = "node_modules"; const inputPath = "node_modules";
const cachePath = path.resolve(inputPath); const cachePaths = [path.resolve(inputPath)];
testUtils.setInput(Inputs.Path, inputPath); testUtils.setInput(Inputs.Path, inputPath);
const cacheId = 4; const cacheId = 4;
@ -369,7 +370,7 @@ test("save with valid inputs uploads a cache", async () => {
const archivePath = path.join("/foo/bar", "cache.tgz"); const archivePath = path.join("/foo/bar", "cache.tgz");
expect(createTarMock).toHaveBeenCalledTimes(1); expect(createTarMock).toHaveBeenCalledTimes(1);
expect(createTarMock).toHaveBeenCalledWith(archivePath, cachePath); expect(createTarMock).toHaveBeenCalledWith(archivePath, cachePaths);
expect(saveCacheMock).toHaveBeenCalledTimes(1); expect(saveCacheMock).toHaveBeenCalledTimes(1);
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archivePath); expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archivePath);

View file

@ -9,6 +9,12 @@ beforeAll(() => {
jest.spyOn(io, "which").mockImplementation(tool => { jest.spyOn(io, "which").mockImplementation(tool => {
return Promise.resolve(tool); return Promise.resolve(tool);
}); });
process.env["GITHUB_WORKSPACE"] = process.cwd();
});
afterAll(() => {
process.env["GITHUB_WORKSPACE"] = undefined;
}); });
test("extract tar", async () => { test("extract tar", async () => {
@ -16,10 +22,11 @@ test("extract tar", async () => {
const execMock = jest.spyOn(exec, "exec"); const execMock = jest.spyOn(exec, "exec");
const archivePath = "cache.tar"; const archivePath = "cache.tar";
const targetDirectory = "~/.npm/cache"; const workspace = process.env["GITHUB_WORKSPACE"];
await tar.extractTar(archivePath, targetDirectory);
expect(mkdirMock).toHaveBeenCalledWith(targetDirectory); await tar.extractTar(archivePath);
expect(mkdirMock).toHaveBeenCalledWith(workspace);
const IS_WINDOWS = process.platform === "win32"; const IS_WINDOWS = process.platform === "win32";
const tarPath = IS_WINDOWS const tarPath = IS_WINDOWS
@ -30,8 +37,9 @@ test("extract tar", async () => {
"-xz", "-xz",
"-f", "-f",
archivePath, archivePath,
"-P",
"-C", "-C",
targetDirectory workspace
]); ]);
}); });
@ -39,8 +47,10 @@ test("create tar", async () => {
const execMock = jest.spyOn(exec, "exec"); const execMock = jest.spyOn(exec, "exec");
const archivePath = "cache.tar"; const archivePath = "cache.tar";
const sourceDirectory = "~/.npm/cache"; const workspace = process.env["GITHUB_WORKSPACE"];
await tar.createTar(archivePath, sourceDirectory); const sourceDirectories = ["~/.npm/cache", `${workspace}/dist`];
await tar.createTar(archivePath, sourceDirectories);
const IS_WINDOWS = process.platform === "win32"; const IS_WINDOWS = process.platform === "win32";
const tarPath = IS_WINDOWS const tarPath = IS_WINDOWS
@ -52,7 +62,7 @@ test("create tar", async () => {
"-f", "-f",
archivePath, archivePath,
"-C", "-C",
sourceDirectory, workspace,
"." sourceDirectories.join(" ")
]); ]);
}); });

34
dist/restore/index.js vendored
View file

@ -2704,6 +2704,7 @@ var Inputs;
(function (Inputs) { (function (Inputs) {
Inputs["Key"] = "key"; Inputs["Key"] = "key";
Inputs["Path"] = "path"; Inputs["Path"] = "path";
Inputs["Paths"] = "paths";
Inputs["RestoreKeys"] = "restore-keys"; Inputs["RestoreKeys"] = "restore-keys";
})(Inputs = exports.Inputs || (exports.Inputs = {})); })(Inputs = exports.Inputs || (exports.Inputs = {}));
var Outputs; var Outputs;
@ -2802,8 +2803,10 @@ function run() {
.join(", ")} events are supported at this time.`); .join(", ")} events are supported at this time.`);
return; return;
} }
const cachePath = utils.resolvePath(core.getInput(constants_1.Inputs.Path, { required: true })); // const cachePath = utils.resolvePath(
core.debug(`Cache Path: ${cachePath}`); // core.getInput(Inputs.Path, { required: true })
// );
// core.debug(`Cache Path: ${cachePath}`);
const primaryKey = core.getInput(constants_1.Inputs.Key, { required: true }); const primaryKey = core.getInput(constants_1.Inputs.Key, { required: true });
core.saveState(constants_1.State.CacheKey, primaryKey); core.saveState(constants_1.State.CacheKey, primaryKey);
const restoreKeys = core const restoreKeys = core
@ -2831,7 +2834,7 @@ function run() {
try { try {
const cacheEntry = yield cacheHttpClient.getCacheEntry(keys); const cacheEntry = yield cacheHttpClient.getCacheEntry(keys);
if (!((_a = cacheEntry) === null || _a === void 0 ? void 0 : _a.archiveLocation)) { if (!((_a = cacheEntry) === null || _a === void 0 ? void 0 : _a.archiveLocation)) {
core.info(`Cache not found for input keys: ${keys.join(", ")}.`); core.info(`Cache not found for input keys: ${keys.join(", ")}`);
return; return;
} }
const archivePath = path.join(yield utils.createTempDirectory(), "cache.tgz"); const archivePath = path.join(yield utils.createTempDirectory(), "cache.tgz");
@ -2842,7 +2845,7 @@ function run() {
yield cacheHttpClient.downloadCache(cacheEntry.archiveLocation, archivePath); yield cacheHttpClient.downloadCache(cacheEntry.archiveLocation, archivePath);
const archiveFileSize = utils.getArchiveFileSize(archivePath); const archiveFileSize = utils.getArchiveFileSize(archivePath);
core.info(`Cache Size: ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B)`); core.info(`Cache Size: ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B)`);
yield tar_1.extractTar(archivePath, cachePath); yield tar_1.extractTar(archivePath);
const isExactKeyMatch = utils.isExactKeyMatch(primaryKey, cacheEntry); const isExactKeyMatch = utils.isExactKeyMatch(primaryKey, cacheEntry);
utils.setCacheHitOutput(isExactKeyMatch); utils.setCacheHitOutput(isExactKeyMatch);
core.info(`Cache restored from key: ${cacheEntry && cacheEntry.cacheKey}`); core.info(`Cache restored from key: ${cacheEntry && cacheEntry.cacheKey}`);
@ -2959,18 +2962,31 @@ function execTar(args) {
} }
}); });
} }
function extractTar(archivePath, targetDirectory) { function getWorkingDirectory() {
var _a;
return _a = process.env.GITHUB_WORKSPACE, (_a !== null && _a !== void 0 ? _a : process.cwd());
}
function extractTar(archivePath) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
// Create directory to extract tar into // Create directory to extract tar into
yield io.mkdirP(targetDirectory); const workingDirectory = getWorkingDirectory();
const args = ["-xz", "-f", archivePath, "-C", targetDirectory]; yield io.mkdirP(workingDirectory);
const args = ["-xz", "-f", archivePath, "-P", "-C", workingDirectory];
yield execTar(args); yield execTar(args);
}); });
} }
exports.extractTar = extractTar; exports.extractTar = extractTar;
function createTar(archivePath, sourceDirectory) { function createTar(archivePath, sourceDirectories) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const args = ["-cz", "-f", archivePath, "-C", sourceDirectory, "."]; const workingDirectory = getWorkingDirectory();
const args = [
"-cz",
"-f",
archivePath,
"-C",
workingDirectory,
sourceDirectories.join(" ")
];
yield execTar(args); yield execTar(args);
}); });
} }

35
dist/save/index.js vendored
View file

@ -2749,11 +2749,16 @@ function run() {
return; return;
} }
core.debug(`Cache ID: ${cacheId}`); core.debug(`Cache ID: ${cacheId}`);
const cachePath = utils.resolvePath(core.getInput(constants_1.Inputs.Path, { required: true })); const cachePaths = core
core.debug(`Cache Path: ${cachePath}`); .getInput(constants_1.Inputs.Path, { required: false })
.split("\n")
.filter(x => x !== "")
.map(x => utils.resolvePath(x));
core.debug("Cache Paths:");
core.debug(`${JSON.stringify(cachePaths)}`);
const archivePath = path.join(yield utils.createTempDirectory(), "cache.tgz"); const archivePath = path.join(yield utils.createTempDirectory(), "cache.tgz");
core.debug(`Archive Path: ${archivePath}`); core.debug(`Archive Path: ${archivePath}`);
yield tar_1.createTar(archivePath, cachePath); yield tar_1.createTar(archivePath, cachePaths);
const fileSizeLimit = 5 * 1024 * 1024 * 1024; // 5GB per repo limit const fileSizeLimit = 5 * 1024 * 1024 * 1024; // 5GB per repo limit
const archiveFileSize = utils.getArchiveFileSize(archivePath); const archiveFileSize = utils.getArchiveFileSize(archivePath);
core.debug(`File Size: ${archiveFileSize}`); core.debug(`File Size: ${archiveFileSize}`);
@ -2785,6 +2790,7 @@ var Inputs;
(function (Inputs) { (function (Inputs) {
Inputs["Key"] = "key"; Inputs["Key"] = "key";
Inputs["Path"] = "path"; Inputs["Path"] = "path";
Inputs["Paths"] = "paths";
Inputs["RestoreKeys"] = "restore-keys"; Inputs["RestoreKeys"] = "restore-keys";
})(Inputs = exports.Inputs || (exports.Inputs = {})); })(Inputs = exports.Inputs || (exports.Inputs = {}));
var Outputs; var Outputs;
@ -2940,18 +2946,31 @@ function execTar(args) {
} }
}); });
} }
function extractTar(archivePath, targetDirectory) { function getWorkingDirectory() {
var _a;
return _a = process.env.GITHUB_WORKSPACE, (_a !== null && _a !== void 0 ? _a : process.cwd());
}
function extractTar(archivePath) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
// Create directory to extract tar into // Create directory to extract tar into
yield io.mkdirP(targetDirectory); const workingDirectory = getWorkingDirectory();
const args = ["-xz", "-f", archivePath, "-C", targetDirectory]; yield io.mkdirP(workingDirectory);
const args = ["-xz", "-f", archivePath, "-P", "-C", workingDirectory];
yield execTar(args); yield execTar(args);
}); });
} }
exports.extractTar = extractTar; exports.extractTar = extractTar;
function createTar(archivePath, sourceDirectory) { function createTar(archivePath, sourceDirectories) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const args = ["-cz", "-f", archivePath, "-C", sourceDirectory, "."]; const workingDirectory = getWorkingDirectory();
const args = [
"-cz",
"-f",
archivePath,
"-C",
workingDirectory,
sourceDirectories.join(" ")
];
yield execTar(args); yield execTar(args);
}); });
} }

View file

@ -19,10 +19,10 @@ async function run(): Promise<void> {
return; return;
} }
const cachePath = utils.resolvePath( // const cachePath = utils.resolvePath(
core.getInput(Inputs.Path, { required: true }) // core.getInput(Inputs.Path, { required: true })
); // );
core.debug(`Cache Path: ${cachePath}`); // core.debug(`Cache Path: ${cachePath}`);
const primaryKey = core.getInput(Inputs.Key, { required: true }); const primaryKey = core.getInput(Inputs.Key, { required: true });
core.saveState(State.CacheKey, primaryKey); core.saveState(State.CacheKey, primaryKey);
@ -87,7 +87,7 @@ async function run(): Promise<void> {
)} MB (${archiveFileSize} B)` )} MB (${archiveFileSize} B)`
); );
await extractTar(archivePath, cachePath); await extractTar(archivePath);
const isExactKeyMatch = utils.isExactKeyMatch( const isExactKeyMatch = utils.isExactKeyMatch(
primaryKey, primaryKey,

View file

@ -43,10 +43,14 @@ async function run(): Promise<void> {
return; return;
} }
core.debug(`Cache ID: ${cacheId}`); core.debug(`Cache ID: ${cacheId}`);
const cachePath = utils.resolvePath( const cachePaths = core
core.getInput(Inputs.Path, { required: true }) .getInput(Inputs.Path)
); .split("\n")
core.debug(`Cache Path: ${cachePath}`); .filter(x => x !== "")
.map(x => utils.resolvePath(x));
core.debug("Cache Paths:");
core.debug(`${JSON.stringify(cachePaths)}`);
const archivePath = path.join( const archivePath = path.join(
await utils.createTempDirectory(), await utils.createTempDirectory(),
@ -54,7 +58,7 @@ async function run(): Promise<void> {
); );
core.debug(`Archive Path: ${archivePath}`); core.debug(`Archive Path: ${archivePath}`);
await createTar(archivePath, cachePath); await createTar(archivePath, cachePaths);
const fileSizeLimit = 5 * 1024 * 1024 * 1024; // 5GB per repo limit const fileSizeLimit = 5 * 1024 * 1024 * 1024; // 5GB per repo limit
const archiveFileSize = utils.getArchiveFileSize(archivePath); const archiveFileSize = utils.getArchiveFileSize(archivePath);

View file

@ -28,20 +28,30 @@ async function execTar(args: string[]): Promise<void> {
} }
} }
export async function extractTar( function getWorkingDirectory(): string {
archivePath: string, return process.env["GITHUB_WORKSPACE"] ?? process.cwd();
targetDirectory: string }
): Promise<void> {
export async function extractTar(archivePath: string): Promise<void> {
// Create directory to extract tar into // Create directory to extract tar into
await io.mkdirP(targetDirectory); const workingDirectory = getWorkingDirectory();
const args = ["-xz", "-f", archivePath, "-C", targetDirectory]; await io.mkdirP(workingDirectory);
const args = ["-xz", "-f", archivePath, "-P", "-C", workingDirectory];
await execTar(args); await execTar(args);
} }
export async function createTar( export async function createTar(
archivePath: string, archivePath: string,
sourceDirectory: string sourceDirectories: string[]
): Promise<void> { ): Promise<void> {
const args = ["-cz", "-f", archivePath, "-C", sourceDirectory, "."]; const workingDirectory = getWorkingDirectory();
const args = [
"-cz",
"-f",
archivePath,
"-C",
workingDirectory,
sourceDirectories.join(" ")
];
await execTar(args); await execTar(args);
} }