Compare commits
137 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f152b798e | |||
| c390199be6 | |||
| a3053b5cc2 | |||
| b9872153b8 | |||
| ce9eae0785 | |||
| d3c5f358d1 | |||
| 75a3586061 | |||
| 8ac8bf1d3d | |||
| 141b3509e4 | |||
| 790e6f7194 | |||
| ef454f0991 | |||
| 86ce0b159a | |||
| c11a7cdeac | |||
| c94ca49c9c | |||
| fa7657714a | |||
| c1f9d37323 | |||
| 8f1c589e25 | |||
| 281697ecbe | |||
| a59f976dd4 | |||
| 57db7a6302 | |||
| 4789a46578 | |||
| 32549e8197 | |||
| 22b7aeb707 | |||
| e9d6649a14 | |||
| 695bf98f84 | |||
| 0787a93181 | |||
| faa425440f | |||
| 0407266511 | |||
| a920781ca9 | |||
| 9e7201ff5b | |||
| 3a610e848c | |||
| 606ebdcf6d | |||
| 7b01731091 | |||
| 20f826bfe7 | |||
| fe3e7ce9a7 | |||
| 8cd02dfabc | |||
| 82474125c8 | |||
| 494f12bcd9 | |||
| 797f48fcfa | |||
| c8d1588732 | |||
| 13e0ce9cf7 | |||
| eae1b66cb0 | |||
| 129f884271 | |||
| 0faced6a0b | |||
| 0d63834474 | |||
| 8f032d304a | |||
| 28b09e224f | |||
| 111c95866e | |||
| ddc9c52eb6 | |||
| 6d37c6eb2b | |||
| 6477ef1460 | |||
| 2e5b10e3bd | |||
| 8c1e6a00f0 | |||
| b2d5fa216f | |||
| c5c786523e | |||
| 63c648f3c2 | |||
| ce31408ff5 | |||
| e26febd988 | |||
| b051b4bada | |||
| a08d666c78 | |||
| 83bb7cdeef | |||
| b552972717 | |||
| e3b0601228 | |||
| 0956e634df | |||
| c171cf52fb | |||
| 2f1b34f165 | |||
| b61854c5ca | |||
| 3d652d3133 | |||
| c3df0928e2 | |||
| 9d756b2bc9 | |||
| 67c3b7a45c | |||
| 3963c722d8 | |||
| 3b44a4cc23 | |||
| 03a876f0a7 | |||
| 62f943c0cc | |||
| 291200d54f | |||
| 06e751600e | |||
| 4b6a4d80e1 | |||
| b2da9aa12c | |||
| 88f749f686 | |||
| b4f8e602b2 | |||
| ced07aa89c | |||
| 6adf053d36 | |||
| 671bf1ebd5 | |||
| dd26bb1149 | |||
| 81a802e7e0 | |||
| 4214a1ff24 | |||
| 0555a5f458 | |||
| 3aaff6685b | |||
| 9b383229c1 | |||
| 7b617c260d | |||
| 20afb1a9fc | |||
| c9dab8c79d | |||
| 45c49b09df | |||
| ab78839e86 | |||
| f03b6d639f | |||
| 58858b5078 | |||
| 188abfc20b | |||
| 2f42c127c7 | |||
| 4dda3ab8a0 | |||
| 4b219f79f3 | |||
| 08d6314f7c | |||
| b851b70474 | |||
| e8fb71c4bb | |||
| 73ad88882e | |||
| 92695f58da | |||
| 760f3fd3d1 | |||
| c6117995d3 | |||
| 24da3e2d1c | |||
| deda97d5e6 | |||
| cfad1451e9 | |||
| c0684c5add | |||
| ad9b955fe9 | |||
| 1718e0d97c | |||
| e85cd96d85 | |||
| bc24adbfd6 | |||
| af1621025d | |||
| 6552cb9722 | |||
| f74ff155bd | |||
| a66e49ec8a | |||
| d4c2fa4c68 | |||
| 8c9ab93da7 | |||
| 3773ef22b1 | |||
| 80e4680ac8 | |||
| c608703ecf | |||
| 66ac937f2f | |||
| efcab31d38 | |||
| 4c6d88f93a | |||
| 19e0016878 | |||
| 2820b17d9d | |||
| 8a5343d54a | |||
| 3ebee1e8b4 | |||
| 7da3ac6eda | |||
| 2461056696 | |||
| 3749c51d21 | |||
| 769c896931 | |||
| c4f5ce2665 |
+2
-1
@@ -1,4 +1,5 @@
|
||||
node_modules/
|
||||
packages/*/node_modules/
|
||||
packages/*/lib/
|
||||
packages/glob/__tests__/_temp
|
||||
packages/glob/__tests__/_temp
|
||||
packages/*/src/generated/*/
|
||||
|
||||
+45
-8
@@ -1,6 +1,13 @@
|
||||
{
|
||||
"plugins": ["jest", "@typescript-eslint"],
|
||||
"extends": ["plugin:github/recommended"],
|
||||
"plugins": [
|
||||
"jest",
|
||||
"@typescript-eslint",
|
||||
"prettier"
|
||||
],
|
||||
"extends": [
|
||||
"plugin:github/recommended",
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 9,
|
||||
@@ -8,14 +15,33 @@
|
||||
"project": "./tsconfig.eslint.json"
|
||||
},
|
||||
"rules": {
|
||||
"prettier/prettier": [
|
||||
"error",
|
||||
{
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
],
|
||||
"eslint-comments/no-use": "off",
|
||||
"no-constant-condition": ["error", { "checkLoops": false }],
|
||||
"github/no-then": "off",
|
||||
"import/no-namespace": "off",
|
||||
"no-shadow": "off",
|
||||
"no-unused-vars": "off",
|
||||
"i18n-text/no-en": "off",
|
||||
"filenames/match-regex": "off",
|
||||
"import/no-commonjs": "off",
|
||||
"import/named": "off",
|
||||
"no-sequences": "off",
|
||||
"import/no-unresolved": "off",
|
||||
"no-undef": "off",
|
||||
"no-only-tests/no-only-tests": "off",
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
|
||||
"@typescript-eslint/explicit-member-accessibility": [
|
||||
"error",
|
||||
{
|
||||
"accessibility": "no-public"
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/no-require-imports": "error",
|
||||
"@typescript-eslint/array-type": "error",
|
||||
"@typescript-eslint/await-thenable": "error",
|
||||
@@ -23,8 +49,16 @@
|
||||
"camelcase": "off",
|
||||
"@typescript-eslint/camelcase": "off",
|
||||
"@typescript-eslint/consistent-type-assertions": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
|
||||
"@typescript-eslint/func-call-spacing": ["error", "never"],
|
||||
"@typescript-eslint/explicit-function-return-type": [
|
||||
"error",
|
||||
{
|
||||
"allowExpressions": true
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/func-call-spacing": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"@typescript-eslint/naming-convention": [
|
||||
"error",
|
||||
{
|
||||
@@ -56,15 +90,18 @@
|
||||
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
||||
"@typescript-eslint/promise-function-async": "error",
|
||||
"@typescript-eslint/require-array-sort-compare": "error",
|
||||
"@typescript-eslint/restrict-plus-operands": "error",
|
||||
"semi": "off",
|
||||
"@typescript-eslint/semi": ["error", "never"],
|
||||
"@typescript-eslint/semi": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"@typescript-eslint/type-annotation-spacing": "error",
|
||||
"@typescript-eslint/unbound-method": "error"
|
||||
},
|
||||
"ignorePatterns": "packages/glob/__tests__/_temp/**/",
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true,
|
||||
"jest/globals": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ Note that before a PR will be accepted, you must ensure:
|
||||
|
||||
### Useful Scripts
|
||||
|
||||
- `npm run bootstrap` This runs `lerna bootstrap` which will install dependencies in this repository's packages and cross-link packages where necessary.
|
||||
- `npm run bootstrap` This runs `lerna exec -- npm install` which will install dependencies in this repository's packages and cross-link packages where necessary.
|
||||
- `npm run build` This compiles TypeScript code in each package (this is especially important if one package relies on changes in another when you're running tests). This is just an alias for `lerna run tsc`.
|
||||
- `npm run format` This checks that formatting has been applied with Prettier.
|
||||
- `npm test` This runs all Jest tests in all packages in this repository.
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Temporarily disabled while v2.0.0 of @actions/artifact is under development
|
||||
|
||||
name: artifact-unit-tests
|
||||
on:
|
||||
push:
|
||||
@@ -22,17 +24,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set Node.js 16.x
|
||||
uses: actions/setup-node@v3
|
||||
- name: Set Node.js 20.x
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 16.x
|
||||
|
||||
# In order to upload & download artifacts from a shell script, certain env variables need to be set that are only available in the
|
||||
# node context. This runs a local action that gets and sets the necessary env variables that are needed
|
||||
- name: Set env variables
|
||||
uses: ./packages/artifact/__tests__/ci-test-action/
|
||||
node-version: 20.x
|
||||
|
||||
# Need root node_modules because certain npm packages like jest are configured for the entire repository and it won't be possible
|
||||
# without these to just compile the artifacts package
|
||||
@@ -48,48 +45,86 @@ jobs:
|
||||
- name: Set artifact file contents
|
||||
shell: bash
|
||||
run: |
|
||||
echo "non-gzip-artifact-content=hello" >> $GITHUB_ENV
|
||||
echo "gzip-artifact-content=Some large amount of text that has a compression ratio that is greater than 100%. If greater than 100%, gzip is used to upload the file" >> $GITHUB_ENV
|
||||
echo "empty-artifact-content=_EMPTY_" >> $GITHUB_ENV
|
||||
echo "file1=hello from file 1" >> $GITHUB_ENV
|
||||
echo "file2=hello from file 2" >> $GITHUB_ENV
|
||||
|
||||
- name: Create files that will be uploaded
|
||||
run: |
|
||||
mkdir artifact-path
|
||||
echo '${{ env.non-gzip-artifact-content }}' > artifact-path/world.txt
|
||||
echo '${{ env.gzip-artifact-content }}' > artifact-path/gzip.txt
|
||||
touch artifact-path/empty.txt
|
||||
echo '${{ env.file1 }}' > artifact-path/first.txt
|
||||
echo '${{ env.file2 }}' > artifact-path/second.txt
|
||||
|
||||
# We're using node -e to call the functions directly available in the @actions/artifact package
|
||||
- name: Upload artifacts using uploadArtifact()
|
||||
run: |
|
||||
node -e "Promise.resolve(require('./packages/artifact/lib/artifact-client').create().uploadArtifact('my-artifact-1',['artifact-path/world.txt'], process.argv[1]))" "${{ github.workspace }}"
|
||||
node -e "Promise.resolve(require('./packages/artifact/lib/artifact-client').create().uploadArtifact('my-artifact-2',['artifact-path/gzip.txt'], process.argv[1]))" "${{ github.workspace }}"
|
||||
node -e "Promise.resolve(require('./packages/artifact/lib/artifact-client').create().uploadArtifact('my-artifact-3',['artifact-path/empty.txt'], process.argv[1]))" "${{ github.workspace }}"
|
||||
- name: Upload Artifacts using actions/github-script@v7
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const artifact = require('./packages/artifact/lib/artifact')
|
||||
|
||||
- name: Download artifacts using downloadArtifact()
|
||||
run: |
|
||||
mkdir artifact-1-directory
|
||||
node -e "Promise.resolve(require('./packages/artifact/lib/artifact-client').create().downloadArtifact('my-artifact-1','artifact-1-directory'))"
|
||||
mkdir artifact-2-directory
|
||||
node -e "Promise.resolve(require('./packages/artifact/lib/artifact-client').create().downloadArtifact('my-artifact-2','artifact-2-directory'))"
|
||||
mkdir artifact-3-directory
|
||||
node -e "Promise.resolve(require('./packages/artifact/lib/artifact-client').create().downloadArtifact('my-artifact-3','artifact-3-directory'))"
|
||||
const artifactName = 'my-artifact-${{ matrix.runs-on }}'
|
||||
console.log('artifactName: ' + artifactName)
|
||||
|
||||
- name: Verify downloadArtifact()
|
||||
shell: bash
|
||||
run: |
|
||||
packages/artifact/__tests__/test-artifact-file.sh "artifact-1-directory/artifact-path/world.txt" "${{ env.non-gzip-artifact-content }}"
|
||||
packages/artifact/__tests__/test-artifact-file.sh "artifact-2-directory/artifact-path/gzip.txt" "${{ env.gzip-artifact-content }}"
|
||||
packages/artifact/__tests__/test-artifact-file.sh "artifact-3-directory/artifact-path/empty.txt" "${{ env.empty-artifact-content }}"
|
||||
const fileContents = ['artifact-path/first.txt','artifact-path/second.txt']
|
||||
|
||||
- name: Download artifacts using downloadAllArtifacts()
|
||||
run: |
|
||||
mkdir multi-artifact-directory
|
||||
node -e "Promise.resolve(require('./packages/artifact/lib/artifact-client').create().downloadAllArtifacts('multi-artifact-directory'))"
|
||||
const uploadResult = await artifact.create().uploadArtifact(artifactName, fileContents, './')
|
||||
console.log(uploadResult)
|
||||
|
||||
- name: Verify downloadAllArtifacts()
|
||||
shell: bash
|
||||
const size = uploadResult.size
|
||||
const id = uploadResult.id
|
||||
|
||||
console.log(`Successfully uploaded artifact ${id}`)
|
||||
|
||||
verify:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set Node.js 20.x
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
|
||||
# Need root node_modules because certain npm packages like jest are configured for the entire repository and it won't be possible
|
||||
# without these to just compile the artifacts package
|
||||
- name: Install root npm packages
|
||||
run: npm ci
|
||||
|
||||
- name: Compile artifact package
|
||||
run: |
|
||||
packages/artifact/__tests__/test-artifact-file.sh "multi-artifact-directory/my-artifact-1/artifact-path/world.txt" "${{ env.non-gzip-artifact-content }}"
|
||||
packages/artifact/__tests__/test-artifact-file.sh "multi-artifact-directory/my-artifact-2/artifact-path/gzip.txt" "${{ env.gzip-artifact-content }}"
|
||||
packages/artifact/__tests__/test-artifact-file.sh "multi-artifact-directory/my-artifact-3/artifact-path/empty.txt" "${{ env.empty-artifact-content }}"
|
||||
npm ci
|
||||
npm run tsc
|
||||
working-directory: packages/artifact
|
||||
|
||||
- name: List artifacts using actions/github-script@v7
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const artifact = require('./packages/artifact/lib/artifact')
|
||||
|
||||
const workflowRunId = process.env.GITHUB_RUN_ID
|
||||
const repository = process.env.GITHUB_REPOSITORY
|
||||
const repositoryOwner = repository.split('/')[0]
|
||||
const repositoryName = repository.split('/')[1]
|
||||
|
||||
const listResult = await artifact.create().listArtifacts(workflowRunId, repositoryOwner, repositoryName, '${{ secrets.GITHUB_TOKEN }}')
|
||||
console.log(listResult)
|
||||
|
||||
const artifacts = listResult.artifacts
|
||||
|
||||
if (artifacts.length !== 3) {
|
||||
throw new Error('Expected 3 artifacts but only found ' + artifacts.length + ' artifacts')
|
||||
}
|
||||
|
||||
const artifactNames = artifacts.map(artifact => artifact.name)
|
||||
if (!artifactNames.includes('my-artifact-ubuntu-latest')){
|
||||
throw new Error("Expected artifact list to contain an artifact named my-artifact-ubuntu-latest but it's missing")
|
||||
}
|
||||
if (!artifactNames.includes('my-artifact-windows-latest')){
|
||||
throw new Error("Expected artifact list to contain an artifact named my-artifact-windows-latest but it's missing")
|
||||
}
|
||||
if (!artifactNames.includes('my-artifact-macos-latest')){
|
||||
throw new Error("Expected artifact list to contain an artifact named my-artifact-macos-latest but it's missing")
|
||||
}
|
||||
|
||||
console.log('Successfully listed artifacts that were uploaded')
|
||||
|
||||
@@ -20,10 +20,10 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set Node.js 16.x
|
||||
- name: Set Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
node-version: 20.x
|
||||
|
||||
- name: npm install
|
||||
run: npm install
|
||||
|
||||
@@ -24,10 +24,10 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set Node.js 16.x
|
||||
- name: Set Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
node-version: 20.x
|
||||
|
||||
# In order to save & restore cache from a shell script, certain env variables need to be set that are only available in the
|
||||
# node context. This runs a local action that gets and sets the necessary env variables that are needed
|
||||
|
||||
@@ -23,10 +23,10 @@ jobs:
|
||||
run: |
|
||||
rm "C:\Program Files\Git\usr\bin\tar.exe"
|
||||
|
||||
- name: Set Node.js 12.x
|
||||
- name: Set Node.js 20.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12.x
|
||||
node-version: 20.x
|
||||
|
||||
# In order to save & restore cache from a shell script, certain env variables need to be set that are only available in the
|
||||
# node context. This runs a local action that gets and sets the necessary env variables that are needed
|
||||
|
||||
@@ -24,14 +24,14 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: javascript
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
||||
@@ -18,10 +18,10 @@ jobs:
|
||||
- name: verify package exists
|
||||
run: ls packages/${{ github.event.inputs.package }}
|
||||
|
||||
- name: Set Node.js 16.x
|
||||
- name: Set Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
node-version: 20.x
|
||||
|
||||
- name: npm install
|
||||
run: npm install
|
||||
|
||||
@@ -25,10 +25,10 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set Node.js 16.x
|
||||
- name: Set Node.js 20.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
node-version: 20.x
|
||||
|
||||
- name: npm install
|
||||
run: npm install
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
run: npm run build
|
||||
|
||||
- name: npm test
|
||||
run: npm test -- --runInBand
|
||||
run: npm test -- --runInBand --forceExit
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
|
||||
+3
-1
@@ -1,3 +1,5 @@
|
||||
node_modules/
|
||||
packages/*/node_modules/
|
||||
packages/*/lib/
|
||||
packages/*/lib/
|
||||
packages/glob/__tests__/_temp/**/
|
||||
packages/*/src/generated/*/
|
||||
|
||||
+2
-1
@@ -7,5 +7,6 @@
|
||||
"trailingComma": "none",
|
||||
"bracketSpacing": false,
|
||||
"arrowParens": "avoid",
|
||||
"parser": "typescript"
|
||||
"parser": "typescript",
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"packages": [
|
||||
"packages/*"
|
||||
"packages/**/*"
|
||||
],
|
||||
"version": "independent"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"tasksRunnerOptions": {
|
||||
"default": {
|
||||
"runner": "nx/tasks-runners/default",
|
||||
"options": {
|
||||
"cacheableOperations": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"affected": {
|
||||
"defaultBase": "master"
|
||||
},
|
||||
"$schema": "./node_modules/nx/schemas/nx-schema.json",
|
||||
"namedInputs": {
|
||||
"default": [
|
||||
"{projectRoot}/**/*",
|
||||
"sharedGlobals"
|
||||
],
|
||||
"sharedGlobals": [],
|
||||
"production": [
|
||||
"default"
|
||||
]
|
||||
}
|
||||
}
|
||||
Generated
+6061
-22924
File diff suppressed because it is too large
Load Diff
+17
-13
@@ -3,8 +3,10 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"audit-all": "lerna run audit-moderate",
|
||||
"bootstrap": "lerna bootstrap",
|
||||
"bootstrap": "lerna exec -- npm install",
|
||||
"build": "lerna run tsc",
|
||||
"clean": "lerna clean",
|
||||
"repair": "lerna repair",
|
||||
"check-all": "concurrently \"npm:format-check\" \"npm:lint\" \"npm:test\" \"npm:build -- -- --noEmit\"",
|
||||
"format": "prettier --write packages/**/*.ts",
|
||||
"format-check": "prettier --check packages/**/*.ts",
|
||||
@@ -14,19 +16,21 @@
|
||||
"test": "jest --testTimeout 10000"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^27.0.2",
|
||||
"@types/node": "^16.18.1",
|
||||
"@types/jest": "^29.5.4",
|
||||
"@types/node": "^20.5.7",
|
||||
"@types/signale": "^1.4.1",
|
||||
"@typescript-eslint/parser": "^4.0.0",
|
||||
"concurrently": "^6.1.0",
|
||||
"eslint": "^7.23.0",
|
||||
"eslint-plugin-github": "^4.1.3",
|
||||
"eslint-plugin-jest": "^22.21.0",
|
||||
"eslint": "^8.0.1",
|
||||
"eslint-config-prettier": "^8.9.0",
|
||||
"eslint-plugin-github": "^4.9.2",
|
||||
"eslint-plugin-jest": "^27.2.3",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"flow-bin": "^0.115.0",
|
||||
"jest": "^27.2.5",
|
||||
"lerna": "^5.4.0",
|
||||
"prettier": "^1.19.1",
|
||||
"ts-jest": "^27.0.5",
|
||||
"typescript": "^3.9.9"
|
||||
"jest": "^29.6.4",
|
||||
"lerna": "^7.1.4",
|
||||
"nx": "16.6.0",
|
||||
"prettier": "^3.0.0",
|
||||
"ts-jest": "^29.1.1",
|
||||
"typescript": "^5.2.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,94 +2,12 @@
|
||||
|
||||
## Usage
|
||||
|
||||
You can use this package to interact with the actions artifacts.
|
||||
- [Upload an Artifact](#Upload-an-Artifact)
|
||||
- [Download a Single Artifact](#Download-a-Single-Artifact)
|
||||
- [Download All Artifacts](#Download-all-Artifacts)
|
||||
- [Additional Documentation](#Additional-Documentation)
|
||||
- [Contributions](#Contributions)
|
||||
You can use this package to interact with the Actions artifacts.
|
||||
|
||||
Relative paths and absolute paths are both allowed. Relative paths are rooted against the current working directory.
|
||||
This most recently published version of this package (`1.1.1`) can be found [here](https://github.com/actions/toolkit/tree/@actions/artifact@1.1.1/packages/artifact)
|
||||
|
||||
## Upload an Artifact
|
||||
## 🚧 Under construction 🚧
|
||||
|
||||
Method Name: `uploadArtifact`
|
||||
This package is currently undergoing a major overhaul in preparation for `v4` versions of `upload-artifact` and `download-artifact` (these Actions will use a new `2.0.0` version of `@actions/artifact` that will soon be released). The upcoming version of `@actions/artifact` will take advantage of a major re-architecture with entirely new APIs.
|
||||
|
||||
#### Inputs
|
||||
- `name`
|
||||
- The name of the artifact that is being uploaded
|
||||
- Required
|
||||
- `files`
|
||||
- A list of file paths that describe what should be uploaded as part of the artifact
|
||||
- If a path is provided that does not exist, an error will be thrown
|
||||
- Can be absolute or relative. Internally everything is normalized and resolved
|
||||
- Required
|
||||
- `rootDirectory`
|
||||
- A file path that denotes the root directory of the files being uploaded. This path is used to strip the paths provided in `files` to control how they are uploaded and structured
|
||||
- If a file specified in `files` is not in the `rootDirectory`, an error will be thrown
|
||||
- Required
|
||||
- `options`
|
||||
- Extra options that allow for the customization of the upload behavior
|
||||
- Optional
|
||||
|
||||
#### Available Options
|
||||
|
||||
- `retentionDays`
|
||||
- Duration after which artifact will expire in days
|
||||
- Minimum value: 1
|
||||
- Maximum value: 90 unless changed by repository setting
|
||||
- If this is set to a greater value than the retention settings allowed, the retention on artifacts will be reduced to match the max value allowed on the server, and the upload process will continue. An input of 0 assumes default retention value.
|
||||
|
||||
#### Example using Absolute File Paths
|
||||
|
||||
```js
|
||||
const artifact = require('@actions/artifact');
|
||||
const artifactClient = artifact.create()
|
||||
const artifactName = 'my-artifact';
|
||||
const files = [
|
||||
'/home/user/files/plz-upload/file1.txt',
|
||||
'/home/user/files/plz-upload/file2.txt',
|
||||
'/home/user/files/plz-upload/dir/file3.txt'
|
||||
]
|
||||
const rootDirectory = '/home/user/files/plz-upload'
|
||||
const options = {
|
||||
continueOnError: true
|
||||
}
|
||||
|
||||
const uploadResult = await artifactClient.uploadArtifact(artifactName, files, rootDirectory, options)
|
||||
```
|
||||
|
||||
#### Example using Relative File Paths
|
||||
```js
|
||||
// Assuming the current working directory is /home/user/files/plz-upload
|
||||
const artifact = require('@actions/artifact');
|
||||
const artifactClient = artifact.create()
|
||||
const artifactName = 'my-artifact';
|
||||
const files = [
|
||||
'file1.txt',
|
||||
'file2.txt',
|
||||
'dir/file3.txt'
|
||||
]
|
||||
|
||||
const rootDirectory = '.' // Also possible to use __dirname
|
||||
const options = {
|
||||
continueOnError: false
|
||||
}
|
||||
|
||||
const uploadResponse = await artifactClient.uploadArtifact(artifactName, files, rootDirectory, options)
|
||||
```
|
||||
|
||||
#### Upload Result
|
||||
|
||||
The returned `UploadResponse` will contain the following information
|
||||
|
||||
- `artifactName`
|
||||
- The name of the artifact that was uploaded
|
||||
- `size`
|
||||
- Total size of the artifact that was uploaded in bytes
|
||||
|
||||
## Contributions
|
||||
|
||||
See [contributor guidelines](https://github.com/actions/toolkit/blob/main/.github/CONTRIBUTING.md) for general guidelines and information about toolkit contributions.
|
||||
|
||||
For contributions related to this package, see [artifact contributions](CONTRIBUTIONS.md) for more information.
|
||||
The upcoming `2.0.0` package and `v4` artifact Actions aim to solve some of the major pain-points that have made artifact usage difficult up until now.
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
import * as http from 'http'
|
||||
import * as net from 'net'
|
||||
import {HttpClient} from '@actions/http-client'
|
||||
import * as config from '../src/internal/shared/config'
|
||||
import {internalArtifactTwirpClient} from '../src/internal/shared/artifact-twirp-client'
|
||||
import {noopLogs} from './common'
|
||||
|
||||
jest.mock('@actions/http-client')
|
||||
|
||||
describe('artifact-http-client', () => {
|
||||
beforeAll(() => {
|
||||
noopLogs()
|
||||
jest
|
||||
.spyOn(config, 'getResultsServiceUrl')
|
||||
.mockReturnValue('http://localhost:8080')
|
||||
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('token')
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it('should successfully create a client', () => {
|
||||
const client = internalArtifactTwirpClient()
|
||||
expect(client).toBeDefined()
|
||||
})
|
||||
|
||||
it('should make a request', async () => {
|
||||
const mockPost = jest.fn(() => {
|
||||
const msg = new http.IncomingMessage(new net.Socket())
|
||||
msg.statusCode = 200
|
||||
return {
|
||||
message: msg,
|
||||
readBody: async () => {
|
||||
return Promise.resolve(
|
||||
`{"ok": true, "signedUploadUrl": "http://localhost:8080/upload"}`
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
const mockHttpClient = (
|
||||
HttpClient as unknown as jest.Mock
|
||||
).mockImplementation(() => {
|
||||
return {
|
||||
post: mockPost
|
||||
}
|
||||
})
|
||||
|
||||
const client = internalArtifactTwirpClient()
|
||||
const artifact = await client.CreateArtifact({
|
||||
workflowRunBackendId: '1234',
|
||||
workflowJobRunBackendId: '5678',
|
||||
name: 'artifact',
|
||||
version: 4
|
||||
})
|
||||
|
||||
expect(mockHttpClient).toHaveBeenCalledTimes(1)
|
||||
expect(mockPost).toHaveBeenCalledTimes(1)
|
||||
expect(artifact).toBeDefined()
|
||||
expect(artifact.ok).toBe(true)
|
||||
expect(artifact.signedUploadUrl).toBe('http://localhost:8080/upload')
|
||||
})
|
||||
|
||||
it('should retry if the request fails', async () => {
|
||||
const mockPost = jest
|
||||
.fn(() => {
|
||||
const msgSucceeded = new http.IncomingMessage(new net.Socket())
|
||||
msgSucceeded.statusCode = 200
|
||||
return {
|
||||
message: msgSucceeded,
|
||||
readBody: async () => {
|
||||
return Promise.resolve(
|
||||
`{"ok": true, "signedUploadUrl": "http://localhost:8080/upload"}`
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
const msgFailed = new http.IncomingMessage(new net.Socket())
|
||||
msgFailed.statusCode = 500
|
||||
msgFailed.statusMessage = 'Internal Server Error'
|
||||
return {
|
||||
message: msgFailed,
|
||||
readBody: async () => {
|
||||
return Promise.resolve(`{"ok": false}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
const mockHttpClient = (
|
||||
HttpClient as unknown as jest.Mock
|
||||
).mockImplementation(() => {
|
||||
return {
|
||||
post: mockPost
|
||||
}
|
||||
})
|
||||
|
||||
const client = internalArtifactTwirpClient({
|
||||
maxAttempts: 5,
|
||||
retryIntervalMs: 1,
|
||||
retryMultiplier: 1.5
|
||||
})
|
||||
const artifact = await client.CreateArtifact({
|
||||
workflowRunBackendId: '1234',
|
||||
workflowJobRunBackendId: '5678',
|
||||
name: 'artifact',
|
||||
version: 4
|
||||
})
|
||||
|
||||
expect(mockHttpClient).toHaveBeenCalledTimes(1)
|
||||
expect(artifact).toBeDefined()
|
||||
expect(artifact.ok).toBe(true)
|
||||
expect(artifact.signedUploadUrl).toBe('http://localhost:8080/upload')
|
||||
expect(mockPost).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
it('should fail if the request fails 5 times', async () => {
|
||||
const mockPost = jest.fn(() => {
|
||||
const msgFailed = new http.IncomingMessage(new net.Socket())
|
||||
msgFailed.statusCode = 500
|
||||
msgFailed.statusMessage = 'Internal Server Error'
|
||||
return {
|
||||
message: msgFailed,
|
||||
readBody: async () => {
|
||||
return Promise.resolve(`{"ok": false}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const mockHttpClient = (
|
||||
HttpClient as unknown as jest.Mock
|
||||
).mockImplementation(() => {
|
||||
return {
|
||||
post: mockPost
|
||||
}
|
||||
})
|
||||
const client = internalArtifactTwirpClient({
|
||||
maxAttempts: 5,
|
||||
retryIntervalMs: 1,
|
||||
retryMultiplier: 1.5
|
||||
})
|
||||
await expect(async () => {
|
||||
await client.CreateArtifact({
|
||||
workflowRunBackendId: '1234',
|
||||
workflowJobRunBackendId: '5678',
|
||||
name: 'artifact',
|
||||
version: 4
|
||||
})
|
||||
}).rejects.toThrowError(
|
||||
'Failed to make request after 5 attempts: Failed request: (500) Internal Server Error'
|
||||
)
|
||||
expect(mockHttpClient).toHaveBeenCalledTimes(1)
|
||||
expect(mockPost).toHaveBeenCalledTimes(5)
|
||||
})
|
||||
|
||||
it('should fail immediately if there is a non-retryable error', async () => {
|
||||
const mockPost = jest.fn(() => {
|
||||
const msgFailed = new http.IncomingMessage(new net.Socket())
|
||||
msgFailed.statusCode = 401
|
||||
msgFailed.statusMessage = 'Unauthorized'
|
||||
return {
|
||||
message: msgFailed,
|
||||
readBody: async () => {
|
||||
return Promise.resolve(`{"ok": false}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const mockHttpClient = (
|
||||
HttpClient as unknown as jest.Mock
|
||||
).mockImplementation(() => {
|
||||
return {
|
||||
post: mockPost
|
||||
}
|
||||
})
|
||||
const client = internalArtifactTwirpClient({
|
||||
maxAttempts: 5,
|
||||
retryIntervalMs: 1,
|
||||
retryMultiplier: 1.5
|
||||
})
|
||||
await expect(async () => {
|
||||
await client.CreateArtifact({
|
||||
workflowRunBackendId: '1234',
|
||||
workflowJobRunBackendId: '5678',
|
||||
name: 'artifact',
|
||||
version: 4
|
||||
})
|
||||
}).rejects.toThrowError(
|
||||
'Received non-retryable error: Failed request: (401) Unauthorized'
|
||||
)
|
||||
expect(mockHttpClient).toHaveBeenCalledTimes(1)
|
||||
expect(mockPost).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
@@ -1,5 +0,0 @@
|
||||
name: 'Set env variables'
|
||||
description: 'Sets certain env variables so that e2e artifact upload and download can be tested in a shell'
|
||||
runs:
|
||||
using: 'node12'
|
||||
main: 'index.js'
|
||||
@@ -1,14 +0,0 @@
|
||||
// Certain env variables are not set by default in a shell context and are only available in a node context from a running action
|
||||
// In order to be able to upload and download artifacts e2e in a shell when running CI tests, we need these env variables set
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const filePath = process.env[`GITHUB_ENV`]
|
||||
fs.appendFileSync(filePath, `ACTIONS_RUNTIME_URL=${process.env.ACTIONS_RUNTIME_URL}${os.EOL}`, {
|
||||
encoding: 'utf8'
|
||||
})
|
||||
fs.appendFileSync(filePath, `ACTIONS_RUNTIME_TOKEN=${process.env.ACTIONS_RUNTIME_TOKEN}${os.EOL}`, {
|
||||
encoding: 'utf8'
|
||||
})
|
||||
fs.appendFileSync(filePath, `GITHUB_RUN_ID=${process.env.GITHUB_RUN_ID}${os.EOL}`, {
|
||||
encoding: 'utf8'
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
import * as core from '@actions/core'
|
||||
|
||||
// noopLogs mocks the console.log and core.* functions to prevent output in the console while testing
|
||||
export const noopLogs = (): void => {
|
||||
jest.spyOn(console, 'log').mockImplementation(() => {})
|
||||
jest.spyOn(core, 'debug').mockImplementation(() => {})
|
||||
jest.spyOn(core, 'info').mockImplementation(() => {})
|
||||
jest.spyOn(core, 'warning').mockImplementation(() => {})
|
||||
}
|
||||
@@ -0,0 +1,466 @@
|
||||
import fs from 'fs'
|
||||
import * as http from 'http'
|
||||
import * as net from 'net'
|
||||
import * as path from 'path'
|
||||
import * as github from '@actions/github'
|
||||
import {HttpClient} from '@actions/http-client'
|
||||
import type {RestEndpointMethods} from '@octokit/plugin-rest-endpoint-methods/dist-types/generated/method-types'
|
||||
import archiver from 'archiver'
|
||||
|
||||
import {
|
||||
downloadArtifactInternal,
|
||||
downloadArtifactPublic
|
||||
} from '../src/internal/download/download-artifact'
|
||||
import {getUserAgentString} from '../src/internal/shared/user-agent'
|
||||
import {noopLogs} from './common'
|
||||
import * as config from '../src/internal/shared/config'
|
||||
import {ArtifactServiceClientJSON} from '../src/generated'
|
||||
import * as util from '../src/internal/shared/util'
|
||||
|
||||
type MockedDownloadArtifact = jest.MockedFunction<
|
||||
RestEndpointMethods['actions']['downloadArtifact']
|
||||
>
|
||||
|
||||
const testDir = path.join(__dirname, '_temp', 'download-artifact')
|
||||
const fixtures = {
|
||||
workspaceDir: path.join(testDir, 'workspace'),
|
||||
exampleArtifact: {
|
||||
path: path.join(testDir, 'artifact.zip'),
|
||||
files: [
|
||||
{
|
||||
path: 'hello.txt',
|
||||
content: 'Hello World!'
|
||||
},
|
||||
{
|
||||
path: 'goodbye.txt',
|
||||
content: 'Goodbye World!'
|
||||
}
|
||||
]
|
||||
},
|
||||
artifactID: 1234,
|
||||
artifactName: 'my-artifact',
|
||||
artifactSize: 123456,
|
||||
repositoryOwner: 'actions',
|
||||
repositoryName: 'toolkit',
|
||||
token: 'ghp_1234567890',
|
||||
blobStorageUrl: 'https://blob-storage.local?signed=true',
|
||||
backendIds: {
|
||||
workflowRunBackendId: 'c4d7c21f-ba3f-4ddc-a8c8-6f2f626f8422',
|
||||
workflowJobRunBackendId: '760803a1-f890-4d25-9a6e-a3fc01a0c7cf'
|
||||
}
|
||||
}
|
||||
|
||||
jest.mock('@actions/github', () => ({
|
||||
getOctokit: jest.fn().mockReturnValue({
|
||||
rest: {
|
||||
actions: {
|
||||
downloadArtifact: jest.fn()
|
||||
}
|
||||
}
|
||||
})
|
||||
}))
|
||||
|
||||
jest.mock('@actions/http-client')
|
||||
|
||||
// Create a zip archive with the contents of the example artifact
|
||||
const createTestArchive = async (): Promise<void> => {
|
||||
const archive = archiver('zip', {
|
||||
zlib: {level: 9}
|
||||
})
|
||||
for (const file of fixtures.exampleArtifact.files) {
|
||||
archive.append(file.content, {name: file.path})
|
||||
}
|
||||
archive.finalize()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
archive.pipe(fs.createWriteStream(fixtures.exampleArtifact.path))
|
||||
archive.on('error', reject)
|
||||
archive.on('finish', resolve)
|
||||
})
|
||||
}
|
||||
|
||||
const expectExtractedArchive = async (dir: string): Promise<void> => {
|
||||
for (const file of fixtures.exampleArtifact.files) {
|
||||
const filePath = path.join(dir, file.path)
|
||||
expect(fs.readFileSync(filePath, 'utf8')).toEqual(file.content)
|
||||
}
|
||||
}
|
||||
|
||||
const setup = async (): Promise<void> => {
|
||||
noopLogs()
|
||||
await fs.promises.mkdir(testDir, {recursive: true})
|
||||
await createTestArchive()
|
||||
|
||||
process.env['GITHUB_WORKSPACE'] = fixtures.workspaceDir
|
||||
}
|
||||
|
||||
const cleanup = async (): Promise<void> => {
|
||||
jest.restoreAllMocks()
|
||||
await fs.promises.rm(testDir, {recursive: true})
|
||||
delete process.env['GITHUB_WORKSPACE']
|
||||
}
|
||||
|
||||
const mockGetArtifactSuccess = jest.fn(() => {
|
||||
const message = new http.IncomingMessage(new net.Socket())
|
||||
message.statusCode = 200
|
||||
message.push(fs.readFileSync(fixtures.exampleArtifact.path))
|
||||
return {
|
||||
message
|
||||
}
|
||||
})
|
||||
|
||||
const mockGetArtifactFailure = jest.fn(() => {
|
||||
const message = new http.IncomingMessage(new net.Socket())
|
||||
message.statusCode = 500
|
||||
message.push('Internal Server Error')
|
||||
return {
|
||||
message
|
||||
}
|
||||
})
|
||||
|
||||
describe('download-artifact', () => {
|
||||
describe('public', () => {
|
||||
beforeEach(setup)
|
||||
afterEach(cleanup)
|
||||
|
||||
it('should successfully download an artifact to $GITHUB_WORKSPACE', async () => {
|
||||
const downloadArtifactMock = github.getOctokit(fixtures.token).rest
|
||||
.actions.downloadArtifact as MockedDownloadArtifact
|
||||
downloadArtifactMock.mockResolvedValueOnce({
|
||||
headers: {
|
||||
location: fixtures.blobStorageUrl
|
||||
},
|
||||
status: 302,
|
||||
url: '',
|
||||
data: Buffer.from('')
|
||||
})
|
||||
|
||||
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
|
||||
() => {
|
||||
return {
|
||||
get: mockGetArtifactSuccess
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const response = await downloadArtifactPublic(
|
||||
fixtures.artifactID,
|
||||
fixtures.repositoryOwner,
|
||||
fixtures.repositoryName,
|
||||
fixtures.token
|
||||
)
|
||||
|
||||
expect(downloadArtifactMock).toHaveBeenCalledWith({
|
||||
owner: fixtures.repositoryOwner,
|
||||
repo: fixtures.repositoryName,
|
||||
artifact_id: fixtures.artifactID,
|
||||
archive_format: 'zip',
|
||||
request: {
|
||||
redirect: 'manual'
|
||||
}
|
||||
})
|
||||
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
|
||||
expect(mockGetArtifactSuccess).toHaveBeenCalledWith(
|
||||
fixtures.blobStorageUrl
|
||||
)
|
||||
expectExtractedArchive(fixtures.workspaceDir)
|
||||
expect(response.downloadPath).toBe(fixtures.workspaceDir)
|
||||
})
|
||||
|
||||
it('should successfully download an artifact to user defined path', async () => {
|
||||
const customPath = path.join(testDir, 'custom')
|
||||
|
||||
const downloadArtifactMock = github.getOctokit(fixtures.token).rest
|
||||
.actions.downloadArtifact as MockedDownloadArtifact
|
||||
downloadArtifactMock.mockResolvedValueOnce({
|
||||
headers: {
|
||||
location: fixtures.blobStorageUrl
|
||||
},
|
||||
status: 302,
|
||||
url: '',
|
||||
data: Buffer.from('')
|
||||
})
|
||||
|
||||
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
|
||||
() => {
|
||||
return {
|
||||
get: mockGetArtifactSuccess
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const response = await downloadArtifactPublic(
|
||||
fixtures.artifactID,
|
||||
fixtures.repositoryOwner,
|
||||
fixtures.repositoryName,
|
||||
fixtures.token,
|
||||
{
|
||||
path: customPath
|
||||
}
|
||||
)
|
||||
|
||||
expect(downloadArtifactMock).toHaveBeenCalledWith({
|
||||
owner: fixtures.repositoryOwner,
|
||||
repo: fixtures.repositoryName,
|
||||
artifact_id: fixtures.artifactID,
|
||||
archive_format: 'zip',
|
||||
request: {
|
||||
redirect: 'manual'
|
||||
}
|
||||
})
|
||||
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
|
||||
expect(mockGetArtifactSuccess).toHaveBeenCalledWith(
|
||||
fixtures.blobStorageUrl
|
||||
)
|
||||
expectExtractedArchive(customPath)
|
||||
expect(response.downloadPath).toBe(customPath)
|
||||
})
|
||||
|
||||
it('should fail if download artifact API does not respond with location', async () => {
|
||||
const downloadArtifactMock = github.getOctokit(fixtures.token).rest
|
||||
.actions.downloadArtifact as MockedDownloadArtifact
|
||||
downloadArtifactMock.mockResolvedValueOnce({
|
||||
headers: {},
|
||||
status: 302,
|
||||
url: '',
|
||||
data: Buffer.from('')
|
||||
})
|
||||
|
||||
await expect(
|
||||
downloadArtifactPublic(
|
||||
fixtures.artifactID,
|
||||
fixtures.repositoryOwner,
|
||||
fixtures.repositoryName,
|
||||
fixtures.token
|
||||
)
|
||||
).rejects.toBeInstanceOf(Error)
|
||||
|
||||
expect(downloadArtifactMock).toHaveBeenCalledWith({
|
||||
owner: fixtures.repositoryOwner,
|
||||
repo: fixtures.repositoryName,
|
||||
artifact_id: fixtures.artifactID,
|
||||
archive_format: 'zip',
|
||||
request: {
|
||||
redirect: 'manual'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('should fail if blob storage response is non-200', async () => {
|
||||
const downloadArtifactMock = github.getOctokit(fixtures.token).rest
|
||||
.actions.downloadArtifact as MockedDownloadArtifact
|
||||
downloadArtifactMock.mockResolvedValueOnce({
|
||||
headers: {
|
||||
location: fixtures.blobStorageUrl
|
||||
},
|
||||
status: 302,
|
||||
url: '',
|
||||
data: Buffer.from('')
|
||||
})
|
||||
|
||||
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
|
||||
() => {
|
||||
return {
|
||||
get: mockGetArtifactFailure
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
await expect(
|
||||
downloadArtifactPublic(
|
||||
fixtures.artifactID,
|
||||
fixtures.repositoryOwner,
|
||||
fixtures.repositoryName,
|
||||
fixtures.token
|
||||
)
|
||||
).rejects.toBeInstanceOf(Error)
|
||||
|
||||
expect(downloadArtifactMock).toHaveBeenCalledWith({
|
||||
owner: fixtures.repositoryOwner,
|
||||
repo: fixtures.repositoryName,
|
||||
artifact_id: fixtures.artifactID,
|
||||
archive_format: 'zip',
|
||||
request: {
|
||||
redirect: 'manual'
|
||||
}
|
||||
})
|
||||
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
|
||||
expect(mockGetArtifactFailure).toHaveBeenCalledWith(
|
||||
fixtures.blobStorageUrl
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('internal', () => {
|
||||
beforeEach(async () => {
|
||||
await setup()
|
||||
|
||||
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token')
|
||||
|
||||
jest
|
||||
.spyOn(util, 'getBackendIdsFromToken')
|
||||
.mockReturnValue(fixtures.backendIds)
|
||||
|
||||
jest
|
||||
.spyOn(config, 'getResultsServiceUrl')
|
||||
.mockReturnValue('https://results.local')
|
||||
})
|
||||
afterEach(async () => {
|
||||
await cleanup()
|
||||
})
|
||||
|
||||
it('should successfully download an artifact to $GITHUB_WORKSPACE', async () => {
|
||||
const mockListArtifacts = jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
|
||||
.mockResolvedValue({
|
||||
artifacts: [
|
||||
{
|
||||
...fixtures.backendIds,
|
||||
databaseId: fixtures.artifactID.toString(),
|
||||
name: fixtures.artifactName,
|
||||
size: fixtures.artifactSize.toString()
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const mockGetSignedArtifactURL = jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'GetSignedArtifactURL')
|
||||
.mockReturnValue(
|
||||
Promise.resolve({
|
||||
signedUrl: fixtures.blobStorageUrl
|
||||
})
|
||||
)
|
||||
|
||||
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
|
||||
() => {
|
||||
return {
|
||||
get: mockGetArtifactSuccess
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const response = await downloadArtifactInternal(fixtures.artifactID)
|
||||
|
||||
expectExtractedArchive(fixtures.workspaceDir)
|
||||
expect(response.downloadPath).toBe(fixtures.workspaceDir)
|
||||
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
|
||||
expect(mockListArtifacts).toHaveBeenCalledWith({
|
||||
idFilter: {
|
||||
value: fixtures.artifactID.toString()
|
||||
},
|
||||
...fixtures.backendIds
|
||||
})
|
||||
expect(mockGetSignedArtifactURL).toHaveBeenCalledWith({
|
||||
...fixtures.backendIds,
|
||||
name: fixtures.artifactName
|
||||
})
|
||||
})
|
||||
|
||||
it('should successfully download an artifact to user defined path', async () => {
|
||||
const customPath = path.join(testDir, 'custom')
|
||||
|
||||
const mockListArtifacts = jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
|
||||
.mockResolvedValue({
|
||||
artifacts: [
|
||||
{
|
||||
...fixtures.backendIds,
|
||||
databaseId: fixtures.artifactID.toString(),
|
||||
name: fixtures.artifactName,
|
||||
size: fixtures.artifactSize.toString()
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const mockGetSignedArtifactURL = jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'GetSignedArtifactURL')
|
||||
.mockReturnValue(
|
||||
Promise.resolve({
|
||||
signedUrl: fixtures.blobStorageUrl
|
||||
})
|
||||
)
|
||||
|
||||
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
|
||||
() => {
|
||||
return {
|
||||
get: mockGetArtifactSuccess
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const response = await downloadArtifactInternal(fixtures.artifactID, {
|
||||
path: customPath
|
||||
})
|
||||
|
||||
expectExtractedArchive(customPath)
|
||||
expect(response.downloadPath).toBe(customPath)
|
||||
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
|
||||
expect(mockListArtifacts).toHaveBeenCalledWith({
|
||||
idFilter: {
|
||||
value: fixtures.artifactID.toString()
|
||||
},
|
||||
...fixtures.backendIds
|
||||
})
|
||||
expect(mockGetSignedArtifactURL).toHaveBeenCalledWith({
|
||||
...fixtures.backendIds,
|
||||
name: fixtures.artifactName
|
||||
})
|
||||
})
|
||||
|
||||
it('should fail if download artifact API does not respond with location', async () => {
|
||||
jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
|
||||
.mockRejectedValue(new Error('boom'))
|
||||
|
||||
await expect(
|
||||
downloadArtifactInternal(fixtures.artifactID)
|
||||
).rejects.toBeInstanceOf(Error)
|
||||
})
|
||||
|
||||
it('should fail if blob storage response is non-200', async () => {
|
||||
const mockListArtifacts = jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
|
||||
.mockResolvedValue({
|
||||
artifacts: [
|
||||
{
|
||||
...fixtures.backendIds,
|
||||
databaseId: fixtures.artifactID.toString(),
|
||||
name: fixtures.artifactName,
|
||||
size: fixtures.artifactSize.toString()
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const mockGetSignedArtifactURL = jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'GetSignedArtifactURL')
|
||||
.mockReturnValue(
|
||||
Promise.resolve({
|
||||
signedUrl: fixtures.blobStorageUrl
|
||||
})
|
||||
)
|
||||
|
||||
const mockHttpClient = (HttpClient as jest.Mock).mockImplementation(
|
||||
() => {
|
||||
return {
|
||||
get: mockGetArtifactFailure
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
await expect(
|
||||
downloadArtifactInternal(fixtures.artifactID)
|
||||
).rejects.toBeInstanceOf(Error)
|
||||
expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString())
|
||||
expect(mockListArtifacts).toHaveBeenCalledWith({
|
||||
idFilter: {
|
||||
value: fixtures.artifactID.toString()
|
||||
},
|
||||
...fixtures.backendIds
|
||||
})
|
||||
expect(mockGetSignedArtifactURL).toHaveBeenCalledWith({
|
||||
...fixtures.backendIds,
|
||||
name: fixtures.artifactName
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,239 @@
|
||||
import * as github from '@actions/github'
|
||||
import type {RequestInterface} from '@octokit/types'
|
||||
import {
|
||||
getArtifactInternal,
|
||||
getArtifactPublic
|
||||
} from '../src/internal/find/get-artifact'
|
||||
import * as config from '../src/internal/shared/config'
|
||||
import {ArtifactServiceClientJSON, Timestamp} from '../src/generated'
|
||||
import * as util from '../src/internal/shared/util'
|
||||
import {noopLogs} from './common'
|
||||
import {
|
||||
ArtifactNotFoundError,
|
||||
InvalidResponseError
|
||||
} from '../src/internal/shared/errors'
|
||||
|
||||
type MockedRequest = jest.MockedFunction<RequestInterface<object>>
|
||||
|
||||
jest.mock('@actions/github', () => ({
|
||||
getOctokit: jest.fn().mockReturnValue({
|
||||
request: jest.fn()
|
||||
})
|
||||
}))
|
||||
|
||||
const fixtures = {
|
||||
repo: 'toolkit',
|
||||
owner: 'actions',
|
||||
token: 'ghp_1234567890',
|
||||
runId: 123,
|
||||
backendIds: {
|
||||
workflowRunBackendId: 'c4d7c21f-ba3f-4ddc-a8c8-6f2f626f8422',
|
||||
workflowJobRunBackendId: '760803a1-f890-4d25-9a6e-a3fc01a0c7cf'
|
||||
},
|
||||
artifacts: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'my-artifact',
|
||||
size: 456,
|
||||
createdAt: new Date('2023-12-01')
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'my-artifact',
|
||||
size: 456,
|
||||
createdAt: new Date('2023-12-02')
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
describe('get-artifact', () => {
|
||||
beforeAll(() => {
|
||||
noopLogs()
|
||||
})
|
||||
|
||||
describe('public', () => {
|
||||
it('should return the artifact if it is found', async () => {
|
||||
const mockRequest = github.getOctokit(fixtures.token)
|
||||
.request as MockedRequest
|
||||
mockRequest.mockResolvedValueOnce({
|
||||
status: 200,
|
||||
headers: {},
|
||||
url: '',
|
||||
data: {
|
||||
artifacts: [
|
||||
{
|
||||
name: fixtures.artifacts[0].name,
|
||||
id: fixtures.artifacts[0].id,
|
||||
size_in_bytes: fixtures.artifacts[0].size,
|
||||
created_at: fixtures.artifacts[0].createdAt.toISOString()
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
const response = await getArtifactPublic(
|
||||
fixtures.artifacts[0].name,
|
||||
fixtures.runId,
|
||||
fixtures.owner,
|
||||
fixtures.repo,
|
||||
fixtures.token
|
||||
)
|
||||
|
||||
expect(response).toEqual({
|
||||
artifact: fixtures.artifacts[0]
|
||||
})
|
||||
})
|
||||
|
||||
it('should return the latest artifact if multiple are found', async () => {
|
||||
const mockRequest = github.getOctokit(fixtures.token)
|
||||
.request as MockedRequest
|
||||
mockRequest.mockResolvedValueOnce({
|
||||
status: 200,
|
||||
headers: {},
|
||||
url: '',
|
||||
data: {
|
||||
artifacts: fixtures.artifacts.map(artifact => ({
|
||||
name: artifact.name,
|
||||
id: artifact.id,
|
||||
size_in_bytes: artifact.size,
|
||||
created_at: artifact.createdAt.toISOString()
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
const response = await getArtifactPublic(
|
||||
fixtures.artifacts[0].name,
|
||||
fixtures.runId,
|
||||
fixtures.owner,
|
||||
fixtures.repo,
|
||||
fixtures.token
|
||||
)
|
||||
|
||||
expect(response).toEqual({
|
||||
artifact: fixtures.artifacts[1]
|
||||
})
|
||||
})
|
||||
|
||||
it('should fail if no artifacts are found', async () => {
|
||||
const mockRequest = github.getOctokit(fixtures.token)
|
||||
.request as MockedRequest
|
||||
mockRequest.mockResolvedValueOnce({
|
||||
status: 200,
|
||||
headers: {},
|
||||
url: '',
|
||||
data: {
|
||||
artifacts: []
|
||||
}
|
||||
})
|
||||
|
||||
const response = getArtifactPublic(
|
||||
fixtures.artifacts[0].name,
|
||||
fixtures.runId,
|
||||
fixtures.owner,
|
||||
fixtures.repo,
|
||||
fixtures.token
|
||||
)
|
||||
|
||||
expect(response).rejects.toThrowError(ArtifactNotFoundError)
|
||||
})
|
||||
|
||||
it('should fail if non-200 response', async () => {
|
||||
const mockRequest = github.getOctokit(fixtures.token)
|
||||
.request as MockedRequest
|
||||
mockRequest.mockResolvedValueOnce({
|
||||
status: 404,
|
||||
headers: {},
|
||||
url: '',
|
||||
data: {}
|
||||
})
|
||||
|
||||
const response = getArtifactPublic(
|
||||
fixtures.artifacts[0].name,
|
||||
fixtures.runId,
|
||||
fixtures.owner,
|
||||
fixtures.repo,
|
||||
fixtures.token
|
||||
)
|
||||
|
||||
expect(response).rejects.toThrowError(InvalidResponseError)
|
||||
})
|
||||
})
|
||||
|
||||
describe('internal', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token')
|
||||
|
||||
jest
|
||||
.spyOn(util, 'getBackendIdsFromToken')
|
||||
.mockReturnValue(fixtures.backendIds)
|
||||
|
||||
jest
|
||||
.spyOn(config, 'getResultsServiceUrl')
|
||||
.mockReturnValue('https://results.local')
|
||||
})
|
||||
|
||||
it('should return the artifact if it is found', async () => {
|
||||
jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
|
||||
.mockResolvedValue({
|
||||
artifacts: [
|
||||
{
|
||||
...fixtures.backendIds,
|
||||
databaseId: fixtures.artifacts[0].id.toString(),
|
||||
name: fixtures.artifacts[0].name,
|
||||
size: fixtures.artifacts[0].size.toString(),
|
||||
createdAt: Timestamp.fromDate(fixtures.artifacts[0].createdAt)
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const response = await getArtifactInternal(fixtures.artifacts[0].name)
|
||||
|
||||
expect(response).toEqual({
|
||||
artifact: fixtures.artifacts[0]
|
||||
})
|
||||
})
|
||||
|
||||
it('should return the latest artifact if multiple are found', async () => {
|
||||
jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
|
||||
.mockResolvedValue({
|
||||
artifacts: fixtures.artifacts.map(artifact => ({
|
||||
...fixtures.backendIds,
|
||||
databaseId: artifact.id.toString(),
|
||||
name: artifact.name,
|
||||
size: artifact.size.toString(),
|
||||
createdAt: Timestamp.fromDate(artifact.createdAt)
|
||||
}))
|
||||
})
|
||||
|
||||
const response = await getArtifactInternal(fixtures.artifacts[0].name)
|
||||
|
||||
expect(response).toEqual({
|
||||
artifact: fixtures.artifacts[1]
|
||||
})
|
||||
})
|
||||
|
||||
it('should fail if no artifacts are found', async () => {
|
||||
jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
|
||||
.mockResolvedValue({
|
||||
artifacts: []
|
||||
})
|
||||
|
||||
const response = getArtifactInternal(fixtures.artifacts[0].name)
|
||||
|
||||
expect(response).rejects.toThrowError(ArtifactNotFoundError)
|
||||
})
|
||||
|
||||
it('should fail if non-200 response', async () => {
|
||||
jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
|
||||
.mockRejectedValue(new Error('boom'))
|
||||
|
||||
const response = getArtifactInternal(fixtures.artifacts[0].name)
|
||||
|
||||
expect(response).rejects.toThrow()
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,242 @@
|
||||
import * as github from '@actions/github'
|
||||
import type {RestEndpointMethods} from '@octokit/plugin-rest-endpoint-methods/dist-types/generated/method-types'
|
||||
import type {RestEndpointMethodTypes} from '@octokit/plugin-rest-endpoint-methods/dist-types/generated/parameters-and-response-types'
|
||||
import {
|
||||
listArtifactsInternal,
|
||||
listArtifactsPublic
|
||||
} from '../src/internal/find/list-artifacts'
|
||||
import * as config from '../src/internal/shared/config'
|
||||
import {ArtifactServiceClientJSON, Timestamp} from '../src/generated'
|
||||
import * as util from '../src/internal/shared/util'
|
||||
import {noopLogs} from './common'
|
||||
import {Artifact} from '../src/internal/shared/interfaces'
|
||||
|
||||
type MockedListWorkflowRunArtifacts = jest.MockedFunction<
|
||||
RestEndpointMethods['actions']['listWorkflowRunArtifacts']
|
||||
>
|
||||
|
||||
jest.mock('@actions/github', () => ({
|
||||
getOctokit: jest.fn().mockReturnValue({
|
||||
rest: {
|
||||
actions: {
|
||||
listWorkflowRunArtifacts: jest.fn()
|
||||
}
|
||||
}
|
||||
})
|
||||
}))
|
||||
|
||||
const artifactsToListResponse = (
|
||||
artifacts: Artifact[]
|
||||
): RestEndpointMethodTypes['actions']['listWorkflowRunArtifacts']['response']['data'] => {
|
||||
return {
|
||||
total_count: artifacts.length,
|
||||
artifacts: artifacts.map(artifact => ({
|
||||
name: artifact.name,
|
||||
id: artifact.id,
|
||||
size_in_bytes: artifact.size,
|
||||
created_at: artifact.createdAt?.toISOString() || '',
|
||||
run_id: fixtures.runId,
|
||||
// unused fields for tests
|
||||
url: '',
|
||||
archive_download_url: '',
|
||||
expired: false,
|
||||
expires_at: '',
|
||||
node_id: '',
|
||||
run_url: '',
|
||||
type: '',
|
||||
updated_at: ''
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
const fixtures = {
|
||||
repo: 'toolkit',
|
||||
owner: 'actions',
|
||||
token: 'ghp_1234567890',
|
||||
runId: 123,
|
||||
backendIds: {
|
||||
workflowRunBackendId: 'c4d7c21f-ba3f-4ddc-a8c8-6f2f626f8422',
|
||||
workflowJobRunBackendId: '760803a1-f890-4d25-9a6e-a3fc01a0c7cf'
|
||||
},
|
||||
artifacts: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'my-artifact',
|
||||
size: 456,
|
||||
createdAt: new Date('2023-12-01')
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'my-artifact',
|
||||
size: 456,
|
||||
createdAt: new Date('2023-12-02')
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
describe('list-artifact', () => {
|
||||
beforeAll(() => {
|
||||
noopLogs()
|
||||
})
|
||||
|
||||
describe('public', () => {
|
||||
it('should return a list of artifacts', async () => {
|
||||
const mockListArtifacts = github.getOctokit(fixtures.token).rest.actions
|
||||
.listWorkflowRunArtifacts as MockedListWorkflowRunArtifacts
|
||||
|
||||
mockListArtifacts.mockResolvedValueOnce({
|
||||
status: 200,
|
||||
headers: {},
|
||||
url: '',
|
||||
data: artifactsToListResponse(fixtures.artifacts)
|
||||
})
|
||||
|
||||
const response = await listArtifactsPublic(
|
||||
fixtures.runId,
|
||||
fixtures.owner,
|
||||
fixtures.repo,
|
||||
fixtures.token,
|
||||
false
|
||||
)
|
||||
|
||||
expect(response).toEqual({
|
||||
artifacts: fixtures.artifacts
|
||||
})
|
||||
})
|
||||
|
||||
it('should return the latest artifact when latest is specified', async () => {
|
||||
const mockListArtifacts = github.getOctokit(fixtures.token).rest.actions
|
||||
.listWorkflowRunArtifacts as MockedListWorkflowRunArtifacts
|
||||
|
||||
mockListArtifacts.mockResolvedValueOnce({
|
||||
status: 200,
|
||||
headers: {},
|
||||
url: '',
|
||||
data: artifactsToListResponse(fixtures.artifacts)
|
||||
})
|
||||
|
||||
const response = await listArtifactsPublic(
|
||||
fixtures.runId,
|
||||
fixtures.owner,
|
||||
fixtures.repo,
|
||||
fixtures.token,
|
||||
true
|
||||
)
|
||||
|
||||
expect(response).toEqual({
|
||||
artifacts: [fixtures.artifacts[1]]
|
||||
})
|
||||
})
|
||||
|
||||
it('can return empty artifacts', async () => {
|
||||
const mockListArtifacts = github.getOctokit(fixtures.token).rest.actions
|
||||
.listWorkflowRunArtifacts as MockedListWorkflowRunArtifacts
|
||||
|
||||
mockListArtifacts.mockResolvedValueOnce({
|
||||
status: 200,
|
||||
headers: {},
|
||||
url: '',
|
||||
data: {
|
||||
total_count: 0,
|
||||
artifacts: []
|
||||
}
|
||||
})
|
||||
|
||||
const response = await listArtifactsPublic(
|
||||
fixtures.runId,
|
||||
fixtures.owner,
|
||||
fixtures.repo,
|
||||
fixtures.token,
|
||||
true
|
||||
)
|
||||
|
||||
expect(response).toEqual({
|
||||
artifacts: []
|
||||
})
|
||||
})
|
||||
|
||||
it('should fail if non-200 response', async () => {
|
||||
const mockListArtifacts = github.getOctokit(fixtures.token).rest.actions
|
||||
.listWorkflowRunArtifacts as MockedListWorkflowRunArtifacts
|
||||
|
||||
mockListArtifacts.mockRejectedValue(new Error('boom'))
|
||||
|
||||
await expect(
|
||||
listArtifactsPublic(
|
||||
fixtures.runId,
|
||||
fixtures.owner,
|
||||
fixtures.repo,
|
||||
fixtures.token,
|
||||
false
|
||||
)
|
||||
).rejects.toThrow('boom')
|
||||
})
|
||||
})
|
||||
|
||||
describe('internal', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token')
|
||||
jest
|
||||
.spyOn(util, 'getBackendIdsFromToken')
|
||||
.mockReturnValue(fixtures.backendIds)
|
||||
jest
|
||||
.spyOn(config, 'getResultsServiceUrl')
|
||||
.mockReturnValue('https://results.local')
|
||||
})
|
||||
|
||||
it('should return a list of artifacts', async () => {
|
||||
jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
|
||||
.mockResolvedValue({
|
||||
artifacts: fixtures.artifacts.map(artifact => ({
|
||||
...fixtures.backendIds,
|
||||
databaseId: artifact.id.toString(),
|
||||
name: artifact.name,
|
||||
size: artifact.size.toString(),
|
||||
createdAt: Timestamp.fromDate(artifact.createdAt)
|
||||
}))
|
||||
})
|
||||
const response = await listArtifactsInternal(false)
|
||||
expect(response).toEqual({
|
||||
artifacts: fixtures.artifacts
|
||||
})
|
||||
})
|
||||
|
||||
it('should return the latest artifact when latest is specified', async () => {
|
||||
jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
|
||||
.mockResolvedValue({
|
||||
artifacts: fixtures.artifacts.map(artifact => ({
|
||||
...fixtures.backendIds,
|
||||
databaseId: artifact.id.toString(),
|
||||
name: artifact.name,
|
||||
size: artifact.size.toString(),
|
||||
createdAt: Timestamp.fromDate(artifact.createdAt)
|
||||
}))
|
||||
})
|
||||
const response = await listArtifactsInternal(true)
|
||||
expect(response).toEqual({
|
||||
artifacts: [fixtures.artifacts[1]]
|
||||
})
|
||||
})
|
||||
|
||||
it('can return empty artifacts', async () => {
|
||||
jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
|
||||
.mockResolvedValue({
|
||||
artifacts: []
|
||||
})
|
||||
const response = await listArtifactsInternal(false)
|
||||
expect(response).toEqual({
|
||||
artifacts: []
|
||||
})
|
||||
})
|
||||
|
||||
it('should fail if non-200 response', async () => {
|
||||
jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'ListArtifacts')
|
||||
.mockRejectedValue(new Error('boom'))
|
||||
await expect(listArtifactsInternal(false)).rejects.toThrow('boom')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,75 @@
|
||||
import {
|
||||
validateArtifactName,
|
||||
validateFilePath
|
||||
} from '../src/internal/upload/path-and-artifact-name-validation'
|
||||
|
||||
import {noopLogs} from './common'
|
||||
|
||||
describe('Path and artifact name validation', () => {
|
||||
beforeAll(() => {
|
||||
noopLogs()
|
||||
})
|
||||
|
||||
it('Check Artifact Name for any invalid characters', () => {
|
||||
const invalidNames = [
|
||||
'my\\artifact',
|
||||
'my/artifact',
|
||||
'my"artifact',
|
||||
'my:artifact',
|
||||
'my<artifact',
|
||||
'my>artifact',
|
||||
'my|artifact',
|
||||
'my*artifact',
|
||||
'my?artifact',
|
||||
''
|
||||
]
|
||||
for (const invalidName of invalidNames) {
|
||||
expect(() => {
|
||||
validateArtifactName(invalidName)
|
||||
}).toThrow()
|
||||
}
|
||||
|
||||
const validNames = [
|
||||
'my-normal-artifact',
|
||||
'myNormalArtifact',
|
||||
'm¥ñðrmålÄr†ï£å¢†'
|
||||
]
|
||||
for (const validName of validNames) {
|
||||
expect(() => {
|
||||
validateArtifactName(validName)
|
||||
}).not.toThrow()
|
||||
}
|
||||
})
|
||||
|
||||
it('Check Artifact File Path for any invalid characters', () => {
|
||||
const invalidNames = [
|
||||
'some/invalid"artifact/path',
|
||||
'some/invalid:artifact/path',
|
||||
'some/invalid<artifact/path',
|
||||
'some/invalid>artifact/path',
|
||||
'some/invalid|artifact/path',
|
||||
'some/invalid*artifact/path',
|
||||
'some/invalid?artifact/path',
|
||||
'some/invalid\rartifact/path',
|
||||
'some/invalid\nartifact/path',
|
||||
'some/invalid\r\nartifact/path',
|
||||
''
|
||||
]
|
||||
for (const invalidName of invalidNames) {
|
||||
expect(() => {
|
||||
validateFilePath(invalidName)
|
||||
}).toThrow()
|
||||
}
|
||||
|
||||
const validNames = [
|
||||
'my/perfectly-normal/artifact-path',
|
||||
'my/perfectly\\Normal/Artifact-path',
|
||||
'm¥/ñðrmål/Är†ï£å¢†'
|
||||
]
|
||||
for (const validName of validNames) {
|
||||
expect(() => {
|
||||
validateFilePath(validName)
|
||||
}).not.toThrow()
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,65 @@
|
||||
import {Timestamp} from '../src/generated'
|
||||
import * as retention from '../src/internal/upload/retention'
|
||||
|
||||
describe('retention', () => {
|
||||
beforeEach(() => {
|
||||
delete process.env['GITHUB_RETENTION_DAYS']
|
||||
})
|
||||
it('should return the inputted retention days if it is less than the max retention days', () => {
|
||||
// setup
|
||||
const mockDate = new Date('2020-01-01')
|
||||
jest.useFakeTimers().setSystemTime(mockDate)
|
||||
process.env['GITHUB_RETENTION_DAYS'] = '90'
|
||||
|
||||
const exp = retention.getExpiration(30)
|
||||
|
||||
expect(exp).toBeDefined()
|
||||
if (exp) {
|
||||
const expDate = Timestamp.toDate(exp)
|
||||
const expected = new Date()
|
||||
expected.setDate(expected.getDate() + 30)
|
||||
|
||||
expect(expDate).toEqual(expected)
|
||||
}
|
||||
})
|
||||
|
||||
it('should return the max retention days if the inputted retention days is greater than the max retention days', () => {
|
||||
// setup
|
||||
const mockDate = new Date('2020-01-01')
|
||||
jest.useFakeTimers().setSystemTime(mockDate)
|
||||
process.env['GITHUB_RETENTION_DAYS'] = '90'
|
||||
|
||||
const exp = retention.getExpiration(120)
|
||||
|
||||
expect(exp).toBeDefined()
|
||||
if (exp) {
|
||||
const expDate = Timestamp.toDate(exp) // we check whether exp is defined above
|
||||
const expected = new Date()
|
||||
expected.setDate(expected.getDate() + 90)
|
||||
|
||||
expect(expDate).toEqual(expected)
|
||||
}
|
||||
})
|
||||
|
||||
it('should return undefined if the inputted retention days is undefined', () => {
|
||||
const exp = retention.getExpiration()
|
||||
expect(exp).toBeUndefined()
|
||||
})
|
||||
|
||||
it('should return the inputted retention days if there is no max retention days', () => {
|
||||
// setup
|
||||
const mockDate = new Date('2020-01-01')
|
||||
jest.useFakeTimers().setSystemTime(mockDate)
|
||||
|
||||
const exp = retention.getExpiration(30)
|
||||
|
||||
expect(exp).toBeDefined()
|
||||
if (exp) {
|
||||
const expDate = Timestamp.toDate(exp) // we check whether exp is defined above
|
||||
const expected = new Date()
|
||||
expected.setDate(expected.getDate() + 30)
|
||||
|
||||
expect(expDate).toEqual(expected)
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -1,27 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
path="$1"
|
||||
expectedContent="$2"
|
||||
|
||||
if [ "$path" == "" ]; then
|
||||
echo "File path not provided"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$expectedContent" == "" ]; then
|
||||
echo "Expected file contents not provided"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$path" ]; then
|
||||
echo "Expected file $path does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
actualContent=$(cat "$path")
|
||||
if [ "$expectedContent" == "_EMPTY_" ] && [ ! -s "$path" ]; then
|
||||
exit 0
|
||||
elif [ "$actualContent" != "$expectedContent" ]; then
|
||||
echo "File contents are not correct, expected $expectedContent, received $actualContent"
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,354 @@
|
||||
import * as uploadZipSpecification from '../src/internal/upload/upload-zip-specification'
|
||||
import * as zip from '../src/internal/upload/zip'
|
||||
import * as util from '../src/internal/shared/util'
|
||||
import * as retention from '../src/internal/upload/retention'
|
||||
import * as config from '../src/internal/shared/config'
|
||||
import {Timestamp, ArtifactServiceClientJSON} from '../src/generated'
|
||||
import * as blobUpload from '../src/internal/upload/blob-upload'
|
||||
import {uploadArtifact} from '../src/internal/upload/upload-artifact'
|
||||
import {noopLogs} from './common'
|
||||
import {FilesNotFoundError} from '../src/internal/shared/errors'
|
||||
|
||||
describe('upload-artifact', () => {
|
||||
beforeEach(() => {
|
||||
noopLogs()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks()
|
||||
})
|
||||
|
||||
it('should successfully upload an artifact', () => {
|
||||
const mockDate = new Date('2020-01-01')
|
||||
jest
|
||||
.spyOn(uploadZipSpecification, 'validateRootDirectory')
|
||||
.mockReturnValue()
|
||||
jest
|
||||
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
|
||||
.mockReturnValue([
|
||||
{
|
||||
sourcePath: '/home/user/files/plz-upload/file1.txt',
|
||||
destinationPath: 'file1.txt'
|
||||
},
|
||||
{
|
||||
sourcePath: '/home/user/files/plz-upload/file2.txt',
|
||||
destinationPath: 'file2.txt'
|
||||
},
|
||||
{
|
||||
sourcePath: '/home/user/files/plz-upload/dir/file3.txt',
|
||||
destinationPath: 'dir/file3.txt'
|
||||
}
|
||||
])
|
||||
|
||||
jest
|
||||
.spyOn(zip, 'createZipUploadStream')
|
||||
.mockReturnValue(Promise.resolve(new zip.ZipUploadStream(1)))
|
||||
jest.spyOn(util, 'getBackendIdsFromToken').mockReturnValue({
|
||||
workflowRunBackendId: '1234',
|
||||
workflowJobRunBackendId: '5678'
|
||||
})
|
||||
jest
|
||||
.spyOn(retention, 'getExpiration')
|
||||
.mockReturnValue(Timestamp.fromDate(mockDate))
|
||||
jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'CreateArtifact')
|
||||
.mockReturnValue(
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
signedUploadUrl: 'https://signed-upload-url.com'
|
||||
})
|
||||
)
|
||||
jest.spyOn(blobUpload, 'uploadZipToBlobStorage').mockReturnValue(
|
||||
Promise.resolve({
|
||||
uploadSize: 1234,
|
||||
sha256Hash: 'test-sha256-hash'
|
||||
})
|
||||
)
|
||||
jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'FinalizeArtifact')
|
||||
.mockReturnValue(Promise.resolve({ok: true, artifactId: '1'}))
|
||||
|
||||
// ArtifactHttpClient mocks
|
||||
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token')
|
||||
jest
|
||||
.spyOn(config, 'getResultsServiceUrl')
|
||||
.mockReturnValue('https://test-url.com')
|
||||
|
||||
const uploadResp = uploadArtifact(
|
||||
'test-artifact',
|
||||
[
|
||||
'/home/user/files/plz-upload/file1.txt',
|
||||
'/home/user/files/plz-upload/file2.txt',
|
||||
'/home/user/files/plz-upload/dir/file3.txt'
|
||||
],
|
||||
'/home/user/files/plz-upload'
|
||||
)
|
||||
|
||||
expect(uploadResp).resolves.toEqual({size: 1234, id: 1})
|
||||
})
|
||||
|
||||
it('should throw an error if the root directory is invalid', () => {
|
||||
jest
|
||||
.spyOn(uploadZipSpecification, 'validateRootDirectory')
|
||||
.mockImplementation(() => {
|
||||
throw new Error('Invalid root directory')
|
||||
})
|
||||
|
||||
const uploadResp = uploadArtifact(
|
||||
'test-artifact',
|
||||
[
|
||||
'/home/user/files/plz-upload/file1.txt',
|
||||
'/home/user/files/plz-upload/file2.txt',
|
||||
'/home/user/files/plz-upload/dir/file3.txt'
|
||||
],
|
||||
'/home/user/files/plz-upload'
|
||||
)
|
||||
|
||||
expect(uploadResp).rejects.toThrow('Invalid root directory')
|
||||
})
|
||||
|
||||
it('should reject if there are no files to upload', () => {
|
||||
jest
|
||||
.spyOn(uploadZipSpecification, 'validateRootDirectory')
|
||||
.mockReturnValue()
|
||||
jest
|
||||
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
|
||||
.mockReturnValue([])
|
||||
|
||||
const uploadResp = uploadArtifact(
|
||||
'test-artifact',
|
||||
[
|
||||
'/home/user/files/plz-upload/file1.txt',
|
||||
'/home/user/files/plz-upload/file2.txt',
|
||||
'/home/user/files/plz-upload/dir/file3.txt'
|
||||
],
|
||||
'/home/user/files/plz-upload'
|
||||
)
|
||||
expect(uploadResp).rejects.toThrowError(FilesNotFoundError)
|
||||
})
|
||||
|
||||
it('should reject if no backend IDs are found', () => {
|
||||
jest
|
||||
.spyOn(uploadZipSpecification, 'validateRootDirectory')
|
||||
.mockReturnValue()
|
||||
jest
|
||||
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
|
||||
.mockReturnValue([
|
||||
{
|
||||
sourcePath: '/home/user/files/plz-upload/file1.txt',
|
||||
destinationPath: 'file1.txt'
|
||||
},
|
||||
{
|
||||
sourcePath: '/home/user/files/plz-upload/file2.txt',
|
||||
destinationPath: 'file2.txt'
|
||||
},
|
||||
{
|
||||
sourcePath: '/home/user/files/plz-upload/dir/file3.txt',
|
||||
destinationPath: 'dir/file3.txt'
|
||||
}
|
||||
])
|
||||
|
||||
jest
|
||||
.spyOn(zip, 'createZipUploadStream')
|
||||
.mockReturnValue(Promise.resolve(new zip.ZipUploadStream(1)))
|
||||
|
||||
const uploadResp = uploadArtifact(
|
||||
'test-artifact',
|
||||
[
|
||||
'/home/user/files/plz-upload/file1.txt',
|
||||
'/home/user/files/plz-upload/file2.txt',
|
||||
'/home/user/files/plz-upload/dir/file3.txt'
|
||||
],
|
||||
'/home/user/files/plz-upload'
|
||||
)
|
||||
|
||||
expect(uploadResp).rejects.toThrow()
|
||||
})
|
||||
|
||||
it('should return false if the creation request fails', () => {
|
||||
const mockDate = new Date('2020-01-01')
|
||||
jest
|
||||
.spyOn(uploadZipSpecification, 'validateRootDirectory')
|
||||
.mockReturnValue()
|
||||
jest
|
||||
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
|
||||
.mockReturnValue([
|
||||
{
|
||||
sourcePath: '/home/user/files/plz-upload/file1.txt',
|
||||
destinationPath: 'file1.txt'
|
||||
},
|
||||
{
|
||||
sourcePath: '/home/user/files/plz-upload/file2.txt',
|
||||
destinationPath: 'file2.txt'
|
||||
},
|
||||
{
|
||||
sourcePath: '/home/user/files/plz-upload/dir/file3.txt',
|
||||
destinationPath: 'dir/file3.txt'
|
||||
}
|
||||
])
|
||||
|
||||
jest
|
||||
.spyOn(zip, 'createZipUploadStream')
|
||||
.mockReturnValue(Promise.resolve(new zip.ZipUploadStream(1)))
|
||||
jest.spyOn(util, 'getBackendIdsFromToken').mockReturnValue({
|
||||
workflowRunBackendId: '1234',
|
||||
workflowJobRunBackendId: '5678'
|
||||
})
|
||||
jest
|
||||
.spyOn(retention, 'getExpiration')
|
||||
.mockReturnValue(Timestamp.fromDate(mockDate))
|
||||
jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'CreateArtifact')
|
||||
.mockReturnValue(Promise.resolve({ok: false, signedUploadUrl: ''}))
|
||||
|
||||
// ArtifactHttpClient mocks
|
||||
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token')
|
||||
jest
|
||||
.spyOn(config, 'getResultsServiceUrl')
|
||||
.mockReturnValue('https://test-url.com')
|
||||
|
||||
const uploadResp = uploadArtifact(
|
||||
'test-artifact',
|
||||
[
|
||||
'/home/user/files/plz-upload/file1.txt',
|
||||
'/home/user/files/plz-upload/file2.txt',
|
||||
'/home/user/files/plz-upload/dir/file3.txt'
|
||||
],
|
||||
'/home/user/files/plz-upload'
|
||||
)
|
||||
|
||||
expect(uploadResp).rejects.toThrow()
|
||||
})
|
||||
|
||||
it('should return false if blob storage upload is unsuccessful', () => {
|
||||
const mockDate = new Date('2020-01-01')
|
||||
jest
|
||||
.spyOn(uploadZipSpecification, 'validateRootDirectory')
|
||||
.mockReturnValue()
|
||||
jest
|
||||
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
|
||||
.mockReturnValue([
|
||||
{
|
||||
sourcePath: '/home/user/files/plz-upload/file1.txt',
|
||||
destinationPath: 'file1.txt'
|
||||
},
|
||||
{
|
||||
sourcePath: '/home/user/files/plz-upload/file2.txt',
|
||||
destinationPath: 'file2.txt'
|
||||
},
|
||||
{
|
||||
sourcePath: '/home/user/files/plz-upload/dir/file3.txt',
|
||||
destinationPath: 'dir/file3.txt'
|
||||
}
|
||||
])
|
||||
|
||||
jest
|
||||
.spyOn(zip, 'createZipUploadStream')
|
||||
.mockReturnValue(Promise.resolve(new zip.ZipUploadStream(1)))
|
||||
jest.spyOn(util, 'getBackendIdsFromToken').mockReturnValue({
|
||||
workflowRunBackendId: '1234',
|
||||
workflowJobRunBackendId: '5678'
|
||||
})
|
||||
jest
|
||||
.spyOn(retention, 'getExpiration')
|
||||
.mockReturnValue(Timestamp.fromDate(mockDate))
|
||||
jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'CreateArtifact')
|
||||
.mockReturnValue(
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
signedUploadUrl: 'https://signed-upload-url.com'
|
||||
})
|
||||
)
|
||||
jest
|
||||
.spyOn(blobUpload, 'uploadZipToBlobStorage')
|
||||
.mockReturnValue(Promise.reject(new Error('boom')))
|
||||
|
||||
// ArtifactHttpClient mocks
|
||||
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token')
|
||||
jest
|
||||
.spyOn(config, 'getResultsServiceUrl')
|
||||
.mockReturnValue('https://test-url.com')
|
||||
|
||||
const uploadResp = uploadArtifact(
|
||||
'test-artifact',
|
||||
[
|
||||
'/home/user/files/plz-upload/file1.txt',
|
||||
'/home/user/files/plz-upload/file2.txt',
|
||||
'/home/user/files/plz-upload/dir/file3.txt'
|
||||
],
|
||||
'/home/user/files/plz-upload'
|
||||
)
|
||||
|
||||
expect(uploadResp).rejects.toThrow()
|
||||
})
|
||||
|
||||
it('should reject if finalize artifact fails', () => {
|
||||
const mockDate = new Date('2020-01-01')
|
||||
jest
|
||||
.spyOn(uploadZipSpecification, 'validateRootDirectory')
|
||||
.mockReturnValue()
|
||||
jest
|
||||
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
|
||||
.mockReturnValue([
|
||||
{
|
||||
sourcePath: '/home/user/files/plz-upload/file1.txt',
|
||||
destinationPath: 'file1.txt'
|
||||
},
|
||||
{
|
||||
sourcePath: '/home/user/files/plz-upload/file2.txt',
|
||||
destinationPath: 'file2.txt'
|
||||
},
|
||||
{
|
||||
sourcePath: '/home/user/files/plz-upload/dir/file3.txt',
|
||||
destinationPath: 'dir/file3.txt'
|
||||
}
|
||||
])
|
||||
|
||||
jest
|
||||
.spyOn(zip, 'createZipUploadStream')
|
||||
.mockReturnValue(Promise.resolve(new zip.ZipUploadStream(1)))
|
||||
jest.spyOn(util, 'getBackendIdsFromToken').mockReturnValue({
|
||||
workflowRunBackendId: '1234',
|
||||
workflowJobRunBackendId: '5678'
|
||||
})
|
||||
jest
|
||||
.spyOn(retention, 'getExpiration')
|
||||
.mockReturnValue(Timestamp.fromDate(mockDate))
|
||||
jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'CreateArtifact')
|
||||
.mockReturnValue(
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
signedUploadUrl: 'https://signed-upload-url.com'
|
||||
})
|
||||
)
|
||||
jest.spyOn(blobUpload, 'uploadZipToBlobStorage').mockReturnValue(
|
||||
Promise.resolve({
|
||||
uploadSize: 1234,
|
||||
sha256Hash: 'test-sha256-hash'
|
||||
})
|
||||
)
|
||||
jest
|
||||
.spyOn(ArtifactServiceClientJSON.prototype, 'FinalizeArtifact')
|
||||
.mockReturnValue(Promise.resolve({ok: false, artifactId: ''}))
|
||||
|
||||
// ArtifactHttpClient mocks
|
||||
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token')
|
||||
jest
|
||||
.spyOn(config, 'getResultsServiceUrl')
|
||||
.mockReturnValue('https://test-url.com')
|
||||
|
||||
const uploadResp = uploadArtifact(
|
||||
'test-artifact',
|
||||
[
|
||||
'/home/user/files/plz-upload/file1.txt',
|
||||
'/home/user/files/plz-upload/file2.txt',
|
||||
'/home/user/files/plz-upload/dir/file3.txt'
|
||||
],
|
||||
'/home/user/files/plz-upload'
|
||||
)
|
||||
|
||||
expect(uploadResp).rejects.toThrow()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,308 @@
|
||||
import * as io from '../../io/src/io'
|
||||
import * as path from 'path'
|
||||
import {promises as fs} from 'fs'
|
||||
import {
|
||||
getUploadZipSpecification,
|
||||
validateRootDirectory
|
||||
} from '../src/internal/upload/upload-zip-specification'
|
||||
import {noopLogs} from './common'
|
||||
|
||||
const root = path.join(__dirname, '_temp', 'upload-specification')
|
||||
const goodItem1Path = path.join(
|
||||
root,
|
||||
'folder-a',
|
||||
'folder-b',
|
||||
'folder-c',
|
||||
'good-item1.txt'
|
||||
)
|
||||
const goodItem2Path = path.join(root, 'folder-d', 'good-item2.txt')
|
||||
const goodItem3Path = path.join(root, 'folder-d', 'good-item3.txt')
|
||||
const goodItem4Path = path.join(root, 'folder-d', 'good-item4.txt')
|
||||
const goodItem5Path = path.join(root, 'good-item5.txt')
|
||||
const badItem1Path = path.join(
|
||||
root,
|
||||
'folder-a',
|
||||
'folder-b',
|
||||
'folder-c',
|
||||
'bad-item1.txt'
|
||||
)
|
||||
const badItem2Path = path.join(root, 'folder-d', 'bad-item2.txt')
|
||||
const badItem3Path = path.join(root, 'folder-f', 'bad-item3.txt')
|
||||
const badItem4Path = path.join(root, 'folder-h', 'folder-i', 'bad-item4.txt')
|
||||
const badItem5Path = path.join(root, 'folder-h', 'folder-i', 'bad-item5.txt')
|
||||
const extraFileInFolderCPath = path.join(
|
||||
root,
|
||||
'folder-a',
|
||||
'folder-b',
|
||||
'folder-c',
|
||||
'extra-file-in-folder-c.txt'
|
||||
)
|
||||
const amazingFileInFolderHPath = path.join(root, 'folder-h', 'amazing-item.txt')
|
||||
|
||||
const artifactFilesToUpload = [
|
||||
goodItem1Path,
|
||||
goodItem2Path,
|
||||
goodItem3Path,
|
||||
goodItem4Path,
|
||||
goodItem5Path,
|
||||
extraFileInFolderCPath,
|
||||
amazingFileInFolderHPath
|
||||
]
|
||||
|
||||
describe('Search', () => {
|
||||
beforeAll(async () => {
|
||||
noopLogs()
|
||||
|
||||
// clear temp directory
|
||||
await io.rmRF(root)
|
||||
await fs.mkdir(path.join(root, 'folder-a', 'folder-b', 'folder-c'), {
|
||||
recursive: true
|
||||
})
|
||||
await fs.mkdir(path.join(root, 'folder-a', 'folder-b', 'folder-e'), {
|
||||
recursive: true
|
||||
})
|
||||
await fs.mkdir(path.join(root, 'folder-d'), {
|
||||
recursive: true
|
||||
})
|
||||
await fs.mkdir(path.join(root, 'folder-f'), {
|
||||
recursive: true
|
||||
})
|
||||
await fs.mkdir(path.join(root, 'folder-g'), {
|
||||
recursive: true
|
||||
})
|
||||
await fs.mkdir(path.join(root, 'folder-h', 'folder-i'), {
|
||||
recursive: true
|
||||
})
|
||||
|
||||
await fs.writeFile(goodItem1Path, 'good item1 file')
|
||||
await fs.writeFile(goodItem2Path, 'good item2 file')
|
||||
await fs.writeFile(goodItem3Path, 'good item3 file')
|
||||
await fs.writeFile(goodItem4Path, 'good item4 file')
|
||||
await fs.writeFile(goodItem5Path, 'good item5 file')
|
||||
|
||||
await fs.writeFile(badItem1Path, 'bad item1 file')
|
||||
await fs.writeFile(badItem2Path, 'bad item2 file')
|
||||
await fs.writeFile(badItem3Path, 'bad item3 file')
|
||||
await fs.writeFile(badItem4Path, 'bad item4 file')
|
||||
await fs.writeFile(badItem5Path, 'bad item5 file')
|
||||
|
||||
await fs.writeFile(extraFileInFolderCPath, 'extra file')
|
||||
|
||||
await fs.writeFile(amazingFileInFolderHPath, 'amazing file')
|
||||
/*
|
||||
Directory structure of files that get created:
|
||||
root/
|
||||
folder-a/
|
||||
folder-b/
|
||||
folder-c/
|
||||
good-item1.txt
|
||||
bad-item1.txt
|
||||
extra-file-in-folder-c.txt
|
||||
folder-e/
|
||||
folder-d/
|
||||
good-item2.txt
|
||||
good-item3.txt
|
||||
good-item4.txt
|
||||
bad-item2.txt
|
||||
folder-f/
|
||||
bad-item3.txt
|
||||
folder-g/
|
||||
folder-h/
|
||||
amazing-item.txt
|
||||
folder-i/
|
||||
bad-item4.txt
|
||||
bad-item5.txt
|
||||
good-item5.txt
|
||||
*/
|
||||
})
|
||||
|
||||
it('Upload Specification - Fail non-existent rootDirectory', async () => {
|
||||
const invalidRootDirectory = path.join(
|
||||
__dirname,
|
||||
'_temp',
|
||||
'upload-specification-invalid'
|
||||
)
|
||||
expect(() => {
|
||||
validateRootDirectory(invalidRootDirectory)
|
||||
}).toThrow(
|
||||
`The provided rootDirectory ${invalidRootDirectory} does not exist`
|
||||
)
|
||||
})
|
||||
|
||||
it('Upload Specification - Fail invalid rootDirectory', async () => {
|
||||
expect(() => {
|
||||
validateRootDirectory(goodItem1Path)
|
||||
}).toThrow(
|
||||
`The provided rootDirectory ${goodItem1Path} is not a valid directory`
|
||||
)
|
||||
})
|
||||
|
||||
it('Upload Specification - File does not exist', async () => {
|
||||
const fakeFilePath = path.join(
|
||||
'folder-a',
|
||||
'folder-b',
|
||||
'non-existent-file.txt'
|
||||
)
|
||||
expect(() => {
|
||||
getUploadZipSpecification([fakeFilePath], root)
|
||||
}).toThrow(`File ${fakeFilePath} does not exist`)
|
||||
})
|
||||
|
||||
it('Upload Specification - Non parent directory', async () => {
|
||||
const folderADirectory = path.join(root, 'folder-a')
|
||||
const artifactFiles = [
|
||||
goodItem1Path,
|
||||
badItem1Path,
|
||||
extraFileInFolderCPath,
|
||||
goodItem5Path
|
||||
]
|
||||
expect(() => {
|
||||
getUploadZipSpecification(artifactFiles, folderADirectory)
|
||||
}).toThrow(
|
||||
`The rootDirectory: ${folderADirectory} is not a parent directory of the file: ${goodItem5Path}`
|
||||
)
|
||||
})
|
||||
|
||||
it('Upload Specification - Success', async () => {
|
||||
const specifications = getUploadZipSpecification(
|
||||
artifactFilesToUpload,
|
||||
root
|
||||
)
|
||||
expect(specifications.length).toEqual(7)
|
||||
|
||||
const absolutePaths = specifications.map(item => item.sourcePath)
|
||||
expect(absolutePaths).toContain(goodItem1Path)
|
||||
expect(absolutePaths).toContain(goodItem2Path)
|
||||
expect(absolutePaths).toContain(goodItem3Path)
|
||||
expect(absolutePaths).toContain(goodItem4Path)
|
||||
expect(absolutePaths).toContain(goodItem5Path)
|
||||
expect(absolutePaths).toContain(extraFileInFolderCPath)
|
||||
expect(absolutePaths).toContain(amazingFileInFolderHPath)
|
||||
|
||||
for (const specification of specifications) {
|
||||
if (specification.sourcePath === goodItem1Path) {
|
||||
expect(specification.destinationPath).toEqual(
|
||||
path.join('/folder-a', 'folder-b', 'folder-c', 'good-item1.txt')
|
||||
)
|
||||
} else if (specification.sourcePath === goodItem2Path) {
|
||||
expect(specification.destinationPath).toEqual(
|
||||
path.join('/folder-d', 'good-item2.txt')
|
||||
)
|
||||
} else if (specification.sourcePath === goodItem3Path) {
|
||||
expect(specification.destinationPath).toEqual(
|
||||
path.join('/folder-d', 'good-item3.txt')
|
||||
)
|
||||
} else if (specification.sourcePath === goodItem4Path) {
|
||||
expect(specification.destinationPath).toEqual(
|
||||
path.join('/folder-d', 'good-item4.txt')
|
||||
)
|
||||
} else if (specification.sourcePath === goodItem5Path) {
|
||||
expect(specification.destinationPath).toEqual(
|
||||
path.join('/good-item5.txt')
|
||||
)
|
||||
} else if (specification.sourcePath === extraFileInFolderCPath) {
|
||||
expect(specification.destinationPath).toEqual(
|
||||
path.join(
|
||||
'/folder-a',
|
||||
'folder-b',
|
||||
'folder-c',
|
||||
'extra-file-in-folder-c.txt'
|
||||
)
|
||||
)
|
||||
} else if (specification.sourcePath === amazingFileInFolderHPath) {
|
||||
expect(specification.destinationPath).toEqual(
|
||||
path.join('/folder-h', 'amazing-item.txt')
|
||||
)
|
||||
} else {
|
||||
throw new Error(
|
||||
'Invalid specification found. This should never be reached'
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('Upload Specification - Success with extra slash', async () => {
|
||||
const rootWithSlash = `${root}/`
|
||||
const specifications = getUploadZipSpecification(
|
||||
artifactFilesToUpload,
|
||||
rootWithSlash
|
||||
)
|
||||
expect(specifications.length).toEqual(7)
|
||||
|
||||
const absolutePaths = specifications.map(item => item.sourcePath)
|
||||
expect(absolutePaths).toContain(goodItem1Path)
|
||||
expect(absolutePaths).toContain(goodItem2Path)
|
||||
expect(absolutePaths).toContain(goodItem3Path)
|
||||
expect(absolutePaths).toContain(goodItem4Path)
|
||||
expect(absolutePaths).toContain(goodItem5Path)
|
||||
expect(absolutePaths).toContain(extraFileInFolderCPath)
|
||||
expect(absolutePaths).toContain(amazingFileInFolderHPath)
|
||||
|
||||
for (const specification of specifications) {
|
||||
if (specification.sourcePath === goodItem1Path) {
|
||||
expect(specification.destinationPath).toEqual(
|
||||
path.join('/folder-a', 'folder-b', 'folder-c', 'good-item1.txt')
|
||||
)
|
||||
} else if (specification.sourcePath === goodItem2Path) {
|
||||
expect(specification.destinationPath).toEqual(
|
||||
path.join('/folder-d', 'good-item2.txt')
|
||||
)
|
||||
} else if (specification.sourcePath === goodItem3Path) {
|
||||
expect(specification.destinationPath).toEqual(
|
||||
path.join('/folder-d', 'good-item3.txt')
|
||||
)
|
||||
} else if (specification.sourcePath === goodItem4Path) {
|
||||
expect(specification.destinationPath).toEqual(
|
||||
path.join('/folder-d', 'good-item4.txt')
|
||||
)
|
||||
} else if (specification.sourcePath === goodItem5Path) {
|
||||
expect(specification.destinationPath).toEqual(
|
||||
path.join('/good-item5.txt')
|
||||
)
|
||||
} else if (specification.sourcePath === extraFileInFolderCPath) {
|
||||
expect(specification.destinationPath).toEqual(
|
||||
path.join(
|
||||
'/folder-a',
|
||||
'folder-b',
|
||||
'folder-c',
|
||||
'extra-file-in-folder-c.txt'
|
||||
)
|
||||
)
|
||||
} else if (specification.sourcePath === amazingFileInFolderHPath) {
|
||||
expect(specification.destinationPath).toEqual(
|
||||
path.join('/folder-h', 'amazing-item.txt')
|
||||
)
|
||||
} else {
|
||||
throw new Error(
|
||||
'Invalid specification found. This should never be reached'
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('Upload Specification - Empty Directories are included', async () => {
|
||||
const folderEPath = path.join(root, 'folder-a', 'folder-b', 'folder-e')
|
||||
const filesWithDirectory = [goodItem1Path, folderEPath]
|
||||
const specifications = getUploadZipSpecification(filesWithDirectory, root)
|
||||
expect(specifications.length).toEqual(2)
|
||||
const absolutePaths = specifications.map(item => item.sourcePath)
|
||||
expect(absolutePaths).toContain(goodItem1Path)
|
||||
expect(absolutePaths).toContain(null)
|
||||
|
||||
for (const specification of specifications) {
|
||||
if (specification.sourcePath === goodItem1Path) {
|
||||
expect(specification.destinationPath).toEqual(
|
||||
path.join('/folder-a', 'folder-b', 'folder-c', 'good-item1.txt')
|
||||
)
|
||||
} else if (specification.sourcePath === null) {
|
||||
expect(specification.destinationPath).toEqual(
|
||||
path.join('/folder-a', 'folder-b', 'folder-e')
|
||||
)
|
||||
} else {
|
||||
throw new Error(
|
||||
'Invalid specification found. This should never be reached'
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,61 @@
|
||||
import * as config from '../src/internal/shared/config'
|
||||
import * as util from '../src/internal/shared/util'
|
||||
|
||||
export const testRuntimeToken =
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwic2NwIjoiQWN0aW9ucy5FeGFtcGxlIEFjdGlvbnMuQW5vdGhlckV4YW1wbGU6dGVzdCBBY3Rpb25zLlJlc3VsdHM6Y2U3ZjU0YzctNjFjNy00YWFlLTg4N2YtMzBkYTQ3NWY1ZjFhOmNhMzk1MDg1LTA0MGEtNTI2Yi0yY2U4LWJkYzg1ZjY5Mjc3NCIsImlhdCI6MTUxNjIzOTAyMn0.XYnI_wHPBlUi1mqYveJnnkJhp4dlFjqxzRmISPsqfw8'
|
||||
|
||||
describe('get-backend-ids-from-token', () => {
|
||||
it('should return backend ids when the token is valid', () => {
|
||||
jest.spyOn(config, 'getRuntimeToken').mockReturnValue(testRuntimeToken)
|
||||
|
||||
const backendIds = util.getBackendIdsFromToken()
|
||||
expect(backendIds.workflowRunBackendId).toBe(
|
||||
'ce7f54c7-61c7-4aae-887f-30da475f5f1a'
|
||||
)
|
||||
expect(backendIds.workflowJobRunBackendId).toBe(
|
||||
'ca395085-040a-526b-2ce8-bdc85f692774'
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw an error when the token doesn't have the right scope", () => {
|
||||
jest
|
||||
.spyOn(config, 'getRuntimeToken')
|
||||
.mockReturnValue(
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwic2NwIjoiQWN0aW9ucy5FeGFtcGxlIEFjdGlvbnMuQW5vdGhlckV4YW1wbGU6dGVzdCIsImlhdCI6MTUxNjIzOTAyMn0.K0IEoULZteGevF38G94xiaA8zcZ5UlKWfGfqE6q3dhw'
|
||||
)
|
||||
|
||||
expect(util.getBackendIdsFromToken).toThrowError(
|
||||
'Failed to get backend IDs: The provided JWT token is invalid'
|
||||
)
|
||||
})
|
||||
|
||||
it('should throw an error when the token has a malformed scope', () => {
|
||||
jest
|
||||
.spyOn(config, 'getRuntimeToken')
|
||||
.mockReturnValue(
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwic2NwIjoiQWN0aW9ucy5FeGFtcGxlIEFjdGlvbnMuQW5vdGhlckV4YW1wbGU6dGVzdCBBY3Rpb25zLlJlc3VsdHM6Y2U3ZjU0YzctNjFjNy00YWFlLTg4N2YtMzBkYTQ3NWY1ZjFhIiwiaWF0IjoxNTE2MjM5MDIyfQ.7D0_LRfRFRZFImHQ7GxH2S6ZyFjjZ5U0ujjGCfle1XE'
|
||||
)
|
||||
|
||||
expect(util.getBackendIdsFromToken).toThrowError(
|
||||
'Failed to get backend IDs: The provided JWT token is invalid'
|
||||
)
|
||||
})
|
||||
|
||||
it('should throw an error when the token is in an invalid format', () => {
|
||||
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('token')
|
||||
|
||||
expect(util.getBackendIdsFromToken).toThrowError('Invalid token specified')
|
||||
})
|
||||
|
||||
it("should throw an error when the token doesn't have the right field", () => {
|
||||
jest
|
||||
.spyOn(config, 'getRuntimeToken')
|
||||
.mockReturnValue(
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
|
||||
)
|
||||
|
||||
expect(util.getBackendIdsFromToken).toThrowError(
|
||||
'Failed to get backend IDs: The provided JWT token is invalid'
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1 @@
|
||||
Docs will be added here once development of version `2.0.0` has finished
|
||||
Generated
+473
-868
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@actions/artifact",
|
||||
"version": "1.1.1",
|
||||
"version": "2.0.0",
|
||||
"preview": true,
|
||||
"description": "Actions artifact lib",
|
||||
"keywords": [
|
||||
@@ -30,23 +30,33 @@
|
||||
},
|
||||
"scripts": {
|
||||
"audit-moderate": "npm install && npm audit --json --audit-level=moderate > audit.json",
|
||||
"test": "echo \"Error: run tests from root\" && exit 1",
|
||||
"tsc": "tsc"
|
||||
"test": "cd ../../ && npm run test ./packages/artifact",
|
||||
"bootstrap": "cd ../../ && npm run bootstrap",
|
||||
"tsc-run": "tsc",
|
||||
"tsc": "npm run bootstrap && npm run tsc-run"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/actions/toolkit/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.0",
|
||||
"@actions/github": "^5.1.1",
|
||||
"@actions/http-client": "^2.1.0",
|
||||
"@azure/storage-blob": "^12.15.0",
|
||||
"@types/node": "^20.4.5",
|
||||
"archiver": "^5.3.1"
|
||||
"@octokit/core": "^3.5.1",
|
||||
"@octokit/plugin-request-log": "^1.0.4",
|
||||
"@octokit/plugin-retry": "^3.0.9",
|
||||
"@octokit/request-error": "^5.0.0",
|
||||
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
|
||||
"@types/unzipper": "^0.10.6",
|
||||
"archiver": "^5.3.1",
|
||||
"crypto": "^1.0.1",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"twirp-ts": "^2.5.0",
|
||||
"unzipper": "^0.10.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
|
||||
"@types/archiver": "^5.3.2",
|
||||
"twirp-ts": "^2.5.0",
|
||||
"typescript": "^3.9.10"
|
||||
"typescript": "^5.2.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import { ArtifactClient, Client} from './internal/client'
|
||||
import { UploadOptions } from './internal/upload/upload-options'
|
||||
import { UploadResponse } from './internal/upload/upload-response'
|
||||
import {ArtifactClient, Client} from './internal/client'
|
||||
|
||||
/**
|
||||
* Exported functionality that we want to expose for any users of @actions/artifact
|
||||
*/
|
||||
export {
|
||||
ArtifactClient,
|
||||
UploadOptions,
|
||||
UploadResponse,
|
||||
}
|
||||
export * from './internal/shared/interfaces'
|
||||
export * from './internal/shared/errors'
|
||||
export {ArtifactClient}
|
||||
|
||||
export function create(): ArtifactClient {
|
||||
return Client.create()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @generated by protobuf-ts 2.9.1 with parameter client_none,generate_dependencies
|
||||
// @generated by protobuf-ts 2.9.1 with parameter long_type_string,client_none,generate_dependencies
|
||||
// @generated from protobuf file "google/protobuf/timestamp.proto" (package "google.protobuf", syntax proto3)
|
||||
// tslint:disable
|
||||
//
|
||||
@@ -139,7 +139,7 @@ export interface Timestamp {
|
||||
*
|
||||
* @generated from protobuf field: int64 seconds = 1;
|
||||
*/
|
||||
seconds: bigint;
|
||||
seconds: string;
|
||||
/**
|
||||
* Non-negative fractions of a second at nanosecond resolution. Negative
|
||||
* second values with fractions must still have non-negative nanos values
|
||||
@@ -154,7 +154,7 @@ export interface Timestamp {
|
||||
class Timestamp$Type extends MessageType<Timestamp> {
|
||||
constructor() {
|
||||
super("google.protobuf.Timestamp", [
|
||||
{ no: 1, name: "seconds", kind: "scalar", T: 3 /*ScalarType.INT64*/, L: 0 /*LongType.BIGINT*/ },
|
||||
{ no: 1, name: "seconds", kind: "scalar", T: 3 /*ScalarType.INT64*/ },
|
||||
{ no: 2, name: "nanos", kind: "scalar", T: 5 /*ScalarType.INT32*/ }
|
||||
]);
|
||||
}
|
||||
@@ -164,7 +164,7 @@ class Timestamp$Type extends MessageType<Timestamp> {
|
||||
now(): Timestamp {
|
||||
const msg = this.create();
|
||||
const ms = Date.now();
|
||||
msg.seconds = PbLong.from(Math.floor(ms / 1000)).toBigInt();
|
||||
msg.seconds = PbLong.from(Math.floor(ms / 1000)).toString();
|
||||
msg.nanos = (ms % 1000) * 1000000;
|
||||
return msg;
|
||||
}
|
||||
@@ -180,7 +180,7 @@ class Timestamp$Type extends MessageType<Timestamp> {
|
||||
fromDate(date: Date): Timestamp {
|
||||
const msg = this.create();
|
||||
const ms = date.getTime();
|
||||
msg.seconds = PbLong.from(Math.floor(ms / 1000)).toBigInt();
|
||||
msg.seconds = PbLong.from(Math.floor(ms / 1000)).toString();
|
||||
msg.nanos = (ms % 1000) * 1000000;
|
||||
return msg;
|
||||
}
|
||||
@@ -223,14 +223,14 @@ class Timestamp$Type extends MessageType<Timestamp> {
|
||||
throw new globalThis.Error("Unable to parse Timestamp from JSON. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.");
|
||||
if (!target)
|
||||
target = this.create();
|
||||
target.seconds = PbLong.from(ms / 1000).toBigInt();
|
||||
target.seconds = PbLong.from(ms / 1000).toString();
|
||||
target.nanos = 0;
|
||||
if (matches[7])
|
||||
target.nanos = (parseInt("1" + matches[7] + "0".repeat(9 - matches[7].length)) - 1000000000);
|
||||
return target;
|
||||
}
|
||||
create(value?: PartialMessage<Timestamp>): Timestamp {
|
||||
const message = { seconds: 0n, nanos: 0 };
|
||||
const message = { seconds: "0", nanos: 0 };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<Timestamp>(this, message, value);
|
||||
@@ -242,7 +242,7 @@ class Timestamp$Type extends MessageType<Timestamp> {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* int64 seconds */ 1:
|
||||
message.seconds = reader.int64().toBigInt();
|
||||
message.seconds = reader.int64().toString();
|
||||
break;
|
||||
case /* int32 nanos */ 2:
|
||||
message.nanos = reader.int32();
|
||||
@@ -260,7 +260,7 @@ class Timestamp$Type extends MessageType<Timestamp> {
|
||||
}
|
||||
internalBinaryWrite(message: Timestamp, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* int64 seconds = 1; */
|
||||
if (message.seconds !== 0n)
|
||||
if (message.seconds !== "0")
|
||||
writer.tag(1, WireType.Varint).int64(message.seconds);
|
||||
/* int32 nanos = 2; */
|
||||
if (message.nanos !== 0)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @generated by protobuf-ts 2.9.1 with parameter client_none,generate_dependencies
|
||||
// @generated by protobuf-ts 2.9.1 with parameter long_type_string,client_none,generate_dependencies
|
||||
// @generated from protobuf file "google/protobuf/wrappers.proto" (package "google.protobuf", syntax proto3)
|
||||
// tslint:disable
|
||||
//
|
||||
@@ -96,7 +96,7 @@ export interface Int64Value {
|
||||
*
|
||||
* @generated from protobuf field: int64 value = 1;
|
||||
*/
|
||||
value: bigint;
|
||||
value: string;
|
||||
}
|
||||
/**
|
||||
* Wrapper message for `uint64`.
|
||||
@@ -111,7 +111,7 @@ export interface UInt64Value {
|
||||
*
|
||||
* @generated from protobuf field: uint64 value = 1;
|
||||
*/
|
||||
value: bigint;
|
||||
value: string;
|
||||
}
|
||||
/**
|
||||
* Wrapper message for `int32`.
|
||||
@@ -316,7 +316,7 @@ export const FloatValue = new FloatValue$Type();
|
||||
class Int64Value$Type extends MessageType<Int64Value> {
|
||||
constructor() {
|
||||
super("google.protobuf.Int64Value", [
|
||||
{ no: 1, name: "value", kind: "scalar", T: 3 /*ScalarType.INT64*/, L: 0 /*LongType.BIGINT*/ }
|
||||
{ no: 1, name: "value", kind: "scalar", T: 3 /*ScalarType.INT64*/ }
|
||||
]);
|
||||
}
|
||||
/**
|
||||
@@ -331,11 +331,11 @@ class Int64Value$Type extends MessageType<Int64Value> {
|
||||
internalJsonRead(json: JsonValue, options: JsonReadOptions, target?: Int64Value): Int64Value {
|
||||
if (!target)
|
||||
target = this.create();
|
||||
target.value = this.refJsonReader.scalar(json, ScalarType.INT64, LongType.BIGINT, "value") as any;
|
||||
target.value = this.refJsonReader.scalar(json, ScalarType.INT64, LongType.STRING, "value") as any;
|
||||
return target;
|
||||
}
|
||||
create(value?: PartialMessage<Int64Value>): Int64Value {
|
||||
const message = { value: 0n };
|
||||
const message = { value: "0" };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<Int64Value>(this, message, value);
|
||||
@@ -347,7 +347,7 @@ class Int64Value$Type extends MessageType<Int64Value> {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* int64 value */ 1:
|
||||
message.value = reader.int64().toBigInt();
|
||||
message.value = reader.int64().toString();
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
@@ -362,7 +362,7 @@ class Int64Value$Type extends MessageType<Int64Value> {
|
||||
}
|
||||
internalBinaryWrite(message: Int64Value, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* int64 value = 1; */
|
||||
if (message.value !== 0n)
|
||||
if (message.value !== "0")
|
||||
writer.tag(1, WireType.Varint).int64(message.value);
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
@@ -378,7 +378,7 @@ export const Int64Value = new Int64Value$Type();
|
||||
class UInt64Value$Type extends MessageType<UInt64Value> {
|
||||
constructor() {
|
||||
super("google.protobuf.UInt64Value", [
|
||||
{ no: 1, name: "value", kind: "scalar", T: 4 /*ScalarType.UINT64*/, L: 0 /*LongType.BIGINT*/ }
|
||||
{ no: 1, name: "value", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }
|
||||
]);
|
||||
}
|
||||
/**
|
||||
@@ -393,11 +393,11 @@ class UInt64Value$Type extends MessageType<UInt64Value> {
|
||||
internalJsonRead(json: JsonValue, options: JsonReadOptions, target?: UInt64Value): UInt64Value {
|
||||
if (!target)
|
||||
target = this.create();
|
||||
target.value = this.refJsonReader.scalar(json, ScalarType.UINT64, LongType.BIGINT, "value") as any;
|
||||
target.value = this.refJsonReader.scalar(json, ScalarType.UINT64, LongType.STRING, "value") as any;
|
||||
return target;
|
||||
}
|
||||
create(value?: PartialMessage<UInt64Value>): UInt64Value {
|
||||
const message = { value: 0n };
|
||||
const message = { value: "0" };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<UInt64Value>(this, message, value);
|
||||
@@ -409,7 +409,7 @@ class UInt64Value$Type extends MessageType<UInt64Value> {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* uint64 value */ 1:
|
||||
message.value = reader.uint64().toBigInt();
|
||||
message.value = reader.uint64().toString();
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
@@ -424,7 +424,7 @@ class UInt64Value$Type extends MessageType<UInt64Value> {
|
||||
}
|
||||
internalBinaryWrite(message: UInt64Value, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* uint64 value = 1; */
|
||||
if (message.value !== 0n)
|
||||
if (message.value !== "0")
|
||||
writer.tag(1, WireType.Varint).uint64(message.value);
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export * from "../generated/google/protobuf/timestamp";
|
||||
export * from "../generated/google/protobuf/wrappers";
|
||||
export * from "../generated/results/api/v1/artifact";
|
||||
export * from "../generated/results/api/v1/artifact.twirp";
|
||||
export * from './google/protobuf/timestamp'
|
||||
export * from './google/protobuf/wrappers'
|
||||
export * from './results/api/v1/artifact'
|
||||
export * from './results/api/v1/artifact.twirp'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// @generated by protobuf-ts 2.9.1 with parameter client_none,generate_dependencies
|
||||
// @generated by protobuf-ts 2.9.1 with parameter long_type_string,client_none,generate_dependencies
|
||||
// @generated from protobuf file "results/api/v1/artifact.proto" (package "github.actions.results.api.v1", syntax proto3)
|
||||
// tslint:disable
|
||||
import { ServiceType } from "@protobuf-ts/runtime-rpc";
|
||||
@@ -12,6 +12,7 @@ import type { PartialMessage } from "@protobuf-ts/runtime";
|
||||
import { reflectionMergePartial } from "@protobuf-ts/runtime";
|
||||
import { MESSAGE_TYPE } from "@protobuf-ts/runtime";
|
||||
import { MessageType } from "@protobuf-ts/runtime";
|
||||
import { Int64Value } from "../../../google/protobuf/wrappers";
|
||||
import { StringValue } from "../../../google/protobuf/wrappers";
|
||||
import { Timestamp } from "../../../google/protobuf/timestamp";
|
||||
/**
|
||||
@@ -71,7 +72,7 @@ export interface FinalizeArtifactRequest {
|
||||
/**
|
||||
* @generated from protobuf field: int64 size = 4;
|
||||
*/
|
||||
size: bigint;
|
||||
size: string;
|
||||
/**
|
||||
* @generated from protobuf field: google.protobuf.StringValue hash = 5;
|
||||
*/
|
||||
@@ -85,6 +86,115 @@ export interface FinalizeArtifactResponse {
|
||||
* @generated from protobuf field: bool ok = 1;
|
||||
*/
|
||||
ok: boolean;
|
||||
/**
|
||||
* @generated from protobuf field: int64 artifact_id = 2;
|
||||
*/
|
||||
artifactId: string;
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf message github.actions.results.api.v1.ListArtifactsRequest
|
||||
*/
|
||||
export interface ListArtifactsRequest {
|
||||
/**
|
||||
* The backend plan ID
|
||||
*
|
||||
* @generated from protobuf field: string workflow_run_backend_id = 1;
|
||||
*/
|
||||
workflowRunBackendId: string;
|
||||
/**
|
||||
* The backend job ID
|
||||
*
|
||||
* @generated from protobuf field: string workflow_job_run_backend_id = 2;
|
||||
*/
|
||||
workflowJobRunBackendId: string;
|
||||
/**
|
||||
* Name of the artifact to filter on
|
||||
*
|
||||
* @generated from protobuf field: google.protobuf.StringValue name_filter = 3;
|
||||
*/
|
||||
nameFilter?: StringValue; // optional
|
||||
/**
|
||||
* Monolith Database ID of the artifact to filter on
|
||||
*
|
||||
* @generated from protobuf field: google.protobuf.Int64Value id_filter = 4;
|
||||
*/
|
||||
idFilter?: Int64Value; // optional
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf message github.actions.results.api.v1.ListArtifactsResponse
|
||||
*/
|
||||
export interface ListArtifactsResponse {
|
||||
/**
|
||||
* @generated from protobuf field: repeated github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact artifacts = 1;
|
||||
*/
|
||||
artifacts: ListArtifactsResponse_MonolithArtifact[];
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf message github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact
|
||||
*/
|
||||
export interface ListArtifactsResponse_MonolithArtifact {
|
||||
/**
|
||||
* The backend plan ID
|
||||
*
|
||||
* @generated from protobuf field: string workflow_run_backend_id = 1;
|
||||
*/
|
||||
workflowRunBackendId: string;
|
||||
/**
|
||||
* The backend job ID
|
||||
*
|
||||
* @generated from protobuf field: string workflow_job_run_backend_id = 2;
|
||||
*/
|
||||
workflowJobRunBackendId: string;
|
||||
/**
|
||||
* Monolith database ID of the artifact
|
||||
*
|
||||
* @generated from protobuf field: int64 database_id = 3;
|
||||
*/
|
||||
databaseId: string;
|
||||
/**
|
||||
* Name of the artifact
|
||||
*
|
||||
* @generated from protobuf field: string name = 4;
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Size of the artifact in bytes
|
||||
*
|
||||
* @generated from protobuf field: int64 size = 5;
|
||||
*/
|
||||
size: string;
|
||||
/**
|
||||
* When the artifact was created in the monolith
|
||||
*
|
||||
* @generated from protobuf field: google.protobuf.Timestamp created_at = 6;
|
||||
*/
|
||||
createdAt?: Timestamp;
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf message github.actions.results.api.v1.GetSignedArtifactURLRequest
|
||||
*/
|
||||
export interface GetSignedArtifactURLRequest {
|
||||
/**
|
||||
* @generated from protobuf field: string workflow_run_backend_id = 1;
|
||||
*/
|
||||
workflowRunBackendId: string;
|
||||
/**
|
||||
* @generated from protobuf field: string workflow_job_run_backend_id = 2;
|
||||
*/
|
||||
workflowJobRunBackendId: string;
|
||||
/**
|
||||
* @generated from protobuf field: string name = 3;
|
||||
*/
|
||||
name: string;
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf message github.actions.results.api.v1.GetSignedArtifactURLResponse
|
||||
*/
|
||||
export interface GetSignedArtifactURLResponse {
|
||||
/**
|
||||
* @generated from protobuf field: string signed_url = 1;
|
||||
*/
|
||||
signedUrl: string;
|
||||
}
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class CreateArtifactRequest$Type extends MessageType<CreateArtifactRequest> {
|
||||
@@ -222,12 +332,12 @@ class FinalizeArtifactRequest$Type extends MessageType<FinalizeArtifactRequest>
|
||||
{ no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 2, name: "workflow_job_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 3, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 4, name: "size", kind: "scalar", T: 3 /*ScalarType.INT64*/, L: 0 /*LongType.BIGINT*/ },
|
||||
{ no: 4, name: "size", kind: "scalar", T: 3 /*ScalarType.INT64*/ },
|
||||
{ no: 5, name: "hash", kind: "message", T: () => StringValue }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<FinalizeArtifactRequest>): FinalizeArtifactRequest {
|
||||
const message = { workflowRunBackendId: "", workflowJobRunBackendId: "", name: "", size: 0n };
|
||||
const message = { workflowRunBackendId: "", workflowJobRunBackendId: "", name: "", size: "0" };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<FinalizeArtifactRequest>(this, message, value);
|
||||
@@ -248,7 +358,7 @@ class FinalizeArtifactRequest$Type extends MessageType<FinalizeArtifactRequest>
|
||||
message.name = reader.string();
|
||||
break;
|
||||
case /* int64 size */ 4:
|
||||
message.size = reader.int64().toBigInt();
|
||||
message.size = reader.int64().toString();
|
||||
break;
|
||||
case /* google.protobuf.StringValue hash */ 5:
|
||||
message.hash = StringValue.internalBinaryRead(reader, reader.uint32(), options, message.hash);
|
||||
@@ -275,7 +385,7 @@ class FinalizeArtifactRequest$Type extends MessageType<FinalizeArtifactRequest>
|
||||
if (message.name !== "")
|
||||
writer.tag(3, WireType.LengthDelimited).string(message.name);
|
||||
/* int64 size = 4; */
|
||||
if (message.size !== 0n)
|
||||
if (message.size !== "0")
|
||||
writer.tag(4, WireType.Varint).int64(message.size);
|
||||
/* google.protobuf.StringValue hash = 5; */
|
||||
if (message.hash)
|
||||
@@ -294,11 +404,12 @@ export const FinalizeArtifactRequest = new FinalizeArtifactRequest$Type();
|
||||
class FinalizeArtifactResponse$Type extends MessageType<FinalizeArtifactResponse> {
|
||||
constructor() {
|
||||
super("github.actions.results.api.v1.FinalizeArtifactResponse", [
|
||||
{ no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
|
||||
{ no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
|
||||
{ no: 2, name: "artifact_id", kind: "scalar", T: 3 /*ScalarType.INT64*/ }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<FinalizeArtifactResponse>): FinalizeArtifactResponse {
|
||||
const message = { ok: false };
|
||||
const message = { ok: false, artifactId: "0" };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<FinalizeArtifactResponse>(this, message, value);
|
||||
@@ -312,6 +423,9 @@ class FinalizeArtifactResponse$Type extends MessageType<FinalizeArtifactResponse
|
||||
case /* bool ok */ 1:
|
||||
message.ok = reader.bool();
|
||||
break;
|
||||
case /* int64 artifact_id */ 2:
|
||||
message.artifactId = reader.int64().toString();
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
@@ -327,6 +441,9 @@ class FinalizeArtifactResponse$Type extends MessageType<FinalizeArtifactResponse
|
||||
/* bool ok = 1; */
|
||||
if (message.ok !== false)
|
||||
writer.tag(1, WireType.Varint).bool(message.ok);
|
||||
/* int64 artifact_id = 2; */
|
||||
if (message.artifactId !== "0")
|
||||
writer.tag(2, WireType.Varint).int64(message.artifactId);
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
@@ -337,10 +454,317 @@ class FinalizeArtifactResponse$Type extends MessageType<FinalizeArtifactResponse
|
||||
* @generated MessageType for protobuf message github.actions.results.api.v1.FinalizeArtifactResponse
|
||||
*/
|
||||
export const FinalizeArtifactResponse = new FinalizeArtifactResponse$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class ListArtifactsRequest$Type extends MessageType<ListArtifactsRequest> {
|
||||
constructor() {
|
||||
super("github.actions.results.api.v1.ListArtifactsRequest", [
|
||||
{ no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 2, name: "workflow_job_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 3, name: "name_filter", kind: "message", T: () => StringValue },
|
||||
{ no: 4, name: "id_filter", kind: "message", T: () => Int64Value }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<ListArtifactsRequest>): ListArtifactsRequest {
|
||||
const message = { workflowRunBackendId: "", workflowJobRunBackendId: "" };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<ListArtifactsRequest>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ListArtifactsRequest): ListArtifactsRequest {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* string workflow_run_backend_id */ 1:
|
||||
message.workflowRunBackendId = reader.string();
|
||||
break;
|
||||
case /* string workflow_job_run_backend_id */ 2:
|
||||
message.workflowJobRunBackendId = reader.string();
|
||||
break;
|
||||
case /* google.protobuf.StringValue name_filter */ 3:
|
||||
message.nameFilter = StringValue.internalBinaryRead(reader, reader.uint32(), options, message.nameFilter);
|
||||
break;
|
||||
case /* google.protobuf.Int64Value id_filter */ 4:
|
||||
message.idFilter = Int64Value.internalBinaryRead(reader, reader.uint32(), options, message.idFilter);
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: ListArtifactsRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* string workflow_run_backend_id = 1; */
|
||||
if (message.workflowRunBackendId !== "")
|
||||
writer.tag(1, WireType.LengthDelimited).string(message.workflowRunBackendId);
|
||||
/* string workflow_job_run_backend_id = 2; */
|
||||
if (message.workflowJobRunBackendId !== "")
|
||||
writer.tag(2, WireType.LengthDelimited).string(message.workflowJobRunBackendId);
|
||||
/* google.protobuf.StringValue name_filter = 3; */
|
||||
if (message.nameFilter)
|
||||
StringValue.internalBinaryWrite(message.nameFilter, writer.tag(3, WireType.LengthDelimited).fork(), options).join();
|
||||
/* google.protobuf.Int64Value id_filter = 4; */
|
||||
if (message.idFilter)
|
||||
Int64Value.internalBinaryWrite(message.idFilter, writer.tag(4, WireType.LengthDelimited).fork(), options).join();
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message github.actions.results.api.v1.ListArtifactsRequest
|
||||
*/
|
||||
export const ListArtifactsRequest = new ListArtifactsRequest$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class ListArtifactsResponse$Type extends MessageType<ListArtifactsResponse> {
|
||||
constructor() {
|
||||
super("github.actions.results.api.v1.ListArtifactsResponse", [
|
||||
{ no: 1, name: "artifacts", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => ListArtifactsResponse_MonolithArtifact }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<ListArtifactsResponse>): ListArtifactsResponse {
|
||||
const message = { artifacts: [] };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<ListArtifactsResponse>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ListArtifactsResponse): ListArtifactsResponse {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* repeated github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact artifacts */ 1:
|
||||
message.artifacts.push(ListArtifactsResponse_MonolithArtifact.internalBinaryRead(reader, reader.uint32(), options));
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: ListArtifactsResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* repeated github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact artifacts = 1; */
|
||||
for (let i = 0; i < message.artifacts.length; i++)
|
||||
ListArtifactsResponse_MonolithArtifact.internalBinaryWrite(message.artifacts[i], writer.tag(1, WireType.LengthDelimited).fork(), options).join();
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message github.actions.results.api.v1.ListArtifactsResponse
|
||||
*/
|
||||
export const ListArtifactsResponse = new ListArtifactsResponse$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class ListArtifactsResponse_MonolithArtifact$Type extends MessageType<ListArtifactsResponse_MonolithArtifact> {
|
||||
constructor() {
|
||||
super("github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact", [
|
||||
{ no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 2, name: "workflow_job_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 3, name: "database_id", kind: "scalar", T: 3 /*ScalarType.INT64*/ },
|
||||
{ no: 4, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 5, name: "size", kind: "scalar", T: 3 /*ScalarType.INT64*/ },
|
||||
{ no: 6, name: "created_at", kind: "message", T: () => Timestamp }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<ListArtifactsResponse_MonolithArtifact>): ListArtifactsResponse_MonolithArtifact {
|
||||
const message = { workflowRunBackendId: "", workflowJobRunBackendId: "", databaseId: "0", name: "", size: "0" };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<ListArtifactsResponse_MonolithArtifact>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ListArtifactsResponse_MonolithArtifact): ListArtifactsResponse_MonolithArtifact {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* string workflow_run_backend_id */ 1:
|
||||
message.workflowRunBackendId = reader.string();
|
||||
break;
|
||||
case /* string workflow_job_run_backend_id */ 2:
|
||||
message.workflowJobRunBackendId = reader.string();
|
||||
break;
|
||||
case /* int64 database_id */ 3:
|
||||
message.databaseId = reader.int64().toString();
|
||||
break;
|
||||
case /* string name */ 4:
|
||||
message.name = reader.string();
|
||||
break;
|
||||
case /* int64 size */ 5:
|
||||
message.size = reader.int64().toString();
|
||||
break;
|
||||
case /* google.protobuf.Timestamp created_at */ 6:
|
||||
message.createdAt = Timestamp.internalBinaryRead(reader, reader.uint32(), options, message.createdAt);
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: ListArtifactsResponse_MonolithArtifact, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* string workflow_run_backend_id = 1; */
|
||||
if (message.workflowRunBackendId !== "")
|
||||
writer.tag(1, WireType.LengthDelimited).string(message.workflowRunBackendId);
|
||||
/* string workflow_job_run_backend_id = 2; */
|
||||
if (message.workflowJobRunBackendId !== "")
|
||||
writer.tag(2, WireType.LengthDelimited).string(message.workflowJobRunBackendId);
|
||||
/* int64 database_id = 3; */
|
||||
if (message.databaseId !== "0")
|
||||
writer.tag(3, WireType.Varint).int64(message.databaseId);
|
||||
/* string name = 4; */
|
||||
if (message.name !== "")
|
||||
writer.tag(4, WireType.LengthDelimited).string(message.name);
|
||||
/* int64 size = 5; */
|
||||
if (message.size !== "0")
|
||||
writer.tag(5, WireType.Varint).int64(message.size);
|
||||
/* google.protobuf.Timestamp created_at = 6; */
|
||||
if (message.createdAt)
|
||||
Timestamp.internalBinaryWrite(message.createdAt, writer.tag(6, WireType.LengthDelimited).fork(), options).join();
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message github.actions.results.api.v1.ListArtifactsResponse.MonolithArtifact
|
||||
*/
|
||||
export const ListArtifactsResponse_MonolithArtifact = new ListArtifactsResponse_MonolithArtifact$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class GetSignedArtifactURLRequest$Type extends MessageType<GetSignedArtifactURLRequest> {
|
||||
constructor() {
|
||||
super("github.actions.results.api.v1.GetSignedArtifactURLRequest", [
|
||||
{ no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 2, name: "workflow_job_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 3, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<GetSignedArtifactURLRequest>): GetSignedArtifactURLRequest {
|
||||
const message = { workflowRunBackendId: "", workflowJobRunBackendId: "", name: "" };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<GetSignedArtifactURLRequest>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetSignedArtifactURLRequest): GetSignedArtifactURLRequest {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* string workflow_run_backend_id */ 1:
|
||||
message.workflowRunBackendId = reader.string();
|
||||
break;
|
||||
case /* string workflow_job_run_backend_id */ 2:
|
||||
message.workflowJobRunBackendId = reader.string();
|
||||
break;
|
||||
case /* string name */ 3:
|
||||
message.name = reader.string();
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: GetSignedArtifactURLRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* string workflow_run_backend_id = 1; */
|
||||
if (message.workflowRunBackendId !== "")
|
||||
writer.tag(1, WireType.LengthDelimited).string(message.workflowRunBackendId);
|
||||
/* string workflow_job_run_backend_id = 2; */
|
||||
if (message.workflowJobRunBackendId !== "")
|
||||
writer.tag(2, WireType.LengthDelimited).string(message.workflowJobRunBackendId);
|
||||
/* string name = 3; */
|
||||
if (message.name !== "")
|
||||
writer.tag(3, WireType.LengthDelimited).string(message.name);
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message github.actions.results.api.v1.GetSignedArtifactURLRequest
|
||||
*/
|
||||
export const GetSignedArtifactURLRequest = new GetSignedArtifactURLRequest$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class GetSignedArtifactURLResponse$Type extends MessageType<GetSignedArtifactURLResponse> {
|
||||
constructor() {
|
||||
super("github.actions.results.api.v1.GetSignedArtifactURLResponse", [
|
||||
{ no: 1, name: "signed_url", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<GetSignedArtifactURLResponse>): GetSignedArtifactURLResponse {
|
||||
const message = { signedUrl: "" };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<GetSignedArtifactURLResponse>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetSignedArtifactURLResponse): GetSignedArtifactURLResponse {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* string signed_url */ 1:
|
||||
message.signedUrl = reader.string();
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: GetSignedArtifactURLResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* string signed_url = 1; */
|
||||
if (message.signedUrl !== "")
|
||||
writer.tag(1, WireType.LengthDelimited).string(message.signedUrl);
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message github.actions.results.api.v1.GetSignedArtifactURLResponse
|
||||
*/
|
||||
export const GetSignedArtifactURLResponse = new GetSignedArtifactURLResponse$Type();
|
||||
/**
|
||||
* @generated ServiceType for protobuf service github.actions.results.api.v1.ArtifactService
|
||||
*/
|
||||
export const ArtifactService = new ServiceType("github.actions.results.api.v1.ArtifactService", [
|
||||
{ name: "CreateArtifact", options: {}, I: CreateArtifactRequest, O: CreateArtifactResponse },
|
||||
{ name: "FinalizeArtifact", options: {}, I: FinalizeArtifactRequest, O: FinalizeArtifactResponse }
|
||||
{ name: "FinalizeArtifact", options: {}, I: FinalizeArtifactRequest, O: FinalizeArtifactResponse },
|
||||
{ name: "ListArtifacts", options: {}, I: ListArtifactsRequest, O: ListArtifactsResponse },
|
||||
{ name: "GetSignedArtifactURL", options: {}, I: GetSignedArtifactURLRequest, O: GetSignedArtifactURLResponse }
|
||||
]);
|
||||
|
||||
@@ -6,14 +6,18 @@ import {
|
||||
TwirpErrorCode,
|
||||
Interceptor,
|
||||
TwirpContentType,
|
||||
chainInterceptors
|
||||
} from 'twirp-ts'
|
||||
chainInterceptors,
|
||||
} from "twirp-ts";
|
||||
import {
|
||||
CreateArtifactRequest,
|
||||
CreateArtifactResponse,
|
||||
FinalizeArtifactRequest,
|
||||
FinalizeArtifactResponse
|
||||
} from './artifact'
|
||||
FinalizeArtifactResponse,
|
||||
ListArtifactsRequest,
|
||||
ListArtifactsResponse,
|
||||
GetSignedArtifactURLRequest,
|
||||
GetSignedArtifactURLResponse,
|
||||
} from "./artifact";
|
||||
|
||||
//==================================//
|
||||
// Client Code //
|
||||
@@ -23,43 +27,51 @@ interface Rpc {
|
||||
request(
|
||||
service: string,
|
||||
method: string,
|
||||
contentType: 'application/json' | 'application/protobuf',
|
||||
contentType: "application/json" | "application/protobuf",
|
||||
data: object | Uint8Array
|
||||
): Promise<object | Uint8Array>
|
||||
): Promise<object | Uint8Array>;
|
||||
}
|
||||
|
||||
export interface ArtifactServiceClient {
|
||||
CreateArtifact(
|
||||
request: CreateArtifactRequest
|
||||
): Promise<CreateArtifactResponse>
|
||||
): Promise<CreateArtifactResponse>;
|
||||
FinalizeArtifact(
|
||||
request: FinalizeArtifactRequest
|
||||
): Promise<FinalizeArtifactResponse>
|
||||
): Promise<FinalizeArtifactResponse>;
|
||||
ListArtifacts(request: ListArtifactsRequest): Promise<ListArtifactsResponse>;
|
||||
GetSignedArtifactURL(
|
||||
request: GetSignedArtifactURLRequest
|
||||
): Promise<GetSignedArtifactURLResponse>;
|
||||
}
|
||||
|
||||
export class ArtifactServiceClientJSON implements ArtifactServiceClient {
|
||||
private readonly rpc: Rpc
|
||||
private readonly rpc: Rpc;
|
||||
constructor(rpc: Rpc) {
|
||||
this.rpc = rpc
|
||||
this.CreateArtifact.bind(this)
|
||||
this.FinalizeArtifact.bind(this)
|
||||
this.rpc = rpc;
|
||||
this.CreateArtifact.bind(this);
|
||||
this.FinalizeArtifact.bind(this);
|
||||
this.ListArtifacts.bind(this);
|
||||
this.GetSignedArtifactURL.bind(this);
|
||||
}
|
||||
CreateArtifact(
|
||||
request: CreateArtifactRequest
|
||||
): Promise<CreateArtifactResponse> {
|
||||
const data = CreateArtifactRequest.toJson(request, {
|
||||
useProtoFieldName: true,
|
||||
emitDefaultValues: false
|
||||
})
|
||||
emitDefaultValues: false,
|
||||
});
|
||||
const promise = this.rpc.request(
|
||||
'github.actions.results.api.v1.ArtifactService',
|
||||
'CreateArtifact',
|
||||
'application/json',
|
||||
"github.actions.results.api.v1.ArtifactService",
|
||||
"CreateArtifact",
|
||||
"application/json",
|
||||
data as object
|
||||
)
|
||||
return promise.then(data =>
|
||||
CreateArtifactResponse.fromJson(data as any, {ignoreUnknownFields: true})
|
||||
)
|
||||
);
|
||||
return promise.then((data) =>
|
||||
CreateArtifactResponse.fromJson(data as any, {
|
||||
ignoreUnknownFields: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
FinalizeArtifact(
|
||||
@@ -67,57 +79,123 @@ export class ArtifactServiceClientJSON implements ArtifactServiceClient {
|
||||
): Promise<FinalizeArtifactResponse> {
|
||||
const data = FinalizeArtifactRequest.toJson(request, {
|
||||
useProtoFieldName: true,
|
||||
emitDefaultValues: false
|
||||
})
|
||||
emitDefaultValues: false,
|
||||
});
|
||||
const promise = this.rpc.request(
|
||||
'github.actions.results.api.v1.ArtifactService',
|
||||
'FinalizeArtifact',
|
||||
'application/json',
|
||||
"github.actions.results.api.v1.ArtifactService",
|
||||
"FinalizeArtifact",
|
||||
"application/json",
|
||||
data as object
|
||||
)
|
||||
return promise.then(data =>
|
||||
);
|
||||
return promise.then((data) =>
|
||||
FinalizeArtifactResponse.fromJson(data as any, {
|
||||
ignoreUnknownFields: true
|
||||
ignoreUnknownFields: true,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
ListArtifacts(request: ListArtifactsRequest): Promise<ListArtifactsResponse> {
|
||||
const data = ListArtifactsRequest.toJson(request, {
|
||||
useProtoFieldName: true,
|
||||
emitDefaultValues: false,
|
||||
});
|
||||
const promise = this.rpc.request(
|
||||
"github.actions.results.api.v1.ArtifactService",
|
||||
"ListArtifacts",
|
||||
"application/json",
|
||||
data as object
|
||||
);
|
||||
return promise.then((data) =>
|
||||
ListArtifactsResponse.fromJson(data as any, { ignoreUnknownFields: true })
|
||||
);
|
||||
}
|
||||
|
||||
GetSignedArtifactURL(
|
||||
request: GetSignedArtifactURLRequest
|
||||
): Promise<GetSignedArtifactURLResponse> {
|
||||
const data = GetSignedArtifactURLRequest.toJson(request, {
|
||||
useProtoFieldName: true,
|
||||
emitDefaultValues: false,
|
||||
});
|
||||
const promise = this.rpc.request(
|
||||
"github.actions.results.api.v1.ArtifactService",
|
||||
"GetSignedArtifactURL",
|
||||
"application/json",
|
||||
data as object
|
||||
);
|
||||
return promise.then((data) =>
|
||||
GetSignedArtifactURLResponse.fromJson(data as any, {
|
||||
ignoreUnknownFields: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class ArtifactServiceClientProtobuf implements ArtifactServiceClient {
|
||||
private readonly rpc: Rpc
|
||||
private readonly rpc: Rpc;
|
||||
constructor(rpc: Rpc) {
|
||||
this.rpc = rpc
|
||||
this.CreateArtifact.bind(this)
|
||||
this.FinalizeArtifact.bind(this)
|
||||
this.rpc = rpc;
|
||||
this.CreateArtifact.bind(this);
|
||||
this.FinalizeArtifact.bind(this);
|
||||
this.ListArtifacts.bind(this);
|
||||
this.GetSignedArtifactURL.bind(this);
|
||||
}
|
||||
CreateArtifact(
|
||||
request: CreateArtifactRequest
|
||||
): Promise<CreateArtifactResponse> {
|
||||
const data = CreateArtifactRequest.toBinary(request)
|
||||
const data = CreateArtifactRequest.toBinary(request);
|
||||
const promise = this.rpc.request(
|
||||
'github.actions.results.api.v1.ArtifactService',
|
||||
'CreateArtifact',
|
||||
'application/protobuf',
|
||||
"github.actions.results.api.v1.ArtifactService",
|
||||
"CreateArtifact",
|
||||
"application/protobuf",
|
||||
data
|
||||
)
|
||||
return promise.then(data =>
|
||||
);
|
||||
return promise.then((data) =>
|
||||
CreateArtifactResponse.fromBinary(data as Uint8Array)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
FinalizeArtifact(
|
||||
request: FinalizeArtifactRequest
|
||||
): Promise<FinalizeArtifactResponse> {
|
||||
const data = FinalizeArtifactRequest.toBinary(request)
|
||||
const data = FinalizeArtifactRequest.toBinary(request);
|
||||
const promise = this.rpc.request(
|
||||
'github.actions.results.api.v1.ArtifactService',
|
||||
'FinalizeArtifact',
|
||||
'application/protobuf',
|
||||
"github.actions.results.api.v1.ArtifactService",
|
||||
"FinalizeArtifact",
|
||||
"application/protobuf",
|
||||
data
|
||||
)
|
||||
return promise.then(data =>
|
||||
);
|
||||
return promise.then((data) =>
|
||||
FinalizeArtifactResponse.fromBinary(data as Uint8Array)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
ListArtifacts(request: ListArtifactsRequest): Promise<ListArtifactsResponse> {
|
||||
const data = ListArtifactsRequest.toBinary(request);
|
||||
const promise = this.rpc.request(
|
||||
"github.actions.results.api.v1.ArtifactService",
|
||||
"ListArtifacts",
|
||||
"application/protobuf",
|
||||
data
|
||||
);
|
||||
return promise.then((data) =>
|
||||
ListArtifactsResponse.fromBinary(data as Uint8Array)
|
||||
);
|
||||
}
|
||||
|
||||
GetSignedArtifactURL(
|
||||
request: GetSignedArtifactURLRequest
|
||||
): Promise<GetSignedArtifactURLResponse> {
|
||||
const data = GetSignedArtifactURLRequest.toBinary(request);
|
||||
const promise = this.rpc.request(
|
||||
"github.actions.results.api.v1.ArtifactService",
|
||||
"GetSignedArtifactURL",
|
||||
"application/protobuf",
|
||||
data
|
||||
);
|
||||
return promise.then((data) =>
|
||||
GetSignedArtifactURLResponse.fromBinary(data as Uint8Array)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,33 +207,45 @@ export interface ArtifactServiceTwirp<T extends TwirpContext = TwirpContext> {
|
||||
CreateArtifact(
|
||||
ctx: T,
|
||||
request: CreateArtifactRequest
|
||||
): Promise<CreateArtifactResponse>
|
||||
): Promise<CreateArtifactResponse>;
|
||||
FinalizeArtifact(
|
||||
ctx: T,
|
||||
request: FinalizeArtifactRequest
|
||||
): Promise<FinalizeArtifactResponse>
|
||||
): Promise<FinalizeArtifactResponse>;
|
||||
ListArtifacts(
|
||||
ctx: T,
|
||||
request: ListArtifactsRequest
|
||||
): Promise<ListArtifactsResponse>;
|
||||
GetSignedArtifactURL(
|
||||
ctx: T,
|
||||
request: GetSignedArtifactURLRequest
|
||||
): Promise<GetSignedArtifactURLResponse>;
|
||||
}
|
||||
|
||||
export enum ArtifactServiceMethod {
|
||||
CreateArtifact = 'CreateArtifact',
|
||||
FinalizeArtifact = 'FinalizeArtifact'
|
||||
CreateArtifact = "CreateArtifact",
|
||||
FinalizeArtifact = "FinalizeArtifact",
|
||||
ListArtifacts = "ListArtifacts",
|
||||
GetSignedArtifactURL = "GetSignedArtifactURL",
|
||||
}
|
||||
|
||||
export const ArtifactServiceMethodList = [
|
||||
ArtifactServiceMethod.CreateArtifact,
|
||||
ArtifactServiceMethod.FinalizeArtifact
|
||||
]
|
||||
ArtifactServiceMethod.FinalizeArtifact,
|
||||
ArtifactServiceMethod.ListArtifacts,
|
||||
ArtifactServiceMethod.GetSignedArtifactURL,
|
||||
];
|
||||
|
||||
export function createArtifactServiceServer<
|
||||
T extends TwirpContext = TwirpContext
|
||||
>(service: ArtifactServiceTwirp<T>) {
|
||||
return new TwirpServer<ArtifactServiceTwirp, T>({
|
||||
service,
|
||||
packageName: 'github.actions.results.api.v1',
|
||||
serviceName: 'ArtifactService',
|
||||
packageName: "github.actions.results.api.v1",
|
||||
serviceName: "ArtifactService",
|
||||
methodList: ArtifactServiceMethodList,
|
||||
matchRoute: matchArtifactServiceRoute
|
||||
})
|
||||
matchRoute: matchArtifactServiceRoute,
|
||||
});
|
||||
}
|
||||
|
||||
function matchArtifactServiceRoute<T extends TwirpContext = TwirpContext>(
|
||||
@@ -163,7 +253,7 @@ function matchArtifactServiceRoute<T extends TwirpContext = TwirpContext>(
|
||||
events: RouterEvents<T>
|
||||
) {
|
||||
switch (method) {
|
||||
case 'CreateArtifact':
|
||||
case "CreateArtifact":
|
||||
return async (
|
||||
ctx: T,
|
||||
service: ArtifactServiceTwirp,
|
||||
@@ -174,16 +264,16 @@ function matchArtifactServiceRoute<T extends TwirpContext = TwirpContext>(
|
||||
CreateArtifactResponse
|
||||
>[]
|
||||
) => {
|
||||
ctx = {...ctx, methodName: 'CreateArtifact'}
|
||||
await events.onMatch(ctx)
|
||||
ctx = { ...ctx, methodName: "CreateArtifact" };
|
||||
await events.onMatch(ctx);
|
||||
return handleArtifactServiceCreateArtifactRequest(
|
||||
ctx,
|
||||
service,
|
||||
data,
|
||||
interceptors
|
||||
)
|
||||
}
|
||||
case 'FinalizeArtifact':
|
||||
);
|
||||
};
|
||||
case "FinalizeArtifact":
|
||||
return async (
|
||||
ctx: T,
|
||||
service: ArtifactServiceTwirp,
|
||||
@@ -194,19 +284,59 @@ function matchArtifactServiceRoute<T extends TwirpContext = TwirpContext>(
|
||||
FinalizeArtifactResponse
|
||||
>[]
|
||||
) => {
|
||||
ctx = {...ctx, methodName: 'FinalizeArtifact'}
|
||||
await events.onMatch(ctx)
|
||||
ctx = { ...ctx, methodName: "FinalizeArtifact" };
|
||||
await events.onMatch(ctx);
|
||||
return handleArtifactServiceFinalizeArtifactRequest(
|
||||
ctx,
|
||||
service,
|
||||
data,
|
||||
interceptors
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
case "ListArtifacts":
|
||||
return async (
|
||||
ctx: T,
|
||||
service: ArtifactServiceTwirp,
|
||||
data: Buffer,
|
||||
interceptors?: Interceptor<
|
||||
T,
|
||||
ListArtifactsRequest,
|
||||
ListArtifactsResponse
|
||||
>[]
|
||||
) => {
|
||||
ctx = { ...ctx, methodName: "ListArtifacts" };
|
||||
await events.onMatch(ctx);
|
||||
return handleArtifactServiceListArtifactsRequest(
|
||||
ctx,
|
||||
service,
|
||||
data,
|
||||
interceptors
|
||||
);
|
||||
};
|
||||
case "GetSignedArtifactURL":
|
||||
return async (
|
||||
ctx: T,
|
||||
service: ArtifactServiceTwirp,
|
||||
data: Buffer,
|
||||
interceptors?: Interceptor<
|
||||
T,
|
||||
GetSignedArtifactURLRequest,
|
||||
GetSignedArtifactURLResponse
|
||||
>[]
|
||||
) => {
|
||||
ctx = { ...ctx, methodName: "GetSignedArtifactURL" };
|
||||
await events.onMatch(ctx);
|
||||
return handleArtifactServiceGetSignedArtifactURLRequest(
|
||||
ctx,
|
||||
service,
|
||||
data,
|
||||
interceptors
|
||||
);
|
||||
};
|
||||
default:
|
||||
events.onNotFound()
|
||||
const msg = `no handler found`
|
||||
throw new TwirpError(TwirpErrorCode.BadRoute, msg)
|
||||
events.onNotFound();
|
||||
const msg = `no handler found`;
|
||||
throw new TwirpError(TwirpErrorCode.BadRoute, msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,17 +355,17 @@ function handleArtifactServiceCreateArtifactRequest<
|
||||
service,
|
||||
data,
|
||||
interceptors
|
||||
)
|
||||
);
|
||||
case TwirpContentType.Protobuf:
|
||||
return handleArtifactServiceCreateArtifactProtobuf<T>(
|
||||
ctx,
|
||||
service,
|
||||
data,
|
||||
interceptors
|
||||
)
|
||||
);
|
||||
default:
|
||||
const msg = 'unexpected Content-Type'
|
||||
throw new TwirpError(TwirpErrorCode.BadRoute, msg)
|
||||
const msg = "unexpected Content-Type";
|
||||
throw new TwirpError(TwirpErrorCode.BadRoute, msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,17 +388,79 @@ function handleArtifactServiceFinalizeArtifactRequest<
|
||||
service,
|
||||
data,
|
||||
interceptors
|
||||
)
|
||||
);
|
||||
case TwirpContentType.Protobuf:
|
||||
return handleArtifactServiceFinalizeArtifactProtobuf<T>(
|
||||
ctx,
|
||||
service,
|
||||
data,
|
||||
interceptors
|
||||
)
|
||||
);
|
||||
default:
|
||||
const msg = 'unexpected Content-Type'
|
||||
throw new TwirpError(TwirpErrorCode.BadRoute, msg)
|
||||
const msg = "unexpected Content-Type";
|
||||
throw new TwirpError(TwirpErrorCode.BadRoute, msg);
|
||||
}
|
||||
}
|
||||
|
||||
function handleArtifactServiceListArtifactsRequest<
|
||||
T extends TwirpContext = TwirpContext
|
||||
>(
|
||||
ctx: T,
|
||||
service: ArtifactServiceTwirp,
|
||||
data: Buffer,
|
||||
interceptors?: Interceptor<T, ListArtifactsRequest, ListArtifactsResponse>[]
|
||||
): Promise<string | Uint8Array> {
|
||||
switch (ctx.contentType) {
|
||||
case TwirpContentType.JSON:
|
||||
return handleArtifactServiceListArtifactsJSON<T>(
|
||||
ctx,
|
||||
service,
|
||||
data,
|
||||
interceptors
|
||||
);
|
||||
case TwirpContentType.Protobuf:
|
||||
return handleArtifactServiceListArtifactsProtobuf<T>(
|
||||
ctx,
|
||||
service,
|
||||
data,
|
||||
interceptors
|
||||
);
|
||||
default:
|
||||
const msg = "unexpected Content-Type";
|
||||
throw new TwirpError(TwirpErrorCode.BadRoute, msg);
|
||||
}
|
||||
}
|
||||
|
||||
function handleArtifactServiceGetSignedArtifactURLRequest<
|
||||
T extends TwirpContext = TwirpContext
|
||||
>(
|
||||
ctx: T,
|
||||
service: ArtifactServiceTwirp,
|
||||
data: Buffer,
|
||||
interceptors?: Interceptor<
|
||||
T,
|
||||
GetSignedArtifactURLRequest,
|
||||
GetSignedArtifactURLResponse
|
||||
>[]
|
||||
): Promise<string | Uint8Array> {
|
||||
switch (ctx.contentType) {
|
||||
case TwirpContentType.JSON:
|
||||
return handleArtifactServiceGetSignedArtifactURLJSON<T>(
|
||||
ctx,
|
||||
service,
|
||||
data,
|
||||
interceptors
|
||||
);
|
||||
case TwirpContentType.Protobuf:
|
||||
return handleArtifactServiceGetSignedArtifactURLProtobuf<T>(
|
||||
ctx,
|
||||
service,
|
||||
data,
|
||||
interceptors
|
||||
);
|
||||
default:
|
||||
const msg = "unexpected Content-Type";
|
||||
throw new TwirpError(TwirpErrorCode.BadRoute, msg);
|
||||
}
|
||||
}
|
||||
async function handleArtifactServiceCreateArtifactJSON<
|
||||
@@ -279,16 +471,18 @@ async function handleArtifactServiceCreateArtifactJSON<
|
||||
data: Buffer,
|
||||
interceptors?: Interceptor<T, CreateArtifactRequest, CreateArtifactResponse>[]
|
||||
) {
|
||||
let request: CreateArtifactRequest
|
||||
let response: CreateArtifactResponse
|
||||
let request: CreateArtifactRequest;
|
||||
let response: CreateArtifactResponse;
|
||||
|
||||
try {
|
||||
const body = JSON.parse(data.toString() || '{}')
|
||||
request = CreateArtifactRequest.fromJson(body, {ignoreUnknownFields: true})
|
||||
const body = JSON.parse(data.toString() || "{}");
|
||||
request = CreateArtifactRequest.fromJson(body, {
|
||||
ignoreUnknownFields: true,
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = 'the json request could not be decoded'
|
||||
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true)
|
||||
const msg = "the json request could not be decoded";
|
||||
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,20 +491,20 @@ async function handleArtifactServiceCreateArtifactJSON<
|
||||
T,
|
||||
CreateArtifactRequest,
|
||||
CreateArtifactResponse
|
||||
>
|
||||
>;
|
||||
response = await interceptor(ctx, request!, (ctx, inputReq) => {
|
||||
return service.CreateArtifact(ctx, inputReq)
|
||||
})
|
||||
return service.CreateArtifact(ctx, inputReq);
|
||||
});
|
||||
} else {
|
||||
response = await service.CreateArtifact(ctx, request!)
|
||||
response = await service.CreateArtifact(ctx, request!);
|
||||
}
|
||||
|
||||
return JSON.stringify(
|
||||
CreateArtifactResponse.toJson(response, {
|
||||
useProtoFieldName: true,
|
||||
emitDefaultValues: false
|
||||
emitDefaultValues: false,
|
||||
}) as string
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
async function handleArtifactServiceFinalizeArtifactJSON<
|
||||
@@ -325,18 +519,18 @@ async function handleArtifactServiceFinalizeArtifactJSON<
|
||||
FinalizeArtifactResponse
|
||||
>[]
|
||||
) {
|
||||
let request: FinalizeArtifactRequest
|
||||
let response: FinalizeArtifactResponse
|
||||
let request: FinalizeArtifactRequest;
|
||||
let response: FinalizeArtifactResponse;
|
||||
|
||||
try {
|
||||
const body = JSON.parse(data.toString() || '{}')
|
||||
const body = JSON.parse(data.toString() || "{}");
|
||||
request = FinalizeArtifactRequest.fromJson(body, {
|
||||
ignoreUnknownFields: true
|
||||
})
|
||||
ignoreUnknownFields: true,
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = 'the json request could not be decoded'
|
||||
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true)
|
||||
const msg = "the json request could not be decoded";
|
||||
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,20 +539,112 @@ async function handleArtifactServiceFinalizeArtifactJSON<
|
||||
T,
|
||||
FinalizeArtifactRequest,
|
||||
FinalizeArtifactResponse
|
||||
>
|
||||
>;
|
||||
response = await interceptor(ctx, request!, (ctx, inputReq) => {
|
||||
return service.FinalizeArtifact(ctx, inputReq)
|
||||
})
|
||||
return service.FinalizeArtifact(ctx, inputReq);
|
||||
});
|
||||
} else {
|
||||
response = await service.FinalizeArtifact(ctx, request!)
|
||||
response = await service.FinalizeArtifact(ctx, request!);
|
||||
}
|
||||
|
||||
return JSON.stringify(
|
||||
FinalizeArtifactResponse.toJson(response, {
|
||||
useProtoFieldName: true,
|
||||
emitDefaultValues: false
|
||||
emitDefaultValues: false,
|
||||
}) as string
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
async function handleArtifactServiceListArtifactsJSON<
|
||||
T extends TwirpContext = TwirpContext
|
||||
>(
|
||||
ctx: T,
|
||||
service: ArtifactServiceTwirp,
|
||||
data: Buffer,
|
||||
interceptors?: Interceptor<T, ListArtifactsRequest, ListArtifactsResponse>[]
|
||||
) {
|
||||
let request: ListArtifactsRequest;
|
||||
let response: ListArtifactsResponse;
|
||||
|
||||
try {
|
||||
const body = JSON.parse(data.toString() || "{}");
|
||||
request = ListArtifactsRequest.fromJson(body, {
|
||||
ignoreUnknownFields: true,
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = "the json request could not be decoded";
|
||||
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (interceptors && interceptors.length > 0) {
|
||||
const interceptor = chainInterceptors(...interceptors) as Interceptor<
|
||||
T,
|
||||
ListArtifactsRequest,
|
||||
ListArtifactsResponse
|
||||
>;
|
||||
response = await interceptor(ctx, request!, (ctx, inputReq) => {
|
||||
return service.ListArtifacts(ctx, inputReq);
|
||||
});
|
||||
} else {
|
||||
response = await service.ListArtifacts(ctx, request!);
|
||||
}
|
||||
|
||||
return JSON.stringify(
|
||||
ListArtifactsResponse.toJson(response, {
|
||||
useProtoFieldName: true,
|
||||
emitDefaultValues: false,
|
||||
}) as string
|
||||
);
|
||||
}
|
||||
|
||||
async function handleArtifactServiceGetSignedArtifactURLJSON<
|
||||
T extends TwirpContext = TwirpContext
|
||||
>(
|
||||
ctx: T,
|
||||
service: ArtifactServiceTwirp,
|
||||
data: Buffer,
|
||||
interceptors?: Interceptor<
|
||||
T,
|
||||
GetSignedArtifactURLRequest,
|
||||
GetSignedArtifactURLResponse
|
||||
>[]
|
||||
) {
|
||||
let request: GetSignedArtifactURLRequest;
|
||||
let response: GetSignedArtifactURLResponse;
|
||||
|
||||
try {
|
||||
const body = JSON.parse(data.toString() || "{}");
|
||||
request = GetSignedArtifactURLRequest.fromJson(body, {
|
||||
ignoreUnknownFields: true,
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = "the json request could not be decoded";
|
||||
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (interceptors && interceptors.length > 0) {
|
||||
const interceptor = chainInterceptors(...interceptors) as Interceptor<
|
||||
T,
|
||||
GetSignedArtifactURLRequest,
|
||||
GetSignedArtifactURLResponse
|
||||
>;
|
||||
response = await interceptor(ctx, request!, (ctx, inputReq) => {
|
||||
return service.GetSignedArtifactURL(ctx, inputReq);
|
||||
});
|
||||
} else {
|
||||
response = await service.GetSignedArtifactURL(ctx, request!);
|
||||
}
|
||||
|
||||
return JSON.stringify(
|
||||
GetSignedArtifactURLResponse.toJson(response, {
|
||||
useProtoFieldName: true,
|
||||
emitDefaultValues: false,
|
||||
}) as string
|
||||
);
|
||||
}
|
||||
async function handleArtifactServiceCreateArtifactProtobuf<
|
||||
T extends TwirpContext = TwirpContext
|
||||
@@ -368,15 +654,15 @@ async function handleArtifactServiceCreateArtifactProtobuf<
|
||||
data: Buffer,
|
||||
interceptors?: Interceptor<T, CreateArtifactRequest, CreateArtifactResponse>[]
|
||||
) {
|
||||
let request: CreateArtifactRequest
|
||||
let response: CreateArtifactResponse
|
||||
let request: CreateArtifactRequest;
|
||||
let response: CreateArtifactResponse;
|
||||
|
||||
try {
|
||||
request = CreateArtifactRequest.fromBinary(data)
|
||||
request = CreateArtifactRequest.fromBinary(data);
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = 'the protobuf request could not be decoded'
|
||||
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true)
|
||||
const msg = "the protobuf request could not be decoded";
|
||||
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,15 +671,15 @@ async function handleArtifactServiceCreateArtifactProtobuf<
|
||||
T,
|
||||
CreateArtifactRequest,
|
||||
CreateArtifactResponse
|
||||
>
|
||||
>;
|
||||
response = await interceptor(ctx, request!, (ctx, inputReq) => {
|
||||
return service.CreateArtifact(ctx, inputReq)
|
||||
})
|
||||
return service.CreateArtifact(ctx, inputReq);
|
||||
});
|
||||
} else {
|
||||
response = await service.CreateArtifact(ctx, request!)
|
||||
response = await service.CreateArtifact(ctx, request!);
|
||||
}
|
||||
|
||||
return Buffer.from(CreateArtifactResponse.toBinary(response))
|
||||
return Buffer.from(CreateArtifactResponse.toBinary(response));
|
||||
}
|
||||
|
||||
async function handleArtifactServiceFinalizeArtifactProtobuf<
|
||||
@@ -408,15 +694,15 @@ async function handleArtifactServiceFinalizeArtifactProtobuf<
|
||||
FinalizeArtifactResponse
|
||||
>[]
|
||||
) {
|
||||
let request: FinalizeArtifactRequest
|
||||
let response: FinalizeArtifactResponse
|
||||
let request: FinalizeArtifactRequest;
|
||||
let response: FinalizeArtifactResponse;
|
||||
|
||||
try {
|
||||
request = FinalizeArtifactRequest.fromBinary(data)
|
||||
request = FinalizeArtifactRequest.fromBinary(data);
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = 'the protobuf request could not be decoded'
|
||||
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true)
|
||||
const msg = "the protobuf request could not be decoded";
|
||||
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,13 +711,89 @@ async function handleArtifactServiceFinalizeArtifactProtobuf<
|
||||
T,
|
||||
FinalizeArtifactRequest,
|
||||
FinalizeArtifactResponse
|
||||
>
|
||||
>;
|
||||
response = await interceptor(ctx, request!, (ctx, inputReq) => {
|
||||
return service.FinalizeArtifact(ctx, inputReq)
|
||||
})
|
||||
return service.FinalizeArtifact(ctx, inputReq);
|
||||
});
|
||||
} else {
|
||||
response = await service.FinalizeArtifact(ctx, request!)
|
||||
response = await service.FinalizeArtifact(ctx, request!);
|
||||
}
|
||||
|
||||
return Buffer.from(FinalizeArtifactResponse.toBinary(response))
|
||||
return Buffer.from(FinalizeArtifactResponse.toBinary(response));
|
||||
}
|
||||
|
||||
async function handleArtifactServiceListArtifactsProtobuf<
|
||||
T extends TwirpContext = TwirpContext
|
||||
>(
|
||||
ctx: T,
|
||||
service: ArtifactServiceTwirp,
|
||||
data: Buffer,
|
||||
interceptors?: Interceptor<T, ListArtifactsRequest, ListArtifactsResponse>[]
|
||||
) {
|
||||
let request: ListArtifactsRequest;
|
||||
let response: ListArtifactsResponse;
|
||||
|
||||
try {
|
||||
request = ListArtifactsRequest.fromBinary(data);
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = "the protobuf request could not be decoded";
|
||||
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (interceptors && interceptors.length > 0) {
|
||||
const interceptor = chainInterceptors(...interceptors) as Interceptor<
|
||||
T,
|
||||
ListArtifactsRequest,
|
||||
ListArtifactsResponse
|
||||
>;
|
||||
response = await interceptor(ctx, request!, (ctx, inputReq) => {
|
||||
return service.ListArtifacts(ctx, inputReq);
|
||||
});
|
||||
} else {
|
||||
response = await service.ListArtifacts(ctx, request!);
|
||||
}
|
||||
|
||||
return Buffer.from(ListArtifactsResponse.toBinary(response));
|
||||
}
|
||||
|
||||
async function handleArtifactServiceGetSignedArtifactURLProtobuf<
|
||||
T extends TwirpContext = TwirpContext
|
||||
>(
|
||||
ctx: T,
|
||||
service: ArtifactServiceTwirp,
|
||||
data: Buffer,
|
||||
interceptors?: Interceptor<
|
||||
T,
|
||||
GetSignedArtifactURLRequest,
|
||||
GetSignedArtifactURLResponse
|
||||
>[]
|
||||
) {
|
||||
let request: GetSignedArtifactURLRequest;
|
||||
let response: GetSignedArtifactURLResponse;
|
||||
|
||||
try {
|
||||
request = GetSignedArtifactURLRequest.fromBinary(data);
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
const msg = "the protobuf request could not be decoded";
|
||||
throw new TwirpError(TwirpErrorCode.Malformed, msg).withCause(e, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (interceptors && interceptors.length > 0) {
|
||||
const interceptor = chainInterceptors(...interceptors) as Interceptor<
|
||||
T,
|
||||
GetSignedArtifactURLRequest,
|
||||
GetSignedArtifactURLResponse
|
||||
>;
|
||||
response = await interceptor(ctx, request!, (ctx, inputReq) => {
|
||||
return service.GetSignedArtifactURL(ctx, inputReq);
|
||||
});
|
||||
} else {
|
||||
response = await service.GetSignedArtifactURL(ctx, request!);
|
||||
}
|
||||
|
||||
return Buffer.from(GetSignedArtifactURLResponse.toBinary(response));
|
||||
}
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
import { HttpCodes, HttpClient, HttpClientResponse } from '@actions/http-client'
|
||||
import { BearerCredentialHandler } from '@actions/http-client/lib/auth'
|
||||
import { info } from '@actions/core'
|
||||
import { getRuntimeToken, getResultsServiceUrl, getRetryMultiplier, getInitialRetryIntervalInMilliseconds, getRetryLimit } from './config'
|
||||
|
||||
interface Rpc { request(
|
||||
service: string,
|
||||
method: string,
|
||||
contentType: "application/json" | "application/protobuf",
|
||||
data: object | Uint8Array
|
||||
): Promise<object | Uint8Array>
|
||||
}
|
||||
|
||||
export class ArtifactHttpClient implements Rpc {
|
||||
private httpClient: HttpClient
|
||||
private baseUrl: string
|
||||
|
||||
constructor(userAgent: string) {
|
||||
const token = getRuntimeToken()
|
||||
this.httpClient = new HttpClient(userAgent, [
|
||||
new BearerCredentialHandler(token)
|
||||
])
|
||||
this.baseUrl = getResultsServiceUrl()
|
||||
}
|
||||
|
||||
async request(service: string, method: string, contentType: "application/json" | "application/protobuf", data: object | Uint8Array): Promise<object | Uint8Array> {
|
||||
let url = `${this.baseUrl}/twirp/${service}/${method}`
|
||||
let headers = {
|
||||
"Content-Type": contentType
|
||||
}
|
||||
|
||||
const resp = await this.retry(
|
||||
`${method}`,
|
||||
this.httpClient.post(url, JSON.stringify(data), headers),
|
||||
)
|
||||
const body = await resp.readBody()
|
||||
return JSON.parse(body)
|
||||
}
|
||||
|
||||
async retry(name: string, operation: Promise<HttpClientResponse>): Promise<HttpClientResponse> {
|
||||
let response: HttpClientResponse | undefined = undefined
|
||||
let statusCode: number | undefined = undefined
|
||||
let isRetryable = false
|
||||
let errorMessage = ''
|
||||
let attempt = 1
|
||||
const maxAttempts = getRetryLimit()
|
||||
|
||||
while (attempt <= maxAttempts) {
|
||||
try {
|
||||
response = await operation
|
||||
statusCode = response.message.statusCode
|
||||
|
||||
if (this.isSuccessStatusCode(statusCode)) {
|
||||
return response
|
||||
}
|
||||
|
||||
isRetryable = this.isRetryableStatusCode(statusCode)
|
||||
errorMessage = `Artifact service responded with ${statusCode}`
|
||||
} catch (error: any) {
|
||||
isRetryable = true
|
||||
errorMessage = error.message
|
||||
}
|
||||
|
||||
if (!isRetryable) {
|
||||
info(`${name} - Error is not retryable`)
|
||||
if (response) {
|
||||
this.displayHttpDiagnostics(response)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
info(
|
||||
`${name} - Attempt ${attempt} of ${maxAttempts} failed with error: ${errorMessage}`
|
||||
)
|
||||
|
||||
await this.sleep(this.getExponentialRetryTimeInMilliseconds(attempt))
|
||||
attempt++
|
||||
}
|
||||
|
||||
if (response) {
|
||||
this.displayHttpDiagnostics(response)
|
||||
}
|
||||
|
||||
throw Error(`${name} failed: ${errorMessage}`)
|
||||
}
|
||||
|
||||
isSuccessStatusCode(statusCode?: number): boolean {
|
||||
if (!statusCode) {
|
||||
return false
|
||||
}
|
||||
return statusCode >= 200 && statusCode < 300
|
||||
}
|
||||
|
||||
isRetryableStatusCode(statusCode: number | undefined): boolean {
|
||||
if (!statusCode) {
|
||||
return false
|
||||
}
|
||||
|
||||
const retryableStatusCodes = [
|
||||
HttpCodes.BadGateway,
|
||||
HttpCodes.GatewayTimeout,
|
||||
HttpCodes.InternalServerError,
|
||||
HttpCodes.ServiceUnavailable,
|
||||
HttpCodes.TooManyRequests,
|
||||
413 // Payload Too Large
|
||||
]
|
||||
return retryableStatusCodes.includes(statusCode)
|
||||
}
|
||||
|
||||
displayHttpDiagnostics(response: HttpClientResponse): void {
|
||||
info(
|
||||
`##### Begin Diagnostic HTTP information #####
|
||||
Status Code: ${response.message.statusCode}
|
||||
Status Message: ${response.message.statusMessage}
|
||||
Header Information: ${JSON.stringify(response.message.headers, undefined, 2)}
|
||||
###### End Diagnostic HTTP information ######`
|
||||
)
|
||||
}
|
||||
|
||||
getExponentialRetryTimeInMilliseconds(
|
||||
retryCount: number
|
||||
): number {
|
||||
if (retryCount < 0) {
|
||||
throw new Error('RetryCount should not be negative')
|
||||
} else if (retryCount === 0) {
|
||||
return getInitialRetryIntervalInMilliseconds()
|
||||
}
|
||||
|
||||
const minTime =
|
||||
getInitialRetryIntervalInMilliseconds() * getRetryMultiplier() * retryCount
|
||||
const maxTime = minTime * getRetryMultiplier()
|
||||
|
||||
// returns a random number between the minTime (inclusive) and the maxTime (exclusive)
|
||||
return Math.trunc(Math.random() * (maxTime - minTime) + minTime)
|
||||
}
|
||||
|
||||
async sleep(milliseconds: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, milliseconds))
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,87 @@
|
||||
import { UploadOptions } from './upload/upload-options'
|
||||
import { UploadResponse } from './upload/upload-response'
|
||||
import { uploadArtifact } from './upload/upload-artifact'
|
||||
import {warning} from '@actions/core'
|
||||
import {isGhes} from './shared/config'
|
||||
import {
|
||||
UploadArtifactOptions,
|
||||
UploadArtifactResponse,
|
||||
DownloadArtifactOptions,
|
||||
GetArtifactResponse,
|
||||
ListArtifactsOptions,
|
||||
ListArtifactsResponse,
|
||||
DownloadArtifactResponse,
|
||||
FindOptions
|
||||
} from './shared/interfaces'
|
||||
import {uploadArtifact} from './upload/upload-artifact'
|
||||
import {
|
||||
downloadArtifactPublic,
|
||||
downloadArtifactInternal
|
||||
} from './download/download-artifact'
|
||||
import {getArtifactPublic, getArtifactInternal} from './find/get-artifact'
|
||||
import {listArtifactsPublic, listArtifactsInternal} from './find/list-artifacts'
|
||||
import {GHESNotSupportedError} from './shared/errors'
|
||||
|
||||
export interface ArtifactClient {
|
||||
/**
|
||||
* Uploads an artifact
|
||||
*
|
||||
* @param name the name of the artifact, required
|
||||
* @param files a list of absolute or relative paths that denote what files should be uploaded
|
||||
* @param rootDirectory an absolute or relative file path that denotes the root parent directory of the files being uploaded
|
||||
* @param options extra options for customizing the upload behavior
|
||||
* @returns single UploadInfo object
|
||||
* @param name The name of the artifact, required
|
||||
* @param files A list of absolute or relative paths that denote what files should be uploaded
|
||||
* @param rootDirectory An absolute or relative file path that denotes the root parent directory of the files being uploaded
|
||||
* @param options Extra options for customizing the upload behavior
|
||||
* @returns single UploadArtifactResponse object
|
||||
*/
|
||||
uploadArtifact(
|
||||
name: string,
|
||||
files: string[],
|
||||
rootDirectory: string,
|
||||
options?: UploadOptions
|
||||
): Promise<UploadResponse>
|
||||
options?: UploadArtifactOptions
|
||||
): Promise<UploadArtifactResponse>
|
||||
|
||||
// TODO Download functionality
|
||||
/**
|
||||
* Lists all artifacts that are part of the current workflow run.
|
||||
* This function will return at most 1000 artifacts per workflow run.
|
||||
*
|
||||
* If options.findBy is specified, this will call the public List-Artifacts API which can list from other runs.
|
||||
* https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#list-workflow-run-artifacts
|
||||
*
|
||||
* @param options Extra options that allow for the customization of the list behavior
|
||||
* @returns ListArtifactResponse object
|
||||
*/
|
||||
listArtifacts(
|
||||
options?: ListArtifactsOptions & FindOptions
|
||||
): Promise<ListArtifactsResponse>
|
||||
|
||||
/**
|
||||
* Finds an artifact by name.
|
||||
* If there are multiple artifacts with the same name in the same workflow run, this will return the latest.
|
||||
* If the artifact is not found, it will throw.
|
||||
*
|
||||
* If options.findBy is specified, this will use the public List Artifacts API with a name filter which can get artifacts from other runs.
|
||||
* https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#list-workflow-run-artifacts
|
||||
* @actions/artifact > 2.0.0 does not allow for creating multiple artifacts with the same name in the same workflow run.
|
||||
* It is possible to have multiple artifacts with the same name in the same workflow run by using old versions of upload-artifact (v1,v2 and v3), @actions/artifact < v2.0.0 or it is a rerun.
|
||||
* If there are multiple artifacts with the same name in the same workflow run this function will return the first artifact that matches the name.
|
||||
*
|
||||
* @param artifactName The name of the artifact to find
|
||||
* @param options Extra options that allow for the customization of the get behavior
|
||||
*/
|
||||
getArtifact(
|
||||
artifactName: string,
|
||||
options?: FindOptions
|
||||
): Promise<GetArtifactResponse>
|
||||
|
||||
/**
|
||||
* Downloads an artifact and unzips the content.
|
||||
*
|
||||
* If options.findBy is specified, this will use the public Download Artifact API https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28#download-an-artifact
|
||||
*
|
||||
* @param artifactId The name of the artifact to download
|
||||
* @param options Extra options that allow for the customization of the download behavior
|
||||
* @returns single DownloadArtifactResponse object
|
||||
*/
|
||||
downloadArtifact(
|
||||
artifactId: number,
|
||||
options?: DownloadArtifactOptions & FindOptions
|
||||
): Promise<DownloadArtifactResponse>
|
||||
}
|
||||
|
||||
export class Client implements ArtifactClient {
|
||||
@@ -31,14 +93,149 @@ export class Client implements ArtifactClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads an artifact
|
||||
* Upload Artifact
|
||||
*/
|
||||
async uploadArtifact(
|
||||
name: string,
|
||||
files: string[],
|
||||
rootDirectory: string,
|
||||
options?: UploadOptions | undefined
|
||||
): Promise<UploadResponse> {
|
||||
return uploadArtifact(name, files, rootDirectory, options)
|
||||
options?: UploadArtifactOptions
|
||||
): Promise<UploadArtifactResponse> {
|
||||
try {
|
||||
if (isGhes()) {
|
||||
throw new GHESNotSupportedError()
|
||||
}
|
||||
|
||||
return uploadArtifact(name, files, rootDirectory, options)
|
||||
} catch (error) {
|
||||
warning(
|
||||
`Artifact upload failed with error: ${error}.
|
||||
|
||||
Errors can be temporary, so please try again and optionally run the action with debug mode enabled for more information.
|
||||
|
||||
If the error persists, please check whether Actions is operating normally at [https://githubstatus.com](https://www.githubstatus.com).`
|
||||
)
|
||||
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download Artifact
|
||||
*/
|
||||
async downloadArtifact(
|
||||
artifactId: number,
|
||||
options?: DownloadArtifactOptions & FindOptions
|
||||
): Promise<DownloadArtifactResponse> {
|
||||
try {
|
||||
if (isGhes()) {
|
||||
throw new GHESNotSupportedError()
|
||||
}
|
||||
|
||||
if (options?.findBy) {
|
||||
const {
|
||||
findBy: {repositoryOwner, repositoryName, token},
|
||||
...downloadOptions
|
||||
} = options
|
||||
|
||||
return downloadArtifactPublic(
|
||||
artifactId,
|
||||
repositoryOwner,
|
||||
repositoryName,
|
||||
token,
|
||||
downloadOptions
|
||||
)
|
||||
}
|
||||
|
||||
return downloadArtifactInternal(artifactId, options)
|
||||
} catch (error) {
|
||||
warning(
|
||||
`Download Artifact failed with error: ${error}.
|
||||
|
||||
Errors can be temporary, so please try again and optionally run the action with debug mode enabled for more information.
|
||||
|
||||
If the error persists, please check whether Actions and API requests are operating normally at [https://githubstatus.com](https://www.githubstatus.com).`
|
||||
)
|
||||
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List Artifacts
|
||||
*/
|
||||
async listArtifacts(
|
||||
options?: ListArtifactsOptions & FindOptions
|
||||
): Promise<ListArtifactsResponse> {
|
||||
try {
|
||||
if (isGhes()) {
|
||||
throw new GHESNotSupportedError()
|
||||
}
|
||||
|
||||
if (options?.findBy) {
|
||||
const {
|
||||
findBy: {workflowRunId, repositoryOwner, repositoryName, token}
|
||||
} = options
|
||||
|
||||
return listArtifactsPublic(
|
||||
workflowRunId,
|
||||
repositoryOwner,
|
||||
repositoryName,
|
||||
token,
|
||||
options?.latest
|
||||
)
|
||||
}
|
||||
|
||||
return listArtifactsInternal(options?.latest)
|
||||
} catch (error: unknown) {
|
||||
warning(
|
||||
`Listing Artifacts failed with error: ${error}.
|
||||
|
||||
Errors can be temporary, so please try again and optionally run the action with debug mode enabled for more information.
|
||||
|
||||
If the error persists, please check whether Actions and API requests are operating normally at [https://githubstatus.com](https://www.githubstatus.com).`
|
||||
)
|
||||
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Artifact
|
||||
*/
|
||||
async getArtifact(
|
||||
artifactName: string,
|
||||
options?: FindOptions
|
||||
): Promise<GetArtifactResponse> {
|
||||
try {
|
||||
if (isGhes()) {
|
||||
throw new GHESNotSupportedError()
|
||||
}
|
||||
|
||||
if (options?.findBy) {
|
||||
const {
|
||||
findBy: {workflowRunId, repositoryOwner, repositoryName, token}
|
||||
} = options
|
||||
|
||||
return getArtifactPublic(
|
||||
artifactName,
|
||||
workflowRunId,
|
||||
repositoryOwner,
|
||||
repositoryName,
|
||||
token
|
||||
)
|
||||
}
|
||||
|
||||
return getArtifactInternal(artifactName)
|
||||
} catch (error: unknown) {
|
||||
warning(
|
||||
`Get Artifact failed with error: ${error}.
|
||||
|
||||
Errors can be temporary, so please try again and optionally run the action with debug mode enabled for more information.
|
||||
|
||||
If the error persists, please check whether Actions and API requests are operating normally at [https://githubstatus.com](https://www.githubstatus.com).`
|
||||
)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
export function getRuntimeToken(): string {
|
||||
const token = process.env['ACTIONS_RUNTIME_TOKEN']
|
||||
if (!token) {
|
||||
throw new Error('Unable to get the ACTIONS_RUNTIME_TOKEN environment variable which is required')
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
export function getResultsServiceUrl(): string {
|
||||
const resultsUrl = process.env['ACTIONS_RESULTS_URL']
|
||||
if (!resultsUrl) {
|
||||
throw new Error('Unable to get the ACTIONS_RESULTS_URL environment variable which is required')
|
||||
}
|
||||
return resultsUrl
|
||||
}
|
||||
|
||||
export function getWorkFlowRunId(): string {
|
||||
const workFlowRunId = process.env['GITHUB_RUN_ID']
|
||||
if (!workFlowRunId) {
|
||||
throw new Error('Unable to get the GITHUB_RUN_ID environment variable which is required')
|
||||
}
|
||||
return workFlowRunId
|
||||
}
|
||||
|
||||
export function getWorkSpaceDirectory(): string {
|
||||
const workspaceDirectory = process.env['GITHUB_WORKSPACE']
|
||||
if (!workspaceDirectory) {
|
||||
throw new Error('Unable to get the GITHUB_WORKSPACE environment variable which is required')
|
||||
}
|
||||
return workspaceDirectory
|
||||
}
|
||||
|
||||
export function getRetentionDays(): string | undefined {
|
||||
return process.env['GITHUB_RETENTION_DAYS']
|
||||
}
|
||||
|
||||
export function getInitialRetryIntervalInMilliseconds(): number {
|
||||
return 3000
|
||||
}
|
||||
|
||||
// With exponential backoff, the larger the retry count, the larger the wait time before another attempt
|
||||
// The retry multiplier controls by how much the backOff time increases depending on the number of retries
|
||||
export function getRetryMultiplier(): number {
|
||||
return 1.5
|
||||
}
|
||||
|
||||
// The maximum number of retries that can be attempted before an upload or download fails
|
||||
export function getRetryLimit(): number {
|
||||
return 5
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
import fs from 'fs/promises'
|
||||
import * as github from '@actions/github'
|
||||
import * as core from '@actions/core'
|
||||
import * as httpClient from '@actions/http-client'
|
||||
import unzipper from 'unzipper'
|
||||
import {
|
||||
DownloadArtifactOptions,
|
||||
DownloadArtifactResponse
|
||||
} from '../shared/interfaces'
|
||||
import {getUserAgentString} from '../shared/user-agent'
|
||||
import {getGitHubWorkspaceDir} from '../shared/config'
|
||||
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
|
||||
import {
|
||||
GetSignedArtifactURLRequest,
|
||||
Int64Value,
|
||||
ListArtifactsRequest
|
||||
} from '../../generated'
|
||||
import {getBackendIdsFromToken} from '../shared/util'
|
||||
import {ArtifactNotFoundError} from '../shared/errors'
|
||||
|
||||
const scrubQueryParameters = (url: string): string => {
|
||||
const parsed = new URL(url)
|
||||
parsed.search = ''
|
||||
return parsed.toString()
|
||||
}
|
||||
|
||||
async function exists(path: string): Promise<boolean> {
|
||||
try {
|
||||
await fs.access(path)
|
||||
return true
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
return false
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function streamExtract(url: string, directory: string): Promise<void> {
|
||||
const client = new httpClient.HttpClient(getUserAgentString())
|
||||
const response = await client.get(url)
|
||||
|
||||
if (response.message.statusCode !== 200) {
|
||||
throw new Error(
|
||||
`Unexpected HTTP response from blob storage: ${response.message.statusCode} ${response.message.statusMessage}`
|
||||
)
|
||||
}
|
||||
|
||||
return response.message.pipe(unzipper.Extract({path: directory})).promise()
|
||||
}
|
||||
|
||||
export async function downloadArtifactPublic(
|
||||
artifactId: number,
|
||||
repositoryOwner: string,
|
||||
repositoryName: string,
|
||||
token: string,
|
||||
options?: DownloadArtifactOptions
|
||||
): Promise<DownloadArtifactResponse> {
|
||||
const downloadPath = await resolveOrCreateDirectory(options?.path)
|
||||
|
||||
const api = github.getOctokit(token)
|
||||
|
||||
core.info(
|
||||
`Downloading artifact '${artifactId}' from '${repositoryOwner}/${repositoryName}'`
|
||||
)
|
||||
|
||||
const {headers, status} = await api.rest.actions.downloadArtifact({
|
||||
owner: repositoryOwner,
|
||||
repo: repositoryName,
|
||||
artifact_id: artifactId,
|
||||
archive_format: 'zip',
|
||||
request: {
|
||||
redirect: 'manual'
|
||||
}
|
||||
})
|
||||
|
||||
if (status !== 302) {
|
||||
throw new Error(`Unable to download artifact. Unexpected status: ${status}`)
|
||||
}
|
||||
|
||||
const {location} = headers
|
||||
if (!location) {
|
||||
throw new Error(`Unable to redirect to artifact download url`)
|
||||
}
|
||||
|
||||
core.info(
|
||||
`Redirecting to blob download url: ${scrubQueryParameters(location)}`
|
||||
)
|
||||
|
||||
try {
|
||||
core.info(`Starting download of artifact to: ${downloadPath}`)
|
||||
await streamExtract(location, downloadPath)
|
||||
core.info(`Artifact download completed successfully.`)
|
||||
} catch (error) {
|
||||
throw new Error(`Unable to download and extract artifact: ${error.message}`)
|
||||
}
|
||||
|
||||
return {downloadPath}
|
||||
}
|
||||
|
||||
export async function downloadArtifactInternal(
|
||||
artifactId: number,
|
||||
options?: DownloadArtifactOptions
|
||||
): Promise<DownloadArtifactResponse> {
|
||||
const downloadPath = await resolveOrCreateDirectory(options?.path)
|
||||
|
||||
const artifactClient = internalArtifactTwirpClient()
|
||||
|
||||
const {workflowRunBackendId, workflowJobRunBackendId} =
|
||||
getBackendIdsFromToken()
|
||||
|
||||
const listReq: ListArtifactsRequest = {
|
||||
workflowRunBackendId,
|
||||
workflowJobRunBackendId,
|
||||
idFilter: Int64Value.create({value: artifactId.toString()})
|
||||
}
|
||||
|
||||
const {artifacts} = await artifactClient.ListArtifacts(listReq)
|
||||
|
||||
if (artifacts.length === 0) {
|
||||
throw new ArtifactNotFoundError(
|
||||
`No artifacts found for ID: ${artifactId}\nAre you trying to download from a different run? Try specifying a github-token with \`actions:read\` scope.`
|
||||
)
|
||||
}
|
||||
|
||||
if (artifacts.length > 1) {
|
||||
core.warning('Multiple artifacts found, defaulting to first.')
|
||||
}
|
||||
|
||||
const signedReq: GetSignedArtifactURLRequest = {
|
||||
workflowRunBackendId: artifacts[0].workflowRunBackendId,
|
||||
workflowJobRunBackendId: artifacts[0].workflowJobRunBackendId,
|
||||
name: artifacts[0].name
|
||||
}
|
||||
|
||||
const {signedUrl} = await artifactClient.GetSignedArtifactURL(signedReq)
|
||||
|
||||
core.info(
|
||||
`Redirecting to blob download url: ${scrubQueryParameters(signedUrl)}`
|
||||
)
|
||||
|
||||
try {
|
||||
core.info(`Starting download of artifact to: ${downloadPath}`)
|
||||
await streamExtract(signedUrl, downloadPath)
|
||||
core.info(`Artifact download completed successfully.`)
|
||||
} catch (error) {
|
||||
throw new Error(`Unable to download and extract artifact: ${error.message}`)
|
||||
}
|
||||
|
||||
return {downloadPath}
|
||||
}
|
||||
|
||||
async function resolveOrCreateDirectory(
|
||||
downloadPath = getGitHubWorkspaceDir()
|
||||
): Promise<string> {
|
||||
if (!(await exists(downloadPath))) {
|
||||
core.debug(
|
||||
`Artifact destination folder does not exist, creating: ${downloadPath}`
|
||||
)
|
||||
await fs.mkdir(downloadPath, {recursive: true})
|
||||
} else {
|
||||
core.debug(`Artifact destination folder already exists: ${downloadPath}`)
|
||||
}
|
||||
|
||||
return downloadPath
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
import {getOctokit} from '@actions/github'
|
||||
import {retry} from '@octokit/plugin-retry'
|
||||
import * as core from '@actions/core'
|
||||
import {OctokitOptions} from '@octokit/core/dist-types/types'
|
||||
import {defaults as defaultGitHubOptions} from '@actions/github/lib/utils'
|
||||
import {getRetryOptions} from './retry-options'
|
||||
import {requestLog} from '@octokit/plugin-request-log'
|
||||
import {GetArtifactResponse} from '../shared/interfaces'
|
||||
import {getBackendIdsFromToken} from '../shared/util'
|
||||
import {getUserAgentString} from '../shared/user-agent'
|
||||
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
|
||||
import {ListArtifactsRequest, StringValue, Timestamp} from '../../generated'
|
||||
import {ArtifactNotFoundError, InvalidResponseError} from '../shared/errors'
|
||||
|
||||
export async function getArtifactPublic(
|
||||
artifactName: string,
|
||||
workflowRunId: number,
|
||||
repositoryOwner: string,
|
||||
repositoryName: string,
|
||||
token: string
|
||||
): Promise<GetArtifactResponse> {
|
||||
const [retryOpts, requestOpts] = getRetryOptions(defaultGitHubOptions)
|
||||
|
||||
const opts: OctokitOptions = {
|
||||
log: undefined,
|
||||
userAgent: getUserAgentString(),
|
||||
previews: undefined,
|
||||
retry: retryOpts,
|
||||
request: requestOpts
|
||||
}
|
||||
|
||||
const github = getOctokit(token, opts, retry, requestLog)
|
||||
|
||||
const getArtifactResp = await github.request(
|
||||
'GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts{?name}',
|
||||
{
|
||||
owner: repositoryOwner,
|
||||
repo: repositoryName,
|
||||
run_id: workflowRunId,
|
||||
name: artifactName
|
||||
}
|
||||
)
|
||||
|
||||
if (getArtifactResp.status !== 200) {
|
||||
throw new InvalidResponseError(
|
||||
`Invalid response from GitHub API: ${getArtifactResp.status} (${getArtifactResp?.headers?.['x-github-request-id']})`
|
||||
)
|
||||
}
|
||||
|
||||
if (getArtifactResp.data.artifacts.length === 0) {
|
||||
throw new ArtifactNotFoundError(
|
||||
`Artifact not found for name: ${artifactName}`
|
||||
)
|
||||
}
|
||||
|
||||
let artifact = getArtifactResp.data.artifacts[0]
|
||||
if (getArtifactResp.data.artifacts.length > 1) {
|
||||
artifact = getArtifactResp.data.artifacts.sort((a, b) => b.id - a.id)[0]
|
||||
core.debug(
|
||||
`More than one artifact found for a single name, returning newest (id: ${artifact.id})`
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
artifact: {
|
||||
name: artifact.name,
|
||||
id: artifact.id,
|
||||
size: artifact.size_in_bytes,
|
||||
createdAt: artifact.created_at ? new Date(artifact.created_at) : undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function getArtifactInternal(
|
||||
artifactName: string
|
||||
): Promise<GetArtifactResponse> {
|
||||
const artifactClient = internalArtifactTwirpClient()
|
||||
|
||||
const {workflowRunBackendId, workflowJobRunBackendId} =
|
||||
getBackendIdsFromToken()
|
||||
|
||||
const req: ListArtifactsRequest = {
|
||||
workflowRunBackendId,
|
||||
workflowJobRunBackendId,
|
||||
nameFilter: StringValue.create({value: artifactName})
|
||||
}
|
||||
|
||||
const res = await artifactClient.ListArtifacts(req)
|
||||
|
||||
if (res.artifacts.length === 0) {
|
||||
throw new ArtifactNotFoundError(
|
||||
`Artifact not found for name: ${artifactName}`
|
||||
)
|
||||
}
|
||||
|
||||
let artifact = res.artifacts[0]
|
||||
if (res.artifacts.length > 1) {
|
||||
artifact = res.artifacts.sort(
|
||||
(a, b) => Number(b.databaseId) - Number(a.databaseId)
|
||||
)[0]
|
||||
|
||||
core.debug(
|
||||
`More than one artifact found for a single name, returning newest (id: ${artifact.databaseId})`
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
artifact: {
|
||||
name: artifact.name,
|
||||
id: Number(artifact.databaseId),
|
||||
size: Number(artifact.size),
|
||||
createdAt: artifact.createdAt
|
||||
? Timestamp.toDate(artifact.createdAt)
|
||||
: undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
import {info, warning, debug} from '@actions/core'
|
||||
import {getOctokit} from '@actions/github'
|
||||
import {ListArtifactsResponse, Artifact} from '../shared/interfaces'
|
||||
import {getUserAgentString} from '../shared/user-agent'
|
||||
import {getRetryOptions} from './retry-options'
|
||||
import {defaults as defaultGitHubOptions} from '@actions/github/lib/utils'
|
||||
import {requestLog} from '@octokit/plugin-request-log'
|
||||
import {retry} from '@octokit/plugin-retry'
|
||||
import {OctokitOptions} from '@octokit/core/dist-types/types'
|
||||
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
|
||||
import {getBackendIdsFromToken} from '../shared/util'
|
||||
import {ListArtifactsRequest, Timestamp} from '../../generated'
|
||||
|
||||
// Limiting to 1000 for perf reasons
|
||||
const maximumArtifactCount = 1000
|
||||
const paginationCount = 100
|
||||
const maxNumberOfPages = maximumArtifactCount / paginationCount
|
||||
|
||||
export async function listArtifactsPublic(
|
||||
workflowRunId: number,
|
||||
repositoryOwner: string,
|
||||
repositoryName: string,
|
||||
token: string,
|
||||
latest = false
|
||||
): Promise<ListArtifactsResponse> {
|
||||
info(
|
||||
`Fetching artifact list for workflow run ${workflowRunId} in repository ${repositoryOwner}/${repositoryName}`
|
||||
)
|
||||
|
||||
let artifacts: Artifact[] = []
|
||||
const [retryOpts, requestOpts] = getRetryOptions(defaultGitHubOptions)
|
||||
|
||||
const opts: OctokitOptions = {
|
||||
log: undefined,
|
||||
userAgent: getUserAgentString(),
|
||||
previews: undefined,
|
||||
retry: retryOpts,
|
||||
request: requestOpts
|
||||
}
|
||||
|
||||
const github = getOctokit(token, opts, retry, requestLog)
|
||||
|
||||
let currentPageNumber = 1
|
||||
const {data: listArtifactResponse} =
|
||||
await github.rest.actions.listWorkflowRunArtifacts({
|
||||
owner: repositoryOwner,
|
||||
repo: repositoryName,
|
||||
run_id: workflowRunId,
|
||||
per_page: paginationCount,
|
||||
page: currentPageNumber
|
||||
})
|
||||
|
||||
let numberOfPages = Math.ceil(
|
||||
listArtifactResponse.total_count / paginationCount
|
||||
)
|
||||
const totalArtifactCount = listArtifactResponse.total_count
|
||||
if (totalArtifactCount > maximumArtifactCount) {
|
||||
warning(
|
||||
`Workflow run ${workflowRunId} has more than 1000 artifacts. Results will be incomplete as only the first ${maximumArtifactCount} artifacts will be returned`
|
||||
)
|
||||
numberOfPages = maxNumberOfPages
|
||||
}
|
||||
|
||||
// Iterate over the first page
|
||||
for (const artifact of listArtifactResponse.artifacts) {
|
||||
artifacts.push({
|
||||
name: artifact.name,
|
||||
id: artifact.id,
|
||||
size: artifact.size_in_bytes,
|
||||
createdAt: artifact.created_at ? new Date(artifact.created_at) : undefined
|
||||
})
|
||||
}
|
||||
|
||||
// Iterate over any remaining pages
|
||||
for (
|
||||
currentPageNumber;
|
||||
currentPageNumber < numberOfPages;
|
||||
currentPageNumber++
|
||||
) {
|
||||
currentPageNumber++
|
||||
debug(`Fetching page ${currentPageNumber} of artifact list`)
|
||||
|
||||
const {data: listArtifactResponse} =
|
||||
await github.rest.actions.listWorkflowRunArtifacts({
|
||||
owner: repositoryOwner,
|
||||
repo: repositoryName,
|
||||
run_id: workflowRunId,
|
||||
per_page: paginationCount,
|
||||
page: currentPageNumber
|
||||
})
|
||||
|
||||
for (const artifact of listArtifactResponse.artifacts) {
|
||||
artifacts.push({
|
||||
name: artifact.name,
|
||||
id: artifact.id,
|
||||
size: artifact.size_in_bytes,
|
||||
createdAt: artifact.created_at
|
||||
? new Date(artifact.created_at)
|
||||
: undefined
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (latest) {
|
||||
artifacts = filterLatest(artifacts)
|
||||
}
|
||||
|
||||
info(`Found ${artifacts.length} artifact(s)`)
|
||||
|
||||
return {
|
||||
artifacts
|
||||
}
|
||||
}
|
||||
|
||||
export async function listArtifactsInternal(
|
||||
latest = false
|
||||
): Promise<ListArtifactsResponse> {
|
||||
const artifactClient = internalArtifactTwirpClient()
|
||||
|
||||
const {workflowRunBackendId, workflowJobRunBackendId} =
|
||||
getBackendIdsFromToken()
|
||||
|
||||
const req: ListArtifactsRequest = {
|
||||
workflowRunBackendId,
|
||||
workflowJobRunBackendId
|
||||
}
|
||||
|
||||
const res = await artifactClient.ListArtifacts(req)
|
||||
let artifacts: Artifact[] = res.artifacts.map(artifact => ({
|
||||
name: artifact.name,
|
||||
id: Number(artifact.databaseId),
|
||||
size: Number(artifact.size),
|
||||
createdAt: artifact.createdAt
|
||||
? Timestamp.toDate(artifact.createdAt)
|
||||
: undefined
|
||||
}))
|
||||
|
||||
if (latest) {
|
||||
artifacts = filterLatest(artifacts)
|
||||
}
|
||||
|
||||
info(`Found ${artifacts.length} artifact(s)`)
|
||||
|
||||
return {
|
||||
artifacts
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters a list of artifacts to only include the latest artifact for each name
|
||||
* @param artifacts The artifacts to filter
|
||||
* @returns The filtered list of artifacts
|
||||
*/
|
||||
function filterLatest(artifacts: Artifact[]): Artifact[] {
|
||||
artifacts.sort((a, b) => b.id - a.id)
|
||||
const latestArtifacts: Artifact[] = []
|
||||
const seenArtifactNames = new Set<string>()
|
||||
for (const artifact of artifacts) {
|
||||
if (!seenArtifactNames.has(artifact.name)) {
|
||||
latestArtifacts.push(artifact)
|
||||
seenArtifactNames.add(artifact.name)
|
||||
}
|
||||
}
|
||||
return latestArtifacts
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import * as core from '@actions/core'
|
||||
import {OctokitOptions} from '@octokit/core/dist-types/types'
|
||||
import {RequestRequestOptions} from '@octokit/types'
|
||||
|
||||
export type RetryOptions = {
|
||||
doNotRetry?: number[]
|
||||
enabled?: boolean
|
||||
}
|
||||
|
||||
// Defaults for fetching artifacts
|
||||
const defaultMaxRetryNumber = 5
|
||||
const defaultExemptStatusCodes = [400, 401, 403, 404, 422] // https://github.com/octokit/plugin-retry.js/blob/9a2443746c350b3beedec35cf26e197ea318a261/src/index.ts#L14
|
||||
|
||||
export function getRetryOptions(
|
||||
defaultOptions: OctokitOptions,
|
||||
retries: number = defaultMaxRetryNumber,
|
||||
exemptStatusCodes: number[] = defaultExemptStatusCodes
|
||||
): [RetryOptions, RequestRequestOptions | undefined] {
|
||||
if (retries <= 0) {
|
||||
return [{enabled: false}, defaultOptions.request]
|
||||
}
|
||||
|
||||
const retryOptions: RetryOptions = {
|
||||
enabled: true
|
||||
}
|
||||
|
||||
if (exemptStatusCodes.length > 0) {
|
||||
retryOptions.doNotRetry = exemptStatusCodes
|
||||
}
|
||||
|
||||
// The GitHub type has some defaults for `options.request`
|
||||
// see: https://github.com/actions/toolkit/blob/4fbc5c941a57249b19562015edbd72add14be93d/packages/github/src/utils.ts#L15
|
||||
// We pass these in here so they are not overridden.
|
||||
const requestOptions: RequestRequestOptions = {
|
||||
...defaultOptions.request,
|
||||
retries
|
||||
}
|
||||
|
||||
core.debug(
|
||||
`GitHub client configured with: (retries: ${
|
||||
requestOptions.retries
|
||||
}, retry-exempt-status-code: ${
|
||||
retryOptions.doNotRetry ?? 'octokit default: [400, 401, 403, 404, 422]'
|
||||
})`
|
||||
)
|
||||
|
||||
return [retryOptions, requestOptions]
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
import {HttpClient, HttpClientResponse, HttpCodes} from '@actions/http-client'
|
||||
import {BearerCredentialHandler} from '@actions/http-client/lib/auth'
|
||||
import {info, debug} from '@actions/core'
|
||||
import {ArtifactServiceClientJSON} from '../../generated'
|
||||
import {getResultsServiceUrl, getRuntimeToken} from './config'
|
||||
import {getUserAgentString} from './user-agent'
|
||||
|
||||
// The twirp http client must implement this interface
|
||||
interface Rpc {
|
||||
request(
|
||||
service: string,
|
||||
method: string,
|
||||
contentType: 'application/json' | 'application/protobuf',
|
||||
data: object | Uint8Array
|
||||
): Promise<object | Uint8Array>
|
||||
}
|
||||
|
||||
class ArtifactHttpClient implements Rpc {
|
||||
private httpClient: HttpClient
|
||||
private baseUrl: string
|
||||
private maxAttempts = 5
|
||||
private baseRetryIntervalMilliseconds = 3000
|
||||
private retryMultiplier = 1.5
|
||||
|
||||
constructor(
|
||||
userAgent: string,
|
||||
maxAttempts?: number,
|
||||
baseRetryIntervalMilliseconds?: number,
|
||||
retryMultiplier?: number
|
||||
) {
|
||||
const token = getRuntimeToken()
|
||||
this.baseUrl = getResultsServiceUrl()
|
||||
if (maxAttempts) {
|
||||
this.maxAttempts = maxAttempts
|
||||
}
|
||||
if (baseRetryIntervalMilliseconds) {
|
||||
this.baseRetryIntervalMilliseconds = baseRetryIntervalMilliseconds
|
||||
}
|
||||
if (retryMultiplier) {
|
||||
this.retryMultiplier = retryMultiplier
|
||||
}
|
||||
|
||||
this.httpClient = new HttpClient(userAgent, [
|
||||
new BearerCredentialHandler(token)
|
||||
])
|
||||
}
|
||||
|
||||
// This function satisfies the Rpc interface. It is compatible with the JSON
|
||||
// JSON generated client.
|
||||
async request(
|
||||
service: string,
|
||||
method: string,
|
||||
contentType: 'application/json' | 'application/protobuf',
|
||||
data: object | Uint8Array
|
||||
): Promise<object | Uint8Array> {
|
||||
const url = new URL(`/twirp/${service}/${method}`, this.baseUrl).href
|
||||
debug(`[Request] ${method} ${url}`)
|
||||
const headers = {
|
||||
'Content-Type': contentType
|
||||
}
|
||||
try {
|
||||
const response = await this.retryableRequest(async () =>
|
||||
this.httpClient.post(url, JSON.stringify(data), headers)
|
||||
)
|
||||
const body = await response.readBody()
|
||||
return JSON.parse(body)
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to ${method}: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async retryableRequest(
|
||||
operation: () => Promise<HttpClientResponse>
|
||||
): Promise<HttpClientResponse> {
|
||||
let attempt = 0
|
||||
let errorMessage = ''
|
||||
while (attempt < this.maxAttempts) {
|
||||
let isRetryable = false
|
||||
|
||||
try {
|
||||
const response = await operation()
|
||||
const statusCode = response.message.statusCode
|
||||
debug(`[Response] ${response.message.statusCode}`)
|
||||
debug(JSON.stringify(response.message.headers, null, 2))
|
||||
|
||||
if (this.isSuccessStatusCode(statusCode)) {
|
||||
return response
|
||||
}
|
||||
|
||||
isRetryable = this.isRetryableHttpStatusCode(statusCode)
|
||||
errorMessage = `Failed request: (${statusCode}) ${response.message.statusMessage}`
|
||||
} catch (error) {
|
||||
isRetryable = true
|
||||
errorMessage = error.message
|
||||
}
|
||||
|
||||
if (!isRetryable) {
|
||||
throw new Error(`Received non-retryable error: ${errorMessage}`)
|
||||
}
|
||||
|
||||
if (attempt + 1 === this.maxAttempts) {
|
||||
throw new Error(
|
||||
`Failed to make request after ${this.maxAttempts} attempts: ${errorMessage}`
|
||||
)
|
||||
}
|
||||
|
||||
const retryTimeMilliseconds =
|
||||
this.getExponentialRetryTimeMilliseconds(attempt)
|
||||
info(
|
||||
`Attempt ${attempt + 1} of ${
|
||||
this.maxAttempts
|
||||
} failed with error: ${errorMessage}. Retrying request in ${retryTimeMilliseconds} ms...`
|
||||
)
|
||||
await this.sleep(retryTimeMilliseconds)
|
||||
attempt++
|
||||
}
|
||||
|
||||
throw new Error(`Request failed`)
|
||||
}
|
||||
|
||||
isSuccessStatusCode(statusCode?: number): boolean {
|
||||
if (!statusCode) return false
|
||||
return statusCode >= 200 && statusCode < 300
|
||||
}
|
||||
|
||||
isRetryableHttpStatusCode(statusCode?: number): boolean {
|
||||
if (!statusCode) return false
|
||||
|
||||
const retryableStatusCodes = [
|
||||
HttpCodes.BadGateway,
|
||||
HttpCodes.GatewayTimeout,
|
||||
HttpCodes.InternalServerError,
|
||||
HttpCodes.ServiceUnavailable,
|
||||
HttpCodes.TooManyRequests,
|
||||
413 // Payload Too Large
|
||||
]
|
||||
|
||||
return retryableStatusCodes.includes(statusCode)
|
||||
}
|
||||
|
||||
async sleep(milliseconds: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, milliseconds))
|
||||
}
|
||||
|
||||
getExponentialRetryTimeMilliseconds(attempt: number): number {
|
||||
if (attempt < 0) {
|
||||
throw new Error('attempt should be a positive integer')
|
||||
}
|
||||
|
||||
if (attempt === 0) {
|
||||
return this.baseRetryIntervalMilliseconds
|
||||
}
|
||||
|
||||
const minTime =
|
||||
this.baseRetryIntervalMilliseconds * this.retryMultiplier ** attempt
|
||||
const maxTime = minTime * this.retryMultiplier
|
||||
|
||||
// returns a random number between minTime and maxTime (exclusive)
|
||||
return Math.trunc(Math.random() * (maxTime - minTime) + minTime)
|
||||
}
|
||||
}
|
||||
|
||||
export function internalArtifactTwirpClient(options?: {
|
||||
maxAttempts?: number
|
||||
retryIntervalMs?: number
|
||||
retryMultiplier?: number
|
||||
}): ArtifactServiceClientJSON {
|
||||
const client = new ArtifactHttpClient(
|
||||
getUserAgentString(),
|
||||
options?.maxAttempts,
|
||||
options?.retryIntervalMs,
|
||||
options?.retryMultiplier
|
||||
)
|
||||
return new ArtifactServiceClientJSON(client)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import os from 'os'
|
||||
|
||||
// Used for controlling the highWaterMark value of the zip that is being streamed
|
||||
// The same value is used as the chunk size that is use during upload to blob storage
|
||||
export function getUploadChunkSize(): number {
|
||||
return 8 * 1024 * 1024 // 8 MB Chunks
|
||||
}
|
||||
|
||||
export function getRuntimeToken(): string {
|
||||
const token = process.env['ACTIONS_RUNTIME_TOKEN']
|
||||
if (!token) {
|
||||
throw new Error('Unable to get the ACTIONS_RUNTIME_TOKEN env variable')
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
export function getResultsServiceUrl(): string {
|
||||
const resultsUrl = process.env['ACTIONS_RESULTS_URL']
|
||||
if (!resultsUrl) {
|
||||
throw new Error('Unable to get the ACTIONS_RESULTS_URL env variable')
|
||||
}
|
||||
|
||||
return new URL(resultsUrl).origin
|
||||
}
|
||||
|
||||
export function isGhes(): boolean {
|
||||
const ghUrl = new URL(
|
||||
process.env['GITHUB_SERVER_URL'] || 'https://github.com'
|
||||
)
|
||||
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'
|
||||
}
|
||||
|
||||
export function getGitHubWorkspaceDir(): string {
|
||||
const ghWorkspaceDir = process.env['GITHUB_WORKSPACE']
|
||||
if (!ghWorkspaceDir) {
|
||||
throw new Error('Unable to get the GITHUB_WORKSPACE env variable')
|
||||
}
|
||||
return ghWorkspaceDir
|
||||
}
|
||||
|
||||
// Mimics behavior of azcopy: https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-optimize
|
||||
// If your machine has fewer than 5 CPUs, then the value of this variable is set to 32.
|
||||
// Otherwise, the default value is equal to 16 multiplied by the number of CPUs. The maximum value of this variable is 300.
|
||||
export function getConcurrency(): number {
|
||||
const numCPUs = os.cpus().length
|
||||
|
||||
if (numCPUs <= 4) {
|
||||
return 32
|
||||
}
|
||||
|
||||
const concurrency = 16 * numCPUs
|
||||
return concurrency > 300 ? 300 : concurrency
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
export class FilesNotFoundError extends Error {
|
||||
files: string[]
|
||||
|
||||
constructor(files: string[] = []) {
|
||||
let message = 'No files were found to upload'
|
||||
if (files.length > 0) {
|
||||
message += `: ${files.join(', ')}`
|
||||
}
|
||||
|
||||
super(message)
|
||||
this.files = files
|
||||
this.name = 'FilesNotFoundError'
|
||||
}
|
||||
}
|
||||
|
||||
export class InvalidResponseError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message)
|
||||
this.name = 'InvalidResponseError'
|
||||
}
|
||||
}
|
||||
|
||||
export class ArtifactNotFoundError extends Error {
|
||||
constructor(message = 'Artifact not found') {
|
||||
super(message)
|
||||
this.name = 'ArtifactNotFoundError'
|
||||
}
|
||||
}
|
||||
|
||||
export class GHESNotSupportedError extends Error {
|
||||
constructor(
|
||||
message = '@actions/artifact v2.0.0+ and download-artifact@v4+ are not currently supported on GHES.'
|
||||
) {
|
||||
super(message)
|
||||
this.name = 'GHESNotSupportedError'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*****************************************************************************
|
||||
* *
|
||||
* UploadArtifact *
|
||||
* *
|
||||
*****************************************************************************/
|
||||
export interface UploadArtifactResponse {
|
||||
/**
|
||||
* Total size of the artifact in bytes. Not provided if no artifact was uploaded
|
||||
*/
|
||||
size?: number
|
||||
|
||||
/**
|
||||
* The id of the artifact that was created. Not provided if no artifact was uploaded
|
||||
* This ID can be used as input to other APIs to download, delete or get more information about an artifact: https://docs.github.com/en/rest/actions/artifacts
|
||||
*/
|
||||
id?: number
|
||||
}
|
||||
|
||||
export interface UploadArtifactOptions {
|
||||
/**
|
||||
* Duration after which artifact will expire in days.
|
||||
*
|
||||
* By default artifact expires after 90 days:
|
||||
* https://docs.github.com/en/actions/configuring-and-managing-workflows/persisting-workflow-data-using-artifacts#downloading-and-deleting-artifacts-after-a-workflow-run-is-complete
|
||||
*
|
||||
* Use this option to override the default expiry.
|
||||
*
|
||||
* Min value: 1
|
||||
* Max value: 90 unless changed by repository setting
|
||||
*
|
||||
* If this is set to a greater value than the retention settings allowed, the retention on artifacts
|
||||
* will be reduced to match the max value allowed on server, and the upload process will continue. An
|
||||
* input of 0 assumes default retention setting.
|
||||
*/
|
||||
retentionDays?: number
|
||||
/**
|
||||
* The level of compression for Zlib to be applied to the artifact archive.
|
||||
* The value can range from 0 to 9:
|
||||
* - 0: No compression
|
||||
* - 1: Best speed
|
||||
* - 6: Default compression (same as GNU Gzip)
|
||||
* - 9: Best compression
|
||||
* Higher levels will result in better compression, but will take longer to complete.
|
||||
* For large files that are not easily compressed, a value of 0 is recommended for significantly faster uploads.
|
||||
*/
|
||||
compressionLevel?: number
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* *
|
||||
* GetArtifact *
|
||||
* *
|
||||
*****************************************************************************/
|
||||
|
||||
export interface GetArtifactResponse {
|
||||
/**
|
||||
* Metadata about the artifact that was found
|
||||
*/
|
||||
artifact: Artifact
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* *
|
||||
* ListArtifact *
|
||||
* *
|
||||
*****************************************************************************/
|
||||
|
||||
export interface ListArtifactsOptions {
|
||||
/**
|
||||
* Filter the workflow run's artifacts to the latest by name
|
||||
* In the case of reruns, this can be useful to avoid duplicates
|
||||
*/
|
||||
latest?: boolean
|
||||
}
|
||||
|
||||
export interface ListArtifactsResponse {
|
||||
/**
|
||||
* A list of artifacts that were found
|
||||
*/
|
||||
artifacts: Artifact[]
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* *
|
||||
* DownloadArtifact *
|
||||
* *
|
||||
*****************************************************************************/
|
||||
export interface DownloadArtifactResponse {
|
||||
/**
|
||||
* The path where the artifact was downloaded to
|
||||
*/
|
||||
downloadPath?: string
|
||||
}
|
||||
|
||||
export interface DownloadArtifactOptions {
|
||||
/**
|
||||
* Denotes where the artifact will be downloaded to. If not specified then the artifact is download to GITHUB_WORKSPACE
|
||||
*/
|
||||
path?: string
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* *
|
||||
* Shared *
|
||||
* *
|
||||
*****************************************************************************/
|
||||
export interface Artifact {
|
||||
/**
|
||||
* The name of the artifact
|
||||
*/
|
||||
name: string
|
||||
|
||||
/**
|
||||
* The ID of the artifact
|
||||
*/
|
||||
id: number
|
||||
|
||||
/**
|
||||
* The size of the artifact in bytes
|
||||
*/
|
||||
size: number
|
||||
|
||||
/**
|
||||
* The time when the artifact was created
|
||||
*/
|
||||
createdAt?: Date
|
||||
}
|
||||
|
||||
// FindOptions are for fetching Artifact(s) out of the scope of the current run.
|
||||
// Must specify a PAT with actions:read scope for cross run/repo lookup otherwise these will be ignored.
|
||||
export interface FindOptions {
|
||||
findBy?: {
|
||||
// Token with actions:read permissions
|
||||
token: string
|
||||
// WorkflowRun of the artifact(s) to lookup
|
||||
workflowRunId: number
|
||||
// Repository owner
|
||||
repositoryOwner: string
|
||||
// Repository name
|
||||
repositoryName: string
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
|
||||
const packageJson = require('../../../package.json')
|
||||
|
||||
/**
|
||||
* Ensure that this User Agent String is used in all HTTP calls so that we can monitor telemetry between different versions of this package
|
||||
*/
|
||||
export function getUserAgentString(): string {
|
||||
return `@actions/artifact-${packageJson.version}`
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import * as core from '@actions/core'
|
||||
import {getRuntimeToken} from './config'
|
||||
import jwt_decode from 'jwt-decode'
|
||||
|
||||
export interface BackendIds {
|
||||
workflowRunBackendId: string
|
||||
workflowJobRunBackendId: string
|
||||
}
|
||||
|
||||
interface ActionsToken {
|
||||
scp: string
|
||||
}
|
||||
|
||||
const InvalidJwtError = new Error(
|
||||
'Failed to get backend IDs: The provided JWT token is invalid and/or missing claims'
|
||||
)
|
||||
|
||||
// uses the JWT token claims to get the
|
||||
// workflow run and workflow job run backend ids
|
||||
export function getBackendIdsFromToken(): BackendIds {
|
||||
const token = getRuntimeToken()
|
||||
const decoded = jwt_decode<ActionsToken>(token)
|
||||
if (!decoded.scp) {
|
||||
throw InvalidJwtError
|
||||
}
|
||||
|
||||
/*
|
||||
* example decoded:
|
||||
* {
|
||||
* scp: "Actions.ExampleScope Actions.Results:ce7f54c7-61c7-4aae-887f-30da475f5f1a:ca395085-040a-526b-2ce8-bdc85f692774"
|
||||
* }
|
||||
*/
|
||||
|
||||
const scpParts = decoded.scp.split(' ')
|
||||
if (scpParts.length === 0) {
|
||||
throw InvalidJwtError
|
||||
}
|
||||
/*
|
||||
* example scpParts:
|
||||
* ["Actions.ExampleScope", "Actions.Results:ce7f54c7-61c7-4aae-887f-30da475f5f1a:ca395085-040a-526b-2ce8-bdc85f692774"]
|
||||
*/
|
||||
|
||||
for (const scopes of scpParts) {
|
||||
const scopeParts = scopes.split(':')
|
||||
if (scopeParts?.[0] !== 'Actions.Results') {
|
||||
// not the Actions.Results scope
|
||||
continue
|
||||
}
|
||||
|
||||
/*
|
||||
* example scopeParts:
|
||||
* ["Actions.Results", "ce7f54c7-61c7-4aae-887f-30da475f5f1a", "ca395085-040a-526b-2ce8-bdc85f692774"]
|
||||
*/
|
||||
if (scopeParts.length !== 3) {
|
||||
// missing expected number of claims
|
||||
throw InvalidJwtError
|
||||
}
|
||||
|
||||
const ids = {
|
||||
workflowRunBackendId: scopeParts[1],
|
||||
workflowJobRunBackendId: scopeParts[2]
|
||||
}
|
||||
|
||||
core.debug(`Workflow Run Backend ID: ${ids.workflowRunBackendId}`)
|
||||
core.debug(`Workflow Job Run Backend ID: ${ids.workflowJobRunBackendId}`)
|
||||
|
||||
return ids
|
||||
}
|
||||
|
||||
throw InvalidJwtError
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import {BlobClient, BlockBlobUploadStreamOptions} from '@azure/storage-blob'
|
||||
import {TransferProgressEvent} from '@azure/core-http'
|
||||
import {ZipUploadStream} from './zip'
|
||||
import {getUploadChunkSize, getConcurrency} from '../shared/config'
|
||||
import * as core from '@actions/core'
|
||||
import * as crypto from 'crypto'
|
||||
import * as stream from 'stream'
|
||||
|
||||
export interface BlobUploadResponse {
|
||||
/**
|
||||
* The total reported upload size in bytes. Empty if the upload failed
|
||||
*/
|
||||
uploadSize?: number
|
||||
|
||||
/**
|
||||
* The SHA256 hash of the uploaded file. Empty if the upload failed
|
||||
*/
|
||||
sha256Hash?: string
|
||||
}
|
||||
|
||||
export async function uploadZipToBlobStorage(
|
||||
authenticatedUploadURL: string,
|
||||
zipUploadStream: ZipUploadStream
|
||||
): Promise<BlobUploadResponse> {
|
||||
let uploadByteCount = 0
|
||||
|
||||
const maxConcurrency = getConcurrency()
|
||||
const bufferSize = getUploadChunkSize()
|
||||
const blobClient = new BlobClient(authenticatedUploadURL)
|
||||
const blockBlobClient = blobClient.getBlockBlobClient()
|
||||
|
||||
core.debug(
|
||||
`Uploading artifact zip to blob storage with maxConcurrency: ${maxConcurrency}, bufferSize: ${bufferSize}`
|
||||
)
|
||||
|
||||
const uploadCallback = (progress: TransferProgressEvent): void => {
|
||||
core.info(`Uploaded bytes ${progress.loadedBytes}`)
|
||||
uploadByteCount = progress.loadedBytes
|
||||
}
|
||||
|
||||
const options: BlockBlobUploadStreamOptions = {
|
||||
blobHTTPHeaders: {blobContentType: 'zip'},
|
||||
onProgress: uploadCallback
|
||||
}
|
||||
|
||||
let sha256Hash: string | undefined = undefined
|
||||
const uploadStream = new stream.PassThrough()
|
||||
const hashStream = crypto.createHash('sha256')
|
||||
|
||||
zipUploadStream.pipe(uploadStream) // This stream is used for the upload
|
||||
zipUploadStream.pipe(hashStream).setEncoding('hex') // This stream is used to compute a hash of the zip content that gets used. Integrity check
|
||||
|
||||
core.info('Beginning upload of artifact content to blob storage')
|
||||
|
||||
await blockBlobClient.uploadStream(
|
||||
uploadStream,
|
||||
bufferSize,
|
||||
maxConcurrency,
|
||||
options
|
||||
)
|
||||
|
||||
core.info('Finished uploading artifact content to blob storage!')
|
||||
|
||||
hashStream.end()
|
||||
sha256Hash = hashStream.read() as string
|
||||
core.info(`SHA256 hash of uploaded artifact zip is ${sha256Hash}`)
|
||||
|
||||
if (uploadByteCount === 0) {
|
||||
core.warning(
|
||||
`No data was uploaded to blob storage. Reported upload byte count is 0.`
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
uploadSize: uploadByteCount,
|
||||
sha256Hash
|
||||
}
|
||||
}
|
||||
@@ -27,11 +27,11 @@ const invalidArtifactNameCharacters = new Map<string, string>([
|
||||
])
|
||||
|
||||
/**
|
||||
* Scans the name of the artifact to make sure there are no illegal characters
|
||||
* Validates the name of the artifact to check to make sure there are no illegal characters
|
||||
*/
|
||||
export function checkArtifactName(name: string): void {
|
||||
export function validateArtifactName(name: string): void {
|
||||
if (!name) {
|
||||
throw new Error(`Artifact name: ${name}, is incorrectly provided`)
|
||||
throw new Error(`Provided artifact name input during validation is empty`)
|
||||
}
|
||||
|
||||
for (const [
|
||||
@@ -40,7 +40,7 @@ export function checkArtifactName(name: string): void {
|
||||
] of invalidArtifactNameCharacters) {
|
||||
if (name.includes(invalidCharacterKey)) {
|
||||
throw new Error(
|
||||
`Artifact name is not valid: ${name}. Contains the following character: ${errorMessageForCharacter}
|
||||
`The artifact name is not valid: ${name}. Contains the following character: ${errorMessageForCharacter}
|
||||
|
||||
Invalid characters include: ${Array.from(
|
||||
invalidArtifactNameCharacters.values()
|
||||
@@ -55,11 +55,11 @@ These characters are not allowed in the artifact name due to limitations with ce
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the name of the filePath used to make sure there are no illegal characters
|
||||
* Validates file paths to check for any illegal characters that can cause problems on different file systems
|
||||
*/
|
||||
export function checkArtifactFilePath(path: string): void {
|
||||
export function validateFilePath(path: string): void {
|
||||
if (!path) {
|
||||
throw new Error(`Artifact path: ${path}, is incorrectly provided`)
|
||||
throw new Error(`Provided file path input during validation is empty`)
|
||||
}
|
||||
|
||||
for (const [
|
||||
@@ -68,7 +68,7 @@ export function checkArtifactFilePath(path: string): void {
|
||||
] of invalidArtifactFilePathCharacters) {
|
||||
if (path.includes(invalidCharacterKey)) {
|
||||
throw new Error(
|
||||
`Artifact path is not valid: ${path}. Contains the following character: ${errorMessageForCharacter}
|
||||
`The path for one of the files in artifact is not valid: ${path}. Contains the following character: ${errorMessageForCharacter}
|
||||
|
||||
Invalid characters include: ${Array.from(
|
||||
invalidArtifactFilePathCharacters.values()
|
||||
@@ -79,4 +79,4 @@ The following characters are not allowed in files that are uploaded due to limit
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import {Timestamp} from '../../generated'
|
||||
import * as core from '@actions/core'
|
||||
|
||||
export function getExpiration(retentionDays?: number): Timestamp | undefined {
|
||||
if (!retentionDays) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const maxRetentionDays = getRetentionDays()
|
||||
if (maxRetentionDays && maxRetentionDays < retentionDays) {
|
||||
core.warning(
|
||||
`Retention days cannot be greater than the maximum allowed retention set within the repository. Using ${maxRetentionDays} instead.`
|
||||
)
|
||||
retentionDays = maxRetentionDays
|
||||
}
|
||||
|
||||
const expirationDate = new Date()
|
||||
expirationDate.setDate(expirationDate.getDate() + retentionDays)
|
||||
|
||||
return Timestamp.fromDate(expirationDate)
|
||||
}
|
||||
|
||||
function getRetentionDays(): number | undefined {
|
||||
const retentionDays = process.env['GITHUB_RETENTION_DAYS']
|
||||
if (!retentionDays) {
|
||||
return undefined
|
||||
}
|
||||
const days = parseInt(retentionDays)
|
||||
if (isNaN(days)) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return days
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
hello there! This is from a.txt
|
||||
@@ -1 +0,0 @@
|
||||
This is from b.txt
|
||||
@@ -1,123 +0,0 @@
|
||||
import {BlobClient, BlockBlobUploadStreamOptions} from '@azure/storage-blob'
|
||||
import { TransferProgressEvent } from '@azure/core-http';
|
||||
import * as a from 'archiver'
|
||||
import * as fs from 'fs'
|
||||
import * as stream from 'stream'
|
||||
|
||||
const bufferSize = 1024 * 1024 * 8 // 8 MB
|
||||
|
||||
// Custom stream transformer so we can set the highWaterMark property
|
||||
// See https://github.com/nodejs/node/issues/8855
|
||||
export class ZipUploadStream extends stream.Transform {
|
||||
constructor(bufferSize: number) {
|
||||
super({
|
||||
highWaterMark: bufferSize
|
||||
})
|
||||
}
|
||||
|
||||
_transform(chunk:any, enc:any, cb:any) {
|
||||
cb(null, chunk)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// for local testing, run this using ts-node testing.ts
|
||||
export async function test(){
|
||||
let sasURL = "paste here"
|
||||
sasURL = sasURL.replace("http://devstoreaccount1.blob.codedev.localhost", "http://127.0.0.1:11000/devstoreaccount1")
|
||||
|
||||
const blobClient = new BlobClient(sasURL);
|
||||
const zip = a.create('zip', {
|
||||
zlib: { level: 9 } // Sets the compression level.
|
||||
// Available options are 0-9
|
||||
// 0 => no compression
|
||||
// 1 => fastest with low compression
|
||||
// 9 => highest compression ratio but the slowest
|
||||
});
|
||||
|
||||
// append files that are going to be part of the final zip
|
||||
zip.append('this is file 1', { name: 'file1.txt' });
|
||||
zip.append('this is file 2', { name: 'file2.txt' });
|
||||
zip.append('this is file 1 in a directory', { name: 'dir/file1.txt' });
|
||||
zip.append('this is file 2 in a directory', { name: 'dir/file2.txt' });
|
||||
zip.append('this is a live demo!!!', { name: 'dir/alive.txt' });
|
||||
zip.append(fs.createReadStream('a.txt'), { name: 'dir2/a.txt' })
|
||||
zip.append(fs.createReadStream('b.txt'), { name: 'dir2/b.txt' })
|
||||
|
||||
const zipUploadStream = new ZipUploadStream(bufferSize)
|
||||
zip.pipe(zipUploadStream)
|
||||
zip.finalize();
|
||||
|
||||
console.log("Write high watermark value " + zipUploadStream.writableHighWaterMark)
|
||||
console.log("Read high watermark value " + zipUploadStream.readableHighWaterMark)
|
||||
|
||||
// good practice to catch warnings (ie stat failures and other non-blocking errors)
|
||||
zip.on('warning', function(err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
console.log("zip error ENOENT")
|
||||
} else {
|
||||
console.log("some other warning ")
|
||||
console.log(err)
|
||||
}
|
||||
});
|
||||
|
||||
// good practice to catch this error explicitly
|
||||
zip.on('error', function(err) {
|
||||
console.log("some error with zip ")
|
||||
console.log(err)
|
||||
});
|
||||
|
||||
zip.on("progress", function(progress: a.ProgressData) {
|
||||
console.log(progress)
|
||||
|
||||
/* This outputs data like this, we could potentially do something with this for even more logging to show the status of the zip creation
|
||||
{
|
||||
entries: { total: 7, processed: 1 },
|
||||
fs: { totalBytes: 0, processedBytes: 0 }
|
||||
}
|
||||
{
|
||||
entries: { total: 7, processed: 2 },
|
||||
fs: { totalBytes: 0, processedBytes: 0 }
|
||||
}
|
||||
*/
|
||||
})
|
||||
|
||||
|
||||
// We can add these to debug logging
|
||||
zip.on('end', function() {
|
||||
console.log("zip ending")
|
||||
});
|
||||
zip.on('finish', function() {
|
||||
console.log("zip finished")
|
||||
});
|
||||
|
||||
// Upload options
|
||||
const maxBuffers = 5
|
||||
const blockBlobClient = blobClient.getBlockBlobClient()
|
||||
|
||||
let uploadByteCount = 0
|
||||
var myCallback = function(progress: TransferProgressEvent) {
|
||||
console.log("Byte upload count " + progress.loadedBytes)
|
||||
uploadByteCount = progress.loadedBytes
|
||||
};
|
||||
|
||||
const options: BlockBlobUploadStreamOptions = {
|
||||
blobHTTPHeaders: { "blobContentType": "zip" },
|
||||
onProgress: myCallback
|
||||
}
|
||||
|
||||
// Upload!
|
||||
try {
|
||||
const aa = await blockBlobClient.uploadStream(
|
||||
zipUploadStream,
|
||||
bufferSize,
|
||||
maxBuffers,
|
||||
options
|
||||
);
|
||||
} catch (error){
|
||||
console.log(error)
|
||||
}
|
||||
console.log("final upload size in bytes is " + uploadByteCount)
|
||||
}
|
||||
|
||||
test()
|
||||
@@ -1,32 +0,0 @@
|
||||
import { ArtifactHttpClient } from '../../artifact-http-client'
|
||||
import { ArtifactServiceClientJSON } from '../../../generated/results/api/v1/artifact.twirp'
|
||||
|
||||
export async function twirpTest(){
|
||||
const artifactClient = new ArtifactHttpClient('@actions/artifact-upload')
|
||||
const jsonClient = new ArtifactServiceClientJSON(artifactClient)
|
||||
|
||||
try {
|
||||
const createResp = await jsonClient.CreateArtifact({workflowRunBackendId: "ce7f54c7-61c7-4aae-887f-30da475f5f1a", workflowJobRunBackendId: "ca395085-040a-526b-2ce8-bdc85f692774", name: Math.random().toString(), version: 4})
|
||||
|
||||
if (!createResp.ok) {
|
||||
console.log("CreateArtifact failed")
|
||||
return
|
||||
}
|
||||
|
||||
console.log(createResp.signedUploadUrl)
|
||||
|
||||
const finalizeResp = await jsonClient.FinalizeArtifact({workflowRunBackendId: "ce7f54c7-61c7-4aae-887f-30da475f5f1a", workflowJobRunBackendId: "ca395085-040a-526b-2ce8-bdc85f692774", name: Math.random().toString(), size: BigInt(5)})
|
||||
|
||||
if (!finalizeResp.ok) {
|
||||
console.log("FinalizeArtifact failed")
|
||||
return
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
return
|
||||
}
|
||||
|
||||
console.log("FinalizeArtifact succeeded")
|
||||
}
|
||||
|
||||
twirpTest()
|
||||
@@ -1,190 +1,115 @@
|
||||
import * as core from '@actions/core'
|
||||
import {checkArtifactName} from './path-and-artifact-name-validation'
|
||||
import {UploadOptions} from './upload-options'
|
||||
import {UploadResponse} from './upload-response'
|
||||
import { UploadSpecification, getUploadSpecification } from './upload-specification'
|
||||
import { ArtifactHttpClient } from '../artifact-http-client'
|
||||
import { ArtifactServiceClientJSON } from '../../generated/results/api/v1/artifact.twirp'
|
||||
|
||||
import {BlobClient, BlockBlobUploadStreamOptions} from '@azure/storage-blob'
|
||||
import { TransferProgressEvent } from '@azure/core-http';
|
||||
import * as a from 'archiver'
|
||||
import * as fs from 'fs'
|
||||
import * as stream from 'stream'
|
||||
|
||||
import {getBackendIds, BackendIds} from '../util'
|
||||
|
||||
const bufferSize = 1024 * 1024 * 8 // 8 MB
|
||||
|
||||
// Custom stream transformer so we can set the highWaterMark property
|
||||
// See https://github.com/nodejs/node/issues/8855
|
||||
export class ZipUploadStream extends stream.Transform {
|
||||
constructor(bufferSize: number) {
|
||||
super({
|
||||
highWaterMark: bufferSize
|
||||
})
|
||||
}
|
||||
|
||||
_transform(chunk:any, enc:any, cb:any) {
|
||||
cb(null, chunk)
|
||||
}
|
||||
}
|
||||
import {
|
||||
UploadArtifactOptions,
|
||||
UploadArtifactResponse
|
||||
} from '../shared/interfaces'
|
||||
import {getExpiration} from './retention'
|
||||
import {validateArtifactName} from './path-and-artifact-name-validation'
|
||||
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client'
|
||||
import {
|
||||
UploadZipSpecification,
|
||||
getUploadZipSpecification,
|
||||
validateRootDirectory
|
||||
} from './upload-zip-specification'
|
||||
import {getBackendIdsFromToken} from '../shared/util'
|
||||
import {uploadZipToBlobStorage} from './blob-upload'
|
||||
import {createZipUploadStream} from './zip'
|
||||
import {
|
||||
CreateArtifactRequest,
|
||||
FinalizeArtifactRequest,
|
||||
StringValue
|
||||
} from '../../generated'
|
||||
import {FilesNotFoundError, InvalidResponseError} from '../shared/errors'
|
||||
|
||||
export async function uploadArtifact(
|
||||
name: string,
|
||||
files: string[],
|
||||
rootDirectory: string,
|
||||
options?: UploadOptions | undefined
|
||||
): Promise<UploadResponse> {
|
||||
name: string,
|
||||
files: string[],
|
||||
rootDirectory: string,
|
||||
options?: UploadArtifactOptions | undefined
|
||||
): Promise<UploadArtifactResponse> {
|
||||
validateArtifactName(name)
|
||||
validateRootDirectory(rootDirectory)
|
||||
|
||||
let uploadByteCount = 0
|
||||
|
||||
// Need to keep checking the artifact name
|
||||
checkArtifactName(name)
|
||||
|
||||
// Get specification for the files being uploaded
|
||||
const uploadSpecification: UploadSpecification[] = getUploadSpecification(
|
||||
name,
|
||||
rootDirectory,
|
||||
files
|
||||
const zipSpecification: UploadZipSpecification[] = getUploadZipSpecification(
|
||||
files,
|
||||
rootDirectory
|
||||
)
|
||||
if (zipSpecification.length === 0) {
|
||||
throw new FilesNotFoundError(
|
||||
zipSpecification.flatMap(s => (s.sourcePath ? [s.sourcePath] : []))
|
||||
)
|
||||
}
|
||||
|
||||
if (uploadSpecification.length === 0) {
|
||||
core.warning(`No files found that can be uploaded`)
|
||||
} else {
|
||||
const artifactClient = new ArtifactHttpClient('@actions/artifact-upload')
|
||||
const jsonClient = new ArtifactServiceClientJSON(artifactClient)
|
||||
const zipUploadStream = await createZipUploadStream(
|
||||
zipSpecification,
|
||||
options?.compressionLevel
|
||||
)
|
||||
|
||||
const backendIDs: BackendIds = getBackendIds()
|
||||
// get the IDs needed for the artifact creation
|
||||
const backendIds = getBackendIdsFromToken()
|
||||
|
||||
console.log("workflow Run Backend ID " + backendIDs.workflowRunBackendId)
|
||||
console.log("workflow Job Run Backend ID " + backendIDs.workflowJobRunBackendId)
|
||||
// create the artifact client
|
||||
const artifactClient = internalArtifactTwirpClient()
|
||||
|
||||
console.log("hello Rob!!")
|
||||
// create the artifact
|
||||
const createArtifactReq: CreateArtifactRequest = {
|
||||
workflowRunBackendId: backendIds.workflowRunBackendId,
|
||||
workflowJobRunBackendId: backendIds.workflowJobRunBackendId,
|
||||
name,
|
||||
version: 4
|
||||
}
|
||||
|
||||
try {
|
||||
// if there is a retention period, add it to the request
|
||||
const expiresAt = getExpiration(options?.retentionDays)
|
||||
if (expiresAt) {
|
||||
createArtifactReq.expiresAt = expiresAt
|
||||
}
|
||||
|
||||
const createArtifactResp =
|
||||
await artifactClient.CreateArtifact(createArtifactReq)
|
||||
if (!createArtifactResp.ok) {
|
||||
throw new InvalidResponseError(
|
||||
'CreateArtifact: response from backend was not ok'
|
||||
)
|
||||
}
|
||||
|
||||
// Upload zip to blob storage
|
||||
const uploadResult = await uploadZipToBlobStorage(
|
||||
createArtifactResp.signedUploadUrl,
|
||||
zipUploadStream
|
||||
)
|
||||
|
||||
// finalize the artifact
|
||||
const finalizeArtifactReq: FinalizeArtifactRequest = {
|
||||
workflowRunBackendId: backendIds.workflowRunBackendId,
|
||||
workflowJobRunBackendId: backendIds.workflowJobRunBackendId,
|
||||
name,
|
||||
size: uploadResult.uploadSize ? uploadResult.uploadSize.toString() : '0'
|
||||
}
|
||||
|
||||
const createResp = await jsonClient.CreateArtifact({workflowRunBackendId: backendIDs.workflowRunBackendId, workflowJobRunBackendId: backendIDs.workflowJobRunBackendId, name: name, version: 4})
|
||||
|
||||
if (!createResp.ok) {
|
||||
core.error("CreateArtifact failed")
|
||||
}
|
||||
|
||||
console.log(createResp.signedUploadUrl)
|
||||
|
||||
// Blob upload start
|
||||
if (uploadResult.sha256Hash) {
|
||||
finalizeArtifactReq.hash = StringValue.create({
|
||||
value: `sha256:${uploadResult.sha256Hash}`
|
||||
})
|
||||
}
|
||||
|
||||
const blobClient = new BlobClient(createResp.signedUploadUrl);
|
||||
const zip = a.create('zip', {
|
||||
zlib: { level: 9 } // Sets the compression level.
|
||||
// Available options are 0-9
|
||||
// 0 => no compression
|
||||
// 1 => fastest with low compression
|
||||
// 9 => highest compression ratio but the slowest
|
||||
});
|
||||
core.info(`Finalizing artifact upload`)
|
||||
|
||||
console.log("file specification")
|
||||
for (const file of uploadSpecification) {
|
||||
console.log("uploadPath:" + file.uploadFilePath + " absolute:" + file.absoluteFilePath)
|
||||
zip.append(fs.createReadStream(file.absoluteFilePath), {name: file.uploadFilePath})
|
||||
}
|
||||
const finalizeArtifactResp =
|
||||
await artifactClient.FinalizeArtifact(finalizeArtifactReq)
|
||||
if (!finalizeArtifactResp.ok) {
|
||||
throw new InvalidResponseError(
|
||||
'FinalizeArtifact: response from backend was not ok'
|
||||
)
|
||||
}
|
||||
|
||||
const zipUploadStream = new ZipUploadStream(bufferSize)
|
||||
zip.pipe(zipUploadStream)
|
||||
zip.finalize();
|
||||
const artifactId = BigInt(finalizeArtifactResp.artifactId)
|
||||
core.info(
|
||||
`Artifact ${name}.zip successfully finalized. Artifact ID ${artifactId}`
|
||||
)
|
||||
|
||||
console.log("Write high watermark value " + zipUploadStream.writableHighWaterMark)
|
||||
console.log("Read high watermark value " + zipUploadStream.readableHighWaterMark)
|
||||
|
||||
// good practice to catch warnings (ie stat failures and other non-blocking errors)
|
||||
zip.on('warning', function(err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
console.log("zip error ENOENT")
|
||||
} else {
|
||||
console.log("some other warning ")
|
||||
console.log(err)
|
||||
}
|
||||
});
|
||||
|
||||
// good practice to catch this error explicitly
|
||||
zip.on('error', function(err) {
|
||||
console.log("some error with zip ")
|
||||
console.log(err)
|
||||
});
|
||||
|
||||
zip.on("progress", function(progress: a.ProgressData) {
|
||||
console.log(progress)
|
||||
|
||||
/* This outputs data like this, we could potentially do something with this for even more logging to show the status of the zip creation
|
||||
{
|
||||
entries: { total: 7, processed: 1 },
|
||||
fs: { totalBytes: 0, processedBytes: 0 }
|
||||
}
|
||||
{
|
||||
entries: { total: 7, processed: 2 },
|
||||
fs: { totalBytes: 0, processedBytes: 0 }
|
||||
}
|
||||
*/
|
||||
})
|
||||
|
||||
|
||||
// We can add these to debug logging
|
||||
zip.on('end', function() {
|
||||
console.log("zip ending")
|
||||
});
|
||||
zip.on('finish', function() {
|
||||
console.log("zip finished")
|
||||
});
|
||||
|
||||
// Upload options
|
||||
const maxBuffers = 5
|
||||
const blockBlobClient = blobClient.getBlockBlobClient()
|
||||
|
||||
var myCallback = function(progress: TransferProgressEvent) {
|
||||
console.log("Byte upload count " + progress.loadedBytes)
|
||||
uploadByteCount = progress.loadedBytes
|
||||
};
|
||||
|
||||
const options: BlockBlobUploadStreamOptions = {
|
||||
blobHTTPHeaders: { "blobContentType": "zip" },
|
||||
onProgress: myCallback
|
||||
}
|
||||
|
||||
// Upload!
|
||||
try {
|
||||
await blockBlobClient.uploadStream(
|
||||
zipUploadStream,
|
||||
bufferSize,
|
||||
maxBuffers,
|
||||
options
|
||||
);
|
||||
} catch (error){
|
||||
console.log(error)
|
||||
}
|
||||
console.log("final upload size in bytes is " + uploadByteCount)
|
||||
|
||||
console.log("we are done with the blob upload!")
|
||||
// Blob upload end
|
||||
|
||||
const finalizeResp = await jsonClient.FinalizeArtifact({workflowRunBackendId: backendIDs.workflowRunBackendId, workflowJobRunBackendId: backendIDs.workflowJobRunBackendId, name: name, size: BigInt(5)})
|
||||
|
||||
if (!finalizeResp.ok) {
|
||||
core.error("FinalizeArtifact failed")
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
console.log("FinalizeArtifact succeeded")
|
||||
}
|
||||
|
||||
const uploadResponse: UploadResponse = {
|
||||
artifactName: name,
|
||||
size: uploadByteCount
|
||||
}
|
||||
|
||||
return uploadResponse
|
||||
}
|
||||
return {
|
||||
size: uploadResult.uploadSize,
|
||||
id: Number(artifactId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
export interface UploadOptions {
|
||||
/**
|
||||
* Duration after which artifact will expire in days.
|
||||
*
|
||||
* By default artifact expires after 90 days:
|
||||
* https://docs.github.com/en/actions/configuring-and-managing-workflows/persisting-workflow-data-using-artifacts#downloading-and-deleting-artifacts-after-a-workflow-run-is-complete
|
||||
*
|
||||
* Use this option to override the default expiry.
|
||||
*
|
||||
* Min value: 1
|
||||
* Max value: 90 unless changed by repository setting
|
||||
*
|
||||
* If this is set to a greater value than the retention settings allowed, the retention on artifacts
|
||||
* will be reduced to match the max value allowed on server, and the upload process will continue. An
|
||||
* input of 0 assumes default retention setting.
|
||||
*/
|
||||
retentionDays?: number
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
export interface UploadResponse {
|
||||
/**
|
||||
* The name of the artifact that was uploaded
|
||||
*/
|
||||
artifactName: string
|
||||
|
||||
/**
|
||||
* Total size of the artifact that was uploaded in bytes
|
||||
*/
|
||||
size: number
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
import * as fs from 'fs'
|
||||
import {debug} from '@actions/core'
|
||||
import {join, normalize, resolve} from 'path'
|
||||
import {checkArtifactFilePath} from './path-and-artifact-name-validation'
|
||||
|
||||
export interface UploadSpecification {
|
||||
absoluteFilePath: string
|
||||
uploadFilePath: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a specification that describes how each file that is part of the artifact will be uploaded
|
||||
* @param artifactName the name of the artifact being uploaded. Used during upload to denote where the artifact is stored on the server
|
||||
* @param rootDirectory an absolute file path that denotes the path that should be removed from the beginning of each artifact file
|
||||
* @param artifactFiles a list of absolute file paths that denote what should be uploaded as part of the artifact
|
||||
*/
|
||||
export function getUploadSpecification(
|
||||
artifactName: string,
|
||||
rootDirectory: string,
|
||||
artifactFiles: string[]
|
||||
): UploadSpecification[] {
|
||||
// artifact name was checked earlier on, no need to check again
|
||||
const specifications: UploadSpecification[] = []
|
||||
|
||||
if (!fs.existsSync(rootDirectory)) {
|
||||
throw new Error(`Provided rootDirectory ${rootDirectory} does not exist`)
|
||||
}
|
||||
if (!fs.statSync(rootDirectory).isDirectory()) {
|
||||
throw new Error(
|
||||
`Provided rootDirectory ${rootDirectory} is not a valid directory`
|
||||
)
|
||||
}
|
||||
// Normalize and resolve, this allows for either absolute or relative paths to be used
|
||||
rootDirectory = normalize(rootDirectory)
|
||||
rootDirectory = resolve(rootDirectory)
|
||||
|
||||
/*
|
||||
Example to demonstrate behavior
|
||||
|
||||
Input:
|
||||
artifactName: my-artifact
|
||||
rootDirectory: '/home/user/files/plz-upload'
|
||||
artifactFiles: [
|
||||
'/home/user/files/plz-upload/file1.txt',
|
||||
'/home/user/files/plz-upload/file2.txt',
|
||||
'/home/user/files/plz-upload/dir/file3.txt'
|
||||
]
|
||||
|
||||
Output:
|
||||
specifications: [
|
||||
['/home/user/files/plz-upload/file1.txt', 'my-artifact/file1.txt'],
|
||||
['/home/user/files/plz-upload/file1.txt', 'my-artifact/file2.txt'],
|
||||
['/home/user/files/plz-upload/file1.txt', 'my-artifact/dir/file3.txt']
|
||||
]
|
||||
*/
|
||||
for (let file of artifactFiles) {
|
||||
if (!fs.existsSync(file)) {
|
||||
throw new Error(`File ${file} does not exist`)
|
||||
}
|
||||
if (!fs.statSync(file).isDirectory()) {
|
||||
// Normalize and resolve, this allows for either absolute or relative paths to be used
|
||||
file = normalize(file)
|
||||
file = resolve(file)
|
||||
if (!file.startsWith(rootDirectory)) {
|
||||
throw new Error(
|
||||
`The rootDirectory: ${rootDirectory} is not a parent directory of the file: ${file}`
|
||||
)
|
||||
}
|
||||
|
||||
// Check for forbidden characters in file paths that will be rejected during upload
|
||||
const uploadPath = file.replace(rootDirectory, '')
|
||||
checkArtifactFilePath(uploadPath)
|
||||
|
||||
/*
|
||||
uploadFilePath denotes where the file will be uploaded in the file container on the server. During a run, if multiple artifacts are uploaded, they will all
|
||||
be saved in the same container. The artifact name is used as the root directory in the container to separate and distinguish uploaded artifacts
|
||||
|
||||
path.join handles all the following cases and would return 'artifact-name/file-to-upload.txt
|
||||
join('artifact-name/', 'file-to-upload.txt')
|
||||
join('artifact-name/', '/file-to-upload.txt')
|
||||
join('artifact-name', 'file-to-upload.txt')
|
||||
join('artifact-name', '/file-to-upload.txt')
|
||||
*/
|
||||
specifications.push({
|
||||
absoluteFilePath: file,
|
||||
uploadFilePath: join(artifactName, uploadPath)
|
||||
})
|
||||
} else {
|
||||
// Directories are rejected by the server during upload
|
||||
debug(`Removing ${file} from rawSearchResults because it is a directory`)
|
||||
}
|
||||
}
|
||||
return specifications
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
import * as fs from 'fs'
|
||||
import {info} from '@actions/core'
|
||||
import {normalize, resolve} from 'path'
|
||||
import {validateFilePath} from './path-and-artifact-name-validation'
|
||||
|
||||
export interface UploadZipSpecification {
|
||||
/**
|
||||
* An absolute source path that points to a file that will be added to a zip. Null if creating a new directory
|
||||
*/
|
||||
sourcePath: string | null
|
||||
|
||||
/**
|
||||
* The destination path in a zip for a file
|
||||
*/
|
||||
destinationPath: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a root directory exists and is valid
|
||||
* @param rootDirectory an absolute root directory path common to all input files that that will be trimmed from the final zip structure
|
||||
*/
|
||||
export function validateRootDirectory(rootDirectory: string): void {
|
||||
if (!fs.existsSync(rootDirectory)) {
|
||||
throw new Error(
|
||||
`The provided rootDirectory ${rootDirectory} does not exist`
|
||||
)
|
||||
}
|
||||
if (!fs.statSync(rootDirectory).isDirectory()) {
|
||||
throw new Error(
|
||||
`The provided rootDirectory ${rootDirectory} is not a valid directory`
|
||||
)
|
||||
}
|
||||
info(`Root directory input is valid!`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a specification that describes how a zip file will be created for a set of input files
|
||||
* @param filesToZip a list of file that should be included in the zip
|
||||
* @param rootDirectory an absolute root directory path common to all input files that that will be trimmed from the final zip structure
|
||||
*/
|
||||
export function getUploadZipSpecification(
|
||||
filesToZip: string[],
|
||||
rootDirectory: string
|
||||
): UploadZipSpecification[] {
|
||||
const specification: UploadZipSpecification[] = []
|
||||
|
||||
// Normalize and resolve, this allows for either absolute or relative paths to be used
|
||||
rootDirectory = normalize(rootDirectory)
|
||||
rootDirectory = resolve(rootDirectory)
|
||||
|
||||
/*
|
||||
Example
|
||||
|
||||
Input:
|
||||
rootDirectory: '/home/user/files/plz-upload'
|
||||
artifactFiles: [
|
||||
'/home/user/files/plz-upload/file1.txt',
|
||||
'/home/user/files/plz-upload/file2.txt',
|
||||
'/home/user/files/plz-upload/dir/file3.txt'
|
||||
]
|
||||
|
||||
Output:
|
||||
specifications: [
|
||||
['/home/user/files/plz-upload/file1.txt', '/file1.txt'],
|
||||
['/home/user/files/plz-upload/file1.txt', '/file2.txt'],
|
||||
['/home/user/files/plz-upload/file1.txt', '/dir/file3.txt']
|
||||
]
|
||||
|
||||
The final zip that is later uploaded will look like this:
|
||||
|
||||
my-artifact.zip
|
||||
- file.txt
|
||||
- file2.txt
|
||||
- dir/
|
||||
- file3.txt
|
||||
*/
|
||||
for (let file of filesToZip) {
|
||||
if (!fs.existsSync(file)) {
|
||||
throw new Error(`File ${file} does not exist`)
|
||||
}
|
||||
if (!fs.statSync(file).isDirectory()) {
|
||||
// Normalize and resolve, this allows for either absolute or relative paths to be used
|
||||
file = normalize(file)
|
||||
file = resolve(file)
|
||||
if (!file.startsWith(rootDirectory)) {
|
||||
throw new Error(
|
||||
`The rootDirectory: ${rootDirectory} is not a parent directory of the file: ${file}`
|
||||
)
|
||||
}
|
||||
|
||||
// Check for forbidden characters in file paths that may cause ambiguous behavior if downloaded on different file systems
|
||||
const uploadPath = file.replace(rootDirectory, '')
|
||||
validateFilePath(uploadPath)
|
||||
|
||||
specification.push({
|
||||
sourcePath: file,
|
||||
destinationPath: uploadPath
|
||||
})
|
||||
} else {
|
||||
// Empty directory
|
||||
const directoryPath = file.replace(rootDirectory, '')
|
||||
validateFilePath(directoryPath)
|
||||
|
||||
specification.push({
|
||||
sourcePath: null,
|
||||
destinationPath: directoryPath
|
||||
})
|
||||
}
|
||||
}
|
||||
return specification
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import * as stream from 'stream'
|
||||
import * as archiver from 'archiver'
|
||||
import * as core from '@actions/core'
|
||||
import {createReadStream} from 'fs'
|
||||
import {UploadZipSpecification} from './upload-zip-specification'
|
||||
import {getUploadChunkSize} from '../shared/config'
|
||||
|
||||
export const DEFAULT_COMPRESSION_LEVEL = 6
|
||||
|
||||
// Custom stream transformer so we can set the highWaterMark property
|
||||
// See https://github.com/nodejs/node/issues/8855
|
||||
export class ZipUploadStream extends stream.Transform {
|
||||
constructor(bufferSize: number) {
|
||||
super({
|
||||
highWaterMark: bufferSize
|
||||
})
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
_transform(chunk: any, enc: any, cb: any): void {
|
||||
cb(null, chunk)
|
||||
}
|
||||
}
|
||||
|
||||
export async function createZipUploadStream(
|
||||
uploadSpecification: UploadZipSpecification[],
|
||||
compressionLevel: number = DEFAULT_COMPRESSION_LEVEL
|
||||
): Promise<ZipUploadStream> {
|
||||
core.debug(
|
||||
`Creating Artifact archive with compressionLevel: ${compressionLevel}`
|
||||
)
|
||||
|
||||
const zip = archiver.create('zip', {
|
||||
highWaterMark: getUploadChunkSize(),
|
||||
zlib: {level: compressionLevel}
|
||||
})
|
||||
|
||||
// register callbacks for various events during the zip lifecycle
|
||||
zip.on('error', zipErrorCallback)
|
||||
zip.on('warning', zipWarningCallback)
|
||||
zip.on('finish', zipFinishCallback)
|
||||
zip.on('end', zipEndCallback)
|
||||
|
||||
for (const file of uploadSpecification) {
|
||||
if (file.sourcePath !== null) {
|
||||
// Add a normal file to the zip
|
||||
zip.append(createReadStream(file.sourcePath), {
|
||||
name: file.destinationPath
|
||||
})
|
||||
} else {
|
||||
// Add a directory to the zip
|
||||
zip.append('', {name: file.destinationPath})
|
||||
}
|
||||
}
|
||||
|
||||
const bufferSize = getUploadChunkSize()
|
||||
const zipUploadStream = new ZipUploadStream(bufferSize)
|
||||
|
||||
core.debug(
|
||||
`Zip write high watermark value ${zipUploadStream.writableHighWaterMark}`
|
||||
)
|
||||
core.debug(
|
||||
`Zip read high watermark value ${zipUploadStream.readableHighWaterMark}`
|
||||
)
|
||||
|
||||
zip.pipe(zipUploadStream)
|
||||
zip.finalize()
|
||||
|
||||
return zipUploadStream
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const zipErrorCallback = (error: any): void => {
|
||||
core.error('An error has occurred while creating the zip file for upload')
|
||||
core.info(error)
|
||||
|
||||
throw new Error('An error has occurred during zip creation for the artifact')
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const zipWarningCallback = (error: any): void => {
|
||||
if (error.code === 'ENOENT') {
|
||||
core.warning(
|
||||
'ENOENT warning during artifact zip creation. No such file or directory'
|
||||
)
|
||||
core.info(error)
|
||||
} else {
|
||||
core.warning(
|
||||
`A non-blocking warning has occurred during artifact zip creation: ${error.code}`
|
||||
)
|
||||
core.info(error)
|
||||
}
|
||||
}
|
||||
|
||||
const zipFinishCallback = (): void => {
|
||||
core.debug('Zip stream for upload has finished.')
|
||||
}
|
||||
|
||||
const zipEndCallback = (): void => {
|
||||
core.debug('Zip stream for upload has ended.')
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import { getRuntimeToken } from './config';
|
||||
|
||||
export interface BackendIds {
|
||||
workflowRunBackendId: string;
|
||||
workflowJobRunBackendId: string;
|
||||
}
|
||||
|
||||
export function getBackendIds(): BackendIds {
|
||||
const token = getRuntimeToken();
|
||||
const parsedToken = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString())
|
||||
if (!parsedToken["scp"]) {
|
||||
throw new Error('Unable to get scp from token')
|
||||
}
|
||||
|
||||
const scp = parsedToken["scp"]
|
||||
const scpParts = scp.split(' ')
|
||||
if (scpParts.length == 0) {
|
||||
throw new Error('No scp parts found')
|
||||
}
|
||||
|
||||
for (const part of scpParts) {
|
||||
const partParts = part.split(':')
|
||||
if(partParts.length == 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (partParts[0] == "Actions.Results") {
|
||||
if (partParts.length == 3) {
|
||||
return {workflowRunBackendId: partParts[1], workflowJobRunBackendId: partParts[2]}
|
||||
}
|
||||
throw new Error('Unable to parse Actions.Results scp part')
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('Unable to find ids')
|
||||
}
|
||||
@@ -4,11 +4,15 @@
|
||||
"baseUrl": "./",
|
||||
"outDir": "./lib",
|
||||
"rootDir": "./src",
|
||||
"lib": [
|
||||
"es2020"
|
||||
],
|
||||
"module": "commonjs",
|
||||
"target": "es2020"
|
||||
"paths": {
|
||||
"@actions/core": [
|
||||
"../core"
|
||||
],
|
||||
"@actions/http-client": [
|
||||
"../http-client"
|
||||
]
|
||||
},
|
||||
"useUnknownInCatchVariables": false,
|
||||
},
|
||||
"include": [
|
||||
"./src"
|
||||
|
||||
Vendored
+4
@@ -160,3 +160,7 @@
|
||||
### 3.2.1
|
||||
|
||||
- Updated @azure/storage-blob to `v12.13.0`
|
||||
|
||||
### 3.2.2
|
||||
|
||||
- Add new default cache download method to improve performance and reduce hangs [#1484](https://github.com/actions/toolkit/pull/1484)
|
||||
|
||||
+21
-6
@@ -84,18 +84,24 @@ test('downloadCache uses storage SDK for Azure storage URLs', async () => {
|
||||
'downloadCacheStorageSDK'
|
||||
)
|
||||
|
||||
const downloadCacheHttpClientConcurrentMock = jest.spyOn(
|
||||
downloadUtils,
|
||||
'downloadCacheHttpClientConcurrent'
|
||||
)
|
||||
|
||||
const archiveLocation = 'http://foo.blob.core.windows.net/bar/baz'
|
||||
const archivePath = '/foo/bar'
|
||||
|
||||
await downloadCache(archiveLocation, archivePath)
|
||||
|
||||
expect(downloadCacheStorageSDKMock).toHaveBeenCalledTimes(1)
|
||||
expect(downloadCacheStorageSDKMock).toHaveBeenCalledWith(
|
||||
expect(downloadCacheHttpClientConcurrentMock).toHaveBeenCalledTimes(1)
|
||||
expect(downloadCacheHttpClientConcurrentMock).toHaveBeenCalledWith(
|
||||
archiveLocation,
|
||||
archivePath,
|
||||
getDownloadOptions()
|
||||
)
|
||||
|
||||
expect(downloadCacheStorageSDKMock).toHaveBeenCalledTimes(0)
|
||||
expect(downloadCacheHttpClientMock).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
|
||||
@@ -109,20 +115,26 @@ test('downloadCache passes options to download methods', async () => {
|
||||
'downloadCacheStorageSDK'
|
||||
)
|
||||
|
||||
const downloadCacheHttpClientConcurrentMock = jest.spyOn(
|
||||
downloadUtils,
|
||||
'downloadCacheHttpClientConcurrent'
|
||||
)
|
||||
|
||||
const archiveLocation = 'http://foo.blob.core.windows.net/bar/baz'
|
||||
const archivePath = '/foo/bar'
|
||||
const options: DownloadOptions = {downloadConcurrency: 4}
|
||||
|
||||
await downloadCache(archiveLocation, archivePath, options)
|
||||
|
||||
expect(downloadCacheStorageSDKMock).toHaveBeenCalledTimes(1)
|
||||
expect(downloadCacheStorageSDKMock).toHaveBeenCalled()
|
||||
expect(downloadCacheStorageSDKMock).toHaveBeenCalledWith(
|
||||
expect(downloadCacheHttpClientConcurrentMock).toHaveBeenCalledTimes(1)
|
||||
expect(downloadCacheHttpClientConcurrentMock).toHaveBeenCalled()
|
||||
expect(downloadCacheHttpClientConcurrentMock).toHaveBeenCalledWith(
|
||||
archiveLocation,
|
||||
archivePath,
|
||||
getDownloadOptions(options)
|
||||
)
|
||||
|
||||
expect(downloadCacheStorageSDKMock).toHaveBeenCalledTimes(0)
|
||||
expect(downloadCacheHttpClientMock).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
|
||||
@@ -138,7 +150,10 @@ test('downloadCache uses http-client when overridden', async () => {
|
||||
|
||||
const archiveLocation = 'http://foo.blob.core.windows.net/bar/baz'
|
||||
const archivePath = '/foo/bar'
|
||||
const options: DownloadOptions = {useAzureSdk: false}
|
||||
const options: DownloadOptions = {
|
||||
useAzureSdk: false,
|
||||
concurrentBlobDownloads: false
|
||||
}
|
||||
|
||||
await downloadCache(archiveLocation, archivePath, options)
|
||||
|
||||
|
||||
+5
-2
@@ -5,7 +5,8 @@ import {
|
||||
getUploadOptions
|
||||
} from '../src/options'
|
||||
|
||||
const useAzureSdk = true
|
||||
const useAzureSdk = false
|
||||
const concurrentBlobDownloads = true
|
||||
const downloadConcurrency = 8
|
||||
const timeoutInMs = 30000
|
||||
const segmentTimeoutInMs = 600000
|
||||
@@ -18,6 +19,7 @@ test('getDownloadOptions sets defaults', async () => {
|
||||
|
||||
expect(actualOptions).toEqual({
|
||||
useAzureSdk,
|
||||
concurrentBlobDownloads,
|
||||
downloadConcurrency,
|
||||
timeoutInMs,
|
||||
segmentTimeoutInMs,
|
||||
@@ -27,7 +29,8 @@ test('getDownloadOptions sets defaults', async () => {
|
||||
|
||||
test('getDownloadOptions overrides all settings', async () => {
|
||||
const expectedOptions: DownloadOptions = {
|
||||
useAzureSdk: false,
|
||||
useAzureSdk: true,
|
||||
concurrentBlobDownloads: false,
|
||||
downloadConcurrency: 14,
|
||||
timeoutInMs: 20000,
|
||||
segmentTimeoutInMs: 3600000,
|
||||
|
||||
+175
-344
@@ -1,29 +1,29 @@
|
||||
{
|
||||
"name": "@actions/cache",
|
||||
"version": "3.2.1",
|
||||
"version": "3.2.2",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@actions/cache",
|
||||
"version": "3.2.1",
|
||||
"version": "3.2.2",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.0",
|
||||
"@actions/exec": "^1.0.1",
|
||||
"@actions/glob": "^0.1.0",
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"@actions/http-client": "^2.1.1",
|
||||
"@actions/io": "^1.0.1",
|
||||
"@azure/abort-controller": "^1.1.0",
|
||||
"@azure/ms-rest-js": "^2.6.0",
|
||||
"@azure/storage-blob": "^12.13.0",
|
||||
"semver": "^6.1.0",
|
||||
"semver": "^6.3.1",
|
||||
"uuid": "^3.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/semver": "^6.0.0",
|
||||
"@types/uuid": "^3.4.5",
|
||||
"typescript": "^4.8.0"
|
||||
"typescript": "^5.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/core": {
|
||||
@@ -52,26 +52,26 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/glob": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.1.0.tgz",
|
||||
"integrity": "sha512-lx8SzyQ2FE9+UUvjqY1f28QbTJv+w8qP7kHHbfQRhphrlcx0Mdmm1tZdGJzfxv1jxREa/sLW4Oy8CbGQKCJySA==",
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.1.2.tgz",
|
||||
"integrity": "sha512-SclLR7Ia5sEqjkJTPs7Sd86maMDw43p769YxBOxvPvEWuPEhpAnBsQfENOpXjFYMmhCqd127bmf+YdvJqVqR4A==",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.2.0",
|
||||
"@actions/core": "^1.2.6",
|
||||
"minimatch": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.1.tgz",
|
||||
"integrity": "sha512-qhrkRMB40bbbLo7gF+0vu+X+UawOvQQqNAA/5Unx774RS8poaOhThDOG6BGmxvAnxhQnDp2BG/ZUm65xZILTpw==",
|
||||
"dependencies": {
|
||||
"tunnel": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/io": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.2.tgz",
|
||||
"integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw=="
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
|
||||
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="
|
||||
},
|
||||
"node_modules/@azure/abort-controller": {
|
||||
"version": "1.1.0",
|
||||
@@ -84,20 +84,10 @@
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/abort-controller/node_modules/tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
},
|
||||
"node_modules/@azure/core-asynciterator-polyfill": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-asynciterator-polyfill/-/core-asynciterator-polyfill-1.0.0.tgz",
|
||||
"integrity": "sha512-kmv8CGrPfN9SwMwrkiBK9VTQYxdFQEGe0BmQk+M8io56P9KNzpAxcWE/1fxJj7uouwN4kXF0BHW8DNlgx+wtCg=="
|
||||
},
|
||||
"node_modules/@azure/core-auth": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.3.2.tgz",
|
||||
"integrity": "sha512-7CU6DmCHIZp5ZPiZ9r3J17lTKMmYsm/zGvNkjArQwPkrLlZ1TZ+EUYfGgh2X31OLMVAQCTJZW4cXHJi02EbJnA==",
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.4.0.tgz",
|
||||
"integrity": "sha512-HFrcTgmuSuukRf/EdPmqBrc5l6Q5Uu+2TbuhaKbgaCpP2TfAeiNaQPAadxO+CYBRHGUzIDteMAjFspFLDLnKVQ==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"tslib": "^2.2.0"
|
||||
@@ -106,15 +96,10 @@
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-auth/node_modules/tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
},
|
||||
"node_modules/@azure/core-http": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.1.tgz",
|
||||
"integrity": "sha512-A3x+um3cAPgQe42Lu7Iv/x8/fNjhL/nIoEfqFxfn30EyxK6zC13n+OUxzZBRC0IzQqssqIbt4INf5YG7lYYFtw==",
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.2.tgz",
|
||||
"integrity": "sha512-o1wR9JrmoM0xEAa0Ue7Sp8j+uJvmqYaGoHOCT5qaVYmvgmnZDC0OvQimPA/JR3u77Sz6D1y3Xmk1y69cDU9q9A==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"@azure/core-auth": "^1.3.0",
|
||||
@@ -148,11 +133,6 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-http/node_modules/tslib": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
|
||||
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
|
||||
},
|
||||
"node_modules/@azure/core-http/node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
@@ -162,41 +142,30 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-lro": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.2.3.tgz",
|
||||
"integrity": "sha512-UMdlR9NsqDCLTba3EUbRjfMF4gDmWvld196JmUjbz9WWhJ2XT00OR5MXeWiR+vmGT+ETiO4hHFCi2/eGO5YVtg==",
|
||||
"version": "2.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.5.4.tgz",
|
||||
"integrity": "sha512-3GJiMVH7/10bulzOKGrrLeG/uCBH/9VtxqaMcB9lIqAeamI/xYQSHJL/KcsLDuH+yTjYpro/u6D/MuRe4dN70Q==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"@azure/core-tracing": "1.0.0-preview.13",
|
||||
"@azure/core-util": "^1.2.0",
|
||||
"@azure/logger": "^1.0.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-lro/node_modules/tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
},
|
||||
"node_modules/@azure/core-paging": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.2.1.tgz",
|
||||
"integrity": "sha512-UtH5iMlYsvg+nQYIl4UHlvvSrsBjOlRF4fs0j7mxd3rWdAStrKYrh2durOpHs5C9yZbVhsVDaisoyaf/lL1EVA==",
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.5.0.tgz",
|
||||
"integrity": "sha512-zqWdVIt+2Z+3wqxEOGzR5hXFZ8MGKK52x4vFLw8n58pR6ZfKRx3EXYTxTaYxYHc/PexPUTyimcTWFJbji9Z6Iw==",
|
||||
"dependencies": {
|
||||
"@azure/core-asynciterator-polyfill": "^1.0.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-paging/node_modules/tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
},
|
||||
"node_modules/@azure/core-tracing": {
|
||||
"version": "1.0.0-preview.13",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.0-preview.13.tgz",
|
||||
@@ -209,15 +178,10 @@
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-tracing/node_modules/tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
},
|
||||
"node_modules/@azure/core-util": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.2.0.tgz",
|
||||
"integrity": "sha512-ffGIw+Qs8bNKNLxz5UPkz4/VBM/EZY07mPve1ZYFqYUdPwFqRj0RPk0U7LZMOfT7GCck9YjuT1Rfp1PApNl1ng==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.3.2.tgz",
|
||||
"integrity": "sha512-2bECOUh88RvL1pMZTcc6OzfobBeWDBf5oBbhjIhT1MV9otMVWCzpOJkkiKtrnO88y5GGBelgY8At73KGAdbkeQ==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"tslib": "^2.2.0"
|
||||
@@ -226,43 +190,37 @@
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-util/node_modules/tslib": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
|
||||
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
|
||||
},
|
||||
"node_modules/@azure/logger": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.0.3.tgz",
|
||||
"integrity": "sha512-aK4s3Xxjrx3daZr3VylxejK3vG5ExXck5WOHDJ8in/k9AqlfIyFMMT1uG7u8mNjX+QRILTIn0/Xgschfh/dQ9g==",
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.0.4.tgz",
|
||||
"integrity": "sha512-ustrPY8MryhloQj7OWGe+HrYx+aoiOxzbXTtgblbV3xwCqpzUK36phH3XNHQKj3EPonyFUuDTfR3qFhTEAuZEg==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/logger/node_modules/tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
},
|
||||
"node_modules/@azure/ms-rest-js": {
|
||||
"version": "2.6.6",
|
||||
"resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-2.6.6.tgz",
|
||||
"integrity": "sha512-WYIda8VvrkZE68xHgOxUXvjThxNf1nnGPPe0rAljqK5HJHIZ12Pi3YhEDOn3Ge7UnwaaM3eFO0VtAy4nGVI27Q==",
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-2.7.0.tgz",
|
||||
"integrity": "sha512-ngbzWbqF+NmztDOpLBVDxYM+XLcUj7nKhxGbSU9WtIsXfRB//cf2ZbAG5HkOrhU9/wd/ORRB6lM/d69RKVjiyA==",
|
||||
"dependencies": {
|
||||
"@azure/core-auth": "^1.1.4",
|
||||
"abort-controller": "^3.0.0",
|
||||
"form-data": "^2.5.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"tough-cookie": "^3.0.1",
|
||||
"tslib": "^1.10.0",
|
||||
"tunnel": "0.0.6",
|
||||
"uuid": "^8.3.2",
|
||||
"xml2js": "^0.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/ms-rest-js/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"node_modules/@azure/ms-rest-js/node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
@@ -272,9 +230,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/storage-blob": {
|
||||
"version": "12.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.13.0.tgz",
|
||||
"integrity": "sha512-t3Q2lvBMJucgTjQcP5+hvEJMAsJSk0qmAnjDLie2td017IiduZbbC9BOcFfmwzR6y6cJdZOuewLCNFmEx9IrXA==",
|
||||
"version": "12.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.15.0.tgz",
|
||||
"integrity": "sha512-e7JBKLOFi0QVJqqLzrjx1eL3je3/Ug2IQj24cTM9b85CsnnFjLGeGjJVIjbGGZaytewiCEG7r3lRwQX7fKj0/w==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"@azure/core-http": "^3.0.0",
|
||||
@@ -289,28 +247,23 @@
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/storage-blob/node_modules/tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
},
|
||||
"node_modules/@opentelemetry/api": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.0.4.tgz",
|
||||
"integrity": "sha512-BuJuXRSJNQ3QoKA6GWWDyuLpOUck+9hAXNMCnrloc1aWVoy6Xq6t9PUV08aBZ4Lutqq2LEHM486bpZqoViScog==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.4.1.tgz",
|
||||
"integrity": "sha512-O2yRJce1GOc6PAy3QxFM4NzFiWzvScDC1/5ihYBL6BUEVdq0XMWN01sppE+H6bBXbaFYipjwFLEWLg5PaSOThA==",
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.14.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz",
|
||||
"integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA=="
|
||||
"version": "20.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.6.tgz",
|
||||
"integrity": "sha512-q0RkvNgMweWWIvSMDiXhflGUKMdIxBo2M2tYM/0kEGDueQByFzK4KZAgu5YHGFNxziTlppNpTIBcqHQAxlfHdA=="
|
||||
},
|
||||
"node_modules/@types/node-fetch": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz",
|
||||
"integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==",
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.4.tgz",
|
||||
"integrity": "sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==",
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"form-data": "^3.0.0"
|
||||
@@ -330,9 +283,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.2.1.tgz",
|
||||
"integrity": "sha512-+beqKQOh9PYxuHvijhVl+tIHvT6tuwOrE9m14zd+MT2A38KoKZhh7pYJ0SNleLtwDsiIxHDsIk9bv01oOxvSvA==",
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.2.3.tgz",
|
||||
"integrity": "sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/tunnel": {
|
||||
@@ -344,9 +297,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/uuid": {
|
||||
"version": "3.4.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.9.tgz",
|
||||
"integrity": "sha512-XDwyIlt/47l2kWLTzw/mtrpLdB+GPSskR2n/PIcPn+VYhVO77rGhRncIR5GPU0KRzXuqkDO+J5qqrG0Y8P6jzQ==",
|
||||
"version": "3.4.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.10.tgz",
|
||||
"integrity": "sha512-BgeaZuElf7DEYZhWYDTc/XcLZXdVgFkVSTa13BqKvbnmUrxr3TJFKofUxCtDO9UQOdhnV+HPOESdHiHKZOJV1A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/abort-controller": {
|
||||
@@ -363,12 +316,12 @@
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
@@ -393,12 +346,12 @@
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
@@ -432,28 +385,20 @@
|
||||
"node": ">= 0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/ip-regex": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
|
||||
"integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.51.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
|
||||
"integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==",
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.34",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
|
||||
"integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"dependencies": {
|
||||
"mime-db": "1.51.0"
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
@@ -471,9 +416,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz",
|
||||
"integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
@@ -497,54 +442,28 @@
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/psl": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
|
||||
"integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/tough-cookie": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
|
||||
"integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==",
|
||||
"dependencies": {
|
||||
"ip-regex": "^2.1.0",
|
||||
"psl": "^1.1.28",
|
||||
"punycode": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
|
||||
"integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig=="
|
||||
},
|
||||
"node_modules/tunnel": {
|
||||
"version": "0.0.6",
|
||||
@@ -555,16 +474,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.8.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
|
||||
"integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
||||
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.2.0"
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
@@ -579,12 +498,12 @@
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
@@ -637,26 +556,26 @@
|
||||
}
|
||||
},
|
||||
"@actions/glob": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.1.0.tgz",
|
||||
"integrity": "sha512-lx8SzyQ2FE9+UUvjqY1f28QbTJv+w8qP7kHHbfQRhphrlcx0Mdmm1tZdGJzfxv1jxREa/sLW4Oy8CbGQKCJySA==",
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.1.2.tgz",
|
||||
"integrity": "sha512-SclLR7Ia5sEqjkJTPs7Sd86maMDw43p769YxBOxvPvEWuPEhpAnBsQfENOpXjFYMmhCqd127bmf+YdvJqVqR4A==",
|
||||
"requires": {
|
||||
"@actions/core": "^1.2.0",
|
||||
"@actions/core": "^1.2.6",
|
||||
"minimatch": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"@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==",
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.1.tgz",
|
||||
"integrity": "sha512-qhrkRMB40bbbLo7gF+0vu+X+UawOvQQqNAA/5Unx774RS8poaOhThDOG6BGmxvAnxhQnDp2BG/ZUm65xZILTpw==",
|
||||
"requires": {
|
||||
"tunnel": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"@actions/io": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.2.tgz",
|
||||
"integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw=="
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
|
||||
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="
|
||||
},
|
||||
"@azure/abort-controller": {
|
||||
"version": "1.1.0",
|
||||
@@ -664,40 +583,21 @@
|
||||
"integrity": "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==",
|
||||
"requires": {
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@azure/core-asynciterator-polyfill": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-asynciterator-polyfill/-/core-asynciterator-polyfill-1.0.0.tgz",
|
||||
"integrity": "sha512-kmv8CGrPfN9SwMwrkiBK9VTQYxdFQEGe0BmQk+M8io56P9KNzpAxcWE/1fxJj7uouwN4kXF0BHW8DNlgx+wtCg=="
|
||||
},
|
||||
"@azure/core-auth": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.3.2.tgz",
|
||||
"integrity": "sha512-7CU6DmCHIZp5ZPiZ9r3J17lTKMmYsm/zGvNkjArQwPkrLlZ1TZ+EUYfGgh2X31OLMVAQCTJZW4cXHJi02EbJnA==",
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.4.0.tgz",
|
||||
"integrity": "sha512-HFrcTgmuSuukRf/EdPmqBrc5l6Q5Uu+2TbuhaKbgaCpP2TfAeiNaQPAadxO+CYBRHGUzIDteMAjFspFLDLnKVQ==",
|
||||
"requires": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@azure/core-http": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.1.tgz",
|
||||
"integrity": "sha512-A3x+um3cAPgQe42Lu7Iv/x8/fNjhL/nIoEfqFxfn30EyxK6zC13n+OUxzZBRC0IzQqssqIbt4INf5YG7lYYFtw==",
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.2.tgz",
|
||||
"integrity": "sha512-o1wR9JrmoM0xEAa0Ue7Sp8j+uJvmqYaGoHOCT5qaVYmvgmnZDC0OvQimPA/JR3u77Sz6D1y3Xmk1y69cDU9q9A==",
|
||||
"requires": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"@azure/core-auth": "^1.3.0",
|
||||
@@ -725,11 +625,6 @@
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
|
||||
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
@@ -738,37 +633,22 @@
|
||||
}
|
||||
},
|
||||
"@azure/core-lro": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.2.3.tgz",
|
||||
"integrity": "sha512-UMdlR9NsqDCLTba3EUbRjfMF4gDmWvld196JmUjbz9WWhJ2XT00OR5MXeWiR+vmGT+ETiO4hHFCi2/eGO5YVtg==",
|
||||
"version": "2.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.5.4.tgz",
|
||||
"integrity": "sha512-3GJiMVH7/10bulzOKGrrLeG/uCBH/9VtxqaMcB9lIqAeamI/xYQSHJL/KcsLDuH+yTjYpro/u6D/MuRe4dN70Q==",
|
||||
"requires": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"@azure/core-tracing": "1.0.0-preview.13",
|
||||
"@azure/core-util": "^1.2.0",
|
||||
"@azure/logger": "^1.0.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@azure/core-paging": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.2.1.tgz",
|
||||
"integrity": "sha512-UtH5iMlYsvg+nQYIl4UHlvvSrsBjOlRF4fs0j7mxd3rWdAStrKYrh2durOpHs5C9yZbVhsVDaisoyaf/lL1EVA==",
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.5.0.tgz",
|
||||
"integrity": "sha512-zqWdVIt+2Z+3wqxEOGzR5hXFZ8MGKK52x4vFLw8n58pR6ZfKRx3EXYTxTaYxYHc/PexPUTyimcTWFJbji9Z6Iw==",
|
||||
"requires": {
|
||||
"@azure/core-asynciterator-polyfill": "^1.0.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@azure/core-tracing": {
|
||||
@@ -778,62 +658,45 @@
|
||||
"requires": {
|
||||
"@opentelemetry/api": "^1.0.1",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@azure/core-util": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.2.0.tgz",
|
||||
"integrity": "sha512-ffGIw+Qs8bNKNLxz5UPkz4/VBM/EZY07mPve1ZYFqYUdPwFqRj0RPk0U7LZMOfT7GCck9YjuT1Rfp1PApNl1ng==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.3.2.tgz",
|
||||
"integrity": "sha512-2bECOUh88RvL1pMZTcc6OzfobBeWDBf5oBbhjIhT1MV9otMVWCzpOJkkiKtrnO88y5GGBelgY8At73KGAdbkeQ==",
|
||||
"requires": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
|
||||
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@azure/logger": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.0.3.tgz",
|
||||
"integrity": "sha512-aK4s3Xxjrx3daZr3VylxejK3vG5ExXck5WOHDJ8in/k9AqlfIyFMMT1uG7u8mNjX+QRILTIn0/Xgschfh/dQ9g==",
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.0.4.tgz",
|
||||
"integrity": "sha512-ustrPY8MryhloQj7OWGe+HrYx+aoiOxzbXTtgblbV3xwCqpzUK36phH3XNHQKj3EPonyFUuDTfR3qFhTEAuZEg==",
|
||||
"requires": {
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@azure/ms-rest-js": {
|
||||
"version": "2.6.6",
|
||||
"resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-2.6.6.tgz",
|
||||
"integrity": "sha512-WYIda8VvrkZE68xHgOxUXvjThxNf1nnGPPe0rAljqK5HJHIZ12Pi3YhEDOn3Ge7UnwaaM3eFO0VtAy4nGVI27Q==",
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-2.7.0.tgz",
|
||||
"integrity": "sha512-ngbzWbqF+NmztDOpLBVDxYM+XLcUj7nKhxGbSU9WtIsXfRB//cf2ZbAG5HkOrhU9/wd/ORRB6lM/d69RKVjiyA==",
|
||||
"requires": {
|
||||
"@azure/core-auth": "^1.1.4",
|
||||
"abort-controller": "^3.0.0",
|
||||
"form-data": "^2.5.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"tough-cookie": "^3.0.1",
|
||||
"tslib": "^1.10.0",
|
||||
"tunnel": "0.0.6",
|
||||
"uuid": "^8.3.2",
|
||||
"xml2js": "^0.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
@@ -842,9 +705,9 @@
|
||||
}
|
||||
},
|
||||
"@azure/storage-blob": {
|
||||
"version": "12.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.13.0.tgz",
|
||||
"integrity": "sha512-t3Q2lvBMJucgTjQcP5+hvEJMAsJSk0qmAnjDLie2td017IiduZbbC9BOcFfmwzR6y6cJdZOuewLCNFmEx9IrXA==",
|
||||
"version": "12.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.15.0.tgz",
|
||||
"integrity": "sha512-e7JBKLOFi0QVJqqLzrjx1eL3je3/Ug2IQj24cTM9b85CsnnFjLGeGjJVIjbGGZaytewiCEG7r3lRwQX7fKj0/w==",
|
||||
"requires": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"@azure/core-http": "^3.0.0",
|
||||
@@ -854,29 +717,22 @@
|
||||
"@azure/logger": "^1.0.0",
|
||||
"events": "^3.0.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@opentelemetry/api": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.0.4.tgz",
|
||||
"integrity": "sha512-BuJuXRSJNQ3QoKA6GWWDyuLpOUck+9hAXNMCnrloc1aWVoy6Xq6t9PUV08aBZ4Lutqq2LEHM486bpZqoViScog=="
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.4.1.tgz",
|
||||
"integrity": "sha512-O2yRJce1GOc6PAy3QxFM4NzFiWzvScDC1/5ihYBL6BUEVdq0XMWN01sppE+H6bBXbaFYipjwFLEWLg5PaSOThA=="
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "18.14.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz",
|
||||
"integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA=="
|
||||
"version": "20.4.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.6.tgz",
|
||||
"integrity": "sha512-q0RkvNgMweWWIvSMDiXhflGUKMdIxBo2M2tYM/0kEGDueQByFzK4KZAgu5YHGFNxziTlppNpTIBcqHQAxlfHdA=="
|
||||
},
|
||||
"@types/node-fetch": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz",
|
||||
"integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==",
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.4.tgz",
|
||||
"integrity": "sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==",
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"form-data": "^3.0.0"
|
||||
@@ -895,9 +751,9 @@
|
||||
}
|
||||
},
|
||||
"@types/semver": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.2.1.tgz",
|
||||
"integrity": "sha512-+beqKQOh9PYxuHvijhVl+tIHvT6tuwOrE9m14zd+MT2A38KoKZhh7pYJ0SNleLtwDsiIxHDsIk9bv01oOxvSvA==",
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.2.3.tgz",
|
||||
"integrity": "sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/tunnel": {
|
||||
@@ -909,9 +765,9 @@
|
||||
}
|
||||
},
|
||||
"@types/uuid": {
|
||||
"version": "3.4.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.9.tgz",
|
||||
"integrity": "sha512-XDwyIlt/47l2kWLTzw/mtrpLdB+GPSskR2n/PIcPn+VYhVO77rGhRncIR5GPU0KRzXuqkDO+J5qqrG0Y8P6jzQ==",
|
||||
"version": "3.4.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.10.tgz",
|
||||
"integrity": "sha512-BgeaZuElf7DEYZhWYDTc/XcLZXdVgFkVSTa13BqKvbnmUrxr3TJFKofUxCtDO9UQOdhnV+HPOESdHiHKZOJV1A==",
|
||||
"dev": true
|
||||
},
|
||||
"abort-controller": {
|
||||
@@ -925,12 +781,12 @@
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
@@ -952,12 +808,12 @@
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
||||
},
|
||||
"delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
|
||||
},
|
||||
"event-target-shim": {
|
||||
"version": "5.0.1",
|
||||
@@ -979,22 +835,17 @@
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"ip-regex": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
|
||||
"integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.51.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
|
||||
"integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g=="
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.34",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
|
||||
"integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"requires": {
|
||||
"mime-db": "1.51.0"
|
||||
"mime-db": "1.52.0"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
@@ -1006,9 +857,9 @@
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz",
|
||||
"integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==",
|
||||
"requires": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
}
|
||||
@@ -1018,45 +869,25 @@
|
||||
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="
|
||||
},
|
||||
"psl": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
|
||||
"integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
|
||||
},
|
||||
"punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||
},
|
||||
"sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
|
||||
"integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==",
|
||||
"requires": {
|
||||
"ip-regex": "^2.1.0",
|
||||
"psl": "^1.1.28",
|
||||
"punycode": "^2.1.1"
|
||||
}
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||
},
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
|
||||
"integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig=="
|
||||
},
|
||||
"tunnel": {
|
||||
"version": "0.0.6",
|
||||
@@ -1064,9 +895,9 @@
|
||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.8.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
|
||||
"integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
||||
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
|
||||
"dev": true
|
||||
},
|
||||
"uuid": {
|
||||
@@ -1077,12 +908,12 @@
|
||||
"webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"requires": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
|
||||
Vendored
+4
-4
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@actions/cache",
|
||||
"version": "3.2.1",
|
||||
"version": "3.2.2",
|
||||
"preview": true,
|
||||
"description": "Actions cache lib",
|
||||
"keywords": [
|
||||
@@ -40,17 +40,17 @@
|
||||
"@actions/core": "^1.10.0",
|
||||
"@actions/exec": "^1.0.1",
|
||||
"@actions/glob": "^0.1.0",
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"@actions/http-client": "^2.1.1",
|
||||
"@actions/io": "^1.0.1",
|
||||
"@azure/abort-controller": "^1.1.0",
|
||||
"@azure/ms-rest-js": "^2.6.0",
|
||||
"@azure/storage-blob": "^12.13.0",
|
||||
"semver": "^6.1.0",
|
||||
"semver": "^6.3.1",
|
||||
"uuid": "^3.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/semver": "^6.0.0",
|
||||
"@types/uuid": "^3.4.5",
|
||||
"typescript": "^4.8.0"
|
||||
"typescript": "^5.2.2"
|
||||
}
|
||||
}
|
||||
|
||||
+28
-15
@@ -20,7 +20,11 @@ import {
|
||||
ITypedResponseWithError,
|
||||
ArtifactCacheList
|
||||
} from './contracts'
|
||||
import {downloadCacheHttpClient, downloadCacheStorageSDK} from './downloadUtils'
|
||||
import {
|
||||
downloadCacheHttpClient,
|
||||
downloadCacheHttpClientConcurrent,
|
||||
downloadCacheStorageSDK
|
||||
} from './downloadUtils'
|
||||
import {
|
||||
DownloadOptions,
|
||||
UploadOptions,
|
||||
@@ -92,10 +96,7 @@ export function getCacheVersion(
|
||||
// Add salt to cache version to support breaking changes in cache entry
|
||||
components.push(versionSalt)
|
||||
|
||||
return crypto
|
||||
.createHash('sha256')
|
||||
.update(components.join('|'))
|
||||
.digest('hex')
|
||||
return crypto.createHash('sha256').update(components.join('|')).digest('hex')
|
||||
}
|
||||
|
||||
export async function getCacheEntry(
|
||||
@@ -174,14 +175,26 @@ export async function downloadCache(
|
||||
const archiveUrl = new URL(archiveLocation)
|
||||
const downloadOptions = getDownloadOptions(options)
|
||||
|
||||
if (
|
||||
downloadOptions.useAzureSdk &&
|
||||
archiveUrl.hostname.endsWith('.blob.core.windows.net')
|
||||
) {
|
||||
// Use Azure storage SDK to download caches hosted on Azure to improve speed and reliability.
|
||||
await downloadCacheStorageSDK(archiveLocation, archivePath, downloadOptions)
|
||||
if (archiveUrl.hostname.endsWith('.blob.core.windows.net')) {
|
||||
if (downloadOptions.useAzureSdk) {
|
||||
// Use Azure storage SDK to download caches hosted on Azure to improve speed and reliability.
|
||||
await downloadCacheStorageSDK(
|
||||
archiveLocation,
|
||||
archivePath,
|
||||
downloadOptions
|
||||
)
|
||||
} else if (downloadOptions.concurrentBlobDownloads) {
|
||||
// Use concurrent implementation with HttpClient to work around blob SDK issue
|
||||
await downloadCacheHttpClientConcurrent(
|
||||
archiveLocation,
|
||||
archivePath,
|
||||
downloadOptions
|
||||
)
|
||||
} else {
|
||||
// Otherwise, download using the Actions http-client.
|
||||
await downloadCacheHttpClient(archiveLocation, archivePath)
|
||||
}
|
||||
} else {
|
||||
// Otherwise, download using the Actions http-client.
|
||||
await downloadCacheHttpClient(archiveLocation, archivePath)
|
||||
}
|
||||
}
|
||||
@@ -230,9 +243,9 @@ async function uploadChunk(
|
||||
end: number
|
||||
): Promise<void> {
|
||||
core.debug(
|
||||
`Uploading chunk of size ${end -
|
||||
start +
|
||||
1} bytes at offset ${start} with content range: ${getContentRange(
|
||||
`Uploading chunk of size ${
|
||||
end - start + 1
|
||||
} bytes at offset ${start} with content range: ${getContentRange(
|
||||
start,
|
||||
end
|
||||
)}`
|
||||
|
||||
+164
-4
@@ -203,6 +203,166 @@ export async function downloadCacheHttpClient(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the cache using the Actions toolkit http-client concurrently
|
||||
*
|
||||
* @param archiveLocation the URL for the cache
|
||||
* @param archivePath the local path where the cache is saved
|
||||
*/
|
||||
export async function downloadCacheHttpClientConcurrent(
|
||||
archiveLocation: string,
|
||||
archivePath: fs.PathLike,
|
||||
options: DownloadOptions
|
||||
): Promise<void> {
|
||||
const archiveDescriptor = await fs.promises.open(archivePath, 'w')
|
||||
const httpClient = new HttpClient('actions/cache', undefined, {
|
||||
socketTimeout: options.timeoutInMs,
|
||||
keepAlive: true
|
||||
})
|
||||
try {
|
||||
const res = await retryHttpClientResponse(
|
||||
'downloadCacheMetadata',
|
||||
async () => await httpClient.request('HEAD', archiveLocation, null, {})
|
||||
)
|
||||
|
||||
const lengthHeader = res.message.headers['content-length']
|
||||
if (lengthHeader === undefined || lengthHeader === null) {
|
||||
throw new Error('Content-Length not found on blob response')
|
||||
}
|
||||
|
||||
const length = parseInt(lengthHeader)
|
||||
if (Number.isNaN(length)) {
|
||||
throw new Error(`Could not interpret Content-Length: ${length}`)
|
||||
}
|
||||
|
||||
const downloads: {
|
||||
offset: number
|
||||
promiseGetter: () => Promise<DownloadSegment>
|
||||
}[] = []
|
||||
const blockSize = 4 * 1024 * 1024
|
||||
|
||||
for (let offset = 0; offset < length; offset += blockSize) {
|
||||
const count = Math.min(blockSize, length - offset)
|
||||
downloads.push({
|
||||
offset,
|
||||
promiseGetter: async () => {
|
||||
return await downloadSegmentRetry(
|
||||
httpClient,
|
||||
archiveLocation,
|
||||
offset,
|
||||
count
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// reverse to use .pop instead of .shift
|
||||
downloads.reverse()
|
||||
let actives = 0
|
||||
let bytesDownloaded = 0
|
||||
const progress = new DownloadProgress(length)
|
||||
progress.startDisplayTimer()
|
||||
const progressFn = progress.onProgress()
|
||||
|
||||
const activeDownloads: {[offset: number]: Promise<DownloadSegment>} = []
|
||||
let nextDownload:
|
||||
| {offset: number; promiseGetter: () => Promise<DownloadSegment>}
|
||||
| undefined
|
||||
|
||||
const waitAndWrite: () => Promise<void> = async () => {
|
||||
const segment = await Promise.race(Object.values(activeDownloads))
|
||||
await archiveDescriptor.write(
|
||||
segment.buffer,
|
||||
0,
|
||||
segment.count,
|
||||
segment.offset
|
||||
)
|
||||
actives--
|
||||
delete activeDownloads[segment.offset]
|
||||
bytesDownloaded += segment.count
|
||||
progressFn({loadedBytes: bytesDownloaded})
|
||||
}
|
||||
|
||||
while ((nextDownload = downloads.pop())) {
|
||||
activeDownloads[nextDownload.offset] = nextDownload.promiseGetter()
|
||||
actives++
|
||||
|
||||
if (actives >= (options.downloadConcurrency ?? 10)) {
|
||||
await waitAndWrite()
|
||||
}
|
||||
}
|
||||
|
||||
while (actives > 0) {
|
||||
await waitAndWrite()
|
||||
}
|
||||
} finally {
|
||||
httpClient.dispose()
|
||||
await archiveDescriptor.close()
|
||||
}
|
||||
}
|
||||
|
||||
async function downloadSegmentRetry(
|
||||
httpClient: HttpClient,
|
||||
archiveLocation: string,
|
||||
offset: number,
|
||||
count: number
|
||||
): Promise<DownloadSegment> {
|
||||
const retries = 5
|
||||
let failures = 0
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
const timeout = 30000
|
||||
const result = await promiseWithTimeout(
|
||||
timeout,
|
||||
downloadSegment(httpClient, archiveLocation, offset, count)
|
||||
)
|
||||
if (typeof result === 'string') {
|
||||
throw new Error('downloadSegmentRetry failed due to timeout')
|
||||
}
|
||||
|
||||
return result
|
||||
} catch (err) {
|
||||
if (failures >= retries) {
|
||||
throw err
|
||||
}
|
||||
|
||||
failures++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function downloadSegment(
|
||||
httpClient: HttpClient,
|
||||
archiveLocation: string,
|
||||
offset: number,
|
||||
count: number
|
||||
): Promise<DownloadSegment> {
|
||||
const partRes = await retryHttpClientResponse(
|
||||
'downloadCachePart',
|
||||
async () =>
|
||||
await httpClient.get(archiveLocation, {
|
||||
Range: `bytes=${offset}-${offset + count - 1}`
|
||||
})
|
||||
)
|
||||
|
||||
if (!partRes.readBodyBuffer) {
|
||||
throw new Error('Expected HttpClientResponse to implement readBodyBuffer')
|
||||
}
|
||||
|
||||
return {
|
||||
offset,
|
||||
count,
|
||||
buffer: await partRes.readBodyBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
declare class DownloadSegment {
|
||||
offset: number
|
||||
count: number
|
||||
buffer: Buffer
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the cache using the Azure Storage SDK. Only call this method if the
|
||||
* URL points to an Azure Storage endpoint.
|
||||
@@ -287,12 +447,12 @@ export async function downloadCacheStorageSDK(
|
||||
}
|
||||
}
|
||||
|
||||
const promiseWithTimeout = async (
|
||||
const promiseWithTimeout = async <T>(
|
||||
timeoutMs: number,
|
||||
promise: Promise<Buffer>
|
||||
): Promise<unknown> => {
|
||||
promise: Promise<T>
|
||||
): Promise<T | string> => {
|
||||
let timeoutHandle: NodeJS.Timeout
|
||||
const timeoutPromise = new Promise(resolve => {
|
||||
const timeoutPromise = new Promise<string>(resolve => {
|
||||
timeoutHandle = setTimeout(() => resolve('timeout'), timeoutMs)
|
||||
})
|
||||
|
||||
|
||||
Vendored
+12
-1
@@ -39,6 +39,12 @@ export interface DownloadOptions {
|
||||
*/
|
||||
downloadConcurrency?: number
|
||||
|
||||
/**
|
||||
* Indicates whether to use Actions HttpClient with concurrency
|
||||
* for Azure Blob Storage
|
||||
*/
|
||||
concurrentBlobDownloads?: boolean
|
||||
|
||||
/**
|
||||
* Maximum time for each download request, in milliseconds (this
|
||||
* option only applies when using the Azure SDK)
|
||||
@@ -98,7 +104,8 @@ export function getUploadOptions(copy?: UploadOptions): UploadOptions {
|
||||
*/
|
||||
export function getDownloadOptions(copy?: DownloadOptions): DownloadOptions {
|
||||
const result: DownloadOptions = {
|
||||
useAzureSdk: true,
|
||||
useAzureSdk: false,
|
||||
concurrentBlobDownloads: true,
|
||||
downloadConcurrency: 8,
|
||||
timeoutInMs: 30000,
|
||||
segmentTimeoutInMs: 600000,
|
||||
@@ -110,6 +117,10 @@ export function getDownloadOptions(copy?: DownloadOptions): DownloadOptions {
|
||||
result.useAzureSdk = copy.useAzureSdk
|
||||
}
|
||||
|
||||
if (typeof copy.concurrentBlobDownloads === 'boolean') {
|
||||
result.concurrentBlobDownloads = copy.concurrentBlobDownloads
|
||||
}
|
||||
|
||||
if (typeof copy.downloadConcurrency === 'number') {
|
||||
result.downloadConcurrency = copy.downloadConcurrency
|
||||
}
|
||||
|
||||
Vendored
+4
-1
@@ -4,7 +4,10 @@
|
||||
"baseUrl": "./",
|
||||
"outDir": "./lib",
|
||||
"rootDir": "./src",
|
||||
"lib": ["es6", "dom"],
|
||||
"lib": [
|
||||
"es6",
|
||||
"dom"
|
||||
],
|
||||
"useUnknownInCatchVariables": false
|
||||
},
|
||||
"include": [
|
||||
|
||||
@@ -333,3 +333,28 @@ toPlatformPath('/foo/bar') // => \foo\bar
|
||||
// On a Linux runner.
|
||||
toPlatformPath('\\foo\\bar') // => /foo/bar
|
||||
```
|
||||
|
||||
#### Platform helper
|
||||
|
||||
Provides shorthands for getting information about platform action is running on.
|
||||
|
||||
```js
|
||||
import { platform } from '@actions/core'
|
||||
|
||||
/* equals to a call of os.platform() */
|
||||
platform.platform // 'win32' | 'darwin' | 'linux' | 'freebsd' | 'openbsd' | 'android' | 'cygwin' | 'sunos'
|
||||
|
||||
/* equals to a call of os.arch() */
|
||||
platform.arch // 'x64' | 'arm' | 'arm64' | 'ia32' | 'mips' | 'mipsel' | 'ppc' | 'ppc64' | 'riscv64' | 's390' | 's390x'
|
||||
|
||||
/* common shorthands for platform-specific logic */
|
||||
platform.isWindows // true
|
||||
platform.isMacOS // false
|
||||
platform.isLinux // false
|
||||
|
||||
/* run platform-specific script to get more details about the exact platform, works on Windows, MacOS and Linux */
|
||||
const {
|
||||
name, // Microsoft Windows 11 Enterprise
|
||||
version, // 10.0.22621
|
||||
} = await platform.getDetails()
|
||||
```
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# @actions/core Releases
|
||||
|
||||
### 1.10.1
|
||||
- Fix error message reference in oidc utils [#1511](https://github.com/actions/toolkit/pull/1511)
|
||||
|
||||
### 1.10.0
|
||||
- `saveState` and `setOutput` now use environment files if available [#1178](https://github.com/actions/toolkit/pull/1178)
|
||||
- `getMultilineInput` now correctly trims whitespace by default [#1185](https://github.com/actions/toolkit/pull/1185)
|
||||
|
||||
@@ -17,7 +17,7 @@ describe('@actions/core/src/command', () => {
|
||||
afterEach(() => {})
|
||||
|
||||
afterAll(() => {
|
||||
process.stdout.write = (originalWriteFunction as unknown) as (
|
||||
process.stdout.write = originalWriteFunction as unknown as (
|
||||
str: string
|
||||
) => boolean
|
||||
})
|
||||
@@ -51,8 +51,7 @@ describe('@actions/core/src/command', () => {
|
||||
command.issueCommand(
|
||||
'some-command',
|
||||
{
|
||||
name:
|
||||
'percent % percent % cr \r cr \r lf \n lf \n colon : colon : comma , comma ,'
|
||||
name: 'percent % percent % cr \r cr \r lf \n lf \n colon : colon : comma , comma ,'
|
||||
},
|
||||
''
|
||||
)
|
||||
@@ -117,11 +116,11 @@ describe('@actions/core/src/command', () => {
|
||||
command.issueCommand(
|
||||
'some-command',
|
||||
{
|
||||
prop1: ({test: 'object'} as unknown) as string,
|
||||
prop2: (123 as unknown) as string,
|
||||
prop3: (true as unknown) as string
|
||||
prop1: {test: 'object'} as unknown as string,
|
||||
prop2: 123 as unknown as string,
|
||||
prop3: true as unknown as string
|
||||
},
|
||||
({test: 'object'} as unknown) as string
|
||||
{test: 'object'} as unknown as string
|
||||
)
|
||||
assertWriteCalls([
|
||||
`::some-command prop1={"test"%3A"object"},prop2=123,prop3=true::{"test":"object"}${os.EOL}`
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import os from 'os'
|
||||
import {platform} from '../src/core'
|
||||
|
||||
describe('getInfo', () => {
|
||||
it('returns the platform info', async () => {
|
||||
const info = await platform.getDetails()
|
||||
expect(info).toEqual({
|
||||
name: expect.any(String),
|
||||
platform: expect.any(String),
|
||||
arch: expect.any(String),
|
||||
version: expect.any(String),
|
||||
isWindows: expect.any(Boolean),
|
||||
isMacOS: expect.any(Boolean),
|
||||
isLinux: expect.any(Boolean)
|
||||
})
|
||||
})
|
||||
|
||||
it('returns the platform info with the correct name', async () => {
|
||||
const isWindows = os.platform() === 'win32'
|
||||
const isMacOS = os.platform() === 'darwin'
|
||||
const isLinux = os.platform() === 'linux'
|
||||
|
||||
const info = await platform.getDetails()
|
||||
expect(info.platform).toEqual(os.platform())
|
||||
expect(info.isWindows).toEqual(isWindows)
|
||||
expect(info.isMacOS).toEqual(isMacOS)
|
||||
expect(info.isLinux).toEqual(isLinux)
|
||||
})
|
||||
})
|
||||
@@ -150,10 +150,7 @@ describe('@actions/core/src/summary', () => {
|
||||
})
|
||||
|
||||
it('adds EOL', async () => {
|
||||
await summary
|
||||
.addRaw(fixtures.text)
|
||||
.addEOL()
|
||||
.write()
|
||||
await summary.addRaw(fixtures.text).addEOL().write()
|
||||
await assertSummary(fixtures.text + os.EOL)
|
||||
})
|
||||
|
||||
|
||||
Generated
+35
-8
@@ -1,14 +1,15 @@
|
||||
{
|
||||
"name": "@actions/core",
|
||||
"version": "1.10.0",
|
||||
"version": "1.10.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@actions/core",
|
||||
"version": "1.10.0",
|
||||
"version": "1.10.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
@@ -17,14 +18,27 @@
|
||||
"@types/uuid": "^8.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/exec": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
|
||||
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
|
||||
"dependencies": {
|
||||
"@actions/io": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.0.tgz",
|
||||
"integrity": "sha512-BonhODnXr3amchh4qkmjPMUO8mFi/zLaaCeCAJZqch8iQqyDnVIkySjB38VHAC8IJ+bnlgfOqlhpyCUZHlQsqw==",
|
||||
"dependencies": {
|
||||
"tunnel": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/io": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
|
||||
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "12.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz",
|
||||
@@ -55,14 +69,27 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/exec": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
|
||||
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
|
||||
"requires": {
|
||||
"@actions/io": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"@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==",
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.0.tgz",
|
||||
"integrity": "sha512-BonhODnXr3amchh4qkmjPMUO8mFi/zLaaCeCAJZqch8iQqyDnVIkySjB38VHAC8IJ+bnlgfOqlhpyCUZHlQsqw==",
|
||||
"requires": {
|
||||
"tunnel": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"@actions/io": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
|
||||
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "12.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@actions/core",
|
||||
"version": "1.10.0",
|
||||
"version": "1.10.1",
|
||||
"description": "Actions core lib",
|
||||
"keywords": [
|
||||
"github",
|
||||
@@ -30,12 +30,13 @@
|
||||
"scripts": {
|
||||
"audit-moderate": "npm install && npm audit --json --audit-level=moderate > audit.json",
|
||||
"test": "echo \"Error: run tests from root\" && exit 1",
|
||||
"tsc": "tsc"
|
||||
"tsc": "tsc -p tsconfig.json"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/actions/toolkit/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
@@ -43,4 +44,4 @@
|
||||
"@types/node": "^12.0.2",
|
||||
"@types/uuid": "^8.3.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -386,3 +386,8 @@ export {markdownSummary} from './summary'
|
||||
* Path exports
|
||||
*/
|
||||
export {toPosixPath, toWin32Path, toPlatformPath} from './path-utils'
|
||||
|
||||
/**
|
||||
* Platform utilities exports
|
||||
*/
|
||||
export * as platform from './platform'
|
||||
|
||||
@@ -52,7 +52,7 @@ export class OidcClient {
|
||||
throw new Error(
|
||||
`Failed to get ID Token. \n
|
||||
Error Code : ${error.statusCode}\n
|
||||
Error Message: ${error.result.message}`
|
||||
Error Message: ${error.message}`
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
import os from 'os'
|
||||
import * as exec from '@actions/exec'
|
||||
|
||||
const getWindowsInfo = async (): Promise<{name: string; version: string}> => {
|
||||
const {stdout: version} = await exec.getExecOutput(
|
||||
'powershell -command "(Get-CimInstance -ClassName Win32_OperatingSystem).Version"',
|
||||
undefined,
|
||||
{
|
||||
silent: true
|
||||
}
|
||||
)
|
||||
|
||||
const {stdout: name} = await exec.getExecOutput(
|
||||
'powershell -command "(Get-CimInstance -ClassName Win32_OperatingSystem).Caption"',
|
||||
undefined,
|
||||
{
|
||||
silent: true
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
name: name.trim(),
|
||||
version: version.trim()
|
||||
}
|
||||
}
|
||||
|
||||
const getMacOsInfo = async (): Promise<{
|
||||
name: string
|
||||
version: string
|
||||
}> => {
|
||||
const {stdout} = await exec.getExecOutput('sw_vers', undefined, {
|
||||
silent: true
|
||||
})
|
||||
|
||||
const version = stdout.match(/ProductVersion:\s*(.+)/)?.[1] ?? ''
|
||||
const name = stdout.match(/ProductName:\s*(.+)/)?.[1] ?? ''
|
||||
|
||||
return {
|
||||
name,
|
||||
version
|
||||
}
|
||||
}
|
||||
|
||||
const getLinuxInfo = async (): Promise<{
|
||||
name: string
|
||||
version: string
|
||||
}> => {
|
||||
const {stdout} = await exec.getExecOutput('lsb_release', ['-i', '-r', '-s'], {
|
||||
silent: true
|
||||
})
|
||||
|
||||
const [name, version] = stdout.trim().split('\n')
|
||||
|
||||
return {
|
||||
name,
|
||||
version
|
||||
}
|
||||
}
|
||||
|
||||
export const platform = os.platform()
|
||||
export const arch = os.arch()
|
||||
export const isWindows = platform === 'win32'
|
||||
export const isMacOS = platform === 'darwin'
|
||||
export const isLinux = platform === 'linux'
|
||||
|
||||
export async function getDetails(): Promise<{
|
||||
name: string
|
||||
platform: string
|
||||
arch: string
|
||||
version: string
|
||||
isWindows: boolean
|
||||
isMacOS: boolean
|
||||
isLinux: boolean
|
||||
}> {
|
||||
return {
|
||||
...(await (isWindows
|
||||
? getWindowsInfo()
|
||||
: isMacOS
|
||||
? getMacOsInfo()
|
||||
: getLinuxInfo())),
|
||||
platform,
|
||||
arch,
|
||||
isWindows,
|
||||
isMacOS,
|
||||
isLinux
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "./lib",
|
||||
"declaration": true,
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"include": [
|
||||
|
||||
@@ -357,7 +357,7 @@ describe('@actions/exec', () => {
|
||||
expect(exitCode).toBe(0)
|
||||
})
|
||||
|
||||
it('Handles child process holding streams open', async function() {
|
||||
it('Handles child process holding streams open', async function () {
|
||||
const semaphorePath = path.join(
|
||||
getTestTemp(),
|
||||
'child-process-semaphore.txt'
|
||||
@@ -403,7 +403,7 @@ describe('@actions/exec', () => {
|
||||
fs.unlinkSync(semaphorePath)
|
||||
}, 10000) // this was timing out on some slower hosted macOS runs at default 5s
|
||||
|
||||
it('Handles child process holding streams open and non-zero exit code', async function() {
|
||||
it('Handles child process holding streams open and non-zero exit code', async function () {
|
||||
const semaphorePath = path.join(
|
||||
getTestTemp(),
|
||||
'child-process-semaphore.txt'
|
||||
@@ -457,7 +457,7 @@ describe('@actions/exec', () => {
|
||||
fs.unlinkSync(semaphorePath)
|
||||
}, 10000) // this was timing out on some slower hosted macOS runs at default 5s
|
||||
|
||||
it('Handles child process holding streams open and stderr', async function() {
|
||||
it('Handles child process holding streams open and stderr', async function () {
|
||||
const semaphorePath = path.join(
|
||||
getTestTemp(),
|
||||
'child-process-semaphore.txt'
|
||||
|
||||
@@ -267,10 +267,7 @@ export class ToolRunner extends events.EventEmitter {
|
||||
}
|
||||
|
||||
reverse += '"'
|
||||
return reverse
|
||||
.split('')
|
||||
.reverse()
|
||||
.join('')
|
||||
return reverse.split('').reverse().join('')
|
||||
}
|
||||
|
||||
private _uvQuoteCmdArg(arg: string): string {
|
||||
@@ -350,10 +347,7 @@ export class ToolRunner extends events.EventEmitter {
|
||||
}
|
||||
|
||||
reverse += '"'
|
||||
return reverse
|
||||
.split('')
|
||||
.reverse()
|
||||
.join('')
|
||||
return reverse.split('').reverse().join('')
|
||||
}
|
||||
|
||||
private _cloneExecOptions(options?: im.ExecOptions): im.ExecOptions {
|
||||
@@ -637,7 +631,7 @@ class ExecState extends events.EventEmitter {
|
||||
private delay = 10000 // 10 seconds
|
||||
private done = false
|
||||
private options: im.ExecOptions
|
||||
private timeout: NodeJS.Timer | null = null
|
||||
private timeout: NodeJS.Timeout | null = null
|
||||
private toolPath: string
|
||||
|
||||
CheckComplete(): void {
|
||||
@@ -691,8 +685,9 @@ class ExecState extends events.EventEmitter {
|
||||
}
|
||||
|
||||
if (!state.processClosed && state.processExited) {
|
||||
const message = `The STDIO streams did not close within ${state.delay /
|
||||
1000} seconds of the exit event from process '${
|
||||
const message = `The STDIO streams did not close within ${
|
||||
state.delay / 1000
|
||||
} seconds of the exit event from process '${
|
||||
state.toolPath
|
||||
}'. This may indicate a child process inherited the STDIO streams and has not yet exited.`
|
||||
state._debug(message)
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# @actions/github Releases
|
||||
|
||||
### 6.0.0
|
||||
- Support the latest Octokit in @actions/github [#1553](https://github.com/actions/toolkit/pull/1553)
|
||||
- Drop support of NodeJS v14, v16
|
||||
|
||||
### 5.1.1
|
||||
- Export default octokit options [#1188](https://github.com/actions/toolkit/pull/1188)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as http from 'http'
|
||||
import * as https from 'https'
|
||||
import proxy from 'proxy'
|
||||
import {createProxy} from 'proxy'
|
||||
|
||||
// Default values are set when the module is imported, so we need to set proxy first.
|
||||
const proxyUrl = 'http://127.0.0.1:8081'
|
||||
@@ -16,8 +16,8 @@ describe('@actions/github', () => {
|
||||
|
||||
beforeAll(async () => {
|
||||
// Start proxy server
|
||||
proxyServer = proxy()
|
||||
await new Promise(resolve => {
|
||||
proxyServer = createProxy()
|
||||
await new Promise<void>(resolve => {
|
||||
const port = Number(proxyUrl.split(':')[2])
|
||||
proxyServer.listen(port, () => resolve())
|
||||
})
|
||||
@@ -32,7 +32,7 @@ describe('@actions/github', () => {
|
||||
|
||||
afterAll(async () => {
|
||||
// Stop proxy server
|
||||
await new Promise(resolve => {
|
||||
await new Promise<void>(resolve => {
|
||||
proxyServer.once('close', () => resolve())
|
||||
proxyServer.close()
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as http from 'http'
|
||||
import proxy from 'proxy'
|
||||
import {createProxy} from 'proxy'
|
||||
import {getOctokit} from '../src/github'
|
||||
import {GitHub, getOctokitOptions} from '../src/utils'
|
||||
|
||||
@@ -12,10 +12,10 @@ describe('@actions/github', () => {
|
||||
|
||||
beforeAll(async () => {
|
||||
// Start proxy server
|
||||
proxyServer = proxy()
|
||||
await new Promise(resolve => {
|
||||
proxyServer = createProxy()
|
||||
await new Promise<void>(resolve => {
|
||||
const port = Number(proxyUrl.split(':')[2])
|
||||
proxyServer.listen(port, () => resolve(null))
|
||||
proxyServer.listen(port, () => resolve())
|
||||
})
|
||||
proxyServer.on('connect', req => {
|
||||
proxyConnects.push(req.url ?? '')
|
||||
@@ -29,8 +29,8 @@ describe('@actions/github', () => {
|
||||
|
||||
afterAll(async () => {
|
||||
// Stop proxy server
|
||||
await new Promise(resolve => {
|
||||
proxyServer.once('close', () => resolve(null))
|
||||
await new Promise<void>(resolve => {
|
||||
proxyServer.once('close', () => resolve())
|
||||
proxyServer.close()
|
||||
})
|
||||
|
||||
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
declare module 'proxy' {
|
||||
import * as http from 'http'
|
||||
function internal(): http.Server
|
||||
export = internal
|
||||
}
|
||||
Generated
+331
-345
@@ -1,148 +1,161 @@
|
||||
{
|
||||
"name": "@actions/github",
|
||||
"version": "5.1.1",
|
||||
"version": "6.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@actions/github",
|
||||
"version": "5.1.1",
|
||||
"version": "6.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"@octokit/core": "^3.6.0",
|
||||
"@octokit/plugin-paginate-rest": "^2.17.0",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^5.13.0"
|
||||
"@actions/http-client": "^2.2.0",
|
||||
"@octokit/core": "^5.0.1",
|
||||
"@octokit/plugin-paginate-rest": "^9.0.0",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^10.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"proxy": "^1.0.2"
|
||||
"proxy": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.0.tgz",
|
||||
"integrity": "sha512-q+epW0trjVUUHboliPb4UF9g2msf+w61b32tAkFEwL/IwP0DQWgbCMM0Hbe3e3WXSKz5VcUXbzJQgy8Hkra/Lg==",
|
||||
"dependencies": {
|
||||
"tunnel": "^0.0.6"
|
||||
"tunnel": "^0.0.6",
|
||||
"undici": "^5.25.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@fastify/busboy": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.0.0.tgz",
|
||||
"integrity": "sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/auth-token": {
|
||||
"version": "2.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz",
|
||||
"integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3"
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz",
|
||||
"integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/core": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
|
||||
"integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.0.1.tgz",
|
||||
"integrity": "sha512-lyeeeZyESFo+ffI801SaBKmCfsvarO+dgV8/0gD8u1d87clbEdWsP5yC+dSj3zLhb2eIf5SJrn6vDz9AheETHw==",
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^2.4.4",
|
||||
"@octokit/graphql": "^4.5.8",
|
||||
"@octokit/request": "^5.6.3",
|
||||
"@octokit/request-error": "^2.0.5",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"@octokit/auth-token": "^4.0.0",
|
||||
"@octokit/graphql": "^7.0.0",
|
||||
"@octokit/request": "^8.0.2",
|
||||
"@octokit/request-error": "^5.0.0",
|
||||
"@octokit/types": "^12.0.0",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/endpoint": {
|
||||
"version": "6.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.11.tgz",
|
||||
"integrity": "sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ==",
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.1.tgz",
|
||||
"integrity": "sha512-hRlOKAovtINHQPYHZlfyFwaM8OyetxeoC81lAkBy34uLb8exrZB50SQdeW3EROqiY9G9yxQTpp5OHTV54QD+vA==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"@octokit/types": "^12.0.0",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/graphql": {
|
||||
"version": "4.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.6.1.tgz",
|
||||
"integrity": "sha512-2lYlvf4YTDgZCTXTW4+OX+9WTLFtEUc6hGm4qM1nlZjzxj+arizM4aHWzBVBCxY9glh7GIs0WEuiSgbVzv8cmA==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.0.2.tgz",
|
||||
"integrity": "sha512-OJ2iGMtj5Tg3s6RaXH22cJcxXRi7Y3EBqbHTBRq+PQAqfaS8f/236fUrWhfSn8P4jovyzqucxme7/vWSSZBX2Q==",
|
||||
"dependencies": {
|
||||
"@octokit/request": "^5.3.0",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"@octokit/request": "^8.0.1",
|
||||
"@octokit/types": "^12.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/openapi-types": {
|
||||
"version": "11.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz",
|
||||
"integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA=="
|
||||
"version": "19.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.0.0.tgz",
|
||||
"integrity": "sha512-PclQ6JGMTE9iUStpzMkwLCISFn/wDeRjkZFIKALpvJQNBGwDoYYi2fFvuHwssoQ1rXI5mfh6jgTgWuddeUzfWw=="
|
||||
},
|
||||
"node_modules/@octokit/plugin-paginate-rest": {
|
||||
"version": "2.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz",
|
||||
"integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==",
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.0.0.tgz",
|
||||
"integrity": "sha512-oIJzCpttmBTlEhBmRvb+b9rlnGpmFgDtZ0bB6nq39qIod6A5DP+7RkVLMOixIgRCYSHDTeayWqmiJ2SZ6xgfdw==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.34.0"
|
||||
"@octokit/types": "^12.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=2"
|
||||
"@octokit/core": ">=5"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "5.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz",
|
||||
"integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==",
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.0.0.tgz",
|
||||
"integrity": "sha512-16VkwE2v6rXU+/gBsYC62M8lKWOphY5Lg4wpjYnVE9Zbu0J6IwiT5kILoj1YOB53XLmcJR+Nqp8DmifOPY4H3g==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.34.0",
|
||||
"deprecation": "^2.3.1"
|
||||
"@octokit/types": "^12.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": ">=3"
|
||||
"@octokit/core": ">=5"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request": {
|
||||
"version": "5.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
|
||||
"integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
|
||||
"version": "8.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.1.4.tgz",
|
||||
"integrity": "sha512-M0aaFfpGPEKrg7XoA/gwgRvc9MSXHRO2Ioki1qrPDbl1e9YhjIwVoHE7HIKmv/m3idzldj//xBujcFNqGX6ENA==",
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^6.0.1",
|
||||
"@octokit/request-error": "^2.1.0",
|
||||
"@octokit/types": "^6.16.1",
|
||||
"@octokit/endpoint": "^9.0.0",
|
||||
"@octokit/request-error": "^5.0.0",
|
||||
"@octokit/types": "^12.0.0",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request-error": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
|
||||
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.0.1.tgz",
|
||||
"integrity": "sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"@octokit/types": "^12.0.0",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/types": {
|
||||
"version": "6.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz",
|
||||
"integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==",
|
||||
"version": "12.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.0.0.tgz",
|
||||
"integrity": "sha512-EzD434aHTFifGudYAygnFlS1Tl6KhbTynEWELQXIbTY8Msvb5nEqTZIm7sbPEt4mQYLZwu3zPKVdeIrw0g7ovg==",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^11.2.0"
|
||||
"@octokit/openapi-types": "^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/args": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/args/-/args-5.0.1.tgz",
|
||||
"integrity": "sha512-1kqmFCFsPffavQFGt8OxJdIcETti99kySRUPMpOhaGjL6mRJn8HFU1OxKY5bMqfZKUwTQc1mZkAjmGYaVOHFtQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"camelcase": "5.0.0",
|
||||
"chalk": "2.4.2",
|
||||
"leven": "2.1.0",
|
||||
"mri": "1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/args/node_modules/ansi-styles": {
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
@@ -154,7 +167,33 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/args/node_modules/camelcase": {
|
||||
"node_modules/args": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/args/-/args-5.0.3.tgz",
|
||||
"integrity": "sha512-h6k/zfFgusnv3i5TU08KQkVKuCPBtL/PWQbWkHUxvJrZ2nAyeaUupneemcrgn1xmqxPQsPIzwkUhOpoqPDRZuA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"camelcase": "5.0.0",
|
||||
"chalk": "2.4.2",
|
||||
"leven": "2.1.0",
|
||||
"mri": "1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/basic-auth-parser": {
|
||||
"version": "0.0.2-1",
|
||||
"resolved": "https://registry.npmjs.org/basic-auth-parser/-/basic-auth-parser-0.0.2-1.tgz",
|
||||
"integrity": "sha512-GFj8iVxo9onSU6BnnQvVwqvxh60UcSHJEDnIk3z4B6iOjsKSmqe+ibW0Rsz7YO7IE1HG3D3tqCNIidP46SZVdQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/before-after-hook": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.1.tgz",
|
||||
"integrity": "sha512-/6FKxSTWoJdbsLDF8tdIjaRiFXiE6UHsEHE3OPI/cwPURCVi1ukP0gmLn7XWEiFk5TcwQjjY5PWsU+j+tgXgmw=="
|
||||
},
|
||||
"node_modules/camelcase": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz",
|
||||
"integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==",
|
||||
@@ -163,7 +202,7 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/args/node_modules/chalk": {
|
||||
"node_modules/chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
@@ -177,7 +216,7 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/args/node_modules/color-convert": {
|
||||
"node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
@@ -186,61 +225,27 @@
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/args/node_modules/color-name": {
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/args/node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/args/node_modules/leven": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz",
|
||||
"integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/args/node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/basic-auth-parser": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/basic-auth-parser/-/basic-auth-parser-0.0.2.tgz",
|
||||
"integrity": "sha1-zp5xp38jwSee7NJlmypGJEwVbkE=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/before-after-hook": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.1.tgz",
|
||||
"integrity": "sha512-/6FKxSTWoJdbsLDF8tdIjaRiFXiE6UHsEHE3OPI/cwPURCVi1ukP0gmLn7XWEiFk5TcwQjjY5PWsU+j+tgXgmw=="
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "^2.1.1"
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/deprecation": {
|
||||
@@ -251,12 +256,21 @@
|
||||
"node_modules/escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
@@ -265,6 +279,15 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/leven": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz",
|
||||
"integrity": "sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mri": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz",
|
||||
@@ -280,64 +303,38 @@
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/proxy/-/proxy-1.0.2.tgz",
|
||||
"integrity": "sha512-KNac2ueWRpjbUh77OAFPZuNdfEqNynm9DD4xHT14CccGpW8wKZwEkN0yjlb7X9G9Z9F55N0Q+1z+WfgAhwYdzQ==",
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/proxy/-/proxy-2.1.1.tgz",
|
||||
"integrity": "sha512-nLgd7zdUAOpB3ZO/xCkU8gy74UER7P0aihU8DkUsDS5ZoFwVCX7u8dy+cv5tVK8UaB/yminU1GiLWE26TKPYpg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"args": "5.0.1",
|
||||
"basic-auth-parser": "0.0.2",
|
||||
"debug": "^4.1.1"
|
||||
"args": "^5.0.3",
|
||||
"basic-auth-parser": "0.0.2-1",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"bin": {
|
||||
"proxy": "bin/proxy.js"
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/tunnel": {
|
||||
@@ -348,6 +345,17 @@
|
||||
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
|
||||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "5.25.4",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.25.4.tgz",
|
||||
"integrity": "sha512-450yJxT29qKMf3aoudzFpIciqpx6Pji3hEWaXqXmanbXF58LTAGCKxcJjxMXWu3iG+Mudgo3ZUfDB6YDFd/dAw==",
|
||||
"dependencies": {
|
||||
"@fastify/busboy": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/universal-user-agent": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
||||
@@ -356,193 +364,139 @@
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@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==",
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.0.tgz",
|
||||
"integrity": "sha512-q+epW0trjVUUHboliPb4UF9g2msf+w61b32tAkFEwL/IwP0DQWgbCMM0Hbe3e3WXSKz5VcUXbzJQgy8Hkra/Lg==",
|
||||
"requires": {
|
||||
"tunnel": "^0.0.6"
|
||||
"tunnel": "^0.0.6",
|
||||
"undici": "^5.25.4"
|
||||
}
|
||||
},
|
||||
"@fastify/busboy": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.0.0.tgz",
|
||||
"integrity": "sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ=="
|
||||
},
|
||||
"@octokit/auth-token": {
|
||||
"version": "2.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz",
|
||||
"integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.0.3"
|
||||
}
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz",
|
||||
"integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA=="
|
||||
},
|
||||
"@octokit/core": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
|
||||
"integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.0.1.tgz",
|
||||
"integrity": "sha512-lyeeeZyESFo+ffI801SaBKmCfsvarO+dgV8/0gD8u1d87clbEdWsP5yC+dSj3zLhb2eIf5SJrn6vDz9AheETHw==",
|
||||
"requires": {
|
||||
"@octokit/auth-token": "^2.4.4",
|
||||
"@octokit/graphql": "^4.5.8",
|
||||
"@octokit/request": "^5.6.3",
|
||||
"@octokit/request-error": "^2.0.5",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"@octokit/auth-token": "^4.0.0",
|
||||
"@octokit/graphql": "^7.0.0",
|
||||
"@octokit/request": "^8.0.2",
|
||||
"@octokit/request-error": "^5.0.0",
|
||||
"@octokit/types": "^12.0.0",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/endpoint": {
|
||||
"version": "6.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.11.tgz",
|
||||
"integrity": "sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ==",
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.1.tgz",
|
||||
"integrity": "sha512-hRlOKAovtINHQPYHZlfyFwaM8OyetxeoC81lAkBy34uLb8exrZB50SQdeW3EROqiY9G9yxQTpp5OHTV54QD+vA==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"@octokit/types": "^12.0.0",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/graphql": {
|
||||
"version": "4.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.6.1.tgz",
|
||||
"integrity": "sha512-2lYlvf4YTDgZCTXTW4+OX+9WTLFtEUc6hGm4qM1nlZjzxj+arizM4aHWzBVBCxY9glh7GIs0WEuiSgbVzv8cmA==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.0.2.tgz",
|
||||
"integrity": "sha512-OJ2iGMtj5Tg3s6RaXH22cJcxXRi7Y3EBqbHTBRq+PQAqfaS8f/236fUrWhfSn8P4jovyzqucxme7/vWSSZBX2Q==",
|
||||
"requires": {
|
||||
"@octokit/request": "^5.3.0",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"@octokit/request": "^8.0.1",
|
||||
"@octokit/types": "^12.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/openapi-types": {
|
||||
"version": "11.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz",
|
||||
"integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA=="
|
||||
"version": "19.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.0.0.tgz",
|
||||
"integrity": "sha512-PclQ6JGMTE9iUStpzMkwLCISFn/wDeRjkZFIKALpvJQNBGwDoYYi2fFvuHwssoQ1rXI5mfh6jgTgWuddeUzfWw=="
|
||||
},
|
||||
"@octokit/plugin-paginate-rest": {
|
||||
"version": "2.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz",
|
||||
"integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==",
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.0.0.tgz",
|
||||
"integrity": "sha512-oIJzCpttmBTlEhBmRvb+b9rlnGpmFgDtZ0bB6nq39qIod6A5DP+7RkVLMOixIgRCYSHDTeayWqmiJ2SZ6xgfdw==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.34.0"
|
||||
"@octokit/types": "^12.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "5.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz",
|
||||
"integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==",
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.0.0.tgz",
|
||||
"integrity": "sha512-16VkwE2v6rXU+/gBsYC62M8lKWOphY5Lg4wpjYnVE9Zbu0J6IwiT5kILoj1YOB53XLmcJR+Nqp8DmifOPY4H3g==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.34.0",
|
||||
"deprecation": "^2.3.1"
|
||||
"@octokit/types": "^12.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/request": {
|
||||
"version": "5.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
|
||||
"integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
|
||||
"version": "8.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.1.4.tgz",
|
||||
"integrity": "sha512-M0aaFfpGPEKrg7XoA/gwgRvc9MSXHRO2Ioki1qrPDbl1e9YhjIwVoHE7HIKmv/m3idzldj//xBujcFNqGX6ENA==",
|
||||
"requires": {
|
||||
"@octokit/endpoint": "^6.0.1",
|
||||
"@octokit/request-error": "^2.1.0",
|
||||
"@octokit/types": "^6.16.1",
|
||||
"@octokit/endpoint": "^9.0.0",
|
||||
"@octokit/request-error": "^5.0.0",
|
||||
"@octokit/types": "^12.0.0",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/request-error": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
|
||||
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.0.1.tgz",
|
||||
"integrity": "sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==",
|
||||
"requires": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"@octokit/types": "^12.0.0",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "6.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz",
|
||||
"integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==",
|
||||
"version": "12.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.0.0.tgz",
|
||||
"integrity": "sha512-EzD434aHTFifGudYAygnFlS1Tl6KhbTynEWELQXIbTY8Msvb5nEqTZIm7sbPEt4mQYLZwu3zPKVdeIrw0g7ovg==",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^11.2.0"
|
||||
"@octokit/openapi-types": "^19.0.0"
|
||||
}
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"args": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/args/-/args-5.0.1.tgz",
|
||||
"integrity": "sha512-1kqmFCFsPffavQFGt8OxJdIcETti99kySRUPMpOhaGjL6mRJn8HFU1OxKY5bMqfZKUwTQc1mZkAjmGYaVOHFtQ==",
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/args/-/args-5.0.3.tgz",
|
||||
"integrity": "sha512-h6k/zfFgusnv3i5TU08KQkVKuCPBtL/PWQbWkHUxvJrZ2nAyeaUupneemcrgn1xmqxPQsPIzwkUhOpoqPDRZuA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase": "5.0.0",
|
||||
"chalk": "2.4.2",
|
||||
"leven": "2.1.0",
|
||||
"mri": "1.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"camelcase": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz",
|
||||
"integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==",
|
||||
"dev": true
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||
"dev": true
|
||||
},
|
||||
"leven": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz",
|
||||
"integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"basic-auth-parser": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/basic-auth-parser/-/basic-auth-parser-0.0.2.tgz",
|
||||
"integrity": "sha1-zp5xp38jwSee7NJlmypGJEwVbkE=",
|
||||
"version": "0.0.2-1",
|
||||
"resolved": "https://registry.npmjs.org/basic-auth-parser/-/basic-auth-parser-0.0.2-1.tgz",
|
||||
"integrity": "sha512-GFj8iVxo9onSU6BnnQvVwqvxh60UcSHJEDnIk3z4B6iOjsKSmqe+ibW0Rsz7YO7IE1HG3D3tqCNIidP46SZVdQ==",
|
||||
"dev": true
|
||||
},
|
||||
"before-after-hook": {
|
||||
@@ -550,13 +504,45 @@
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.1.tgz",
|
||||
"integrity": "sha512-/6FKxSTWoJdbsLDF8tdIjaRiFXiE6UHsEHE3OPI/cwPURCVi1ukP0gmLn7XWEiFk5TcwQjjY5PWsU+j+tgXgmw=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"camelcase": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz",
|
||||
"integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==",
|
||||
"dev": true
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"deprecation": {
|
||||
@@ -567,7 +553,13 @@
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||
"dev": true
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true
|
||||
},
|
||||
"is-plain-object": {
|
||||
@@ -575,6 +567,12 @@
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
|
||||
},
|
||||
"leven": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz",
|
||||
"integrity": "sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA==",
|
||||
"dev": true
|
||||
},
|
||||
"mri": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz",
|
||||
@@ -587,52 +585,32 @@
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||
"requires": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||
"requires": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"proxy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/proxy/-/proxy-1.0.2.tgz",
|
||||
"integrity": "sha512-KNac2ueWRpjbUh77OAFPZuNdfEqNynm9DD4xHT14CccGpW8wKZwEkN0yjlb7X9G9Z9F55N0Q+1z+WfgAhwYdzQ==",
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/proxy/-/proxy-2.1.1.tgz",
|
||||
"integrity": "sha512-nLgd7zdUAOpB3ZO/xCkU8gy74UER7P0aihU8DkUsDS5ZoFwVCX7u8dy+cv5tVK8UaB/yminU1GiLWE26TKPYpg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"args": "5.0.1",
|
||||
"basic-auth-parser": "0.0.2",
|
||||
"debug": "^4.1.1"
|
||||
"args": "^5.0.3",
|
||||
"basic-auth-parser": "0.0.2-1",
|
||||
"debug": "^4.3.4"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"tunnel": {
|
||||
@@ -640,6 +618,14 @@
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
|
||||
},
|
||||
"undici": {
|
||||
"version": "5.25.4",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.25.4.tgz",
|
||||
"integrity": "sha512-450yJxT29qKMf3aoudzFpIciqpx6Pji3hEWaXqXmanbXF58LTAGCKxcJjxMXWu3iG+Mudgo3ZUfDB6YDFd/dAw==",
|
||||
"requires": {
|
||||
"@fastify/busboy": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"universal-user-agent": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
||||
@@ -648,7 +634,7 @@
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@actions/github",
|
||||
"version": "5.1.1",
|
||||
"version": "6.0.0",
|
||||
"description": "Actions github lib",
|
||||
"keywords": [
|
||||
"github",
|
||||
@@ -38,12 +38,12 @@
|
||||
"url": "https://github.com/actions/toolkit/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"@octokit/core": "^3.6.0",
|
||||
"@octokit/plugin-paginate-rest": "^2.17.0",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^5.13.0"
|
||||
"@actions/http-client": "^2.2.0",
|
||||
"@octokit/core": "^5.0.1",
|
||||
"@octokit/plugin-paginate-rest": "^9.0.0",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^10.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"proxy": "^1.0.2"
|
||||
"proxy": "^2.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ export class Context {
|
||||
action: string
|
||||
actor: string
|
||||
job: string
|
||||
runAttempt: number
|
||||
runNumber: number
|
||||
runId: number
|
||||
apiUrl: string
|
||||
@@ -44,6 +45,7 @@ export class Context {
|
||||
this.action = process.env.GITHUB_ACTION as string
|
||||
this.actor = process.env.GITHUB_ACTOR as string
|
||||
this.job = process.env.GITHUB_JOB as string
|
||||
this.runAttempt = parseInt(process.env.GITHUB_RUN_ATTEMPT as string, 10)
|
||||
this.runNumber = parseInt(process.env.GITHUB_RUN_NUMBER as string, 10)
|
||||
this.runId = parseInt(process.env.GITHUB_RUN_ID as string, 10)
|
||||
this.apiUrl = process.env.GITHUB_API_URL ?? `https://api.github.com`
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as http from 'http'
|
||||
import * as httpClient from '@actions/http-client'
|
||||
import {OctokitOptions} from '@octokit/core/dist-types/types'
|
||||
import {ProxyAgent, fetch} from 'undici'
|
||||
|
||||
export function getAuthString(
|
||||
token: string,
|
||||
@@ -20,6 +21,24 @@ export function getProxyAgent(destinationUrl: string): http.Agent {
|
||||
return hc.getAgent(destinationUrl)
|
||||
}
|
||||
|
||||
export function getProxyAgentDispatcher(
|
||||
destinationUrl: string
|
||||
): ProxyAgent | undefined {
|
||||
const hc = new httpClient.HttpClient()
|
||||
return hc.getAgentDispatcher(destinationUrl)
|
||||
}
|
||||
|
||||
export function getProxyFetch(destinationUrl): typeof fetch {
|
||||
const httpDispatcher = getProxyAgentDispatcher(destinationUrl)
|
||||
const proxyFetch: typeof fetch = async (url, opts) => {
|
||||
return fetch(url, {
|
||||
...opts,
|
||||
dispatcher: httpDispatcher
|
||||
})
|
||||
}
|
||||
return proxyFetch
|
||||
}
|
||||
|
||||
export function getApiBaseUrl(): string {
|
||||
return process.env['GITHUB_API_URL'] || 'https://api.github.com'
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ const baseUrl = Utils.getApiBaseUrl()
|
||||
export const defaults: OctokitOptions = {
|
||||
baseUrl,
|
||||
request: {
|
||||
agent: Utils.getProxyAgent(baseUrl)
|
||||
agent: Utils.getProxyAgent(baseUrl),
|
||||
fetch: Utils.getProxyFetch(baseUrl)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -255,6 +255,7 @@ describe('globber', () => {
|
||||
'file-under-a'
|
||||
)
|
||||
])
|
||||
await unlinkSymlinkDir(itemPaths)
|
||||
})
|
||||
|
||||
it('detects cycle starting from symlink when followSymbolicLinks=true', async () => {
|
||||
@@ -861,6 +862,14 @@ async function createHiddenFile(file: string, content: string): Promise<void> {
|
||||
function getTestTemp(): string {
|
||||
return path.join(__dirname, '_temp', 'glob')
|
||||
}
|
||||
/**
|
||||
* Deletes a symlink directory
|
||||
*/
|
||||
async function unlinkSymlinkDir(links: string[]): Promise<void> {
|
||||
for (const link of links) {
|
||||
await fs.rm(link, {recursive: true, force: true})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a symlink directory on OSX/Linux, and a junction point directory on Windows.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user