@actions/cache
Advanced tools
Comparing version 3.1.1 to 3.1.2
@@ -21,5 +21,6 @@ import { DownloadOptions, UploadOptions } from './options'; | ||
* @param downloadOptions cache download options | ||
* @param enableCrossOsArchive an optional boolean enabled to restore on windows any cache created on any platform | ||
* @returns string returns the key for the cache hit, otherwise returns undefined | ||
*/ | ||
export declare function restoreCache(paths: string[], primaryKey: string, restoreKeys?: string[], options?: DownloadOptions): Promise<string | undefined>; | ||
export declare function restoreCache(paths: string[], primaryKey: string, restoreKeys?: string[], options?: DownloadOptions, enableCrossOsArchive?: boolean): Promise<string | undefined>; | ||
/** | ||
@@ -30,5 +31,6 @@ * Saves a list of files with the specified key | ||
* @param key an explicit key for restoring the cache | ||
* @param enableCrossOsArchive an optional boolean enabled to save cache on windows which could be restored on any platform | ||
* @param options cache upload options | ||
* @returns number returns cacheId if the cache was saved successfully and throws an error if save fails | ||
*/ | ||
export declare function saveCache(paths: string[], key: string, options?: UploadOptions): Promise<number>; | ||
export declare function saveCache(paths: string[], key: string, options?: UploadOptions, enableCrossOsArchive?: boolean): Promise<number>; |
@@ -70,5 +70,6 @@ "use strict"; | ||
* @param downloadOptions cache download options | ||
* @param enableCrossOsArchive an optional boolean enabled to restore on windows any cache created on any platform | ||
* @returns string returns the key for the cache hit, otherwise returns undefined | ||
*/ | ||
function restoreCache(paths, primaryKey, restoreKeys, options) { | ||
function restoreCache(paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
@@ -91,3 +92,4 @@ checkPaths(paths); | ||
const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, { | ||
compressionMethod | ||
compressionMethod, | ||
enableCrossOsArchive | ||
}); | ||
@@ -139,6 +141,7 @@ if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) { | ||
* @param key an explicit key for restoring the cache | ||
* @param enableCrossOsArchive an optional boolean enabled to save cache on windows which could be restored on any platform | ||
* @param options cache upload options | ||
* @returns number returns cacheId if the cache was saved successfully and throws an error if save fails | ||
*/ | ||
function saveCache(paths, key, options) { | ||
function saveCache(paths, key, options, enableCrossOsArchive = false) { | ||
var _a, _b, _c, _d, _e; | ||
@@ -174,2 +177,3 @@ return __awaiter(this, void 0, void 0, function* () { | ||
compressionMethod, | ||
enableCrossOsArchive, | ||
cacheSize: archiveFileSize | ||
@@ -176,0 +180,0 @@ }); |
import { CompressionMethod } from './constants'; | ||
import { ArtifactCacheEntry, InternalCacheOptions, ReserveCacheResponse, ITypedResponseWithError } from './contracts'; | ||
import { DownloadOptions, UploadOptions } from '../options'; | ||
export declare function getCacheVersion(paths: string[], compressionMethod?: CompressionMethod): string; | ||
export declare function getCacheVersion(paths: string[], compressionMethod?: CompressionMethod, enableCrossOsArchive?: boolean): string; | ||
export declare function getCacheEntry(keys: string[], paths: string[], options?: InternalCacheOptions): Promise<ArtifactCacheEntry | null>; | ||
@@ -6,0 +6,0 @@ export declare function downloadCache(archiveLocation: string, archivePath: string, options?: DownloadOptions): Promise<void>; |
@@ -26,3 +26,2 @@ "use strict"; | ||
const utils = __importStar(require("./cacheUtils")); | ||
const constants_1 = require("./constants"); | ||
const downloadUtils_1 = require("./downloadUtils"); | ||
@@ -57,6 +56,13 @@ const options_1 = require("../options"); | ||
} | ||
function getCacheVersion(paths, compressionMethod) { | ||
const components = paths.concat(!compressionMethod || compressionMethod === constants_1.CompressionMethod.Gzip | ||
? [] | ||
: [compressionMethod]); | ||
function getCacheVersion(paths, compressionMethod, enableCrossOsArchive = false) { | ||
const components = paths; | ||
// Add compression method to cache version to restore | ||
// compressed cache as per compression method | ||
if (compressionMethod) { | ||
components.push(compressionMethod); | ||
} | ||
// Only check for windows platforms if enableCrossOsArchive is false | ||
if (process.platform === 'win32' && !enableCrossOsArchive) { | ||
components.push('windows-only'); | ||
} | ||
// Add salt to cache version to support breaking changes in cache entry | ||
@@ -73,5 +79,6 @@ components.push(versionSalt); | ||
const httpClient = createHttpClient(); | ||
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod); | ||
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive); | ||
const resource = `cache?keys=${encodeURIComponent(keys.join(','))}&version=${version}`; | ||
const response = yield requestUtils_1.retryTypedResponse('getCacheEntry', () => __awaiter(this, void 0, void 0, function* () { return httpClient.getJson(getCacheApiUrl(resource)); })); | ||
// Cache not found | ||
if (response.statusCode === 204) { | ||
@@ -90,2 +97,3 @@ // List cache for primary key only if cache miss occurs | ||
if (!cacheDownloadUrl) { | ||
// Cache achiveLocation not found. This should never happen, and hence bail out. | ||
throw new Error('Cache not found.'); | ||
@@ -136,3 +144,3 @@ } | ||
const httpClient = createHttpClient(); | ||
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod); | ||
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive); | ||
const reserveCacheRequest = { | ||
@@ -139,0 +147,0 @@ key, |
@@ -10,4 +10,4 @@ /// <reference types="node" /> | ||
export declare function getCacheFileName(compressionMethod: CompressionMethod): string; | ||
export declare function isGnuTarInstalled(): Promise<boolean>; | ||
export declare function getGnuTarPathOnWindows(): Promise<string>; | ||
export declare function assertDefined<T>(name: string, value?: T): T; | ||
export declare function isGhes(): boolean; |
@@ -135,6 +135,2 @@ "use strict"; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (process.platform === 'win32' && !(yield isGnuTarInstalled())) { | ||
// Disable zstd due to bug https://github.com/actions/cache/issues/301 | ||
return constants_1.CompressionMethod.Gzip; | ||
} | ||
const versionOutput = yield getVersion('zstd'); | ||
@@ -163,9 +159,12 @@ const version = semver.clean(versionOutput); | ||
exports.getCacheFileName = getCacheFileName; | ||
function isGnuTarInstalled() { | ||
function getGnuTarPathOnWindows() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (fs.existsSync(constants_1.GnuTarPathOnWindows)) { | ||
return constants_1.GnuTarPathOnWindows; | ||
} | ||
const versionOutput = yield getVersion('tar'); | ||
return versionOutput.toLowerCase().includes('gnu tar'); | ||
return versionOutput.toLowerCase().includes('gnu tar') ? io.which('tar') : ''; | ||
}); | ||
} | ||
exports.isGnuTarInstalled = isGnuTarInstalled; | ||
exports.getGnuTarPathOnWindows = getGnuTarPathOnWindows; | ||
function assertDefined(name, value) { | ||
@@ -172,0 +171,0 @@ if (value === undefined) { |
@@ -10,4 +10,12 @@ export declare enum CacheFilename { | ||
} | ||
export declare enum ArchiveToolType { | ||
GNU = "gnu", | ||
BSD = "bsd" | ||
} | ||
export declare const DefaultRetryAttempts = 2; | ||
export declare const DefaultRetryDelay = 5000; | ||
export declare const SocketTimeout = 5000; | ||
export declare const GnuTarPathOnWindows: string; | ||
export declare const SystemTarPathOnWindows: string; | ||
export declare const TarFilename = "cache.tar"; | ||
export declare const ManifestFilename = "manifest.txt"; |
@@ -16,2 +16,7 @@ "use strict"; | ||
})(CompressionMethod = exports.CompressionMethod || (exports.CompressionMethod = {})); | ||
var ArchiveToolType; | ||
(function (ArchiveToolType) { | ||
ArchiveToolType["GNU"] = "gnu"; | ||
ArchiveToolType["BSD"] = "bsd"; | ||
})(ArchiveToolType = exports.ArchiveToolType || (exports.ArchiveToolType = {})); | ||
// The default number of retry attempts. | ||
@@ -25,2 +30,8 @@ exports.DefaultRetryAttempts = 2; | ||
exports.SocketTimeout = 5000; | ||
// The default path of GNUtar on hosted Windows runners | ||
exports.GnuTarPathOnWindows = `${process.env['PROGRAMFILES']}\\Git\\usr\\bin\\tar.exe`; | ||
// The default path of BSDtar on hosted Windows runners | ||
exports.SystemTarPathOnWindows = `${process.env['SYSTEMDRIVE']}\\Windows\\System32\\tar.exe`; | ||
exports.TarFilename = 'cache.tar'; | ||
exports.ManifestFilename = 'manifest.txt'; | ||
//# sourceMappingURL=constants.js.map |
@@ -20,2 +20,3 @@ "use strict"; | ||
const exec_1 = require("@actions/exec"); | ||
const core_1 = require("@actions/core"); | ||
const io = __importStar(require("@actions/io")); | ||
@@ -27,18 +28,17 @@ const fs_1 = require("fs"); | ||
const IS_WINDOWS = process.platform === 'win32'; | ||
function getTarPath(args, compressionMethod) { | ||
core_1.exportVariable('MSYS', 'winsymlinks:nativestrict'); | ||
// Returns tar path and type: BSD or GNU | ||
function getTarPath() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
switch (process.platform) { | ||
case 'win32': { | ||
const systemTar = `${process.env['windir']}\\System32\\tar.exe`; | ||
if (compressionMethod !== constants_1.CompressionMethod.Gzip) { | ||
// We only use zstandard compression on windows when gnu tar is installed due to | ||
// a bug with compressing large files with bsdtar + zstd | ||
args.push('--force-local'); | ||
const gnuTar = yield utils.getGnuTarPathOnWindows(); | ||
const systemTar = constants_1.SystemTarPathOnWindows; | ||
if (gnuTar) { | ||
// Use GNUtar as default on windows | ||
return { path: gnuTar, type: constants_1.ArchiveToolType.GNU }; | ||
} | ||
else if (fs_1.existsSync(systemTar)) { | ||
return systemTar; | ||
return { path: systemTar, type: constants_1.ArchiveToolType.BSD }; | ||
} | ||
else if (yield utils.isGnuTarInstalled()) { | ||
args.push('--force-local'); | ||
} | ||
break; | ||
@@ -50,6 +50,10 @@ } | ||
// fix permission denied errors when extracting BSD tar archive with GNU tar - https://github.com/actions/cache/issues/527 | ||
args.push('--delay-directory-restore'); | ||
return gnuTar; | ||
return { path: gnuTar, type: constants_1.ArchiveToolType.GNU }; | ||
} | ||
break; | ||
else { | ||
return { | ||
path: yield io.which('tar', true), | ||
type: constants_1.ArchiveToolType.BSD | ||
}; | ||
} | ||
} | ||
@@ -59,15 +63,78 @@ default: | ||
} | ||
return yield io.which('tar', true); | ||
// Default assumption is GNU tar is present in path | ||
return { | ||
path: yield io.which('tar', true), | ||
type: constants_1.ArchiveToolType.GNU | ||
}; | ||
}); | ||
} | ||
function execTar(args, compressionMethod, cwd) { | ||
// Return arguments for tar as per tarPath, compressionMethod, method type and os | ||
function getTarArgs(tarPath, compressionMethod, type, archivePath = '') { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
yield exec_1.exec(`"${yield getTarPath(args, compressionMethod)}"`, args, { cwd }); | ||
const args = [`"${tarPath.path}"`]; | ||
const cacheFileName = utils.getCacheFileName(compressionMethod); | ||
const tarFile = 'cache.tar'; | ||
const workingDirectory = getWorkingDirectory(); | ||
// Speficic args for BSD tar on windows for workaround | ||
const BSD_TAR_ZSTD = tarPath.type === constants_1.ArchiveToolType.BSD && | ||
compressionMethod !== constants_1.CompressionMethod.Gzip && | ||
IS_WINDOWS; | ||
// Method specific args | ||
switch (type) { | ||
case 'create': | ||
args.push('--posix', '-cf', BSD_TAR_ZSTD | ||
? tarFile | ||
: cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), '--exclude', BSD_TAR_ZSTD | ||
? tarFile | ||
: cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), '-P', '-C', workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), '--files-from', constants_1.ManifestFilename); | ||
break; | ||
case 'extract': | ||
args.push('-xf', BSD_TAR_ZSTD | ||
? tarFile | ||
: archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), '-P', '-C', workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/')); | ||
break; | ||
case 'list': | ||
args.push('-tf', BSD_TAR_ZSTD | ||
? tarFile | ||
: archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), '-P'); | ||
break; | ||
} | ||
catch (error) { | ||
throw new Error(`Tar failed with error: ${error === null || error === void 0 ? void 0 : error.message}`); | ||
// Platform specific args | ||
if (tarPath.type === constants_1.ArchiveToolType.GNU) { | ||
switch (process.platform) { | ||
case 'win32': | ||
args.push('--force-local'); | ||
break; | ||
case 'darwin': | ||
args.push('--delay-directory-restore'); | ||
break; | ||
} | ||
} | ||
return args; | ||
}); | ||
} | ||
// Returns commands to run tar and compression program | ||
function getCommands(compressionMethod, type, archivePath = '') { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let args; | ||
const tarPath = yield getTarPath(); | ||
const tarArgs = yield getTarArgs(tarPath, compressionMethod, type, archivePath); | ||
const compressionArgs = type !== 'create' | ||
? yield getDecompressionProgram(tarPath, compressionMethod, archivePath) | ||
: yield getCompressionProgram(tarPath, compressionMethod); | ||
const BSD_TAR_ZSTD = tarPath.type === constants_1.ArchiveToolType.BSD && | ||
compressionMethod !== constants_1.CompressionMethod.Gzip && | ||
IS_WINDOWS; | ||
if (BSD_TAR_ZSTD && type !== 'create') { | ||
args = [[...compressionArgs].join(' '), [...tarArgs].join(' ')]; | ||
} | ||
else { | ||
args = [[...tarArgs].join(' '), [...compressionArgs].join(' ')]; | ||
} | ||
if (BSD_TAR_ZSTD) { | ||
return args; | ||
} | ||
return [args.join(' ')]; | ||
}); | ||
} | ||
function getWorkingDirectory() { | ||
@@ -78,31 +145,95 @@ var _a; | ||
// Common function for extractTar and listTar to get the compression method | ||
function getCompressionProgram(compressionMethod) { | ||
// -d: Decompress. | ||
// unzstd is equivalent to 'zstd -d' | ||
// --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit. | ||
// Using 30 here because we also support 32-bit self-hosted runners. | ||
switch (compressionMethod) { | ||
case constants_1.CompressionMethod.Zstd: | ||
return [ | ||
'--use-compress-program', | ||
IS_WINDOWS ? 'zstd -d --long=30' : 'unzstd --long=30' | ||
]; | ||
case constants_1.CompressionMethod.ZstdWithoutLong: | ||
return ['--use-compress-program', IS_WINDOWS ? 'zstd -d' : 'unzstd']; | ||
default: | ||
return ['-z']; | ||
} | ||
function getDecompressionProgram(tarPath, compressionMethod, archivePath) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// -d: Decompress. | ||
// unzstd is equivalent to 'zstd -d' | ||
// --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit. | ||
// Using 30 here because we also support 32-bit self-hosted runners. | ||
const BSD_TAR_ZSTD = tarPath.type === constants_1.ArchiveToolType.BSD && | ||
compressionMethod !== constants_1.CompressionMethod.Gzip && | ||
IS_WINDOWS; | ||
switch (compressionMethod) { | ||
case constants_1.CompressionMethod.Zstd: | ||
return BSD_TAR_ZSTD | ||
? [ | ||
'zstd -d --long=30 --force -o', | ||
constants_1.TarFilename, | ||
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/') | ||
] | ||
: [ | ||
'--use-compress-program', | ||
IS_WINDOWS ? '"zstd -d --long=30"' : 'unzstd --long=30' | ||
]; | ||
case constants_1.CompressionMethod.ZstdWithoutLong: | ||
return BSD_TAR_ZSTD | ||
? [ | ||
'zstd -d --force -o', | ||
constants_1.TarFilename, | ||
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/') | ||
] | ||
: ['--use-compress-program', IS_WINDOWS ? '"zstd -d"' : 'unzstd']; | ||
default: | ||
return ['-z']; | ||
} | ||
}); | ||
} | ||
// Used for creating the archive | ||
// -T#: Compress using # working thread. If # is 0, attempt to detect and use the number of physical CPU cores. | ||
// zstdmt is equivalent to 'zstd -T0' | ||
// --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit. | ||
// Using 30 here because we also support 32-bit self-hosted runners. | ||
// Long range mode is added to zstd in v1.3.2 release, so we will not use --long in older version of zstd. | ||
function getCompressionProgram(tarPath, compressionMethod) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const cacheFileName = utils.getCacheFileName(compressionMethod); | ||
const BSD_TAR_ZSTD = tarPath.type === constants_1.ArchiveToolType.BSD && | ||
compressionMethod !== constants_1.CompressionMethod.Gzip && | ||
IS_WINDOWS; | ||
switch (compressionMethod) { | ||
case constants_1.CompressionMethod.Zstd: | ||
return BSD_TAR_ZSTD | ||
? [ | ||
'zstd -T0 --long=30 --force -o', | ||
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), | ||
constants_1.TarFilename | ||
] | ||
: [ | ||
'--use-compress-program', | ||
IS_WINDOWS ? '"zstd -T0 --long=30"' : 'zstdmt --long=30' | ||
]; | ||
case constants_1.CompressionMethod.ZstdWithoutLong: | ||
return BSD_TAR_ZSTD | ||
? [ | ||
'zstd -T0 --force -o', | ||
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), | ||
constants_1.TarFilename | ||
] | ||
: ['--use-compress-program', IS_WINDOWS ? '"zstd -T0"' : 'zstdmt']; | ||
default: | ||
return ['-z']; | ||
} | ||
}); | ||
} | ||
// Executes all commands as separate processes | ||
function execCommands(commands, cwd) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
for (const command of commands) { | ||
try { | ||
yield exec_1.exec(command, undefined, { cwd }); | ||
} | ||
catch (error) { | ||
throw new Error(`${command.split(' ')[0]} failed with error: ${error === null || error === void 0 ? void 0 : error.message}`); | ||
} | ||
} | ||
}); | ||
} | ||
// List the contents of a tar | ||
function listTar(archivePath, compressionMethod) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const args = [ | ||
...getCompressionProgram(compressionMethod), | ||
'-tf', | ||
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), | ||
'-P' | ||
]; | ||
yield execTar(args, compressionMethod); | ||
const commands = yield getCommands(compressionMethod, 'list', archivePath); | ||
yield execCommands(commands); | ||
}); | ||
} | ||
exports.listTar = listTar; | ||
// Extract a tar | ||
function extractTar(archivePath, compressionMethod) { | ||
@@ -113,53 +244,14 @@ return __awaiter(this, void 0, void 0, function* () { | ||
yield io.mkdirP(workingDirectory); | ||
const args = [ | ||
...getCompressionProgram(compressionMethod), | ||
'-xf', | ||
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), | ||
'-P', | ||
'-C', | ||
workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/') | ||
]; | ||
yield execTar(args, compressionMethod); | ||
const commands = yield getCommands(compressionMethod, 'extract', archivePath); | ||
yield execCommands(commands); | ||
}); | ||
} | ||
exports.extractTar = extractTar; | ||
// Create a tar | ||
function createTar(archiveFolder, sourceDirectories, compressionMethod) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// Write source directories to manifest.txt to avoid command length limits | ||
const manifestFilename = 'manifest.txt'; | ||
const cacheFileName = utils.getCacheFileName(compressionMethod); | ||
fs_1.writeFileSync(path.join(archiveFolder, manifestFilename), sourceDirectories.join('\n')); | ||
const workingDirectory = getWorkingDirectory(); | ||
// -T#: Compress using # working thread. If # is 0, attempt to detect and use the number of physical CPU cores. | ||
// zstdmt is equivalent to 'zstd -T0' | ||
// --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit. | ||
// Using 30 here because we also support 32-bit self-hosted runners. | ||
// Long range mode is added to zstd in v1.3.2 release, so we will not use --long in older version of zstd. | ||
function getCompressionProgram() { | ||
switch (compressionMethod) { | ||
case constants_1.CompressionMethod.Zstd: | ||
return [ | ||
'--use-compress-program', | ||
IS_WINDOWS ? 'zstd -T0 --long=30' : 'zstdmt --long=30' | ||
]; | ||
case constants_1.CompressionMethod.ZstdWithoutLong: | ||
return ['--use-compress-program', IS_WINDOWS ? 'zstd -T0' : 'zstdmt']; | ||
default: | ||
return ['-z']; | ||
} | ||
} | ||
const args = [ | ||
'--posix', | ||
...getCompressionProgram(), | ||
'-cf', | ||
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), | ||
'--exclude', | ||
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), | ||
'-P', | ||
'-C', | ||
workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), | ||
'--files-from', | ||
manifestFilename | ||
]; | ||
yield execTar(args, compressionMethod, archiveFolder); | ||
fs_1.writeFileSync(path.join(archiveFolder, constants_1.ManifestFilename), sourceDirectories.join('\n')); | ||
const commands = yield getCommands(compressionMethod, 'create'); | ||
yield execCommands(commands, archiveFolder); | ||
}); | ||
@@ -166,0 +258,0 @@ } |
{ | ||
"name": "@actions/cache", | ||
"version": "3.1.1", | ||
"version": "3.1.2", | ||
"preview": true, | ||
@@ -5,0 +5,0 @@ "description": "Actions cache lib", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
112248
1586
15