mirror of
https://code.forgejo.org/actions/cache.git
synced 2024-11-06 03:55:52 +00:00
Use zstd instead of gzip if available
Add zstd to cache versioning
This commit is contained in:
parent
9ceee97d99
commit
97f7baa910
14 changed files with 523 additions and 201 deletions
|
@ -1,12 +1,12 @@
|
||||||
import { getCacheVersion } from "../src/cacheHttpClient";
|
import { getCacheVersion } from "../src/cacheHttpClient";
|
||||||
import { Inputs } from "../src/constants";
|
import { CompressionMethod, Inputs } from "../src/constants";
|
||||||
import * as testUtils from "../src/utils/testUtils";
|
import * as testUtils from "../src/utils/testUtils";
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
testUtils.clearInputs();
|
testUtils.clearInputs();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("getCacheVersion with path input returns version", async () => {
|
test("getCacheVersion with path input and compression method undefined returns version", async () => {
|
||||||
testUtils.setInput(Inputs.Path, "node_modules");
|
testUtils.setInput(Inputs.Path, "node_modules");
|
||||||
|
|
||||||
const result = getCacheVersion();
|
const result = getCacheVersion();
|
||||||
|
@ -16,6 +16,24 @@ test("getCacheVersion with path input returns version", async () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("getCacheVersion with zstd compression returns version", async () => {
|
||||||
|
testUtils.setInput(Inputs.Path, "node_modules");
|
||||||
|
const result = getCacheVersion(CompressionMethod.Zstd);
|
||||||
|
|
||||||
|
expect(result).toEqual(
|
||||||
|
"273877e14fd65d270b87a198edbfa2db5a43de567c9a548d2a2505b408befe24"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("getCacheVersion with gzip compression does not change vesion", async () => {
|
||||||
|
testUtils.setInput(Inputs.Path, "node_modules");
|
||||||
|
const result = getCacheVersion(CompressionMethod.Gzip);
|
||||||
|
|
||||||
|
expect(result).toEqual(
|
||||||
|
"b3e0c6cb5ecf32614eeb2997d905b9c297046d7cbf69062698f25b14b4cb0985"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
test("getCacheVersion with no input throws", async () => {
|
test("getCacheVersion with no input throws", async () => {
|
||||||
expect(() => getCacheVersion()).toThrow();
|
expect(() => getCacheVersion()).toThrow();
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,12 @@ import * as core from "@actions/core";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
|
||||||
import * as cacheHttpClient from "../src/cacheHttpClient";
|
import * as cacheHttpClient from "../src/cacheHttpClient";
|
||||||
import { Events, Inputs } from "../src/constants";
|
import {
|
||||||
|
CacheFilename,
|
||||||
|
CompressionMethod,
|
||||||
|
Events,
|
||||||
|
Inputs
|
||||||
|
} from "../src/constants";
|
||||||
import { ArtifactCacheEntry } from "../src/contracts";
|
import { ArtifactCacheEntry } from "../src/contracts";
|
||||||
import run from "../src/restore";
|
import run from "../src/restore";
|
||||||
import * as tar from "../src/tar";
|
import * as tar from "../src/tar";
|
||||||
|
@ -30,6 +35,11 @@ beforeAll(() => {
|
||||||
const actualUtils = jest.requireActual("../src/utils/actionUtils");
|
const actualUtils = jest.requireActual("../src/utils/actionUtils");
|
||||||
return actualUtils.getSupportedEvents();
|
return actualUtils.getSupportedEvents();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jest.spyOn(actionUtils, "getCacheFileName").mockImplementation(cm => {
|
||||||
|
const actualUtils = jest.requireActual("../src/utils/actionUtils");
|
||||||
|
return actualUtils.getCacheFileName(cm);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -197,7 +207,7 @@ test("restore with restore keys and no cache found", async () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("restore with cache found", async () => {
|
test("restore with gzip compressed cache found", async () => {
|
||||||
const key = "node-test";
|
const key = "node-test";
|
||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: "node_modules",
|
path: "node_modules",
|
||||||
|
@ -227,7 +237,7 @@ test("restore with cache found", async () => {
|
||||||
return Promise.resolve(tempPath);
|
return Promise.resolve(tempPath);
|
||||||
});
|
});
|
||||||
|
|
||||||
const archivePath = path.join(tempPath, "cache.tgz");
|
const archivePath = path.join(tempPath, CacheFilename.Gzip);
|
||||||
const setCacheStateMock = jest.spyOn(actionUtils, "setCacheState");
|
const setCacheStateMock = jest.spyOn(actionUtils, "setCacheState");
|
||||||
const downloadCacheMock = jest.spyOn(cacheHttpClient, "downloadCache");
|
const downloadCacheMock = jest.spyOn(cacheHttpClient, "downloadCache");
|
||||||
|
|
||||||
|
@ -240,10 +250,17 @@ test("restore with cache found", async () => {
|
||||||
const unlinkFileMock = jest.spyOn(actionUtils, "unlinkFile");
|
const unlinkFileMock = jest.spyOn(actionUtils, "unlinkFile");
|
||||||
const setCacheHitOutputMock = jest.spyOn(actionUtils, "setCacheHitOutput");
|
const setCacheHitOutputMock = jest.spyOn(actionUtils, "setCacheHitOutput");
|
||||||
|
|
||||||
|
const compression = CompressionMethod.Gzip;
|
||||||
|
const getCompressionMock = jest
|
||||||
|
.spyOn(actionUtils, "getCompressionMethod")
|
||||||
|
.mockReturnValue(Promise.resolve(compression));
|
||||||
|
|
||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
||||||
expect(getCacheMock).toHaveBeenCalledWith([key]);
|
expect(getCacheMock).toHaveBeenCalledWith([key], {
|
||||||
|
compressionMethod: compression
|
||||||
|
});
|
||||||
expect(setCacheStateMock).toHaveBeenCalledWith(cacheEntry);
|
expect(setCacheStateMock).toHaveBeenCalledWith(cacheEntry);
|
||||||
expect(createTempDirectoryMock).toHaveBeenCalledTimes(1);
|
expect(createTempDirectoryMock).toHaveBeenCalledTimes(1);
|
||||||
expect(downloadCacheMock).toHaveBeenCalledWith(
|
expect(downloadCacheMock).toHaveBeenCalledWith(
|
||||||
|
@ -253,7 +270,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);
|
expect(extractTarMock).toHaveBeenCalledWith(archivePath, compression);
|
||||||
|
|
||||||
expect(unlinkFileMock).toHaveBeenCalledTimes(1);
|
expect(unlinkFileMock).toHaveBeenCalledTimes(1);
|
||||||
expect(unlinkFileMock).toHaveBeenCalledWith(archivePath);
|
expect(unlinkFileMock).toHaveBeenCalledWith(archivePath);
|
||||||
|
@ -263,9 +280,10 @@ test("restore with cache found", async () => {
|
||||||
|
|
||||||
expect(infoMock).toHaveBeenCalledWith(`Cache restored from key: ${key}`);
|
expect(infoMock).toHaveBeenCalledWith(`Cache restored from key: ${key}`);
|
||||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||||
|
expect(getCompressionMock).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("restore with a pull request event and cache found", async () => {
|
test("restore with a pull request event and zstd compressed cache found", async () => {
|
||||||
const key = "node-test";
|
const key = "node-test";
|
||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: "node_modules",
|
path: "node_modules",
|
||||||
|
@ -297,7 +315,7 @@ test("restore with a pull request event and cache found", async () => {
|
||||||
return Promise.resolve(tempPath);
|
return Promise.resolve(tempPath);
|
||||||
});
|
});
|
||||||
|
|
||||||
const archivePath = path.join(tempPath, "cache.tgz");
|
const archivePath = path.join(tempPath, CacheFilename.Zstd);
|
||||||
const setCacheStateMock = jest.spyOn(actionUtils, "setCacheState");
|
const setCacheStateMock = jest.spyOn(actionUtils, "setCacheState");
|
||||||
const downloadCacheMock = jest.spyOn(cacheHttpClient, "downloadCache");
|
const downloadCacheMock = jest.spyOn(cacheHttpClient, "downloadCache");
|
||||||
|
|
||||||
|
@ -308,11 +326,17 @@ test("restore with a pull request event and cache found", async () => {
|
||||||
|
|
||||||
const extractTarMock = jest.spyOn(tar, "extractTar");
|
const extractTarMock = jest.spyOn(tar, "extractTar");
|
||||||
const setCacheHitOutputMock = jest.spyOn(actionUtils, "setCacheHitOutput");
|
const setCacheHitOutputMock = jest.spyOn(actionUtils, "setCacheHitOutput");
|
||||||
|
const compression = CompressionMethod.Zstd;
|
||||||
|
const getCompressionMock = jest
|
||||||
|
.spyOn(actionUtils, "getCompressionMethod")
|
||||||
|
.mockReturnValue(Promise.resolve(compression));
|
||||||
|
|
||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
||||||
expect(getCacheMock).toHaveBeenCalledWith([key]);
|
expect(getCacheMock).toHaveBeenCalledWith([key], {
|
||||||
|
compressionMethod: compression
|
||||||
|
});
|
||||||
expect(setCacheStateMock).toHaveBeenCalledWith(cacheEntry);
|
expect(setCacheStateMock).toHaveBeenCalledWith(cacheEntry);
|
||||||
expect(createTempDirectoryMock).toHaveBeenCalledTimes(1);
|
expect(createTempDirectoryMock).toHaveBeenCalledTimes(1);
|
||||||
expect(downloadCacheMock).toHaveBeenCalledWith(
|
expect(downloadCacheMock).toHaveBeenCalledWith(
|
||||||
|
@ -323,13 +347,14 @@ 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);
|
expect(extractTarMock).toHaveBeenCalledWith(archivePath, compression);
|
||||||
|
|
||||||
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
||||||
expect(setCacheHitOutputMock).toHaveBeenCalledWith(true);
|
expect(setCacheHitOutputMock).toHaveBeenCalledWith(true);
|
||||||
|
|
||||||
expect(infoMock).toHaveBeenCalledWith(`Cache restored from key: ${key}`);
|
expect(infoMock).toHaveBeenCalledWith(`Cache restored from key: ${key}`);
|
||||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||||
|
expect(getCompressionMock).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("restore with cache found for restore key", async () => {
|
test("restore with cache found for restore key", async () => {
|
||||||
|
@ -364,7 +389,7 @@ test("restore with cache found for restore key", async () => {
|
||||||
return Promise.resolve(tempPath);
|
return Promise.resolve(tempPath);
|
||||||
});
|
});
|
||||||
|
|
||||||
const archivePath = path.join(tempPath, "cache.tgz");
|
const archivePath = path.join(tempPath, CacheFilename.Zstd);
|
||||||
const setCacheStateMock = jest.spyOn(actionUtils, "setCacheState");
|
const setCacheStateMock = jest.spyOn(actionUtils, "setCacheState");
|
||||||
const downloadCacheMock = jest.spyOn(cacheHttpClient, "downloadCache");
|
const downloadCacheMock = jest.spyOn(cacheHttpClient, "downloadCache");
|
||||||
|
|
||||||
|
@ -375,11 +400,17 @@ test("restore with cache found for restore key", async () => {
|
||||||
|
|
||||||
const extractTarMock = jest.spyOn(tar, "extractTar");
|
const extractTarMock = jest.spyOn(tar, "extractTar");
|
||||||
const setCacheHitOutputMock = jest.spyOn(actionUtils, "setCacheHitOutput");
|
const setCacheHitOutputMock = jest.spyOn(actionUtils, "setCacheHitOutput");
|
||||||
|
const compression = CompressionMethod.Zstd;
|
||||||
|
const getCompressionMock = jest
|
||||||
|
.spyOn(actionUtils, "getCompressionMethod")
|
||||||
|
.mockReturnValue(Promise.resolve(compression));
|
||||||
|
|
||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
||||||
expect(getCacheMock).toHaveBeenCalledWith([key, restoreKey]);
|
expect(getCacheMock).toHaveBeenCalledWith([key, restoreKey], {
|
||||||
|
compressionMethod: compression
|
||||||
|
});
|
||||||
expect(setCacheStateMock).toHaveBeenCalledWith(cacheEntry);
|
expect(setCacheStateMock).toHaveBeenCalledWith(cacheEntry);
|
||||||
expect(createTempDirectoryMock).toHaveBeenCalledTimes(1);
|
expect(createTempDirectoryMock).toHaveBeenCalledTimes(1);
|
||||||
expect(downloadCacheMock).toHaveBeenCalledWith(
|
expect(downloadCacheMock).toHaveBeenCalledWith(
|
||||||
|
@ -390,7 +421,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);
|
expect(extractTarMock).toHaveBeenCalledWith(archivePath, compression);
|
||||||
|
|
||||||
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
||||||
expect(setCacheHitOutputMock).toHaveBeenCalledWith(false);
|
expect(setCacheHitOutputMock).toHaveBeenCalledWith(false);
|
||||||
|
@ -399,4 +430,5 @@ test("restore with cache found for restore key", async () => {
|
||||||
`Cache restored from key: ${restoreKey}`
|
`Cache restored from key: ${restoreKey}`
|
||||||
);
|
);
|
||||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||||
|
expect(getCompressionMock).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,12 @@ import * as core from "@actions/core";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
|
||||||
import * as cacheHttpClient from "../src/cacheHttpClient";
|
import * as cacheHttpClient from "../src/cacheHttpClient";
|
||||||
import { CacheFilename, Events, Inputs } from "../src/constants";
|
import {
|
||||||
|
CacheFilename,
|
||||||
|
CompressionMethod,
|
||||||
|
Events,
|
||||||
|
Inputs
|
||||||
|
} from "../src/constants";
|
||||||
import { ArtifactCacheEntry } from "../src/contracts";
|
import { ArtifactCacheEntry } from "../src/contracts";
|
||||||
import run from "../src/save";
|
import run from "../src/save";
|
||||||
import * as tar from "../src/tar";
|
import * as tar from "../src/tar";
|
||||||
|
@ -50,6 +55,11 @@ beforeAll(() => {
|
||||||
jest.spyOn(actionUtils, "createTempDirectory").mockImplementation(() => {
|
jest.spyOn(actionUtils, "createTempDirectory").mockImplementation(() => {
|
||||||
return Promise.resolve("/foo/bar");
|
return Promise.resolve("/foo/bar");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jest.spyOn(actionUtils, "getCacheFileName").mockImplementation(cm => {
|
||||||
|
const actualUtils = jest.requireActual("../src/utils/actionUtils");
|
||||||
|
return actualUtils.getCacheFileName(cm);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -201,20 +211,27 @@ test("save with large cache outputs warning", async () => {
|
||||||
jest.spyOn(actionUtils, "getArchiveFileSize").mockImplementationOnce(() => {
|
jest.spyOn(actionUtils, "getArchiveFileSize").mockImplementationOnce(() => {
|
||||||
return cacheSize;
|
return cacheSize;
|
||||||
});
|
});
|
||||||
|
const compression = CompressionMethod.Gzip;
|
||||||
|
const getCompressionMock = jest
|
||||||
|
.spyOn(actionUtils, "getCompressionMethod")
|
||||||
|
.mockReturnValue(Promise.resolve(compression));
|
||||||
|
|
||||||
await run();
|
await run();
|
||||||
|
|
||||||
const archiveFolder = "/foo/bar";
|
const archiveFolder = "/foo/bar";
|
||||||
|
|
||||||
expect(createTarMock).toHaveBeenCalledTimes(1);
|
expect(createTarMock).toHaveBeenCalledTimes(1);
|
||||||
expect(createTarMock).toHaveBeenCalledWith(archiveFolder, cachePaths);
|
expect(createTarMock).toHaveBeenCalledWith(
|
||||||
|
archiveFolder,
|
||||||
|
cachePaths,
|
||||||
|
compression
|
||||||
|
);
|
||||||
expect(logWarningMock).toHaveBeenCalledTimes(1);
|
expect(logWarningMock).toHaveBeenCalledTimes(1);
|
||||||
expect(logWarningMock).toHaveBeenCalledWith(
|
expect(logWarningMock).toHaveBeenCalledWith(
|
||||||
"Cache size of ~6144 MB (6442450944 B) is over the 5GB limit, not saving cache."
|
"Cache size of ~6144 MB (6442450944 B) is over the 5GB limit, not saving cache."
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||||
|
expect(getCompressionMock).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("save with reserve cache failure outputs warning", async () => {
|
test("save with reserve cache failure outputs warning", async () => {
|
||||||
|
@ -250,13 +267,18 @@ test("save with reserve cache failure outputs warning", async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const createTarMock = jest.spyOn(tar, "createTar");
|
const createTarMock = jest.spyOn(tar, "createTar");
|
||||||
|
|
||||||
const saveCacheMock = jest.spyOn(cacheHttpClient, "saveCache");
|
const saveCacheMock = jest.spyOn(cacheHttpClient, "saveCache");
|
||||||
|
const compression = CompressionMethod.Zstd;
|
||||||
|
const getCompressionMock = jest
|
||||||
|
.spyOn(actionUtils, "getCompressionMethod")
|
||||||
|
.mockReturnValue(Promise.resolve(compression));
|
||||||
|
|
||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(reserveCacheMock).toHaveBeenCalledTimes(1);
|
expect(reserveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey);
|
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, {
|
||||||
|
compressionMethod: compression
|
||||||
|
});
|
||||||
|
|
||||||
expect(infoMock).toHaveBeenCalledWith(
|
expect(infoMock).toHaveBeenCalledWith(
|
||||||
`Unable to reserve cache with key ${primaryKey}, another job may be creating this cache.`
|
`Unable to reserve cache with key ${primaryKey}, another job may be creating this cache.`
|
||||||
|
@ -266,6 +288,7 @@ test("save with reserve cache failure outputs warning", async () => {
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(0);
|
expect(saveCacheMock).toHaveBeenCalledTimes(0);
|
||||||
expect(logWarningMock).toHaveBeenCalledTimes(0);
|
expect(logWarningMock).toHaveBeenCalledTimes(0);
|
||||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||||
|
expect(getCompressionMock).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("save with server error outputs warning", async () => {
|
test("save with server error outputs warning", async () => {
|
||||||
|
@ -308,17 +331,27 @@ test("save with server error outputs warning", async () => {
|
||||||
.mockImplementationOnce(() => {
|
.mockImplementationOnce(() => {
|
||||||
throw new Error("HTTP Error Occurred");
|
throw new Error("HTTP Error Occurred");
|
||||||
});
|
});
|
||||||
|
const compression = CompressionMethod.Zstd;
|
||||||
|
const getCompressionMock = jest
|
||||||
|
.spyOn(actionUtils, "getCompressionMethod")
|
||||||
|
.mockReturnValue(Promise.resolve(compression));
|
||||||
|
|
||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(reserveCacheMock).toHaveBeenCalledTimes(1);
|
expect(reserveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey);
|
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, {
|
||||||
|
compressionMethod: compression
|
||||||
|
});
|
||||||
|
|
||||||
const archiveFolder = "/foo/bar";
|
const archiveFolder = "/foo/bar";
|
||||||
const archiveFile = path.join(archiveFolder, CacheFilename);
|
const archiveFile = path.join(archiveFolder, CacheFilename.Zstd);
|
||||||
|
|
||||||
expect(createTarMock).toHaveBeenCalledTimes(1);
|
expect(createTarMock).toHaveBeenCalledTimes(1);
|
||||||
expect(createTarMock).toHaveBeenCalledWith(archiveFolder, cachePaths);
|
expect(createTarMock).toHaveBeenCalledWith(
|
||||||
|
archiveFolder,
|
||||||
|
cachePaths,
|
||||||
|
compression
|
||||||
|
);
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile);
|
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile);
|
||||||
|
@ -327,6 +360,7 @@ test("save with server error outputs warning", async () => {
|
||||||
expect(logWarningMock).toHaveBeenCalledWith("HTTP Error Occurred");
|
expect(logWarningMock).toHaveBeenCalledWith("HTTP Error Occurred");
|
||||||
|
|
||||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||||
|
expect(getCompressionMock).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("save with valid inputs uploads a cache", async () => {
|
test("save with valid inputs uploads a cache", async () => {
|
||||||
|
@ -364,20 +398,31 @@ test("save with valid inputs uploads a cache", async () => {
|
||||||
const createTarMock = jest.spyOn(tar, "createTar");
|
const createTarMock = jest.spyOn(tar, "createTar");
|
||||||
|
|
||||||
const saveCacheMock = jest.spyOn(cacheHttpClient, "saveCache");
|
const saveCacheMock = jest.spyOn(cacheHttpClient, "saveCache");
|
||||||
|
const compression = CompressionMethod.Zstd;
|
||||||
|
const getCompressionMock = jest
|
||||||
|
.spyOn(actionUtils, "getCompressionMethod")
|
||||||
|
.mockReturnValue(Promise.resolve(compression));
|
||||||
|
|
||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(reserveCacheMock).toHaveBeenCalledTimes(1);
|
expect(reserveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey);
|
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, {
|
||||||
|
compressionMethod: compression
|
||||||
|
});
|
||||||
|
|
||||||
const archiveFolder = "/foo/bar";
|
const archiveFolder = "/foo/bar";
|
||||||
const archiveFile = path.join(archiveFolder, CacheFilename);
|
const archiveFile = path.join(archiveFolder, CacheFilename.Zstd);
|
||||||
|
|
||||||
expect(createTarMock).toHaveBeenCalledTimes(1);
|
expect(createTarMock).toHaveBeenCalledTimes(1);
|
||||||
expect(createTarMock).toHaveBeenCalledWith(archiveFolder, cachePaths);
|
expect(createTarMock).toHaveBeenCalledWith(
|
||||||
|
archiveFolder,
|
||||||
|
cachePaths,
|
||||||
|
compression
|
||||||
|
);
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile);
|
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile);
|
||||||
|
|
||||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||||
|
expect(getCompressionMock).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,14 +2,17 @@ import * as exec from "@actions/exec";
|
||||||
import * as io from "@actions/io";
|
import * as io from "@actions/io";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
|
||||||
import { CacheFilename } from "../src/constants";
|
import { CacheFilename, CompressionMethod } from "../src/constants";
|
||||||
import * as tar from "../src/tar";
|
import * as tar from "../src/tar";
|
||||||
|
import * as utils from "../src/utils/actionUtils";
|
||||||
|
|
||||||
import fs = require("fs");
|
import fs = require("fs");
|
||||||
|
|
||||||
jest.mock("@actions/exec");
|
jest.mock("@actions/exec");
|
||||||
jest.mock("@actions/io");
|
jest.mock("@actions/io");
|
||||||
|
|
||||||
|
const IS_WINDOWS = process.platform === "win32";
|
||||||
|
|
||||||
function getTempDir(): string {
|
function getTempDir(): string {
|
||||||
return path.join(__dirname, "_temp", "tar");
|
return path.join(__dirname, "_temp", "tar");
|
||||||
}
|
}
|
||||||
|
@ -28,29 +31,28 @@ afterAll(async () => {
|
||||||
await jest.requireActual("@actions/io").rmRF(getTempDir());
|
await jest.requireActual("@actions/io").rmRF(getTempDir());
|
||||||
});
|
});
|
||||||
|
|
||||||
test("extract BSD tar", async () => {
|
test("zstd extract tar", async () => {
|
||||||
const mkdirMock = jest.spyOn(io, "mkdirP");
|
const mkdirMock = jest.spyOn(io, "mkdirP");
|
||||||
const execMock = jest.spyOn(exec, "exec");
|
const execMock = jest.spyOn(exec, "exec");
|
||||||
|
|
||||||
const IS_WINDOWS = process.platform === "win32";
|
|
||||||
const archivePath = IS_WINDOWS
|
const archivePath = IS_WINDOWS
|
||||||
? `${process.env["windir"]}\\fakepath\\cache.tar`
|
? `${process.env["windir"]}\\fakepath\\cache.tar`
|
||||||
: "cache.tar";
|
: "cache.tar";
|
||||||
const workspace = process.env["GITHUB_WORKSPACE"];
|
const workspace = process.env["GITHUB_WORKSPACE"];
|
||||||
|
|
||||||
await tar.extractTar(archivePath);
|
await tar.extractTar(archivePath, CompressionMethod.Zstd);
|
||||||
|
|
||||||
expect(mkdirMock).toHaveBeenCalledWith(workspace);
|
expect(mkdirMock).toHaveBeenCalledWith(workspace);
|
||||||
|
|
||||||
const tarPath = IS_WINDOWS
|
const tarPath = IS_WINDOWS
|
||||||
? `${process.env["windir"]}\\System32\\tar.exe`
|
? `${process.env["windir"]}\\System32\\tar.exe`
|
||||||
: "tar";
|
: "tar";
|
||||||
expect(execMock).toHaveBeenCalledTimes(1);
|
expect(execMock).toHaveBeenCalledTimes(1);
|
||||||
expect(execMock).toHaveBeenCalledWith(
|
expect(execMock).toHaveBeenCalledWith(
|
||||||
`"${tarPath}"`,
|
`${tarPath}`,
|
||||||
[
|
[
|
||||||
"-xz",
|
"--use-compress-program",
|
||||||
"-f",
|
"zstd -d",
|
||||||
|
"-xf",
|
||||||
IS_WINDOWS ? archivePath.replace(/\\/g, "/") : archivePath,
|
IS_WINDOWS ? archivePath.replace(/\\/g, "/") : archivePath,
|
||||||
"-P",
|
"-P",
|
||||||
"-C",
|
"-C",
|
||||||
|
@ -60,24 +62,55 @@ test("extract BSD tar", async () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("extract GNU tar", async () => {
|
test("gzip extract tar", async () => {
|
||||||
const IS_WINDOWS = process.platform === "win32";
|
const mkdirMock = jest.spyOn(io, "mkdirP");
|
||||||
|
const execMock = jest.spyOn(exec, "exec");
|
||||||
|
const archivePath = IS_WINDOWS
|
||||||
|
? `${process.env["windir"]}\\fakepath\\cache.tar`
|
||||||
|
: "cache.tar";
|
||||||
|
const workspace = process.env["GITHUB_WORKSPACE"];
|
||||||
|
|
||||||
|
await tar.extractTar(archivePath, CompressionMethod.Gzip);
|
||||||
|
|
||||||
|
expect(mkdirMock).toHaveBeenCalledWith(workspace);
|
||||||
|
const tarPath = IS_WINDOWS
|
||||||
|
? `${process.env["windir"]}\\System32\\tar.exe`
|
||||||
|
: "tar";
|
||||||
|
expect(execMock).toHaveBeenCalledTimes(1);
|
||||||
|
expect(execMock).toHaveBeenCalledWith(
|
||||||
|
`${tarPath}`,
|
||||||
|
[
|
||||||
|
"-z",
|
||||||
|
"-xf",
|
||||||
|
IS_WINDOWS ? archivePath.replace(/\\/g, "/") : archivePath,
|
||||||
|
"-P",
|
||||||
|
"-C",
|
||||||
|
IS_WINDOWS ? workspace?.replace(/\\/g, "/") : workspace
|
||||||
|
],
|
||||||
|
{ cwd: undefined }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("gzip extract GNU tar on windows", async () => {
|
||||||
if (IS_WINDOWS) {
|
if (IS_WINDOWS) {
|
||||||
jest.spyOn(fs, "existsSync").mockReturnValueOnce(false);
|
jest.spyOn(fs, "existsSync").mockReturnValueOnce(false);
|
||||||
jest.spyOn(tar, "isGnuTar").mockReturnValue(Promise.resolve(true));
|
|
||||||
|
|
||||||
|
const isGnuMock = jest
|
||||||
|
.spyOn(utils, "useGnuTar")
|
||||||
|
.mockReturnValue(Promise.resolve(true));
|
||||||
const execMock = jest.spyOn(exec, "exec");
|
const execMock = jest.spyOn(exec, "exec");
|
||||||
const archivePath = `${process.env["windir"]}\\fakepath\\cache.tar`;
|
const archivePath = `${process.env["windir"]}\\fakepath\\cache.tar`;
|
||||||
const workspace = process.env["GITHUB_WORKSPACE"];
|
const workspace = process.env["GITHUB_WORKSPACE"];
|
||||||
|
|
||||||
await tar.extractTar(archivePath);
|
await tar.extractTar(archivePath, CompressionMethod.Gzip);
|
||||||
|
|
||||||
expect(execMock).toHaveBeenCalledTimes(2);
|
expect(isGnuMock).toHaveBeenCalledTimes(1);
|
||||||
expect(execMock).toHaveBeenLastCalledWith(
|
expect(execMock).toHaveBeenCalledTimes(1);
|
||||||
`"tar"`,
|
expect(execMock).toHaveBeenCalledWith(
|
||||||
|
`tar`,
|
||||||
[
|
[
|
||||||
"-xz",
|
"-z",
|
||||||
"-f",
|
"-xf",
|
||||||
archivePath.replace(/\\/g, "/"),
|
archivePath.replace(/\\/g, "/"),
|
||||||
"-P",
|
"-P",
|
||||||
"-C",
|
"-C",
|
||||||
|
@ -89,7 +122,7 @@ test("extract GNU tar", async () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("create BSD tar", async () => {
|
test("zstd create tar", async () => {
|
||||||
const execMock = jest.spyOn(exec, "exec");
|
const execMock = jest.spyOn(exec, "exec");
|
||||||
|
|
||||||
const archiveFolder = getTempDir();
|
const archiveFolder = getTempDir();
|
||||||
|
@ -98,20 +131,66 @@ test("create BSD tar", async () => {
|
||||||
|
|
||||||
await fs.promises.mkdir(archiveFolder, { recursive: true });
|
await fs.promises.mkdir(archiveFolder, { recursive: true });
|
||||||
|
|
||||||
await tar.createTar(archiveFolder, sourceDirectories);
|
await tar.createTar(
|
||||||
|
archiveFolder,
|
||||||
|
sourceDirectories,
|
||||||
|
CompressionMethod.Zstd
|
||||||
|
);
|
||||||
|
|
||||||
const IS_WINDOWS = process.platform === "win32";
|
|
||||||
const tarPath = IS_WINDOWS
|
const tarPath = IS_WINDOWS
|
||||||
? `${process.env["windir"]}\\System32\\tar.exe`
|
? `${process.env["windir"]}\\System32\\tar.exe`
|
||||||
: "tar";
|
: "tar";
|
||||||
|
|
||||||
expect(execMock).toHaveBeenCalledTimes(1);
|
expect(execMock).toHaveBeenCalledTimes(1);
|
||||||
expect(execMock).toHaveBeenCalledWith(
|
expect(execMock).toHaveBeenCalledWith(
|
||||||
`"${tarPath}"`,
|
`${tarPath}`,
|
||||||
[
|
[
|
||||||
"-cz",
|
"--use-compress-program",
|
||||||
"-f",
|
"zstd -T0",
|
||||||
IS_WINDOWS ? CacheFilename.replace(/\\/g, "/") : CacheFilename,
|
"-cf",
|
||||||
|
IS_WINDOWS
|
||||||
|
? CacheFilename.Zstd.replace(/\\/g, "/")
|
||||||
|
: CacheFilename.Zstd,
|
||||||
|
"-P",
|
||||||
|
"-C",
|
||||||
|
IS_WINDOWS ? workspace?.replace(/\\/g, "/") : workspace,
|
||||||
|
"--files-from",
|
||||||
|
"manifest.txt"
|
||||||
|
],
|
||||||
|
{
|
||||||
|
cwd: archiveFolder
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("gzip create tar", async () => {
|
||||||
|
const execMock = jest.spyOn(exec, "exec");
|
||||||
|
|
||||||
|
const archiveFolder = getTempDir();
|
||||||
|
const workspace = process.env["GITHUB_WORKSPACE"];
|
||||||
|
const sourceDirectories = ["~/.npm/cache", `${workspace}/dist`];
|
||||||
|
|
||||||
|
await fs.promises.mkdir(archiveFolder, { recursive: true });
|
||||||
|
|
||||||
|
await tar.createTar(
|
||||||
|
archiveFolder,
|
||||||
|
sourceDirectories,
|
||||||
|
CompressionMethod.Gzip
|
||||||
|
);
|
||||||
|
|
||||||
|
const tarPath = IS_WINDOWS
|
||||||
|
? `${process.env["windir"]}\\System32\\tar.exe`
|
||||||
|
: "tar";
|
||||||
|
|
||||||
|
expect(execMock).toHaveBeenCalledTimes(1);
|
||||||
|
expect(execMock).toHaveBeenCalledWith(
|
||||||
|
`${tarPath}`,
|
||||||
|
[
|
||||||
|
"-z",
|
||||||
|
"-cf",
|
||||||
|
IS_WINDOWS
|
||||||
|
? CacheFilename.Gzip.replace(/\\/g, "/")
|
||||||
|
: CacheFilename.Gzip,
|
||||||
"-P",
|
"-P",
|
||||||
"-C",
|
"-C",
|
||||||
IS_WINDOWS ? workspace?.replace(/\\/g, "/") : workspace,
|
IS_WINDOWS ? workspace?.replace(/\\/g, "/") : workspace,
|
||||||
|
|
140
dist/restore/index.js
vendored
140
dist/restore/index.js
vendored
|
@ -2236,23 +2236,22 @@ function createHttpClient() {
|
||||||
const bearerCredentialHandler = new auth_1.BearerCredentialHandler(token);
|
const bearerCredentialHandler = new auth_1.BearerCredentialHandler(token);
|
||||||
return new http_client_1.HttpClient("actions/cache", [bearerCredentialHandler], getRequestOptions());
|
return new http_client_1.HttpClient("actions/cache", [bearerCredentialHandler], getRequestOptions());
|
||||||
}
|
}
|
||||||
function getCacheVersion() {
|
function getCacheVersion(compressionMethod) {
|
||||||
// Add salt to cache version to support breaking changes in cache entry
|
// Add salt to cache version to support breaking changes in cache entry
|
||||||
const components = [
|
const components = [core.getInput(constants_1.Inputs.Path, { required: true })].concat(compressionMethod == constants_1.CompressionMethod.Zstd
|
||||||
core.getInput(constants_1.Inputs.Path, { required: true }),
|
? [compressionMethod, versionSalt]
|
||||||
versionSalt
|
: versionSalt);
|
||||||
];
|
|
||||||
return crypto
|
return crypto
|
||||||
.createHash("sha256")
|
.createHash("sha256")
|
||||||
.update(components.join("|"))
|
.update(components.join("|"))
|
||||||
.digest("hex");
|
.digest("hex");
|
||||||
}
|
}
|
||||||
exports.getCacheVersion = getCacheVersion;
|
exports.getCacheVersion = getCacheVersion;
|
||||||
function getCacheEntry(keys) {
|
function getCacheEntry(keys, options) {
|
||||||
var _a;
|
var _a, _b;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const httpClient = createHttpClient();
|
const httpClient = createHttpClient();
|
||||||
const version = getCacheVersion();
|
const version = getCacheVersion((_a = options) === null || _a === void 0 ? void 0 : _a.compressionMethod);
|
||||||
const resource = `cache?keys=${encodeURIComponent(keys.join(","))}&version=${version}`;
|
const resource = `cache?keys=${encodeURIComponent(keys.join(","))}&version=${version}`;
|
||||||
const response = yield httpClient.getJson(getCacheApiUrl(resource));
|
const response = yield httpClient.getJson(getCacheApiUrl(resource));
|
||||||
if (response.statusCode === 204) {
|
if (response.statusCode === 204) {
|
||||||
|
@ -2262,7 +2261,7 @@ function getCacheEntry(keys) {
|
||||||
throw new Error(`Cache service responded with ${response.statusCode}`);
|
throw new Error(`Cache service responded with ${response.statusCode}`);
|
||||||
}
|
}
|
||||||
const cacheResult = response.result;
|
const cacheResult = response.result;
|
||||||
const cacheDownloadUrl = (_a = cacheResult) === null || _a === void 0 ? void 0 : _a.archiveLocation;
|
const cacheDownloadUrl = (_b = cacheResult) === null || _b === void 0 ? void 0 : _b.archiveLocation;
|
||||||
if (!cacheDownloadUrl) {
|
if (!cacheDownloadUrl) {
|
||||||
throw new Error("Cache not found.");
|
throw new Error("Cache not found.");
|
||||||
}
|
}
|
||||||
|
@ -2306,17 +2305,17 @@ function downloadCache(archiveLocation, archivePath) {
|
||||||
}
|
}
|
||||||
exports.downloadCache = downloadCache;
|
exports.downloadCache = downloadCache;
|
||||||
// Reserve Cache
|
// Reserve Cache
|
||||||
function reserveCache(key) {
|
function reserveCache(key, options) {
|
||||||
var _a, _b, _c;
|
var _a, _b, _c, _d;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const httpClient = createHttpClient();
|
const httpClient = createHttpClient();
|
||||||
const version = getCacheVersion();
|
const version = getCacheVersion((_a = options) === null || _a === void 0 ? void 0 : _a.compressionMethod);
|
||||||
const reserveCacheRequest = {
|
const reserveCacheRequest = {
|
||||||
key,
|
key,
|
||||||
version
|
version
|
||||||
};
|
};
|
||||||
const response = yield httpClient.postJson(getCacheApiUrl("caches"), reserveCacheRequest);
|
const response = yield httpClient.postJson(getCacheApiUrl("caches"), reserveCacheRequest);
|
||||||
return _c = (_b = (_a = response) === null || _a === void 0 ? void 0 : _a.result) === null || _b === void 0 ? void 0 : _b.cacheId, (_c !== null && _c !== void 0 ? _c : -1);
|
return _d = (_c = (_b = response) === null || _b === void 0 ? void 0 : _b.result) === null || _c === void 0 ? void 0 : _c.cacheId, (_d !== null && _d !== void 0 ? _d : -1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.reserveCache = reserveCache;
|
exports.reserveCache = reserveCache;
|
||||||
|
@ -3201,6 +3200,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const core = __importStar(__webpack_require__(470));
|
const core = __importStar(__webpack_require__(470));
|
||||||
|
const exec = __importStar(__webpack_require__(986));
|
||||||
const glob = __importStar(__webpack_require__(281));
|
const glob = __importStar(__webpack_require__(281));
|
||||||
const io = __importStar(__webpack_require__(1));
|
const io = __importStar(__webpack_require__(1));
|
||||||
const fs = __importStar(__webpack_require__(747));
|
const fs = __importStar(__webpack_require__(747));
|
||||||
|
@ -3320,6 +3320,50 @@ function unlinkFile(path) {
|
||||||
return util.promisify(fs.unlink)(path);
|
return util.promisify(fs.unlink)(path);
|
||||||
}
|
}
|
||||||
exports.unlinkFile = unlinkFile;
|
exports.unlinkFile = unlinkFile;
|
||||||
|
function checkVersion(app) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
core.debug(`Checking ${app} --version`);
|
||||||
|
let versionOutput = "";
|
||||||
|
try {
|
||||||
|
yield exec.exec(`${app} --version`, [], {
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
silent: true,
|
||||||
|
listeners: {
|
||||||
|
stdout: (data) => (versionOutput += data.toString()),
|
||||||
|
stderr: (data) => (versionOutput += data.toString())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
core.debug(err.message);
|
||||||
|
}
|
||||||
|
versionOutput = versionOutput.trim();
|
||||||
|
core.debug(versionOutput);
|
||||||
|
return versionOutput;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function getCompressionMethod() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const versionOutput = yield checkVersion("zstd");
|
||||||
|
return versionOutput.toLowerCase().includes("zstd command line interface")
|
||||||
|
? constants_1.CompressionMethod.Zstd
|
||||||
|
: constants_1.CompressionMethod.Gzip;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.getCompressionMethod = getCompressionMethod;
|
||||||
|
function getCacheFileName(compressionMethod) {
|
||||||
|
return compressionMethod == constants_1.CompressionMethod.Zstd
|
||||||
|
? constants_1.CacheFilename.Zstd
|
||||||
|
: constants_1.CacheFilename.Gzip;
|
||||||
|
}
|
||||||
|
exports.getCacheFileName = getCacheFileName;
|
||||||
|
function useGnuTar() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const versionOutput = yield checkVersion("tar");
|
||||||
|
return versionOutput.toLowerCase().includes("gnu tar");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.useGnuTar = useGnuTar;
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
@ -3599,12 +3643,6 @@ class HttpClientResponse {
|
||||||
this.message.on('data', (chunk) => {
|
this.message.on('data', (chunk) => {
|
||||||
output = Buffer.concat([output, chunk]);
|
output = Buffer.concat([output, chunk]);
|
||||||
});
|
});
|
||||||
this.message.on('aborted', () => {
|
|
||||||
reject("Request was aborted or closed prematurely");
|
|
||||||
});
|
|
||||||
this.message.on('timeout', (socket) => {
|
|
||||||
reject("Request timed out");
|
|
||||||
});
|
|
||||||
this.message.on('end', () => {
|
this.message.on('end', () => {
|
||||||
resolve(output.toString());
|
resolve(output.toString());
|
||||||
});
|
});
|
||||||
|
@ -3726,7 +3764,6 @@ class HttpClient {
|
||||||
let response;
|
let response;
|
||||||
while (numTries < maxTries) {
|
while (numTries < maxTries) {
|
||||||
response = await this.requestRaw(info, data);
|
response = await this.requestRaw(info, data);
|
||||||
|
|
||||||
// Check if it's an authentication challenge
|
// Check if it's an authentication challenge
|
||||||
if (response && response.message && response.message.statusCode === HttpCodes.Unauthorized) {
|
if (response && response.message && response.message.statusCode === HttpCodes.Unauthorized) {
|
||||||
let authenticationHandler;
|
let authenticationHandler;
|
||||||
|
@ -4490,7 +4527,16 @@ var Events;
|
||||||
Events["Push"] = "push";
|
Events["Push"] = "push";
|
||||||
Events["PullRequest"] = "pull_request";
|
Events["PullRequest"] = "pull_request";
|
||||||
})(Events = exports.Events || (exports.Events = {}));
|
})(Events = exports.Events || (exports.Events = {}));
|
||||||
exports.CacheFilename = "cache.tgz";
|
var CacheFilename;
|
||||||
|
(function (CacheFilename) {
|
||||||
|
CacheFilename["Gzip"] = "cache.tgz";
|
||||||
|
CacheFilename["Zstd"] = "cache.tzst";
|
||||||
|
})(CacheFilename = exports.CacheFilename || (exports.CacheFilename = {}));
|
||||||
|
var CompressionMethod;
|
||||||
|
(function (CompressionMethod) {
|
||||||
|
CompressionMethod["Gzip"] = "gzip";
|
||||||
|
CompressionMethod["Zstd"] = "zstd";
|
||||||
|
})(CompressionMethod = exports.CompressionMethod || (exports.CompressionMethod = {}));
|
||||||
// Socket timeout in milliseconds during download. If no traffic is received
|
// Socket timeout in milliseconds during download. If no traffic is received
|
||||||
// over the socket during this period, the socket is destroyed and the download
|
// over the socket during this period, the socket is destroyed and the download
|
||||||
// is aborted.
|
// is aborted.
|
||||||
|
@ -4617,13 +4663,16 @@ function run() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const compressionMethod = yield utils.getCompressionMethod();
|
||||||
try {
|
try {
|
||||||
const cacheEntry = yield cacheHttpClient.getCacheEntry(keys);
|
const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, {
|
||||||
|
compressionMethod: compressionMethod
|
||||||
|
});
|
||||||
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(), utils.getCacheFileName(compressionMethod));
|
||||||
core.debug(`Archive Path: ${archivePath}`);
|
core.debug(`Archive Path: ${archivePath}`);
|
||||||
// Store the cache result
|
// Store the cache result
|
||||||
utils.setCacheState(cacheEntry);
|
utils.setCacheState(cacheEntry);
|
||||||
|
@ -4632,7 +4681,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);
|
yield tar_1.extractTar(archivePath, compressionMethod);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// Try to delete the archive to save space
|
// Try to delete the archive to save space
|
||||||
|
@ -4993,29 +5042,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const core = __importStar(__webpack_require__(470));
|
|
||||||
const exec_1 = __webpack_require__(986);
|
const exec_1 = __webpack_require__(986);
|
||||||
const io = __importStar(__webpack_require__(1));
|
const io = __importStar(__webpack_require__(1));
|
||||||
const fs_1 = __webpack_require__(747);
|
const fs_1 = __webpack_require__(747);
|
||||||
const path = __importStar(__webpack_require__(622));
|
const path = __importStar(__webpack_require__(622));
|
||||||
const constants_1 = __webpack_require__(694);
|
const constants_1 = __webpack_require__(694);
|
||||||
function isGnuTar() {
|
const utils = __importStar(__webpack_require__(443));
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
core.debug("Checking tar --version");
|
|
||||||
let versionOutput = "";
|
|
||||||
yield exec_1.exec("tar --version", [], {
|
|
||||||
ignoreReturnCode: true,
|
|
||||||
silent: true,
|
|
||||||
listeners: {
|
|
||||||
stdout: (data) => (versionOutput += data.toString()),
|
|
||||||
stderr: (data) => (versionOutput += data.toString())
|
|
||||||
}
|
|
||||||
});
|
|
||||||
core.debug(versionOutput.trim());
|
|
||||||
return versionOutput.toUpperCase().includes("GNU TAR");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exports.isGnuTar = isGnuTar;
|
|
||||||
function getTarPath(args) {
|
function getTarPath(args) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
// Explicitly use BSD Tar on Windows
|
// Explicitly use BSD Tar on Windows
|
||||||
|
@ -5025,7 +5057,7 @@ function getTarPath(args) {
|
||||||
if (fs_1.existsSync(systemTar)) {
|
if (fs_1.existsSync(systemTar)) {
|
||||||
return systemTar;
|
return systemTar;
|
||||||
}
|
}
|
||||||
else if (isGnuTar()) {
|
else if (yield utils.useGnuTar()) {
|
||||||
args.push("--force-local");
|
args.push("--force-local");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5036,7 +5068,7 @@ function execTar(args, cwd) {
|
||||||
var _a;
|
var _a;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
yield exec_1.exec(`"${yield getTarPath(args)}"`, args, { cwd: cwd });
|
yield exec_1.exec(`${yield getTarPath(args)}`, args, { cwd: cwd });
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
throw new Error(`Tar failed with error: ${(_a = error) === null || _a === void 0 ? void 0 : _a.message}`);
|
throw new Error(`Tar failed with error: ${(_a = error) === null || _a === void 0 ? void 0 : _a.message}`);
|
||||||
|
@ -5047,14 +5079,16 @@ function getWorkingDirectory() {
|
||||||
var _a;
|
var _a;
|
||||||
return _a = process.env["GITHUB_WORKSPACE"], (_a !== null && _a !== void 0 ? _a : process.cwd());
|
return _a = process.env["GITHUB_WORKSPACE"], (_a !== null && _a !== void 0 ? _a : process.cwd());
|
||||||
}
|
}
|
||||||
function extractTar(archivePath) {
|
function extractTar(archivePath, compressionMethod) {
|
||||||
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
|
||||||
const workingDirectory = getWorkingDirectory();
|
const workingDirectory = getWorkingDirectory();
|
||||||
yield io.mkdirP(workingDirectory);
|
yield io.mkdirP(workingDirectory);
|
||||||
const args = [
|
const args = [
|
||||||
"-xz",
|
...(compressionMethod == constants_1.CompressionMethod.Zstd
|
||||||
"-f",
|
? ["--use-compress-program", "zstd -d"]
|
||||||
|
: ["-z"]),
|
||||||
|
"-xf",
|
||||||
archivePath.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
archivePath.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
||||||
"-P",
|
"-P",
|
||||||
"-C",
|
"-C",
|
||||||
|
@ -5064,16 +5098,20 @@ function extractTar(archivePath) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.extractTar = extractTar;
|
exports.extractTar = extractTar;
|
||||||
function createTar(archiveFolder, sourceDirectories) {
|
function createTar(archiveFolder, sourceDirectories, compressionMethod) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
// Write source directories to manifest.txt to avoid command length limits
|
// Write source directories to manifest.txt to avoid command length limits
|
||||||
const manifestFilename = "manifest.txt";
|
const manifestFilename = "manifest.txt";
|
||||||
|
const cacheFileName = utils.getCacheFileName(compressionMethod);
|
||||||
fs_1.writeFileSync(path.join(archiveFolder, manifestFilename), sourceDirectories.join("\n"));
|
fs_1.writeFileSync(path.join(archiveFolder, manifestFilename), sourceDirectories.join("\n"));
|
||||||
|
// -T#: Compress using # working thread. If # is 0, attempt to detect and use the number of physical CPU cores.
|
||||||
const workingDirectory = getWorkingDirectory();
|
const workingDirectory = getWorkingDirectory();
|
||||||
const args = [
|
const args = [
|
||||||
"-cz",
|
...(compressionMethod == constants_1.CompressionMethod.Zstd
|
||||||
"-f",
|
? ["--use-compress-program", "zstd -T0"]
|
||||||
constants_1.CacheFilename.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
: ["-z"]),
|
||||||
|
"-cf",
|
||||||
|
cacheFileName.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
||||||
"-P",
|
"-P",
|
||||||
"-C",
|
"-C",
|
||||||
workingDirectory.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
workingDirectory.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
||||||
|
|
140
dist/save/index.js
vendored
140
dist/save/index.js
vendored
|
@ -2236,23 +2236,22 @@ function createHttpClient() {
|
||||||
const bearerCredentialHandler = new auth_1.BearerCredentialHandler(token);
|
const bearerCredentialHandler = new auth_1.BearerCredentialHandler(token);
|
||||||
return new http_client_1.HttpClient("actions/cache", [bearerCredentialHandler], getRequestOptions());
|
return new http_client_1.HttpClient("actions/cache", [bearerCredentialHandler], getRequestOptions());
|
||||||
}
|
}
|
||||||
function getCacheVersion() {
|
function getCacheVersion(compressionMethod) {
|
||||||
// Add salt to cache version to support breaking changes in cache entry
|
// Add salt to cache version to support breaking changes in cache entry
|
||||||
const components = [
|
const components = [core.getInput(constants_1.Inputs.Path, { required: true })].concat(compressionMethod == constants_1.CompressionMethod.Zstd
|
||||||
core.getInput(constants_1.Inputs.Path, { required: true }),
|
? [compressionMethod, versionSalt]
|
||||||
versionSalt
|
: versionSalt);
|
||||||
];
|
|
||||||
return crypto
|
return crypto
|
||||||
.createHash("sha256")
|
.createHash("sha256")
|
||||||
.update(components.join("|"))
|
.update(components.join("|"))
|
||||||
.digest("hex");
|
.digest("hex");
|
||||||
}
|
}
|
||||||
exports.getCacheVersion = getCacheVersion;
|
exports.getCacheVersion = getCacheVersion;
|
||||||
function getCacheEntry(keys) {
|
function getCacheEntry(keys, options) {
|
||||||
var _a;
|
var _a, _b;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const httpClient = createHttpClient();
|
const httpClient = createHttpClient();
|
||||||
const version = getCacheVersion();
|
const version = getCacheVersion((_a = options) === null || _a === void 0 ? void 0 : _a.compressionMethod);
|
||||||
const resource = `cache?keys=${encodeURIComponent(keys.join(","))}&version=${version}`;
|
const resource = `cache?keys=${encodeURIComponent(keys.join(","))}&version=${version}`;
|
||||||
const response = yield httpClient.getJson(getCacheApiUrl(resource));
|
const response = yield httpClient.getJson(getCacheApiUrl(resource));
|
||||||
if (response.statusCode === 204) {
|
if (response.statusCode === 204) {
|
||||||
|
@ -2262,7 +2261,7 @@ function getCacheEntry(keys) {
|
||||||
throw new Error(`Cache service responded with ${response.statusCode}`);
|
throw new Error(`Cache service responded with ${response.statusCode}`);
|
||||||
}
|
}
|
||||||
const cacheResult = response.result;
|
const cacheResult = response.result;
|
||||||
const cacheDownloadUrl = (_a = cacheResult) === null || _a === void 0 ? void 0 : _a.archiveLocation;
|
const cacheDownloadUrl = (_b = cacheResult) === null || _b === void 0 ? void 0 : _b.archiveLocation;
|
||||||
if (!cacheDownloadUrl) {
|
if (!cacheDownloadUrl) {
|
||||||
throw new Error("Cache not found.");
|
throw new Error("Cache not found.");
|
||||||
}
|
}
|
||||||
|
@ -2306,17 +2305,17 @@ function downloadCache(archiveLocation, archivePath) {
|
||||||
}
|
}
|
||||||
exports.downloadCache = downloadCache;
|
exports.downloadCache = downloadCache;
|
||||||
// Reserve Cache
|
// Reserve Cache
|
||||||
function reserveCache(key) {
|
function reserveCache(key, options) {
|
||||||
var _a, _b, _c;
|
var _a, _b, _c, _d;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const httpClient = createHttpClient();
|
const httpClient = createHttpClient();
|
||||||
const version = getCacheVersion();
|
const version = getCacheVersion((_a = options) === null || _a === void 0 ? void 0 : _a.compressionMethod);
|
||||||
const reserveCacheRequest = {
|
const reserveCacheRequest = {
|
||||||
key,
|
key,
|
||||||
version
|
version
|
||||||
};
|
};
|
||||||
const response = yield httpClient.postJson(getCacheApiUrl("caches"), reserveCacheRequest);
|
const response = yield httpClient.postJson(getCacheApiUrl("caches"), reserveCacheRequest);
|
||||||
return _c = (_b = (_a = response) === null || _a === void 0 ? void 0 : _a.result) === null || _b === void 0 ? void 0 : _b.cacheId, (_c !== null && _c !== void 0 ? _c : -1);
|
return _d = (_c = (_b = response) === null || _b === void 0 ? void 0 : _b.result) === null || _c === void 0 ? void 0 : _c.cacheId, (_d !== null && _d !== void 0 ? _d : -1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.reserveCache = reserveCache;
|
exports.reserveCache = reserveCache;
|
||||||
|
@ -3201,6 +3200,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const core = __importStar(__webpack_require__(470));
|
const core = __importStar(__webpack_require__(470));
|
||||||
|
const exec = __importStar(__webpack_require__(986));
|
||||||
const glob = __importStar(__webpack_require__(281));
|
const glob = __importStar(__webpack_require__(281));
|
||||||
const io = __importStar(__webpack_require__(1));
|
const io = __importStar(__webpack_require__(1));
|
||||||
const fs = __importStar(__webpack_require__(747));
|
const fs = __importStar(__webpack_require__(747));
|
||||||
|
@ -3320,6 +3320,50 @@ function unlinkFile(path) {
|
||||||
return util.promisify(fs.unlink)(path);
|
return util.promisify(fs.unlink)(path);
|
||||||
}
|
}
|
||||||
exports.unlinkFile = unlinkFile;
|
exports.unlinkFile = unlinkFile;
|
||||||
|
function checkVersion(app) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
core.debug(`Checking ${app} --version`);
|
||||||
|
let versionOutput = "";
|
||||||
|
try {
|
||||||
|
yield exec.exec(`${app} --version`, [], {
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
silent: true,
|
||||||
|
listeners: {
|
||||||
|
stdout: (data) => (versionOutput += data.toString()),
|
||||||
|
stderr: (data) => (versionOutput += data.toString())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
core.debug(err.message);
|
||||||
|
}
|
||||||
|
versionOutput = versionOutput.trim();
|
||||||
|
core.debug(versionOutput);
|
||||||
|
return versionOutput;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function getCompressionMethod() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const versionOutput = yield checkVersion("zstd");
|
||||||
|
return versionOutput.toLowerCase().includes("zstd command line interface")
|
||||||
|
? constants_1.CompressionMethod.Zstd
|
||||||
|
: constants_1.CompressionMethod.Gzip;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.getCompressionMethod = getCompressionMethod;
|
||||||
|
function getCacheFileName(compressionMethod) {
|
||||||
|
return compressionMethod == constants_1.CompressionMethod.Zstd
|
||||||
|
? constants_1.CacheFilename.Zstd
|
||||||
|
: constants_1.CacheFilename.Gzip;
|
||||||
|
}
|
||||||
|
exports.getCacheFileName = getCacheFileName;
|
||||||
|
function useGnuTar() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const versionOutput = yield checkVersion("tar");
|
||||||
|
return versionOutput.toLowerCase().includes("gnu tar");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.useGnuTar = useGnuTar;
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
@ -3599,12 +3643,6 @@ class HttpClientResponse {
|
||||||
this.message.on('data', (chunk) => {
|
this.message.on('data', (chunk) => {
|
||||||
output = Buffer.concat([output, chunk]);
|
output = Buffer.concat([output, chunk]);
|
||||||
});
|
});
|
||||||
this.message.on('aborted', () => {
|
|
||||||
reject("Request was aborted or closed prematurely");
|
|
||||||
});
|
|
||||||
this.message.on('timeout', (socket) => {
|
|
||||||
reject("Request timed out");
|
|
||||||
});
|
|
||||||
this.message.on('end', () => {
|
this.message.on('end', () => {
|
||||||
resolve(output.toString());
|
resolve(output.toString());
|
||||||
});
|
});
|
||||||
|
@ -3726,7 +3764,6 @@ class HttpClient {
|
||||||
let response;
|
let response;
|
||||||
while (numTries < maxTries) {
|
while (numTries < maxTries) {
|
||||||
response = await this.requestRaw(info, data);
|
response = await this.requestRaw(info, data);
|
||||||
|
|
||||||
// Check if it's an authentication challenge
|
// Check if it's an authentication challenge
|
||||||
if (response && response.message && response.message.statusCode === HttpCodes.Unauthorized) {
|
if (response && response.message && response.message.statusCode === HttpCodes.Unauthorized) {
|
||||||
let authenticationHandler;
|
let authenticationHandler;
|
||||||
|
@ -4511,8 +4548,11 @@ function run() {
|
||||||
core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`);
|
core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const compressionMethod = yield utils.getCompressionMethod();
|
||||||
core.debug("Reserving Cache");
|
core.debug("Reserving Cache");
|
||||||
const cacheId = yield cacheHttpClient.reserveCache(primaryKey);
|
const cacheId = yield cacheHttpClient.reserveCache(primaryKey, {
|
||||||
|
compressionMethod: compressionMethod
|
||||||
|
});
|
||||||
if (cacheId == -1) {
|
if (cacheId == -1) {
|
||||||
core.info(`Unable to reserve cache with key ${primaryKey}, another job may be creating this cache.`);
|
core.info(`Unable to reserve cache with key ${primaryKey}, another job may be creating this cache.`);
|
||||||
return;
|
return;
|
||||||
|
@ -4525,9 +4565,9 @@ function run() {
|
||||||
core.debug("Cache Paths:");
|
core.debug("Cache Paths:");
|
||||||
core.debug(`${JSON.stringify(cachePaths)}`);
|
core.debug(`${JSON.stringify(cachePaths)}`);
|
||||||
const archiveFolder = yield utils.createTempDirectory();
|
const archiveFolder = yield utils.createTempDirectory();
|
||||||
const archivePath = path.join(archiveFolder, constants_1.CacheFilename);
|
const archivePath = path.join(archiveFolder, utils.getCacheFileName(compressionMethod));
|
||||||
core.debug(`Archive Path: ${archivePath}`);
|
core.debug(`Archive Path: ${archivePath}`);
|
||||||
yield tar_1.createTar(archiveFolder, cachePaths);
|
yield tar_1.createTar(archiveFolder, cachePaths, compressionMethod);
|
||||||
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}`);
|
||||||
|
@ -4576,7 +4616,16 @@ var Events;
|
||||||
Events["Push"] = "push";
|
Events["Push"] = "push";
|
||||||
Events["PullRequest"] = "pull_request";
|
Events["PullRequest"] = "pull_request";
|
||||||
})(Events = exports.Events || (exports.Events = {}));
|
})(Events = exports.Events || (exports.Events = {}));
|
||||||
exports.CacheFilename = "cache.tgz";
|
var CacheFilename;
|
||||||
|
(function (CacheFilename) {
|
||||||
|
CacheFilename["Gzip"] = "cache.tgz";
|
||||||
|
CacheFilename["Zstd"] = "cache.tzst";
|
||||||
|
})(CacheFilename = exports.CacheFilename || (exports.CacheFilename = {}));
|
||||||
|
var CompressionMethod;
|
||||||
|
(function (CompressionMethod) {
|
||||||
|
CompressionMethod["Gzip"] = "gzip";
|
||||||
|
CompressionMethod["Zstd"] = "zstd";
|
||||||
|
})(CompressionMethod = exports.CompressionMethod || (exports.CompressionMethod = {}));
|
||||||
// Socket timeout in milliseconds during download. If no traffic is received
|
// Socket timeout in milliseconds during download. If no traffic is received
|
||||||
// over the socket during this period, the socket is destroyed and the download
|
// over the socket during this period, the socket is destroyed and the download
|
||||||
// is aborted.
|
// is aborted.
|
||||||
|
@ -4970,29 +5019,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const core = __importStar(__webpack_require__(470));
|
|
||||||
const exec_1 = __webpack_require__(986);
|
const exec_1 = __webpack_require__(986);
|
||||||
const io = __importStar(__webpack_require__(1));
|
const io = __importStar(__webpack_require__(1));
|
||||||
const fs_1 = __webpack_require__(747);
|
const fs_1 = __webpack_require__(747);
|
||||||
const path = __importStar(__webpack_require__(622));
|
const path = __importStar(__webpack_require__(622));
|
||||||
const constants_1 = __webpack_require__(694);
|
const constants_1 = __webpack_require__(694);
|
||||||
function isGnuTar() {
|
const utils = __importStar(__webpack_require__(443));
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
core.debug("Checking tar --version");
|
|
||||||
let versionOutput = "";
|
|
||||||
yield exec_1.exec("tar --version", [], {
|
|
||||||
ignoreReturnCode: true,
|
|
||||||
silent: true,
|
|
||||||
listeners: {
|
|
||||||
stdout: (data) => (versionOutput += data.toString()),
|
|
||||||
stderr: (data) => (versionOutput += data.toString())
|
|
||||||
}
|
|
||||||
});
|
|
||||||
core.debug(versionOutput.trim());
|
|
||||||
return versionOutput.toUpperCase().includes("GNU TAR");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exports.isGnuTar = isGnuTar;
|
|
||||||
function getTarPath(args) {
|
function getTarPath(args) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
// Explicitly use BSD Tar on Windows
|
// Explicitly use BSD Tar on Windows
|
||||||
|
@ -5002,7 +5034,7 @@ function getTarPath(args) {
|
||||||
if (fs_1.existsSync(systemTar)) {
|
if (fs_1.existsSync(systemTar)) {
|
||||||
return systemTar;
|
return systemTar;
|
||||||
}
|
}
|
||||||
else if (isGnuTar()) {
|
else if (yield utils.useGnuTar()) {
|
||||||
args.push("--force-local");
|
args.push("--force-local");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5013,7 +5045,7 @@ function execTar(args, cwd) {
|
||||||
var _a;
|
var _a;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
yield exec_1.exec(`"${yield getTarPath(args)}"`, args, { cwd: cwd });
|
yield exec_1.exec(`${yield getTarPath(args)}`, args, { cwd: cwd });
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
throw new Error(`Tar failed with error: ${(_a = error) === null || _a === void 0 ? void 0 : _a.message}`);
|
throw new Error(`Tar failed with error: ${(_a = error) === null || _a === void 0 ? void 0 : _a.message}`);
|
||||||
|
@ -5024,14 +5056,16 @@ function getWorkingDirectory() {
|
||||||
var _a;
|
var _a;
|
||||||
return _a = process.env["GITHUB_WORKSPACE"], (_a !== null && _a !== void 0 ? _a : process.cwd());
|
return _a = process.env["GITHUB_WORKSPACE"], (_a !== null && _a !== void 0 ? _a : process.cwd());
|
||||||
}
|
}
|
||||||
function extractTar(archivePath) {
|
function extractTar(archivePath, compressionMethod) {
|
||||||
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
|
||||||
const workingDirectory = getWorkingDirectory();
|
const workingDirectory = getWorkingDirectory();
|
||||||
yield io.mkdirP(workingDirectory);
|
yield io.mkdirP(workingDirectory);
|
||||||
const args = [
|
const args = [
|
||||||
"-xz",
|
...(compressionMethod == constants_1.CompressionMethod.Zstd
|
||||||
"-f",
|
? ["--use-compress-program", "zstd -d"]
|
||||||
|
: ["-z"]),
|
||||||
|
"-xf",
|
||||||
archivePath.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
archivePath.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
||||||
"-P",
|
"-P",
|
||||||
"-C",
|
"-C",
|
||||||
|
@ -5041,16 +5075,20 @@ function extractTar(archivePath) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.extractTar = extractTar;
|
exports.extractTar = extractTar;
|
||||||
function createTar(archiveFolder, sourceDirectories) {
|
function createTar(archiveFolder, sourceDirectories, compressionMethod) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
// Write source directories to manifest.txt to avoid command length limits
|
// Write source directories to manifest.txt to avoid command length limits
|
||||||
const manifestFilename = "manifest.txt";
|
const manifestFilename = "manifest.txt";
|
||||||
|
const cacheFileName = utils.getCacheFileName(compressionMethod);
|
||||||
fs_1.writeFileSync(path.join(archiveFolder, manifestFilename), sourceDirectories.join("\n"));
|
fs_1.writeFileSync(path.join(archiveFolder, manifestFilename), sourceDirectories.join("\n"));
|
||||||
|
// -T#: Compress using # working thread. If # is 0, attempt to detect and use the number of physical CPU cores.
|
||||||
const workingDirectory = getWorkingDirectory();
|
const workingDirectory = getWorkingDirectory();
|
||||||
const args = [
|
const args = [
|
||||||
"-cz",
|
...(compressionMethod == constants_1.CompressionMethod.Zstd
|
||||||
"-f",
|
? ["--use-compress-program", "zstd -T0"]
|
||||||
constants_1.CacheFilename.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
: ["-z"]),
|
||||||
|
"-cf",
|
||||||
|
cacheFileName.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
||||||
"-P",
|
"-P",
|
||||||
"-C",
|
"-C",
|
||||||
workingDirectory.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
workingDirectory.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
||||||
|
|
|
@ -11,9 +11,10 @@ import * as fs from "fs";
|
||||||
import * as stream from "stream";
|
import * as stream from "stream";
|
||||||
import * as util from "util";
|
import * as util from "util";
|
||||||
|
|
||||||
import { Inputs, SocketTimeout } from "./constants";
|
import { CompressionMethod, Inputs, SocketTimeout } from "./constants";
|
||||||
import {
|
import {
|
||||||
ArtifactCacheEntry,
|
ArtifactCacheEntry,
|
||||||
|
CacheOptions,
|
||||||
CommitCacheRequest,
|
CommitCacheRequest,
|
||||||
ReserveCacheRequest,
|
ReserveCacheRequest,
|
||||||
ReserveCacheResponse
|
ReserveCacheResponse
|
||||||
|
@ -84,12 +85,13 @@ function createHttpClient(): HttpClient {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCacheVersion(): string {
|
export function getCacheVersion(compressionMethod?: CompressionMethod): string {
|
||||||
// Add salt to cache version to support breaking changes in cache entry
|
// Add salt to cache version to support breaking changes in cache entry
|
||||||
const components = [
|
const components = [core.getInput(Inputs.Path, { required: true })].concat(
|
||||||
core.getInput(Inputs.Path, { required: true }),
|
compressionMethod == CompressionMethod.Zstd
|
||||||
versionSalt
|
? [compressionMethod, versionSalt]
|
||||||
];
|
: versionSalt
|
||||||
|
);
|
||||||
|
|
||||||
return crypto
|
return crypto
|
||||||
.createHash("sha256")
|
.createHash("sha256")
|
||||||
|
@ -98,10 +100,11 @@ export function getCacheVersion(): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getCacheEntry(
|
export async function getCacheEntry(
|
||||||
keys: string[]
|
keys: string[],
|
||||||
|
options?: CacheOptions
|
||||||
): Promise<ArtifactCacheEntry | null> {
|
): Promise<ArtifactCacheEntry | null> {
|
||||||
const httpClient = createHttpClient();
|
const httpClient = createHttpClient();
|
||||||
const version = getCacheVersion();
|
const version = getCacheVersion(options?.compressionMethod);
|
||||||
const resource = `cache?keys=${encodeURIComponent(
|
const resource = `cache?keys=${encodeURIComponent(
|
||||||
keys.join(",")
|
keys.join(",")
|
||||||
)}&version=${version}`;
|
)}&version=${version}`;
|
||||||
|
@ -173,9 +176,12 @@ export async function downloadCache(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reserve Cache
|
// Reserve Cache
|
||||||
export async function reserveCache(key: string): Promise<number> {
|
export async function reserveCache(
|
||||||
|
key: string,
|
||||||
|
options?: CacheOptions
|
||||||
|
): Promise<number> {
|
||||||
const httpClient = createHttpClient();
|
const httpClient = createHttpClient();
|
||||||
const version = getCacheVersion();
|
const version = getCacheVersion(options?.compressionMethod);
|
||||||
|
|
||||||
const reserveCacheRequest: ReserveCacheRequest = {
|
const reserveCacheRequest: ReserveCacheRequest = {
|
||||||
key,
|
key,
|
||||||
|
|
|
@ -19,7 +19,15 @@ export enum Events {
|
||||||
PullRequest = "pull_request"
|
PullRequest = "pull_request"
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CacheFilename = "cache.tgz";
|
export enum CacheFilename {
|
||||||
|
Gzip = "cache.tgz",
|
||||||
|
Zstd = "cache.tzst"
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum CompressionMethod {
|
||||||
|
Gzip = "gzip",
|
||||||
|
Zstd = "zstd"
|
||||||
|
}
|
||||||
|
|
||||||
// Socket timeout in milliseconds during download. If no traffic is received
|
// Socket timeout in milliseconds during download. If no traffic is received
|
||||||
// over the socket during this period, the socket is destroyed and the download
|
// over the socket during this period, the socket is destroyed and the download
|
||||||
|
|
6
src/contracts.d.ts
vendored
6
src/contracts.d.ts
vendored
|
@ -1,3 +1,5 @@
|
||||||
|
import { CompressionMethod } from "./constants";
|
||||||
|
|
||||||
export interface ArtifactCacheEntry {
|
export interface ArtifactCacheEntry {
|
||||||
cacheKey?: string;
|
cacheKey?: string;
|
||||||
scope?: string;
|
scope?: string;
|
||||||
|
@ -17,3 +19,7 @@ export interface ReserveCacheRequest {
|
||||||
export interface ReserveCacheResponse {
|
export interface ReserveCacheResponse {
|
||||||
cacheId: number;
|
cacheId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CacheOptions {
|
||||||
|
compressionMethod?: CompressionMethod;
|
||||||
|
}
|
||||||
|
|
|
@ -54,8 +54,12 @@ async function run(): Promise<void> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const compressionMethod = await utils.getCompressionMethod();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const cacheEntry = await cacheHttpClient.getCacheEntry(keys);
|
const cacheEntry = await cacheHttpClient.getCacheEntry(keys, {
|
||||||
|
compressionMethod: compressionMethod
|
||||||
|
});
|
||||||
if (!cacheEntry?.archiveLocation) {
|
if (!cacheEntry?.archiveLocation) {
|
||||||
core.info(`Cache not found for input keys: ${keys.join(", ")}`);
|
core.info(`Cache not found for input keys: ${keys.join(", ")}`);
|
||||||
return;
|
return;
|
||||||
|
@ -63,7 +67,7 @@ async function run(): Promise<void> {
|
||||||
|
|
||||||
const archivePath = path.join(
|
const archivePath = path.join(
|
||||||
await utils.createTempDirectory(),
|
await utils.createTempDirectory(),
|
||||||
"cache.tgz"
|
utils.getCacheFileName(compressionMethod)
|
||||||
);
|
);
|
||||||
core.debug(`Archive Path: ${archivePath}`);
|
core.debug(`Archive Path: ${archivePath}`);
|
||||||
|
|
||||||
|
@ -84,7 +88,7 @@ async function run(): Promise<void> {
|
||||||
)} MB (${archiveFileSize} B)`
|
)} MB (${archiveFileSize} B)`
|
||||||
);
|
);
|
||||||
|
|
||||||
await extractTar(archivePath);
|
await extractTar(archivePath, compressionMethod);
|
||||||
} finally {
|
} finally {
|
||||||
// Try to delete the archive to save space
|
// Try to delete the archive to save space
|
||||||
try {
|
try {
|
||||||
|
|
16
src/save.ts
16
src/save.ts
|
@ -2,7 +2,7 @@ import * as core from "@actions/core";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
|
||||||
import * as cacheHttpClient from "./cacheHttpClient";
|
import * as cacheHttpClient from "./cacheHttpClient";
|
||||||
import { CacheFilename, Events, Inputs, State } from "./constants";
|
import { Events, Inputs, State } from "./constants";
|
||||||
import { createTar } from "./tar";
|
import { createTar } from "./tar";
|
||||||
import * as utils from "./utils/actionUtils";
|
import * as utils from "./utils/actionUtils";
|
||||||
|
|
||||||
|
@ -35,8 +35,12 @@ async function run(): Promise<void> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const compressionMethod = await utils.getCompressionMethod();
|
||||||
|
|
||||||
core.debug("Reserving Cache");
|
core.debug("Reserving Cache");
|
||||||
const cacheId = await cacheHttpClient.reserveCache(primaryKey);
|
const cacheId = await cacheHttpClient.reserveCache(primaryKey, {
|
||||||
|
compressionMethod: compressionMethod
|
||||||
|
});
|
||||||
if (cacheId == -1) {
|
if (cacheId == -1) {
|
||||||
core.info(
|
core.info(
|
||||||
`Unable to reserve cache with key ${primaryKey}, another job may be creating this cache.`
|
`Unable to reserve cache with key ${primaryKey}, another job may be creating this cache.`
|
||||||
|
@ -55,10 +59,14 @@ async function run(): Promise<void> {
|
||||||
core.debug(`${JSON.stringify(cachePaths)}`);
|
core.debug(`${JSON.stringify(cachePaths)}`);
|
||||||
|
|
||||||
const archiveFolder = await utils.createTempDirectory();
|
const archiveFolder = await utils.createTempDirectory();
|
||||||
const archivePath = path.join(archiveFolder, CacheFilename);
|
const archivePath = path.join(
|
||||||
|
archiveFolder,
|
||||||
|
utils.getCacheFileName(compressionMethod)
|
||||||
|
);
|
||||||
|
|
||||||
core.debug(`Archive Path: ${archivePath}`);
|
core.debug(`Archive Path: ${archivePath}`);
|
||||||
|
|
||||||
await createTar(archiveFolder, cachePaths);
|
await createTar(archiveFolder, cachePaths, compressionMethod);
|
||||||
|
|
||||||
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);
|
||||||
|
|
50
src/tar.ts
50
src/tar.ts
|
@ -1,27 +1,10 @@
|
||||||
import * as core from "@actions/core";
|
|
||||||
import { exec } from "@actions/exec";
|
import { exec } from "@actions/exec";
|
||||||
import * as io from "@actions/io";
|
import * as io from "@actions/io";
|
||||||
import { existsSync, writeFileSync } from "fs";
|
import { existsSync, writeFileSync } from "fs";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
|
||||||
import { CacheFilename } from "./constants";
|
import { CompressionMethod } from "./constants";
|
||||||
|
import * as utils from "./utils/actionUtils";
|
||||||
export async function isGnuTar(): Promise<boolean> {
|
|
||||||
core.debug("Checking tar --version");
|
|
||||||
let versionOutput = "";
|
|
||||||
await exec("tar --version", [], {
|
|
||||||
ignoreReturnCode: true,
|
|
||||||
silent: true,
|
|
||||||
listeners: {
|
|
||||||
stdout: (data: Buffer): string =>
|
|
||||||
(versionOutput += data.toString()),
|
|
||||||
stderr: (data: Buffer): string => (versionOutput += data.toString())
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
core.debug(versionOutput.trim());
|
|
||||||
return versionOutput.toUpperCase().includes("GNU TAR");
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getTarPath(args: string[]): Promise<string> {
|
async function getTarPath(args: string[]): Promise<string> {
|
||||||
// Explicitly use BSD Tar on Windows
|
// Explicitly use BSD Tar on Windows
|
||||||
|
@ -30,7 +13,7 @@ async function getTarPath(args: string[]): Promise<string> {
|
||||||
const systemTar = `${process.env["windir"]}\\System32\\tar.exe`;
|
const systemTar = `${process.env["windir"]}\\System32\\tar.exe`;
|
||||||
if (existsSync(systemTar)) {
|
if (existsSync(systemTar)) {
|
||||||
return systemTar;
|
return systemTar;
|
||||||
} else if (isGnuTar()) {
|
} else if (await utils.useGnuTar()) {
|
||||||
args.push("--force-local");
|
args.push("--force-local");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +22,7 @@ async function getTarPath(args: string[]): Promise<string> {
|
||||||
|
|
||||||
async function execTar(args: string[], cwd?: string): Promise<void> {
|
async function execTar(args: string[], cwd?: string): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await exec(`"${await getTarPath(args)}"`, args, { cwd: cwd });
|
await exec(`${await getTarPath(args)}`, args, { cwd: cwd });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`Tar failed with error: ${error?.message}`);
|
throw new Error(`Tar failed with error: ${error?.message}`);
|
||||||
}
|
}
|
||||||
|
@ -49,13 +32,18 @@ function getWorkingDirectory(): string {
|
||||||
return process.env["GITHUB_WORKSPACE"] ?? process.cwd();
|
return process.env["GITHUB_WORKSPACE"] ?? process.cwd();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function extractTar(archivePath: string): Promise<void> {
|
export async function extractTar(
|
||||||
|
archivePath: string,
|
||||||
|
compressionMethod: CompressionMethod
|
||||||
|
): Promise<void> {
|
||||||
// Create directory to extract tar into
|
// Create directory to extract tar into
|
||||||
const workingDirectory = getWorkingDirectory();
|
const workingDirectory = getWorkingDirectory();
|
||||||
await io.mkdirP(workingDirectory);
|
await io.mkdirP(workingDirectory);
|
||||||
const args = [
|
const args = [
|
||||||
"-xz",
|
...(compressionMethod == CompressionMethod.Zstd
|
||||||
"-f",
|
? ["--use-compress-program", "zstd -d"]
|
||||||
|
: ["-z"]),
|
||||||
|
"-xf",
|
||||||
archivePath.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
archivePath.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
||||||
"-P",
|
"-P",
|
||||||
"-C",
|
"-C",
|
||||||
|
@ -66,20 +54,24 @@ export async function extractTar(archivePath: string): Promise<void> {
|
||||||
|
|
||||||
export async function createTar(
|
export async function createTar(
|
||||||
archiveFolder: string,
|
archiveFolder: string,
|
||||||
sourceDirectories: string[]
|
sourceDirectories: string[],
|
||||||
|
compressionMethod: CompressionMethod
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// Write source directories to manifest.txt to avoid command length limits
|
// Write source directories to manifest.txt to avoid command length limits
|
||||||
const manifestFilename = "manifest.txt";
|
const manifestFilename = "manifest.txt";
|
||||||
|
const cacheFileName = utils.getCacheFileName(compressionMethod);
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
path.join(archiveFolder, manifestFilename),
|
path.join(archiveFolder, manifestFilename),
|
||||||
sourceDirectories.join("\n")
|
sourceDirectories.join("\n")
|
||||||
);
|
);
|
||||||
|
// -T#: Compress using # working thread. If # is 0, attempt to detect and use the number of physical CPU cores.
|
||||||
const workingDirectory = getWorkingDirectory();
|
const workingDirectory = getWorkingDirectory();
|
||||||
const args = [
|
const args = [
|
||||||
"-cz",
|
...(compressionMethod == CompressionMethod.Zstd
|
||||||
"-f",
|
? ["--use-compress-program", "zstd -T0"]
|
||||||
CacheFilename.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
: ["-z"]),
|
||||||
|
"-cf",
|
||||||
|
cacheFileName.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
||||||
"-P",
|
"-P",
|
||||||
"-C",
|
"-C",
|
||||||
workingDirectory.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
workingDirectory.replace(new RegExp("\\" + path.sep, "g"), "/"),
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
import * as exec from "@actions/exec";
|
||||||
import * as glob from "@actions/glob";
|
import * as glob from "@actions/glob";
|
||||||
import * as io from "@actions/io";
|
import * as io from "@actions/io";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
|
@ -6,7 +7,13 @@ import * as path from "path";
|
||||||
import * as util from "util";
|
import * as util from "util";
|
||||||
import * as uuidV4 from "uuid/v4";
|
import * as uuidV4 from "uuid/v4";
|
||||||
|
|
||||||
import { Events, Outputs, State } from "../constants";
|
import {
|
||||||
|
CacheFilename,
|
||||||
|
CompressionMethod,
|
||||||
|
Events,
|
||||||
|
Outputs,
|
||||||
|
State
|
||||||
|
} from "../constants";
|
||||||
import { ArtifactCacheEntry } from "../contracts";
|
import { ArtifactCacheEntry } from "../contracts";
|
||||||
|
|
||||||
// From https://github.com/actions/toolkit/blob/master/packages/tool-cache/src/tool-cache.ts#L23
|
// From https://github.com/actions/toolkit/blob/master/packages/tool-cache/src/tool-cache.ts#L23
|
||||||
|
@ -116,3 +123,44 @@ export function isValidEvent(): boolean {
|
||||||
export function unlinkFile(path: fs.PathLike): Promise<void> {
|
export function unlinkFile(path: fs.PathLike): Promise<void> {
|
||||||
return util.promisify(fs.unlink)(path);
|
return util.promisify(fs.unlink)(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function checkVersion(app: string): Promise<string> {
|
||||||
|
core.debug(`Checking ${app} --version`);
|
||||||
|
let versionOutput = "";
|
||||||
|
try {
|
||||||
|
await exec.exec(`${app} --version`, [], {
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
silent: true,
|
||||||
|
listeners: {
|
||||||
|
stdout: (data: Buffer): string =>
|
||||||
|
(versionOutput += data.toString()),
|
||||||
|
stderr: (data: Buffer): string =>
|
||||||
|
(versionOutput += data.toString())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
core.debug(err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
versionOutput = versionOutput.trim();
|
||||||
|
core.debug(versionOutput);
|
||||||
|
return versionOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getCompressionMethod(): Promise<CompressionMethod> {
|
||||||
|
const versionOutput = await checkVersion("zstd");
|
||||||
|
return versionOutput.toLowerCase().includes("zstd command line interface")
|
||||||
|
? CompressionMethod.Zstd
|
||||||
|
: CompressionMethod.Gzip;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCacheFileName(compressionMethod: CompressionMethod): string {
|
||||||
|
return compressionMethod == CompressionMethod.Zstd
|
||||||
|
? CacheFilename.Zstd
|
||||||
|
: CacheFilename.Gzip;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function useGnuTar(): Promise<boolean> {
|
||||||
|
const versionOutput = await checkVersion("tar");
|
||||||
|
return versionOutput.toLowerCase().includes("gnu tar");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue