Compare commits

..
Author SHA1 Message Date
Lovepreet Singh bc772ce6eb Move zstd to use long-form flags instead of short-form 2022-07-14 22:17:00 +05:30
39 changed files with 7000 additions and 7716 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
+3 -3
View File
@@ -4,7 +4,7 @@ Self-hosted runners [can be configured](https://help.github.com/en/actions/hosti
For actions to **just work** behind a proxy server: For actions to **just work** behind a proxy server:
1. Use [tool-cache](/packages/tool-cache) version >= 1.3.1 1. Use [tool-cache] version >= 1.3.1
2. Optionally use [actions/http-client](/packages/http-client) 2. Optionally use [actions/http-client](https://github.com/actions/http-client)
If you are using other http clients, refer to the [environment variables set by the runner](https://help.github.com/en/actions/hosting-your-own-runners/using-a-proxy-server-with-self-hosted-runners). If you are using other http clients, refer to the [environment variables set by the runner](https://help.github.com/en/actions/hosting-your-own-runners/using-a-proxy-server-with-self-hosted-runners).
+6668 -6443
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -24,7 +24,7 @@
"eslint-plugin-jest": "^22.21.0", "eslint-plugin-jest": "^22.21.0",
"flow-bin": "^0.115.0", "flow-bin": "^0.115.0",
"jest": "^27.2.5", "jest": "^27.2.5",
"lerna": "^5.4.0", "lerna": "^4.0.0",
"prettier": "^1.19.1", "prettier": "^1.19.1",
"ts-jest": "^27.0.5", "ts-jest": "^27.0.5",
"typescript": "^3.9.9" "typescript": "^3.9.9"
+28 -25
View File
@@ -6,10 +6,10 @@
"packages": { "packages": {
"": { "": {
"name": "@actions/artifact", "name": "@actions/artifact",
"version": "1.1.0", "version": "1.0.1",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.9.1", "@actions/core": "^1.2.6",
"@actions/http-client": "^2.0.1", "@actions/http-client": "^2.0.1",
"tmp": "^0.2.1", "tmp": "^0.2.1",
"tmp-promise": "^3.0.2" "tmp-promise": "^3.0.2"
@@ -20,12 +20,19 @@
} }
}, },
"node_modules/@actions/core": { "node_modules/@actions/core": {
"version": "1.9.1", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz",
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==",
"dependencies": { "dependencies": {
"@actions/http-client": "^2.0.1", "@actions/http-client": "^1.0.11"
"uuid": "^8.3.2" }
},
"node_modules/@actions/core/node_modules/@actions/http-client": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
"dependencies": {
"tunnel": "0.0.6"
} }
}, },
"node_modules/@actions/http-client": { "node_modules/@actions/http-client": {
@@ -180,14 +187,6 @@
"node": ">=4.2.0" "node": ">=4.2.0"
} }
}, },
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/wrappy": { "node_modules/wrappy": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
@@ -196,12 +195,21 @@
}, },
"dependencies": { "dependencies": {
"@actions/core": { "@actions/core": {
"version": "1.9.1", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz",
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==",
"requires": { "requires": {
"@actions/http-client": "^2.0.1", "@actions/http-client": "^1.0.11"
"uuid": "^8.3.2" },
"dependencies": {
"@actions/http-client": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
"requires": {
"tunnel": "0.0.6"
}
}
} }
}, },
"@actions/http-client": { "@actions/http-client": {
@@ -325,11 +333,6 @@
"integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==",
"dev": true "dev": true
}, },
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
},
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+1 -1
View File
@@ -37,7 +37,7 @@
"url": "https://github.com/actions/toolkit/issues" "url": "https://github.com/actions/toolkit/issues"
}, },
"dependencies": { "dependencies": {
"@actions/core": "^1.9.1", "@actions/core": "^1.2.6",
"@actions/http-client": "^2.0.1", "@actions/http-client": "^2.0.1",
"tmp": "^0.2.1", "tmp": "^0.2.1",
"tmp-promise": "^3.0.2" "tmp-promise": "^3.0.2"
+4 -9
View File
@@ -2,17 +2,17 @@
> Functions necessary for caching dependencies and build outputs to improve workflow execution time. > Functions necessary for caching dependencies and build outputs to improve workflow execution time.
See ["Caching dependencies to speed up workflows"](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows) for how caching works. See ["Caching dependencies to speed up workflows"](https://help.github.com/github/automating-your-workflow-with-github-actions/caching-dependencies-to-speed-up-workflows) for how caching works.
Note that GitHub will remove any cache entries that have not been accessed in over 7 days. There is no limit on the number of caches you can store, but the total size of all caches in a repository is limited to 10 GB. If you exceed this limit, GitHub will save your cache but will begin evicting caches until the total size is less than 10 GB. Note that GitHub will remove any cache entries that have not been accessed in over 7 days. There is no limit on the number of caches you can store, but the total size of all caches in a repository is limited to 10 GB. If you exceed this limit, GitHub will save your cache but will begin evicting caches until the total size is less than 10 GB.
## Usage ## Usage
This package is used by the v2+ versions of our first party cache action. You can find an example implementation in the cache repo [here](https://github.com/actions/cache). This package is used by the v2+ versions of our first party cache action. You can find an example implementation in the cache repo [here](https://github.com/actions/cache).
#### Save Cache #### Save Cache
Saves a cache containing the files in `paths` using the `key` provided. The files would be compressed using zstandard compression algorithm if zstd is installed, otherwise gzip is used. Function returns the cache id if the cache was saved succesfully and throws an error if cache upload fails. Saves a cache containing the files in `paths` using the `key` provided. The files would be compressed using zstandard compression algorithm if zstd is installed, otherwise gzip is used. Function returns the cache id if the cache was saved succesfully and throws an error if cache upload fails.
```js ```js
const cache = require('@actions/cache'); const cache = require('@actions/cache');
@@ -26,7 +26,7 @@ const cacheId = await cache.saveCache(paths, key)
#### Restore Cache #### Restore Cache
Restores a cache based on `key` and `restoreKeys` to the `paths` provided. Function returns the cache key for cache hit and returns undefined if cache not found. Restores a cache based on `key` and `restoreKeys` to the `paths` provided. Function returns the cache key for cache hit and returns undefined if cache not found.
```js ```js
const cache = require('@actions/cache'); const cache = require('@actions/cache');
@@ -42,8 +42,3 @@ const restoreKeys = [
const cacheKey = await cache.restoreCache(paths, key, restoreKeys) const cacheKey = await cache.restoreCache(paths, key, restoreKeys)
``` ```
##### Cache segment restore timeout
A cache gets downloaded in multiple segments of fixed sizes (`1GB` for a `32-bit` runner and `2GB` for a `64-bit` runner). Sometimes, a segment download gets stuck which causes the workflow job to be stuck forever and fail. Version `v3.0.4` of cache package introduces a segment download timeout. The segment download timeout will allow the segment download to get aborted and hence allow the job to proceed with a cache miss.
Default value of this timeout is 60 minutes and can be customized by specifying an [environment variable](https://docs.github.com/en/actions/learn-github-actions/environment-variables) named `SEGMENT_DOWNLOAD_TIMEOUT_MINS` with timeout value in minutes.
+1 -24
View File
@@ -70,27 +70,4 @@
- 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 ### 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) - Updated actions/cache to suppress Actions cache server error and log warning for those error [#1122](https://github.com/actions/toolkit/pull/1122)
### 3.0.1
- Fix [#833](https://github.com/actions/cache/issues/833) - cache doesn't work with github workspace directory.
- Fix [#809](https://github.com/actions/cache/issues/809) `zstd -d: no such file or directory` error on AWS self-hosted runners.
### 3.0.2
- Added 1 hour timeout for the download stuck issue [#810](https://github.com/actions/cache/issues/810).
### 3.0.3
- Bug fixes for download stuck issue [#810](https://github.com/actions/cache/issues/810).
### 3.0.4
- Fix zstd not working for windows on gnu tar in issues [#888](https://github.com/actions/cache/issues/888) and [#891](https://github.com/actions/cache/issues/891).
- Allowing users to provide a custom timeout as input for aborting download of a cache segment using an environment variable `SEGMENT_DOWNLOAD_TIMEOUT_MINS`. Default is 60 minutes.
### 3.0.5
- Update `@actions/cache` to use `@actions/core@^1.10.0`
### 3.0.6
- 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))
-6
View File
@@ -32,9 +32,3 @@ test('assertDefined throws if undefined', () => {
test('assertDefined returns value', () => { test('assertDefined returns value', () => {
expect(cacheUtils.assertDefined('test', 5)).toBe(5) expect(cacheUtils.assertDefined('test', 5)).toBe(5)
}) })
test('resolvePaths works on github workspace directory', async () => {
const workspace = process.env['GITHUB_WORKSPACE'] ?? '.'
const paths = await cacheUtils.resolvePaths([workspace])
expect(paths.length).toBeGreaterThan(0)
})
+2 -23
View File
@@ -8,7 +8,6 @@ import {
const useAzureSdk = true const useAzureSdk = true
const downloadConcurrency = 8 const downloadConcurrency = 8
const timeoutInMs = 30000 const timeoutInMs = 30000
const segmentTimeoutInMs = 3600000
const uploadConcurrency = 4 const uploadConcurrency = 4
const uploadChunkSize = 32 * 1024 * 1024 const uploadChunkSize = 32 * 1024 * 1024
@@ -18,8 +17,7 @@ test('getDownloadOptions sets defaults', async () => {
expect(actualOptions).toEqual({ expect(actualOptions).toEqual({
useAzureSdk, useAzureSdk,
downloadConcurrency, downloadConcurrency,
timeoutInMs, timeoutInMs
segmentTimeoutInMs
}) })
}) })
@@ -27,8 +25,7 @@ test('getDownloadOptions overrides all settings', async () => {
const expectedOptions: DownloadOptions = { const expectedOptions: DownloadOptions = {
useAzureSdk: false, useAzureSdk: false,
downloadConcurrency: 14, downloadConcurrency: 14,
timeoutInMs: 20000, timeoutInMs: 20000
segmentTimeoutInMs: 3600000
} }
const actualOptions = getDownloadOptions(expectedOptions) const actualOptions = getDownloadOptions(expectedOptions)
@@ -55,21 +52,3 @@ test('getUploadOptions overrides all settings', async () => {
expect(actualOptions).toEqual(expectedOptions) expect(actualOptions).toEqual(expectedOptions)
}) })
test('getDownloadOptions overrides download timeout minutes', async () => {
const expectedOptions: DownloadOptions = {
useAzureSdk: false,
downloadConcurrency: 14,
timeoutInMs: 20000,
segmentTimeoutInMs: 3600000
}
process.env.SEGMENT_DOWNLOAD_TIMEOUT_MINS = '10'
const actualOptions = getDownloadOptions(expectedOptions)
expect(actualOptions.useAzureSdk).toEqual(expectedOptions.useAzureSdk)
expect(actualOptions.downloadConcurrency).toEqual(
expectedOptions.downloadConcurrency
)
expect(actualOptions.timeoutInMs).toEqual(expectedOptions.timeoutInMs)
expect(actualOptions.segmentTimeoutInMs).toEqual(600000)
})
-75
View File
@@ -161,81 +161,6 @@ test('restore with gzip compressed cache found', async () => {
expect(getCompressionMock).toHaveBeenCalledTimes(1) expect(getCompressionMock).toHaveBeenCalledTimes(1)
}) })
test('restore with zstd as default but gzip compressed cache found on windows', async () => {
if (process.platform === 'win32') {
const paths = ['node_modules']
const key = 'node-test'
const cacheEntry: ArtifactCacheEntry = {
cacheKey: key,
scope: 'refs/heads/main',
archiveLocation: 'www.actionscache.test/download'
}
const getCacheMock = jest.spyOn(cacheHttpClient, 'getCacheEntry')
getCacheMock
.mockImplementationOnce(async () => {
return Promise.resolve(null)
})
.mockImplementationOnce(async () => {
return Promise.resolve(cacheEntry)
})
const tempPath = '/foo/bar'
const createTempDirectoryMock = jest.spyOn(
cacheUtils,
'createTempDirectory'
)
createTempDirectoryMock.mockImplementation(async () => {
return Promise.resolve(tempPath)
})
const archivePath = path.join(tempPath, CacheFilename.Gzip)
const downloadCacheMock = jest.spyOn(cacheHttpClient, 'downloadCache')
const fileSize = 142
const getArchiveFileSizeInBytesMock = jest
.spyOn(cacheUtils, 'getArchiveFileSizeInBytes')
.mockReturnValue(fileSize)
const extractTarMock = jest.spyOn(tar, 'extractTar')
const unlinkFileMock = jest.spyOn(cacheUtils, 'unlinkFile')
const compression = CompressionMethod.Zstd
const getCompressionMock = jest
.spyOn(cacheUtils, 'getCompressionMethod')
.mockReturnValue(Promise.resolve(compression))
const cacheKey = await restoreCache(paths, key)
expect(cacheKey).toBe(key)
expect(getCacheMock).toHaveBeenNthCalledWith(1, [key], paths, {
compressionMethod: compression
})
expect(getCacheMock).toHaveBeenNthCalledWith(2, [key], paths, {
compressionMethod: CompressionMethod.Gzip
})
expect(createTempDirectoryMock).toHaveBeenCalledTimes(1)
expect(downloadCacheMock).toHaveBeenCalledWith(
cacheEntry.archiveLocation,
archivePath,
undefined
)
expect(getArchiveFileSizeInBytesMock).toHaveBeenCalledWith(archivePath)
expect(extractTarMock).toHaveBeenCalledTimes(1)
expect(extractTarMock).toHaveBeenCalledWith(
archivePath,
CompressionMethod.Gzip
)
expect(unlinkFileMock).toHaveBeenCalledTimes(1)
expect(unlinkFileMock).toHaveBeenCalledWith(archivePath)
expect(getCompressionMock).toHaveBeenCalledTimes(1)
}
})
test('restore with zstd compressed cache found', async () => { test('restore with zstd compressed cache found', async () => {
const paths = ['node_modules'] const paths = ['node_modules']
const key = 'node-test' const key = 'node-test'
+49 -224
View File
@@ -1,14 +1,7 @@
import * as exec from '@actions/exec' import * as exec from '@actions/exec'
import * as io from '@actions/io' import * as io from '@actions/io'
import * as path from 'path' import * as path from 'path'
import { import {CacheFilename, CompressionMethod} from '../src/internal/constants'
CacheFilename,
CompressionMethod,
GnuTarPathOnWindows,
ManifestFilename,
SystemTarPathOnWindows,
TarFilename
} from '../src/internal/constants'
import * as tar from '../src/internal/tar' import * as tar from '../src/internal/tar'
import * as utils from '../src/internal/cacheUtils' import * as utils from '../src/internal/cacheUtils'
// eslint-disable-next-line @typescript-eslint/no-require-imports // eslint-disable-next-line @typescript-eslint/no-require-imports
@@ -20,7 +13,7 @@ jest.mock('@actions/io')
const IS_WINDOWS = process.platform === 'win32' const IS_WINDOWS = process.platform === 'win32'
const IS_MAC = process.platform === 'darwin' const IS_MAC = process.platform === 'darwin'
const defaultTarPath = IS_MAC ? 'gtar' : 'tar' const defaultTarPath = process.platform === 'darwin' ? 'gtar' : 'tar'
function getTempDir(): string { function getTempDir(): string {
return path.join(__dirname, '_temp', 'tar') return path.join(__dirname, '_temp', 'tar')
@@ -35,10 +28,6 @@ beforeAll(async () => {
await jest.requireActual('@actions/io').rmRF(getTempDir()) await jest.requireActual('@actions/io').rmRF(getTempDir())
}) })
beforeEach(async () => {
jest.restoreAllMocks()
})
afterAll(async () => { afterAll(async () => {
delete process.env['GITHUB_WORKSPACE'] delete process.env['GITHUB_WORKSPACE']
await jest.requireActual('@actions/io').rmRF(getTempDir()) await jest.requireActual('@actions/io').rmRF(getTempDir())
@@ -52,15 +41,16 @@ test('zstd extract tar', async () => {
? `${process.env['windir']}\\fakepath\\cache.tar` ? `${process.env['windir']}\\fakepath\\cache.tar`
: 'cache.tar' : 'cache.tar'
const workspace = process.env['GITHUB_WORKSPACE'] const workspace = process.env['GITHUB_WORKSPACE']
const tarPath = IS_WINDOWS ? GnuTarPathOnWindows : defaultTarPath
await tar.extractTar(archivePath, CompressionMethod.Zstd) await tar.extractTar(archivePath, CompressionMethod.Zstd)
expect(mkdirMock).toHaveBeenCalledWith(workspace) expect(mkdirMock).toHaveBeenCalledWith(workspace)
expect(execMock).toHaveBeenCalledTimes(1) expect(execMock).toHaveBeenCalledTimes(1)
expect(execMock).toHaveBeenCalledWith( expect(execMock).toHaveBeenCalledWith(
`"${defaultTarPath}"`,
[ [
`"${tarPath}"`, '--use-compress-program',
'zstd -d --long=30',
'-xf', '-xf',
IS_WINDOWS ? archivePath.replace(/\\/g, '/') : archivePath, IS_WINDOWS ? archivePath.replace(/\\/g, '/') : archivePath,
'-P', '-P',
@@ -68,61 +58,11 @@ test('zstd extract tar', async () => {
IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace
] ]
.concat(IS_WINDOWS ? ['--force-local'] : []) .concat(IS_WINDOWS ? ['--force-local'] : [])
.concat(IS_MAC ? ['--delay-directory-restore'] : []) .concat(IS_MAC ? ['--delay-directory-restore'] : []),
.concat([
'--use-compress-program',
IS_WINDOWS ? '"zstd -d --long=30"' : 'unzstd --long=30'
])
.join(' '),
undefined,
{cwd: undefined} {cwd: undefined}
) )
}) })
test('zstd extract tar with windows BSDtar', async () => {
if (IS_WINDOWS) {
const mkdirMock = jest.spyOn(io, 'mkdirP')
const execMock = jest.spyOn(exec, 'exec')
jest
.spyOn(utils, 'getGnuTarPathOnWindows')
.mockReturnValue(Promise.resolve(''))
const archivePath = `${process.env['windir']}\\fakepath\\cache.tar`
const workspace = process.env['GITHUB_WORKSPACE']
const tarPath = SystemTarPathOnWindows
await tar.extractTar(archivePath, CompressionMethod.Zstd)
expect(mkdirMock).toHaveBeenCalledWith(workspace)
expect(execMock).toHaveBeenCalledTimes(2)
expect(execMock).toHaveBeenNthCalledWith(
1,
[
'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,
[
`"${tarPath}"`,
'-xf',
TarFilename.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'-P',
'-C',
workspace?.replace(/\\/g, '/')
].join(' '),
undefined,
{cwd: undefined}
)
}
})
test('gzip extract tar', async () => { test('gzip extract tar', async () => {
const mkdirMock = jest.spyOn(io, 'mkdirP') const mkdirMock = jest.spyOn(io, 'mkdirP')
const execMock = jest.spyOn(exec, 'exec') const execMock = jest.spyOn(exec, 'exec')
@@ -134,51 +74,50 @@ test('gzip extract tar', async () => {
await tar.extractTar(archivePath, CompressionMethod.Gzip) await tar.extractTar(archivePath, CompressionMethod.Gzip)
expect(mkdirMock).toHaveBeenCalledWith(workspace) expect(mkdirMock).toHaveBeenCalledWith(workspace)
const tarPath = IS_WINDOWS ? GnuTarPathOnWindows : defaultTarPath const tarPath = IS_WINDOWS
? `${process.env['windir']}\\System32\\tar.exe`
: defaultTarPath
expect(execMock).toHaveBeenCalledTimes(1) expect(execMock).toHaveBeenCalledTimes(1)
expect(execMock).toHaveBeenCalledWith( expect(execMock).toHaveBeenCalledWith(
`"${tarPath}"`,
[ [
`"${tarPath}"`, '-z',
'-xf', '-xf',
IS_WINDOWS ? archivePath.replace(/\\/g, '/') : archivePath, IS_WINDOWS ? archivePath.replace(/\\/g, '/') : archivePath,
'-P', '-P',
'-C', '-C',
IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace
] ].concat(IS_MAC ? ['--delay-directory-restore'] : []),
.concat(IS_WINDOWS ? ['--force-local'] : [])
.concat(IS_MAC ? ['--delay-directory-restore'] : [])
.concat(['-z'])
.join(' '),
undefined,
{cwd: undefined} {cwd: undefined}
) )
}) })
test('gzip extract GNU tar on windows with GNUtar in path', async () => { test('gzip extract GNU tar on windows', async () => {
if (IS_WINDOWS) { if (IS_WINDOWS) {
// GNU tar present in path but not at default location jest.spyOn(fs, 'existsSync').mockReturnValueOnce(false)
jest
.spyOn(utils, 'getGnuTarPathOnWindows') const isGnuMock = jest
.mockReturnValue(Promise.resolve('tar')) .spyOn(utils, 'isGnuTarInstalled')
.mockReturnValue(Promise.resolve(true))
const execMock = jest.spyOn(exec, 'exec') const execMock = jest.spyOn(exec, 'exec')
const archivePath = `${process.env['windir']}\\fakepath\\cache.tar` const archivePath = `${process.env['windir']}\\fakepath\\cache.tar`
const workspace = process.env['GITHUB_WORKSPACE'] const workspace = process.env['GITHUB_WORKSPACE']
await tar.extractTar(archivePath, CompressionMethod.Gzip) await tar.extractTar(archivePath, CompressionMethod.Gzip)
expect(isGnuMock).toHaveBeenCalledTimes(1)
expect(execMock).toHaveBeenCalledTimes(1) expect(execMock).toHaveBeenCalledTimes(1)
expect(execMock).toHaveBeenCalledWith( expect(execMock).toHaveBeenCalledWith(
`"tar"`,
[ [
`"tar"`, '-z',
'-xf', '-xf',
archivePath.replace(/\\/g, '/'), archivePath.replace(/\\/g, '/'),
'-P', '-P',
'-C', '-C',
workspace?.replace(/\\/g, '/'), workspace?.replace(/\\/g, '/'),
'--force-local', '--force-local'
'-z' ],
].join(' '),
undefined,
{cwd: undefined} {cwd: undefined}
) )
} }
@@ -195,13 +134,13 @@ test('zstd create tar', async () => {
await tar.createTar(archiveFolder, sourceDirectories, CompressionMethod.Zstd) await tar.createTar(archiveFolder, sourceDirectories, CompressionMethod.Zstd)
const tarPath = IS_WINDOWS ? GnuTarPathOnWindows : defaultTarPath
expect(execMock).toHaveBeenCalledTimes(1) expect(execMock).toHaveBeenCalledTimes(1)
expect(execMock).toHaveBeenCalledWith( expect(execMock).toHaveBeenCalledWith(
`"${defaultTarPath}"`,
[ [
`"${tarPath}"`,
'--posix', '--posix',
'--use-compress-program',
'zstd -T0 --long=30',
'-cf', '-cf',
IS_WINDOWS ? CacheFilename.Zstd.replace(/\\/g, '/') : CacheFilename.Zstd, IS_WINDOWS ? CacheFilename.Zstd.replace(/\\/g, '/') : CacheFilename.Zstd,
'--exclude', '--exclude',
@@ -210,81 +149,16 @@ test('zstd create tar', async () => {
'-C', '-C',
IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace, IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace,
'--files-from', '--files-from',
ManifestFilename 'manifest.txt'
] ]
.concat(IS_WINDOWS ? ['--force-local'] : []) .concat(IS_WINDOWS ? ['--force-local'] : [])
.concat(IS_MAC ? ['--delay-directory-restore'] : []) .concat(IS_MAC ? ['--delay-directory-restore'] : []),
.concat([
'--use-compress-program',
IS_WINDOWS ? '"zstd -T0 --long=30"' : 'zstdmt --long=30'
])
.join(' '),
undefined, // args
{ {
cwd: archiveFolder cwd: archiveFolder
} }
) )
}) })
test('zstd create tar with windows BSDtar', async () => {
if (IS_WINDOWS) {
const execMock = jest.spyOn(exec, 'exec')
jest
.spyOn(utils, 'getGnuTarPathOnWindows')
.mockReturnValue(Promise.resolve(''))
const archiveFolder = getTempDir()
const workspace = process.env['GITHUB_WORKSPACE']
const sourceDirectories = ['~/.npm/cache', `${workspace}/dist`]
await fs.promises.mkdir(archiveFolder, {recursive: true})
await tar.createTar(
archiveFolder,
sourceDirectories,
CompressionMethod.Zstd
)
const tarPath = SystemTarPathOnWindows
expect(execMock).toHaveBeenCalledTimes(2)
expect(execMock).toHaveBeenNthCalledWith(
1,
[
`"${tarPath}"`,
'--posix',
'-cf',
TarFilename.replace(/\\/g, '/'),
'--exclude',
TarFilename.replace(/\\/g, '/'),
'-P',
'-C',
workspace?.replace(/\\/g, '/'),
'--files-from',
ManifestFilename
].join(' '),
undefined, // args
{
cwd: archiveFolder
}
)
expect(execMock).toHaveBeenNthCalledWith(
2,
[
'zstd -T0 --long=30 -o',
CacheFilename.Zstd.replace(/\\/g, '/'),
TarFilename.replace(/\\/g, '/')
].join(' '),
undefined, // args
{
cwd: archiveFolder
}
)
}
})
test('gzip create tar', async () => { test('gzip create tar', async () => {
const execMock = jest.spyOn(exec, 'exec') const execMock = jest.spyOn(exec, 'exec')
@@ -296,13 +170,16 @@ test('gzip create tar', async () => {
await tar.createTar(archiveFolder, sourceDirectories, CompressionMethod.Gzip) await tar.createTar(archiveFolder, sourceDirectories, CompressionMethod.Gzip)
const tarPath = IS_WINDOWS ? GnuTarPathOnWindows : defaultTarPath const tarPath = IS_WINDOWS
? `${process.env['windir']}\\System32\\tar.exe`
: defaultTarPath
expect(execMock).toHaveBeenCalledTimes(1) expect(execMock).toHaveBeenCalledTimes(1)
expect(execMock).toHaveBeenCalledWith( expect(execMock).toHaveBeenCalledWith(
`"${tarPath}"`,
[ [
`"${tarPath}"`,
'--posix', '--posix',
'-z',
'-cf', '-cf',
IS_WINDOWS ? CacheFilename.Gzip.replace(/\\/g, '/') : CacheFilename.Gzip, IS_WINDOWS ? CacheFilename.Gzip.replace(/\\/g, '/') : CacheFilename.Gzip,
'--exclude', '--exclude',
@@ -311,13 +188,8 @@ test('gzip create tar', async () => {
'-C', '-C',
IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace, IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace,
'--files-from', '--files-from',
ManifestFilename 'manifest.txt'
] ].concat(IS_MAC ? ['--delay-directory-restore'] : []),
.concat(IS_WINDOWS ? ['--force-local'] : [])
.concat(IS_MAC ? ['--delay-directory-restore'] : [])
.concat(['-z'])
.join(' '),
undefined, // args
{ {
cwd: archiveFolder cwd: archiveFolder
} }
@@ -333,65 +205,22 @@ test('zstd list tar', async () => {
await tar.listTar(archivePath, CompressionMethod.Zstd) await tar.listTar(archivePath, CompressionMethod.Zstd)
const tarPath = IS_WINDOWS ? GnuTarPathOnWindows : defaultTarPath
expect(execMock).toHaveBeenCalledTimes(1) expect(execMock).toHaveBeenCalledTimes(1)
expect(execMock).toHaveBeenCalledWith( expect(execMock).toHaveBeenCalledWith(
`"${defaultTarPath}"`,
[ [
`"${tarPath}"`, '--use-compress-program',
'zstd -d --long=30',
'-tf', '-tf',
IS_WINDOWS ? archivePath.replace(/\\/g, '/') : archivePath, IS_WINDOWS ? archivePath.replace(/\\/g, '/') : archivePath,
'-P' '-P'
] ]
.concat(IS_WINDOWS ? ['--force-local'] : []) .concat(IS_WINDOWS ? ['--force-local'] : [])
.concat(IS_MAC ? ['--delay-directory-restore'] : []) .concat(IS_MAC ? ['--delay-directory-restore'] : []),
.concat([
'--use-compress-program',
IS_WINDOWS ? '"zstd -d --long=30"' : 'unzstd --long=30'
])
.join(' '),
undefined,
{cwd: undefined} {cwd: undefined}
) )
}) })
test('zstd list tar with windows BSDtar', async () => {
if (IS_WINDOWS) {
const execMock = jest.spyOn(exec, 'exec')
jest
.spyOn(utils, 'getGnuTarPathOnWindows')
.mockReturnValue(Promise.resolve(''))
const archivePath = `${process.env['windir']}\\fakepath\\cache.tar`
await tar.listTar(archivePath, CompressionMethod.Zstd)
const tarPath = SystemTarPathOnWindows
expect(execMock).toHaveBeenCalledTimes(2)
expect(execMock).toHaveBeenNthCalledWith(
1,
[
'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,
[
`"${tarPath}"`,
'-tf',
TarFilename.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'-P'
].join(' '),
undefined,
{cwd: undefined}
)
}
})
test('zstdWithoutLong list tar', async () => { test('zstdWithoutLong list tar', async () => {
const execMock = jest.spyOn(exec, 'exec') const execMock = jest.spyOn(exec, 'exec')
@@ -401,20 +230,18 @@ test('zstdWithoutLong list tar', async () => {
await tar.listTar(archivePath, CompressionMethod.ZstdWithoutLong) await tar.listTar(archivePath, CompressionMethod.ZstdWithoutLong)
const tarPath = IS_WINDOWS ? GnuTarPathOnWindows : defaultTarPath
expect(execMock).toHaveBeenCalledTimes(1) expect(execMock).toHaveBeenCalledTimes(1)
expect(execMock).toHaveBeenCalledWith( expect(execMock).toHaveBeenCalledWith(
`"${defaultTarPath}"`,
[ [
`"${tarPath}"`, '--use-compress-program',
'zstd -d',
'-tf', '-tf',
IS_WINDOWS ? archivePath.replace(/\\/g, '/') : archivePath, IS_WINDOWS ? archivePath.replace(/\\/g, '/') : archivePath,
'-P' '-P'
] ]
.concat(IS_WINDOWS ? ['--force-local'] : []) .concat(IS_WINDOWS ? ['--force-local'] : [])
.concat(IS_MAC ? ['--delay-directory-restore'] : []) .concat(IS_MAC ? ['--delay-directory-restore'] : []),
.concat(['--use-compress-program', IS_WINDOWS ? '"zstd -d"' : 'unzstd'])
.join(' '),
undefined,
{cwd: undefined} {cwd: undefined}
) )
}) })
@@ -427,20 +254,18 @@ test('gzip list tar', async () => {
await tar.listTar(archivePath, CompressionMethod.Gzip) await tar.listTar(archivePath, CompressionMethod.Gzip)
const tarPath = IS_WINDOWS ? GnuTarPathOnWindows : defaultTarPath const tarPath = IS_WINDOWS
? `${process.env['windir']}\\System32\\tar.exe`
: defaultTarPath
expect(execMock).toHaveBeenCalledTimes(1) expect(execMock).toHaveBeenCalledTimes(1)
expect(execMock).toHaveBeenCalledWith( expect(execMock).toHaveBeenCalledWith(
`"${tarPath}"`,
[ [
`"${tarPath}"`, '-z',
'-tf', '-tf',
IS_WINDOWS ? archivePath.replace(/\\/g, '/') : archivePath, IS_WINDOWS ? archivePath.replace(/\\/g, '/') : archivePath,
'-P' '-P'
] ].concat(IS_MAC ? ['--delay-directory-restore'] : []),
.concat(IS_WINDOWS ? ['--force-local'] : [])
.concat(IS_MAC ? ['--delay-directory-restore'] : [])
.concat(['-z'])
.join(' '),
undefined,
{cwd: undefined} {cwd: undefined}
) )
}) })
+24 -48
View File
@@ -1,20 +1,19 @@
{ {
"name": "@actions/cache", "name": "@actions/cache",
"version": "3.1.0-beta.1", "version": "3.0.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@actions/cache", "name": "@actions/cache",
"version": "3.1.0-beta.1", "version": "3.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.10.0", "@actions/core": "^1.2.6",
"@actions/exec": "^1.0.1", "@actions/exec": "^1.0.1",
"@actions/glob": "^0.1.0", "@actions/glob": "^0.1.0",
"@actions/http-client": "^2.0.1", "@actions/http-client": "^2.0.1",
"@actions/io": "^1.0.1", "@actions/io": "^1.0.1",
"@azure/abort-controller": "^1.1.0",
"@azure/ms-rest-js": "^2.6.0", "@azure/ms-rest-js": "^2.6.0",
"@azure/storage-blob": "^12.8.0", "@azure/storage-blob": "^12.8.0",
"semver": "^6.1.0", "semver": "^6.1.0",
@@ -27,21 +26,9 @@
} }
}, },
"node_modules/@actions/core": { "node_modules/@actions/core": {
"version": "1.10.0", "version": "1.2.6",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz",
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", "integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
"dependencies": {
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
}
},
"node_modules/@actions/core/node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
}, },
"node_modules/@actions/exec": { "node_modules/@actions/exec": {
"version": "1.1.1", "version": "1.1.1",
@@ -74,14 +61,14 @@
"integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw==" "integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw=="
}, },
"node_modules/@azure/abort-controller": { "node_modules/@azure/abort-controller": {
"version": "1.1.0", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.0.4.tgz",
"integrity": "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==", "integrity": "sha512-lNUmDRVGpanCsiUN3NWxFTdwmdFI53xwhkTFfHDGTYk46ca7Ind3nanJc+U6Zj9Tv+9nTCWRBscWEW1DyKOpTw==",
"dependencies": { "dependencies": {
"tslib": "^2.2.0" "tslib": "^2.0.0"
}, },
"engines": { "engines": {
"node": ">=12.0.0" "node": ">=8.0.0"
} }
}, },
"node_modules/@azure/abort-controller/node_modules/tslib": { "node_modules/@azure/abort-controller/node_modules/tslib": {
@@ -457,9 +444,9 @@
} }
}, },
"node_modules/minimatch": { "node_modules/minimatch": {
"version": "3.1.2", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dependencies": { "dependencies": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
}, },
@@ -618,20 +605,9 @@
}, },
"dependencies": { "dependencies": {
"@actions/core": { "@actions/core": {
"version": "1.10.0", "version": "1.2.6",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz",
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", "integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
"requires": {
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
},
"dependencies": {
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
}
}
}, },
"@actions/exec": { "@actions/exec": {
"version": "1.1.1", "version": "1.1.1",
@@ -664,11 +640,11 @@
"integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw==" "integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw=="
}, },
"@azure/abort-controller": { "@azure/abort-controller": {
"version": "1.1.0", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.0.4.tgz",
"integrity": "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==", "integrity": "sha512-lNUmDRVGpanCsiUN3NWxFTdwmdFI53xwhkTFfHDGTYk46ca7Ind3nanJc+U6Zj9Tv+9nTCWRBscWEW1DyKOpTw==",
"requires": { "requires": {
"tslib": "^2.2.0" "tslib": "^2.0.0"
}, },
"dependencies": { "dependencies": {
"tslib": { "tslib": {
@@ -998,9 +974,9 @@
} }
}, },
"minimatch": { "minimatch": {
"version": "3.1.2", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
+2 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "@actions/cache", "name": "@actions/cache",
"version": "3.1.0-beta.1", "version": "3.0.0",
"preview": true, "preview": true,
"description": "Actions cache lib", "description": "Actions cache lib",
"keywords": [ "keywords": [
@@ -37,12 +37,11 @@
"url": "https://github.com/actions/toolkit/issues" "url": "https://github.com/actions/toolkit/issues"
}, },
"dependencies": { "dependencies": {
"@actions/core": "^1.10.0", "@actions/core": "^1.2.6",
"@actions/exec": "^1.0.1", "@actions/exec": "^1.0.1",
"@actions/glob": "^0.1.0", "@actions/glob": "^0.1.0",
"@actions/http-client": "^2.0.1", "@actions/http-client": "^2.0.1",
"@actions/io": "^1.0.1", "@actions/io": "^1.0.1",
"@azure/abort-controller": "^1.1.0",
"@azure/ms-rest-js": "^2.6.0", "@azure/ms-rest-js": "^2.6.0",
"@azure/storage-blob": "^12.8.0", "@azure/storage-blob": "^12.8.0",
"semver": "^6.1.0", "semver": "^6.1.0",
+5 -25
View File
@@ -4,8 +4,6 @@ import * as utils from './internal/cacheUtils'
import * as cacheHttpClient from './internal/cacheHttpClient' import * as cacheHttpClient from './internal/cacheHttpClient'
import {createTar, extractTar, listTar} from './internal/tar' import {createTar, extractTar, listTar} from './internal/tar'
import {DownloadOptions, UploadOptions} from './options' import {DownloadOptions, UploadOptions} from './options'
import {CompressionMethod} from './internal/constants'
import {ArtifactCacheEntry} from './internal/contracts'
export class ValidationError extends Error { export class ValidationError extends Error {
constructor(message: string) { constructor(message: string) {
@@ -87,35 +85,17 @@ export async function restoreCache(
checkKey(key) checkKey(key)
} }
let cacheEntry: ArtifactCacheEntry | null const compressionMethod = await utils.getCompressionMethod()
let compressionMethod = await utils.getCompressionMethod()
let archivePath = '' let archivePath = ''
try { try {
// path are needed to compute version // path are needed to compute version
cacheEntry = await cacheHttpClient.getCacheEntry(keys, paths, { const cacheEntry = await cacheHttpClient.getCacheEntry(keys, paths, {
compressionMethod compressionMethod
}) })
if (!cacheEntry?.archiveLocation) {
// This is to support the old cache entry created by gzip on windows.
if (
process.platform === 'win32' &&
compressionMethod !== CompressionMethod.Gzip
) {
compressionMethod = CompressionMethod.Gzip
cacheEntry = await cacheHttpClient.getCacheEntry(keys, paths, {
compressionMethod
})
if (!cacheEntry?.archiveLocation) {
return undefined
}
core.debug( if (!cacheEntry?.archiveLocation) {
"Couldn't find cache entry with zstd compression, falling back to gzip compression." // Cache not found
) return undefined
} else {
// Cache not found
return undefined
}
} }
archivePath = path.join( archivePath = path.join(
-2
View File
@@ -104,7 +104,6 @@ export async function getCacheEntry(
httpClient.getJson<ArtifactCacheEntry>(getCacheApiUrl(resource)) httpClient.getJson<ArtifactCacheEntry>(getCacheApiUrl(resource))
) )
if (response.statusCode === 204) { if (response.statusCode === 204) {
// Cache not found
return null return null
} }
if (!isSuccessStatusCode(response.statusCode)) { if (!isSuccessStatusCode(response.statusCode)) {
@@ -114,7 +113,6 @@ export async function getCacheEntry(
const cacheResult = response.result const cacheResult = response.result
const cacheDownloadUrl = cacheResult?.archiveLocation const cacheDownloadUrl = cacheResult?.archiveLocation
if (!cacheDownloadUrl) { if (!cacheDownloadUrl) {
// Cache achiveLocation not found. This should never happen, and hence bail out.
throw new Error('Cache not found.') throw new Error('Cache not found.')
} }
core.setSecret(cacheDownloadUrl) core.setSecret(cacheDownloadUrl)
+9 -16
View File
@@ -7,11 +7,7 @@ import * as path from 'path'
import * as semver from 'semver' import * as semver from 'semver'
import * as util from 'util' import * as util from 'util'
import {v4 as uuidV4} from 'uuid' import {v4 as uuidV4} from 'uuid'
import { import {CacheFilename, CompressionMethod} from './constants'
CacheFilename,
CompressionMethod,
GnuTarPathOnWindows
} from './constants'
// From https://github.com/actions/toolkit/blob/main/packages/tool-cache/src/tool-cache.ts#L23 // From https://github.com/actions/toolkit/blob/main/packages/tool-cache/src/tool-cache.ts#L23
export async function createTempDirectory(): Promise<string> { export async function createTempDirectory(): Promise<string> {
@@ -56,12 +52,7 @@ export async function resolvePaths(patterns: string[]): Promise<string[]> {
.replace(new RegExp(`\\${path.sep}`, 'g'), '/') .replace(new RegExp(`\\${path.sep}`, 'g'), '/')
core.debug(`Matched: ${relativeFile}`) core.debug(`Matched: ${relativeFile}`)
// Paths are made relative so the tar entries are all relative to the root of the workspace. // Paths are made relative so the tar entries are all relative to the root of the workspace.
if (relativeFile === '') { paths.push(`${relativeFile}`)
// path.relative returns empty string if workspace and file are equal
paths.push('.')
} else {
paths.push(`${relativeFile}`)
}
} }
return paths return paths
@@ -94,6 +85,11 @@ async function getVersion(app: string): Promise<string> {
// Use zstandard if possible to maximize cache performance // Use zstandard if possible to maximize cache performance
export async function getCompressionMethod(): Promise<CompressionMethod> { export async function getCompressionMethod(): Promise<CompressionMethod> {
if (process.platform === 'win32' && !(await isGnuTarInstalled())) {
// Disable zstd due to bug https://github.com/actions/cache/issues/301
return CompressionMethod.Gzip
}
const versionOutput = await getVersion('zstd') const versionOutput = await getVersion('zstd')
const version = semver.clean(versionOutput) const version = semver.clean(versionOutput)
@@ -115,12 +111,9 @@ export function getCacheFileName(compressionMethod: CompressionMethod): string {
: CacheFilename.Zstd : CacheFilename.Zstd
} }
export async function getGnuTarPathOnWindows(): Promise<string> { export async function isGnuTarInstalled(): Promise<boolean> {
if (fs.existsSync(GnuTarPathOnWindows)) {
return GnuTarPathOnWindows
}
const versionOutput = await getVersion('tar') const versionOutput = await getVersion('tar')
return versionOutput.toLowerCase().includes('gnu tar') ? io.which('tar') : '' return versionOutput.toLowerCase().includes('gnu tar')
} }
export function assertDefined<T>(name: string, value?: T): T { export function assertDefined<T>(name: string, value?: T): T {
-15
View File
@@ -11,11 +11,6 @@ export enum CompressionMethod {
Zstd = 'zstd' Zstd = 'zstd'
} }
export enum ArchiveToolType {
GNU = 'gnu',
BSD = 'bsd'
}
// The default number of retry attempts. // The default number of retry attempts.
export const DefaultRetryAttempts = 2 export const DefaultRetryAttempts = 2
@@ -26,13 +21,3 @@ export const DefaultRetryDelay = 5000
// over the socket during this period, the socket is destroyed and the download // over the socket during this period, the socket is destroyed and the download
// is aborted. // is aborted.
export const SocketTimeout = 5000 export const SocketTimeout = 5000
// The default path of GNUtar on hosted Windows runners
export const GnuTarPathOnWindows = `${process.env['PROGRAMFILES']}\\Git\\usr\\bin\\tar.exe`
// The default path of BSDtar on hosted Windows runners
export const SystemTarPathOnWindows = `${process.env['SYSTEMDRIVE']}\\Windows\\System32\\tar.exe`
export const TarFilename = 'cache.tar'
export const ManifestFilename = 'manifest.txt'
-5
View File
@@ -31,8 +31,3 @@ export interface InternalCacheOptions {
compressionMethod?: CompressionMethod compressionMethod?: CompressionMethod
cacheSize?: number cacheSize?: number
} }
export interface ArchiveTool {
path: string
type: string
}
+9 -32
View File
@@ -12,8 +12,6 @@ import {SocketTimeout} from './constants'
import {DownloadOptions} from '../options' import {DownloadOptions} from '../options'
import {retryHttpClientResponse} from './requestUtils' import {retryHttpClientResponse} from './requestUtils'
import {AbortController} from '@azure/abort-controller'
/** /**
* Pipes the body of a HTTP response to a stream * Pipes the body of a HTTP response to a stream
* *
@@ -249,8 +247,7 @@ export async function downloadCacheStorageSDK(
try { try {
downloadProgress.startDisplayTimer() downloadProgress.startDisplayTimer()
const controller = new AbortController()
const abortSignal = controller.signal
while (!downloadProgress.isDone()) { while (!downloadProgress.isDone()) {
const segmentStart = const segmentStart =
downloadProgress.segmentOffset + downloadProgress.segmentSize downloadProgress.segmentOffset + downloadProgress.segmentSize
@@ -261,22 +258,17 @@ export async function downloadCacheStorageSDK(
) )
downloadProgress.nextSegment(segmentSize) downloadProgress.nextSegment(segmentSize)
const result = await promiseWithTimeout(
options.segmentTimeoutInMs || 3600000, const result = await client.downloadToBuffer(
client.downloadToBuffer(segmentStart, segmentSize, { segmentStart,
abortSignal, segmentSize,
{
concurrency: options.downloadConcurrency, concurrency: options.downloadConcurrency,
onProgress: downloadProgress.onProgress() onProgress: downloadProgress.onProgress()
}) }
) )
if (result === 'timeout') {
controller.abort() fs.writeFileSync(fd, result)
throw new Error(
'Aborting cache download as the download time exceeded the timeout.'
)
} else if (Buffer.isBuffer(result)) {
fs.writeFileSync(fd, result)
}
} }
} finally { } finally {
downloadProgress.stopDisplayTimer() downloadProgress.stopDisplayTimer()
@@ -284,18 +276,3 @@ export async function downloadCacheStorageSDK(
} }
} }
} }
const promiseWithTimeout = async (
timeoutMs: number,
promise: Promise<Buffer>
): Promise<unknown> => {
let timeoutHandle: NodeJS.Timeout
const timeoutPromise = new Promise(resolve => {
timeoutHandle = setTimeout(() => resolve('timeout'), timeoutMs)
})
return Promise.race([promise, timeoutPromise]).then(result => {
clearTimeout(timeoutHandle)
return result
})
}
+106 -244
View File
@@ -3,28 +3,23 @@ import * as io from '@actions/io'
import {existsSync, writeFileSync} from 'fs' import {existsSync, writeFileSync} from 'fs'
import * as path from 'path' import * as path from 'path'
import * as utils from './cacheUtils' import * as utils from './cacheUtils'
import {ArchiveTool} from './contracts' import {CompressionMethod} from './constants'
import {
CompressionMethod,
SystemTarPathOnWindows,
ArchiveToolType,
TarFilename,
ManifestFilename
} from './constants'
const IS_WINDOWS = process.platform === 'win32' async function getTarPath(
args: string[],
// Returns tar path and type: BSD or GNU compressionMethod: CompressionMethod
async function getTarPath(): Promise<ArchiveTool> { ): Promise<string> {
switch (process.platform) { switch (process.platform) {
case 'win32': { case 'win32': {
const gnuTar = await utils.getGnuTarPathOnWindows() const systemTar = `${process.env['windir']}\\System32\\tar.exe`
const systemTar = SystemTarPathOnWindows if (compressionMethod !== CompressionMethod.Gzip) {
if (gnuTar) { // We only use zstandard compression on windows when gnu tar is installed due to
// Use GNUtar as default on windows // a bug with compressing large files with bsdtar + zstd
return <ArchiveTool>{path: gnuTar, type: ArchiveToolType.GNU} args.push('--force-local')
} else if (existsSync(systemTar)) { } else if (existsSync(systemTar)) {
return <ArchiveTool>{path: systemTar, type: ArchiveToolType.BSD} return systemTar
} else if (await utils.isGnuTarInstalled()) {
args.push('--force-local')
} }
break break
} }
@@ -32,241 +27,33 @@ async function getTarPath(): Promise<ArchiveTool> {
const gnuTar = await io.which('gtar', false) const gnuTar = await io.which('gtar', false)
if (gnuTar) { if (gnuTar) {
// fix permission denied errors when extracting BSD tar archive with GNU tar - https://github.com/actions/cache/issues/527 // fix permission denied errors when extracting BSD tar archive with GNU tar - https://github.com/actions/cache/issues/527
return <ArchiveTool>{path: gnuTar, type: ArchiveToolType.GNU} args.push('--delay-directory-restore')
} else { return gnuTar
return <ArchiveTool>{
path: await io.which('tar', true),
type: ArchiveToolType.BSD
}
} }
break
} }
default: default:
break break
} }
// Default assumption is GNU tar is present in path return await io.which('tar', true)
return <ArchiveTool>{
path: await io.which('tar', true),
type: ArchiveToolType.GNU
}
} }
// Return arguments for tar as per tarPath, compressionMethod, method type and os async function execTar(
async function getTarArgs( args: string[],
tarPath: ArchiveTool,
compressionMethod: CompressionMethod, compressionMethod: CompressionMethod,
type: string, cwd?: string
archivePath = '' ): Promise<void> {
): Promise<string[]> { try {
const args = [`"${tarPath.path}"`] await exec(`"${await getTarPath(args, compressionMethod)}"`, args, {cwd})
const cacheFileName = utils.getCacheFileName(compressionMethod) } catch (error) {
const tarFile = 'cache.tar' throw new Error(`Tar failed with error: ${error?.message}`)
const workingDirectory = getWorkingDirectory()
// Speficic args for BSD tar on windows for workaround
const BSD_TAR_ZSTD =
tarPath.type === ArchiveToolType.BSD &&
compressionMethod !== 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',
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
} }
// Platform specific args
if (tarPath.type === 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
async function getCommands(
compressionMethod: CompressionMethod,
type: string,
archivePath = ''
): Promise<string[]> {
let args
const tarPath = await getTarPath()
const tarArgs = await getTarArgs(
tarPath,
compressionMethod,
type,
archivePath
)
const compressionArgs =
type !== 'create'
? await getDecompressionProgram(tarPath, compressionMethod, archivePath)
: await getCompressionProgram(tarPath, compressionMethod)
const BSD_TAR_ZSTD =
tarPath.type === ArchiveToolType.BSD &&
compressionMethod !== 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(): string { function getWorkingDirectory(): string {
return process.env['GITHUB_WORKSPACE'] ?? process.cwd() return process.env['GITHUB_WORKSPACE'] ?? process.cwd()
} }
// Common function for extractTar and listTar to get the compression method
async function getDecompressionProgram(
tarPath: ArchiveTool,
compressionMethod: CompressionMethod,
archivePath: string
): Promise<string[]> {
// -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 === ArchiveToolType.BSD &&
compressionMethod !== CompressionMethod.Gzip &&
IS_WINDOWS
switch (compressionMethod) {
case CompressionMethod.Zstd:
return BSD_TAR_ZSTD
? [
'zstd -d --long=30 -o',
TarFilename,
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
]
: [
'--use-compress-program',
IS_WINDOWS ? '"zstd -d --long=30"' : 'unzstd --long=30'
]
case CompressionMethod.ZstdWithoutLong:
return BSD_TAR_ZSTD
? [
'zstd -d -o',
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.
async function getCompressionProgram(
tarPath: ArchiveTool,
compressionMethod: CompressionMethod
): Promise<string[]> {
const cacheFileName = utils.getCacheFileName(compressionMethod)
const BSD_TAR_ZSTD =
tarPath.type === ArchiveToolType.BSD &&
compressionMethod !== CompressionMethod.Gzip &&
IS_WINDOWS
switch (compressionMethod) {
case CompressionMethod.Zstd:
return BSD_TAR_ZSTD
? [
'zstd -T0 --long=30 -o',
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
TarFilename
]
: [
'--use-compress-program',
IS_WINDOWS ? '"zstd -T0 --long=30"' : 'zstdmt --long=30'
]
case CompressionMethod.ZstdWithoutLong:
return BSD_TAR_ZSTD
? [
'zstd -T0 -o',
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
TarFilename
]
: ['--use-compress-program', IS_WINDOWS ? '"zstd -T0"' : 'zstdmt']
default:
return ['-z']
}
}
// 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)
}
// Extract a tar
export async function extractTar( export async function extractTar(
archivePath: string, archivePath: string,
compressionMethod: CompressionMethod compressionMethod: CompressionMethod
@@ -274,21 +61,96 @@ 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)
const commands = await getCommands(compressionMethod, 'extract', archivePath) // --decompress: Decompress.
await execCommands(commands) // --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.
function getCompressionProgram(): string[] {
switch (compressionMethod) {
case CompressionMethod.Zstd:
return ['--use-compress-program', 'zstd --decompress --long=30']
case CompressionMethod.ZstdWithoutLong:
return ['--use-compress-program', 'zstd --decompress']
default:
return ['-z']
}
}
const args = [
...getCompressionProgram(),
'-xf',
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'-P',
'-C',
workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
]
await execTar(args, compressionMethod)
} }
// Create a tar
export async function createTar( export async function createTar(
archiveFolder: string, archiveFolder: string,
sourceDirectories: string[], sourceDirectories: string[],
compressionMethod: CompressionMethod compressionMethod: CompressionMethod
): Promise<void> { ): Promise<void> {
// Write source directories to manifest.txt to avoid command length limits // Write source directories to manifest.txt to avoid command length limits
const manifestFilename = 'manifest.txt'
const cacheFileName = utils.getCacheFileName(compressionMethod)
writeFileSync( writeFileSync(
path.join(archiveFolder, ManifestFilename), path.join(archiveFolder, manifestFilename),
sourceDirectories.join('\n') sourceDirectories.join('\n')
) )
const commands = await getCommands(compressionMethod, 'create') const workingDirectory = getWorkingDirectory()
await execCommands(commands, archiveFolder)
// --threads=#: 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.
// 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(): string[] {
switch (compressionMethod) {
case CompressionMethod.Zstd:
return ['--use-compress-program', 'zstd --threads=0 --long=30']
case CompressionMethod.ZstdWithoutLong:
return ['--use-compress-program', 'zstd --threads=0']
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
]
await execTar(args, compressionMethod, archiveFolder)
}
export async function listTar(
archivePath: string,
compressionMethod: CompressionMethod
): Promise<void> {
// --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.
function getCompressionProgram(): string[] {
switch (compressionMethod) {
case CompressionMethod.Zstd:
return ['--use-compress-program', 'zstd --long=30']
case CompressionMethod.ZstdWithoutLong:
return ['--use-compress-program', 'zstd']
default:
return ['-z']
}
}
const args = [
...getCompressionProgram(),
'-tf',
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'-P'
]
await execTar(args, compressionMethod)
} }
+1 -26
View File
@@ -46,13 +46,6 @@ export interface DownloadOptions {
* @default 30000 * @default 30000
*/ */
timeoutInMs?: number timeoutInMs?: number
/**
* Time after which a segment download should be aborted if stuck
*
* @default 3600000
*/
segmentTimeoutInMs?: number
} }
/** /**
@@ -91,8 +84,7 @@ export function getDownloadOptions(copy?: DownloadOptions): DownloadOptions {
const result: DownloadOptions = { const result: DownloadOptions = {
useAzureSdk: true, useAzureSdk: true,
downloadConcurrency: 8, downloadConcurrency: 8,
timeoutInMs: 30000, timeoutInMs: 30000
segmentTimeoutInMs: 3600000
} }
if (copy) { if (copy) {
@@ -107,28 +99,11 @@ export function getDownloadOptions(copy?: DownloadOptions): DownloadOptions {
if (typeof copy.timeoutInMs === 'number') { if (typeof copy.timeoutInMs === 'number') {
result.timeoutInMs = copy.timeoutInMs result.timeoutInMs = copy.timeoutInMs
} }
if (typeof copy.segmentTimeoutInMs === 'number') {
result.segmentTimeoutInMs = copy.segmentTimeoutInMs
}
} }
const segmentDownloadTimeoutMins =
process.env['SEGMENT_DOWNLOAD_TIMEOUT_MINS']
if (
segmentDownloadTimeoutMins &&
!isNaN(Number(segmentDownloadTimeoutMins)) &&
isFinite(Number(segmentDownloadTimeoutMins))
) {
result.segmentTimeoutInMs = Number(segmentDownloadTimeoutMins) * 60 * 1000
}
core.debug(`Use Azure SDK: ${result.useAzureSdk}`) core.debug(`Use Azure SDK: ${result.useAzureSdk}`)
core.debug(`Download concurrency: ${result.downloadConcurrency}`) core.debug(`Download concurrency: ${result.downloadConcurrency}`)
core.debug(`Request timeout (ms): ${result.timeoutInMs}`) core.debug(`Request timeout (ms): ${result.timeoutInMs}`)
core.debug(
`Cache segment download timeout mins env var: ${process.env['SEGMENT_DOWNLOAD_TIMEOUT_MINS']}`
)
core.debug(`Segment download timeout (ms): ${result.segmentTimeoutInMs}`)
return result return result
} }
+1 -1
View File
@@ -163,7 +163,7 @@ export interface AnnotationProperties {
startColumn?: number startColumn?: number
/** /**
* The end column for the annotation. Cannot be sent when `startLine` and `endLine` are different values. * The start column for the annotation. Cannot be sent when `startLine` and `endLine` are different values.
* Defaults to `startColumn` when `startColumn` is provided. * Defaults to `startColumn` when `startColumn` is provided.
*/ */
endColumn?: number endColumn?: number
-7
View File
@@ -1,12 +1,5 @@
# @actions/core Releases # @actions/core Releases
### 1.10.0
- `saveState` and `setOutput` now use environment files if available [#1178](https://github.com/actions/toolkit/pull/1178)
- `getMultilineInput` now correctly trims whitespace by default [#1185](https://github.com/actions/toolkit/pull/1185)
### 1.9.1
- Randomize delimiter when calling `core.exportVariable`
### 1.9.0 ### 1.9.0
- Added `toPosixPath`, `toWin32Path` and `toPlatformPath` utilities [#1102](https://github.com/actions/toolkit/pull/1102) - Added `toPosixPath`, `toWin32Path` and `toPlatformPath` utilities [#1102](https://github.com/actions/toolkit/pull/1102)
+19 -202
View File
@@ -4,9 +4,6 @@ import * as path from 'path'
import * as core from '../src/core' import * as core from '../src/core'
import {HttpClient} from '@actions/http-client' import {HttpClient} from '@actions/http-client'
import {toCommandProperties} from '../src/utils' import {toCommandProperties} from '../src/utils'
import * as uuid from 'uuid'
jest.mock('uuid')
/* eslint-disable @typescript-eslint/unbound-method */ /* eslint-disable @typescript-eslint/unbound-method */
@@ -33,22 +30,17 @@ const testEnvVars = {
INPUT_BOOLEAN_INPUT_FALSE3: 'FALSE', INPUT_BOOLEAN_INPUT_FALSE3: 'FALSE',
INPUT_WRONG_BOOLEAN_INPUT: 'wrong', INPUT_WRONG_BOOLEAN_INPUT: 'wrong',
INPUT_WITH_TRAILING_WHITESPACE: ' some val ', INPUT_WITH_TRAILING_WHITESPACE: ' some val ',
INPUT_MY_INPUT_LIST: 'val1\nval2\nval3', INPUT_MY_INPUT_LIST: 'val1\nval2\nval3',
INPUT_LIST_WITH_TRAILING_WHITESPACE: ' val1 \n val2 \n ',
// Save inputs // Save inputs
STATE_TEST_1: 'state_val', STATE_TEST_1: 'state_val',
// File Commands // File Commands
GITHUB_PATH: '', GITHUB_PATH: '',
GITHUB_ENV: '', GITHUB_ENV: ''
GITHUB_OUTPUT: '',
GITHUB_STATE: ''
} }
const UUID = '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'
const DELIMITER = `ghadelimiter_${UUID}`
describe('@actions/core', () => { describe('@actions/core', () => {
beforeAll(() => { beforeAll(() => {
const filePath = path.join(__dirname, `test`) const filePath = path.join(__dirname, `test`)
@@ -62,14 +54,6 @@ describe('@actions/core', () => {
process.env[key] = testEnvVars[key as keyof typeof testEnvVars] process.env[key] = testEnvVars[key as keyof typeof testEnvVars]
} }
process.stdout.write = jest.fn() process.stdout.write = jest.fn()
jest.spyOn(uuid, 'v4').mockImplementation(() => {
return UUID
})
})
afterEach(() => {
jest.restoreAllMocks()
}) })
it('legacy exportVariable produces the correct command and sets the env', () => { it('legacy exportVariable produces the correct command and sets the env', () => {
@@ -107,7 +91,7 @@ describe('@actions/core', () => {
core.exportVariable('my var', 'var val') core.exportVariable('my var', 'var val')
verifyFileCommand( verifyFileCommand(
command, command,
`my var<<${DELIMITER}${os.EOL}var val${os.EOL}${DELIMITER}${os.EOL}` `my var<<_GitHubActionsFileCommandDelimeter_${os.EOL}var val${os.EOL}_GitHubActionsFileCommandDelimeter_${os.EOL}`
) )
}) })
@@ -117,7 +101,7 @@ describe('@actions/core', () => {
core.exportVariable('my var', true) core.exportVariable('my var', true)
verifyFileCommand( verifyFileCommand(
command, command,
`my var<<${DELIMITER}${os.EOL}true${os.EOL}${DELIMITER}${os.EOL}` `my var<<_GitHubActionsFileCommandDelimeter_${os.EOL}true${os.EOL}_GitHubActionsFileCommandDelimeter_${os.EOL}`
) )
}) })
@@ -127,38 +111,10 @@ describe('@actions/core', () => {
core.exportVariable('my var', 5) core.exportVariable('my var', 5)
verifyFileCommand( verifyFileCommand(
command, command,
`my var<<${DELIMITER}${os.EOL}5${os.EOL}${DELIMITER}${os.EOL}` `my var<<_GitHubActionsFileCommandDelimeter_${os.EOL}5${os.EOL}_GitHubActionsFileCommandDelimeter_${os.EOL}`
) )
}) })
it('exportVariable does not allow delimiter as value', () => {
const command = 'ENV'
createFileCommandFile(command)
expect(() => {
core.exportVariable('my var', `good stuff ${DELIMITER} bad stuff`)
}).toThrow(
`Unexpected input: value should not contain the delimiter "${DELIMITER}"`
)
const filePath = path.join(__dirname, `test/${command}`)
fs.unlinkSync(filePath)
})
it('exportVariable does not allow delimiter as name', () => {
const command = 'ENV'
createFileCommandFile(command)
expect(() => {
core.exportVariable(`good stuff ${DELIMITER} bad stuff`, 'test')
}).toThrow(
`Unexpected input: name should not contain the delimiter "${DELIMITER}"`
)
const filePath = path.join(__dirname, `test/${command}`)
fs.unlinkSync(filePath)
})
it('setSecret produces the correct command', () => { it('setSecret produces the correct command', () => {
core.setSecret('secret val') core.setSecret('secret val')
assertWriteCalls([`::add-mask::secret val${os.EOL}`]) assertWriteCalls([`::add-mask::secret val${os.EOL}`])
@@ -214,6 +170,14 @@ describe('@actions/core', () => {
) )
}) })
it('getMultilineInput works', () => {
expect(core.getMultilineInput('my input list')).toEqual([
'val1',
'val2',
'val3'
])
})
it('getInput trims whitespace by default', () => { it('getInput trims whitespace by default', () => {
expect(core.getInput('with trailing whitespace')).toBe('some val') expect(core.getInput('with trailing whitespace')).toBe('some val')
}) })
@@ -254,38 +218,7 @@ describe('@actions/core', () => {
) )
}) })
it('getMultilineInput works', () => { it('setOutput produces the correct command', () => {
expect(core.getMultilineInput('my input list')).toEqual([
'val1',
'val2',
'val3'
])
})
it('getMultilineInput trims whitespace by default', () => {
expect(core.getMultilineInput('list with trailing whitespace')).toEqual([
'val1',
'val2'
])
})
it('getMultilineInput trims whitespace when option is explicitly true', () => {
expect(
core.getMultilineInput('list with trailing whitespace', {
trimWhitespace: true
})
).toEqual(['val1', 'val2'])
})
it('getMultilineInput does not trim whitespace when option is false', () => {
expect(
core.getMultilineInput('list with trailing whitespace', {
trimWhitespace: false
})
).toEqual([' val1 ', ' val2 ', ' '])
})
it('legacy setOutput produces the correct command', () => {
core.setOutput('some output', 'some value') core.setOutput('some output', 'some value')
assertWriteCalls([ assertWriteCalls([
os.EOL, os.EOL,
@@ -293,74 +226,16 @@ describe('@actions/core', () => {
]) ])
}) })
it('legacy setOutput handles bools', () => { it('setOutput handles bools', () => {
core.setOutput('some output', false) core.setOutput('some output', false)
assertWriteCalls([os.EOL, `::set-output name=some output::false${os.EOL}`]) assertWriteCalls([os.EOL, `::set-output name=some output::false${os.EOL}`])
}) })
it('legacy setOutput handles numbers', () => { it('setOutput handles numbers', () => {
core.setOutput('some output', 1.01) core.setOutput('some output', 1.01)
assertWriteCalls([os.EOL, `::set-output name=some output::1.01${os.EOL}`]) assertWriteCalls([os.EOL, `::set-output name=some output::1.01${os.EOL}`])
}) })
it('setOutput produces the correct command and sets the output', () => {
const command = 'OUTPUT'
createFileCommandFile(command)
core.setOutput('my out', 'out val')
verifyFileCommand(
command,
`my out<<${DELIMITER}${os.EOL}out val${os.EOL}${DELIMITER}${os.EOL}`
)
})
it('setOutput handles boolean inputs', () => {
const command = 'OUTPUT'
createFileCommandFile(command)
core.setOutput('my out', true)
verifyFileCommand(
command,
`my out<<${DELIMITER}${os.EOL}true${os.EOL}${DELIMITER}${os.EOL}`
)
})
it('setOutput handles number inputs', () => {
const command = 'OUTPUT'
createFileCommandFile(command)
core.setOutput('my out', 5)
verifyFileCommand(
command,
`my out<<${DELIMITER}${os.EOL}5${os.EOL}${DELIMITER}${os.EOL}`
)
})
it('setOutput does not allow delimiter as value', () => {
const command = 'OUTPUT'
createFileCommandFile(command)
expect(() => {
core.setOutput('my out', `good stuff ${DELIMITER} bad stuff`)
}).toThrow(
`Unexpected input: value should not contain the delimiter "${DELIMITER}"`
)
const filePath = path.join(__dirname, `test/${command}`)
fs.unlinkSync(filePath)
})
it('setOutput does not allow delimiter as name', () => {
const command = 'OUTPUT'
createFileCommandFile(command)
expect(() => {
core.setOutput(`good stuff ${DELIMITER} bad stuff`, 'test')
}).toThrow(
`Unexpected input: name should not contain the delimiter "${DELIMITER}"`
)
const filePath = path.join(__dirname, `test/${command}`)
fs.unlinkSync(filePath)
})
it('setFailed sets the correct exit code and failure message', () => { it('setFailed sets the correct exit code and failure message', () => {
core.setFailed('Failure message') core.setFailed('Failure message')
expect(process.exitCode).toBe(core.ExitCode.Failure) expect(process.exitCode).toBe(core.ExitCode.Failure)
@@ -526,79 +401,21 @@ describe('@actions/core', () => {
assertWriteCalls([`::debug::%0D%0Adebug%0A${os.EOL}`]) assertWriteCalls([`::debug::%0D%0Adebug%0A${os.EOL}`])
}) })
it('legacy saveState produces the correct command', () => { it('saveState produces the correct command', () => {
core.saveState('state_1', 'some value') core.saveState('state_1', 'some value')
assertWriteCalls([`::save-state name=state_1::some value${os.EOL}`]) assertWriteCalls([`::save-state name=state_1::some value${os.EOL}`])
}) })
it('legacy saveState handles numbers', () => { it('saveState handles numbers', () => {
core.saveState('state_1', 1) core.saveState('state_1', 1)
assertWriteCalls([`::save-state name=state_1::1${os.EOL}`]) assertWriteCalls([`::save-state name=state_1::1${os.EOL}`])
}) })
it('legacy saveState handles bools', () => { it('saveState handles bools', () => {
core.saveState('state_1', true) core.saveState('state_1', true)
assertWriteCalls([`::save-state name=state_1::true${os.EOL}`]) assertWriteCalls([`::save-state name=state_1::true${os.EOL}`])
}) })
it('saveState produces the correct command and saves the state', () => {
const command = 'STATE'
createFileCommandFile(command)
core.saveState('my state', 'out val')
verifyFileCommand(
command,
`my state<<${DELIMITER}${os.EOL}out val${os.EOL}${DELIMITER}${os.EOL}`
)
})
it('saveState handles boolean inputs', () => {
const command = 'STATE'
createFileCommandFile(command)
core.saveState('my state', true)
verifyFileCommand(
command,
`my state<<${DELIMITER}${os.EOL}true${os.EOL}${DELIMITER}${os.EOL}`
)
})
it('saveState handles number inputs', () => {
const command = 'STATE'
createFileCommandFile(command)
core.saveState('my state', 5)
verifyFileCommand(
command,
`my state<<${DELIMITER}${os.EOL}5${os.EOL}${DELIMITER}${os.EOL}`
)
})
it('saveState does not allow delimiter as value', () => {
const command = 'STATE'
createFileCommandFile(command)
expect(() => {
core.saveState('my state', `good stuff ${DELIMITER} bad stuff`)
}).toThrow(
`Unexpected input: value should not contain the delimiter "${DELIMITER}"`
)
const filePath = path.join(__dirname, `test/${command}`)
fs.unlinkSync(filePath)
})
it('saveState does not allow delimiter as name', () => {
const command = 'STATE'
createFileCommandFile(command)
expect(() => {
core.saveState(`good stuff ${DELIMITER} bad stuff`, 'test')
}).toThrow(
`Unexpected input: name should not contain the delimiter "${DELIMITER}"`
)
const filePath = path.join(__dirname, `test/${command}`)
fs.unlinkSync(filePath)
})
it('getState gets wrapper action state', () => { it('getState gets wrapper action state', () => {
expect(core.getState('TEST_1')).toBe('state_val') expect(core.getState('TEST_1')).toBe('state_val')
}) })
+4 -31
View File
@@ -1,20 +1,18 @@
{ {
"name": "@actions/core", "name": "@actions/core",
"version": "1.10.0", "version": "1.9.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@actions/core", "name": "@actions/core",
"version": "1.10.0", "version": "1.8.1",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/http-client": "^2.0.1", "@actions/http-client": "^2.0.1"
"uuid": "^8.3.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^12.0.2", "@types/node": "^12.0.2"
"@types/uuid": "^8.3.4"
} }
}, },
"node_modules/@actions/http-client": { "node_modules/@actions/http-client": {
@@ -31,12 +29,6 @@
"integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==", "integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==",
"dev": true "dev": true
}, },
"node_modules/@types/uuid": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
"dev": true
},
"node_modules/tunnel": { "node_modules/tunnel": {
"version": "0.0.6", "version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
@@ -44,14 +36,6 @@
"engines": { "engines": {
"node": ">=0.6.11 <=0.7.0 || >=0.7.3" "node": ">=0.6.11 <=0.7.0 || >=0.7.3"
} }
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
} }
}, },
"dependencies": { "dependencies": {
@@ -69,21 +53,10 @@
"integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==", "integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==",
"dev": true "dev": true
}, },
"@types/uuid": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
"dev": true
},
"tunnel": { "tunnel": {
"version": "0.0.6", "version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
},
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
} }
} }
} }
+3 -5
View File
@@ -1,6 +1,6 @@
{ {
"name": "@actions/core", "name": "@actions/core",
"version": "1.10.0", "version": "1.9.0",
"description": "Actions core lib", "description": "Actions core lib",
"keywords": [ "keywords": [
"github", "github",
@@ -36,11 +36,9 @@
"url": "https://github.com/actions/toolkit/issues" "url": "https://github.com/actions/toolkit/issues"
}, },
"dependencies": { "dependencies": {
"@actions/http-client": "^2.0.1", "@actions/http-client": "^2.0.1"
"uuid": "^8.3.2"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^12.0.2", "@types/node": "^12.0.2"
"@types/uuid": "^8.3.4"
} }
} }
+10 -22
View File
@@ -1,5 +1,5 @@
import {issue, issueCommand} from './command' import {issue, issueCommand} from './command'
import {issueFileCommand, prepareKeyValueMessage} from './file-command' import {issueCommand as issueFileCommand} from './file-command'
import {toCommandProperties, toCommandValue} from './utils' import {toCommandProperties, toCommandValue} from './utils'
import * as os from 'os' import * as os from 'os'
@@ -64,7 +64,7 @@ export interface AnnotationProperties {
startColumn?: number startColumn?: number
/** /**
* The end column for the annotation. Cannot be sent when `startLine` and `endLine` are different values. * The start column for the annotation. Cannot be sent when `startLine` and `endLine` are different values.
* Defaults to `startColumn` when `startColumn` is provided. * Defaults to `startColumn` when `startColumn` is provided.
*/ */
endColumn?: number endColumn?: number
@@ -86,10 +86,12 @@ export function exportVariable(name: string, val: any): void {
const filePath = process.env['GITHUB_ENV'] || '' const filePath = process.env['GITHUB_ENV'] || ''
if (filePath) { if (filePath) {
return issueFileCommand('ENV', prepareKeyValueMessage(name, val)) const delimiter = '_GitHubActionsFileCommandDelimeter_'
const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}`
issueFileCommand('ENV', commandValue)
} else {
issueCommand('set-env', {name}, convertedVal)
} }
issueCommand('set-env', {name}, convertedVal)
} }
/** /**
@@ -153,11 +155,7 @@ export function getMultilineInput(
.split('\n') .split('\n')
.filter(x => x !== '') .filter(x => x !== '')
if (options && options.trimWhitespace === false) { return inputs
return inputs
}
return inputs.map(input => input.trim())
} }
/** /**
@@ -190,13 +188,8 @@ export function getBooleanInput(name: string, options?: InputOptions): boolean {
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export function setOutput(name: string, value: any): void { export function setOutput(name: string, value: any): void {
const filePath = process.env['GITHUB_OUTPUT'] || ''
if (filePath) {
return issueFileCommand('OUTPUT', prepareKeyValueMessage(name, value))
}
process.stdout.write(os.EOL) process.stdout.write(os.EOL)
issueCommand('set-output', {name}, toCommandValue(value)) issueCommand('set-output', {name}, value)
} }
/** /**
@@ -350,12 +343,7 @@ export async function group<T>(name: string, fn: () => Promise<T>): Promise<T> {
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export function saveState(name: string, value: any): void { export function saveState(name: string, value: any): void {
const filePath = process.env['GITHUB_STATE'] || '' issueCommand('save-state', {name}, value)
if (filePath) {
return issueFileCommand('STATE', prepareKeyValueMessage(name, value))
}
issueCommand('save-state', {name}, toCommandValue(value))
} }
/** /**
+1 -24
View File
@@ -5,10 +5,9 @@
import * as fs from 'fs' import * as fs from 'fs'
import * as os from 'os' import * as os from 'os'
import {v4 as uuidv4} from 'uuid'
import {toCommandValue} from './utils' import {toCommandValue} from './utils'
export function issueFileCommand(command: string, message: any): void { export function issueCommand(command: string, message: any): void {
const filePath = process.env[`GITHUB_${command}`] const filePath = process.env[`GITHUB_${command}`]
if (!filePath) { if (!filePath) {
throw new Error( throw new Error(
@@ -23,25 +22,3 @@ export function issueFileCommand(command: string, message: any): void {
encoding: 'utf8' encoding: 'utf8'
}) })
} }
export function prepareKeyValueMessage(key: string, value: any): string {
const delimiter = `ghadelimiter_${uuidv4()}`
const convertedValue = toCommandValue(value)
// These should realistically never happen, but just in case someone finds a
// way to exploit uuid generation let's not allow keys or values that contain
// the delimiter.
if (key.includes(delimiter)) {
throw new Error(
`Unexpected input: name should not contain the delimiter "${delimiter}"`
)
}
if (convertedValue.includes(delimiter)) {
throw new Error(
`Unexpected input: value should not contain the delimiter "${delimiter}"`
)
}
return `${key}<<${delimiter}${os.EOL}${convertedValue}${os.EOL}${delimiter}`
}
-8
View File
@@ -1,13 +1,5 @@
# @actions/github Releases # @actions/github Releases
### 5.1.1
- Export default octokit options [#1188](https://github.com/actions/toolkit/pull/1188)
### 5.1.0
- Add additionalPlugins parameter to getOctokit method [#1181](https://github.com/actions/toolkit/pull/1181)
- Dependency updates [#1180](https://github.com/actions/toolkit/pull/1180)
### 5.0.3 ### 5.0.3
- - Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087) - - Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "@actions/github", "name": "@actions/github",
"version": "5.1.1", "version": "5.0.3",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@actions/github", "name": "@actions/github",
"version": "5.1.1", "version": "5.0.2",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/http-client": "^2.0.1", "@actions/http-client": "^2.0.1",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@actions/github", "name": "@actions/github",
"version": "5.1.1", "version": "5.0.3",
"description": "Actions github lib", "description": "Actions github lib",
"keywords": [ "keywords": [
"github", "github",
+3 -5
View File
@@ -2,7 +2,7 @@ import * as Context from './context'
import {GitHub, getOctokitOptions} from './utils' import {GitHub, getOctokitOptions} from './utils'
// octokit + plugins // octokit + plugins
import {OctokitOptions, OctokitPlugin} from '@octokit/core/dist-types/types' import {OctokitOptions} from '@octokit/core/dist-types/types'
export const context = new Context.Context() export const context = new Context.Context()
@@ -14,9 +14,7 @@ export const context = new Context.Context()
*/ */
export function getOctokit( export function getOctokit(
token: string, token: string,
options?: OctokitOptions, options?: OctokitOptions
...additionalPlugins: OctokitPlugin[]
): InstanceType<typeof GitHub> { ): InstanceType<typeof GitHub> {
const GitHubWithPlugins = GitHub.plugin(...additionalPlugins) return new GitHub(getOctokitOptions(token, options))
return new GitHubWithPlugins(getOctokitOptions(token, options))
} }
+1 -1
View File
@@ -10,7 +10,7 @@ import {paginateRest} from '@octokit/plugin-paginate-rest'
export const context = new Context.Context() export const context = new Context.Context()
const baseUrl = Utils.getApiBaseUrl() const baseUrl = Utils.getApiBaseUrl()
export const defaults: OctokitOptions = { const defaults = {
baseUrl, baseUrl,
request: { request: {
agent: Utils.getProxyAgent(baseUrl) agent: Utils.getProxyAgent(baseUrl)
+17 -32
View File
@@ -9,25 +9,24 @@
"version": "0.3.0", "version": "0.3.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.9.1", "@actions/core": "^1.2.6",
"minimatch": "^3.0.4" "minimatch": "^3.0.4"
} }
}, },
"node_modules/@actions/core": { "node_modules/@actions/core": {
"version": "1.9.1", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz",
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==",
"dependencies": { "dependencies": {
"@actions/http-client": "^2.0.1", "@actions/http-client": "^1.0.11"
"uuid": "^8.3.2"
} }
}, },
"node_modules/@actions/http-client": { "node_modules/@actions/http-client": {
"version": "2.0.1", "version": "1.0.11",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
"dependencies": { "dependencies": {
"tunnel": "^0.0.6" "tunnel": "0.0.6"
} }
}, },
"node_modules/balanced-match": { "node_modules/balanced-match": {
@@ -67,32 +66,23 @@
"engines": { "engines": {
"node": ">=0.6.11 <=0.7.0 || >=0.7.3" "node": ">=0.6.11 <=0.7.0 || >=0.7.3"
} }
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
} }
}, },
"dependencies": { "dependencies": {
"@actions/core": { "@actions/core": {
"version": "1.9.1", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz",
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==",
"requires": { "requires": {
"@actions/http-client": "^2.0.1", "@actions/http-client": "^1.0.11"
"uuid": "^8.3.2"
} }
}, },
"@actions/http-client": { "@actions/http-client": {
"version": "2.0.1", "version": "1.0.11",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
"requires": { "requires": {
"tunnel": "^0.0.6" "tunnel": "0.0.6"
} }
}, },
"balanced-match": { "balanced-match": {
@@ -126,11 +116,6 @@
"version": "0.0.6", "version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
},
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
} }
} }
} }
+1 -1
View File
@@ -37,7 +37,7 @@
"url": "https://github.com/actions/toolkit/issues" "url": "https://github.com/actions/toolkit/issues"
}, },
"dependencies": { "dependencies": {
"@actions/core": "^1.9.1", "@actions/core": "^1.2.6",
"minimatch": "^3.0.4" "minimatch": "^3.0.4"
} }
} }
+1 -1
View File
@@ -6,7 +6,7 @@
"packages": { "packages": {
"": { "": {
"name": "@actions/http-client", "name": "@actions/http-client",
"version": "2.0.1", "version": "2.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"tunnel": "^0.0.6" "tunnel": "^0.0.6"
+22 -21
View File
@@ -6,7 +6,7 @@
"packages": { "packages": {
"": { "": {
"name": "@actions/tool-cache", "name": "@actions/tool-cache",
"version": "2.0.1", "version": "2.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.2.6", "@actions/core": "^1.2.6",
@@ -24,20 +24,19 @@
} }
}, },
"node_modules/@actions/core": { "node_modules/@actions/core": {
"version": "1.9.1", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz",
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==",
"dependencies": { "dependencies": {
"@actions/http-client": "^2.0.1", "@actions/http-client": "^1.0.11"
"uuid": "^8.3.2"
} }
}, },
"node_modules/@actions/core/node_modules/uuid": { "node_modules/@actions/core/node_modules/@actions/http-client": {
"version": "8.3.2", "version": "1.0.11",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
"bin": { "dependencies": {
"uuid": "dist/bin/uuid" "tunnel": "0.0.6"
} }
}, },
"node_modules/@actions/exec": { "node_modules/@actions/exec": {
@@ -292,18 +291,20 @@
}, },
"dependencies": { "dependencies": {
"@actions/core": { "@actions/core": {
"version": "1.9.1", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz",
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==",
"requires": { "requires": {
"@actions/http-client": "^2.0.1", "@actions/http-client": "^1.0.11"
"uuid": "^8.3.2"
}, },
"dependencies": { "dependencies": {
"uuid": { "@actions/http-client": {
"version": "8.3.2", "version": "1.0.11",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
"requires": {
"tunnel": "0.0.6"
}
} }
} }
}, },
+1 -11
View File
@@ -54,16 +54,6 @@ const AUDIT_ALLOW_LIST = [
path: "lerna>@lerna/version>@lerna/conventional-commits>conventional-changelog-core>get-pkg-repo>meow>trim-newlines", path: "lerna>@lerna/version>@lerna/conventional-commits>conventional-changelog-core>get-pkg-repo>meow>trim-newlines",
advisoryUrl: "https://www.npmjs.com/advisories/1753", advisoryUrl: "https://www.npmjs.com/advisories/1753",
justification: "dependency of lerna (dev only); low severity" justification: "dependency of lerna (dev only); low severity"
},
{
path: "lerna>@lerna/version>@lerna/github-client>git-url-parse>git-up>parse-url",
advisoryUrl: "https://github.com/advisories/GHSA-j9fq-vwqv-2fm2",
justification: "dependency of lerna; moderate severity"
},
{
path: "lerna>@lerna/publish>@lerna/version>@lerna/github-client>git-url-parse>git-up>parse-url",
advisoryUrl: "https://github.com/advisories/GHSA-j9fq-vwqv-2fm2",
justification: "dependency of lerna; moderate severity"
} }
] ]
@@ -96,4 +86,4 @@ if (numVulnerabilities > 0) {
console.log(`Found ${numVulnerabilities} unrecognized vulnerabilit${pluralized} from \`npm audit\`:`) console.log(`Found ${numVulnerabilities} unrecognized vulnerabilit${pluralized} from \`npm audit\`:`)
console.log(JSON.stringify(remainingVulnerabilities, null, 2)) console.log(JSON.stringify(remainingVulnerabilities, null, 2))
process.exit(1) process.exit(1)
} }