Compare commits
9 Commits
fbe48b1d27
...
v8
| 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)"
|
||||
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"
|
||||
version: 6.1.0
|
||||
version: 6.2.1
|
||||
type: npm
|
||||
summary: Actions artifact lib
|
||||
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)
|
||||
- [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
|
||||
|
||||
> [!IMPORTANT]
|
||||
@@ -69,7 +88,7 @@ For assistance with breaking changes, see [MIGRATION.md](docs/MIGRATION.md).
|
||||
|
||||
## Note
|
||||
|
||||
Thank you for your interest in this GitHub repo, however, right now we are not taking contributions.
|
||||
Thank you for your interest in this GitHub repo, however, right now we are not taking contributions.
|
||||
|
||||
We continue to focus our resources on strategic areas that help our customers be successful while making developers' lives easier. While GitHub Actions remains a key part of this vision, we are allocating resources towards other areas of Actions and are not taking contributions to this repository at this time. The GitHub public roadmap is the best place to follow along for any updates on features we’re working on and what stage they’re in.
|
||||
|
||||
@@ -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)
|
||||
|
||||
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).
|
||||
|
||||
@@ -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:
|
||||
|
||||
```
|
||||
```bash
|
||||
etc/usr/artifacts/
|
||||
Artifact-A/
|
||||
... contents of Artifact-A
|
||||
@@ -258,7 +277,7 @@ steps:
|
||||
|
||||
Which will result in:
|
||||
|
||||
```
|
||||
```bash
|
||||
path/to/artifacts/
|
||||
... contents of Artifact-A
|
||||
... contents of Artifact-B
|
||||
@@ -298,7 +317,7 @@ jobs:
|
||||
|
||||
This results in a directory like so:
|
||||
|
||||
```
|
||||
```bash
|
||||
my-artifact/
|
||||
file-macos-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 = {
|
||||
id: 123,
|
||||
name: 'corrupted-artifact',
|
||||
@@ -242,6 +242,31 @@ describe('download', () => {
|
||||
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
|
||||
.spyOn(artifact.default, 'getArtifact')
|
||||
.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 () => {
|
||||
const mockArtifact = {
|
||||
id: 456,
|
||||
|
||||
@@ -40,6 +40,11 @@ inputs:
|
||||
This is useful when you want to handle the artifact as-is without extraction.'
|
||||
required: 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:
|
||||
download-path:
|
||||
description: 'Path of artifact download'
|
||||
|
||||
Vendored
+231
-272
@@ -77339,7 +77339,7 @@ module.exports = index;
|
||||
/***/ 2822:
|
||||
/***/ ((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
|
||||
class CreateArtifactRequest$Type extends commonjs.MessageType {
|
||||
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: 3, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ 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) {
|
||||
@@ -81701,6 +81472,9 @@ class CreateArtifactRequest$Type extends commonjs.MessageType {
|
||||
case /* int32 version */ 5:
|
||||
message.version = reader.int32();
|
||||
break;
|
||||
case /* google.protobuf.StringValue mime_type */ 6:
|
||||
message.mimeType = StringValue.internalBinaryRead(reader, reader.uint32(), options, message.mimeType);
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
@@ -81728,6 +81502,9 @@ class CreateArtifactRequest$Type extends commonjs.MessageType {
|
||||
/* int32 version = 5; */
|
||||
if (message.version !== 0)
|
||||
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;
|
||||
if (u !== false)
|
||||
(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 {
|
||||
constructor() {
|
||||
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) {
|
||||
@@ -82356,9 +82133,7 @@ const ArtifactService = new build_commonjs/* ServiceType */.C0("github.actions.r
|
||||
{ name: "FinalizeArtifact", options: {}, I: artifact_FinalizeArtifactRequest, O: artifact_FinalizeArtifactResponse },
|
||||
{ name: "ListArtifacts", options: {}, I: artifact_ListArtifactsRequest, O: artifact_ListArtifactsResponse },
|
||||
{ name: "GetSignedArtifactURL", options: {}, I: artifact_GetSignedArtifactURLRequest, O: artifact_GetSignedArtifactURLResponse },
|
||||
{ name: "DeleteArtifact", options: {}, I: artifact_DeleteArtifactRequest, O: artifact_DeleteArtifactResponse },
|
||||
{ name: "MigrateArtifact", options: {}, I: MigrateArtifactRequest, O: MigrateArtifactResponse },
|
||||
{ name: "FinalizeMigratedArtifact", options: {}, I: FinalizeMigratedArtifactRequest, O: FinalizeMigratedArtifactResponse }
|
||||
{ name: "DeleteArtifact", options: {}, I: artifact_DeleteArtifactRequest, O: artifact_DeleteArtifactResponse }
|
||||
]);
|
||||
//# sourceMappingURL=artifact.js.map
|
||||
;// 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 {
|
||||
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);
|
||||
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* () {
|
||||
let uploadByteCount = 0;
|
||||
let lastProgressTime = Date.now();
|
||||
@@ -122123,26 +121898,26 @@ function uploadZipToBlobStorage(authenticatedUploadURL, zipUploadStream) {
|
||||
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}`);
|
||||
core_debug(`Uploading artifact to blob storage with maxConcurrency: ${maxConcurrency}, bufferSize: ${bufferSize}, contentType: ${contentType}`);
|
||||
const uploadCallback = (progress) => {
|
||||
info(`Uploaded bytes ${progress.loadedBytes}`);
|
||||
uploadByteCount = progress.loadedBytes;
|
||||
lastProgressTime = Date.now();
|
||||
};
|
||||
const options = {
|
||||
blobHTTPHeaders: { blobContentType: 'zip' },
|
||||
blobHTTPHeaders: { blobContentType: contentType },
|
||||
onProgress: uploadCallback,
|
||||
abortSignal: abortController.signal
|
||||
};
|
||||
let sha256Hash = undefined;
|
||||
const uploadStream = new external_stream_.PassThrough();
|
||||
const blobUploadStream = new external_stream_.PassThrough();
|
||||
const hashStream = external_crypto_namespaceObject.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
|
||||
uploadStream.pipe(blobUploadStream); // This stream is used for the upload
|
||||
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');
|
||||
try {
|
||||
yield Promise.race([
|
||||
blockBlobClient.uploadStream(uploadStream, bufferSize, maxConcurrency, options),
|
||||
blockBlobClient.uploadStream(blobUploadStream, bufferSize, maxConcurrency, options),
|
||||
chunkTimer(getUploadChunkTimeout())
|
||||
]);
|
||||
}
|
||||
@@ -122158,7 +121933,7 @@ function uploadZipToBlobStorage(authenticatedUploadURL, zipUploadStream) {
|
||||
info('Finished uploading artifact content to blob storage!');
|
||||
hashStream.end();
|
||||
sha256Hash = hashStream.read();
|
||||
info(`SHA256 digest of uploaded artifact zip is ${sha256Hash}`);
|
||||
info(`SHA256 digest of uploaded artifact is ${sha256Hash}`);
|
||||
if (uploadByteCount === 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");
|
||||
// EXTERNAL MODULE: ./node_modules/archiver/index.js
|
||||
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
|
||||
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); }); }
|
||||
@@ -122189,19 +122017,6 @@ var zip_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _argu
|
||||
|
||||
|
||||
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) {
|
||||
return zip_awaiter(this, arguments, void 0, function* (uploadSpecification, compressionLevel = DEFAULT_COMPRESSION_LEVEL) {
|
||||
core_debug(`Creating Artifact archive with compressionLevel: ${compressionLevel}`);
|
||||
@@ -122232,7 +122047,7 @@ function createZipUploadStream(uploadSpecification_1) {
|
||||
}
|
||||
}
|
||||
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 read high watermark value ${zipUploadStream.readableHighWaterMark}`);
|
||||
zip.pipe(zipUploadStream);
|
||||
@@ -122264,6 +122079,78 @@ const zipEndCallback = () => {
|
||||
core_debug('Zip stream for upload has ended.');
|
||||
};
|
||||
//# 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
|
||||
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); }); }
|
||||
@@ -122284,14 +122171,36 @@ var upload_artifact_awaiter = (undefined && undefined.__awaiter) || function (th
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function uploadArtifact(name, files, rootDirectory, options) {
|
||||
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);
|
||||
validateRootDirectory(rootDirectory);
|
||||
const zipSpecification = getUploadZipSpecification(files, rootDirectory);
|
||||
if (zipSpecification.length === 0) {
|
||||
throw new FilesNotFoundError(zipSpecification.flatMap(s => (s.sourcePath ? [s.sourcePath] : [])));
|
||||
let zipSpecification = [];
|
||||
if (!(options === null || options === void 0 ? void 0 : options.skipArchive)) {
|
||||
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
|
||||
const backendIds = getBackendIdsFromToken();
|
||||
// create the artifact client
|
||||
@@ -122301,7 +122210,8 @@ function uploadArtifact(name, files, rootDirectory, options) {
|
||||
workflowRunBackendId: backendIds.workflowRunBackendId,
|
||||
workflowJobRunBackendId: backendIds.workflowJobRunBackendId,
|
||||
name,
|
||||
version: 4
|
||||
mimeType: StringValue.create({ value: contentType }),
|
||||
version: 7
|
||||
};
|
||||
// if there is a retention period, add it to the request
|
||||
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) {
|
||||
throw new InvalidResponseError('CreateArtifact: response from backend was not ok');
|
||||
}
|
||||
const zipUploadStream = yield createZipUploadStream(zipSpecification, options === null || options === void 0 ? void 0 : options.compressionLevel);
|
||||
// Upload zip to blob storage
|
||||
const uploadResult = yield uploadZipToBlobStorage(createArtifactResp.signedUploadUrl, zipUploadStream);
|
||||
let stream;
|
||||
if (options === null || options === void 0 ? void 0 : options.skipArchive) {
|
||||
// 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
|
||||
const finalizeArtifactReq = {
|
||||
workflowRunBackendId: backendIds.workflowRunBackendId,
|
||||
@@ -122333,7 +122251,7 @@ function uploadArtifact(name, files, rootDirectory, options) {
|
||||
throw new InvalidResponseError('FinalizeArtifact: response from backend was not ok');
|
||||
}
|
||||
const artifactId = BigInt(finalizeArtifactResp.artifactId);
|
||||
info(`Artifact ${name}.zip successfully finalized. Artifact ID ${artifactId}`);
|
||||
info(`Artifact ${name} successfully finalized. Artifact ID ${artifactId}`);
|
||||
return {
|
||||
size: uploadResult.uploadSize,
|
||||
digest: uploadResult.sha256Hash,
|
||||
@@ -126504,13 +126422,17 @@ function streamExtractExternal(url_1, directory_1) {
|
||||
mimeType === 'application/zip-compressed' ||
|
||||
urlEndsWithZip;
|
||||
// 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'] || '';
|
||||
let fileName = 'artifact';
|
||||
const filenameMatch = contentDisposition.match(/filename\*?=['"]?(?:UTF-\d['"]*)?([^;\r\n"']*)['"]?/i);
|
||||
if (filenameMatch && filenameMatch[1]) {
|
||||
const filenameStar = contentDisposition.match(/filename\*\s*=\s*UTF-8''([^;\r\n]*)/i);
|
||||
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
|
||||
// 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-Disposition: ${contentDisposition}, fileName: ${fileName}`);
|
||||
@@ -129353,7 +129275,15 @@ var Inputs;
|
||||
Inputs["MergeMultiple"] = "merge-multiple";
|
||||
Inputs["ArtifactIds"] = "artifact-ids";
|
||||
Inputs["SkipDecompress"] = "skip-decompress";
|
||||
Inputs["DigestMismatch"] = "digest-mismatch";
|
||||
})(Inputs || (Inputs = {}));
|
||||
var DigestMismatchBehavior;
|
||||
(function (DigestMismatchBehavior) {
|
||||
DigestMismatchBehavior["Ignore"] = "ignore";
|
||||
DigestMismatchBehavior["Info"] = "info";
|
||||
DigestMismatchBehavior["Warn"] = "warn";
|
||||
DigestMismatchBehavior["Error"] = "error";
|
||||
})(DigestMismatchBehavior || (DigestMismatchBehavior = {}));
|
||||
var Outputs;
|
||||
(function (Outputs) {
|
||||
Outputs["DownloadPath"] = "download-path";
|
||||
@@ -129386,8 +129316,15 @@ async function run() {
|
||||
artifactIds: getInput(Inputs.ArtifactIds, { required: false }),
|
||||
skipDecompress: getBooleanInput(Inputs.SkipDecompress, {
|
||||
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) {
|
||||
inputs.path = process.env['GITHUB_WORKSPACE'] || process.cwd();
|
||||
}
|
||||
@@ -129500,6 +129437,7 @@ async function run() {
|
||||
})
|
||||
}));
|
||||
const chunkedPromises = chunk(downloadPromises, PARALLEL_DOWNLOADS);
|
||||
const digestMismatches = [];
|
||||
for (const chunk of chunkedPromises) {
|
||||
const chunkPromises = chunk.map(item => item.promise);
|
||||
const results = await Promise.all(chunkPromises);
|
||||
@@ -129507,10 +129445,31 @@ async function run() {
|
||||
const outcome = results[i];
|
||||
const artifactName = chunk[i].name;
|
||||
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`);
|
||||
setOutput(Outputs.DownloadPath, resolvedPath);
|
||||
info('Download artifact has finished successfully');
|
||||
|
||||
Generated
+6
-6
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "download-artifact",
|
||||
"version": "7.0.0",
|
||||
"version": "8.0.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "download-artifact",
|
||||
"version": "7.0.0",
|
||||
"version": "8.0.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/artifact": "^6.1.0",
|
||||
"@actions/artifact": "^6.2.1",
|
||||
"@actions/core": "^3.0.0",
|
||||
"minimatch": "^10.1.1"
|
||||
},
|
||||
@@ -36,9 +36,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/artifact": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-6.1.0.tgz",
|
||||
"integrity": "sha512-oRn9YhKkboXgIq2TQZ9uj6bhkT5ZUzFtnyTQ0tLGBwImaD0GfWShE5R0tPbN25EJmS3tz5sDd2JnVokAOtNrZQ==",
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/artifact/-/artifact-6.2.1.tgz",
|
||||
"integrity": "sha512-sJGH0mhEbEjBCw7o6SaLhUU66u27aFW8HTfkIb5Tk2/Wy0caUDc+oYQEgnuFN7a0HCpAbQyK0U6U7XUJDgDWrw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/core": "^3.0.0",
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "download-artifact",
|
||||
"version": "7.0.0",
|
||||
"version": "8.0.1",
|
||||
"description": "Download an Actions Artifact from a workflow run",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
@@ -33,7 +33,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/actions/download-artifact#readme",
|
||||
"dependencies": {
|
||||
"@actions/artifact": "^6.1.0",
|
||||
"@actions/artifact": "^6.2.1",
|
||||
"@actions/core": "^3.0.0",
|
||||
"minimatch": "^10.1.1"
|
||||
},
|
||||
|
||||
+9
-1
@@ -7,7 +7,15 @@ export enum Inputs {
|
||||
Pattern = 'pattern',
|
||||
MergeMultiple = 'merge-multiple',
|
||||
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 {
|
||||
|
||||
@@ -4,7 +4,7 @@ import * as core from '@actions/core'
|
||||
import artifactClient from '@actions/artifact'
|
||||
import type {Artifact, FindOptions} from '@actions/artifact'
|
||||
import {Minimatch} from 'minimatch'
|
||||
import {Inputs, Outputs} from './constants.js'
|
||||
import {Inputs, Outputs, DigestMismatchBehavior} from './constants.js'
|
||||
|
||||
const PARALLEL_DOWNLOADS = 5
|
||||
|
||||
@@ -29,7 +29,17 @@ export async function run(): Promise<void> {
|
||||
artifactIds: core.getInput(Inputs.ArtifactIds, {required: false}),
|
||||
skipDecompress: core.getBooleanInput(Inputs.SkipDecompress, {
|
||||
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) {
|
||||
@@ -188,6 +198,8 @@ export async function run(): Promise<void> {
|
||||
}))
|
||||
|
||||
const chunkedPromises = chunk(downloadPromises, PARALLEL_DOWNLOADS)
|
||||
const digestMismatches: string[] = []
|
||||
|
||||
for (const chunk of chunkedPromises) {
|
||||
const chunkPromises = chunk.map(item => item.promise)
|
||||
const results = await Promise.all(chunkPromises)
|
||||
@@ -197,12 +209,38 @@ export async function run(): Promise<void> {
|
||||
const artifactName = chunk[i].name
|
||||
|
||||
if (outcome.digestMismatch) {
|
||||
core.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:
|
||||
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.setOutput(Outputs.DownloadPath, resolvedPath)
|
||||
core.info('Download artifact has finished successfully')
|
||||
|
||||
Reference in New Issue
Block a user