2023-08-21 21:23:54 +00:00
|
|
|
import fs from 'fs/promises'
|
2023-08-21 21:47:17 +00:00
|
|
|
import * as github from '@actions/github'
|
|
|
|
import * as core from '@actions/core'
|
|
|
|
import * as httpClient from '@actions/http-client'
|
2023-08-21 21:23:54 +00:00
|
|
|
import unzipper from 'unzipper'
|
2023-08-17 18:40:33 +00:00
|
|
|
import {
|
|
|
|
DownloadArtifactOptions,
|
|
|
|
DownloadArtifactResponse
|
|
|
|
} from '../shared/interfaces'
|
2023-08-21 21:23:54 +00:00
|
|
|
import {getUserAgentString} from '../shared/user-agent'
|
2023-08-22 18:47:14 +00:00
|
|
|
import {getGitHubWorkspaceDir} from '../shared/config'
|
2023-08-21 21:23:54 +00:00
|
|
|
|
|
|
|
const scrubQueryParameters = (url: string): string => {
|
|
|
|
const parsed = new URL(url)
|
|
|
|
parsed.search = ''
|
|
|
|
return parsed.toString()
|
|
|
|
}
|
|
|
|
|
|
|
|
async function exists(path: string): Promise<boolean> {
|
|
|
|
try {
|
|
|
|
await fs.access(path)
|
|
|
|
return true
|
|
|
|
} catch (error) {
|
|
|
|
if (error.code === 'ENOENT') {
|
|
|
|
return false
|
|
|
|
} else {
|
|
|
|
throw error
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-22 16:17:43 +00:00
|
|
|
async function streamExtract(url: string, directory: string): Promise<void> {
|
2023-08-21 21:23:54 +00:00
|
|
|
const client = new httpClient.HttpClient(getUserAgentString())
|
|
|
|
const response = await client.get(url)
|
|
|
|
|
|
|
|
if (response.message.statusCode !== 200) {
|
|
|
|
throw new Error(
|
|
|
|
`Unexpected HTTP response from blob storage: ${response.message.statusCode} ${response.message.statusMessage}`
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-08-24 03:18:03 +00:00
|
|
|
return response.message.pipe(unzipper.Extract({path: directory})).promise()
|
2023-08-21 21:23:54 +00:00
|
|
|
}
|
2023-08-17 18:40:33 +00:00
|
|
|
|
|
|
|
export async function downloadArtifact(
|
|
|
|
artifactId: number,
|
|
|
|
repositoryOwner: string,
|
|
|
|
repositoryName: string,
|
|
|
|
token: string,
|
|
|
|
options?: DownloadArtifactOptions
|
|
|
|
): Promise<DownloadArtifactResponse> {
|
2023-08-23 14:28:17 +00:00
|
|
|
const downloadPath = options?.path || getGitHubWorkspaceDir()
|
2023-08-21 21:23:54 +00:00
|
|
|
|
|
|
|
if (!(await exists(downloadPath))) {
|
2023-08-22 16:57:14 +00:00
|
|
|
core.debug(
|
|
|
|
`Artifact destination folder does not exist, creating: ${downloadPath}`
|
|
|
|
)
|
2023-08-21 21:23:54 +00:00
|
|
|
await fs.mkdir(downloadPath, {recursive: true})
|
|
|
|
} else {
|
2023-08-21 21:47:17 +00:00
|
|
|
core.debug(`Artifact destination folder already exists: ${downloadPath}`)
|
2023-08-21 21:23:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const api = github.getOctokit(token)
|
|
|
|
|
|
|
|
core.info(
|
2023-08-21 21:47:17 +00:00
|
|
|
`Downloading artifact '${artifactId}' from '${repositoryOwner}/${repositoryName}'`
|
2023-08-21 21:23:54 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const {headers, status} = await api.rest.actions.downloadArtifact({
|
|
|
|
owner: repositoryOwner,
|
|
|
|
repo: repositoryName,
|
|
|
|
artifact_id: artifactId,
|
|
|
|
archive_format: 'zip',
|
|
|
|
request: {
|
|
|
|
redirect: 'manual'
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
if (status !== 302) {
|
|
|
|
throw new Error(`Unable to download artifact. Unexpected status: ${status}`)
|
|
|
|
}
|
|
|
|
|
|
|
|
const {location} = headers
|
|
|
|
if (!location) {
|
|
|
|
throw new Error(`Unable to redirect to artifact download url`)
|
|
|
|
}
|
|
|
|
|
|
|
|
core.info(
|
|
|
|
`Redirecting to blob download url: ${scrubQueryParameters(location)}`
|
|
|
|
)
|
|
|
|
|
|
|
|
try {
|
|
|
|
core.info(`Starting download of artifact to: ${downloadPath}`)
|
|
|
|
await streamExtract(location, downloadPath)
|
|
|
|
core.info(`Artifact download completed successfully.`)
|
|
|
|
} catch (error) {
|
|
|
|
throw new Error(`Unable to download and extract artifact: ${error.message}`)
|
|
|
|
}
|
|
|
|
|
2023-08-21 21:47:17 +00:00
|
|
|
return {success: true, downloadPath}
|
2023-08-17 18:40:33 +00:00
|
|
|
}
|