Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d05a59451 | ||
|
|
af52a43780 |
Vendored
+1
-4
@@ -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
@@ -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
@@ -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
@@ -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",
|
||||||
|
|||||||
Vendored
+1
-1
@@ -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": [
|
||||||
|
|||||||
Vendored
+18
-38
@@ -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 {
|
||||||
|
|||||||
Vendored
+9
-8
@@ -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']
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user