Compare commits

..
Author SHA1 Message Date
Thomas Boop 9d05a59451 add link to pr 2022-06-15 11:23:09 -04:00
Thomas Boop af52a43780 1.9.0 release 2022-06-15 11:21:28 -04:00
7 changed files with 44 additions and 90 deletions
+1 -4
View File
@@ -67,7 +67,4 @@
- Fix to avoid saving empty cache when no files are available for caching. ([issue](https://github.com/actions/cache/issues/624)) - Fix to avoid saving empty cache when no files are available for caching. ([issue](https://github.com/actions/cache/issues/624))
### 2.0.6 ### 2.0.6
- Fix `Tar failed with error: The process '/usr/bin/tar' failed with exit code 1` issue when temp directory where tar is getting created is actually the subdirectory of the path mentioned by the user for caching. ([issue](https://github.com/actions/cache/issues/689)) - Fix `Tar failed with error: The process '/usr/bin/tar' failed with exit code 1` issue when temp directory where tar is getting created is actually the subdirectory of the path mentioned by the user for caching. ([issue](https://github.com/actions/cache/issues/689))
### 3.0.0
- Updated actions/cache to suppress Actions cache server error and log warning for those error [#1122](https://github.com/actions/toolkit/pull/1122)
+2 -6
View File
@@ -73,17 +73,13 @@ test('restore with no cache found', async () => {
test('restore with server error should fail', async () => { test('restore with server error should fail', async () => {
const paths = ['node_modules'] const paths = ['node_modules']
const key = 'node-test' const key = 'node-test'
const logWarningMock = jest.spyOn(core, 'warning')
jest.spyOn(cacheHttpClient, 'getCacheEntry').mockImplementation(() => { jest.spyOn(cacheHttpClient, 'getCacheEntry').mockImplementation(() => {
throw new Error('HTTP Error Occurred') throw new Error('HTTP Error Occurred')
}) })
const cacheKey = await restoreCache(paths, key) await expect(restoreCache(paths, key)).rejects.toThrowError(
expect(cacheKey).toBe(undefined) 'HTTP Error Occurred'
expect(logWarningMock).toHaveBeenCalledTimes(1)
expect(logWarningMock).toHaveBeenCalledWith(
'Failed to restore: HTTP Error Occurred'
) )
}) })
+11 -31
View File
@@ -48,7 +48,6 @@ test('save with large cache outputs should fail', async () => {
const cachePaths = [path.resolve(filePath)] const cachePaths = [path.resolve(filePath)]
const createTarMock = jest.spyOn(tar, 'createTar') const createTarMock = jest.spyOn(tar, 'createTar')
const logWarningMock = jest.spyOn(core, 'warning')
const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit
jest jest
@@ -59,11 +58,8 @@ test('save with large cache outputs should fail', async () => {
.spyOn(cacheUtils, 'getCompressionMethod') .spyOn(cacheUtils, 'getCompressionMethod')
.mockReturnValueOnce(Promise.resolve(compression)) .mockReturnValueOnce(Promise.resolve(compression))
const cacheId = await saveCache([filePath], primaryKey) await expect(saveCache([filePath], primaryKey)).rejects.toThrowError(
expect(cacheId).toBe(-1) 'Cache size of ~11264 MB (11811160064 B) is over the 10GB limit, not saving cache.'
expect(logWarningMock).toHaveBeenCalledTimes(1)
expect(logWarningMock).toHaveBeenCalledWith(
'Failed to save: Cache size of ~11264 MB (11811160064 B) is over the 10GB limit, not saving cache.'
) )
const archiveFolder = '/foo/bar' const archiveFolder = '/foo/bar'
@@ -83,7 +79,6 @@ test('save with large cache outputs should fail in GHES with error message', asy
const cachePaths = [path.resolve(filePath)] const cachePaths = [path.resolve(filePath)]
const createTarMock = jest.spyOn(tar, 'createTar') const createTarMock = jest.spyOn(tar, 'createTar')
const logWarningMock = jest.spyOn(core, 'warning')
const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit
jest jest
@@ -111,11 +106,8 @@ test('save with large cache outputs should fail in GHES with error message', asy
return response return response
}) })
const cacheId = await saveCache([filePath], primaryKey) await expect(saveCache([filePath], primaryKey)).rejects.toThrowError(
expect(cacheId).toBe(-1) 'The cache filesize must be between 0 and 1073741824 bytes'
expect(logWarningMock).toHaveBeenCalledTimes(1)
expect(logWarningMock).toHaveBeenCalledWith(
'Failed to save: The cache filesize must be between 0 and 1073741824 bytes'
) )
const archiveFolder = '/foo/bar' const archiveFolder = '/foo/bar'
@@ -135,7 +127,6 @@ test('save with large cache outputs should fail in GHES without error message',
const cachePaths = [path.resolve(filePath)] const cachePaths = [path.resolve(filePath)]
const createTarMock = jest.spyOn(tar, 'createTar') const createTarMock = jest.spyOn(tar, 'createTar')
const logWarningMock = jest.spyOn(core, 'warning')
const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit
jest jest
@@ -159,11 +150,8 @@ test('save with large cache outputs should fail in GHES without error message',
return response return response
}) })
const cacheId = await saveCache([filePath], primaryKey) await expect(saveCache([filePath], primaryKey)).rejects.toThrowError(
expect(cacheId).toBe(-1) 'Cache size of ~11264 MB (11811160064 B) is over the data cap limit, not saving cache.'
expect(logWarningMock).toHaveBeenCalledTimes(1)
expect(logWarningMock).toHaveBeenCalledWith(
'Failed to save: Cache size of ~11264 MB (11811160064 B) is over the data cap limit, not saving cache.'
) )
const archiveFolder = '/foo/bar' const archiveFolder = '/foo/bar'
@@ -180,7 +168,6 @@ test('save with large cache outputs should fail in GHES without error message',
test('save with reserve cache failure should fail', async () => { test('save with reserve cache failure should fail', async () => {
const paths = ['node_modules'] const paths = ['node_modules']
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43' const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
const logInfoMock = jest.spyOn(core, 'info')
const reserveCacheMock = jest const reserveCacheMock = jest
.spyOn(cacheHttpClient, 'reserveCache') .spyOn(cacheHttpClient, 'reserveCache')
@@ -200,13 +187,9 @@ test('save with reserve cache failure should fail', async () => {
.spyOn(cacheUtils, 'getCompressionMethod') .spyOn(cacheUtils, 'getCompressionMethod')
.mockReturnValueOnce(Promise.resolve(compression)) .mockReturnValueOnce(Promise.resolve(compression))
const cacheId = await saveCache(paths, primaryKey) await expect(saveCache(paths, primaryKey)).rejects.toThrowError(
expect(cacheId).toBe(-1) `Unable to reserve cache with key ${primaryKey}, another job may be creating this cache.`
expect(logInfoMock).toHaveBeenCalledTimes(1)
expect(logInfoMock).toHaveBeenCalledWith(
`Failed to save: Unable to reserve cache with key ${primaryKey}, another job may be creating this cache. More details: undefined`
) )
expect(reserveCacheMock).toHaveBeenCalledTimes(1) expect(reserveCacheMock).toHaveBeenCalledTimes(1)
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, paths, { expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, paths, {
compressionMethod: compression compressionMethod: compression
@@ -220,7 +203,7 @@ test('save with server error should fail', async () => {
const filePath = 'node_modules' const filePath = 'node_modules'
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43' const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
const cachePaths = [path.resolve(filePath)] const cachePaths = [path.resolve(filePath)]
const logWarningMock = jest.spyOn(core, 'warning')
const cacheId = 4 const cacheId = 4
const reserveCacheMock = jest const reserveCacheMock = jest
.spyOn(cacheHttpClient, 'reserveCache') .spyOn(cacheHttpClient, 'reserveCache')
@@ -245,12 +228,9 @@ test('save with server error should fail', async () => {
.spyOn(cacheUtils, 'getCompressionMethod') .spyOn(cacheUtils, 'getCompressionMethod')
.mockReturnValueOnce(Promise.resolve(compression)) .mockReturnValueOnce(Promise.resolve(compression))
await saveCache([filePath], primaryKey) await expect(saveCache([filePath], primaryKey)).rejects.toThrowError(
expect(logWarningMock).toHaveBeenCalledTimes(1) 'HTTP Error Occurred'
expect(logWarningMock).toHaveBeenCalledWith(
'Failed to save: HTTP Error Occurred'
) )
expect(reserveCacheMock).toHaveBeenCalledTimes(1) expect(reserveCacheMock).toHaveBeenCalledTimes(1)
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, [filePath], { expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, [filePath], {
compressionMethod: compression compressionMethod: compression
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "@actions/cache", "name": "@actions/cache",
"version": "3.0.0", "version": "2.0.6",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@actions/cache", "name": "@actions/cache",
"version": "3.0.0", "version": "2.0.6",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.2.6", "@actions/core": "^1.2.6",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@actions/cache", "name": "@actions/cache",
"version": "3.0.0", "version": "2.0.6",
"preview": true, "preview": true,
"description": "Actions cache lib", "description": "Actions cache lib",
"keywords": [ "keywords": [
+18 -38
View File
@@ -86,24 +86,23 @@ export async function restoreCache(
} }
const compressionMethod = await utils.getCompressionMethod() const compressionMethod = await utils.getCompressionMethod()
let archivePath = ''
// path are needed to compute version
const cacheEntry = await cacheHttpClient.getCacheEntry(keys, paths, {
compressionMethod
})
if (!cacheEntry?.archiveLocation) {
// Cache not found
return undefined
}
const archivePath = path.join(
await utils.createTempDirectory(),
utils.getCacheFileName(compressionMethod)
)
core.debug(`Archive Path: ${archivePath}`)
try { try {
// path are needed to compute version
const cacheEntry = await cacheHttpClient.getCacheEntry(keys, paths, {
compressionMethod
})
if (!cacheEntry?.archiveLocation) {
// Cache not found
return undefined
}
archivePath = path.join(
await utils.createTempDirectory(),
utils.getCacheFileName(compressionMethod)
)
core.debug(`Archive Path: ${archivePath}`)
// Download the cache from the cache entry // Download the cache from the cache entry
await cacheHttpClient.downloadCache( await cacheHttpClient.downloadCache(
cacheEntry.archiveLocation, cacheEntry.archiveLocation,
@@ -124,16 +123,6 @@ export async function restoreCache(
await extractTar(archivePath, compressionMethod) await extractTar(archivePath, compressionMethod)
core.info('Cache restored successfully') core.info('Cache restored successfully')
return cacheEntry.cacheKey
} catch (error) {
const typedError = error as Error
if (typedError.name === ValidationError.name) {
throw error
} else {
// Supress all non-validation cache related errors because caching should be optional
core.warning(`Failed to restore: ${(error as Error).message}`)
}
} finally { } finally {
// Try to delete the archive to save space // Try to delete the archive to save space
try { try {
@@ -143,7 +132,7 @@ export async function restoreCache(
} }
} }
return undefined return cacheEntry.cacheKey
} }
/** /**
@@ -163,7 +152,7 @@ export async function saveCache(
checkKey(key) checkKey(key)
const compressionMethod = await utils.getCompressionMethod() const compressionMethod = await utils.getCompressionMethod()
let cacheId = -1 let cacheId = null
const cachePaths = await utils.resolvePaths(paths) const cachePaths = await utils.resolvePaths(paths)
core.debug('Cache Paths:') core.debug('Cache Paths:')
@@ -228,15 +217,6 @@ export async function saveCache(
core.debug(`Saving Cache (ID: ${cacheId})`) core.debug(`Saving Cache (ID: ${cacheId})`)
await cacheHttpClient.saveCache(cacheId, archivePath, options) await cacheHttpClient.saveCache(cacheId, archivePath, options)
} catch (error) {
const typedError = error as Error
if (typedError.name === ValidationError.name) {
throw error
} else if (typedError.name === ReserveCacheError.name) {
core.info(`Failed to save: ${typedError.message}`)
} else {
core.warning(`Failed to save: ${typedError.message}`)
}
} finally { } finally {
// Try to delete the archive to save space // Try to delete the archive to save space
try { try {
+9 -8
View File
@@ -61,15 +61,15 @@ export async function extractTar(
// 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)
// --decompress: Decompress. // --d: Decompress.
// --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit. // --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. // Using 30 here because we also support 32-bit self-hosted runners.
function getCompressionProgram(): string[] { function getCompressionProgram(): string[] {
switch (compressionMethod) { switch (compressionMethod) {
case CompressionMethod.Zstd: case CompressionMethod.Zstd:
return ['--use-compress-program', 'zstd --decompress --long=30'] return ['--use-compress-program', 'zstd -d --long=30']
case CompressionMethod.ZstdWithoutLong: case CompressionMethod.ZstdWithoutLong:
return ['--use-compress-program', 'zstd --decompress'] return ['--use-compress-program', 'zstd -d']
default: default:
return ['-z'] return ['-z']
} }
@@ -99,16 +99,16 @@ export async function createTar(
) )
const workingDirectory = getWorkingDirectory() const workingDirectory = getWorkingDirectory()
// --threads=#: Compress using # working thread. If # is 0, attempt to detect and use the number of physical CPU cores. // -T#: Compress using # working thread. If # is 0, attempt to detect and use the number of physical CPU cores.
// --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit. // --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. // 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. // 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(): string[] { function getCompressionProgram(): string[] {
switch (compressionMethod) { switch (compressionMethod) {
case CompressionMethod.Zstd: case CompressionMethod.Zstd:
return ['--use-compress-program', 'zstd --threads=0 --long=30'] return ['--use-compress-program', 'zstd -T0 --long=30']
case CompressionMethod.ZstdWithoutLong: case CompressionMethod.ZstdWithoutLong:
return ['--use-compress-program', 'zstd --threads=0'] return ['--use-compress-program', 'zstd -T0']
default: default:
return ['-z'] return ['-z']
} }
@@ -133,15 +133,16 @@ export async function listTar(
archivePath: string, archivePath: string,
compressionMethod: CompressionMethod compressionMethod: CompressionMethod
): Promise<void> { ): Promise<void> {
// --d: Decompress.
// --long=#: Enables long distance matching with # bits. // --long=#: Enables long distance matching with # bits.
// Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit. // 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. // Using 30 here because we also support 32-bit self-hosted runners.
function getCompressionProgram(): string[] { function getCompressionProgram(): string[] {
switch (compressionMethod) { switch (compressionMethod) {
case CompressionMethod.Zstd: case CompressionMethod.Zstd:
return ['--use-compress-program', 'zstd --long=30'] return ['--use-compress-program', 'zstd -d --long=30']
case CompressionMethod.ZstdWithoutLong: case CompressionMethod.ZstdWithoutLong:
return ['--use-compress-program', 'zstd'] return ['--use-compress-program', 'zstd -d']
default: default:
return ['-z'] return ['-z']
} }