Compare commits
9 Commits
fbe48b1d27
..
v8.0.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 3e5f45b2cf | |||
| e6d03f6737 | |||
| 70fc10c6e5 | |||
| f258da9a50 | |||
| ccc058e5fb | |||
| bd7976ba57 | |||
| ac21fcf45e | |||
| 15999bff51 | |||
| 974686ed50 |
@@ -154,3 +154,169 @@ jobs:
|
|||||||
}
|
}
|
||||||
Write-Host "Successfully downloaded artifact without decompressing: $rawFile (size: $($fileInfo.Length) bytes)"
|
Write-Host "Successfully downloaded artifact without decompressing: $rawFile (size: $($fileInfo.Length) bytes)"
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
|
|
||||||
|
# Regression test for artifact filename vs content-type mismatch
|
||||||
|
# When an archived artifact has a name with a file extension that doesn't
|
||||||
|
# match the blob type (e.g. "report.txt" but blob is zip), the server
|
||||||
|
# should append .zip to the content-disposition filename.
|
||||||
|
- name: Create and upload archived artifact with misleading extension
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir -p path/to/extension-test
|
||||||
|
echo '{"key": "value"}' > path/to/extension-test/data.json
|
||||||
|
- uses: actions/upload-artifact@v4 # V4 is important here to ensure we're supporting older versions correctly
|
||||||
|
with:
|
||||||
|
name: report.txt-${{ matrix.runs-on }}.json
|
||||||
|
path: path/to/extension-test/data.json
|
||||||
|
|
||||||
|
- name: Download misleading-extension artifact without decompressing
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
name: report.txt-${{ matrix.runs-on }}.json
|
||||||
|
path: ext-test/raw
|
||||||
|
skip-decompress: true
|
||||||
|
|
||||||
|
- name: Verify downloaded file has .zip extension appended
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
expected="ext-test/raw/report.txt-${{ matrix.runs-on }}.json.zip"
|
||||||
|
if [ -f "$expected" ]; then
|
||||||
|
echo "PASS: Downloaded file has .zip appended: $expected"
|
||||||
|
else
|
||||||
|
echo "FAIL: Expected $expected but got:"
|
||||||
|
ls -al ext-test/raw/
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test uploading and downloading artifacts with CJK (Chinese, Japanese, Korean) characters
|
||||||
|
# Regression test: certain non-ASCII chars (e.g. U+571F 土) caused 400 errors from
|
||||||
|
# Azure Blob Storage due to encoding issues in the Content-Disposition / rscd parameter
|
||||||
|
- name: Create artifacts with CJK names
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir -p path/to/cjk-artifacts
|
||||||
|
# Chinese - 土 (U+571F) known to fail, 日 (U+65E5) known to work
|
||||||
|
echo "Content for 土" > "path/to/cjk-artifacts/file-土-${{ matrix.runs-on }}.txt"
|
||||||
|
echo "Content for 中文测试" > "path/to/cjk-artifacts/file-中文测试-${{ matrix.runs-on }}.txt"
|
||||||
|
# Japanese - katakana and kanji
|
||||||
|
echo "Content for テスト" > "path/to/cjk-artifacts/file-テスト-${{ matrix.runs-on }}.txt"
|
||||||
|
echo "Content for 東京タワー" > "path/to/cjk-artifacts/file-東京タワー-${{ matrix.runs-on }}.txt"
|
||||||
|
# Korean - Hangul
|
||||||
|
echo "Content for 테스트" > "path/to/cjk-artifacts/file-테스트-${{ matrix.runs-on }}.txt"
|
||||||
|
echo "Content for 서울시" > "path/to/cjk-artifacts/file-서울시-${{ matrix.runs-on }}.txt"
|
||||||
|
|
||||||
|
- name: Upload CJK artifact - Chinese 土
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
path: path/to/cjk-artifacts/file-土-${{ matrix.runs-on }}.txt
|
||||||
|
archive: false
|
||||||
|
|
||||||
|
- name: Upload CJK artifact - Chinese 中文测试
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
path: path/to/cjk-artifacts/file-中文测试-${{ matrix.runs-on }}.txt
|
||||||
|
archive: false
|
||||||
|
|
||||||
|
- name: Upload CJK artifact - Japanese テスト
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
path: path/to/cjk-artifacts/file-テスト-${{ matrix.runs-on }}.txt
|
||||||
|
archive: false
|
||||||
|
|
||||||
|
- name: Upload CJK artifact - Japanese 東京タワー
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
path: path/to/cjk-artifacts/file-東京タワー-${{ matrix.runs-on }}.txt
|
||||||
|
archive: false
|
||||||
|
|
||||||
|
- name: Upload CJK artifact - Korean 테스트
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
path: path/to/cjk-artifacts/file-테스트-${{ matrix.runs-on }}.txt
|
||||||
|
archive: false
|
||||||
|
|
||||||
|
- name: Upload CJK artifact - Korean 서울시
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
path: path/to/cjk-artifacts/file-서울시-${{ matrix.runs-on }}.txt
|
||||||
|
archive: false
|
||||||
|
|
||||||
|
- name: Download CJK artifact - Chinese 土
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
name: file-土-${{ matrix.runs-on }}.txt
|
||||||
|
path: cjk-download/土
|
||||||
|
|
||||||
|
- name: Download CJK artifact - Chinese 中文测试
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
name: file-中文测试-${{ matrix.runs-on }}.txt
|
||||||
|
path: cjk-download/中文测试
|
||||||
|
|
||||||
|
- name: Download CJK artifact - Japanese テスト
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
name: file-テスト-${{ matrix.runs-on }}.txt
|
||||||
|
path: cjk-download/テスト
|
||||||
|
|
||||||
|
- name: Download CJK artifact - Japanese 東京タワー
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
name: file-東京タワー-${{ matrix.runs-on }}.txt
|
||||||
|
path: cjk-download/東京タワー
|
||||||
|
|
||||||
|
- name: Download CJK artifact - Korean 테스트
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
name: file-테스트-${{ matrix.runs-on }}.txt
|
||||||
|
path: cjk-download/테스트
|
||||||
|
|
||||||
|
- name: Download CJK artifact - Korean 서울시
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
name: file-서울시-${{ matrix.runs-on }}.txt
|
||||||
|
path: cjk-download/서울시
|
||||||
|
|
||||||
|
- name: Verify CJK artifact downloads
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
fail=0
|
||||||
|
|
||||||
|
check_file() {
|
||||||
|
local file="$1"
|
||||||
|
local expected="$2"
|
||||||
|
if [ ! -f "$file" ]; then
|
||||||
|
echo "FAIL: Missing file: $file"
|
||||||
|
fail=1
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
actual=$(cat "$file")
|
||||||
|
if [ "$actual" != "$expected" ]; then
|
||||||
|
echo "FAIL: Content mismatch in $file"
|
||||||
|
echo " Expected: '$expected'"
|
||||||
|
echo " Got: '$actual'"
|
||||||
|
fail=1
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo "PASS: $file"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "=== Chinese ==="
|
||||||
|
check_file "cjk-download/土/file-土-${{ matrix.runs-on }}.txt" "Content for 土"
|
||||||
|
check_file "cjk-download/中文测试/file-中文测试-${{ matrix.runs-on }}.txt" "Content for 中文测试"
|
||||||
|
|
||||||
|
echo "=== Japanese ==="
|
||||||
|
check_file "cjk-download/テスト/file-テスト-${{ matrix.runs-on }}.txt" "Content for テスト"
|
||||||
|
check_file "cjk-download/東京タワー/file-東京タワー-${{ matrix.runs-on }}.txt" "Content for 東京タワー"
|
||||||
|
|
||||||
|
echo "=== Korean ==="
|
||||||
|
check_file "cjk-download/테스트/file-테스트-${{ matrix.runs-on }}.txt" "Content for 테스트"
|
||||||
|
check_file "cjk-download/서울시/file-서울시-${{ matrix.runs-on }}.txt" "Content for 서울시"
|
||||||
|
|
||||||
|
if [ "$fail" -ne 0 ]; then
|
||||||
|
echo "Some CJK artifact checks failed"
|
||||||
|
ls -alR cjk-download/ || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "All CJK artifact downloads verified successfully"
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: "@actions/artifact"
|
name: "@actions/artifact"
|
||||||
version: 6.1.0
|
version: 6.2.1
|
||||||
type: npm
|
type: npm
|
||||||
summary: Actions artifact lib
|
summary: Actions artifact lib
|
||||||
homepage: https://github.com/actions/toolkit/tree/main/packages/artifact
|
homepage: https://github.com/actions/toolkit/tree/main/packages/artifact
|
||||||
|
|||||||
@@ -23,6 +23,25 @@ See also [upload-artifact](https://github.com/actions/upload-artifact).
|
|||||||
- [Limitations](#limitations)
|
- [Limitations](#limitations)
|
||||||
- [Permission Loss](#permission-loss)
|
- [Permission Loss](#permission-loss)
|
||||||
|
|
||||||
|
## v8 - What's new
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> actions/download-artifact@v8 has been migrated to an ESM module. This should be transparent to the caller but forks might need to make significant changes.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> Hash mismatches will now error by default. Users can override this behavior with a setting change (see below).
|
||||||
|
|
||||||
|
- Downloads will check the content-type returned to determine if a file can be decompressed and skip the decompression stage if so. This removes previous failures where we were trying to decompress a non-zip file. Since this is making a big change to the default behavior, we're making it opt-in via a version bump.
|
||||||
|
- Users can also download a zip file without decompressing it with the new `skip-decompress` flag.
|
||||||
|
|
||||||
|
- Introduces a new parameter `digest-mismatch` that allows callers to specify what to do when the downloaded hash doesn't match the expected hash (`ignore`, `info`, `warn`, `error`). To ensure security by default, the default value is `error`.
|
||||||
|
|
||||||
|
- Chore: we've bumped versions on a lot of our dev packages to get them up to date with the latest bugfixes/security patches.
|
||||||
|
|
||||||
|
### v8.0.1
|
||||||
|
|
||||||
|
- Support for CJK (Chinese/Japanese/Korean) characters in the file name.
|
||||||
|
|
||||||
## v7 - What's new
|
## v7 - What's new
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
@@ -77,7 +96,7 @@ We are taking the following steps to better direct requests related to GitHub Ac
|
|||||||
|
|
||||||
1. We will be directing questions and support requests to our [Community Discussions area](https://github.com/orgs/community/discussions/categories/actions)
|
1. We will be directing questions and support requests to our [Community Discussions area](https://github.com/orgs/community/discussions/categories/actions)
|
||||||
|
|
||||||
2. High Priority bugs can be reported through Community Discussions or you can report these to our support team https://support.github.com/contact/bug-report.
|
2. High Priority bugs can be reported through Community Discussions or you can report these to our support team <https://support.github.com/contact/bug-report>.
|
||||||
|
|
||||||
3. Security Issues should be handled as per our [security.md](SECURITY.md).
|
3. Security Issues should be handled as per our [security.md](SECURITY.md).
|
||||||
|
|
||||||
@@ -216,7 +235,7 @@ If the `name` input parameter is not provided, all artifacts will be downloaded.
|
|||||||
|
|
||||||
Example, if there are two artifacts `Artifact-A` and `Artifact-B`, and the directory is `etc/usr/artifacts/`, the directory structure will look like this:
|
Example, if there are two artifacts `Artifact-A` and `Artifact-B`, and the directory is `etc/usr/artifacts/`, the directory structure will look like this:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
etc/usr/artifacts/
|
etc/usr/artifacts/
|
||||||
Artifact-A/
|
Artifact-A/
|
||||||
... contents of Artifact-A
|
... contents of Artifact-A
|
||||||
@@ -258,7 +277,7 @@ steps:
|
|||||||
|
|
||||||
Which will result in:
|
Which will result in:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
path/to/artifacts/
|
path/to/artifacts/
|
||||||
... contents of Artifact-A
|
... contents of Artifact-A
|
||||||
... contents of Artifact-B
|
... contents of Artifact-B
|
||||||
@@ -298,7 +317,7 @@ jobs:
|
|||||||
|
|
||||||
This results in a directory like so:
|
This results in a directory like so:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
my-artifact/
|
my-artifact/
|
||||||
file-macos-latest.txt
|
file-macos-latest.txt
|
||||||
file-ubuntu-latest.txt
|
file-ubuntu-latest.txt
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ describe('download', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('warns when digest validation fails', async () => {
|
test('errors when digest validation fails (default behavior)', async () => {
|
||||||
const mockArtifact = {
|
const mockArtifact = {
|
||||||
id: 123,
|
id: 123,
|
||||||
name: 'corrupted-artifact',
|
name: 'corrupted-artifact',
|
||||||
@@ -242,6 +242,31 @@ describe('download', () => {
|
|||||||
digest: 'abc123'
|
digest: 'abc123'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(artifact.default, 'getArtifact')
|
||||||
|
.mockImplementation(() => Promise.resolve({artifact: mockArtifact}))
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(artifact.default, 'downloadArtifact')
|
||||||
|
.mockImplementation(() => Promise.resolve({digestMismatch: true}))
|
||||||
|
|
||||||
|
await expect(run()).rejects.toThrow(
|
||||||
|
'Digest validation failed for artifact(s): corrupted-artifact'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('warns when digest validation fails with digest-mismatch set to warn', async () => {
|
||||||
|
const mockArtifact = {
|
||||||
|
id: 123,
|
||||||
|
name: 'corrupted-artifact',
|
||||||
|
size: 1024,
|
||||||
|
digest: 'abc123'
|
||||||
|
}
|
||||||
|
|
||||||
|
mockInputs({
|
||||||
|
[Inputs.DigestMismatch]: 'warn'
|
||||||
|
})
|
||||||
|
|
||||||
jest
|
jest
|
||||||
.spyOn(artifact.default, 'getArtifact')
|
.spyOn(artifact.default, 'getArtifact')
|
||||||
.mockImplementation(() => Promise.resolve({artifact: mockArtifact}))
|
.mockImplementation(() => Promise.resolve({artifact: mockArtifact}))
|
||||||
@@ -257,6 +282,61 @@ describe('download', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('logs info when digest validation fails with digest-mismatch set to info', async () => {
|
||||||
|
const mockArtifact = {
|
||||||
|
id: 123,
|
||||||
|
name: 'corrupted-artifact',
|
||||||
|
size: 1024,
|
||||||
|
digest: 'abc123'
|
||||||
|
}
|
||||||
|
|
||||||
|
mockInputs({
|
||||||
|
[Inputs.DigestMismatch]: 'info'
|
||||||
|
})
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(artifact.default, 'getArtifact')
|
||||||
|
.mockImplementation(() => Promise.resolve({artifact: mockArtifact}))
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(artifact.default, 'downloadArtifact')
|
||||||
|
.mockImplementation(() => Promise.resolve({digestMismatch: true}))
|
||||||
|
|
||||||
|
await run()
|
||||||
|
|
||||||
|
expect(core.info).toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining('digest validation failed')
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('silently continues when digest validation fails with digest-mismatch set to ignore', async () => {
|
||||||
|
const mockArtifact = {
|
||||||
|
id: 123,
|
||||||
|
name: 'corrupted-artifact',
|
||||||
|
size: 1024,
|
||||||
|
digest: 'abc123'
|
||||||
|
}
|
||||||
|
|
||||||
|
mockInputs({
|
||||||
|
[Inputs.DigestMismatch]: 'ignore'
|
||||||
|
})
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(artifact.default, 'getArtifact')
|
||||||
|
.mockImplementation(() => Promise.resolve({artifact: mockArtifact}))
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(artifact.default, 'downloadArtifact')
|
||||||
|
.mockImplementation(() => Promise.resolve({digestMismatch: true}))
|
||||||
|
|
||||||
|
await run()
|
||||||
|
|
||||||
|
expect(core.warning).not.toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining('digest validation failed')
|
||||||
|
)
|
||||||
|
expect(core.info).toHaveBeenCalledWith('Total of 1 artifact(s) downloaded')
|
||||||
|
})
|
||||||
|
|
||||||
test('downloads a single artifact by ID', async () => {
|
test('downloads a single artifact by ID', async () => {
|
||||||
const mockArtifact = {
|
const mockArtifact = {
|
||||||
id: 456,
|
id: 456,
|
||||||
|
|||||||
@@ -40,6 +40,11 @@ inputs:
|
|||||||
This is useful when you want to handle the artifact as-is without extraction.'
|
This is useful when you want to handle the artifact as-is without extraction.'
|
||||||
required: false
|
required: false
|
||||||
default: 'false'
|
default: 'false'
|
||||||
|
digest-mismatch:
|
||||||
|
description: 'The behavior when a downloaded artifact''s digest does not match the expected digest.
|
||||||
|
Options: ignore, info, warn, error. Default is error which will fail the action.'
|
||||||
|
required: false
|
||||||
|
default: 'error'
|
||||||
outputs:
|
outputs:
|
||||||
download-path:
|
download-path:
|
||||||
description: 'Path of artifact download'
|
description: 'Path of artifact download'
|
||||||
|
|||||||
Vendored
+231
-272
@@ -77339,7 +77339,7 @@ module.exports = index;
|
|||||||
/***/ 2822:
|
/***/ 2822:
|
||||||
/***/ ((module) => {
|
/***/ ((module) => {
|
||||||
|
|
||||||
module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/artifact","version":"6.1.0","preview":true,"description":"Actions artifact lib","keywords":["github","actions","artifact"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/artifact","license":"MIT","type":"module","main":"lib/artifact.js","types":"lib/artifact.d.ts","exports":{".":{"types":"./lib/artifact.d.ts","import":"./lib/artifact.js"}},"directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/artifact"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"cd ../../ && npm run test ./packages/artifact","bootstrap":"cd ../../ && npm run bootstrap","tsc-run":"tsc && cp src/internal/shared/package-version.cjs lib/internal/shared/","tsc":"npm run bootstrap && npm run tsc-run","gen:docs":"typedoc --plugin typedoc-plugin-markdown --out docs/generated src/artifact.ts --githubPages false --readme none"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^3.0.0","@actions/github":"^9.0.0","@actions/http-client":"^4.0.0","@azure/storage-blob":"^12.30.0","@octokit/core":"^7.0.6","@octokit/plugin-request-log":"^6.0.0","@octokit/plugin-retry":"^8.0.0","@octokit/request":"^10.0.7","@octokit/request-error":"^7.1.0","@protobuf-ts/plugin":"^2.2.3-alpha.1","@protobuf-ts/runtime":"^2.9.4","archiver":"^7.0.1","jwt-decode":"^4.0.0","unzip-stream":"^0.3.1"},"devDependencies":{"@types/archiver":"^7.0.0","@types/unzip-stream":"^0.3.4","typedoc":"^0.28.16","typedoc-plugin-markdown":"^4.9.0","typescript":"^5.9.3"},"overrides":{"uri-js":"npm:uri-js-replace@^1.0.1","node-fetch":"^3.3.2"}}');
|
module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/artifact","version":"6.2.1","preview":true,"description":"Actions artifact lib","keywords":["github","actions","artifact"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/artifact","license":"MIT","type":"module","main":"lib/artifact.js","types":"lib/artifact.d.ts","exports":{".":{"types":"./lib/artifact.d.ts","import":"./lib/artifact.js"}},"directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/artifact"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"cd ../../ && npm run test ./packages/artifact","bootstrap":"cd ../../ && npm run bootstrap","tsc-run":"tsc && cp src/internal/shared/package-version.cjs lib/internal/shared/","tsc":"npm run bootstrap && npm run tsc-run","gen:docs":"typedoc --plugin typedoc-plugin-markdown --out docs/generated src/artifact.ts --githubPages false --readme none"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^3.0.0","@actions/github":"^9.0.0","@actions/http-client":"^4.0.0","@azure/storage-blob":"^12.30.0","@octokit/core":"^7.0.6","@octokit/plugin-request-log":"^6.0.0","@octokit/plugin-retry":"^8.0.0","@octokit/request":"^10.0.7","@octokit/request-error":"^7.1.0","@protobuf-ts/plugin":"^2.2.3-alpha.1","@protobuf-ts/runtime":"^2.9.4","archiver":"^7.0.1","jwt-decode":"^4.0.0","unzip-stream":"^0.3.1"},"devDependencies":{"@types/archiver":"^7.0.0","@types/unzip-stream":"^0.3.4","typedoc":"^0.28.16","typedoc-plugin-markdown":"^4.9.0","typescript":"^5.9.3"},"overrides":{"uri-js":"npm:uri-js-replace@^1.0.1","node-fetch":"^3.3.2"}}');
|
||||||
|
|
||||||
/***/ })
|
/***/ })
|
||||||
|
|
||||||
@@ -81433,236 +81433,6 @@ var build_commonjs = __nccwpck_require__(4420);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// @generated message type with reflection information, may provide speed optimized methods
|
|
||||||
class MigrateArtifactRequest$Type extends commonjs.MessageType {
|
|
||||||
constructor() {
|
|
||||||
super("github.actions.results.api.v1.MigrateArtifactRequest", [
|
|
||||||
{ no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
||||||
{ no: 2, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
||||||
{ no: 3, name: "expires_at", kind: "message", T: () => Timestamp }
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
create(value) {
|
|
||||||
const message = { workflowRunBackendId: "", name: "" };
|
|
||||||
globalThis.Object.defineProperty(message, commonjs.MESSAGE_TYPE, { enumerable: false, value: this });
|
|
||||||
if (value !== undefined)
|
|
||||||
(0,commonjs.reflectionMergePartial)(this, message, value);
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
internalBinaryRead(reader, length, options, target) {
|
|
||||||
let message = target !== null && target !== void 0 ? 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 name */ 2:
|
|
||||||
message.name = reader.string();
|
|
||||||
break;
|
|
||||||
case /* google.protobuf.Timestamp expires_at */ 3:
|
|
||||||
message.expiresAt = Timestamp.internalBinaryRead(reader, reader.uint32(), options, message.expiresAt);
|
|
||||||
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 ? commonjs.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
internalBinaryWrite(message, writer, options) {
|
|
||||||
/* string workflow_run_backend_id = 1; */
|
|
||||||
if (message.workflowRunBackendId !== "")
|
|
||||||
writer.tag(1, commonjs.WireType.LengthDelimited).string(message.workflowRunBackendId);
|
|
||||||
/* string name = 2; */
|
|
||||||
if (message.name !== "")
|
|
||||||
writer.tag(2, commonjs.WireType.LengthDelimited).string(message.name);
|
|
||||||
/* google.protobuf.Timestamp expires_at = 3; */
|
|
||||||
if (message.expiresAt)
|
|
||||||
Timestamp.internalBinaryWrite(message.expiresAt, writer.tag(3, commonjs.WireType.LengthDelimited).fork(), options).join();
|
|
||||||
let u = options.writeUnknownFields;
|
|
||||||
if (u !== false)
|
|
||||||
(u == true ? commonjs.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
|
||||||
return writer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @generated MessageType for protobuf message github.actions.results.api.v1.MigrateArtifactRequest
|
|
||||||
*/
|
|
||||||
const MigrateArtifactRequest = new MigrateArtifactRequest$Type();
|
|
||||||
// @generated message type with reflection information, may provide speed optimized methods
|
|
||||||
class MigrateArtifactResponse$Type extends commonjs.MessageType {
|
|
||||||
constructor() {
|
|
||||||
super("github.actions.results.api.v1.MigrateArtifactResponse", [
|
|
||||||
{ no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
|
|
||||||
{ no: 2, name: "signed_upload_url", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
create(value) {
|
|
||||||
const message = { ok: false, signedUploadUrl: "" };
|
|
||||||
globalThis.Object.defineProperty(message, commonjs.MESSAGE_TYPE, { enumerable: false, value: this });
|
|
||||||
if (value !== undefined)
|
|
||||||
(0,commonjs.reflectionMergePartial)(this, message, value);
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
internalBinaryRead(reader, length, options, target) {
|
|
||||||
let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length;
|
|
||||||
while (reader.pos < end) {
|
|
||||||
let [fieldNo, wireType] = reader.tag();
|
|
||||||
switch (fieldNo) {
|
|
||||||
case /* bool ok */ 1:
|
|
||||||
message.ok = reader.bool();
|
|
||||||
break;
|
|
||||||
case /* string signed_upload_url */ 2:
|
|
||||||
message.signedUploadUrl = 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 ? commonjs.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
internalBinaryWrite(message, writer, options) {
|
|
||||||
/* bool ok = 1; */
|
|
||||||
if (message.ok !== false)
|
|
||||||
writer.tag(1, commonjs.WireType.Varint).bool(message.ok);
|
|
||||||
/* string signed_upload_url = 2; */
|
|
||||||
if (message.signedUploadUrl !== "")
|
|
||||||
writer.tag(2, commonjs.WireType.LengthDelimited).string(message.signedUploadUrl);
|
|
||||||
let u = options.writeUnknownFields;
|
|
||||||
if (u !== false)
|
|
||||||
(u == true ? commonjs.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
|
||||||
return writer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @generated MessageType for protobuf message github.actions.results.api.v1.MigrateArtifactResponse
|
|
||||||
*/
|
|
||||||
const MigrateArtifactResponse = new MigrateArtifactResponse$Type();
|
|
||||||
// @generated message type with reflection information, may provide speed optimized methods
|
|
||||||
class FinalizeMigratedArtifactRequest$Type extends commonjs.MessageType {
|
|
||||||
constructor() {
|
|
||||||
super("github.actions.results.api.v1.FinalizeMigratedArtifactRequest", [
|
|
||||||
{ no: 1, name: "workflow_run_backend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
||||||
{ no: 2, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
||||||
{ no: 3, name: "size", kind: "scalar", T: 3 /*ScalarType.INT64*/ }
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
create(value) {
|
|
||||||
const message = { workflowRunBackendId: "", name: "", size: "0" };
|
|
||||||
globalThis.Object.defineProperty(message, commonjs.MESSAGE_TYPE, { enumerable: false, value: this });
|
|
||||||
if (value !== undefined)
|
|
||||||
(0,commonjs.reflectionMergePartial)(this, message, value);
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
internalBinaryRead(reader, length, options, target) {
|
|
||||||
let message = target !== null && target !== void 0 ? 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 name */ 2:
|
|
||||||
message.name = reader.string();
|
|
||||||
break;
|
|
||||||
case /* int64 size */ 3:
|
|
||||||
message.size = reader.int64().toString();
|
|
||||||
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 ? commonjs.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
internalBinaryWrite(message, writer, options) {
|
|
||||||
/* string workflow_run_backend_id = 1; */
|
|
||||||
if (message.workflowRunBackendId !== "")
|
|
||||||
writer.tag(1, commonjs.WireType.LengthDelimited).string(message.workflowRunBackendId);
|
|
||||||
/* string name = 2; */
|
|
||||||
if (message.name !== "")
|
|
||||||
writer.tag(2, commonjs.WireType.LengthDelimited).string(message.name);
|
|
||||||
/* int64 size = 3; */
|
|
||||||
if (message.size !== "0")
|
|
||||||
writer.tag(3, commonjs.WireType.Varint).int64(message.size);
|
|
||||||
let u = options.writeUnknownFields;
|
|
||||||
if (u !== false)
|
|
||||||
(u == true ? commonjs.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
|
||||||
return writer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @generated MessageType for protobuf message github.actions.results.api.v1.FinalizeMigratedArtifactRequest
|
|
||||||
*/
|
|
||||||
const FinalizeMigratedArtifactRequest = new FinalizeMigratedArtifactRequest$Type();
|
|
||||||
// @generated message type with reflection information, may provide speed optimized methods
|
|
||||||
class FinalizeMigratedArtifactResponse$Type extends commonjs.MessageType {
|
|
||||||
constructor() {
|
|
||||||
super("github.actions.results.api.v1.FinalizeMigratedArtifactResponse", [
|
|
||||||
{ no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
|
|
||||||
{ no: 2, name: "artifact_id", kind: "scalar", T: 3 /*ScalarType.INT64*/ }
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
create(value) {
|
|
||||||
const message = { ok: false, artifactId: "0" };
|
|
||||||
globalThis.Object.defineProperty(message, commonjs.MESSAGE_TYPE, { enumerable: false, value: this });
|
|
||||||
if (value !== undefined)
|
|
||||||
(0,commonjs.reflectionMergePartial)(this, message, value);
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
internalBinaryRead(reader, length, options, target) {
|
|
||||||
let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length;
|
|
||||||
while (reader.pos < end) {
|
|
||||||
let [fieldNo, wireType] = reader.tag();
|
|
||||||
switch (fieldNo) {
|
|
||||||
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")
|
|
||||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
|
||||||
let d = reader.skip(wireType);
|
|
||||||
if (u !== false)
|
|
||||||
(u === true ? commonjs.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
internalBinaryWrite(message, writer, options) {
|
|
||||||
/* bool ok = 1; */
|
|
||||||
if (message.ok !== false)
|
|
||||||
writer.tag(1, commonjs.WireType.Varint).bool(message.ok);
|
|
||||||
/* int64 artifact_id = 2; */
|
|
||||||
if (message.artifactId !== "0")
|
|
||||||
writer.tag(2, commonjs.WireType.Varint).int64(message.artifactId);
|
|
||||||
let u = options.writeUnknownFields;
|
|
||||||
if (u !== false)
|
|
||||||
(u == true ? commonjs.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
|
||||||
return writer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @generated MessageType for protobuf message github.actions.results.api.v1.FinalizeMigratedArtifactResponse
|
|
||||||
*/
|
|
||||||
const FinalizeMigratedArtifactResponse = new FinalizeMigratedArtifactResponse$Type();
|
|
||||||
// @generated message type with reflection information, may provide speed optimized methods
|
// @generated message type with reflection information, may provide speed optimized methods
|
||||||
class CreateArtifactRequest$Type extends commonjs.MessageType {
|
class CreateArtifactRequest$Type extends commonjs.MessageType {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -81671,7 +81441,8 @@ class CreateArtifactRequest$Type extends commonjs.MessageType {
|
|||||||
{ no: 2, name: "workflow_job_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: 3, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||||
{ no: 4, name: "expires_at", kind: "message", T: () => Timestamp },
|
{ no: 4, name: "expires_at", kind: "message", T: () => Timestamp },
|
||||||
{ no: 5, name: "version", kind: "scalar", T: 5 /*ScalarType.INT32*/ }
|
{ no: 5, name: "version", kind: "scalar", T: 5 /*ScalarType.INT32*/ },
|
||||||
|
{ no: 6, name: "mime_type", kind: "message", T: () => StringValue }
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
create(value) {
|
create(value) {
|
||||||
@@ -81701,6 +81472,9 @@ class CreateArtifactRequest$Type extends commonjs.MessageType {
|
|||||||
case /* int32 version */ 5:
|
case /* int32 version */ 5:
|
||||||
message.version = reader.int32();
|
message.version = reader.int32();
|
||||||
break;
|
break;
|
||||||
|
case /* google.protobuf.StringValue mime_type */ 6:
|
||||||
|
message.mimeType = StringValue.internalBinaryRead(reader, reader.uint32(), options, message.mimeType);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
let u = options.readUnknownField;
|
let u = options.readUnknownField;
|
||||||
if (u === "throw")
|
if (u === "throw")
|
||||||
@@ -81728,6 +81502,9 @@ class CreateArtifactRequest$Type extends commonjs.MessageType {
|
|||||||
/* int32 version = 5; */
|
/* int32 version = 5; */
|
||||||
if (message.version !== 0)
|
if (message.version !== 0)
|
||||||
writer.tag(5, commonjs.WireType.Varint).int32(message.version);
|
writer.tag(5, commonjs.WireType.Varint).int32(message.version);
|
||||||
|
/* google.protobuf.StringValue mime_type = 6; */
|
||||||
|
if (message.mimeType)
|
||||||
|
StringValue.internalBinaryWrite(message.mimeType, writer.tag(6, commonjs.WireType.LengthDelimited).fork(), options).join();
|
||||||
let u = options.writeUnknownFields;
|
let u = options.writeUnknownFields;
|
||||||
if (u !== false)
|
if (u !== false)
|
||||||
(u == true ? commonjs.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
(u == true ? commonjs.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||||
@@ -81993,7 +81770,7 @@ const artifact_ListArtifactsRequest = new ListArtifactsRequest$Type();
|
|||||||
class ListArtifactsResponse$Type extends commonjs.MessageType {
|
class ListArtifactsResponse$Type extends commonjs.MessageType {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("github.actions.results.api.v1.ListArtifactsResponse", [
|
super("github.actions.results.api.v1.ListArtifactsResponse", [
|
||||||
{ no: 1, name: "artifacts", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => ListArtifactsResponse_MonolithArtifact }
|
{ no: 1, name: "artifacts", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => ListArtifactsResponse_MonolithArtifact }
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
create(value) {
|
create(value) {
|
||||||
@@ -82356,9 +82133,7 @@ const ArtifactService = new build_commonjs/* ServiceType */.C0("github.actions.r
|
|||||||
{ name: "FinalizeArtifact", options: {}, I: artifact_FinalizeArtifactRequest, O: artifact_FinalizeArtifactResponse },
|
{ name: "FinalizeArtifact", options: {}, I: artifact_FinalizeArtifactRequest, O: artifact_FinalizeArtifactResponse },
|
||||||
{ name: "ListArtifacts", options: {}, I: artifact_ListArtifactsRequest, O: artifact_ListArtifactsResponse },
|
{ name: "ListArtifacts", options: {}, I: artifact_ListArtifactsRequest, O: artifact_ListArtifactsResponse },
|
||||||
{ name: "GetSignedArtifactURL", options: {}, I: artifact_GetSignedArtifactURLRequest, O: artifact_GetSignedArtifactURLResponse },
|
{ name: "GetSignedArtifactURL", options: {}, I: artifact_GetSignedArtifactURLRequest, O: artifact_GetSignedArtifactURLResponse },
|
||||||
{ name: "DeleteArtifact", options: {}, I: artifact_DeleteArtifactRequest, O: artifact_DeleteArtifactResponse },
|
{ name: "DeleteArtifact", options: {}, I: artifact_DeleteArtifactRequest, O: artifact_DeleteArtifactResponse }
|
||||||
{ name: "MigrateArtifact", options: {}, I: MigrateArtifactRequest, O: MigrateArtifactResponse },
|
|
||||||
{ name: "FinalizeMigratedArtifact", options: {}, I: FinalizeMigratedArtifactRequest, O: FinalizeMigratedArtifactResponse }
|
|
||||||
]);
|
]);
|
||||||
//# sourceMappingURL=artifact.js.map
|
//# sourceMappingURL=artifact.js.map
|
||||||
;// CONCATENATED MODULE: ./node_modules/@actions/artifact/lib/generated/results/api/v1/artifact.twirp-client.js
|
;// CONCATENATED MODULE: ./node_modules/@actions/artifact/lib/generated/results/api/v1/artifact.twirp-client.js
|
||||||
@@ -82616,7 +82391,7 @@ NetworkError.isNetworkErrorCode = (code) => {
|
|||||||
};
|
};
|
||||||
class UsageError extends Error {
|
class UsageError extends Error {
|
||||||
constructor() {
|
constructor() {
|
||||||
const message = `Artifact storage quota has been hit. Unable to upload any new artifacts. Usage is recalculated every 6-12 hours.\nMore info on storage limits: https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions#calculating-minute-and-storage-spending`;
|
const message = `Artifact storage quota has been hit. Unable to upload any new artifacts.\nMore info on storage limits: https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions#calculating-minute-and-storage-spending`;
|
||||||
super(message);
|
super(message);
|
||||||
this.name = 'UsageError';
|
this.name = 'UsageError';
|
||||||
}
|
}
|
||||||
@@ -122101,7 +121876,7 @@ var blob_upload_awaiter = (undefined && undefined.__awaiter) || function (thisAr
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
function uploadZipToBlobStorage(authenticatedUploadURL, zipUploadStream) {
|
function uploadToBlobStorage(authenticatedUploadURL, uploadStream, contentType) {
|
||||||
return blob_upload_awaiter(this, void 0, void 0, function* () {
|
return blob_upload_awaiter(this, void 0, void 0, function* () {
|
||||||
let uploadByteCount = 0;
|
let uploadByteCount = 0;
|
||||||
let lastProgressTime = Date.now();
|
let lastProgressTime = Date.now();
|
||||||
@@ -122123,26 +121898,26 @@ function uploadZipToBlobStorage(authenticatedUploadURL, zipUploadStream) {
|
|||||||
const bufferSize = getUploadChunkSize();
|
const bufferSize = getUploadChunkSize();
|
||||||
const blobClient = new BlobClient(authenticatedUploadURL);
|
const blobClient = new BlobClient(authenticatedUploadURL);
|
||||||
const blockBlobClient = blobClient.getBlockBlobClient();
|
const blockBlobClient = blobClient.getBlockBlobClient();
|
||||||
core_debug(`Uploading artifact zip to blob storage with maxConcurrency: ${maxConcurrency}, bufferSize: ${bufferSize}`);
|
core_debug(`Uploading artifact to blob storage with maxConcurrency: ${maxConcurrency}, bufferSize: ${bufferSize}, contentType: ${contentType}`);
|
||||||
const uploadCallback = (progress) => {
|
const uploadCallback = (progress) => {
|
||||||
info(`Uploaded bytes ${progress.loadedBytes}`);
|
info(`Uploaded bytes ${progress.loadedBytes}`);
|
||||||
uploadByteCount = progress.loadedBytes;
|
uploadByteCount = progress.loadedBytes;
|
||||||
lastProgressTime = Date.now();
|
lastProgressTime = Date.now();
|
||||||
};
|
};
|
||||||
const options = {
|
const options = {
|
||||||
blobHTTPHeaders: { blobContentType: 'zip' },
|
blobHTTPHeaders: { blobContentType: contentType },
|
||||||
onProgress: uploadCallback,
|
onProgress: uploadCallback,
|
||||||
abortSignal: abortController.signal
|
abortSignal: abortController.signal
|
||||||
};
|
};
|
||||||
let sha256Hash = undefined;
|
let sha256Hash = undefined;
|
||||||
const uploadStream = new external_stream_.PassThrough();
|
const blobUploadStream = new external_stream_.PassThrough();
|
||||||
const hashStream = external_crypto_namespaceObject.createHash('sha256');
|
const hashStream = external_crypto_namespaceObject.createHash('sha256');
|
||||||
zipUploadStream.pipe(uploadStream); // This stream is used for the upload
|
uploadStream.pipe(blobUploadStream); // 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
|
uploadStream.pipe(hashStream).setEncoding('hex'); // This stream is used to compute a hash of the content for integrity check
|
||||||
info('Beginning upload of artifact content to blob storage');
|
info('Beginning upload of artifact content to blob storage');
|
||||||
try {
|
try {
|
||||||
yield Promise.race([
|
yield Promise.race([
|
||||||
blockBlobClient.uploadStream(uploadStream, bufferSize, maxConcurrency, options),
|
blockBlobClient.uploadStream(blobUploadStream, bufferSize, maxConcurrency, options),
|
||||||
chunkTimer(getUploadChunkTimeout())
|
chunkTimer(getUploadChunkTimeout())
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -122158,7 +121933,7 @@ function uploadZipToBlobStorage(authenticatedUploadURL, zipUploadStream) {
|
|||||||
info('Finished uploading artifact content to blob storage!');
|
info('Finished uploading artifact content to blob storage!');
|
||||||
hashStream.end();
|
hashStream.end();
|
||||||
sha256Hash = hashStream.read();
|
sha256Hash = hashStream.read();
|
||||||
info(`SHA256 digest of uploaded artifact zip is ${sha256Hash}`);
|
info(`SHA256 digest of uploaded artifact is ${sha256Hash}`);
|
||||||
if (uploadByteCount === 0) {
|
if (uploadByteCount === 0) {
|
||||||
warning(`No data was uploaded to blob storage. Reported upload byte count is 0.`);
|
warning(`No data was uploaded to blob storage. Reported upload byte count is 0.`);
|
||||||
}
|
}
|
||||||
@@ -122173,6 +121948,59 @@ function uploadZipToBlobStorage(authenticatedUploadURL, zipUploadStream) {
|
|||||||
const promises_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("fs/promises");
|
const promises_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("fs/promises");
|
||||||
// EXTERNAL MODULE: ./node_modules/archiver/index.js
|
// EXTERNAL MODULE: ./node_modules/archiver/index.js
|
||||||
var archiver = __nccwpck_require__(9392);
|
var archiver = __nccwpck_require__(9392);
|
||||||
|
;// CONCATENATED MODULE: ./node_modules/@actions/artifact/lib/internal/upload/stream.js
|
||||||
|
var stream_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Custom stream transformer so we can set the highWaterMark property
|
||||||
|
// See https://github.com/nodejs/node/issues/8855
|
||||||
|
class WaterMarkedUploadStream extends external_stream_.Transform {
|
||||||
|
constructor(bufferSize) {
|
||||||
|
super({
|
||||||
|
highWaterMark: bufferSize
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
_transform(chunk, enc, cb) {
|
||||||
|
cb(null, chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function createRawFileUploadStream(filePath) {
|
||||||
|
return stream_awaiter(this, void 0, void 0, function* () {
|
||||||
|
core_debug(`Creating raw file upload stream for: ${filePath}`);
|
||||||
|
const bufferSize = getUploadChunkSize();
|
||||||
|
const uploadStream = new WaterMarkedUploadStream(bufferSize);
|
||||||
|
// Check if symlink and resolve the source path
|
||||||
|
let sourcePath = filePath;
|
||||||
|
const stats = yield external_fs_.promises.lstat(filePath);
|
||||||
|
if (stats.isSymbolicLink()) {
|
||||||
|
sourcePath = yield (0,promises_namespaceObject.realpath)(filePath);
|
||||||
|
}
|
||||||
|
// Create a read stream from the file and pipe it to the upload stream
|
||||||
|
const fileStream = external_fs_.createReadStream(sourcePath, {
|
||||||
|
highWaterMark: bufferSize
|
||||||
|
});
|
||||||
|
fileStream.on('error', error => {
|
||||||
|
core_error('An error has occurred while reading the file for upload');
|
||||||
|
core_error(String(error));
|
||||||
|
uploadStream.destroy(new Error('An error has occurred during file read for the artifact'));
|
||||||
|
});
|
||||||
|
fileStream.pipe(uploadStream);
|
||||||
|
return uploadStream;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=stream.js.map
|
||||||
;// CONCATENATED MODULE: ./node_modules/@actions/artifact/lib/internal/upload/zip.js
|
;// CONCATENATED MODULE: ./node_modules/@actions/artifact/lib/internal/upload/zip.js
|
||||||
var zip_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
var zip_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
@@ -122189,19 +122017,6 @@ var zip_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _argu
|
|||||||
|
|
||||||
|
|
||||||
const DEFAULT_COMPRESSION_LEVEL = 6;
|
const DEFAULT_COMPRESSION_LEVEL = 6;
|
||||||
// Custom stream transformer so we can set the highWaterMark property
|
|
||||||
// See https://github.com/nodejs/node/issues/8855
|
|
||||||
class ZipUploadStream extends external_stream_.Transform {
|
|
||||||
constructor(bufferSize) {
|
|
||||||
super({
|
|
||||||
highWaterMark: bufferSize
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
_transform(chunk, enc, cb) {
|
|
||||||
cb(null, chunk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function createZipUploadStream(uploadSpecification_1) {
|
function createZipUploadStream(uploadSpecification_1) {
|
||||||
return zip_awaiter(this, arguments, void 0, function* (uploadSpecification, compressionLevel = DEFAULT_COMPRESSION_LEVEL) {
|
return zip_awaiter(this, arguments, void 0, function* (uploadSpecification, compressionLevel = DEFAULT_COMPRESSION_LEVEL) {
|
||||||
core_debug(`Creating Artifact archive with compressionLevel: ${compressionLevel}`);
|
core_debug(`Creating Artifact archive with compressionLevel: ${compressionLevel}`);
|
||||||
@@ -122232,7 +122047,7 @@ function createZipUploadStream(uploadSpecification_1) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const bufferSize = getUploadChunkSize();
|
const bufferSize = getUploadChunkSize();
|
||||||
const zipUploadStream = new ZipUploadStream(bufferSize);
|
const zipUploadStream = new WaterMarkedUploadStream(bufferSize);
|
||||||
core_debug(`Zip write high watermark value ${zipUploadStream.writableHighWaterMark}`);
|
core_debug(`Zip write high watermark value ${zipUploadStream.writableHighWaterMark}`);
|
||||||
core_debug(`Zip read high watermark value ${zipUploadStream.readableHighWaterMark}`);
|
core_debug(`Zip read high watermark value ${zipUploadStream.readableHighWaterMark}`);
|
||||||
zip.pipe(zipUploadStream);
|
zip.pipe(zipUploadStream);
|
||||||
@@ -122264,6 +122079,78 @@ const zipEndCallback = () => {
|
|||||||
core_debug('Zip stream for upload has ended.');
|
core_debug('Zip stream for upload has ended.');
|
||||||
};
|
};
|
||||||
//# sourceMappingURL=zip.js.map
|
//# sourceMappingURL=zip.js.map
|
||||||
|
;// CONCATENATED MODULE: ./node_modules/@actions/artifact/lib/internal/upload/types.js
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps file extensions to MIME types
|
||||||
|
*/
|
||||||
|
const types_mimeTypes = {
|
||||||
|
// Text
|
||||||
|
'.txt': 'text/plain',
|
||||||
|
'.html': 'text/html',
|
||||||
|
'.htm': 'text/html',
|
||||||
|
'.css': 'text/css',
|
||||||
|
'.csv': 'text/csv',
|
||||||
|
'.xml': 'text/xml',
|
||||||
|
'.md': 'text/markdown',
|
||||||
|
// JavaScript/JSON
|
||||||
|
'.js': 'application/javascript',
|
||||||
|
'.mjs': 'application/javascript',
|
||||||
|
'.json': 'application/json',
|
||||||
|
// Images
|
||||||
|
'.png': 'image/png',
|
||||||
|
'.jpg': 'image/jpeg',
|
||||||
|
'.jpeg': 'image/jpeg',
|
||||||
|
'.gif': 'image/gif',
|
||||||
|
'.svg': 'image/svg+xml',
|
||||||
|
'.webp': 'image/webp',
|
||||||
|
'.ico': 'image/x-icon',
|
||||||
|
'.bmp': 'image/bmp',
|
||||||
|
'.tiff': 'image/tiff',
|
||||||
|
'.tif': 'image/tiff',
|
||||||
|
// Audio
|
||||||
|
'.mp3': 'audio/mpeg',
|
||||||
|
'.wav': 'audio/wav',
|
||||||
|
'.ogg': 'audio/ogg',
|
||||||
|
'.flac': 'audio/flac',
|
||||||
|
// Video
|
||||||
|
'.mp4': 'video/mp4',
|
||||||
|
'.webm': 'video/webm',
|
||||||
|
'.avi': 'video/x-msvideo',
|
||||||
|
'.mov': 'video/quicktime',
|
||||||
|
// Documents
|
||||||
|
'.pdf': 'application/pdf',
|
||||||
|
'.doc': 'application/msword',
|
||||||
|
'.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||||
|
'.xls': 'application/vnd.ms-excel',
|
||||||
|
'.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||||
|
'.ppt': 'application/vnd.ms-powerpoint',
|
||||||
|
'.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||||
|
// Archives
|
||||||
|
'.zip': 'application/zip',
|
||||||
|
'.tar': 'application/x-tar',
|
||||||
|
'.gz': 'application/gzip',
|
||||||
|
'.rar': 'application/vnd.rar',
|
||||||
|
'.7z': 'application/x-7z-compressed',
|
||||||
|
// Code/Data
|
||||||
|
'.wasm': 'application/wasm',
|
||||||
|
'.yaml': 'application/x-yaml',
|
||||||
|
'.yml': 'application/x-yaml',
|
||||||
|
// Fonts
|
||||||
|
'.woff': 'font/woff',
|
||||||
|
'.woff2': 'font/woff2',
|
||||||
|
'.ttf': 'font/ttf',
|
||||||
|
'.otf': 'font/otf',
|
||||||
|
'.eot': 'application/vnd.ms-fontobject'
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Gets the MIME type for a file based on its extension
|
||||||
|
*/
|
||||||
|
function getMimeType(filePath) {
|
||||||
|
const ext = external_path_.extname(filePath).toLowerCase();
|
||||||
|
return types_mimeTypes[ext] || 'application/octet-stream';
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=types.js.map
|
||||||
;// CONCATENATED MODULE: ./node_modules/@actions/artifact/lib/internal/upload/upload-artifact.js
|
;// CONCATENATED MODULE: ./node_modules/@actions/artifact/lib/internal/upload/upload-artifact.js
|
||||||
var upload_artifact_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
var upload_artifact_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
@@ -122284,14 +122171,36 @@ var upload_artifact_awaiter = (undefined && undefined.__awaiter) || function (th
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function uploadArtifact(name, files, rootDirectory, options) {
|
function uploadArtifact(name, files, rootDirectory, options) {
|
||||||
return upload_artifact_awaiter(this, void 0, void 0, function* () {
|
return upload_artifact_awaiter(this, void 0, void 0, function* () {
|
||||||
|
let artifactFileName = `${name}.zip`;
|
||||||
|
if (options === null || options === void 0 ? void 0 : options.skipArchive) {
|
||||||
|
if (files.length === 0) {
|
||||||
|
throw new FilesNotFoundError([]);
|
||||||
|
}
|
||||||
|
if (files.length > 1) {
|
||||||
|
throw new Error('skipArchive option is only supported when uploading a single file');
|
||||||
|
}
|
||||||
|
if (!external_fs_.existsSync(files[0])) {
|
||||||
|
throw new FilesNotFoundError(files);
|
||||||
|
}
|
||||||
|
artifactFileName = external_path_.basename(files[0]);
|
||||||
|
name = artifactFileName;
|
||||||
|
}
|
||||||
validateArtifactName(name);
|
validateArtifactName(name);
|
||||||
validateRootDirectory(rootDirectory);
|
validateRootDirectory(rootDirectory);
|
||||||
const zipSpecification = getUploadZipSpecification(files, rootDirectory);
|
let zipSpecification = [];
|
||||||
if (zipSpecification.length === 0) {
|
if (!(options === null || options === void 0 ? void 0 : options.skipArchive)) {
|
||||||
throw new FilesNotFoundError(zipSpecification.flatMap(s => (s.sourcePath ? [s.sourcePath] : [])));
|
zipSpecification = getUploadZipSpecification(files, rootDirectory);
|
||||||
|
if (zipSpecification.length === 0) {
|
||||||
|
throw new FilesNotFoundError(zipSpecification.flatMap(s => (s.sourcePath ? [s.sourcePath] : [])));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
const contentType = getMimeType(artifactFileName);
|
||||||
// get the IDs needed for the artifact creation
|
// get the IDs needed for the artifact creation
|
||||||
const backendIds = getBackendIdsFromToken();
|
const backendIds = getBackendIdsFromToken();
|
||||||
// create the artifact client
|
// create the artifact client
|
||||||
@@ -122301,7 +122210,8 @@ function uploadArtifact(name, files, rootDirectory, options) {
|
|||||||
workflowRunBackendId: backendIds.workflowRunBackendId,
|
workflowRunBackendId: backendIds.workflowRunBackendId,
|
||||||
workflowJobRunBackendId: backendIds.workflowJobRunBackendId,
|
workflowJobRunBackendId: backendIds.workflowJobRunBackendId,
|
||||||
name,
|
name,
|
||||||
version: 4
|
mimeType: StringValue.create({ value: contentType }),
|
||||||
|
version: 7
|
||||||
};
|
};
|
||||||
// if there is a retention period, add it to the request
|
// if there is a retention period, add it to the request
|
||||||
const expiresAt = getExpiration(options === null || options === void 0 ? void 0 : options.retentionDays);
|
const expiresAt = getExpiration(options === null || options === void 0 ? void 0 : options.retentionDays);
|
||||||
@@ -122312,9 +122222,17 @@ function uploadArtifact(name, files, rootDirectory, options) {
|
|||||||
if (!createArtifactResp.ok) {
|
if (!createArtifactResp.ok) {
|
||||||
throw new InvalidResponseError('CreateArtifact: response from backend was not ok');
|
throw new InvalidResponseError('CreateArtifact: response from backend was not ok');
|
||||||
}
|
}
|
||||||
const zipUploadStream = yield createZipUploadStream(zipSpecification, options === null || options === void 0 ? void 0 : options.compressionLevel);
|
let stream;
|
||||||
// Upload zip to blob storage
|
if (options === null || options === void 0 ? void 0 : options.skipArchive) {
|
||||||
const uploadResult = yield uploadZipToBlobStorage(createArtifactResp.signedUploadUrl, zipUploadStream);
|
// Upload raw file without archiving
|
||||||
|
stream = yield createRawFileUploadStream(files[0]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Create and upload zip archive
|
||||||
|
stream = yield createZipUploadStream(zipSpecification, options === null || options === void 0 ? void 0 : options.compressionLevel);
|
||||||
|
}
|
||||||
|
info(`Uploading artifact: ${artifactFileName}`);
|
||||||
|
const uploadResult = yield uploadToBlobStorage(createArtifactResp.signedUploadUrl, stream, contentType);
|
||||||
// finalize the artifact
|
// finalize the artifact
|
||||||
const finalizeArtifactReq = {
|
const finalizeArtifactReq = {
|
||||||
workflowRunBackendId: backendIds.workflowRunBackendId,
|
workflowRunBackendId: backendIds.workflowRunBackendId,
|
||||||
@@ -122333,7 +122251,7 @@ function uploadArtifact(name, files, rootDirectory, options) {
|
|||||||
throw new InvalidResponseError('FinalizeArtifact: response from backend was not ok');
|
throw new InvalidResponseError('FinalizeArtifact: response from backend was not ok');
|
||||||
}
|
}
|
||||||
const artifactId = BigInt(finalizeArtifactResp.artifactId);
|
const artifactId = BigInt(finalizeArtifactResp.artifactId);
|
||||||
info(`Artifact ${name}.zip successfully finalized. Artifact ID ${artifactId}`);
|
info(`Artifact ${name} successfully finalized. Artifact ID ${artifactId}`);
|
||||||
return {
|
return {
|
||||||
size: uploadResult.uploadSize,
|
size: uploadResult.uploadSize,
|
||||||
digest: uploadResult.sha256Hash,
|
digest: uploadResult.sha256Hash,
|
||||||
@@ -126504,13 +126422,17 @@ function streamExtractExternal(url_1, directory_1) {
|
|||||||
mimeType === 'application/zip-compressed' ||
|
mimeType === 'application/zip-compressed' ||
|
||||||
urlEndsWithZip;
|
urlEndsWithZip;
|
||||||
// Extract filename from Content-Disposition header
|
// Extract filename from Content-Disposition header
|
||||||
|
// Prefer filename* (RFC 5987) which supports UTF-8 encoded filenames,
|
||||||
|
// fall back to filename which may contain ASCII-only replacements
|
||||||
const contentDisposition = response.message.headers['content-disposition'] || '';
|
const contentDisposition = response.message.headers['content-disposition'] || '';
|
||||||
let fileName = 'artifact';
|
let fileName = 'artifact';
|
||||||
const filenameMatch = contentDisposition.match(/filename\*?=['"]?(?:UTF-\d['"]*)?([^;\r\n"']*)['"]?/i);
|
const filenameStar = contentDisposition.match(/filename\*\s*=\s*UTF-8''([^;\r\n]*)/i);
|
||||||
if (filenameMatch && filenameMatch[1]) {
|
const filenamePlain = contentDisposition.match(/(?<!\*)filename\s*=\s*['"]?([^;\r\n"']*)['"]?/i);
|
||||||
|
const rawName = (filenameStar === null || filenameStar === void 0 ? void 0 : filenameStar[1]) || (filenamePlain === null || filenamePlain === void 0 ? void 0 : filenamePlain[1]);
|
||||||
|
if (rawName) {
|
||||||
// Sanitize fileName to prevent path traversal attacks
|
// Sanitize fileName to prevent path traversal attacks
|
||||||
// Use path.basename to extract only the filename component
|
// Use path.basename to extract only the filename component
|
||||||
fileName = external_path_.basename(decodeURIComponent(filenameMatch[1].trim()));
|
fileName = external_path_.basename(decodeURIComponent(rawName.trim()));
|
||||||
}
|
}
|
||||||
core_debug(`Content-Type: ${contentType}, mimeType: ${mimeType}, urlEndsWithZip: ${urlEndsWithZip}, isZip: ${isZip}, skipDecompress: ${skipDecompress}`);
|
core_debug(`Content-Type: ${contentType}, mimeType: ${mimeType}, urlEndsWithZip: ${urlEndsWithZip}, isZip: ${isZip}, skipDecompress: ${skipDecompress}`);
|
||||||
core_debug(`Content-Disposition: ${contentDisposition}, fileName: ${fileName}`);
|
core_debug(`Content-Disposition: ${contentDisposition}, fileName: ${fileName}`);
|
||||||
@@ -129353,7 +129275,15 @@ var Inputs;
|
|||||||
Inputs["MergeMultiple"] = "merge-multiple";
|
Inputs["MergeMultiple"] = "merge-multiple";
|
||||||
Inputs["ArtifactIds"] = "artifact-ids";
|
Inputs["ArtifactIds"] = "artifact-ids";
|
||||||
Inputs["SkipDecompress"] = "skip-decompress";
|
Inputs["SkipDecompress"] = "skip-decompress";
|
||||||
|
Inputs["DigestMismatch"] = "digest-mismatch";
|
||||||
})(Inputs || (Inputs = {}));
|
})(Inputs || (Inputs = {}));
|
||||||
|
var DigestMismatchBehavior;
|
||||||
|
(function (DigestMismatchBehavior) {
|
||||||
|
DigestMismatchBehavior["Ignore"] = "ignore";
|
||||||
|
DigestMismatchBehavior["Info"] = "info";
|
||||||
|
DigestMismatchBehavior["Warn"] = "warn";
|
||||||
|
DigestMismatchBehavior["Error"] = "error";
|
||||||
|
})(DigestMismatchBehavior || (DigestMismatchBehavior = {}));
|
||||||
var Outputs;
|
var Outputs;
|
||||||
(function (Outputs) {
|
(function (Outputs) {
|
||||||
Outputs["DownloadPath"] = "download-path";
|
Outputs["DownloadPath"] = "download-path";
|
||||||
@@ -129386,8 +129316,15 @@ async function run() {
|
|||||||
artifactIds: getInput(Inputs.ArtifactIds, { required: false }),
|
artifactIds: getInput(Inputs.ArtifactIds, { required: false }),
|
||||||
skipDecompress: getBooleanInput(Inputs.SkipDecompress, {
|
skipDecompress: getBooleanInput(Inputs.SkipDecompress, {
|
||||||
required: false
|
required: false
|
||||||
})
|
}),
|
||||||
|
digestMismatch: (getInput(Inputs.DigestMismatch, { required: false }) ||
|
||||||
|
DigestMismatchBehavior.Error)
|
||||||
};
|
};
|
||||||
|
// Validate digest-mismatch input
|
||||||
|
const validBehaviors = Object.values(DigestMismatchBehavior);
|
||||||
|
if (!validBehaviors.includes(inputs.digestMismatch)) {
|
||||||
|
throw new Error(`Invalid value for 'digest-mismatch': '${inputs.digestMismatch}'. Valid options are: ${validBehaviors.join(', ')}`);
|
||||||
|
}
|
||||||
if (!inputs.path) {
|
if (!inputs.path) {
|
||||||
inputs.path = process.env['GITHUB_WORKSPACE'] || process.cwd();
|
inputs.path = process.env['GITHUB_WORKSPACE'] || process.cwd();
|
||||||
}
|
}
|
||||||
@@ -129500,6 +129437,7 @@ async function run() {
|
|||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
const chunkedPromises = chunk(downloadPromises, PARALLEL_DOWNLOADS);
|
const chunkedPromises = chunk(downloadPromises, PARALLEL_DOWNLOADS);
|
||||||
|
const digestMismatches = [];
|
||||||
for (const chunk of chunkedPromises) {
|
for (const chunk of chunkedPromises) {
|
||||||
const chunkPromises = chunk.map(item => item.promise);
|
const chunkPromises = chunk.map(item => item.promise);
|
||||||
const results = await Promise.all(chunkPromises);
|
const results = await Promise.all(chunkPromises);
|
||||||
@@ -129507,10 +129445,31 @@ async function run() {
|
|||||||
const outcome = results[i];
|
const outcome = results[i];
|
||||||
const artifactName = chunk[i].name;
|
const artifactName = chunk[i].name;
|
||||||
if (outcome.digestMismatch) {
|
if (outcome.digestMismatch) {
|
||||||
warning(`Artifact '${artifactName}' digest validation failed. Please verify the integrity of the artifact.`);
|
digestMismatches.push(artifactName);
|
||||||
|
const message = `Artifact '${artifactName}' digest validation failed. Please verify the integrity of the artifact.`;
|
||||||
|
switch (inputs.digestMismatch) {
|
||||||
|
case DigestMismatchBehavior.Ignore:
|
||||||
|
// Do nothing
|
||||||
|
break;
|
||||||
|
case DigestMismatchBehavior.Info:
|
||||||
|
info(message);
|
||||||
|
break;
|
||||||
|
case DigestMismatchBehavior.Warn:
|
||||||
|
warning(message);
|
||||||
|
break;
|
||||||
|
case DigestMismatchBehavior.Error:
|
||||||
|
// Collect all errors and fail at the end
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If there were digest mismatches and behavior is 'error', fail the action
|
||||||
|
if (digestMismatches.length > 0 &&
|
||||||
|
inputs.digestMismatch === DigestMismatchBehavior.Error) {
|
||||||
|
throw new Error(`Digest validation failed for artifact(s): ${digestMismatches.join(', ')}. ` +
|
||||||
|
`Use 'digest-mismatch: warn' to continue on mismatch.`);
|
||||||
|
}
|
||||||
info(`Total of ${artifacts.length} artifact(s) downloaded`);
|
info(`Total of ${artifacts.length} artifact(s) downloaded`);
|
||||||
setOutput(Outputs.DownloadPath, resolvedPath);
|
setOutput(Outputs.DownloadPath, resolvedPath);
|
||||||
info('Download artifact has finished successfully');
|
info('Download artifact has finished successfully');
|
||||||
|
|||||||
Generated
+6
-6
@@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "download-artifact",
|
"name": "download-artifact",
|
||||||
"version": "7.0.0",
|
"version": "8.0.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "download-artifact",
|
"name": "download-artifact",
|
||||||
"version": "7.0.0",
|
"version": "8.0.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/artifact": "^6.1.0",
|
"@actions/artifact": "^6.2.1",
|
||||||
"@actions/core": "^3.0.0",
|
"@actions/core": "^3.0.0",
|
||||||
"minimatch": "^10.1.1"
|
"minimatch": "^10.1.1"
|
||||||
},
|
},
|
||||||
@@ -36,9 +36,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@actions/artifact": {
|
"node_modules/@actions/artifact": {
|
||||||
"version": "6.1.0",
|
"version": "6.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-6.2.1.tgz",
|
||||||
"integrity": "sha512-oRn9YhKkboXgIq2TQZ9uj6bhkT5ZUzFtnyTQ0tLGBwImaD0GfWShE5R0tPbN25EJmS3tz5sDd2JnVokAOtNrZQ==",
|
"integrity": "sha512-sJGH0mhEbEjBCw7o6SaLhUU66u27aFW8HTfkIb5Tk2/Wy0caUDc+oYQEgnuFN7a0HCpAbQyK0U6U7XUJDgDWrw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^3.0.0",
|
"@actions/core": "^3.0.0",
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "download-artifact",
|
"name": "download-artifact",
|
||||||
"version": "7.0.0",
|
"version": "8.0.1",
|
||||||
"description": "Download an Actions Artifact from a workflow run",
|
"description": "Download an Actions Artifact from a workflow run",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/actions/download-artifact#readme",
|
"homepage": "https://github.com/actions/download-artifact#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/artifact": "^6.1.0",
|
"@actions/artifact": "^6.2.1",
|
||||||
"@actions/core": "^3.0.0",
|
"@actions/core": "^3.0.0",
|
||||||
"minimatch": "^10.1.1"
|
"minimatch": "^10.1.1"
|
||||||
},
|
},
|
||||||
|
|||||||
+9
-1
@@ -7,7 +7,15 @@ export enum Inputs {
|
|||||||
Pattern = 'pattern',
|
Pattern = 'pattern',
|
||||||
MergeMultiple = 'merge-multiple',
|
MergeMultiple = 'merge-multiple',
|
||||||
ArtifactIds = 'artifact-ids',
|
ArtifactIds = 'artifact-ids',
|
||||||
SkipDecompress = 'skip-decompress'
|
SkipDecompress = 'skip-decompress',
|
||||||
|
DigestMismatch = 'digest-mismatch'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum DigestMismatchBehavior {
|
||||||
|
Ignore = 'ignore',
|
||||||
|
Info = 'info',
|
||||||
|
Warn = 'warn',
|
||||||
|
Error = 'error'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Outputs {
|
export enum Outputs {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import * as core from '@actions/core'
|
|||||||
import artifactClient from '@actions/artifact'
|
import artifactClient from '@actions/artifact'
|
||||||
import type {Artifact, FindOptions} from '@actions/artifact'
|
import type {Artifact, FindOptions} from '@actions/artifact'
|
||||||
import {Minimatch} from 'minimatch'
|
import {Minimatch} from 'minimatch'
|
||||||
import {Inputs, Outputs} from './constants.js'
|
import {Inputs, Outputs, DigestMismatchBehavior} from './constants.js'
|
||||||
|
|
||||||
const PARALLEL_DOWNLOADS = 5
|
const PARALLEL_DOWNLOADS = 5
|
||||||
|
|
||||||
@@ -29,7 +29,17 @@ export async function run(): Promise<void> {
|
|||||||
artifactIds: core.getInput(Inputs.ArtifactIds, {required: false}),
|
artifactIds: core.getInput(Inputs.ArtifactIds, {required: false}),
|
||||||
skipDecompress: core.getBooleanInput(Inputs.SkipDecompress, {
|
skipDecompress: core.getBooleanInput(Inputs.SkipDecompress, {
|
||||||
required: false
|
required: false
|
||||||
})
|
}),
|
||||||
|
digestMismatch: (core.getInput(Inputs.DigestMismatch, {required: false}) ||
|
||||||
|
DigestMismatchBehavior.Error) as DigestMismatchBehavior
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate digest-mismatch input
|
||||||
|
const validBehaviors = Object.values(DigestMismatchBehavior)
|
||||||
|
if (!validBehaviors.includes(inputs.digestMismatch)) {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid value for 'digest-mismatch': '${inputs.digestMismatch}'. Valid options are: ${validBehaviors.join(', ')}`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inputs.path) {
|
if (!inputs.path) {
|
||||||
@@ -188,6 +198,8 @@ export async function run(): Promise<void> {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
const chunkedPromises = chunk(downloadPromises, PARALLEL_DOWNLOADS)
|
const chunkedPromises = chunk(downloadPromises, PARALLEL_DOWNLOADS)
|
||||||
|
const digestMismatches: string[] = []
|
||||||
|
|
||||||
for (const chunk of chunkedPromises) {
|
for (const chunk of chunkedPromises) {
|
||||||
const chunkPromises = chunk.map(item => item.promise)
|
const chunkPromises = chunk.map(item => item.promise)
|
||||||
const results = await Promise.all(chunkPromises)
|
const results = await Promise.all(chunkPromises)
|
||||||
@@ -197,12 +209,38 @@ export async function run(): Promise<void> {
|
|||||||
const artifactName = chunk[i].name
|
const artifactName = chunk[i].name
|
||||||
|
|
||||||
if (outcome.digestMismatch) {
|
if (outcome.digestMismatch) {
|
||||||
core.warning(
|
digestMismatches.push(artifactName)
|
||||||
`Artifact '${artifactName}' digest validation failed. Please verify the integrity of the artifact.`
|
const message = `Artifact '${artifactName}' digest validation failed. Please verify the integrity of the artifact.`
|
||||||
)
|
|
||||||
|
switch (inputs.digestMismatch) {
|
||||||
|
case DigestMismatchBehavior.Ignore:
|
||||||
|
// Do nothing
|
||||||
|
break
|
||||||
|
case DigestMismatchBehavior.Info:
|
||||||
|
core.info(message)
|
||||||
|
break
|
||||||
|
case DigestMismatchBehavior.Warn:
|
||||||
|
core.warning(message)
|
||||||
|
break
|
||||||
|
case DigestMismatchBehavior.Error:
|
||||||
|
// Collect all errors and fail at the end
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there were digest mismatches and behavior is 'error', fail the action
|
||||||
|
if (
|
||||||
|
digestMismatches.length > 0 &&
|
||||||
|
inputs.digestMismatch === DigestMismatchBehavior.Error
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
`Digest validation failed for artifact(s): ${digestMismatches.join(', ')}. ` +
|
||||||
|
`Use 'digest-mismatch: warn' to continue on mismatch.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
core.info(`Total of ${artifacts.length} artifact(s) downloaded`)
|
core.info(`Total of ${artifacts.length} artifact(s) downloaded`)
|
||||||
core.setOutput(Outputs.DownloadPath, resolvedPath)
|
core.setOutput(Outputs.DownloadPath, resolvedPath)
|
||||||
core.info('Download artifact has finished successfully')
|
core.info('Download artifact has finished successfully')
|
||||||
|
|||||||
Reference in New Issue
Block a user