5793b08cd9
* `@actions/artifact`: convert to an ESM module * Update the package-lock.json * Undo the GHES ignores * Fix the reference to `@actions/http-client` in the lock file * Bump `@actions/core` to `3.0.0` * Remove `jest.config.cjs` * Import `OctoKitOptions` from `@octokit/core/types` * Pull the package version from `package.json` * Workaround getting the package version for the user-agent * Fix the `archiver` import * Fix linting
188 lines
5.4 KiB
TypeScript
188 lines
5.4 KiB
TypeScript
import {info, warning, debug} from '@actions/core'
|
|
import {getOctokit} from '@actions/github'
|
|
import {ListArtifactsResponse, Artifact} from '../shared/interfaces.js'
|
|
import {getUserAgentString} from '../shared/user-agent.js'
|
|
import {getRetryOptions} from './retry-options.js'
|
|
import {defaults as defaultGitHubOptions} from '@actions/github/lib/utils'
|
|
import {requestLog} from '@octokit/plugin-request-log'
|
|
import {retry} from '@octokit/plugin-retry'
|
|
import type {OctokitOptions} from '@octokit/core/types'
|
|
import {internalArtifactTwirpClient} from '../shared/artifact-twirp-client.js'
|
|
import {getBackendIdsFromToken} from '../shared/util.js'
|
|
import {getMaxArtifactListCount} from '../shared/config.js'
|
|
import {ListArtifactsRequest, Timestamp} from '../../generated/index.js'
|
|
|
|
const maximumArtifactCount = getMaxArtifactListCount()
|
|
const paginationCount = 100
|
|
const maxNumberOfPages = Math.ceil(maximumArtifactCount / paginationCount)
|
|
|
|
export async function listArtifactsPublic(
|
|
workflowRunId: number,
|
|
repositoryOwner: string,
|
|
repositoryName: string,
|
|
token: string,
|
|
latest = false
|
|
): Promise<ListArtifactsResponse> {
|
|
info(
|
|
`Fetching artifact list for workflow run ${workflowRunId} in repository ${repositoryOwner}/${repositoryName}`
|
|
)
|
|
|
|
let artifacts: Artifact[] = []
|
|
const [retryOpts, requestOpts] = getRetryOptions(defaultGitHubOptions)
|
|
|
|
const opts: OctokitOptions = {
|
|
log: undefined,
|
|
userAgent: getUserAgentString(),
|
|
previews: undefined,
|
|
retry: retryOpts,
|
|
request: requestOpts
|
|
}
|
|
|
|
const github = getOctokit(token, opts, retry, requestLog)
|
|
|
|
let currentPageNumber = 1
|
|
|
|
const {data: listArtifactResponse} = await github.request(
|
|
'GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts',
|
|
{
|
|
owner: repositoryOwner,
|
|
repo: repositoryName,
|
|
run_id: workflowRunId,
|
|
per_page: paginationCount,
|
|
page: currentPageNumber
|
|
}
|
|
)
|
|
|
|
let numberOfPages = Math.ceil(
|
|
listArtifactResponse.total_count / paginationCount
|
|
)
|
|
const totalArtifactCount = listArtifactResponse.total_count
|
|
if (totalArtifactCount > maximumArtifactCount) {
|
|
warning(
|
|
`Workflow run ${workflowRunId} has ${totalArtifactCount} artifacts, exceeding the limit of ${maximumArtifactCount}. Results will be incomplete as only the first ${maximumArtifactCount} artifacts will be returned`
|
|
)
|
|
numberOfPages = maxNumberOfPages
|
|
}
|
|
|
|
// Iterate over the first page
|
|
for (const artifact of listArtifactResponse.artifacts) {
|
|
artifacts.push({
|
|
name: artifact.name,
|
|
id: artifact.id,
|
|
size: artifact.size_in_bytes,
|
|
createdAt: artifact.created_at
|
|
? new Date(artifact.created_at)
|
|
: undefined,
|
|
digest: (artifact as ArtifactResponse).digest
|
|
})
|
|
}
|
|
// Move to the next page
|
|
currentPageNumber++
|
|
// Iterate over any remaining pages
|
|
for (
|
|
currentPageNumber;
|
|
currentPageNumber <= numberOfPages;
|
|
currentPageNumber++
|
|
) {
|
|
debug(`Fetching page ${currentPageNumber} of artifact list`)
|
|
|
|
const {data: listArtifactResponse} = await github.request(
|
|
'GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts',
|
|
{
|
|
owner: repositoryOwner,
|
|
repo: repositoryName,
|
|
run_id: workflowRunId,
|
|
per_page: paginationCount,
|
|
page: currentPageNumber
|
|
}
|
|
)
|
|
|
|
for (const artifact of listArtifactResponse.artifacts) {
|
|
artifacts.push({
|
|
name: artifact.name,
|
|
id: artifact.id,
|
|
size: artifact.size_in_bytes,
|
|
createdAt: artifact.created_at
|
|
? new Date(artifact.created_at)
|
|
: undefined,
|
|
digest: (artifact as ArtifactResponse).digest
|
|
})
|
|
}
|
|
}
|
|
|
|
if (latest) {
|
|
artifacts = filterLatest(artifacts)
|
|
}
|
|
|
|
info(`Found ${artifacts.length} artifact(s)`)
|
|
|
|
return {
|
|
artifacts
|
|
}
|
|
}
|
|
|
|
export async function listArtifactsInternal(
|
|
latest = false
|
|
): Promise<ListArtifactsResponse> {
|
|
const artifactClient = internalArtifactTwirpClient()
|
|
|
|
const {workflowRunBackendId, workflowJobRunBackendId} =
|
|
getBackendIdsFromToken()
|
|
|
|
const req: ListArtifactsRequest = {
|
|
workflowRunBackendId,
|
|
workflowJobRunBackendId
|
|
}
|
|
|
|
const res = await artifactClient.ListArtifacts(req)
|
|
let artifacts: Artifact[] = res.artifacts.map(artifact => ({
|
|
name: artifact.name,
|
|
id: Number(artifact.databaseId),
|
|
size: Number(artifact.size),
|
|
createdAt: artifact.createdAt
|
|
? Timestamp.toDate(artifact.createdAt)
|
|
: undefined,
|
|
digest: artifact.digest?.value
|
|
}))
|
|
|
|
if (latest) {
|
|
artifacts = filterLatest(artifacts)
|
|
}
|
|
|
|
info(`Found ${artifacts.length} artifact(s)`)
|
|
|
|
return {
|
|
artifacts
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This exists so that we don't have to use 'any' when receiving the artifact list from the GitHub API.
|
|
* The digest field is not present in OpenAPI/types at time of writing, which necessitates this change.
|
|
*/
|
|
interface ArtifactResponse {
|
|
name: string
|
|
id: number
|
|
size_in_bytes: number
|
|
created_at?: string
|
|
digest?: string
|
|
}
|
|
|
|
/**
|
|
* Filters a list of artifacts to only include the latest artifact for each name
|
|
* @param artifacts The artifacts to filter
|
|
* @returns The filtered list of artifacts
|
|
*/
|
|
function filterLatest(artifacts: Artifact[]): Artifact[] {
|
|
artifacts.sort((a, b) => b.id - a.id)
|
|
const latestArtifacts: Artifact[] = []
|
|
const seenArtifactNames = new Set<string>()
|
|
for (const artifact of artifacts) {
|
|
if (!seenArtifactNames.has(artifact.name)) {
|
|
latestArtifacts.push(artifact)
|
|
seenArtifactNames.add(artifact.name)
|
|
}
|
|
}
|
|
return latestArtifacts
|
|
}
|