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
Shubham Tiwari c5278cdd08 new major version release (#1123) 2022-06-24 15:18:30 +05:30
Shubham Tiwari 46231a7da3 Graceful handling of error (non-validation one) (#1122)
* Initial changes

* added info error as well

* Format

* Unused package

* adding message field

* removed line

* Review comments

* review comment to add validation as errors handling
2022-06-24 10:46:20 +05:30
Thomas Boop 9b7bcb1567 actions/core 1.9.0 release (#1116)
* 1.9.0 release

* add link to pr
2022-06-15 11:34:58 -04:00
Seth Vargo 00282d6145 core: add helpers for working with paths across OSes (#1102) 2022-06-15 11:18:44 -04:00
Sankalp Kotewar b5f31bb5a2 Merge pull request #1108 from actions/users/kotewar/fix-tar-exit-with-code-1
Adding fix for tar exiting with code 1 issue
2022-06-06 14:41:07 +05:30
Sankalp Kotewar 41c667327d Reverted other package-lock.json 2022-06-06 08:03:56 +00:00
Sankalp Kotewar 2fd9a80bc1 Revert "Adding fix for tar exiting with code 1 issue"
This reverts commit 197f5a13a9.
2022-06-06 07:56:27 +00:00
Sankalp Kotewar ebfda315a5 Revert "Adding updated package-lock.json for cache"
This reverts commit 1d5b16aa38.
2022-06-06 07:56:25 +00:00
Sankalp Kotewar fe93288f85 Revert "Fixed test case for tar creation"
This reverts commit 91842768bd.
2022-06-06 07:56:23 +00:00
Sankalp Kotewar 2d6e5ecd7c Revert "Pushing updated package-lock.json for artifact"
This reverts commit 1fc4ec3274.
2022-06-06 07:56:21 +00:00
Sankalp Kotewar 49cd1ccc3f Revert "Fixed test case for Windows env"
This reverts commit a78bb30ca0.
2022-06-06 07:56:18 +00:00
Sankalp Kotewar 3cf35dbd46 Revert "Changed an import in test case to standard import"
This reverts commit 347d2e2a35.
2022-06-06 07:56:16 +00:00
Sankalp Kotewar 845770f824 Revert "Revert "Changed an import in test case to standard import""
This reverts commit c1bb3fb679.
2022-06-06 07:56:13 +00:00
Sankalp Kotewar c1bb3fb679 Revert "Changed an import in test case to standard import"
This reverts commit 347d2e2a35.
2022-06-03 09:05:12 +00:00
Sankalp Kotewar 347d2e2a35 Changed an import in test case to standard import 2022-06-03 07:45:12 +00:00
Sankalp Kotewar a78bb30ca0 Fixed test case for Windows env 2022-06-03 07:33:12 +00:00
Sankalp Kotewar 1fc4ec3274 Pushing updated package-lock.json for artifact 2022-06-03 07:26:28 +00:00
Sankalp Kotewar 91842768bd Fixed test case for tar creation 2022-06-03 07:19:54 +00:00
Sankalp Kotewar 1d5b16aa38 Adding updated package-lock.json for cache 2022-06-01 13:32:34 +00:00
Sankalp Kotewar 197f5a13a9 Adding fix for tar exiting with code 1 issue 2022-06-01 13:18:50 +00:00
Sankalp Kotewar 8263c4d15d Merge pull request #1097 from actions/users/kotewar/avoid-empty-cache-save
Avoid saving empty cache when there are no files to cache.
2022-05-24 13:27:13 +05:30
Sankalp Kotewar 4ee0048304 Updated RELEASES.md with release information 2022-05-24 06:55:11 +00:00
Sankalp Kotewar d618dc457e Added package-lock.json after version upgrade 2022-05-24 05:48:53 +00:00
Sankalp Kotewar 558edc0a3b Patch version bumped from 2.0.4 to 2.0.5 for cache 2022-05-24 05:45:53 +00:00
Sankalp Kotewar 92b210aced Test case fix for warning message changes 2022-05-23 12:05:31 +00:00
Sankalp Kotewar 6f6f4e7588 Enhanced warning description to make more sense. 2022-05-23 12:03:18 +00:00
Sankalp Kotewar 10a3934663 Fixed linting issues 2022-05-23 06:49:26 +00:00
Sankalp Kotewar 6421989639 Standardized test case input 2022-05-23 06:39:22 +00:00
Sankalp Kotewar 07b91eafe5 Added unit test case for #624 2022-05-23 06:32:13 +00:00
Sankalp Kotewar b9fefecf57 Formatting changes 2022-05-23 05:59:56 +00:00
Sankalp Kotewar 9aecf41d21 Updated error type to generic to show warning 2022-05-23 05:39:42 +00:00
Sankalp Kotewar da52b35800 Adding check for cache paths' existence. 2022-05-22 10:09:13 +00:00
Rob Herley 1e0f6285e5 Merge pull request #1095 from actions/robherley/artifact-1.1.0-release
@actions/artifact 1.1.0 release
2022-05-19 14:52:47 -04:00
Rob Herley dd4e856a4e @actions/artifact 1.1.0 release 2022-05-19 18:17:15 +00:00
Rob Herley a70804595b Merge pull request #1063 from actions/robherley/artifact-digest
Add checksum validation on artifact upload
2022-05-19 14:12:50 -04:00
Rob Herley eb7ed88d77 Merge branch 'main' into robherley/artifact-digest 2022-05-19 11:45:42 -04:00
Konrad Pabjan 500d0b42fe Bump all packages that have @actions/http-client as a dependency (#1088)
* bump @actions/artifact

* update @actions/cache

* Update @actions/core

* Update @actions/github

* update @actions/tool-cache
2022-05-13 11:12:58 -04:00
Konrad Pabjan 82efa3d285 Bump @actions/http-client in all packages that use it (#1087) 2022-05-13 10:58:36 -04:00
Konrad Pabjan 2abc7c46f8 Bump to version 2.0.1 (#1086) 2022-05-13 10:29:29 -04:00
Konrad Pabjan e48f1d0c54 Make tunnel a prod dependency for http-client (#1085) 2022-05-13 10:19:06 -04:00
Brian Cristante aa676f3cc7 Update other packages to use http-client v2 (#1082)
We moved `@actions/http-client` to be part of the toolkit in https://github.com/actions/toolkit/pull/1062.  We also made some breaking changes to exported types and released v2.

The biggest change in terms of lines of code affected was to get rid of the `I-` prefix for interfaces since TypeScript doesn't follow this convention.

I bumped the patch version of all packages except for `tool-cache`, where I bumped the major version.  The rationale is explained in the release notes for that package.
2022-05-11 17:14:25 -04:00
Rob Herley 925ae6978b Merge pull request #1074 from actions/robherley/core-1.8.0-release
@actions/core 1.8.0 release
2022-05-05 16:24:45 -04:00
Rob Herley e73063a93c @actions/core 1.8.0 release 2022-05-05 20:17:30 +00:00
Rob Herley c4ae214c26 Merge pull request #1073 from actions/robherley/deprecate-markdownsummary
Add & deprecate old markdownSummary export
2022-05-05 16:07:16 -04:00
Rob Herley 35e5aac523 actually use md5 not sha256 2022-05-05 10:32:09 -04:00
Rob Herley a3c696e88e add md5 and use b64 for digest encodings 2022-05-05 09:26:38 -04:00
Rob Herley b68735e060 misc pr feedback 2022-04-27 22:24:16 +00:00
Rob Herley d5c547c19f update crc header key 2022-04-27 22:22:35 +00:00
Rob Herley 9e285cc3fa crc: update test header data 2022-04-26 23:21:31 +00:00
Rob Herley 3f95e2ea4f crc: update headers & digest stream 2022-04-26 22:59:56 +00:00
Rob Herley fccc5ee6e6 crc: move tbl out of class, more tests 2022-04-26 17:31:17 +00:00
Rob Herley 3d61fe8000 add crc64 & tests 2022-04-26 17:13:40 +00:00
Rob Herley 9387bd7ded Merge branch 'main' into robherley/artifact-digest 2022-04-26 15:54:22 +00:00
Rob Herley e3549a9c58 artifact: tests for stream digest util 2022-04-05 09:31:49 -04:00
Rob Herley c5d1911357 add digest header for uploads 2022-04-04 17:54:15 -04:00
43 changed files with 1079 additions and 235 deletions
+13 -1
View File
@@ -77,4 +77,16 @@
### 1.0.0 ### 1.0.0
- Update `lockfileVersion` to `v2` in `package-lock.json [#1009](https://github.com/actions/toolkit/pull/1009) - Update `lockfileVersion` to `v2` in `package-lock.json` [#1009](https://github.com/actions/toolkit/pull/1009)
### 1.0.1
- Update to v2.0.0 of `@actions/http-client`
### 1.0.2
- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
### 1.1.0
- Add `x-actions-results-crc64` and `x-actions-results-md5` checksum headers on upload [#1063](https://github.com/actions/toolkit/pull/1063)
+57
View File
@@ -0,0 +1,57 @@
import CRC64, {CRC64DigestEncoding} from '../src/internal/crc64'
const fixtures = {
data:
'🚀 👉😎👉 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\nUt enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\nExcepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n',
expected: {
hex: '846CE4ADAD6223ED',
base64: '7SNira3kbIQ=',
buffer: Buffer.from([0xed, 0x23, 0x62, 0xad, 0xad, 0xe4, 0x6c, 0x84])
}
}
function assertEncodings(crc: CRC64): void {
const encodings = Object.keys(fixtures.expected) as CRC64DigestEncoding[]
for (const encoding of encodings) {
expect(crc.digest(encoding)).toEqual(fixtures.expected[encoding])
}
}
describe('@actions/artifact/src/internal/crc64', () => {
it('CRC64 from string', async () => {
const crc = new CRC64()
crc.update(fixtures.data)
assertEncodings(crc)
})
it('CRC64 from buffer', async () => {
const crc = new CRC64()
const buf = Buffer.from(fixtures.data)
crc.update(buf)
assertEncodings(crc)
})
it('CRC64 from split data', async () => {
const crc = new CRC64()
const splits = fixtures.data.split('\n').slice(0, -1)
for (const split of splits) {
crc.update(`${split}\n`)
}
assertEncodings(crc)
})
it('flips 64 bits', async () => {
const tests = [
[BigInt(0), BigInt('0xffffffffffffffff')],
[BigInt('0xffffffffffffffff'), BigInt(0)],
[BigInt('0xdeadbeef'), BigInt('0xffffffff21524110')]
]
for (const [input, expected] of tests) {
expect(CRC64.flip64Bits(input)).toEqual(expected)
}
})
})
+2 -3
View File
@@ -3,7 +3,6 @@ import * as net from 'net'
import * as core from '@actions/core' import * as core from '@actions/core'
import * as configVariables from '../src/internal/config-variables' import * as configVariables from '../src/internal/config-variables'
import {retry} from '../src/internal/requestUtils' import {retry} from '../src/internal/requestUtils'
import {IHttpClientResponse} from '@actions/http-client/interfaces'
import {HttpClientResponse} from '@actions/http-client' import {HttpClientResponse} from '@actions/http-client'
jest.mock('../src/internal/config-variables') jest.mock('../src/internal/config-variables')
@@ -42,7 +41,7 @@ async function testRetry(
async function handleResponse( async function handleResponse(
testResponseCode: number | undefined testResponseCode: number | undefined
): Promise<IHttpClientResponse> { ): Promise<HttpClientResponse> {
if (!testResponseCode) { if (!testResponseCode) {
throw new Error( throw new Error(
'Test incorrectly set up. reverse.pop() was called too many times so not enough test response codes were supplied' 'Test incorrectly set up. reverse.pop() was called too many times so not enough test response codes were supplied'
@@ -72,7 +71,7 @@ async function emptyMockReadBody(): Promise<string> {
async function setupSingleMockResponse( async function setupSingleMockResponse(
statusCode: number statusCode: number
): Promise<IHttpClientResponse> { ): Promise<HttpClientResponse> {
const mockMessage = new http.IncomingMessage(new net.Socket()) const mockMessage = new http.IncomingMessage(new net.Socket())
const mockReadBody = emptyMockReadBody const mockReadBody = emptyMockReadBody
mockMessage.statusCode = statusCode mockMessage.statusCode = statusCode
+19 -2
View File
@@ -10,6 +10,7 @@ import {
getInitialRetryIntervalInMilliseconds, getInitialRetryIntervalInMilliseconds,
getRetryMultiplier getRetryMultiplier
} from '../src/internal/config-variables' } from '../src/internal/config-variables'
import {Readable} from 'stream'
jest.mock('../src/internal/config-variables') jest.mock('../src/internal/config-variables')
@@ -74,15 +75,20 @@ describe('Utils', () => {
const size = 24 const size = 24
const uncompressedLength = 100 const uncompressedLength = 100
const range = 'bytes 0-199/200' const range = 'bytes 0-199/200'
const digest = {
crc64: 'bSzITYnW/P8=',
md5: 'Xiv1fT9AxLbfadrxk2y3ZvgyN0tPwCWafL/wbi9w8mk='
}
const headers = utils.getUploadHeaders( const headers = utils.getUploadHeaders(
contentType, contentType,
true, true,
true, true,
uncompressedLength, uncompressedLength,
size, size,
range range,
digest
) )
expect(Object.keys(headers).length).toEqual(8) expect(Object.keys(headers).length).toEqual(10)
expect(headers['Accept']).toEqual( expect(headers['Accept']).toEqual(
`application/json;api-version=${utils.getApiVersion()}` `application/json;api-version=${utils.getApiVersion()}`
) )
@@ -93,6 +99,8 @@ describe('Utils', () => {
expect(headers['x-tfs-filelength']).toEqual(uncompressedLength) expect(headers['x-tfs-filelength']).toEqual(uncompressedLength)
expect(headers['Content-Length']).toEqual(size) expect(headers['Content-Length']).toEqual(size)
expect(headers['Content-Range']).toEqual(range) expect(headers['Content-Range']).toEqual(range)
expect(headers['x-actions-results-crc64']).toEqual(digest.crc64)
expect(headers['x-actions-results-md5']).toEqual(digest.md5)
}) })
it('Test constructing upload headers with only required parameter', () => { it('Test constructing upload headers with only required parameter', () => {
@@ -219,4 +227,13 @@ describe('Utils', () => {
const size2 = (await fs.promises.stat(emptyFile2)).size const size2 = (await fs.promises.stat(emptyFile2)).size
expect(size2).toEqual(0) expect(size2).toEqual(0)
}) })
it('Creates a digest from a readable stream', async () => {
const data = 'lorem ipsum'
const stream = Readable.from(data)
const digest = await utils.digestForStream(stream)
expect(digest.crc64).toBe('bSzITYnW/P8=')
expect(digest.md5).toBe('gKdR/eV3AoZAxBkADjPrpg==')
})
}) })
+32 -14
View File
@@ -1,16 +1,16 @@
{ {
"name": "@actions/artifact", "name": "@actions/artifact",
"version": "0.6.1", "version": "1.1.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@actions/artifact", "name": "@actions/artifact",
"version": "0.6.1", "version": "1.0.1",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.2.6", "@actions/core": "^1.2.6",
"@actions/http-client": "^1.0.11", "@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,14 +20,14 @@
} }
}, },
"node_modules/@actions/core": { "node_modules/@actions/core": {
"version": "1.6.0", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz",
"integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==",
"dependencies": { "dependencies": {
"@actions/http-client": "^1.0.11" "@actions/http-client": "^1.0.11"
} }
}, },
"node_modules/@actions/http-client": { "node_modules/@actions/core/node_modules/@actions/http-client": {
"version": "1.0.11", "version": "1.0.11",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
@@ -35,6 +35,14 @@
"tunnel": "0.0.6" "tunnel": "0.0.6"
} }
}, },
"node_modules/@actions/http-client": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"dependencies": {
"tunnel": "^0.0.6"
}
},
"node_modules/@types/tmp": { "node_modules/@types/tmp": {
"version": "0.2.3", "version": "0.2.3",
"resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.3.tgz", "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.3.tgz",
@@ -187,19 +195,29 @@
}, },
"dependencies": { "dependencies": {
"@actions/core": { "@actions/core": {
"version": "1.6.0", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz",
"integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==",
"requires": { "requires": {
"@actions/http-client": "^1.0.11" "@actions/http-client": "^1.0.11"
},
"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": {
"version": "1.0.11", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"requires": { "requires": {
"tunnel": "0.0.6" "tunnel": "^0.0.6"
} }
}, },
"@types/tmp": { "@types/tmp": {
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@actions/artifact", "name": "@actions/artifact",
"version": "1.0.0", "version": "1.1.0",
"preview": true, "preview": true,
"description": "Actions artifact lib", "description": "Actions artifact lib",
"keywords": [ "keywords": [
@@ -38,7 +38,7 @@
}, },
"dependencies": { "dependencies": {
"@actions/core": "^1.2.6", "@actions/core": "^1.2.6",
"@actions/http-client": "^1.0.11", "@actions/http-client": "^2.0.1",
"tmp": "^0.2.1", "tmp": "^0.2.1",
"tmp-promise": "^3.0.2" "tmp-promise": "^3.0.2"
}, },
+317
View File
@@ -0,0 +1,317 @@
/**
* CRC64: cyclic redundancy check, 64-bits
*
* In order to validate that artifacts are not being corrupted over the wire, this redundancy check allows us to
* validate that there was no corruption during transmission. The implementation here is based on Go's hash/crc64 pkg,
* but without the slicing-by-8 optimization: https://cs.opensource.google/go/go/+/master:src/hash/crc64/crc64.go
*
* This implementation uses a pregenerated table based on 0x9A6C9329AC4BC9B5 as the polynomial, the same polynomial that
* is used for Azure Storage: https://github.com/Azure/azure-storage-net/blob/cbe605f9faa01bfc3003d75fc5a16b2eaccfe102/Lib/Common/Core/Util/Crc64.cs#L27
*/
// when transpile target is >= ES2020 (after dropping node 12) these can be changed to bigint literals - ts(2737)
const PREGEN_POLY_TABLE = [
BigInt('0x0000000000000000'),
BigInt('0x7F6EF0C830358979'),
BigInt('0xFEDDE190606B12F2'),
BigInt('0x81B31158505E9B8B'),
BigInt('0xC962E5739841B68F'),
BigInt('0xB60C15BBA8743FF6'),
BigInt('0x37BF04E3F82AA47D'),
BigInt('0x48D1F42BC81F2D04'),
BigInt('0xA61CECB46814FE75'),
BigInt('0xD9721C7C5821770C'),
BigInt('0x58C10D24087FEC87'),
BigInt('0x27AFFDEC384A65FE'),
BigInt('0x6F7E09C7F05548FA'),
BigInt('0x1010F90FC060C183'),
BigInt('0x91A3E857903E5A08'),
BigInt('0xEECD189FA00BD371'),
BigInt('0x78E0FF3B88BE6F81'),
BigInt('0x078E0FF3B88BE6F8'),
BigInt('0x863D1EABE8D57D73'),
BigInt('0xF953EE63D8E0F40A'),
BigInt('0xB1821A4810FFD90E'),
BigInt('0xCEECEA8020CA5077'),
BigInt('0x4F5FFBD87094CBFC'),
BigInt('0x30310B1040A14285'),
BigInt('0xDEFC138FE0AA91F4'),
BigInt('0xA192E347D09F188D'),
BigInt('0x2021F21F80C18306'),
BigInt('0x5F4F02D7B0F40A7F'),
BigInt('0x179EF6FC78EB277B'),
BigInt('0x68F0063448DEAE02'),
BigInt('0xE943176C18803589'),
BigInt('0x962DE7A428B5BCF0'),
BigInt('0xF1C1FE77117CDF02'),
BigInt('0x8EAF0EBF2149567B'),
BigInt('0x0F1C1FE77117CDF0'),
BigInt('0x7072EF2F41224489'),
BigInt('0x38A31B04893D698D'),
BigInt('0x47CDEBCCB908E0F4'),
BigInt('0xC67EFA94E9567B7F'),
BigInt('0xB9100A5CD963F206'),
BigInt('0x57DD12C379682177'),
BigInt('0x28B3E20B495DA80E'),
BigInt('0xA900F35319033385'),
BigInt('0xD66E039B2936BAFC'),
BigInt('0x9EBFF7B0E12997F8'),
BigInt('0xE1D10778D11C1E81'),
BigInt('0x606216208142850A'),
BigInt('0x1F0CE6E8B1770C73'),
BigInt('0x8921014C99C2B083'),
BigInt('0xF64FF184A9F739FA'),
BigInt('0x77FCE0DCF9A9A271'),
BigInt('0x08921014C99C2B08'),
BigInt('0x4043E43F0183060C'),
BigInt('0x3F2D14F731B68F75'),
BigInt('0xBE9E05AF61E814FE'),
BigInt('0xC1F0F56751DD9D87'),
BigInt('0x2F3DEDF8F1D64EF6'),
BigInt('0x50531D30C1E3C78F'),
BigInt('0xD1E00C6891BD5C04'),
BigInt('0xAE8EFCA0A188D57D'),
BigInt('0xE65F088B6997F879'),
BigInt('0x9931F84359A27100'),
BigInt('0x1882E91B09FCEA8B'),
BigInt('0x67EC19D339C963F2'),
BigInt('0xD75ADABD7A6E2D6F'),
BigInt('0xA8342A754A5BA416'),
BigInt('0x29873B2D1A053F9D'),
BigInt('0x56E9CBE52A30B6E4'),
BigInt('0x1E383FCEE22F9BE0'),
BigInt('0x6156CF06D21A1299'),
BigInt('0xE0E5DE5E82448912'),
BigInt('0x9F8B2E96B271006B'),
BigInt('0x71463609127AD31A'),
BigInt('0x0E28C6C1224F5A63'),
BigInt('0x8F9BD7997211C1E8'),
BigInt('0xF0F5275142244891'),
BigInt('0xB824D37A8A3B6595'),
BigInt('0xC74A23B2BA0EECEC'),
BigInt('0x46F932EAEA507767'),
BigInt('0x3997C222DA65FE1E'),
BigInt('0xAFBA2586F2D042EE'),
BigInt('0xD0D4D54EC2E5CB97'),
BigInt('0x5167C41692BB501C'),
BigInt('0x2E0934DEA28ED965'),
BigInt('0x66D8C0F56A91F461'),
BigInt('0x19B6303D5AA47D18'),
BigInt('0x980521650AFAE693'),
BigInt('0xE76BD1AD3ACF6FEA'),
BigInt('0x09A6C9329AC4BC9B'),
BigInt('0x76C839FAAAF135E2'),
BigInt('0xF77B28A2FAAFAE69'),
BigInt('0x8815D86ACA9A2710'),
BigInt('0xC0C42C4102850A14'),
BigInt('0xBFAADC8932B0836D'),
BigInt('0x3E19CDD162EE18E6'),
BigInt('0x41773D1952DB919F'),
BigInt('0x269B24CA6B12F26D'),
BigInt('0x59F5D4025B277B14'),
BigInt('0xD846C55A0B79E09F'),
BigInt('0xA72835923B4C69E6'),
BigInt('0xEFF9C1B9F35344E2'),
BigInt('0x90973171C366CD9B'),
BigInt('0x1124202993385610'),
BigInt('0x6E4AD0E1A30DDF69'),
BigInt('0x8087C87E03060C18'),
BigInt('0xFFE938B633338561'),
BigInt('0x7E5A29EE636D1EEA'),
BigInt('0x0134D92653589793'),
BigInt('0x49E52D0D9B47BA97'),
BigInt('0x368BDDC5AB7233EE'),
BigInt('0xB738CC9DFB2CA865'),
BigInt('0xC8563C55CB19211C'),
BigInt('0x5E7BDBF1E3AC9DEC'),
BigInt('0x21152B39D3991495'),
BigInt('0xA0A63A6183C78F1E'),
BigInt('0xDFC8CAA9B3F20667'),
BigInt('0x97193E827BED2B63'),
BigInt('0xE877CE4A4BD8A21A'),
BigInt('0x69C4DF121B863991'),
BigInt('0x16AA2FDA2BB3B0E8'),
BigInt('0xF86737458BB86399'),
BigInt('0x8709C78DBB8DEAE0'),
BigInt('0x06BAD6D5EBD3716B'),
BigInt('0x79D4261DDBE6F812'),
BigInt('0x3105D23613F9D516'),
BigInt('0x4E6B22FE23CC5C6F'),
BigInt('0xCFD833A67392C7E4'),
BigInt('0xB0B6C36E43A74E9D'),
BigInt('0x9A6C9329AC4BC9B5'),
BigInt('0xE50263E19C7E40CC'),
BigInt('0x64B172B9CC20DB47'),
BigInt('0x1BDF8271FC15523E'),
BigInt('0x530E765A340A7F3A'),
BigInt('0x2C608692043FF643'),
BigInt('0xADD397CA54616DC8'),
BigInt('0xD2BD67026454E4B1'),
BigInt('0x3C707F9DC45F37C0'),
BigInt('0x431E8F55F46ABEB9'),
BigInt('0xC2AD9E0DA4342532'),
BigInt('0xBDC36EC59401AC4B'),
BigInt('0xF5129AEE5C1E814F'),
BigInt('0x8A7C6A266C2B0836'),
BigInt('0x0BCF7B7E3C7593BD'),
BigInt('0x74A18BB60C401AC4'),
BigInt('0xE28C6C1224F5A634'),
BigInt('0x9DE29CDA14C02F4D'),
BigInt('0x1C518D82449EB4C6'),
BigInt('0x633F7D4A74AB3DBF'),
BigInt('0x2BEE8961BCB410BB'),
BigInt('0x548079A98C8199C2'),
BigInt('0xD53368F1DCDF0249'),
BigInt('0xAA5D9839ECEA8B30'),
BigInt('0x449080A64CE15841'),
BigInt('0x3BFE706E7CD4D138'),
BigInt('0xBA4D61362C8A4AB3'),
BigInt('0xC52391FE1CBFC3CA'),
BigInt('0x8DF265D5D4A0EECE'),
BigInt('0xF29C951DE49567B7'),
BigInt('0x732F8445B4CBFC3C'),
BigInt('0x0C41748D84FE7545'),
BigInt('0x6BAD6D5EBD3716B7'),
BigInt('0x14C39D968D029FCE'),
BigInt('0x95708CCEDD5C0445'),
BigInt('0xEA1E7C06ED698D3C'),
BigInt('0xA2CF882D2576A038'),
BigInt('0xDDA178E515432941'),
BigInt('0x5C1269BD451DB2CA'),
BigInt('0x237C997575283BB3'),
BigInt('0xCDB181EAD523E8C2'),
BigInt('0xB2DF7122E51661BB'),
BigInt('0x336C607AB548FA30'),
BigInt('0x4C0290B2857D7349'),
BigInt('0x04D364994D625E4D'),
BigInt('0x7BBD94517D57D734'),
BigInt('0xFA0E85092D094CBF'),
BigInt('0x856075C11D3CC5C6'),
BigInt('0x134D926535897936'),
BigInt('0x6C2362AD05BCF04F'),
BigInt('0xED9073F555E26BC4'),
BigInt('0x92FE833D65D7E2BD'),
BigInt('0xDA2F7716ADC8CFB9'),
BigInt('0xA54187DE9DFD46C0'),
BigInt('0x24F29686CDA3DD4B'),
BigInt('0x5B9C664EFD965432'),
BigInt('0xB5517ED15D9D8743'),
BigInt('0xCA3F8E196DA80E3A'),
BigInt('0x4B8C9F413DF695B1'),
BigInt('0x34E26F890DC31CC8'),
BigInt('0x7C339BA2C5DC31CC'),
BigInt('0x035D6B6AF5E9B8B5'),
BigInt('0x82EE7A32A5B7233E'),
BigInt('0xFD808AFA9582AA47'),
BigInt('0x4D364994D625E4DA'),
BigInt('0x3258B95CE6106DA3'),
BigInt('0xB3EBA804B64EF628'),
BigInt('0xCC8558CC867B7F51'),
BigInt('0x8454ACE74E645255'),
BigInt('0xFB3A5C2F7E51DB2C'),
BigInt('0x7A894D772E0F40A7'),
BigInt('0x05E7BDBF1E3AC9DE'),
BigInt('0xEB2AA520BE311AAF'),
BigInt('0x944455E88E0493D6'),
BigInt('0x15F744B0DE5A085D'),
BigInt('0x6A99B478EE6F8124'),
BigInt('0x224840532670AC20'),
BigInt('0x5D26B09B16452559'),
BigInt('0xDC95A1C3461BBED2'),
BigInt('0xA3FB510B762E37AB'),
BigInt('0x35D6B6AF5E9B8B5B'),
BigInt('0x4AB846676EAE0222'),
BigInt('0xCB0B573F3EF099A9'),
BigInt('0xB465A7F70EC510D0'),
BigInt('0xFCB453DCC6DA3DD4'),
BigInt('0x83DAA314F6EFB4AD'),
BigInt('0x0269B24CA6B12F26'),
BigInt('0x7D0742849684A65F'),
BigInt('0x93CA5A1B368F752E'),
BigInt('0xECA4AAD306BAFC57'),
BigInt('0x6D17BB8B56E467DC'),
BigInt('0x12794B4366D1EEA5'),
BigInt('0x5AA8BF68AECEC3A1'),
BigInt('0x25C64FA09EFB4AD8'),
BigInt('0xA4755EF8CEA5D153'),
BigInt('0xDB1BAE30FE90582A'),
BigInt('0xBCF7B7E3C7593BD8'),
BigInt('0xC399472BF76CB2A1'),
BigInt('0x422A5673A732292A'),
BigInt('0x3D44A6BB9707A053'),
BigInt('0x759552905F188D57'),
BigInt('0x0AFBA2586F2D042E'),
BigInt('0x8B48B3003F739FA5'),
BigInt('0xF42643C80F4616DC'),
BigInt('0x1AEB5B57AF4DC5AD'),
BigInt('0x6585AB9F9F784CD4'),
BigInt('0xE436BAC7CF26D75F'),
BigInt('0x9B584A0FFF135E26'),
BigInt('0xD389BE24370C7322'),
BigInt('0xACE74EEC0739FA5B'),
BigInt('0x2D545FB4576761D0'),
BigInt('0x523AAF7C6752E8A9'),
BigInt('0xC41748D84FE75459'),
BigInt('0xBB79B8107FD2DD20'),
BigInt('0x3ACAA9482F8C46AB'),
BigInt('0x45A459801FB9CFD2'),
BigInt('0x0D75ADABD7A6E2D6'),
BigInt('0x721B5D63E7936BAF'),
BigInt('0xF3A84C3BB7CDF024'),
BigInt('0x8CC6BCF387F8795D'),
BigInt('0x620BA46C27F3AA2C'),
BigInt('0x1D6554A417C62355'),
BigInt('0x9CD645FC4798B8DE'),
BigInt('0xE3B8B53477AD31A7'),
BigInt('0xAB69411FBFB21CA3'),
BigInt('0xD407B1D78F8795DA'),
BigInt('0x55B4A08FDFD90E51'),
BigInt('0x2ADA5047EFEC8728')
]
export type CRC64DigestEncoding = 'hex' | 'base64' | 'buffer'
class CRC64 {
private _crc: bigint
constructor() {
this._crc = BigInt(0)
}
update(data: Buffer | string): void {
const buffer = typeof data === 'string' ? Buffer.from(data) : data
let crc = CRC64.flip64Bits(this._crc)
for (const dataByte of buffer) {
const crcByte = Number(crc & BigInt(0xff))
crc = PREGEN_POLY_TABLE[crcByte ^ dataByte] ^ (crc >> BigInt(8))
}
this._crc = CRC64.flip64Bits(crc)
}
digest(encoding?: CRC64DigestEncoding): string | Buffer {
switch (encoding) {
case 'hex':
return this._crc.toString(16).toUpperCase()
case 'base64':
return this.toBuffer().toString('base64')
default:
return this.toBuffer()
}
}
private toBuffer(): Buffer {
return Buffer.from(
[0, 8, 16, 24, 32, 40, 48, 56].map(s =>
Number((this._crc >> BigInt(s)) & BigInt(0xff))
)
)
}
static flip64Bits(n: bigint): bigint {
return (BigInt(1) << BigInt(64)) - BigInt(1) - n
}
}
export default CRC64
@@ -18,7 +18,7 @@ import {URL} from 'url'
import {StatusReporter} from './status-reporter' import {StatusReporter} from './status-reporter'
import {performance} from 'perf_hooks' import {performance} from 'perf_hooks'
import {ListArtifactsResponse, QueryArtifactResponse} from './contracts' import {ListArtifactsResponse, QueryArtifactResponse} from './contracts'
import {IHttpClientResponse} from '@actions/http-client/interfaces' import {HttpClientResponse} from '@actions/http-client'
import {HttpManager} from './http-manager' import {HttpManager} from './http-manager'
import {DownloadItem} from './download-specification' import {DownloadItem} from './download-specification'
import {getDownloadFileConcurrency, getRetryLimit} from './config-variables' import {getDownloadFileConcurrency, getRetryLimit} from './config-variables'
@@ -152,7 +152,7 @@ export class DownloadHttpClient {
const headers = getDownloadHeaders('application/json', true, true) const headers = getDownloadHeaders('application/json', true, true)
// a single GET request is used to download a file // a single GET request is used to download a file
const makeDownloadRequest = async (): Promise<IHttpClientResponse> => { const makeDownloadRequest = async (): Promise<HttpClientResponse> => {
const client = this.downloadHttpManager.getClient(httpClientIndex) const client = this.downloadHttpManager.getClient(httpClientIndex)
return await client.get(artifactLocation, headers) return await client.get(artifactLocation, headers)
} }
@@ -225,7 +225,7 @@ export class DownloadHttpClient {
// keep trying to download a file until a retry limit has been reached // keep trying to download a file until a retry limit has been reached
while (retryCount <= retryLimit) { while (retryCount <= retryLimit) {
let response: IHttpClientResponse let response: HttpClientResponse
try { try {
response = await makeDownloadRequest() response = await makeDownloadRequest()
} catch (error) { } catch (error) {
@@ -295,7 +295,7 @@ export class DownloadHttpClient {
* @param isGzip a boolean denoting if the content is compressed using gzip and if we need to decode it * @param isGzip a boolean denoting if the content is compressed using gzip and if we need to decode it
*/ */
async pipeResponseToFile( async pipeResponseToFile(
response: IHttpClientResponse, response: HttpClientResponse,
destinationStream: fs.WriteStream, destinationStream: fs.WriteStream,
isGzip: boolean isGzip: boolean
): Promise<void> { ): Promise<void> {
@@ -1,4 +1,4 @@
import {HttpClient} from '@actions/http-client/index' import {HttpClient} from '@actions/http-client'
import {createHttpClient} from './utils' import {createHttpClient} from './utils'
/** /**
@@ -1,4 +1,4 @@
import {IHttpClientResponse} from '@actions/http-client/interfaces' import {HttpClientResponse} from '@actions/http-client'
import { import {
isRetryableStatusCode, isRetryableStatusCode,
isSuccessStatusCode, isSuccessStatusCode,
@@ -11,11 +11,11 @@ import {getRetryLimit} from './config-variables'
export async function retry( export async function retry(
name: string, name: string,
operation: () => Promise<IHttpClientResponse>, operation: () => Promise<HttpClientResponse>,
customErrorMessages: Map<number, string>, customErrorMessages: Map<number, string>,
maxAttempts: number maxAttempts: number
): Promise<IHttpClientResponse> { ): Promise<HttpClientResponse> {
let response: IHttpClientResponse | undefined = undefined let response: HttpClientResponse | undefined = undefined
let statusCode: number | undefined = undefined let statusCode: number | undefined = undefined
let isRetryable = false let isRetryable = false
let errorMessage = '' let errorMessage = ''
@@ -71,9 +71,9 @@ export async function retry(
export async function retryHttpClientRequest( export async function retryHttpClientRequest(
name: string, name: string,
method: () => Promise<IHttpClientResponse>, method: () => Promise<HttpClientResponse>,
customErrorMessages: Map<number, string> = new Map(), customErrorMessages: Map<number, string> = new Map(),
maxAttempts = getRetryLimit() maxAttempts = getRetryLimit()
): Promise<IHttpClientResponse> { ): Promise<HttpClientResponse> {
return await retry(name, method, customErrorMessages, maxAttempts) return await retry(name, method, customErrorMessages, maxAttempts)
} }
@@ -9,6 +9,7 @@ import {
UploadResults UploadResults
} from './contracts' } from './contracts'
import { import {
digestForStream,
getArtifactUrl, getArtifactUrl,
getContentRange, getContentRange,
getUploadHeaders, getUploadHeaders,
@@ -31,8 +32,7 @@ import {promisify} from 'util'
import {URL} from 'url' import {URL} from 'url'
import {performance} from 'perf_hooks' import {performance} from 'perf_hooks'
import {StatusReporter} from './status-reporter' import {StatusReporter} from './status-reporter'
import {HttpCodes} from '@actions/http-client' import {HttpCodes, HttpClientResponse} from '@actions/http-client'
import {IHttpClientResponse} from '@actions/http-client/interfaces'
import {HttpManager} from './http-manager' import {HttpManager} from './http-manager'
import {UploadSpecification} from './upload-specification' import {UploadSpecification} from './upload-specification'
import {UploadOptions} from './upload-options' import {UploadOptions} from './upload-options'
@@ -406,6 +406,9 @@ export class UploadHttpClient {
isGzip: boolean, isGzip: boolean,
totalFileSize: number totalFileSize: number
): Promise<boolean> { ): Promise<boolean> {
// open a new stream and read it to compute the digest
const digest = await digestForStream(openStream())
// prepare all the necessary headers before making any http call // prepare all the necessary headers before making any http call
const headers = getUploadHeaders( const headers = getUploadHeaders(
'application/octet-stream', 'application/octet-stream',
@@ -413,10 +416,11 @@ export class UploadHttpClient {
isGzip, isGzip,
totalFileSize, totalFileSize,
end - start + 1, end - start + 1,
getContentRange(start, end, uploadFileSize) getContentRange(start, end, uploadFileSize),
digest
) )
const uploadChunkRequest = async (): Promise<IHttpClientResponse> => { const uploadChunkRequest = async (): Promise<HttpClientResponse> => {
const client = this.uploadHttpManager.getClient(httpClientIndex) const client = this.uploadHttpManager.getClient(httpClientIndex)
return await client.sendStream('PUT', resourceUrl, openStream(), headers) return await client.sendStream('PUT', resourceUrl, openStream(), headers)
} }
@@ -427,7 +431,7 @@ export class UploadHttpClient {
// Increments the current retry count and then checks if the retry limit has been reached // Increments the current retry count and then checks if the retry limit has been reached
// If there have been too many retries, fail so the download stops // If there have been too many retries, fail so the download stops
const incrementAndCheckRetryLimit = ( const incrementAndCheckRetryLimit = (
response?: IHttpClientResponse response?: HttpClientResponse
): boolean => { ): boolean => {
retryCount++ retryCount++
if (retryCount > retryLimit) { if (retryCount > retryLimit) {
@@ -464,7 +468,7 @@ export class UploadHttpClient {
// allow for failed chunks to be retried multiple times // allow for failed chunks to be retried multiple times
while (retryCount <= retryLimit) { while (retryCount <= retryLimit) {
let response: IHttpClientResponse let response: HttpClientResponse
try { try {
response = await uploadChunkRequest() response = await uploadChunkRequest()
+43 -11
View File
@@ -1,9 +1,9 @@
import {debug, info, warning} from '@actions/core' import crypto from 'crypto'
import {promises as fs} from 'fs' import {promises as fs} from 'fs'
import {HttpCodes, HttpClient} from '@actions/http-client' import {IncomingHttpHeaders, OutgoingHttpHeaders} from 'http'
import {BearerCredentialHandler} from '@actions/http-client/auth' import {debug, info, warning} from '@actions/core'
import {IHeaders, IHttpClientResponse} from '@actions/http-client/interfaces' import {HttpCodes, HttpClient, HttpClientResponse} from '@actions/http-client'
import {IncomingHttpHeaders} from 'http' import {BearerCredentialHandler} from '@actions/http-client/lib/auth'
import { import {
getRuntimeToken, getRuntimeToken,
getRuntimeUrl, getRuntimeUrl,
@@ -11,6 +11,7 @@ import {
getRetryMultiplier, getRetryMultiplier,
getInitialRetryIntervalInMilliseconds getInitialRetryIntervalInMilliseconds
} from './config-variables' } from './config-variables'
import CRC64 from './crc64'
/** /**
* Returns a retry time in milliseconds that exponentially gets larger * Returns a retry time in milliseconds that exponentially gets larger
@@ -139,8 +140,8 @@ export function getDownloadHeaders(
contentType: string, contentType: string,
isKeepAlive?: boolean, isKeepAlive?: boolean,
acceptGzip?: boolean acceptGzip?: boolean
): IHeaders { ): OutgoingHttpHeaders {
const requestOptions: IHeaders = {} const requestOptions: OutgoingHttpHeaders = {}
if (contentType) { if (contentType) {
requestOptions['Content-Type'] = contentType requestOptions['Content-Type'] = contentType
@@ -180,9 +181,10 @@ export function getUploadHeaders(
isGzip?: boolean, isGzip?: boolean,
uncompressedLength?: number, uncompressedLength?: number,
contentLength?: number, contentLength?: number,
contentRange?: string contentRange?: string,
): IHeaders { digest?: StreamDigest
const requestOptions: IHeaders = {} ): OutgoingHttpHeaders {
const requestOptions: OutgoingHttpHeaders = {}
requestOptions['Accept'] = `application/json;api-version=${getApiVersion()}` requestOptions['Accept'] = `application/json;api-version=${getApiVersion()}`
if (contentType) { if (contentType) {
requestOptions['Content-Type'] = contentType requestOptions['Content-Type'] = contentType
@@ -202,6 +204,10 @@ export function getUploadHeaders(
if (contentRange) { if (contentRange) {
requestOptions['Content-Range'] = contentRange requestOptions['Content-Range'] = contentRange
} }
if (digest) {
requestOptions['x-actions-results-crc64'] = digest.crc64
requestOptions['x-actions-results-md5'] = digest.md5
}
return requestOptions return requestOptions
} }
@@ -227,7 +233,7 @@ export function getArtifactUrl(): string {
* Certain information such as the TLSSocket and the Readable state are not really useful for diagnostic purposes so they can be avoided. * Certain information such as the TLSSocket and the Readable state are not really useful for diagnostic purposes so they can be avoided.
* Other information such as the headers, the response code and message might be useful, so this is displayed. * Other information such as the headers, the response code and message might be useful, so this is displayed.
*/ */
export function displayHttpDiagnostics(response: IHttpClientResponse): void { export function displayHttpDiagnostics(response: HttpClientResponse): void {
info( info(
`##### Begin Diagnostic HTTP information ##### `##### Begin Diagnostic HTTP information #####
Status Code: ${response.message.statusCode} Status Code: ${response.message.statusCode}
@@ -291,3 +297,29 @@ export function getProperRetention(
export async function sleep(milliseconds: number): Promise<void> { export async function sleep(milliseconds: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, milliseconds)) return new Promise(resolve => setTimeout(resolve, milliseconds))
} }
export interface StreamDigest {
crc64: string
md5: string
}
export async function digestForStream(
stream: NodeJS.ReadableStream
): Promise<StreamDigest> {
return new Promise((resolve, reject) => {
const crc64 = new CRC64()
const md5 = crypto.createHash('md5')
stream
.on('data', data => {
crc64.update(data)
md5.update(data)
})
.on('end', () =>
resolve({
crc64: crc64.digest('base64') as string,
md5: md5.digest('base64')
})
)
.on('error', reject)
})
}
+15
View File
@@ -56,3 +56,18 @@
### 2.0.0 ### 2.0.0
- Added support to check if Actions cache service feature is available or not [#1028](https://github.com/actions/toolkit/pull/1028) - Added support to check if Actions cache service feature is available or not [#1028](https://github.com/actions/toolkit/pull/1028)
### 2.0.3
- Update to v2.0.0 of `@actions/http-client`
### 2.0.4
- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
### 2.0.5
- Fix to avoid saving empty cache when no files are available for caching. ([issue](https://github.com/actions/cache/issues/624))
### 2.0.6
- Fix `Tar failed with error: The process '/usr/bin/tar' failed with exit code 1` issue when temp directory where tar is getting created is actually the subdirectory of the path mentioned by the user for caching. ([issue](https://github.com/actions/cache/issues/689))
### 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)
+6 -2
View File
@@ -73,13 +73,17 @@ test('restore with no cache found', async () => {
test('restore with server error should fail', async () => { test('restore with server error should fail', async () => {
const paths = ['node_modules'] const paths = ['node_modules']
const key = 'node-test' const key = 'node-test'
const logWarningMock = jest.spyOn(core, 'warning')
jest.spyOn(cacheHttpClient, 'getCacheEntry').mockImplementation(() => { jest.spyOn(cacheHttpClient, 'getCacheEntry').mockImplementation(() => {
throw new Error('HTTP Error Occurred') throw new Error('HTTP Error Occurred')
}) })
await expect(restoreCache(paths, key)).rejects.toThrowError( const cacheKey = await restoreCache(paths, key)
'HTTP Error Occurred' expect(cacheKey).toBe(undefined)
expect(logWarningMock).toHaveBeenCalledTimes(1)
expect(logWarningMock).toHaveBeenCalledWith(
'Failed to restore: HTTP Error Occurred'
) )
}) })
+46 -15
View File
@@ -5,7 +5,7 @@ import * as cacheHttpClient from '../src/internal/cacheHttpClient'
import * as cacheUtils from '../src/internal/cacheUtils' import * as cacheUtils from '../src/internal/cacheUtils'
import {CacheFilename, CompressionMethod} from '../src/internal/constants' import {CacheFilename, CompressionMethod} from '../src/internal/constants'
import * as tar from '../src/internal/tar' import * as tar from '../src/internal/tar'
import {ITypedResponse} from '@actions/http-client/interfaces' import {TypedResponse} from '@actions/http-client/lib/interfaces'
import { import {
ReserveCacheResponse, ReserveCacheResponse,
ITypedResponseWithError ITypedResponseWithError
@@ -48,6 +48,7 @@ test('save with large cache outputs should fail', async () => {
const cachePaths = [path.resolve(filePath)] const cachePaths = [path.resolve(filePath)]
const createTarMock = jest.spyOn(tar, 'createTar') const createTarMock = jest.spyOn(tar, 'createTar')
const logWarningMock = jest.spyOn(core, 'warning')
const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit
jest jest
@@ -58,8 +59,11 @@ test('save with large cache outputs should fail', async () => {
.spyOn(cacheUtils, 'getCompressionMethod') .spyOn(cacheUtils, 'getCompressionMethod')
.mockReturnValueOnce(Promise.resolve(compression)) .mockReturnValueOnce(Promise.resolve(compression))
await expect(saveCache([filePath], primaryKey)).rejects.toThrowError( const cacheId = await saveCache([filePath], primaryKey)
'Cache size of ~11264 MB (11811160064 B) is over the 10GB limit, not saving cache.' expect(cacheId).toBe(-1)
expect(logWarningMock).toHaveBeenCalledTimes(1)
expect(logWarningMock).toHaveBeenCalledWith(
'Failed to save: Cache size of ~11264 MB (11811160064 B) is over the 10GB limit, not saving cache.'
) )
const archiveFolder = '/foo/bar' const archiveFolder = '/foo/bar'
@@ -79,6 +83,7 @@ test('save with large cache outputs should fail in GHES with error message', asy
const cachePaths = [path.resolve(filePath)] const cachePaths = [path.resolve(filePath)]
const createTarMock = jest.spyOn(tar, 'createTar') const createTarMock = jest.spyOn(tar, 'createTar')
const logWarningMock = jest.spyOn(core, 'warning')
const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit
jest jest
@@ -106,8 +111,11 @@ test('save with large cache outputs should fail in GHES with error message', asy
return response return response
}) })
await expect(saveCache([filePath], primaryKey)).rejects.toThrowError( const cacheId = await saveCache([filePath], primaryKey)
'The cache filesize must be between 0 and 1073741824 bytes' expect(cacheId).toBe(-1)
expect(logWarningMock).toHaveBeenCalledTimes(1)
expect(logWarningMock).toHaveBeenCalledWith(
'Failed to save: The cache filesize must be between 0 and 1073741824 bytes'
) )
const archiveFolder = '/foo/bar' const archiveFolder = '/foo/bar'
@@ -127,6 +135,7 @@ test('save with large cache outputs should fail in GHES without error message',
const cachePaths = [path.resolve(filePath)] const cachePaths = [path.resolve(filePath)]
const createTarMock = jest.spyOn(tar, 'createTar') const createTarMock = jest.spyOn(tar, 'createTar')
const logWarningMock = jest.spyOn(core, 'warning')
const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit const cacheSize = 11 * 1024 * 1024 * 1024 //~11GB, over the 10GB limit
jest jest
@@ -150,8 +159,11 @@ test('save with large cache outputs should fail in GHES without error message',
return response return response
}) })
await expect(saveCache([filePath], primaryKey)).rejects.toThrowError( const cacheId = await saveCache([filePath], primaryKey)
'Cache size of ~11264 MB (11811160064 B) is over the data cap limit, not saving cache.' expect(cacheId).toBe(-1)
expect(logWarningMock).toHaveBeenCalledTimes(1)
expect(logWarningMock).toHaveBeenCalledWith(
'Failed to save: Cache size of ~11264 MB (11811160064 B) is over the data cap limit, not saving cache.'
) )
const archiveFolder = '/foo/bar' const archiveFolder = '/foo/bar'
@@ -168,11 +180,12 @@ test('save with large cache outputs should fail in GHES without error message',
test('save with reserve cache failure should fail', async () => { test('save with reserve cache failure should fail', async () => {
const paths = ['node_modules'] const paths = ['node_modules']
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43' const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
const logInfoMock = jest.spyOn(core, 'info')
const reserveCacheMock = jest const reserveCacheMock = jest
.spyOn(cacheHttpClient, 'reserveCache') .spyOn(cacheHttpClient, 'reserveCache')
.mockImplementation(async () => { .mockImplementation(async () => {
const response: ITypedResponse<ReserveCacheResponse> = { const response: TypedResponse<ReserveCacheResponse> = {
statusCode: 500, statusCode: 500,
result: null, result: null,
headers: {} headers: {}
@@ -187,9 +200,13 @@ test('save with reserve cache failure should fail', async () => {
.spyOn(cacheUtils, 'getCompressionMethod') .spyOn(cacheUtils, 'getCompressionMethod')
.mockReturnValueOnce(Promise.resolve(compression)) .mockReturnValueOnce(Promise.resolve(compression))
await expect(saveCache(paths, primaryKey)).rejects.toThrowError( const cacheId = await saveCache(paths, primaryKey)
`Unable to reserve cache with key ${primaryKey}, another job may be creating this cache.` expect(cacheId).toBe(-1)
expect(logInfoMock).toHaveBeenCalledTimes(1)
expect(logInfoMock).toHaveBeenCalledWith(
`Failed to save: Unable to reserve cache with key ${primaryKey}, another job may be creating this cache. More details: undefined`
) )
expect(reserveCacheMock).toHaveBeenCalledTimes(1) expect(reserveCacheMock).toHaveBeenCalledTimes(1)
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, paths, { expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, paths, {
compressionMethod: compression compressionMethod: compression
@@ -203,12 +220,12 @@ test('save with server error should fail', async () => {
const filePath = 'node_modules' const filePath = 'node_modules'
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43' const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
const cachePaths = [path.resolve(filePath)] const cachePaths = [path.resolve(filePath)]
const logWarningMock = jest.spyOn(core, 'warning')
const cacheId = 4 const cacheId = 4
const reserveCacheMock = jest const reserveCacheMock = jest
.spyOn(cacheHttpClient, 'reserveCache') .spyOn(cacheHttpClient, 'reserveCache')
.mockImplementation(async () => { .mockImplementation(async () => {
const response: ITypedResponse<ReserveCacheResponse> = { const response: TypedResponse<ReserveCacheResponse> = {
statusCode: 500, statusCode: 500,
result: {cacheId}, result: {cacheId},
headers: {} headers: {}
@@ -228,9 +245,12 @@ test('save with server error should fail', async () => {
.spyOn(cacheUtils, 'getCompressionMethod') .spyOn(cacheUtils, 'getCompressionMethod')
.mockReturnValueOnce(Promise.resolve(compression)) .mockReturnValueOnce(Promise.resolve(compression))
await expect(saveCache([filePath], primaryKey)).rejects.toThrowError( await saveCache([filePath], primaryKey)
'HTTP Error Occurred' expect(logWarningMock).toHaveBeenCalledTimes(1)
expect(logWarningMock).toHaveBeenCalledWith(
'Failed to save: HTTP Error Occurred'
) )
expect(reserveCacheMock).toHaveBeenCalledTimes(1) expect(reserveCacheMock).toHaveBeenCalledTimes(1)
expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, [filePath], { expect(reserveCacheMock).toHaveBeenCalledWith(primaryKey, [filePath], {
compressionMethod: compression compressionMethod: compression
@@ -257,7 +277,7 @@ test('save with valid inputs uploads a cache', async () => {
const reserveCacheMock = jest const reserveCacheMock = jest
.spyOn(cacheHttpClient, 'reserveCache') .spyOn(cacheHttpClient, 'reserveCache')
.mockImplementation(async () => { .mockImplementation(async () => {
const response: ITypedResponse<ReserveCacheResponse> = { const response: TypedResponse<ReserveCacheResponse> = {
statusCode: 500, statusCode: 500,
result: {cacheId}, result: {cacheId},
headers: {} headers: {}
@@ -290,3 +310,14 @@ test('save with valid inputs uploads a cache', async () => {
expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile, undefined) expect(saveCacheMock).toHaveBeenCalledWith(cacheId, archiveFile, undefined)
expect(getCompressionMock).toHaveBeenCalledTimes(1) expect(getCompressionMock).toHaveBeenCalledTimes(1)
}) })
test('save with non existing path should not save cache', async () => {
const path = 'node_modules'
const primaryKey = 'Linux-node-bb828da54c148048dd17899ba9fda624811cfb43'
jest.spyOn(cacheUtils, 'resolvePaths').mockImplementation(async () => {
return []
})
await expect(saveCache([path], primaryKey)).rejects.toThrowError(
`Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.`
)
})
+4
View File
@@ -143,6 +143,8 @@ test('zstd create tar', async () => {
'zstd -T0 --long=30', 'zstd -T0 --long=30',
'-cf', '-cf',
IS_WINDOWS ? CacheFilename.Zstd.replace(/\\/g, '/') : CacheFilename.Zstd, IS_WINDOWS ? CacheFilename.Zstd.replace(/\\/g, '/') : CacheFilename.Zstd,
'--exclude',
IS_WINDOWS ? CacheFilename.Zstd.replace(/\\/g, '/') : CacheFilename.Zstd,
'-P', '-P',
'-C', '-C',
IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace, IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace,
@@ -180,6 +182,8 @@ test('gzip create tar', async () => {
'-z', '-z',
'-cf', '-cf',
IS_WINDOWS ? CacheFilename.Gzip.replace(/\\/g, '/') : CacheFilename.Gzip, IS_WINDOWS ? CacheFilename.Gzip.replace(/\\/g, '/') : CacheFilename.Gzip,
'--exclude',
IS_WINDOWS ? CacheFilename.Gzip.replace(/\\/g, '/') : CacheFilename.Gzip,
'-P', '-P',
'-C', '-C',
IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace, IS_WINDOWS ? workspace?.replace(/\\/g, '/') : workspace,
+23 -38
View File
@@ -1,18 +1,18 @@
{ {
"name": "@actions/cache", "name": "@actions/cache",
"version": "2.0.2", "version": "3.0.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@actions/cache", "name": "@actions/cache",
"version": "2.0.0", "version": "3.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.2.6", "@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": "^1.0.9", "@actions/http-client": "^2.0.1",
"@actions/io": "^1.0.1", "@actions/io": "^1.0.1",
"@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",
@@ -31,9 +31,9 @@
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA==" "integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
}, },
"node_modules/@actions/exec": { "node_modules/@actions/exec": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
"integrity": "sha512-4DPChWow9yc9W3WqEbUj8Nr86xkpyE29ZzWjXucHItclLbEW6jr80Zx4nqv18QL6KK65+cifiQZXvnqgTV6oHw==", "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
"dependencies": { "dependencies": {
"@actions/io": "^1.0.1" "@actions/io": "^1.0.1"
} }
@@ -48,25 +48,17 @@
} }
}, },
"node_modules/@actions/http-client": { "node_modules/@actions/http-client": {
"version": "1.0.9", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.9.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-0O4SsJ7q+MK0ycvXPl2e6bMXV7dxAXOGjrXS1eTF9s2S401Tp6c/P3c3Joz04QefC1J6Gt942Wl2jbm3f4mLcg==", "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"dependencies": { "dependencies": {
"tunnel": "0.0.6" "tunnel": "^0.0.6"
}
},
"node_modules/@actions/http-client/node_modules/tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
"engines": {
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
} }
}, },
"node_modules/@actions/io": { "node_modules/@actions/io": {
"version": "1.0.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.2.tgz",
"integrity": "sha512-J8KuFqVPr3p6U8W93DOXlXW6zFvrQAJANdS+vw0YhusLIq+bszW8zmK2Fh1C2kDPX8FMvwIl1OUcFgvJoXLbAg==" "integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw=="
}, },
"node_modules/@azure/abort-controller": { "node_modules/@azure/abort-controller": {
"version": "1.0.4", "version": "1.0.4",
@@ -618,9 +610,9 @@
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA==" "integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
}, },
"@actions/exec": { "@actions/exec": {
"version": "1.0.4", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
"integrity": "sha512-4DPChWow9yc9W3WqEbUj8Nr86xkpyE29ZzWjXucHItclLbEW6jr80Zx4nqv18QL6KK65+cifiQZXvnqgTV6oHw==", "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
"requires": { "requires": {
"@actions/io": "^1.0.1" "@actions/io": "^1.0.1"
} }
@@ -635,24 +627,17 @@
} }
}, },
"@actions/http-client": { "@actions/http-client": {
"version": "1.0.9", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.9.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-0O4SsJ7q+MK0ycvXPl2e6bMXV7dxAXOGjrXS1eTF9s2S401Tp6c/P3c3Joz04QefC1J6Gt942Wl2jbm3f4mLcg==", "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"requires": { "requires": {
"tunnel": "0.0.6" "tunnel": "^0.0.6"
},
"dependencies": {
"tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
}
} }
}, },
"@actions/io": { "@actions/io": {
"version": "1.0.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.2.tgz",
"integrity": "sha512-J8KuFqVPr3p6U8W93DOXlXW6zFvrQAJANdS+vw0YhusLIq+bszW8zmK2Fh1C2kDPX8FMvwIl1OUcFgvJoXLbAg==" "integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw=="
}, },
"@azure/abort-controller": { "@azure/abort-controller": {
"version": "1.0.4", "version": "1.0.4",
+4 -4
View File
@@ -1,6 +1,6 @@
{ {
"name": "@actions/cache", "name": "@actions/cache",
"version": "2.0.2", "version": "3.0.0",
"preview": true, "preview": true,
"description": "Actions cache lib", "description": "Actions cache lib",
"keywords": [ "keywords": [
@@ -40,7 +40,7 @@
"@actions/core": "^1.2.6", "@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": "^1.0.9", "@actions/http-client": "^2.0.1",
"@actions/io": "^1.0.1", "@actions/io": "^1.0.1",
"@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",
@@ -48,8 +48,8 @@
"uuid": "^3.3.3" "uuid": "^3.3.3"
}, },
"devDependencies": { "devDependencies": {
"typescript": "^3.8.3",
"@types/semver": "^6.0.0", "@types/semver": "^6.0.0",
"@types/uuid": "^3.4.5" "@types/uuid": "^3.4.5",
"typescript": "^3.8.3"
} }
} }
+44 -18
View File
@@ -86,23 +86,24 @@ export async function restoreCache(
} }
const compressionMethod = await utils.getCompressionMethod() const compressionMethod = await utils.getCompressionMethod()
let archivePath = ''
// path are needed to compute version
const cacheEntry = await cacheHttpClient.getCacheEntry(keys, paths, {
compressionMethod
})
if (!cacheEntry?.archiveLocation) {
// Cache not found
return undefined
}
const archivePath = path.join(
await utils.createTempDirectory(),
utils.getCacheFileName(compressionMethod)
)
core.debug(`Archive Path: ${archivePath}`)
try { try {
// path are needed to compute version
const cacheEntry = await cacheHttpClient.getCacheEntry(keys, paths, {
compressionMethod
})
if (!cacheEntry?.archiveLocation) {
// Cache not found
return undefined
}
archivePath = path.join(
await utils.createTempDirectory(),
utils.getCacheFileName(compressionMethod)
)
core.debug(`Archive Path: ${archivePath}`)
// Download the cache from the cache entry // Download the cache from the cache entry
await cacheHttpClient.downloadCache( await cacheHttpClient.downloadCache(
cacheEntry.archiveLocation, cacheEntry.archiveLocation,
@@ -123,6 +124,16 @@ export async function restoreCache(
await extractTar(archivePath, compressionMethod) await extractTar(archivePath, compressionMethod)
core.info('Cache restored successfully') core.info('Cache restored successfully')
return cacheEntry.cacheKey
} catch (error) {
const typedError = error as Error
if (typedError.name === ValidationError.name) {
throw error
} else {
// Supress all non-validation cache related errors because caching should be optional
core.warning(`Failed to restore: ${(error as Error).message}`)
}
} finally { } finally {
// Try to delete the archive to save space // Try to delete the archive to save space
try { try {
@@ -132,7 +143,7 @@ export async function restoreCache(
} }
} }
return cacheEntry.cacheKey return undefined
} }
/** /**
@@ -152,12 +163,18 @@ export async function saveCache(
checkKey(key) checkKey(key)
const compressionMethod = await utils.getCompressionMethod() const compressionMethod = await utils.getCompressionMethod()
let cacheId = null let cacheId = -1
const cachePaths = await utils.resolvePaths(paths) const cachePaths = await utils.resolvePaths(paths)
core.debug('Cache Paths:') core.debug('Cache Paths:')
core.debug(`${JSON.stringify(cachePaths)}`) core.debug(`${JSON.stringify(cachePaths)}`)
if (cachePaths.length === 0) {
throw new Error(
`Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.`
)
}
const archiveFolder = await utils.createTempDirectory() const archiveFolder = await utils.createTempDirectory()
const archivePath = path.join( const archivePath = path.join(
archiveFolder, archiveFolder,
@@ -211,6 +228,15 @@ export async function saveCache(
core.debug(`Saving Cache (ID: ${cacheId})`) core.debug(`Saving Cache (ID: ${cacheId})`)
await cacheHttpClient.saveCache(cacheId, archivePath, options) await cacheHttpClient.saveCache(cacheId, archivePath, options)
} catch (error) {
const typedError = error as Error
if (typedError.name === ValidationError.name) {
throw error
} else if (typedError.name === ReserveCacheError.name) {
core.info(`Failed to save: ${typedError.message}`)
} else {
core.warning(`Failed to save: ${typedError.message}`)
}
} finally { } finally {
// Try to delete the archive to save space // Try to delete the archive to save space
try { try {
+8 -5
View File
@@ -1,7 +1,10 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import {HttpClient} from '@actions/http-client' import {HttpClient} from '@actions/http-client'
import {BearerCredentialHandler} from '@actions/http-client/auth' import {BearerCredentialHandler} from '@actions/http-client/lib/auth'
import {IRequestOptions, ITypedResponse} from '@actions/http-client/interfaces' import {
RequestOptions,
TypedResponse
} from '@actions/http-client/lib/interfaces'
import * as crypto from 'crypto' import * as crypto from 'crypto'
import * as fs from 'fs' import * as fs from 'fs'
import {URL} from 'url' import {URL} from 'url'
@@ -46,8 +49,8 @@ function createAcceptHeader(type: string, apiVersion: string): string {
return `${type};api-version=${apiVersion}` return `${type};api-version=${apiVersion}`
} }
function getRequestOptions(): IRequestOptions { function getRequestOptions(): RequestOptions {
const requestOptions: IRequestOptions = { const requestOptions: RequestOptions = {
headers: { headers: {
Accept: createAcceptHeader('application/json', '6.0-preview.1') Accept: createAcceptHeader('application/json', '6.0-preview.1')
} }
@@ -275,7 +278,7 @@ async function commitCache(
httpClient: HttpClient, httpClient: HttpClient,
cacheId: number, cacheId: number,
filesize: number filesize: number
): Promise<ITypedResponse<null>> { ): Promise<TypedResponse<null>> {
const commitCacheRequest: CommitCacheRequest = {size: filesize} const commitCacheRequest: CommitCacheRequest = {size: filesize}
return await retryTypedResponse('commitCache', async () => return await retryTypedResponse('commitCache', async () =>
httpClient.postJson<null>( httpClient.postJson<null>(
+2 -2
View File
@@ -1,8 +1,8 @@
import {CompressionMethod} from './constants' import {CompressionMethod} from './constants'
import {ITypedResponse} from '@actions/http-client/interfaces' import {TypedResponse} from '@actions/http-client/lib/interfaces'
import {HttpClientError} from '@actions/http-client' import {HttpClientError} from '@actions/http-client'
export interface ITypedResponseWithError<T> extends ITypedResponse<T> { export interface ITypedResponseWithError<T> extends TypedResponse<T> {
error?: HttpClientError error?: HttpClientError
} }
+2 -3
View File
@@ -1,6 +1,5 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import {HttpClient} from '@actions/http-client' import {HttpClient, HttpClientResponse} from '@actions/http-client'
import {IHttpClientResponse} from '@actions/http-client/interfaces'
import {BlockBlobClient} from '@azure/storage-blob' import {BlockBlobClient} from '@azure/storage-blob'
import {TransferProgressEvent} from '@azure/ms-rest-js' import {TransferProgressEvent} from '@azure/ms-rest-js'
import * as buffer from 'buffer' import * as buffer from 'buffer'
@@ -20,7 +19,7 @@ import {retryHttpClientResponse} from './requestUtils'
* @param output the writable stream * @param output the writable stream
*/ */
async function pipeResponseToStream( async function pipeResponseToStream(
response: IHttpClientResponse, response: HttpClientResponse,
output: NodeJS.WritableStream output: NodeJS.WritableStream
): Promise<void> { ): Promise<void> {
const pipeline = util.promisify(stream.pipeline) const pipeline = util.promisify(stream.pipeline)
+9 -6
View File
@@ -1,6 +1,9 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import {HttpCodes, HttpClientError} from '@actions/http-client' import {
import {IHttpClientResponse} from '@actions/http-client/interfaces' HttpCodes,
HttpClientError,
HttpClientResponse
} from '@actions/http-client'
import {DefaultRetryDelay, DefaultRetryAttempts} from './constants' import {DefaultRetryDelay, DefaultRetryAttempts} from './constants'
import {ITypedResponseWithError} from './contracts' import {ITypedResponseWithError} from './contracts'
@@ -103,7 +106,7 @@ export async function retryTypedResponse<T>(
maxAttempts, maxAttempts,
delay, delay,
// If the error object contains the statusCode property, extract it and return // If the error object contains the statusCode property, extract it and return
// an ITypedResponse<T> so it can be processed by the retry logic. // an TypedResponse<T> so it can be processed by the retry logic.
(error: Error) => { (error: Error) => {
if (error instanceof HttpClientError) { if (error instanceof HttpClientError) {
return { return {
@@ -121,14 +124,14 @@ export async function retryTypedResponse<T>(
export async function retryHttpClientResponse( export async function retryHttpClientResponse(
name: string, name: string,
method: () => Promise<IHttpClientResponse>, method: () => Promise<HttpClientResponse>,
maxAttempts = DefaultRetryAttempts, maxAttempts = DefaultRetryAttempts,
delay = DefaultRetryDelay delay = DefaultRetryDelay
): Promise<IHttpClientResponse> { ): Promise<HttpClientResponse> {
return await retry( return await retry(
name, name,
method, method,
(response: IHttpClientResponse) => response.message.statusCode, (response: HttpClientResponse) => response.message.statusCode,
maxAttempts, maxAttempts,
delay delay
) )
+10 -9
View File
@@ -61,15 +61,15 @@ export async function extractTar(
// Create directory to extract tar into // Create directory to extract tar into
const workingDirectory = getWorkingDirectory() const workingDirectory = getWorkingDirectory()
await io.mkdirP(workingDirectory) await io.mkdirP(workingDirectory)
// --d: Decompress. // --decompress: Decompress.
// --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit. // --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit.
// Using 30 here because we also support 32-bit self-hosted runners. // Using 30 here because we also support 32-bit self-hosted runners.
function getCompressionProgram(): string[] { function getCompressionProgram(): string[] {
switch (compressionMethod) { switch (compressionMethod) {
case CompressionMethod.Zstd: case CompressionMethod.Zstd:
return ['--use-compress-program', 'zstd -d --long=30'] return ['--use-compress-program', 'zstd --decompress --long=30']
case CompressionMethod.ZstdWithoutLong: case CompressionMethod.ZstdWithoutLong:
return ['--use-compress-program', 'zstd -d'] return ['--use-compress-program', 'zstd --decompress']
default: default:
return ['-z'] return ['-z']
} }
@@ -99,16 +99,16 @@ export async function createTar(
) )
const workingDirectory = getWorkingDirectory() const workingDirectory = getWorkingDirectory()
// -T#: Compress using # working thread. If # is 0, attempt to detect and use the number of physical CPU cores. // --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. // --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit.
// Using 30 here because we also support 32-bit self-hosted runners. // Using 30 here because we also support 32-bit self-hosted runners.
// Long range mode is added to zstd in v1.3.2 release, so we will not use --long in older version of zstd. // Long range mode is added to zstd in v1.3.2 release, so we will not use --long in older version of zstd.
function getCompressionProgram(): string[] { function getCompressionProgram(): string[] {
switch (compressionMethod) { switch (compressionMethod) {
case CompressionMethod.Zstd: case CompressionMethod.Zstd:
return ['--use-compress-program', 'zstd -T0 --long=30'] return ['--use-compress-program', 'zstd --threads=0 --long=30']
case CompressionMethod.ZstdWithoutLong: case CompressionMethod.ZstdWithoutLong:
return ['--use-compress-program', 'zstd -T0'] return ['--use-compress-program', 'zstd --threads=0']
default: default:
return ['-z'] return ['-z']
} }
@@ -118,6 +118,8 @@ export async function createTar(
...getCompressionProgram(), ...getCompressionProgram(),
'-cf', '-cf',
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'--exclude',
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
'-P', '-P',
'-C', '-C',
workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
@@ -131,16 +133,15 @@ export async function listTar(
archivePath: string, archivePath: string,
compressionMethod: CompressionMethod compressionMethod: CompressionMethod
): Promise<void> { ): Promise<void> {
// --d: Decompress.
// --long=#: Enables long distance matching with # bits. // --long=#: Enables long distance matching with # bits.
// Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit. // Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit.
// Using 30 here because we also support 32-bit self-hosted runners. // Using 30 here because we also support 32-bit self-hosted runners.
function getCompressionProgram(): string[] { function getCompressionProgram(): string[] {
switch (compressionMethod) { switch (compressionMethod) {
case CompressionMethod.Zstd: case CompressionMethod.Zstd:
return ['--use-compress-program', 'zstd -d --long=30'] return ['--use-compress-program', 'zstd --long=30']
case CompressionMethod.ZstdWithoutLong: case CompressionMethod.ZstdWithoutLong:
return ['--use-compress-program', 'zstd -d'] return ['--use-compress-program', 'zstd']
default: default:
return ['-z'] return ['-z']
} }
+24 -1
View File
@@ -309,4 +309,27 @@ outputs:
runs: runs:
using: 'node12' using: 'node12'
main: 'dist/index.js' main: 'dist/index.js'
``` ```
#### Filesystem path helpers
You can use these methods to manipulate file paths across operating systems.
The `toPosixPath` function converts input paths to Posix-style (Linux) paths.
The `toWin32Path` function converts input paths to Windows-style paths. These
functions work independently of the underlying runner operating system.
```js
toPosixPath('\\foo\\bar') // => /foo/bar
toWin32Path('/foo/bar') // => \foo\bar
```
The `toPlatformPath` function converts input paths to the expected value on the runner's operating system.
```js
// On a Windows runner.
toPlatformPath('/foo/bar') // => \foo\bar
// On a Linux runner.
toPlatformPath('\\foo\\bar') // => /foo/bar
```
+14
View File
@@ -1,5 +1,19 @@
# @actions/core Releases # @actions/core Releases
### 1.9.0
- Added `toPosixPath`, `toWin32Path` and `toPlatformPath` utilities [#1102](https://github.com/actions/toolkit/pull/1102)
### 1.8.2
- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
### 1.8.1
- Update to v2.0.0 of `@actions/http-client`
### 1.8.0
- Deprecate `markdownSummary` extension export in favor of `summary`
- https://github.com/actions/toolkit/pull/1072
- https://github.com/actions/toolkit/pull/1073
### 1.7.0 ### 1.7.0
- [Added `markdownSummary` extension](https://github.com/actions/toolkit/pull/1014) - [Added `markdownSummary` extension](https://github.com/actions/toolkit/pull/1014)
+162
View File
@@ -0,0 +1,162 @@
import * as path from 'path'
import {toPlatformPath, toPosixPath, toWin32Path} from '../src/path-utils'
describe('#toPosixPath', () => {
const cases: {
only?: boolean
name: string
input: string
expected: string
}[] = [
{
name: 'empty string',
input: '',
expected: ''
},
{
name: 'single value',
input: 'foo',
expected: 'foo'
},
{
name: 'with posix relative',
input: 'foo/bar/baz',
expected: 'foo/bar/baz'
},
{
name: 'with posix absolute',
input: '/foo/bar/baz',
expected: '/foo/bar/baz'
},
{
name: 'with win32 relative',
input: 'foo\\bar\\baz',
expected: 'foo/bar/baz'
},
{
name: 'with win32 absolute',
input: '\\foo\\bar\\baz',
expected: '/foo/bar/baz'
},
{
name: 'with a mix',
input: '\\foo/bar/baz',
expected: '/foo/bar/baz'
}
]
for (const tc of cases) {
const fn = tc.only ? it.only : it
fn(tc.name, () => {
const result = toPosixPath(tc.input)
expect(result).toEqual(tc.expected)
})
}
})
describe('#toWin32Path', () => {
const cases: {
only?: boolean
name: string
input: string
expected: string
}[] = [
{
name: 'empty string',
input: '',
expected: ''
},
{
name: 'single value',
input: 'foo',
expected: 'foo'
},
{
name: 'with posix relative',
input: 'foo/bar/baz',
expected: 'foo\\bar\\baz'
},
{
name: 'with posix absolute',
input: '/foo/bar/baz',
expected: '\\foo\\bar\\baz'
},
{
name: 'with win32 relative',
input: 'foo\\bar\\baz',
expected: 'foo\\bar\\baz'
},
{
name: 'with win32 absolute',
input: '\\foo\\bar\\baz',
expected: '\\foo\\bar\\baz'
},
{
name: 'with a mix',
input: '\\foo/bar\\baz',
expected: '\\foo\\bar\\baz'
}
]
for (const tc of cases) {
const fn = tc.only ? it.only : it
fn(tc.name, () => {
const result = toWin32Path(tc.input)
expect(result).toEqual(tc.expected)
})
}
})
describe('#toPlatformPath', () => {
const cases: {
only?: boolean
name: string
input: string
expected: string
}[] = [
{
name: 'empty string',
input: '',
expected: ''
},
{
name: 'single value',
input: 'foo',
expected: 'foo'
},
{
name: 'with posix relative',
input: 'foo/bar/baz',
expected: path.join('foo', 'bar', 'baz')
},
{
name: 'with posix absolute',
input: '/foo/bar/baz',
expected: path.join(path.sep, 'foo', 'bar', 'baz')
},
{
name: 'with win32 relative',
input: 'foo\\bar\\baz',
expected: path.join('foo', 'bar', 'baz')
},
{
name: 'with win32 absolute',
input: '\\foo\\bar\\baz',
expected: path.join(path.sep, 'foo', 'bar', 'baz')
},
{
name: 'with a mix',
input: '\\foo/bar\\baz',
expected: path.join(path.sep, 'foo', 'bar', 'baz')
}
]
for (const tc of cases) {
const fn = tc.only ? it.only : it
fn(tc.name, () => {
const result = toPlatformPath(tc.input)
expect(result).toEqual(tc.expected)
})
}
})
+11 -11
View File
@@ -1,26 +1,26 @@
{ {
"name": "@actions/core", "name": "@actions/core",
"version": "1.7.0", "version": "1.9.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@actions/core", "name": "@actions/core",
"version": "1.6.0", "version": "1.8.1",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/http-client": "^1.0.11" "@actions/http-client": "^2.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^12.0.2" "@types/node": "^12.0.2"
} }
}, },
"node_modules/@actions/http-client": { "node_modules/@actions/http-client": {
"version": "1.0.11", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"dependencies": { "dependencies": {
"tunnel": "0.0.6" "tunnel": "^0.0.6"
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
@@ -40,11 +40,11 @@
}, },
"dependencies": { "dependencies": {
"@actions/http-client": { "@actions/http-client": {
"version": "1.0.11", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"requires": { "requires": {
"tunnel": "0.0.6" "tunnel": "^0.0.6"
} }
}, },
"@types/node": { "@types/node": {
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@actions/core", "name": "@actions/core",
"version": "1.7.0", "version": "1.9.0",
"description": "Actions core lib", "description": "Actions core lib",
"keywords": [ "keywords": [
"github", "github",
@@ -36,7 +36,7 @@
"url": "https://github.com/actions/toolkit/issues" "url": "https://github.com/actions/toolkit/issues"
}, },
"dependencies": { "dependencies": {
"@actions/http-client": "^1.0.11" "@actions/http-client": "^2.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^12.0.2" "@types/node": "^12.0.2"
+5
View File
@@ -369,3 +369,8 @@ export {summary} from './summary'
* @deprecated use core.summary * @deprecated use core.summary
*/ */
export {markdownSummary} from './summary' export {markdownSummary} from './summary'
/**
* Path exports
*/
export {toPosixPath, toWin32Path, toPlatformPath} from './path-utils'
+3 -3
View File
@@ -1,8 +1,8 @@
/* eslint-disable @typescript-eslint/no-extraneous-class */ /* eslint-disable @typescript-eslint/no-extraneous-class */
import * as actions_http_client from '@actions/http-client' import * as actions_http_client from '@actions/http-client'
import {IRequestOptions} from '@actions/http-client/interfaces' import {RequestOptions} from '@actions/http-client/lib/interfaces'
import {HttpClient} from '@actions/http-client' import {HttpClient} from '@actions/http-client'
import {BearerCredentialHandler} from '@actions/http-client/auth' import {BearerCredentialHandler} from '@actions/http-client/lib/auth'
import {debug, setSecret} from './core' import {debug, setSecret} from './core'
interface TokenResponse { interface TokenResponse {
value?: string value?: string
@@ -13,7 +13,7 @@ export class OidcClient {
allowRetry = true, allowRetry = true,
maxRetry = 10 maxRetry = 10
): actions_http_client.HttpClient { ): actions_http_client.HttpClient {
const requestOptions: IRequestOptions = { const requestOptions: RequestOptions = {
allowRetries: allowRetry, allowRetries: allowRetry,
maxRetries: maxRetry maxRetries: maxRetry
} }
+35
View File
@@ -0,0 +1,35 @@
import * as path from 'path'
/**
* toPosixPath converts the given path to the posix form. On Windows, \\ will be
* replaced with /.
*
* @param pth. Path to transform.
* @return string Posix path.
*/
export function toPosixPath(pth: string): string {
return pth.replace(/[\\]/g, '/')
}
/**
* toWin32Path converts the given path to the win32 form. On Linux, / will be
* replaced with \\.
*
* @param pth. Path to transform.
* @return string Win32 path.
*/
export function toWin32Path(pth: string): string {
return pth.replace(/[/]/g, '\\')
}
/**
* toPlatformPath converts the given path to a platform-specific path. It does
* this by replacing instances of / and \ with the platform-specific path
* separator.
*
* @param pth The path to platformize.
* @return string The platform-specific path.
*/
export function toPlatformPath(pth: string): string {
return pth.replace(/[/\\]/g, path.sep)
}
+6
View File
@@ -1,5 +1,11 @@
# @actions/github Releases # @actions/github Releases
### 5.0.3
- - Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
### 5.0.2
- Update to v2.0.0 of `@actions/http-client`
### 5.0.1 ### 5.0.1
- [Update Octokit Dependencies](https://github.com/actions/toolkit/pull/1037) - [Update Octokit Dependencies](https://github.com/actions/toolkit/pull/1037)
### 5.0.0 ### 5.0.0
+11 -11
View File
@@ -1,15 +1,15 @@
{ {
"name": "@actions/github", "name": "@actions/github",
"version": "5.0.1", "version": "5.0.3",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@actions/github", "name": "@actions/github",
"version": "5.0.1", "version": "5.0.2",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/http-client": "^1.0.11", "@actions/http-client": "^2.0.1",
"@octokit/core": "^3.6.0", "@octokit/core": "^3.6.0",
"@octokit/plugin-paginate-rest": "^2.17.0", "@octokit/plugin-paginate-rest": "^2.17.0",
"@octokit/plugin-rest-endpoint-methods": "^5.13.0" "@octokit/plugin-rest-endpoint-methods": "^5.13.0"
@@ -19,11 +19,11 @@
} }
}, },
"node_modules/@actions/http-client": { "node_modules/@actions/http-client": {
"version": "1.0.11", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"dependencies": { "dependencies": {
"tunnel": "0.0.6" "tunnel": "^0.0.6"
} }
}, },
"node_modules/@octokit/auth-token": { "node_modules/@octokit/auth-token": {
@@ -361,11 +361,11 @@
}, },
"dependencies": { "dependencies": {
"@actions/http-client": { "@actions/http-client": {
"version": "1.0.11", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"requires": { "requires": {
"tunnel": "0.0.6" "tunnel": "^0.0.6"
} }
}, },
"@octokit/auth-token": { "@octokit/auth-token": {
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@actions/github", "name": "@actions/github",
"version": "5.0.1", "version": "5.0.3",
"description": "Actions github lib", "description": "Actions github lib",
"keywords": [ "keywords": [
"github", "github",
@@ -38,7 +38,7 @@
"url": "https://github.com/actions/toolkit/issues" "url": "https://github.com/actions/toolkit/issues"
}, },
"dependencies": { "dependencies": {
"@actions/http-client": "^1.0.11", "@actions/http-client": "^2.0.1",
"@octokit/core": "^3.6.0", "@octokit/core": "^3.6.0",
"@octokit/plugin-paginate-rest": "^2.17.0", "@octokit/plugin-paginate-rest": "^2.17.0",
"@octokit/plugin-rest-endpoint-methods": "^5.13.0" "@octokit/plugin-rest-endpoint-methods": "^5.13.0"
+42 -7
View File
@@ -6,7 +6,7 @@
"packages": { "packages": {
"": { "": {
"name": "@actions/glob", "name": "@actions/glob",
"version": "0.2.1", "version": "0.3.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.2.6", "@actions/core": "^1.2.6",
@@ -14,9 +14,20 @@
} }
}, },
"node_modules/@actions/core": { "node_modules/@actions/core": {
"version": "1.2.6", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz",
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA==" "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==",
"dependencies": {
"@actions/http-client": "^1.0.11"
}
},
"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/balanced-match": { "node_modules/balanced-match": {
"version": "1.0.0", "version": "1.0.0",
@@ -47,13 +58,32 @@
"engines": { "engines": {
"node": "*" "node": "*"
} }
},
"node_modules/tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
"engines": {
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
}
} }
}, },
"dependencies": { "dependencies": {
"@actions/core": { "@actions/core": {
"version": "1.2.6", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz",
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA==" "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==",
"requires": {
"@actions/http-client": "^1.0.11"
}
},
"@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"
}
}, },
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
@@ -81,6 +111,11 @@
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
},
"tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
} }
} }
} }
+3
View File
@@ -1,5 +1,8 @@
## Releases ## Releases
## 2.0.1
- Fix an issue with missing `tunnel` dependency [#1085](https://github.com/actions/toolkit/pull/1085)
## 2.0.0 ## 2.0.0
- The package is now compiled with TypeScript's [`strict` compiler setting](https://www.typescriptlang.org/tsconfig#strict). To comply with stricter rules: - The package is now compiled with TypeScript's [`strict` compiler setting](https://www.typescriptlang.org/tsconfig#strict). To comply with stricter rules:
- Some exported types now include `| null` or `| undefined`, matching their actual behavior. - Some exported types now include `| null` or `| undefined`, matching their actual behavior.
+6 -6
View File
@@ -1,6 +1,6 @@
{ {
"name": "@actions/http-client", "name": "@actions/http-client",
"version": "2.0.0", "version": "2.0.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
@@ -8,10 +8,12 @@
"name": "@actions/http-client", "name": "@actions/http-client",
"version": "2.0.0", "version": "2.0.0",
"license": "MIT", "license": "MIT",
"dependencies": {
"tunnel": "^0.0.6"
},
"devDependencies": { "devDependencies": {
"@types/tunnel": "0.0.3", "@types/tunnel": "0.0.3",
"proxy": "^1.0.1", "proxy": "^1.0.1"
"tunnel": "0.0.6"
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
@@ -182,7 +184,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==",
"dev": true,
"engines": { "engines": {
"node": ">=0.6.11 <=0.7.0 || >=0.7.3" "node": ">=0.6.11 <=0.7.0 || >=0.7.3"
} }
@@ -325,8 +326,7 @@
"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=="
"dev": true
} }
} }
} }
+6 -4
View File
@@ -1,6 +1,6 @@
{ {
"name": "@actions/http-client", "name": "@actions/http-client",
"version": "2.0.0", "version": "2.0.1",
"description": "Actions Http Client", "description": "Actions Http Client",
"keywords": [ "keywords": [
"github", "github",
@@ -25,7 +25,7 @@
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/actions/toolkit.git", "url": "git+https://github.com/actions/toolkit.git",
"directory": "packages/github" "directory": "packages/http-client"
}, },
"scripts": { "scripts": {
"audit-moderate": "npm install && npm audit --json --audit-level=moderate > audit.json", "audit-moderate": "npm install && npm audit --json --audit-level=moderate > audit.json",
@@ -40,7 +40,9 @@
}, },
"devDependencies": { "devDependencies": {
"@types/tunnel": "0.0.3", "@types/tunnel": "0.0.3",
"proxy": "^1.0.1", "proxy": "^1.0.1"
"tunnel": "0.0.6" },
"dependencies": {
"tunnel": "^0.0.6"
} }
} }
+8
View File
@@ -1,5 +1,13 @@
# @actions/tool-cache Releases # @actions/tool-cache Releases
### 2.0.1
- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087)
### 2.0.0
- Update to v2.0.0 of `@actions/http-client`
- The type of the `headers` parameter in the exported function `downloadTool` has been narrowed from `{ [header: string]: any }` to `{ [header: string]: number | string | string[] | undefined; }` (that is, `http.OutgoingHttpHeaders`).
This is strictly a compile-time change for TypeScript consumers. Previous attempts to use a header value of a type other than those now accepted would have resulted in an error at run time.
### 1.7.2 ### 1.7.2
- Update `lockfileVersion` to `v2` in `package-lock.json [#1025](https://github.com/actions/toolkit/pull/1025) - Update `lockfileVersion` to `v2` in `package-lock.json [#1025](https://github.com/actions/toolkit/pull/1025)
+53 -29
View File
@@ -1,17 +1,17 @@
{ {
"name": "@actions/tool-cache", "name": "@actions/tool-cache",
"version": "1.7.2", "version": "2.0.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@actions/tool-cache", "name": "@actions/tool-cache",
"version": "1.7.2", "version": "2.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.2.6", "@actions/core": "^1.2.6",
"@actions/exec": "^1.0.0", "@actions/exec": "^1.0.0",
"@actions/http-client": "^1.0.8", "@actions/http-client": "^2.0.1",
"@actions/io": "^1.1.1", "@actions/io": "^1.1.1",
"semver": "^6.1.0", "semver": "^6.1.0",
"uuid": "^3.3.2" "uuid": "^3.3.2"
@@ -24,30 +24,41 @@
} }
}, },
"node_modules/@actions/core": { "node_modules/@actions/core": {
"version": "1.2.6", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz",
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA==" "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==",
"dependencies": {
"@actions/http-client": "^1.0.11"
}
},
"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/exec": { "node_modules/@actions/exec": {
"version": "1.0.3", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.3.tgz", "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
"integrity": "sha512-TogJGnueOmM7ntCi0ASTUj4LapRRtDfj57Ja4IhPmg2fls28uVOPbAn8N+JifaOumN2UG3oEO/Ixek2A4NcYSA==", "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
"dependencies": { "dependencies": {
"@actions/io": "^1.0.1" "@actions/io": "^1.0.1"
} }
}, },
"node_modules/@actions/http-client": { "node_modules/@actions/http-client": {
"version": "1.0.8", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.8.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-G4JjJ6f9Hb3Zvejj+ewLLKLf99ZC+9v+yCxoYf9vSyH+WkzPLB2LuUtRMGNkooMqdugGBFStIKXOuvH1W+EctA==", "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"dependencies": { "dependencies": {
"tunnel": "0.0.6" "tunnel": "^0.0.6"
} }
}, },
"node_modules/@actions/io": { "node_modules/@actions/io": {
"version": "1.1.1", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.1.tgz", "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.2.tgz",
"integrity": "sha512-Qi4JoKXjmE0O67wAOH6y0n26QXhMKMFo7GD/4IXNVcrtLjUlGjGuVys6pQgwF3ArfGTQu0XpqaNr0YhED2RaRA==" "integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw=="
}, },
"node_modules/@types/nock": { "node_modules/@types/nock": {
"version": "10.0.3", "version": "10.0.3",
@@ -280,30 +291,43 @@
}, },
"dependencies": { "dependencies": {
"@actions/core": { "@actions/core": {
"version": "1.2.6", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz",
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA==" "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==",
"requires": {
"@actions/http-client": "^1.0.11"
},
"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/exec": { "@actions/exec": {
"version": "1.0.3", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.3.tgz", "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
"integrity": "sha512-TogJGnueOmM7ntCi0ASTUj4LapRRtDfj57Ja4IhPmg2fls28uVOPbAn8N+JifaOumN2UG3oEO/Ixek2A4NcYSA==", "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
"requires": { "requires": {
"@actions/io": "^1.0.1" "@actions/io": "^1.0.1"
} }
}, },
"@actions/http-client": { "@actions/http-client": {
"version": "1.0.8", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.8.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-G4JjJ6f9Hb3Zvejj+ewLLKLf99ZC+9v+yCxoYf9vSyH+WkzPLB2LuUtRMGNkooMqdugGBFStIKXOuvH1W+EctA==", "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"requires": { "requires": {
"tunnel": "0.0.6" "tunnel": "^0.0.6"
} }
}, },
"@actions/io": { "@actions/io": {
"version": "1.1.1", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.1.tgz", "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.2.tgz",
"integrity": "sha512-Qi4JoKXjmE0O67wAOH6y0n26QXhMKMFo7GD/4IXNVcrtLjUlGjGuVys6pQgwF3ArfGTQu0XpqaNr0YhED2RaRA==" "integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw=="
}, },
"@types/nock": { "@types/nock": {
"version": "10.0.3", "version": "10.0.3",
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@actions/tool-cache", "name": "@actions/tool-cache",
"version": "1.7.2", "version": "2.0.1",
"description": "Actions tool-cache lib", "description": "Actions tool-cache lib",
"keywords": [ "keywords": [
"github", "github",
@@ -38,7 +38,7 @@
"dependencies": { "dependencies": {
"@actions/core": "^1.2.6", "@actions/core": "^1.2.6",
"@actions/exec": "^1.0.0", "@actions/exec": "^1.0.0",
"@actions/http-client": "^1.0.8", "@actions/http-client": "^2.0.1",
"@actions/io": "^1.1.1", "@actions/io": "^1.1.1",
"semver": "^6.1.0", "semver": "^6.1.0",
"uuid": "^3.3.2" "uuid": "^3.3.2"
+5 -5
View File
@@ -8,12 +8,12 @@ import * as httpm from '@actions/http-client'
import * as semver from 'semver' import * as semver from 'semver'
import * as stream from 'stream' import * as stream from 'stream'
import * as util from 'util' import * as util from 'util'
import {ok} from 'assert'
import {OutgoingHttpHeaders} from 'http'
import uuidV4 from 'uuid/v4' import uuidV4 from 'uuid/v4'
import {exec} from '@actions/exec/lib/exec' import {exec} from '@actions/exec/lib/exec'
import {ExecOptions} from '@actions/exec/lib/interfaces' import {ExecOptions} from '@actions/exec/lib/interfaces'
import {ok} from 'assert'
import {RetryHelper} from './retry-helper' import {RetryHelper} from './retry-helper'
import {IHeaders} from '@actions/http-client/interfaces'
export class HTTPError extends Error { export class HTTPError extends Error {
constructor(readonly httpStatusCode: number | undefined) { constructor(readonly httpStatusCode: number | undefined) {
@@ -39,7 +39,7 @@ export async function downloadTool(
url: string, url: string,
dest?: string, dest?: string,
auth?: string, auth?: string,
headers?: IHeaders headers?: OutgoingHttpHeaders
): Promise<string> { ): Promise<string> {
dest = dest || path.join(_getTempDirectory(), uuidV4()) dest = dest || path.join(_getTempDirectory(), uuidV4())
await io.mkdirP(path.dirname(dest)) await io.mkdirP(path.dirname(dest))
@@ -82,7 +82,7 @@ async function downloadToolAttempt(
url: string, url: string,
dest: string, dest: string,
auth?: string, auth?: string,
headers?: IHeaders headers?: OutgoingHttpHeaders
): Promise<string> { ): Promise<string> {
if (fs.existsSync(dest)) { if (fs.existsSync(dest)) {
throw new Error(`Destination file path ${dest} already exists`) throw new Error(`Destination file path ${dest} already exists`)
@@ -596,7 +596,7 @@ export async function getManifestFromRepo(
const treeUrl = `https://api.github.com/repos/${owner}/${repo}/git/trees/${branch}` const treeUrl = `https://api.github.com/repos/${owner}/${repo}/git/trees/${branch}`
const http: httpm.HttpClient = new httpm.HttpClient('tool-cache') const http: httpm.HttpClient = new httpm.HttpClient('tool-cache')
const headers: IHeaders = {} const headers: OutgoingHttpHeaders = {}
if (auth) { if (auth) {
core.debug('set auth') core.debug('set auth')
headers.authorization = auth headers.authorization = auth