mirror of
https://github.com/actions/download-artifact.git
synced 2026-03-19 03:40:49 +01:00
Compare commits
2 Commits
v4-beta-in
...
v3/v3.1.0-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad191675b4 | ||
|
|
1163061bb1 |
20
action.yml
20
action.yml
@@ -1,31 +1,13 @@
|
|||||||
name: 'Download a Build Artifact'
|
name: 'Download a Build Artifact'
|
||||||
description: 'Download a build artifact that was previously uploaded in the workflow by the upload-artifact action'
|
description: 'Download a build artifact that was previously uploaded in the workflow by the upload-artifact action'
|
||||||
author: 'GitHub'
|
author: 'GitHub'
|
||||||
inputs:
|
inputs:
|
||||||
name:
|
name:
|
||||||
description: 'Artifact name'
|
description: 'Artifact name'
|
||||||
required: false
|
required: false
|
||||||
path:
|
path:
|
||||||
description: 'Destination path'
|
description: 'Destination path'
|
||||||
required: false
|
required: false
|
||||||
github-token:
|
|
||||||
description: 'The GitHub token used to authenticate with the GitHub API.
|
|
||||||
This is required when downloading artifacts from a different repository or from a different workflow run.
|
|
||||||
If this is not specified, the action will attempt to download artifacts from the current repository and the current workflow run.'
|
|
||||||
required: false
|
|
||||||
repository:
|
|
||||||
description: 'The repository owner and the repository name joined together by "/".
|
|
||||||
If github-token is specified, this is the repository that artifacts will be downloaded from.'
|
|
||||||
required: false
|
|
||||||
default: ${{ github.repository }}
|
|
||||||
run-id:
|
|
||||||
description: 'The id of the workflow run where the desired download artifact was uploaded from.
|
|
||||||
If github-token is specified, this is the run that artifacts will be downloaded from.'
|
|
||||||
required: false
|
|
||||||
default: ${{ github.run_id }}
|
|
||||||
outputs:
|
|
||||||
download-path:
|
|
||||||
description: 'Path of artifact download'
|
|
||||||
runs:
|
runs:
|
||||||
using: 'node20'
|
using: 'node20'
|
||||||
main: 'dist/index.js'
|
main: 'dist/index.js'
|
||||||
|
|||||||
120191
dist/index.js
vendored
120191
dist/index.js
vendored
File diff suppressed because one or more lines are too long
1592
package-lock.json
generated
1592
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "download-artifact",
|
"name": "download-artifact",
|
||||||
"version": "3.0.0",
|
"version": "3.1.0",
|
||||||
"description": "Download a build artifact that was previously uploaded in the workflow by the upload-artifact action",
|
"description": "Download a build artifact that was previously uploaded in the workflow by the upload-artifact action",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -28,9 +28,8 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/actions/download-artifact#readme",
|
"homepage": "https://github.com/actions/download-artifact#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/artifact": "^2.0.0",
|
"@actions/artifact": "^1.1.3",
|
||||||
"@actions/core": "^1.10.0",
|
"@actions/core": "^1.10.0"
|
||||||
"@actions/github": "^5.1.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^12.12.6",
|
"@types/node": "^12.12.6",
|
||||||
@@ -42,4 +41,4 @@
|
|||||||
"prettier": "^2.0.5",
|
"prettier": "^2.0.5",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,7 @@
|
|||||||
export enum Inputs {
|
export enum Inputs {
|
||||||
Name = 'name',
|
Name = 'name',
|
||||||
Path = 'path',
|
Path = 'path'
|
||||||
GitHubToken = 'github-token',
|
|
||||||
Repository = 'repository',
|
|
||||||
RunID = 'run-id'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Outputs {
|
export enum Outputs {
|
||||||
DownloadPath = 'download-path'
|
DownloadPath = 'download-path'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,103 +1,61 @@
|
|||||||
import * as os from 'os'
|
|
||||||
import * as path from 'path'
|
|
||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import * as artifact from '@actions/artifact'
|
import * as artifact from '@actions/artifact'
|
||||||
|
import * as os from 'os'
|
||||||
|
import {resolve} from 'path'
|
||||||
import {Inputs, Outputs} from './constants'
|
import {Inputs, Outputs} from './constants'
|
||||||
|
|
||||||
const PARALLEL_DOWNLOADS = 5
|
|
||||||
|
|
||||||
export const chunk = <T>(arr: T[], n: number): T[][] =>
|
|
||||||
arr.reduce((acc, cur, i) => {
|
|
||||||
const index = Math.floor(i / n)
|
|
||||||
acc[index] = [...(acc[index] || []), cur]
|
|
||||||
return acc
|
|
||||||
}, [] as T[][])
|
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
const inputs = {
|
try {
|
||||||
name: core.getInput(Inputs.Name, {required: false}),
|
const name = core.getInput(Inputs.Name, {required: false})
|
||||||
path: core.getInput(Inputs.Path, {required: false}),
|
const path = core.getInput(Inputs.Path, {required: false})
|
||||||
token: core.getInput(Inputs.GitHubToken, {required: false}),
|
|
||||||
repository: core.getInput(Inputs.Repository, {required: false}),
|
|
||||||
runID: parseInt(core.getInput(Inputs.RunID, {required: false}))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!inputs.path) {
|
let resolvedPath
|
||||||
inputs.path = process.env['GITHUB_WORKSPACE'] || process.cwd()
|
// resolve tilde expansions, path.replace only replaces the first occurrence of a pattern
|
||||||
}
|
if (path.startsWith(`~`)) {
|
||||||
|
resolvedPath = resolve(path.replace('~', os.homedir()))
|
||||||
|
} else {
|
||||||
|
resolvedPath = resolve(path)
|
||||||
|
}
|
||||||
|
core.debug(`Resolved path is ${resolvedPath}`)
|
||||||
|
|
||||||
if (inputs.path.startsWith(`~`)) {
|
const artifactClient = artifact.create()
|
||||||
inputs.path = inputs.path.replace('~', os.homedir())
|
if (!name) {
|
||||||
}
|
// download all artifacts
|
||||||
|
core.info('No artifact name specified, downloading all artifacts')
|
||||||
const resolvedPath = path.resolve(inputs.path)
|
core.info(
|
||||||
core.debug(`Resolved path is ${resolvedPath}`)
|
'Creating an extra directory for each artifact that is being downloaded'
|
||||||
|
)
|
||||||
const options: artifact.FindOptions = {}
|
const downloadResponse = await artifactClient.downloadAllArtifacts(
|
||||||
if (inputs.token) {
|
resolvedPath
|
||||||
const [repositoryOwner, repositoryName] = inputs.repository.split('/')
|
)
|
||||||
if (!repositoryOwner || !repositoryName) {
|
core.info(`There were ${downloadResponse.length} artifacts downloaded`)
|
||||||
throw new Error(
|
for (const artifact of downloadResponse) {
|
||||||
`Invalid repository: '${inputs.repository}'. Must be in format owner/repo`
|
core.info(
|
||||||
|
`Artifact ${artifact.artifactName} was downloaded to ${artifact.downloadPath}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// download a single artifact
|
||||||
|
core.info(`Starting download for ${name}`)
|
||||||
|
const downloadOptions = {
|
||||||
|
createArtifactFolder: false
|
||||||
|
}
|
||||||
|
const downloadResponse = await artifactClient.downloadArtifact(
|
||||||
|
name,
|
||||||
|
resolvedPath,
|
||||||
|
downloadOptions
|
||||||
|
)
|
||||||
|
core.info(
|
||||||
|
`Artifact ${downloadResponse.artifactName} was downloaded to ${downloadResponse.downloadPath}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// output the directory that the artifact(s) was/were downloaded to
|
||||||
options.findBy = {
|
// if no path is provided, an empty string resolves to the current working directory
|
||||||
token: inputs.token,
|
core.setOutput(Outputs.DownloadPath, resolvedPath)
|
||||||
workflowRunId: inputs.runID,
|
core.info('Artifact download has finished successfully')
|
||||||
repositoryName,
|
} catch (err) {
|
||||||
repositoryOwner
|
core.setFailed(err.message)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const artifactClient = artifact.create()
|
|
||||||
let artifacts: artifact.Artifact[] = []
|
|
||||||
|
|
||||||
if (inputs.name) {
|
|
||||||
const {artifact: targetArtifact} = await artifactClient.getArtifact(
|
|
||||||
inputs.name,
|
|
||||||
options
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!targetArtifact) {
|
|
||||||
throw new Error(`Artifact '${inputs.name}' not found`)
|
|
||||||
}
|
|
||||||
|
|
||||||
core.debug('Found named artifact:')
|
|
||||||
core.debug(JSON.stringify(targetArtifact, null, 2))
|
|
||||||
|
|
||||||
artifacts = [targetArtifact]
|
|
||||||
} else {
|
|
||||||
const listArtifactResponse = await artifactClient.listArtifacts(options)
|
|
||||||
|
|
||||||
if (listArtifactResponse.artifacts.length === 0) {
|
|
||||||
throw new Error(
|
|
||||||
`No artifacts found for run '${inputs.runID}' in '${inputs.repository}'`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
core.debug(`Found ${listArtifactResponse.artifacts.length} artifacts:`)
|
|
||||||
core.debug(JSON.stringify(listArtifactResponse, null, 2))
|
|
||||||
artifacts = listArtifactResponse.artifacts
|
|
||||||
}
|
|
||||||
|
|
||||||
const downloadPromises = artifacts.map(artifact =>
|
|
||||||
artifactClient.downloadArtifact(artifact.id, {
|
|
||||||
...options,
|
|
||||||
path: path.join(resolvedPath, artifact.name)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
const chunkedPromises = chunk(downloadPromises, PARALLEL_DOWNLOADS)
|
|
||||||
for (const chunk of chunkedPromises) {
|
|
||||||
await Promise.all(chunk)
|
|
||||||
}
|
|
||||||
|
|
||||||
core.info(`Total of ${artifacts.length} artifact(s) downloaded`)
|
|
||||||
core.setOutput(Outputs.DownloadPath, resolvedPath)
|
|
||||||
core.info('Download artifact has finished successfully')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
run().catch(err =>
|
run()
|
||||||
core.setFailed(`Unable to download artifact(s): ${err.message}`)
|
|
||||||
)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user