Merge pull request #460 from actions/danwkennedy/download-no-unzip

Don't attempt to un-zip non-zipped downloads
This commit is contained in:
Daniel Kennedy
2026-02-23 15:05:25 -05:00
committed by GitHub
58 changed files with 70713 additions and 70302 deletions
-3
View File
@@ -1,3 +0,0 @@
node_modules/
lib/
dist/
-15
View File
@@ -1,15 +0,0 @@
{
"env": { "node": true, "jest": true },
"parser": "@typescript-eslint/parser",
"parserOptions": { "ecmaVersion": 9, "sourceType": "module" },
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:import/errors",
"plugin:import/warnings",
"plugin:import/typescript",
"plugin:prettier/recommended"
],
"plugins": ["@typescript-eslint"]
}
+25 -2
View File
@@ -63,14 +63,14 @@ jobs:
path: path/to/artifact-B path: path/to/artifact-B
# Test downloading a single artifact # Test downloading a single artifact
- name: Download artifact A - name: Download artifact A (absolute path)
uses: ./ uses: ./
with: with:
name: Artifact-A-${{ matrix.runs-on }} name: Artifact-A-${{ matrix.runs-on }}
path: some/new/path path: some/new/path
# Test downloading an artifact using tilde expansion # Test downloading an artifact using tilde expansion
- name: Download artifact A - name: Download artifact A (tilde expansion)
uses: ./ uses: ./
with: with:
name: Artifact-A-${{ matrix.runs-on }} name: Artifact-A-${{ matrix.runs-on }}
@@ -131,3 +131,26 @@ jobs:
Write-Error "File contents of downloaded artifacts are incorrect" Write-Error "File contents of downloaded artifacts are incorrect"
} }
shell: pwsh shell: pwsh
# Test downloading artifact without decompressing (skip-decompress)
- name: Download artifact A without decompressing
uses: ./
with:
name: Artifact-A-${{ matrix.runs-on }}
path: skip-decompress-test
skip-decompress: true
- name: Verify skip-decompress download
run: |
$rawFile = "skip-decompress-test/Artifact-A-${{ matrix.runs-on }}.zip"
if(!(Test-Path -path $rawFile))
{
Write-Error "Expected raw artifact file does not exist at $rawFile"
}
$fileInfo = Get-Item $rawFile
if($fileInfo.Length -eq 0)
{
Write-Error "Downloaded artifact file is empty"
}
Write-Host "Successfully downloaded artifact without decompressing: $rawFile (size: $($fileInfo.Length) bytes)"
shell: pwsh
+2
View File
@@ -3,3 +3,5 @@ node_modules/
# Ignore js files that are transpiled from ts files in src/ # Ignore js files that are transpiled from ts files in src/
lib/ lib/
.DS_Store
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+14 -4
View File
@@ -23,6 +23,16 @@ 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.
- 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.
- Chore: we've bumped versions on a lot of our dev packages to get them up to date with the latest bugfixes/security patches.
## v7 - What's new ## v7 - What's new
> [!IMPORTANT] > [!IMPORTANT]
@@ -77,7 +87,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 +226,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 +268,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 +308,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
+156 -39
View File
@@ -1,10 +1,8 @@
import * as core from '@actions/core' import {jest, describe, test, expect, beforeEach} from '@jest/globals'
import * as path from 'path' import * as path from 'path'
import artifact, {ArtifactNotFoundError} from '@actions/artifact'
import {run} from '../src/download-artifact'
import {Inputs} from '../src/constants'
jest.mock('@actions/github', () => ({ // Mock @actions/github before importing modules that use it
jest.unstable_mockModule('@actions/github', () => ({
context: { context: {
repo: { repo: {
owner: 'actions', owner: 'actions',
@@ -12,14 +10,46 @@ jest.mock('@actions/github', () => ({
}, },
runId: 123, runId: 123,
serverUrl: 'https://github.com' serverUrl: 'https://github.com'
} },
getOctokit: jest.fn()
})) }))
jest.mock('@actions/core') // Mock @actions/core
jest.unstable_mockModule('@actions/core', () => ({
getInput: jest.fn(),
getBooleanInput: jest.fn(),
setOutput: jest.fn(),
setFailed: jest.fn(),
setSecret: jest.fn(),
info: jest.fn(),
warning: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
notice: jest.fn(),
startGroup: jest.fn(),
endGroup: jest.fn(),
isDebug: jest.fn(() => false),
getState: jest.fn(),
saveState: jest.fn(),
exportVariable: jest.fn(),
addPath: jest.fn(),
group: jest.fn((name: string, fn: () => Promise<unknown>) => fn()),
toPlatformPath: jest.fn(p => p),
toWin32Path: jest.fn(p => p),
toPosixPath: jest.fn(p => p)
}))
/* eslint-disable no-unused-vars */ /* eslint-disable @typescript-eslint/no-explicit-any */ // Dynamic imports after mocking
const mockInputs = (overrides?: Partial<{[K in Inputs]?: any}>) => { const core = await import('@actions/core')
const inputs = { const artifact = await import('@actions/artifact')
const {run} = await import('../src/download-artifact.js')
const {Inputs} = await import('../src/constants.js')
const {ArtifactNotFoundError} = artifact
const mockInputs = (
overrides?: Partial<{[K in (typeof Inputs)[keyof typeof Inputs]]?: any}>
) => {
const inputs: Record<string, any> = {
[Inputs.Name]: 'artifact-name', [Inputs.Name]: 'artifact-name',
[Inputs.Path]: '/some/artifact/path', [Inputs.Path]: '/some/artifact/path',
[Inputs.GitHubToken]: 'warn', [Inputs.GitHubToken]: 'warn',
@@ -29,10 +59,14 @@ const mockInputs = (overrides?: Partial<{[K in Inputs]?: any}>) => {
...overrides ...overrides
} }
;(core.getInput as jest.Mock).mockImplementation((name: string) => { ;(core.getInput as jest.Mock<typeof core.getInput>).mockImplementation(
(name: string) => {
return inputs[name] return inputs[name]
}) }
;(core.getBooleanInput as jest.Mock).mockImplementation((name: string) => { )
;(
core.getBooleanInput as jest.Mock<typeof core.getBooleanInput>
).mockImplementation((name: string) => {
return inputs[name] return inputs[name]
}) })
@@ -46,13 +80,13 @@ describe('download', () => {
// Mock artifact client methods // Mock artifact client methods
jest jest
.spyOn(artifact, 'listArtifacts') .spyOn(artifact.default, 'listArtifacts')
.mockImplementation(() => Promise.resolve({artifacts: []})) .mockImplementation(() => Promise.resolve({artifacts: []}))
jest.spyOn(artifact, 'getArtifact').mockImplementation(name => { jest.spyOn(artifact.default, 'getArtifact').mockImplementation(name => {
throw new ArtifactNotFoundError(`Artifact '${name}' not found`) throw new ArtifactNotFoundError(`Artifact '${name}' not found`)
}) })
jest jest
.spyOn(artifact, 'downloadArtifact') .spyOn(artifact.default, 'downloadArtifact')
.mockImplementation(() => Promise.resolve({digestMismatch: false})) .mockImplementation(() => Promise.resolve({digestMismatch: false}))
}) })
@@ -65,12 +99,12 @@ describe('download', () => {
} }
jest jest
.spyOn(artifact, 'getArtifact') .spyOn(artifact.default, 'getArtifact')
.mockImplementation(() => Promise.resolve({artifact: mockArtifact})) .mockImplementation(() => Promise.resolve({artifact: mockArtifact}))
await run() await run()
expect(artifact.downloadArtifact).toHaveBeenCalledWith( expect(artifact.default.downloadArtifact).toHaveBeenCalledWith(
mockArtifact.id, mockArtifact.id,
expect.objectContaining({ expect.objectContaining({
expectedHash: mockArtifact.digest expectedHash: mockArtifact.digest
@@ -102,12 +136,12 @@ describe('download', () => {
// Set up artifact mock after clearing mocks // Set up artifact mock after clearing mocks
jest jest
.spyOn(artifact, 'listArtifacts') .spyOn(artifact.default, 'listArtifacts')
.mockImplementation(() => Promise.resolve({artifacts: mockArtifacts})) .mockImplementation(() => Promise.resolve({artifacts: mockArtifacts}))
// Reset downloadArtifact mock as well // Reset downloadArtifact mock as well
jest jest
.spyOn(artifact, 'downloadArtifact') .spyOn(artifact.default, 'downloadArtifact')
.mockImplementation(() => Promise.resolve({digestMismatch: false})) .mockImplementation(() => Promise.resolve({digestMismatch: false}))
await run() await run()
@@ -117,7 +151,7 @@ describe('download', () => {
) )
expect(core.info).toHaveBeenCalledWith('Total of 2 artifact(s) downloaded') expect(core.info).toHaveBeenCalledWith('Total of 2 artifact(s) downloaded')
expect(artifact.downloadArtifact).toHaveBeenCalledTimes(2) expect(artifact.default.downloadArtifact).toHaveBeenCalledTimes(2)
}) })
test('sets download path output even when no artifacts are found', async () => { test('sets download path output even when no artifacts are found', async () => {
@@ -144,7 +178,7 @@ describe('download', () => {
] ]
jest jest
.spyOn(artifact, 'listArtifacts') .spyOn(artifact.default, 'listArtifacts')
.mockImplementation(() => Promise.resolve({artifacts: mockArtifacts})) .mockImplementation(() => Promise.resolve({artifacts: mockArtifacts}))
mockInputs({ mockInputs({
@@ -154,8 +188,8 @@ describe('download', () => {
await run() await run()
expect(artifact.downloadArtifact).toHaveBeenCalledTimes(1) expect(artifact.default.downloadArtifact).toHaveBeenCalledTimes(1)
expect(artifact.downloadArtifact).toHaveBeenCalledWith( expect(artifact.default.downloadArtifact).toHaveBeenCalledWith(
123, 123,
expect.anything() expect.anything()
) )
@@ -172,12 +206,12 @@ describe('download', () => {
}) })
jest jest
.spyOn(artifact, 'listArtifacts') .spyOn(artifact.default, 'listArtifacts')
.mockImplementation(() => Promise.resolve({artifacts: []})) .mockImplementation(() => Promise.resolve({artifacts: []}))
await run() await run()
expect(artifact.listArtifacts).toHaveBeenCalledWith( expect(artifact.default.listArtifacts).toHaveBeenCalledWith(
expect.objectContaining({ expect.objectContaining({
findBy: { findBy: {
token, token,
@@ -209,11 +243,11 @@ describe('download', () => {
} }
jest jest
.spyOn(artifact, 'getArtifact') .spyOn(artifact.default, 'getArtifact')
.mockImplementation(() => Promise.resolve({artifact: mockArtifact})) .mockImplementation(() => Promise.resolve({artifact: mockArtifact}))
jest jest
.spyOn(artifact, 'downloadArtifact') .spyOn(artifact.default, 'downloadArtifact')
.mockImplementation(() => Promise.resolve({digestMismatch: true})) .mockImplementation(() => Promise.resolve({digestMismatch: true}))
await run() await run()
@@ -237,7 +271,7 @@ describe('download', () => {
[Inputs.ArtifactIds]: '456' [Inputs.ArtifactIds]: '456'
}) })
jest.spyOn(artifact, 'listArtifacts').mockImplementation(() => jest.spyOn(artifact.default, 'listArtifacts').mockImplementation(() =>
Promise.resolve({ Promise.resolve({
artifacts: [mockArtifact] artifacts: [mockArtifact]
}) })
@@ -247,8 +281,8 @@ describe('download', () => {
expect(core.info).toHaveBeenCalledWith('Downloading artifacts by ID') expect(core.info).toHaveBeenCalledWith('Downloading artifacts by ID')
expect(core.debug).toHaveBeenCalledWith('Parsed artifact IDs: ["456"]') expect(core.debug).toHaveBeenCalledWith('Parsed artifact IDs: ["456"]')
expect(artifact.downloadArtifact).toHaveBeenCalledTimes(1) expect(artifact.default.downloadArtifact).toHaveBeenCalledTimes(1)
expect(artifact.downloadArtifact).toHaveBeenCalledWith( expect(artifact.default.downloadArtifact).toHaveBeenCalledWith(
456, 456,
expect.objectContaining({ expect.objectContaining({
expectedHash: mockArtifact.digest expectedHash: mockArtifact.digest
@@ -270,7 +304,7 @@ describe('download', () => {
[Inputs.ArtifactIds]: '123, 456, 789' [Inputs.ArtifactIds]: '123, 456, 789'
}) })
jest.spyOn(artifact, 'listArtifacts').mockImplementation(() => jest.spyOn(artifact.default, 'listArtifacts').mockImplementation(() =>
Promise.resolve({ Promise.resolve({
artifacts: mockArtifacts artifacts: mockArtifacts
}) })
@@ -282,9 +316,9 @@ describe('download', () => {
expect(core.debug).toHaveBeenCalledWith( expect(core.debug).toHaveBeenCalledWith(
'Parsed artifact IDs: ["123","456","789"]' 'Parsed artifact IDs: ["123","456","789"]'
) )
expect(artifact.downloadArtifact).toHaveBeenCalledTimes(3) expect(artifact.default.downloadArtifact).toHaveBeenCalledTimes(3)
mockArtifacts.forEach(mockArtifact => { mockArtifacts.forEach(mockArtifact => {
expect(artifact.downloadArtifact).toHaveBeenCalledWith( expect(artifact.default.downloadArtifact).toHaveBeenCalledWith(
mockArtifact.id, mockArtifact.id,
expect.objectContaining({ expect.objectContaining({
expectedHash: mockArtifact.digest expectedHash: mockArtifact.digest
@@ -305,7 +339,7 @@ describe('download', () => {
[Inputs.ArtifactIds]: '123, 456, 789' [Inputs.ArtifactIds]: '123, 456, 789'
}) })
jest.spyOn(artifact, 'listArtifacts').mockImplementation(() => jest.spyOn(artifact.default, 'listArtifacts').mockImplementation(() =>
Promise.resolve({ Promise.resolve({
artifacts: mockArtifacts artifacts: mockArtifacts
}) })
@@ -317,7 +351,7 @@ describe('download', () => {
'Could not find the following artifact IDs: 456, 789' 'Could not find the following artifact IDs: 456, 789'
) )
expect(core.debug).toHaveBeenCalledWith('Found 1 artifacts by ID') expect(core.debug).toHaveBeenCalledWith('Found 1 artifacts by ID')
expect(artifact.downloadArtifact).toHaveBeenCalledTimes(1) expect(artifact.default.downloadArtifact).toHaveBeenCalledTimes(1)
}) })
test('throws error when no artifacts with requested IDs are found', async () => { test('throws error when no artifacts with requested IDs are found', async () => {
@@ -327,7 +361,7 @@ describe('download', () => {
[Inputs.ArtifactIds]: '123, 456' [Inputs.ArtifactIds]: '123, 456'
}) })
jest.spyOn(artifact, 'listArtifacts').mockImplementation(() => jest.spyOn(artifact.default, 'listArtifacts').mockImplementation(() =>
Promise.resolve({ Promise.resolve({
artifacts: [] artifacts: []
}) })
@@ -389,7 +423,7 @@ describe('download', () => {
[Inputs.Path]: testPath [Inputs.Path]: testPath
}) })
jest.spyOn(artifact, 'listArtifacts').mockImplementation(() => jest.spyOn(artifact.default, 'listArtifacts').mockImplementation(() =>
Promise.resolve({ Promise.resolve({
artifacts: [mockArtifact] artifacts: [mockArtifact]
}) })
@@ -398,7 +432,7 @@ describe('download', () => {
await run() await run()
// Verify it downloads directly to the specified path (not nested in artifact name subdirectory) // Verify it downloads directly to the specified path (not nested in artifact name subdirectory)
expect(artifact.downloadArtifact).toHaveBeenCalledWith( expect(artifact.default.downloadArtifact).toHaveBeenCalledWith(
456, 456,
expect.objectContaining({ expect.objectContaining({
path: path.resolve(testPath), // Should be the resolved path directly, not nested path: path.resolve(testPath), // Should be the resolved path directly, not nested
@@ -406,4 +440,87 @@ describe('download', () => {
}) })
) )
}) })
test('passes skipDecompress option when skip-decompress input is true', async () => {
const mockArtifact = {
id: 123,
name: 'artifact-name',
size: 1024,
digest: 'abc123'
}
mockInputs({
[Inputs.SkipDecompress]: true
})
jest
.spyOn(artifact.default, 'getArtifact')
.mockImplementation(() => Promise.resolve({artifact: mockArtifact}))
await run()
expect(artifact.default.downloadArtifact).toHaveBeenCalledWith(
mockArtifact.id,
expect.objectContaining({
skipDecompress: true,
expectedHash: mockArtifact.digest
})
)
})
test('does not pass skipDecompress when skip-decompress input is false', async () => {
const mockArtifact = {
id: 123,
name: 'artifact-name',
size: 1024,
digest: 'abc123'
}
mockInputs({
[Inputs.SkipDecompress]: false
})
jest
.spyOn(artifact.default, 'getArtifact')
.mockImplementation(() => Promise.resolve({artifact: mockArtifact}))
await run()
expect(artifact.default.downloadArtifact).toHaveBeenCalledWith(
mockArtifact.id,
expect.objectContaining({
skipDecompress: false,
expectedHash: mockArtifact.digest
})
)
})
test('passes skipDecompress for multiple artifact downloads', async () => {
mockInputs({
[Inputs.Name]: '',
[Inputs.Pattern]: '',
[Inputs.SkipDecompress]: true
})
const mockArtifacts = [
{id: 123, name: 'artifact1', size: 1024, digest: 'abc123'},
{id: 456, name: 'artifact2', size: 2048, digest: 'def456'}
]
jest
.spyOn(artifact.default, 'listArtifacts')
.mockImplementation(() => Promise.resolve({artifacts: mockArtifacts}))
await run()
expect(artifact.default.downloadArtifact).toHaveBeenCalledTimes(2)
expect(artifact.default.downloadArtifact).toHaveBeenCalledWith(
123,
expect.objectContaining({skipDecompress: true})
)
expect(artifact.default.downloadArtifact).toHaveBeenCalledWith(
456,
expect.objectContaining({skipDecompress: true})
)
})
}) })
+5
View File
@@ -35,6 +35,11 @@ inputs:
If github-token is specified, this is the run that artifacts will be downloaded from.' If github-token is specified, this is the run that artifacts will be downloaded from.'
required: false required: false
default: ${{ github.run_id }} default: ${{ github.run_id }}
skip-decompress:
description: 'If true, the downloaded artifact will not be automatically extracted/decompressed.
This is useful when you want to handle the artifact as-is without extraction.'
required: false
default: 'false'
outputs: outputs:
download-path: download-path:
description: 'Path of artifact download' description: 'Path of artifact download'
+68353 -66001
View File
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
{
"type": "module"
}
+58
View File
@@ -0,0 +1,58 @@
import github from 'eslint-plugin-github'
import jest from 'eslint-plugin-jest'
import prettier from 'eslint-plugin-prettier/recommended'
const githubConfigs = github.getFlatConfigs()
export default [
{
ignores: ['**/node_modules/**', '**/lib/**', '**/dist/**']
},
githubConfigs.recommended,
...githubConfigs.typescript,
prettier,
{
files: ['**/*.ts'],
languageOptions: {
parserOptions: {
project: './tsconfig.eslint.json'
}
},
rules: {
// Prettier
'prettier/prettier': ['error', {endOfLine: 'auto'}],
// Disable rules that conflict with project style
'eslint-comments/no-use': 'off',
'github/no-then': 'off',
'github/filenames-match-regex': 'off',
'github/array-foreach': 'off',
'import/no-namespace': 'off',
'import/no-commonjs': 'off',
'import/named': 'off',
'import/no-unresolved': 'off',
'i18n-text/no-en': 'off',
'filenames/match-regex': 'off',
'no-shadow': 'off',
'no-unused-vars': 'off',
'no-undef': 'off',
camelcase: 'off',
// TypeScript rules
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-shadow': 'off',
'@typescript-eslint/array-type': 'off',
'@typescript-eslint/no-require-imports': 'off'
}
},
{
files: ['**/__tests__/**/*.ts'],
...jest.configs['flat/recommended'],
rules: {
...jest.configs['flat/recommended'].rules,
'jest/expect-expect': 'off',
'jest/no-conditional-expect': 'off'
}
}
]
+15 -3
View File
@@ -1,12 +1,24 @@
module.exports = { export default {
clearMocks: true, clearMocks: true,
moduleFileExtensions: ['js', 'ts'], moduleFileExtensions: ['js', 'ts'],
roots: ['<rootDir>'], roots: ['<rootDir>'],
testEnvironment: 'node', testEnvironment: 'node',
testMatch: ['**/*.test.ts'], testMatch: ['**/*.test.ts'],
testRunner: 'jest-circus/runner',
transform: { transform: {
'^.+\\.ts$': 'ts-jest' '^.+\\.ts$': [
'ts-jest',
{
useESM: true,
diagnostics: {
ignoreCodes: [151002]
}
}
]
},
extensionsToTreatAsEsm: ['.ts'],
transformIgnorePatterns: ['node_modules/(?!(@actions)/)'],
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1'
}, },
verbose: true verbose: true
} }
+1846 -4015
View File
File diff suppressed because it is too large Load Diff
+19 -16
View File
@@ -1,7 +1,8 @@
{ {
"name": "download-artifact", "name": "download-artifact",
"version": "7.0.0", "version": "8.0.0",
"description": "Download an Actions Artifact from a workflow run", "description": "Download an Actions Artifact from a workflow run",
"type": "module",
"engines": { "engines": {
"node": ">=24" "node": ">=24"
}, },
@@ -13,7 +14,7 @@
"format": "prettier --write **/*.ts", "format": "prettier --write **/*.ts",
"format-check": "prettier --check **/*.ts", "format-check": "prettier --check **/*.ts",
"lint": "eslint **/*.ts", "lint": "eslint **/*.ts",
"test": "jest" "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -32,22 +33,24 @@
}, },
"homepage": "https://github.com/actions/download-artifact#readme", "homepage": "https://github.com/actions/download-artifact#readme",
"dependencies": { "dependencies": {
"@actions/artifact": "^5.0.0", "@actions/artifact": "^6.1.0",
"@actions/core": "^2.0.0", "@actions/core": "^3.0.0",
"@actions/github": "^6.0.1", "minimatch": "^10.1.1"
"minimatch": "^9.0.3"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^29.5.14", "@actions/github": "^9.0.0",
"@types/node": "^24.1.0", "@types/jest": "^30.0.0",
"@typescript-eslint/eslint-plugin": "^6.14.0", "@types/node": "^25.1.0",
"@vercel/ncc": "^0.33.4", "@typescript-eslint/eslint-plugin": "^8.54.0",
"concurrently": "^5.2.0", "@typescript-eslint/parser": "^8.54.0",
"eslint": "^8.55.0", "@vercel/ncc": "^0.38.4",
"eslint-plugin-github": "^4.10.1", "concurrently": "^9.2.1",
"eslint-plugin-prettier": "^5.0.1", "eslint": "^9.39.2",
"jest": "^29.7.0", "eslint-plugin-github": "^6.0.0",
"prettier": "^3.1.1", "eslint-plugin-jest": "^29.12.1",
"eslint-plugin-prettier": "^5.5.5",
"jest": "^30.2.0",
"prettier": "^3.8.1",
"ts-jest": "^29.2.6", "ts-jest": "^29.2.6",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5.3.3" "typescript": "^5.3.3"
+2 -1
View File
@@ -6,7 +6,8 @@ export enum Inputs {
RunID = 'run-id', RunID = 'run-id',
Pattern = 'pattern', Pattern = 'pattern',
MergeMultiple = 'merge-multiple', MergeMultiple = 'merge-multiple',
ArtifactIds = 'artifact-ids' ArtifactIds = 'artifact-ids',
SkipDecompress = 'skip-decompress'
} }
export enum Outputs { export enum Outputs {
+7 -3
View File
@@ -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' import {Inputs, Outputs} from './constants.js'
const PARALLEL_DOWNLOADS = 5 const PARALLEL_DOWNLOADS = 5
@@ -26,7 +26,10 @@ export async function run(): Promise<void> {
mergeMultiple: core.getBooleanInput(Inputs.MergeMultiple, { mergeMultiple: core.getBooleanInput(Inputs.MergeMultiple, {
required: false required: false
}), }),
artifactIds: core.getInput(Inputs.ArtifactIds, {required: false}) artifactIds: core.getInput(Inputs.ArtifactIds, {required: false}),
skipDecompress: core.getBooleanInput(Inputs.SkipDecompress, {
required: false
})
} }
if (!inputs.path) { if (!inputs.path) {
@@ -179,7 +182,8 @@ export async function run(): Promise<void> {
artifacts.length === 1 artifacts.length === 1
? resolvedPath ? resolvedPath
: path.join(resolvedPath, artifact.name), : path.join(resolvedPath, artifact.name),
expectedHash: artifact.digest expectedHash: artifact.digest,
skipDecompress: inputs.skipDecompress
}) })
})) }))
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"rootDir": "."
},
"include": ["src/**/*.ts", "__tests__/**/*.ts", "*.ts"],
"exclude": ["node_modules", "lib", "dist"]
}
+3 -3
View File
@@ -1,12 +1,12 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es6", "target": "ES2022",
"module": "commonjs", "module": "NodeNext",
"outDir": "./lib", "outDir": "./lib",
"rootDir": "./src", "rootDir": "./src",
"strict": true, "strict": true,
"noImplicitAny": false, "noImplicitAny": false,
"moduleResolution": "node", "moduleResolution": "NodeNext",
"esModuleInterop": true "esModuleInterop": true
}, },
"exclude": ["node_modules", "**/*.test.ts", "jest.config.ts", "__tests__"] "exclude": ["node_modules", "**/*.test.ts", "jest.config.ts", "__tests__"]