Compare commits
24
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4d12de60e | ||
|
|
e105138efe | ||
|
|
367a6c2423 | ||
|
|
8f2bd5d713 | ||
|
|
7654d97eb6 | ||
|
|
0b2505c754 | ||
|
|
f8a69bc473 | ||
|
|
03eca1b0c7 | ||
|
|
4b12bd3649 | ||
|
|
6cd8286138 | ||
|
|
3abbc6c24c | ||
|
|
d594f1e4b3 | ||
|
|
4a2602dd58 | ||
|
|
745f129332 | ||
|
|
daa24d7958 | ||
|
|
bda035c74d | ||
|
|
79acd5bac4 | ||
|
|
b602df7c05 | ||
|
|
80a66f3298 | ||
|
|
7756e7c4cb | ||
|
|
6d774fcb59 | ||
|
|
f05c940e43 | ||
|
|
a71585a450 | ||
|
|
76ac2fcd59 |
Generated
+16287
-2997
File diff suppressed because it is too large
Load Diff
+33
-1
@@ -1,5 +1,6 @@
|
|||||||
import {retry} from '../src/internal/requestUtils'
|
import {retry, retryTypedResponse} from '../src/internal/requestUtils'
|
||||||
import {HttpClientError} from '@actions/http-client'
|
import {HttpClientError} from '@actions/http-client'
|
||||||
|
import * as requestUtils from '../src/internal/requestUtils'
|
||||||
|
|
||||||
interface ITestResponse {
|
interface ITestResponse {
|
||||||
statusCode: number
|
statusCode: number
|
||||||
@@ -145,3 +146,34 @@ test('retry converts errors to response object', async () => {
|
|||||||
null
|
null
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('retryTypedResponse gives an error with error message', async () => {
|
||||||
|
const httpClientError = new HttpClientError(
|
||||||
|
'The cache filesize must be between 0 and 10 * 1024 * 1024 bytes',
|
||||||
|
400
|
||||||
|
)
|
||||||
|
jest.spyOn(requestUtils, 'retry').mockReturnValue(
|
||||||
|
new Promise(resolve => {
|
||||||
|
resolve(httpClientError)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
await retryTypedResponse<string>(
|
||||||
|
'reserveCache',
|
||||||
|
async () =>
|
||||||
|
new Promise(resolve => {
|
||||||
|
resolve({
|
||||||
|
statusCode: 400,
|
||||||
|
result: '',
|
||||||
|
headers: {},
|
||||||
|
error: httpClientError
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toHaveProperty(
|
||||||
|
'message',
|
||||||
|
'The cache filesize must be between 0 and 10 * 1024 * 1024 bytes'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|||||||
+117
-13
@@ -5,6 +5,12 @@ import * as cacheHttpClient from '../src/internal/cacheHttpClient'
|
|||||||
import * as cacheUtils from '../src/internal/cacheUtils'
|
import * as cacheUtils from '../src/internal/cacheUtils'
|
||||||
import {CacheFilename, CompressionMethod} from '../src/internal/constants'
|
import {CacheFilename, CompressionMethod} from '../src/internal/constants'
|
||||||
import * as tar from '../src/internal/tar'
|
import * as tar from '../src/internal/tar'
|
||||||
|
import {ITypedResponse} from '@actions/http-client/interfaces'
|
||||||
|
import {
|
||||||
|
ReserveCacheResponse,
|
||||||
|
ITypedResponseWithError
|
||||||
|
} from '../src/internal/contracts'
|
||||||
|
import {HttpClientError} from '@actions/http-client'
|
||||||
|
|
||||||
jest.mock('../src/internal/cacheHttpClient')
|
jest.mock('../src/internal/cacheHttpClient')
|
||||||
jest.mock('../src/internal/cacheUtils')
|
jest.mock('../src/internal/cacheUtils')
|
||||||
@@ -16,16 +22,13 @@ beforeAll(() => {
|
|||||||
jest.spyOn(core, 'info').mockImplementation(() => {})
|
jest.spyOn(core, 'info').mockImplementation(() => {})
|
||||||
jest.spyOn(core, 'warning').mockImplementation(() => {})
|
jest.spyOn(core, 'warning').mockImplementation(() => {})
|
||||||
jest.spyOn(core, 'error').mockImplementation(() => {})
|
jest.spyOn(core, 'error').mockImplementation(() => {})
|
||||||
|
|
||||||
jest.spyOn(cacheUtils, 'getCacheFileName').mockImplementation(cm => {
|
jest.spyOn(cacheUtils, 'getCacheFileName').mockImplementation(cm => {
|
||||||
const actualUtils = jest.requireActual('../src/internal/cacheUtils')
|
const actualUtils = jest.requireActual('../src/internal/cacheUtils')
|
||||||
return actualUtils.getCacheFileName(cm)
|
return actualUtils.getCacheFileName(cm)
|
||||||
})
|
})
|
||||||
|
|
||||||
jest.spyOn(cacheUtils, 'resolvePaths').mockImplementation(async filePaths => {
|
jest.spyOn(cacheUtils, 'resolvePaths').mockImplementation(async filePaths => {
|
||||||
return filePaths.map(x => path.resolve(x))
|
return filePaths.map(x => path.resolve(x))
|
||||||
})
|
})
|
||||||
|
|
||||||
jest.spyOn(cacheUtils, 'createTempDirectory').mockImplementation(async () => {
|
jest.spyOn(cacheUtils, 'createTempDirectory').mockImplementation(async () => {
|
||||||
return Promise.resolve('/foo/bar')
|
return Promise.resolve('/foo/bar')
|
||||||
})
|
})
|
||||||
@@ -70,6 +73,98 @@ test('save with large cache outputs should fail', async () => {
|
|||||||
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('save with large cache outputs should fail in GHES with error message', async () => {
|
||||||
|
const filePath = 'node_modules'
|
||||||
|
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
||||||
|
const cachePaths = [path.resolve(filePath)]
|
||||||
|
|
||||||
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
||||||
|
|
||||||
|
const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit
|
||||||
|
jest
|
||||||
|
.spyOn(cacheUtils, 'getArchiveFileSizeInBytes')
|
||||||
|
.mockReturnValueOnce(cacheSize)
|
||||||
|
const compression = CompressionMethod.Gzip
|
||||||
|
const getCompressionMock = jest
|
||||||
|
.spyOn(cacheUtils, 'getCompressionMethod')
|
||||||
|
.mockReturnValueOnce(Promise.resolve(compression))
|
||||||
|
|
||||||
|
jest.spyOn(cacheUtils, 'isGhes').mockReturnValueOnce(true)
|
||||||
|
|
||||||
|
const reserveCacheMock = jest
|
||||||
|
.spyOn(cacheHttpClient, 'reserveCache')
|
||||||
|
.mockImplementation(async () => {
|
||||||
|
const response: ITypedResponseWithError<ReserveCacheResponse> = {
|
||||||
|
statusCode: 400,
|
||||||
|
result: null,
|
||||||
|
headers: {},
|
||||||
|
error: new HttpClientError(
|
||||||
|
'The cache filesize must be between 0 and 1073741824 bytes',
|
||||||
|
400
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
})
|
||||||
|
|
||||||
|
await expect(saveCache([filePath], primaryKey)).rejects.toThrowError(
|
||||||
|
'The cache filesize must be between 0 and 1073741824 bytes'
|
||||||
|
)
|
||||||
|
|
||||||
|
const archiveFolder = '/foo/bar'
|
||||||
|
expect(reserveCacheMock).toHaveBeenCalledTimes(1)
|
||||||
|
expect(createTarMock).toHaveBeenCalledTimes(1)
|
||||||
|
expect(createTarMock).toHaveBeenCalledWith(
|
||||||
|
archiveFolder,
|
||||||
|
cachePaths,
|
||||||
|
compression
|
||||||
|
)
|
||||||
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('save with large cache outputs should fail in GHES without error message', async () => {
|
||||||
|
const filePath = 'node_modules'
|
||||||
|
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
|
||||||
|
const cachePaths = [path.resolve(filePath)]
|
||||||
|
|
||||||
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
||||||
|
|
||||||
|
const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit
|
||||||
|
jest
|
||||||
|
.spyOn(cacheUtils, 'getArchiveFileSizeInBytes')
|
||||||
|
.mockReturnValueOnce(cacheSize)
|
||||||
|
const compression = CompressionMethod.Gzip
|
||||||
|
const getCompressionMock = jest
|
||||||
|
.spyOn(cacheUtils, 'getCompressionMethod')
|
||||||
|
.mockReturnValueOnce(Promise.resolve(compression))
|
||||||
|
|
||||||
|
jest.spyOn(cacheUtils, 'isGhes').mockReturnValueOnce(true)
|
||||||
|
|
||||||
|
const reserveCacheMock = jest
|
||||||
|
.spyOn(cacheHttpClient, 'reserveCache')
|
||||||
|
.mockImplementation(async () => {
|
||||||
|
const response: ITypedResponseWithError<ReserveCacheResponse> = {
|
||||||
|
statusCode: 400,
|
||||||
|
result: null,
|
||||||
|
headers: {}
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
})
|
||||||
|
|
||||||
|
await expect(saveCache([filePath], primaryKey)).rejects.toThrowError(
|
||||||
|
'Cache size of ~11264 MB (11811160064 B) is over the data cap limit, not saving cache.'
|
||||||
|
)
|
||||||
|
|
||||||
|
const archiveFolder = '/foo/bar'
|
||||||
|
expect(reserveCacheMock).toHaveBeenCalledTimes(1)
|
||||||
|
expect(createTarMock).toHaveBeenCalledTimes(1)
|
||||||
|
expect(createTarMock).toHaveBeenCalledWith(
|
||||||
|
archiveFolder,
|
||||||
|
cachePaths,
|
||||||
|
compression
|
||||||
|
)
|
||||||
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
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'
|
||||||
@@ -77,7 +172,12 @@ test('save with reserve cache failure should fail', async () => {
|
|||||||
const reserveCacheMock = jest
|
const reserveCacheMock = jest
|
||||||
.spyOn(cacheHttpClient, 'reserveCache')
|
.spyOn(cacheHttpClient, 'reserveCache')
|
||||||
.mockImplementation(async () => {
|
.mockImplementation(async () => {
|
||||||
return -1
|
const response: ITypedResponse<ReserveCacheResponse> = {
|
||||||
|
statusCode: 500,
|
||||||
|
result: null,
|
||||||
|
headers: {}
|
||||||
|
}
|
||||||
|
return response
|
||||||
})
|
})
|
||||||
|
|
||||||
const createTarMock = jest.spyOn(tar, 'createTar')
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
||||||
@@ -94,7 +194,7 @@ test('save with reserve cache failure should fail', async () => {
|
|||||||
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, paths, {
|
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, paths, {
|
||||||
compressionMethod: compression
|
compressionMethod: compression
|
||||||
})
|
})
|
||||||
expect(createTarMock).toHaveBeenCalledTimes(0)
|
expect(createTarMock).toHaveBeenCalledTimes(1)
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(0)
|
expect(saveCacheMock).toHaveBeenCalledTimes(0)
|
||||||
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
@@ -108,7 +208,12 @@ test('save with server error should fail', async () => {
|
|||||||
const reserveCacheMock = jest
|
const reserveCacheMock = jest
|
||||||
.spyOn(cacheHttpClient, 'reserveCache')
|
.spyOn(cacheHttpClient, 'reserveCache')
|
||||||
.mockImplementation(async () => {
|
.mockImplementation(async () => {
|
||||||
return cacheId
|
const response: ITypedResponse<ReserveCacheResponse> = {
|
||||||
|
statusCode: 500,
|
||||||
|
result: {cacheId},
|
||||||
|
headers: {}
|
||||||
|
}
|
||||||
|
return response
|
||||||
})
|
})
|
||||||
|
|
||||||
const createTarMock = jest.spyOn(tar, 'createTar')
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
||||||
@@ -130,17 +235,14 @@ test('save with server error should fail', async () => {
|
|||||||
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, [filePath], {
|
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, [filePath], {
|
||||||
compressionMethod: compression
|
compressionMethod: compression
|
||||||
})
|
})
|
||||||
|
|
||||||
const archiveFolder = '/foo/bar'
|
const archiveFolder = '/foo/bar'
|
||||||
const archiveFile = path.join(archiveFolder, CacheFilename.Zstd)
|
const archiveFile = path.join(archiveFolder, CacheFilename.Zstd)
|
||||||
|
|
||||||
expect(createTarMock).toHaveBeenCalledTimes(1)
|
expect(createTarMock).toHaveBeenCalledTimes(1)
|
||||||
expect(createTarMock).toHaveBeenCalledWith(
|
expect(createTarMock).toHaveBeenCalledWith(
|
||||||
archiveFolder,
|
archiveFolder,
|
||||||
cachePaths,
|
cachePaths,
|
||||||
compression
|
compression
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1)
|
expect(saveCacheMock).toHaveBeenCalledTimes(1)
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile, undefined)
|
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile, undefined)
|
||||||
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
||||||
@@ -155,7 +257,12 @@ test('save with valid inputs uploads a cache', async () => {
|
|||||||
const reserveCacheMock = jest
|
const reserveCacheMock = jest
|
||||||
.spyOn(cacheHttpClient, 'reserveCache')
|
.spyOn(cacheHttpClient, 'reserveCache')
|
||||||
.mockImplementation(async () => {
|
.mockImplementation(async () => {
|
||||||
return cacheId
|
const response: ITypedResponse<ReserveCacheResponse> = {
|
||||||
|
statusCode: 500,
|
||||||
|
result: {cacheId},
|
||||||
|
headers: {}
|
||||||
|
}
|
||||||
|
return response
|
||||||
})
|
})
|
||||||
const createTarMock = jest.spyOn(tar, 'createTar')
|
const createTarMock = jest.spyOn(tar, 'createTar')
|
||||||
|
|
||||||
@@ -171,17 +278,14 @@ test('save with valid inputs uploads a cache', async () => {
|
|||||||
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, [filePath], {
|
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, [filePath], {
|
||||||
compressionMethod: compression
|
compressionMethod: compression
|
||||||
})
|
})
|
||||||
|
|
||||||
const archiveFolder = '/foo/bar'
|
const archiveFolder = '/foo/bar'
|
||||||
const archiveFile = path.join(archiveFolder, CacheFilename.Zstd)
|
const archiveFile = path.join(archiveFolder, CacheFilename.Zstd)
|
||||||
|
|
||||||
expect(createTarMock).toHaveBeenCalledTimes(1)
|
expect(createTarMock).toHaveBeenCalledTimes(1)
|
||||||
expect(createTarMock).toHaveBeenCalledWith(
|
expect(createTarMock).toHaveBeenCalledWith(
|
||||||
archiveFolder,
|
archiveFolder,
|
||||||
cachePaths,
|
cachePaths,
|
||||||
compression
|
compression
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1)
|
expect(saveCacheMock).toHaveBeenCalledTimes(1)
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile, undefined)
|
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile, undefined)
|
||||||
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
expect(getCompressionMock).toHaveBeenCalledTimes(1)
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/cache",
|
"name": "@actions/cache",
|
||||||
"version": "2.0.0",
|
"version": "2.0.2",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/cache",
|
"name": "@actions/cache",
|
||||||
"version": "2.0.0",
|
"version": "2.0.2",
|
||||||
"preview": true,
|
"preview": true,
|
||||||
"description": "Actions cache lib",
|
"description": "Actions cache lib",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
Vendored
+29
-13
@@ -152,17 +152,7 @@ export async function saveCache(
|
|||||||
checkKey(key)
|
checkKey(key)
|
||||||
|
|
||||||
const compressionMethod = await utils.getCompressionMethod()
|
const compressionMethod = await utils.getCompressionMethod()
|
||||||
|
let cacheId = null
|
||||||
core.debug('Reserving Cache')
|
|
||||||
const cacheId = await cacheHttpClient.reserveCache(key, paths, {
|
|
||||||
compressionMethod
|
|
||||||
})
|
|
||||||
if (cacheId === -1) {
|
|
||||||
throw new ReserveCacheError(
|
|
||||||
`Unable to reserve cache with key ${key}, another job may be creating this cache.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
core.debug(`Cache ID: ${cacheId}`)
|
|
||||||
|
|
||||||
const cachePaths = await utils.resolvePaths(paths)
|
const cachePaths = await utils.resolvePaths(paths)
|
||||||
core.debug('Cache Paths:')
|
core.debug('Cache Paths:')
|
||||||
@@ -181,11 +171,12 @@ export async function saveCache(
|
|||||||
if (core.isDebug()) {
|
if (core.isDebug()) {
|
||||||
await listTar(archivePath, compressionMethod)
|
await listTar(archivePath, compressionMethod)
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileSizeLimit = 10 * 1024 * 1024 * 1024 // 10GB per repo limit
|
const fileSizeLimit = 10 * 1024 * 1024 * 1024 // 10GB per repo limit
|
||||||
const archiveFileSize = utils.getArchiveFileSizeInBytes(archivePath)
|
const archiveFileSize = utils.getArchiveFileSizeInBytes(archivePath)
|
||||||
core.debug(`File Size: ${archiveFileSize}`)
|
core.debug(`File Size: ${archiveFileSize}`)
|
||||||
if (archiveFileSize > fileSizeLimit) {
|
|
||||||
|
// For GHES, this check will take place in ReserveCache API with enterprise file size limit
|
||||||
|
if (archiveFileSize > fileSizeLimit && !utils.isGhes()) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Cache size of ~${Math.round(
|
`Cache size of ~${Math.round(
|
||||||
archiveFileSize / (1024 * 1024)
|
archiveFileSize / (1024 * 1024)
|
||||||
@@ -193,6 +184,31 @@ export async function saveCache(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
core.debug('Reserving Cache')
|
||||||
|
const reserveCacheResponse = await cacheHttpClient.reserveCache(
|
||||||
|
key,
|
||||||
|
paths,
|
||||||
|
{
|
||||||
|
compressionMethod,
|
||||||
|
cacheSize: archiveFileSize
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (reserveCacheResponse?.result?.cacheId) {
|
||||||
|
cacheId = reserveCacheResponse?.result?.cacheId
|
||||||
|
} else if (reserveCacheResponse?.statusCode === 400) {
|
||||||
|
throw new Error(
|
||||||
|
reserveCacheResponse?.error?.message ??
|
||||||
|
`Cache size of ~${Math.round(
|
||||||
|
archiveFileSize / (1024 * 1024)
|
||||||
|
)} MB (${archiveFileSize} B) is over the data cap limit, not saving cache.`
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
throw new ReserveCacheError(
|
||||||
|
`Unable to reserve cache with key ${key}, another job may be creating this cache. More details: ${reserveCacheResponse?.error?.message}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
core.debug(`Saving Cache (ID: ${cacheId})`)
|
core.debug(`Saving Cache (ID: ${cacheId})`)
|
||||||
await cacheHttpClient.saveCache(cacheId, archivePath, options)
|
await cacheHttpClient.saveCache(cacheId, archivePath, options)
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
+6
-4
@@ -13,7 +13,8 @@ import {
|
|||||||
InternalCacheOptions,
|
InternalCacheOptions,
|
||||||
CommitCacheRequest,
|
CommitCacheRequest,
|
||||||
ReserveCacheRequest,
|
ReserveCacheRequest,
|
||||||
ReserveCacheResponse
|
ReserveCacheResponse,
|
||||||
|
ITypedResponseWithError
|
||||||
} from './contracts'
|
} from './contracts'
|
||||||
import {downloadCacheHttpClient, downloadCacheStorageSDK} from './downloadUtils'
|
import {downloadCacheHttpClient, downloadCacheStorageSDK} from './downloadUtils'
|
||||||
import {
|
import {
|
||||||
@@ -143,13 +144,14 @@ export async function reserveCache(
|
|||||||
key: string,
|
key: string,
|
||||||
paths: string[],
|
paths: string[],
|
||||||
options?: InternalCacheOptions
|
options?: InternalCacheOptions
|
||||||
): Promise<number> {
|
): Promise<ITypedResponseWithError<ReserveCacheResponse>> {
|
||||||
const httpClient = createHttpClient()
|
const httpClient = createHttpClient()
|
||||||
const version = getCacheVersion(paths, options?.compressionMethod)
|
const version = getCacheVersion(paths, options?.compressionMethod)
|
||||||
|
|
||||||
const reserveCacheRequest: ReserveCacheRequest = {
|
const reserveCacheRequest: ReserveCacheRequest = {
|
||||||
key,
|
key,
|
||||||
version
|
version,
|
||||||
|
cacheSize: options?.cacheSize
|
||||||
}
|
}
|
||||||
const response = await retryTypedResponse('reserveCache', async () =>
|
const response = await retryTypedResponse('reserveCache', async () =>
|
||||||
httpClient.postJson<ReserveCacheResponse>(
|
httpClient.postJson<ReserveCacheResponse>(
|
||||||
@@ -157,7 +159,7 @@ export async function reserveCache(
|
|||||||
reserveCacheRequest
|
reserveCacheRequest
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return response?.result?.cacheId ?? -1
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
function getContentRange(start: number, end: number): string {
|
function getContentRange(start: number, end: number): string {
|
||||||
|
|||||||
+7
@@ -123,3 +123,10 @@ export function assertDefined<T>(name: string, value?: T): T {
|
|||||||
|
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isGhes(): boolean {
|
||||||
|
const ghUrl = new URL(
|
||||||
|
process.env['GITHUB_SERVER_URL'] || 'https://github.com'
|
||||||
|
)
|
||||||
|
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'
|
||||||
|
}
|
||||||
|
|||||||
+8
@@ -1,4 +1,10 @@
|
|||||||
import {CompressionMethod} from './constants'
|
import {CompressionMethod} from './constants'
|
||||||
|
import {ITypedResponse} from '@actions/http-client/interfaces'
|
||||||
|
import {HttpClientError} from '@actions/http-client'
|
||||||
|
|
||||||
|
export interface ITypedResponseWithError<T> extends ITypedResponse<T> {
|
||||||
|
error?: HttpClientError
|
||||||
|
}
|
||||||
|
|
||||||
export interface ArtifactCacheEntry {
|
export interface ArtifactCacheEntry {
|
||||||
cacheKey?: string
|
cacheKey?: string
|
||||||
@@ -14,6 +20,7 @@ export interface CommitCacheRequest {
|
|||||||
export interface ReserveCacheRequest {
|
export interface ReserveCacheRequest {
|
||||||
key: string
|
key: string
|
||||||
version?: string
|
version?: string
|
||||||
|
cacheSize?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReserveCacheResponse {
|
export interface ReserveCacheResponse {
|
||||||
@@ -22,4 +29,5 @@ export interface ReserveCacheResponse {
|
|||||||
|
|
||||||
export interface InternalCacheOptions {
|
export interface InternalCacheOptions {
|
||||||
compressionMethod?: CompressionMethod
|
compressionMethod?: CompressionMethod
|
||||||
|
cacheSize?: number
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-8
@@ -1,10 +1,8 @@
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import {HttpCodes, HttpClientError} from '@actions/http-client'
|
import {HttpCodes, HttpClientError} from '@actions/http-client'
|
||||||
import {
|
import {IHttpClientResponse} from '@actions/http-client/interfaces'
|
||||||
IHttpClientResponse,
|
|
||||||
ITypedResponse
|
|
||||||
} from '@actions/http-client/interfaces'
|
|
||||||
import {DefaultRetryDelay, DefaultRetryAttempts} from './constants'
|
import {DefaultRetryDelay, DefaultRetryAttempts} from './constants'
|
||||||
|
import {ITypedResponseWithError} from './contracts'
|
||||||
|
|
||||||
export function isSuccessStatusCode(statusCode?: number): boolean {
|
export function isSuccessStatusCode(statusCode?: number): boolean {
|
||||||
if (!statusCode) {
|
if (!statusCode) {
|
||||||
@@ -94,14 +92,14 @@ export async function retry<T>(
|
|||||||
|
|
||||||
export async function retryTypedResponse<T>(
|
export async function retryTypedResponse<T>(
|
||||||
name: string,
|
name: string,
|
||||||
method: () => Promise<ITypedResponse<T>>,
|
method: () => Promise<ITypedResponseWithError<T>>,
|
||||||
maxAttempts = DefaultRetryAttempts,
|
maxAttempts = DefaultRetryAttempts,
|
||||||
delay = DefaultRetryDelay
|
delay = DefaultRetryDelay
|
||||||
): Promise<ITypedResponse<T>> {
|
): Promise<ITypedResponseWithError<T>> {
|
||||||
return await retry(
|
return await retry(
|
||||||
name,
|
name,
|
||||||
method,
|
method,
|
||||||
(response: ITypedResponse<T>) => response.statusCode,
|
(response: ITypedResponseWithError<T>) => response.statusCode,
|
||||||
maxAttempts,
|
maxAttempts,
|
||||||
delay,
|
delay,
|
||||||
// If the error object contains the statusCode property, extract it and return
|
// If the error object contains the statusCode property, extract it and return
|
||||||
@@ -111,7 +109,8 @@ export async function retryTypedResponse<T>(
|
|||||||
return {
|
return {
|
||||||
statusCode: error.statusCode,
|
statusCode: error.statusCode,
|
||||||
result: null,
|
result: null,
|
||||||
headers: {}
|
headers: {},
|
||||||
|
error
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return undefined
|
return undefined
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# @actions/github Releases
|
# @actions/github Releases
|
||||||
|
|
||||||
|
### 5.0.1
|
||||||
|
- [Update Octokit Dependencies](https://github.com/actions/toolkit/pull/1037)
|
||||||
### 5.0.0
|
### 5.0.0
|
||||||
- [Update @actions/github to include latest octokit definitions](https://github.com/actions/toolkit/pull/783)
|
- [Update @actions/github to include latest octokit definitions](https://github.com/actions/toolkit/pull/783)
|
||||||
- [Add urls to context](https://github.com/actions/toolkit/pull/794)
|
- [Add urls to context](https://github.com/actions/toolkit/pull/794)
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/github",
|
"name": "@actions/github",
|
||||||
"version": "5.0.0",
|
"version": "5.0.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@actions/github",
|
"name": "@actions/github",
|
||||||
"version": "5.0.0",
|
"version": "5.0.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/http-client": "^1.0.11",
|
"@actions/http-client": "^1.0.11",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/github",
|
"name": "@actions/github",
|
||||||
"version": "5.0.0",
|
"version": "5.0.1",
|
||||||
"description": "Actions github lib",
|
"description": "Actions github lib",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"github",
|
"github",
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
# @actions/glob Releases
|
# @actions/glob Releases
|
||||||
|
|
||||||
|
### 0.3.0
|
||||||
|
- Added a `verbose` option to HashFiles [#1052](https://github.com/actions/toolkit/pull/1052/files)
|
||||||
|
|
||||||
### 0.2.1
|
### 0.2.1
|
||||||
- Update `lockfileVersion` to `v2` in `package-lock.json [#1023](https://github.com/actions/toolkit/pull/1023)
|
- Update `lockfileVersion` to `v2` in `package-lock.json [#1023](https://github.com/actions/toolkit/pull/1023)
|
||||||
|
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/glob",
|
"name": "@actions/glob",
|
||||||
"version": "0.2.1",
|
"version": "0.3.0",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/glob",
|
"name": "@actions/glob",
|
||||||
"version": "0.2.1",
|
"version": "0.3.0",
|
||||||
"preview": true,
|
"preview": true,
|
||||||
"description": "Actions glob lib",
|
"description": "Actions glob lib",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
@@ -26,12 +26,13 @@ export async function create(
|
|||||||
*/
|
*/
|
||||||
export async function hashFiles(
|
export async function hashFiles(
|
||||||
patterns: string,
|
patterns: string,
|
||||||
options?: HashFileOptions
|
options?: HashFileOptions,
|
||||||
|
verbose: Boolean = false
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
let followSymbolicLinks = true
|
let followSymbolicLinks = true
|
||||||
if (options && typeof options.followSymbolicLinks === 'boolean') {
|
if (options && typeof options.followSymbolicLinks === 'boolean') {
|
||||||
followSymbolicLinks = options.followSymbolicLinks
|
followSymbolicLinks = options.followSymbolicLinks
|
||||||
}
|
}
|
||||||
const globber = await create(patterns, {followSymbolicLinks})
|
const globber = await create(patterns, {followSymbolicLinks})
|
||||||
return _hashFiles(globber)
|
return _hashFiles(globber, verbose)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,19 +6,23 @@ import * as util from 'util'
|
|||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import {Globber} from './glob'
|
import {Globber} from './glob'
|
||||||
|
|
||||||
export async function hashFiles(globber: Globber): Promise<string> {
|
export async function hashFiles(
|
||||||
|
globber: Globber,
|
||||||
|
verbose: Boolean = false
|
||||||
|
): Promise<string> {
|
||||||
|
const writeDelegate = verbose ? core.info : core.debug
|
||||||
let hasMatch = false
|
let hasMatch = false
|
||||||
const githubWorkspace = process.env['GITHUB_WORKSPACE'] ?? process.cwd()
|
const githubWorkspace = process.env['GITHUB_WORKSPACE'] ?? process.cwd()
|
||||||
const result = crypto.createHash('sha256')
|
const result = crypto.createHash('sha256')
|
||||||
let count = 0
|
let count = 0
|
||||||
for await (const file of globber.globGenerator()) {
|
for await (const file of globber.globGenerator()) {
|
||||||
core.debug(file)
|
writeDelegate(file)
|
||||||
if (!file.startsWith(`${githubWorkspace}${path.sep}`)) {
|
if (!file.startsWith(`${githubWorkspace}${path.sep}`)) {
|
||||||
core.debug(`Ignore '${file}' since it is not under GITHUB_WORKSPACE.`)
|
writeDelegate(`Ignore '${file}' since it is not under GITHUB_WORKSPACE.`)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (fs.statSync(file).isDirectory()) {
|
if (fs.statSync(file).isDirectory()) {
|
||||||
core.debug(`Skip directory '${file}'.`)
|
writeDelegate(`Skip directory '${file}'.`)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const hash = crypto.createHash('sha256')
|
const hash = crypto.createHash('sha256')
|
||||||
@@ -33,10 +37,10 @@ export async function hashFiles(globber: Globber): Promise<string> {
|
|||||||
result.end()
|
result.end()
|
||||||
|
|
||||||
if (hasMatch) {
|
if (hasMatch) {
|
||||||
core.debug(`Found ${count} files to hash.`)
|
writeDelegate(`Found ${count} files to hash.`)
|
||||||
return result.digest('hex')
|
return result.digest('hex')
|
||||||
} else {
|
} else {
|
||||||
core.debug(`No matches found for glob`)
|
writeDelegate(`No matches found for glob`)
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -332,23 +332,9 @@ describe('rmRF', () => {
|
|||||||
await assertExists(filePath)
|
await assertExists(filePath)
|
||||||
|
|
||||||
const fd = await fs.open(filePath, 'r')
|
const fd = await fs.open(filePath, 'r')
|
||||||
|
await io.rmRF(testPath)
|
||||||
|
|
||||||
let worked: boolean
|
await assertNotExists(testPath)
|
||||||
|
|
||||||
try {
|
|
||||||
await io.rmRF(testPath)
|
|
||||||
worked = true
|
|
||||||
} catch (err) {
|
|
||||||
worked = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (os.platform() === 'win32') {
|
|
||||||
expect(worked).toBe(false)
|
|
||||||
await assertExists(testPath)
|
|
||||||
} else {
|
|
||||||
expect(worked).toBe(true)
|
|
||||||
await assertNotExists(testPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
await fd.close()
|
await fd.close()
|
||||||
await io.rmRF(testPath)
|
await io.rmRF(testPath)
|
||||||
|
|||||||
Generated
+12
-12
@@ -164,9 +164,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/minimist": {
|
"node_modules/minimist": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/mkdirp": {
|
"node_modules/mkdirp": {
|
||||||
@@ -217,9 +217,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pathval": {
|
"node_modules/pathval": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
|
||||||
"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
|
"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": "*"
|
||||||
@@ -404,9 +404,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"mkdirp": {
|
"mkdirp": {
|
||||||
@@ -450,9 +450,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pathval": {
|
"pathval": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
|
||||||
"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
|
"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"propagate": {
|
"propagate": {
|
||||||
|
|||||||
Reference in New Issue
Block a user