Compare commits

..

1 Commits

Author SHA1 Message Date
Sampark Sharma 8e39d78020 Release 3.1.0-beta.2 cache package 2022-12-08 07:13:15 +00:00
9 changed files with 71 additions and 218 deletions
-91
View File
@@ -1,91 +0,0 @@
name: cache-windows-bsd-unit-tests
on:
push:
branches:
- main
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
jobs:
build:
name: Build
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- shell: bash
run: |
rm "C:\Program Files\Git\usr\bin\tar.exe"
- name: Set Node.js 12.x
uses: actions/setup-node@v1
with:
node-version: 12.x
# In order to save & restore cache from a shell script, certain env variables need to be set that are only available in the
# node context. This runs a local action that gets and sets the necessary env variables that are needed
- name: Set env variables
uses: ./packages/cache/__tests__/__fixtures__/
# Need root node_modules because certain npm packages like jest are configured for the entire repository and it won't be possible
# without these to just compile the cache package
- name: Install root npm packages
run: npm ci
- name: Compile cache package
run: |
npm ci
npm run tsc
working-directory: packages/cache
- name: Generate files in working directory
shell: bash
run: packages/cache/__tests__/create-cache-files.sh ${{ runner.os }} test-cache
- name: Generate files outside working directory
shell: bash
run: packages/cache/__tests__/create-cache-files.sh ${{ runner.os }} ~/test-cache
# We're using node -e to call the functions directly available in the @actions/cache package
- name: Save cache using saveCache()
run: |
node -e "Promise.resolve(require('./packages/cache/lib/cache').saveCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}'))"
- name: Delete cache folders before restoring
shell: bash
run: |
rm -rf test-cache
rm -rf ~/test-cache
- name: Restore cache using restoreCache() with http-client
run: |
node -e "Promise.resolve(require('./packages/cache/lib/cache').restoreCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}',[],{useAzureSdk: false}))"
- name: Verify cache restored with http-client
shell: bash
run: |
packages/cache/__tests__/verify-cache-files.sh ${{ runner.os }} test-cache
packages/cache/__tests__/verify-cache-files.sh ${{ runner.os }} ~/test-cache
- name: Delete cache folders before restoring
shell: bash
run: |
rm -rf test-cache
rm -rf ~/test-cache
rm -f cache.tar
- name: Restore cache using restoreCache() with Azure SDK
run: |
node -e "Promise.resolve(require('./packages/cache/lib/cache').restoreCache(['test-cache','~/test-cache'],'test-${{ runner.os }}-${{ github.run_id }}'))"
- name: Verify cache restored with Azure SDK
shell: bash
run: |
packages/cache/__tests__/verify-cache-files.sh ${{ runner.os }} test-cache
packages/cache/__tests__/verify-cache-files.sh ${{ runner.os }} ~/test-cache
+4 -1
View File
@@ -93,4 +93,7 @@
- Added `@azure/abort-controller` to dependencies to fix compatibility issue with ESM [#1208](https://github.com/actions/toolkit/issues/1208)
### 3.1.0-beta.1
- Update actions/cache on windows to use gnu tar and zstd by default and fallback to bsdtar and zstd if gnu tar is not available. ([issue](https://github.com/actions/cache/issues/984))
- Update actions/cache on windows to use gnu tar and zstd by default and fallback to bsdtar and zstd if gnu tar is not available. ([issue](https://github.com/actions/cache/issues/984))
### 3.1.0-beta.2
- Added support for fallback to gzip to restore old caches on windows.
+1 -1
View File
@@ -174,7 +174,7 @@ test('restore with zstd as default but gzip compressed cache found on windows',
const getCacheMock = jest.spyOn(cacheHttpClient, 'getCacheEntry')
getCacheMock
.mockImplementationOnce(async () => {
return Promise.resolve(null)
throw new Error('Cache not found.')
})
.mockImplementationOnce(async () => {
return Promise.resolve(cacheEntry)
+20 -65
View File
@@ -73,9 +73,7 @@ test('zstd extract tar', async () => {
'--use-compress-program',
IS_WINDOWS ? '"zstd -d --long=30"' : 'unzstd --long=30'
])
.join(' '),
undefined,
{cwd: undefined}
.join(' ')
)
})
@@ -94,31 +92,20 @@ test('zstd extract tar with windows BSDtar', async () => {
await tar.extractTar(archivePath, CompressionMethod.Zstd)
expect(mkdirMock).toHaveBeenCalledWith(workspace)
expect(execMock).toHaveBeenCalledTimes(2)
expect(execMock).toHaveBeenNthCalledWith(
1,
expect(execMock).toHaveBeenCalledTimes(1)
expect(execMock).toHaveBeenCalledWith(
[
'zstd -d --long=30 -o',
TarFilename.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
].join(' '),
undefined,
{cwd: undefined}
)
expect(execMock).toHaveBeenNthCalledWith(
2,
[
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'&&',
`"${tarPath}"`,
'-xf',
TarFilename.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'-P',
'-C',
workspace?.replace(/\\/g, '/')
].join(' '),
undefined,
{cwd: undefined}
].join(' ')
)
}
})
@@ -148,9 +135,7 @@ test('gzip extract tar', async () => {
.concat(IS_WINDOWS ? ['--force-local'] : [])
.concat(IS_MAC ? ['--delay-directory-restore'] : [])
.concat(['-z'])
.join(' '),
undefined,
{cwd: undefined}
.join(' ')
)
})
@@ -177,9 +162,7 @@ test('gzip extract GNU tar on windows with GNUtar in path', async () => {
workspace?.replace(/\\/g, '/'),
'--force-local',
'-z'
].join(' '),
undefined,
{cwd: undefined}
].join(' ')
)
}
})
@@ -247,10 +230,8 @@ test('zstd create tar with windows BSDtar', async () => {
const tarPath = SystemTarPathOnWindows
expect(execMock).toHaveBeenCalledTimes(2)
expect(execMock).toHaveBeenNthCalledWith(
1,
expect(execMock).toHaveBeenCalledTimes(1)
expect(execMock).toHaveBeenCalledWith(
[
`"${tarPath}"`,
'--posix',
@@ -262,17 +243,8 @@ test('zstd create tar with windows BSDtar', async () => {
'-C',
workspace?.replace(/\\/g, '/'),
'--files-from',
ManifestFilename
].join(' '),
undefined, // args
{
cwd: archiveFolder
}
)
expect(execMock).toHaveBeenNthCalledWith(
2,
[
ManifestFilename,
'&&',
'zstd -T0 --long=30 -o',
CacheFilename.Zstd.replace(/\\/g, '/'),
TarFilename.replace(/\\/g, '/')
@@ -348,9 +320,7 @@ test('zstd list tar', async () => {
'--use-compress-program',
IS_WINDOWS ? '"zstd -d --long=30"' : 'unzstd --long=30'
])
.join(' '),
undefined,
{cwd: undefined}
.join(' ')
)
})
@@ -365,29 +335,18 @@ test('zstd list tar with windows BSDtar', async () => {
await tar.listTar(archivePath, CompressionMethod.Zstd)
const tarPath = SystemTarPathOnWindows
expect(execMock).toHaveBeenCalledTimes(2)
expect(execMock).toHaveBeenNthCalledWith(
1,
expect(execMock).toHaveBeenCalledTimes(1)
expect(execMock).toHaveBeenCalledWith(
[
'zstd -d --long=30 -o',
TarFilename.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
].join(' '),
undefined,
{cwd: undefined}
)
expect(execMock).toHaveBeenNthCalledWith(
2,
[
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'&&',
`"${tarPath}"`,
'-tf',
TarFilename.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'-P'
].join(' '),
undefined,
{cwd: undefined}
].join(' ')
)
}
})
@@ -413,9 +372,7 @@ test('zstdWithoutLong list tar', async () => {
.concat(IS_WINDOWS ? ['--force-local'] : [])
.concat(IS_MAC ? ['--delay-directory-restore'] : [])
.concat(['--use-compress-program', IS_WINDOWS ? '"zstd -d"' : 'unzstd'])
.join(' '),
undefined,
{cwd: undefined}
.join(' ')
)
})
@@ -439,8 +396,6 @@ test('gzip list tar', async () => {
.concat(IS_WINDOWS ? ['--force-local'] : [])
.concat(IS_MAC ? ['--delay-directory-restore'] : [])
.concat(['-z'])
.join(' '),
undefined,
{cwd: undefined}
.join(' ')
)
})
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "@actions/cache",
"version": "3.1.0-beta.1",
"version": "3.1.0-beta.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@actions/cache",
"version": "3.1.0-beta.1",
"version": "3.1.0-beta.2",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.10.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@actions/cache",
"version": "3.1.0-beta.1",
"version": "3.1.0-beta.2",
"preview": true,
"description": "Actions cache lib",
"keywords": [
+14 -13
View File
@@ -91,12 +91,14 @@ export async function restoreCache(
let compressionMethod = await utils.getCompressionMethod()
let archivePath = ''
try {
// path are needed to compute version
cacheEntry = await cacheHttpClient.getCacheEntry(keys, paths, {
compressionMethod
})
if (!cacheEntry?.archiveLocation) {
// This is to support the old cache entry created by gzip on windows.
try {
// path are needed to compute version
cacheEntry = await cacheHttpClient.getCacheEntry(keys, paths, {
compressionMethod
})
} catch (error) {
// This is to support the old cache entry created
// by the old version of the cache action on windows.
if (
process.platform === 'win32' &&
compressionMethod !== CompressionMethod.Gzip
@@ -106,18 +108,17 @@ export async function restoreCache(
compressionMethod
})
if (!cacheEntry?.archiveLocation) {
return undefined
throw error
}
core.debug(
"Couldn't find cache entry with zstd compression, falling back to gzip compression."
)
} else {
// Cache not found
return undefined
throw error
}
}
if (!cacheEntry?.archiveLocation) {
// Cache not found
return undefined
}
archivePath = path.join(
await utils.createTempDirectory(),
utils.getCacheFileName(compressionMethod)
-2
View File
@@ -104,7 +104,6 @@ export async function getCacheEntry(
httpClient.getJson<ArtifactCacheEntry>(getCacheApiUrl(resource))
)
if (response.statusCode === 204) {
// Cache not found
return null
}
if (!isSuccessStatusCode(response.statusCode)) {
@@ -114,7 +113,6 @@ export async function getCacheEntry(
const cacheResult = response.result
const cacheDownloadUrl = cacheResult?.archiveLocation
if (!cacheDownloadUrl) {
// Cache achiveLocation not found. This should never happen, and hence bail out.
throw new Error('Cache not found.')
}
core.setSecret(cacheDownloadUrl)
+29 -42
View File
@@ -14,7 +14,7 @@ import {
const IS_WINDOWS = process.platform === 'win32'
// Returns tar path and type: BSD or GNU
// Function also mutates the args array. For non-mutation call with passing an empty array.
async function getTarPath(): Promise<ArchiveTool> {
switch (process.platform) {
case 'win32': {
@@ -43,7 +43,6 @@ async function getTarPath(): Promise<ArchiveTool> {
default:
break
}
// Default assumption is GNU tar is present in path
return <ArchiveTool>{
path: await io.which('tar', true),
type: ArchiveToolType.GNU
@@ -61,7 +60,6 @@ async function getTarArgs(
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 === ArchiveToolType.BSD &&
compressionMethod !== CompressionMethod.Gzip &&
@@ -124,14 +122,11 @@ async function getTarArgs(
return args
}
// Returns commands to run tar and compression program
async function getCommands(
async function getArgs(
compressionMethod: CompressionMethod,
type: string,
archivePath = ''
): Promise<string[]> {
let args
): Promise<string> {
const tarPath = await getTarPath()
const tarArgs = await getTarArgs(
tarPath,
@@ -147,18 +142,11 @@ async function getCommands(
tarPath.type === ArchiveToolType.BSD &&
compressionMethod !== CompressionMethod.Gzip &&
IS_WINDOWS
if (BSD_TAR_ZSTD && type !== 'create') {
args = [[...compressionArgs].join(' '), [...tarArgs].join(' ')]
return [...compressionArgs, ...tarArgs].join(' ')
} else {
args = [[...tarArgs].join(' '), [...compressionArgs].join(' ')]
return [...tarArgs, ...compressionArgs].join(' ')
}
if (BSD_TAR_ZSTD) {
return args
}
return [args.join(' ')]
}
function getWorkingDirectory(): string {
@@ -185,7 +173,8 @@ async function getDecompressionProgram(
? [
'zstd -d --long=30 -o',
TarFilename,
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'&&'
]
: [
'--use-compress-program',
@@ -196,7 +185,8 @@ async function getDecompressionProgram(
? [
'zstd -d -o',
TarFilename,
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'&&'
]
: ['--use-compress-program', IS_WINDOWS ? '"zstd -d"' : 'unzstd']
default:
@@ -204,7 +194,6 @@ async function getDecompressionProgram(
}
}
// 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.
@@ -223,6 +212,7 @@ async function getCompressionProgram(
case CompressionMethod.Zstd:
return BSD_TAR_ZSTD
? [
'&&',
'zstd -T0 --long=30 -o',
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
TarFilename
@@ -234,6 +224,7 @@ async function getCompressionProgram(
case CompressionMethod.ZstdWithoutLong:
return BSD_TAR_ZSTD
? [
'&&',
'zstd -T0 -o',
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
TarFilename
@@ -244,29 +235,18 @@ async function getCompressionProgram(
}
}
// Executes all commands as separate processes
async function execCommands(commands: string[], cwd?: string): Promise<void> {
for (const command of commands) {
try {
await exec(command, undefined, {cwd})
} catch (error) {
throw new Error(
`${command.split(' ')[0]} failed with error: ${error?.message}`
)
}
}
}
// List the contents of a tar
export async function listTar(
archivePath: string,
compressionMethod: CompressionMethod
): Promise<void> {
const commands = await getCommands(compressionMethod, 'list', archivePath)
await execCommands(commands)
const args = await getArgs(compressionMethod, 'list', archivePath)
try {
await exec(args)
} catch (error) {
throw new Error(`Tar failed with error: ${error?.message}`)
}
}
// Extract a tar
export async function extractTar(
archivePath: string,
compressionMethod: CompressionMethod
@@ -274,11 +254,14 @@ export async function extractTar(
// Create directory to extract tar into
const workingDirectory = getWorkingDirectory()
await io.mkdirP(workingDirectory)
const commands = await getCommands(compressionMethod, 'extract', archivePath)
await execCommands(commands)
const args = await getArgs(compressionMethod, 'extract', archivePath)
try {
await exec(args)
} catch (error) {
throw new Error(`Tar failed with error: ${error?.message}`)
}
}
// Create a tar
export async function createTar(
archiveFolder: string,
sourceDirectories: string[],
@@ -289,6 +272,10 @@ export async function createTar(
path.join(archiveFolder, ManifestFilename),
sourceDirectories.join('\n')
)
const commands = await getCommands(compressionMethod, 'create')
await execCommands(commands, archiveFolder)
const args = await getArgs(compressionMethod, 'create')
try {
await exec(args, undefined, {cwd: archiveFolder})
} catch (error) {
throw new Error(`Tar failed with error: ${error?.message}`)
}
}