@ronaldphilipsen/local-action 0.0.0-stage → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.checkov.yml +3 -0
- package/.env.example +379 -0
- package/.github/codeql/codeql-config.yml +7 -0
- package/.github/copilot-instructions.md +79 -0
- package/.github/dependabot.yml +32 -0
- package/.github/workflows/codeql-analysis.yml +53 -0
- package/.github/workflows/continuous-delivery.yml +93 -0
- package/.github/workflows/continuous-integration.yml +382 -0
- package/.github/workflows/linter.yml +47 -0
- package/.github/workflows/release.yaml +99 -0
- package/.github/workflows/version-check.yml +44 -0
- package/.grype.yml +151 -0
- package/.markdown-lint.yml +7 -0
- package/.mega-linter.yml +188 -0
- package/.node-version +1 -0
- package/.prettierignore +4 -0
- package/.prettierrc.yml +14 -0
- package/.vscode/launch.json +15 -0
- package/.vscode/mcp.json +9 -0
- package/.vscode/settings.json +15 -0
- package/.vscode/tasks.json +51 -0
- package/.yaml-lint.yml +10 -0
- package/CHANGELOG.md +75 -0
- package/CODEOWNERS +3 -0
- package/CODE_OF_CONDUCT.md +74 -0
- package/CONTRIBUTING.md +140 -0
- package/LICENSE +21 -0
- package/README.md +285 -2
- package/SECURITY.md +42 -0
- package/SUPPORT.md +19 -0
- package/__fixtures__/@actions/core.ts +14 -0
- package/__fixtures__/@actions/exec.ts +9 -0
- package/__fixtures__/@actions/github.ts +3 -0
- package/__fixtures__/@actions/http-client.ts +9 -0
- package/__fixtures__/@actions/io.ts +9 -0
- package/__fixtures__/@octokit/rest.ts +18 -0
- package/__fixtures__/crypto.ts +7 -0
- package/__fixtures__/fs.ts +27 -0
- package/__fixtures__/javascript/no-export/.env.fixture +2 -0
- package/__fixtures__/javascript/no-export/action.yml +16 -0
- package/__fixtures__/javascript/no-export/node_modules/.gitkeep +0 -0
- package/__fixtures__/javascript/no-export/package.json +12 -0
- package/__fixtures__/javascript/no-export/src/index.js +0 -0
- package/__fixtures__/javascript/no-export/src/main.js +0 -0
- package/__fixtures__/javascript/no-import/.env.fixture +2 -0
- package/__fixtures__/javascript/no-import/action.yml +16 -0
- package/__fixtures__/javascript/no-import/node_modules/.gitkeep +0 -0
- package/__fixtures__/javascript/no-import/package.json +12 -0
- package/__fixtures__/javascript/no-import/src/index.js +3 -0
- package/__fixtures__/javascript/no-import/src/main.js +7 -0
- package/__fixtures__/javascript/success/.env.fixture +2 -0
- package/__fixtures__/javascript/success/action.yml +16 -0
- package/__fixtures__/javascript/success/node_modules/.gitkeep +0 -0
- package/__fixtures__/javascript/success/package.json +12 -0
- package/__fixtures__/javascript/success/post/index.js +3 -0
- package/__fixtures__/javascript/success/post/main.js +13 -0
- package/__fixtures__/javascript/success/pre/index.js +3 -0
- package/__fixtures__/javascript/success/pre/main.js +13 -0
- package/__fixtures__/javascript/success/src/index.js +3 -0
- package/__fixtures__/javascript/success/src/main.js +13 -0
- package/__fixtures__/javascript-esm/no-import/.env.fixture +2 -0
- package/__fixtures__/javascript-esm/no-import/action.yml +16 -0
- package/__fixtures__/javascript-esm/no-import/node_modules/.gitkeep +0 -0
- package/__fixtures__/javascript-esm/no-import/package.json +13 -0
- package/__fixtures__/javascript-esm/no-import/src/index.js +3 -0
- package/__fixtures__/javascript-esm/no-import/src/main.js +7 -0
- package/__fixtures__/javascript-esm/success/.env.fixture +2 -0
- package/__fixtures__/javascript-esm/success/action.yml +16 -0
- package/__fixtures__/javascript-esm/success/node_modules/.gitkeep +0 -0
- package/__fixtures__/javascript-esm/success/package.json +13 -0
- package/__fixtures__/javascript-esm/success/post/index.js +3 -0
- package/__fixtures__/javascript-esm/success/post/main.js +13 -0
- package/__fixtures__/javascript-esm/success/pre/index.js +3 -0
- package/__fixtures__/javascript-esm/success/pre/main.js +13 -0
- package/__fixtures__/javascript-esm/success/src/index.js +3 -0
- package/__fixtures__/javascript-esm/success/src/main.js +13 -0
- package/__fixtures__/path.ts +7 -0
- package/__fixtures__/payloads/issue_opened.json +33 -0
- package/__fixtures__/stream/promises.ts +3 -0
- package/__fixtures__/tsconfig-paths.ts +4 -0
- package/__fixtures__/typescript/no-import/.env.fixture +2 -0
- package/__fixtures__/typescript/no-import/action.yml +16 -0
- package/__fixtures__/typescript/no-import/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript/no-import/package.json +15 -0
- package/__fixtures__/typescript/no-import/src/index.ts +3 -0
- package/__fixtures__/typescript/no-import/src/main.ts +3 -0
- package/__fixtures__/typescript/no-import/tsconfig.json +20 -0
- package/__fixtures__/typescript/success/.env.fixture +2 -0
- package/__fixtures__/typescript/success/action.yml +16 -0
- package/__fixtures__/typescript/success/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript/success/package.json +15 -0
- package/__fixtures__/typescript/success/post/index.ts +3 -0
- package/__fixtures__/typescript/success/post/main.ts +9 -0
- package/__fixtures__/typescript/success/pre/index.ts +3 -0
- package/__fixtures__/typescript/success/pre/main.ts +9 -0
- package/__fixtures__/typescript/success/src/index.ts +3 -0
- package/__fixtures__/typescript/success/src/main.ts +9 -0
- package/__fixtures__/typescript/success/tsconfig.json +20 -0
- package/__fixtures__/typescript/success-yaml/.env.fixture +2 -0
- package/__fixtures__/typescript/success-yaml/action.yaml +16 -0
- package/__fixtures__/typescript/success-yaml/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript/success-yaml/package.json +15 -0
- package/__fixtures__/typescript/success-yaml/post/index.ts +3 -0
- package/__fixtures__/typescript/success-yaml/post/main.ts +9 -0
- package/__fixtures__/typescript/success-yaml/pre/index.ts +3 -0
- package/__fixtures__/typescript/success-yaml/pre/main.ts +9 -0
- package/__fixtures__/typescript/success-yaml/src/index.ts +3 -0
- package/__fixtures__/typescript/success-yaml/src/main.ts +9 -0
- package/__fixtures__/typescript/success-yaml/tsconfig.json +20 -0
- package/__fixtures__/typescript-esm/no-export/.env.fixture +2 -0
- package/__fixtures__/typescript-esm/no-export/action.yml +17 -0
- package/__fixtures__/typescript-esm/no-export/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript-esm/no-export/package.json +17 -0
- package/__fixtures__/typescript-esm/no-export/src/index.ts +0 -0
- package/__fixtures__/typescript-esm/no-export/src/main.ts +0 -0
- package/__fixtures__/typescript-esm/no-export/tsconfig.json +25 -0
- package/__fixtures__/typescript-esm/no-import/.env.fixture +2 -0
- package/__fixtures__/typescript-esm/no-import/action.yml +17 -0
- package/__fixtures__/typescript-esm/no-import/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript-esm/no-import/package.json +17 -0
- package/__fixtures__/typescript-esm/no-import/src/index.ts +3 -0
- package/__fixtures__/typescript-esm/no-import/src/main.ts +3 -0
- package/__fixtures__/typescript-esm/no-import/tsconfig.json +25 -0
- package/__fixtures__/typescript-esm/success/.env.fixture +2 -0
- package/__fixtures__/typescript-esm/success/action.yml +17 -0
- package/__fixtures__/typescript-esm/success/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript-esm/success/package.json +17 -0
- package/__fixtures__/typescript-esm/success/post/index.ts +3 -0
- package/__fixtures__/typescript-esm/success/post/main.ts +9 -0
- package/__fixtures__/typescript-esm/success/pre/index.ts +3 -0
- package/__fixtures__/typescript-esm/success/pre/main.ts +9 -0
- package/__fixtures__/typescript-esm/success/src/index.ts +3 -0
- package/__fixtures__/typescript-esm/success/src/main.ts +9 -0
- package/__fixtures__/typescript-esm/success/tsconfig.json +25 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/.env.fixture +2 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/action.yml +17 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/node_modules/.gitkeep +0 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/package.json +17 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/src/index.ts +3 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/src/main.ts +9 -0
- package/__fixtures__/typescript-esm/tsconfig-comments/tsconfig.json +21 -0
- package/__tests__/command.test.ts +224 -0
- package/__tests__/stubs/artifact/internal/client.test.ts +340 -0
- package/__tests__/stubs/artifact/internal/delete/delete-artifact.test.ts +152 -0
- package/__tests__/stubs/artifact/internal/download/download-artifact.test.ts +119 -0
- package/__tests__/stubs/artifact/internal/find/get-artifact.test.ts +237 -0
- package/__tests__/stubs/artifact/internal/find/list-artifacts.test.ts +218 -0
- package/__tests__/stubs/artifact/internal/find/retry-options.test.ts +54 -0
- package/__tests__/stubs/artifact/internal/shared/config.test.ts +91 -0
- package/__tests__/stubs/artifact/internal/shared/errors.test.ts +38 -0
- package/__tests__/stubs/artifact/internal/shared/user-agent.test.ts +22 -0
- package/__tests__/stubs/artifact/internal/upload/path-and-artifact-name-validation.test.ts +53 -0
- package/__tests__/stubs/artifact/internal/upload/upload-artifact.test.ts +126 -0
- package/__tests__/stubs/artifact/internal/upload/upload-zip-specification.test.ts +49 -0
- package/__tests__/stubs/cache/cache.test.ts +357 -0
- package/__tests__/stubs/cache/errors.test.ts +55 -0
- package/__tests__/stubs/cache/internal/cacheUtils.test.ts +109 -0
- package/__tests__/stubs/cache/internal/constants.test.ts +81 -0
- package/__tests__/stubs/cache/internal/tar.test.ts +129 -0
- package/__tests__/stubs/core/core.test.ts +760 -0
- package/__tests__/stubs/core/path-utils.test.ts +45 -0
- package/__tests__/stubs/core/platform.test.ts +89 -0
- package/__tests__/stubs/core/summary.test.ts +455 -0
- package/__tests__/stubs/env.test.ts +72 -0
- package/__tests__/stubs/github/context.test.ts +73 -0
- package/__tests__/stubs/github/github.test.ts +15 -0
- package/__tests__/stubs/github/internal/utils.test.ts +98 -0
- package/__tests__/stubs/github/utils.test.ts +16 -0
- package/__tests__/utils/config.test.ts +78 -0
- package/__tests__/utils/output.test.ts +32 -0
- package/__tests__/utils/package.test.ts +33 -0
- package/badges/coverage.svg +1 -0
- package/bin/local-action.js +121 -0
- package/docs/create-a-job-summary.md +32 -0
- package/docs/debugging-in-vscode.md +27 -0
- package/docs/img/job-summary.png +0 -0
- package/docs/supported-functionality.md +126 -0
- package/eslint.config.mjs +74 -0
- package/jest.config.ts +41 -0
- package/package.json +93 -4
- package/src/command.ts +171 -0
- package/src/commands/run.ts +616 -0
- package/src/index.ts +21 -0
- package/src/stubs/artifact/artifact.ts +17 -0
- package/src/stubs/artifact/internal/client.ts +400 -0
- package/src/stubs/artifact/internal/delete/delete-artifact.ts +126 -0
- package/src/stubs/artifact/internal/download/download-artifact.ts +309 -0
- package/src/stubs/artifact/internal/find/get-artifact.ts +135 -0
- package/src/stubs/artifact/internal/find/list-artifacts.ts +188 -0
- package/src/stubs/artifact/internal/find/retry-options.ts +57 -0
- package/src/stubs/artifact/internal/shared/config.ts +64 -0
- package/src/stubs/artifact/internal/shared/errors.ts +53 -0
- package/src/stubs/artifact/internal/shared/interfaces.ts +195 -0
- package/src/stubs/artifact/internal/shared/user-agent.ts +13 -0
- package/src/stubs/artifact/internal/upload/path-and-artifact-name-validation.ts +92 -0
- package/src/stubs/artifact/internal/upload/upload-artifact.ts +127 -0
- package/src/stubs/artifact/internal/upload/upload-zip-specification.ts +108 -0
- package/src/stubs/artifact/internal/upload/zip.ts +122 -0
- package/src/stubs/cache/cache.ts +334 -0
- package/src/stubs/cache/errors.ts +31 -0
- package/src/stubs/cache/interfaces.ts +4 -0
- package/src/stubs/cache/internal/cacheUtils.ts +207 -0
- package/src/stubs/cache/internal/constants.ts +45 -0
- package/src/stubs/cache/internal/tar.ts +374 -0
- package/src/stubs/cache/options.ts +91 -0
- package/src/stubs/core/core.ts +743 -0
- package/src/stubs/core/path-utils.ts +39 -0
- package/src/stubs/core/platform.ts +132 -0
- package/src/stubs/core/summary.ts +399 -0
- package/src/stubs/env.ts +40 -0
- package/src/stubs/github/context.ts +94 -0
- package/src/stubs/github/github.ts +29 -0
- package/src/stubs/github/interfaces.ts +52 -0
- package/src/stubs/github/internal/utils.ts +83 -0
- package/src/stubs/github/utils.ts +52 -0
- package/src/types/quibble.d.ts +5 -0
- package/src/types.ts +116 -0
- package/src/utils/config.ts +47 -0
- package/src/utils/output.ts +20 -0
- package/src/utils/package.ts +38 -0
- package/tsconfig.base.json +29 -0
- package/tsconfig.eslint.json +22 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Last Reviewed Commit: 9b08f07cd305c6060f08e4b64d1805429a773711
|
|
3
|
+
* Last Reviewed Date: 2026-01-16
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as httpClient from '@actions/http-client'
|
|
7
|
+
import * as crypto from 'crypto'
|
|
8
|
+
import fs from 'fs'
|
|
9
|
+
import path from 'path'
|
|
10
|
+
import * as stream from 'stream'
|
|
11
|
+
import { finished } from 'stream/promises'
|
|
12
|
+
import unzip from 'unzip-stream'
|
|
13
|
+
import { EnvMeta } from '../../../../stubs/env.js'
|
|
14
|
+
import * as core from '../../../core/core.js'
|
|
15
|
+
import { getOctokit } from '../../../github/github.js'
|
|
16
|
+
import { getGitHubWorkspaceDir } from '../shared/config.js'
|
|
17
|
+
import { ArtifactNotFoundError } from '../shared/errors.js'
|
|
18
|
+
import type {
|
|
19
|
+
Artifact,
|
|
20
|
+
DownloadArtifactOptions,
|
|
21
|
+
DownloadArtifactResponse
|
|
22
|
+
} from '../shared/interfaces.js'
|
|
23
|
+
import { StreamExtractResponse } from '../shared/interfaces.js'
|
|
24
|
+
import { getUserAgentString } from '../shared/user-agent.js'
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Removes query parameters from a URL.
|
|
28
|
+
*
|
|
29
|
+
* @remarks
|
|
30
|
+
*
|
|
31
|
+
* - Exporting the function to make it available for testing.
|
|
32
|
+
*
|
|
33
|
+
* @param url URL
|
|
34
|
+
* @returns URL without query parameters
|
|
35
|
+
*/
|
|
36
|
+
export const scrubQueryParameters = (url: string): string => {
|
|
37
|
+
const parsed = new URL(url)
|
|
38
|
+
parsed.search = ''
|
|
39
|
+
return parsed.toString()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Checks if a path exists
|
|
44
|
+
*
|
|
45
|
+
* @remarks
|
|
46
|
+
*
|
|
47
|
+
* - Exporting the function to make it available for testing.
|
|
48
|
+
* - Use `accessSync` instead of `access`.
|
|
49
|
+
*
|
|
50
|
+
* @param path Path
|
|
51
|
+
* @returns `true` if the path exists, `false` otherwise
|
|
52
|
+
*/
|
|
53
|
+
export function exists(path: string): boolean {
|
|
54
|
+
try {
|
|
55
|
+
fs.accessSync(path)
|
|
56
|
+
return true
|
|
57
|
+
} catch (error: any) {
|
|
58
|
+
if (error.code === 'ENOENT') return false
|
|
59
|
+
else throw error
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Extract the artifact from the given URL to the specified directory.
|
|
65
|
+
*
|
|
66
|
+
* @param url URL
|
|
67
|
+
* @param directory Directory
|
|
68
|
+
*/
|
|
69
|
+
/* istanbul ignore next */
|
|
70
|
+
async function streamExtract(
|
|
71
|
+
url: string,
|
|
72
|
+
directory: string
|
|
73
|
+
): Promise<StreamExtractResponse> {
|
|
74
|
+
let retryCount = 0
|
|
75
|
+
while (retryCount < 5) {
|
|
76
|
+
try {
|
|
77
|
+
return await streamExtractExternal(url, directory)
|
|
78
|
+
} catch (error: any) {
|
|
79
|
+
retryCount++
|
|
80
|
+
core.debug(
|
|
81
|
+
`Failed to download artifact after ${retryCount} retries due to ${error.message}. Retrying in 5 seconds...`
|
|
82
|
+
)
|
|
83
|
+
// wait 5 seconds before retrying
|
|
84
|
+
await new Promise(resolve => setTimeout(resolve, 5000))
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
throw new Error(`Artifact download failed after ${retryCount} retries.`)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Extract the artifact from the given URL to the specified directory.
|
|
93
|
+
*
|
|
94
|
+
* @remarks
|
|
95
|
+
*
|
|
96
|
+
* - Removed digest verification from the original implementation.
|
|
97
|
+
*
|
|
98
|
+
* @param url URL
|
|
99
|
+
* @param directory Directory
|
|
100
|
+
*/
|
|
101
|
+
/* istanbul ignore next */
|
|
102
|
+
export async function streamExtractExternal(
|
|
103
|
+
url: string,
|
|
104
|
+
directory: string,
|
|
105
|
+
opts: { timeout: number } = { timeout: 30 * 1000 }
|
|
106
|
+
): Promise<StreamExtractResponse> {
|
|
107
|
+
const client = new httpClient.HttpClient(getUserAgentString())
|
|
108
|
+
const response = await client.get(url)
|
|
109
|
+
if (response.message.statusCode !== 200)
|
|
110
|
+
throw new Error(
|
|
111
|
+
`Unexpected HTTP response from blob storage: ${response.message.statusCode} ${response.message.statusMessage}`
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
let sha256Digest: string | undefined = undefined
|
|
115
|
+
|
|
116
|
+
return new Promise((resolve, reject) => {
|
|
117
|
+
const timerFn = (): void => {
|
|
118
|
+
const timeoutError = new Error(
|
|
119
|
+
`Blob storage chunk did not respond in ${opts.timeout}ms`
|
|
120
|
+
)
|
|
121
|
+
response.message.destroy(timeoutError)
|
|
122
|
+
reject(timeoutError)
|
|
123
|
+
}
|
|
124
|
+
const timer = setTimeout(timerFn, opts.timeout)
|
|
125
|
+
|
|
126
|
+
const hashStream = crypto.createHash('sha256').setEncoding('hex')
|
|
127
|
+
const passThrough = new stream.PassThrough()
|
|
128
|
+
|
|
129
|
+
response.message.pipe(passThrough)
|
|
130
|
+
passThrough.pipe(hashStream)
|
|
131
|
+
const extractStream = passThrough
|
|
132
|
+
|
|
133
|
+
extractStream
|
|
134
|
+
.on('data', () => {
|
|
135
|
+
timer.refresh()
|
|
136
|
+
})
|
|
137
|
+
.on('error', (error: Error) => {
|
|
138
|
+
core.debug(
|
|
139
|
+
`response.message: Artifact download failed: ${error.message}`
|
|
140
|
+
)
|
|
141
|
+
clearTimeout(timer)
|
|
142
|
+
reject(error)
|
|
143
|
+
})
|
|
144
|
+
.pipe(unzip.Extract({ path: directory }))
|
|
145
|
+
.on('close', () => {
|
|
146
|
+
clearTimeout(timer)
|
|
147
|
+
if (hashStream) {
|
|
148
|
+
hashStream.end()
|
|
149
|
+
sha256Digest = hashStream.read() as string
|
|
150
|
+
core.info(`SHA256 digest of downloaded artifact is ${sha256Digest}`)
|
|
151
|
+
}
|
|
152
|
+
resolve({ sha256Digest: `sha256:${sha256Digest}` })
|
|
153
|
+
})
|
|
154
|
+
.on('error', (error: Error) => {
|
|
155
|
+
reject(error)
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Download an artifact from the given repository to the specified directory.
|
|
162
|
+
*
|
|
163
|
+
* @remarks
|
|
164
|
+
*
|
|
165
|
+
* - Removed digest verification from the original implementation.
|
|
166
|
+
*
|
|
167
|
+
* @param artifactId Artifact ID
|
|
168
|
+
* @param repositoryOwner Repository Owner
|
|
169
|
+
* @param repositoryName Repository Name
|
|
170
|
+
* @param token Token
|
|
171
|
+
* @param options Options
|
|
172
|
+
* @returns Download Artifact Response
|
|
173
|
+
*/
|
|
174
|
+
/* istanbul ignore next */
|
|
175
|
+
export async function downloadArtifactPublic(
|
|
176
|
+
artifactId: number,
|
|
177
|
+
repositoryOwner: string,
|
|
178
|
+
repositoryName: string,
|
|
179
|
+
token: string,
|
|
180
|
+
options?: DownloadArtifactOptions
|
|
181
|
+
): Promise<DownloadArtifactResponse> {
|
|
182
|
+
const downloadPath = await resolveOrCreateDirectory(options?.path)
|
|
183
|
+
|
|
184
|
+
const api = getOctokit(token)
|
|
185
|
+
|
|
186
|
+
let digestMismatch = false
|
|
187
|
+
|
|
188
|
+
core.info(
|
|
189
|
+
`Downloading artifact '${artifactId}' from '${repositoryOwner}/${repositoryName}'`
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
const { headers, status } = await api.rest.actions.downloadArtifact({
|
|
193
|
+
owner: repositoryOwner,
|
|
194
|
+
repo: repositoryName,
|
|
195
|
+
artifact_id: artifactId,
|
|
196
|
+
archive_format: 'zip',
|
|
197
|
+
request: {
|
|
198
|
+
redirect: 'manual'
|
|
199
|
+
}
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
if (status !== 302)
|
|
203
|
+
throw new Error(`Unable to download artifact. Unexpected status: ${status}`)
|
|
204
|
+
|
|
205
|
+
const { location } = headers
|
|
206
|
+
if (!location) throw new Error(`Unable to redirect to artifact download url`)
|
|
207
|
+
|
|
208
|
+
core.info(
|
|
209
|
+
`Redirecting to blob download url: ${scrubQueryParameters(location)}`
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
try {
|
|
213
|
+
core.info(`Starting download of artifact to: ${downloadPath}`)
|
|
214
|
+
const extractResponse = await streamExtract(location, downloadPath)
|
|
215
|
+
core.info(`Artifact download completed successfully.`)
|
|
216
|
+
if (options?.expectedHash)
|
|
217
|
+
if (options?.expectedHash !== extractResponse.sha256Digest) {
|
|
218
|
+
digestMismatch = true
|
|
219
|
+
core.debug(`Computed digest: ${extractResponse.sha256Digest}`)
|
|
220
|
+
core.debug(`Expected digest: ${options.expectedHash}`)
|
|
221
|
+
}
|
|
222
|
+
} catch (error: any) {
|
|
223
|
+
throw new Error(
|
|
224
|
+
`Unable to download and extract artifact: ${error.message}`,
|
|
225
|
+
{ cause: error }
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return { downloadPath, digestMismatch }
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Downloads an artifact from the current repository to the specified directory.
|
|
234
|
+
*
|
|
235
|
+
* @remarks
|
|
236
|
+
*
|
|
237
|
+
* - Removed digest verification from the original implementation.
|
|
238
|
+
* - Downloads from local filesystem instead of GitHub.
|
|
239
|
+
*
|
|
240
|
+
* @param artifactId Artifact ID
|
|
241
|
+
* @param options Options
|
|
242
|
+
* @returns Download Artifact Response
|
|
243
|
+
*/
|
|
244
|
+
export async function downloadArtifactInternal(
|
|
245
|
+
artifactId: number,
|
|
246
|
+
options?: DownloadArtifactOptions
|
|
247
|
+
): Promise<DownloadArtifactResponse> {
|
|
248
|
+
const downloadPath = await resolveOrCreateDirectory(options?.path)
|
|
249
|
+
|
|
250
|
+
// Check the current list of artifacts for one with a matching ID.
|
|
251
|
+
const artifacts: Artifact[] = EnvMeta.artifacts.filter(
|
|
252
|
+
(artifact: Artifact) => artifact.id === artifactId
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
if (artifacts.length === 0)
|
|
256
|
+
throw new ArtifactNotFoundError(
|
|
257
|
+
`No artifacts found for ID: ${artifactId}\nAre you trying to download from a different run? Try specifying a github-token with \`actions:read\` scope.`
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
if (artifacts.length > 1)
|
|
261
|
+
core.warning('Multiple artifacts found, defaulting to first.')
|
|
262
|
+
|
|
263
|
+
try {
|
|
264
|
+
core.info(`Starting download of artifact to: ${downloadPath}`)
|
|
265
|
+
|
|
266
|
+
// Extract the file to the specified directory. The archive will be
|
|
267
|
+
// available at `${LOCAL_ACTION_ARTIFACT_PATH}/${artifact.id}`.
|
|
268
|
+
const readStream = fs.createReadStream(
|
|
269
|
+
path.join(
|
|
270
|
+
process.env.LOCAL_ACTION_ARTIFACT_PATH!,
|
|
271
|
+
`${artifacts[0].name}.zip`
|
|
272
|
+
)
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
readStream.pipe(unzip.Extract({ path: downloadPath }))
|
|
276
|
+
|
|
277
|
+
await finished(readStream)
|
|
278
|
+
|
|
279
|
+
core.info(`Artifact download completed successfully.`)
|
|
280
|
+
} catch (error: any) {
|
|
281
|
+
throw new Error(
|
|
282
|
+
`Unable to download and extract artifact: ${error.message}`,
|
|
283
|
+
{ cause: error }
|
|
284
|
+
)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return { downloadPath, digestMismatch: false }
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Resolves or creates a directory.
|
|
292
|
+
*
|
|
293
|
+
* @param downloadPath Download Path
|
|
294
|
+
* @returns Download Path
|
|
295
|
+
*/
|
|
296
|
+
/* istanbul ignore next */
|
|
297
|
+
async function resolveOrCreateDirectory(
|
|
298
|
+
downloadPath = getGitHubWorkspaceDir()
|
|
299
|
+
): Promise<string> {
|
|
300
|
+
if (!exists(downloadPath)) {
|
|
301
|
+
core.debug(
|
|
302
|
+
`Artifact destination folder does not exist, creating: ${downloadPath}`
|
|
303
|
+
)
|
|
304
|
+
fs.mkdirSync(downloadPath, { recursive: true })
|
|
305
|
+
} else
|
|
306
|
+
core.debug(`Artifact destination folder already exists: ${downloadPath}`)
|
|
307
|
+
|
|
308
|
+
return downloadPath
|
|
309
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Last Reviewed Commit: d5c8a0fa274d832846b6c3a409b017a6b76b787e
|
|
3
|
+
* Last Reviewed Date: 2026-01-16
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { OctokitOptions } from '@octokit/core'
|
|
7
|
+
import { requestLog } from '@octokit/plugin-request-log'
|
|
8
|
+
import { retry } from '@octokit/plugin-retry'
|
|
9
|
+
import { EnvMeta } from '../../../../stubs/env.js'
|
|
10
|
+
import * as core from '../../../core/core.js'
|
|
11
|
+
import { getOctokit } from '../../../github/github.js'
|
|
12
|
+
import { defaults as defaultGitHubOptions } from '../../../github/utils.js'
|
|
13
|
+
import {
|
|
14
|
+
ArtifactNotFoundError,
|
|
15
|
+
InvalidResponseError
|
|
16
|
+
} from '../shared/errors.js'
|
|
17
|
+
import type { Artifact, GetArtifactResponse } from '../shared/interfaces.js'
|
|
18
|
+
import { getUserAgentString } from '../shared/user-agent.js'
|
|
19
|
+
import { getRetryOptions } from './retry-options.js'
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Gets the artifact from the GitHub API.
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
*
|
|
26
|
+
* - Removed digest from the artifact interface.
|
|
27
|
+
*
|
|
28
|
+
* @param artifactName Artifact Name
|
|
29
|
+
* @param workflowRunId Workflow Run ID
|
|
30
|
+
* @param repositoryOwner Repository Owner
|
|
31
|
+
* @param repositoryName Repository Name
|
|
32
|
+
* @param token Token
|
|
33
|
+
* @returns Get Artifact Response
|
|
34
|
+
*/
|
|
35
|
+
export async function getArtifactPublic(
|
|
36
|
+
artifactName: string,
|
|
37
|
+
workflowRunId: number,
|
|
38
|
+
repositoryOwner: string,
|
|
39
|
+
repositoryName: string,
|
|
40
|
+
token: string
|
|
41
|
+
): Promise<GetArtifactResponse> {
|
|
42
|
+
const [retryOpts, requestOpts] = getRetryOptions(defaultGitHubOptions)
|
|
43
|
+
|
|
44
|
+
const opts: OctokitOptions = {
|
|
45
|
+
log: undefined,
|
|
46
|
+
userAgent: getUserAgentString(),
|
|
47
|
+
previews: undefined,
|
|
48
|
+
retry: retryOpts,
|
|
49
|
+
request: requestOpts
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const github = getOctokit(token, opts, retry as any, requestLog as any)
|
|
53
|
+
|
|
54
|
+
const getArtifactResp = await github.request(
|
|
55
|
+
'GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts{?name}',
|
|
56
|
+
{
|
|
57
|
+
owner: repositoryOwner,
|
|
58
|
+
repo: repositoryName,
|
|
59
|
+
run_id: workflowRunId,
|
|
60
|
+
name: artifactName
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
if (getArtifactResp.status !== 200)
|
|
65
|
+
throw new InvalidResponseError(
|
|
66
|
+
`Invalid response from GitHub API: ${getArtifactResp.status} (${getArtifactResp?.headers?.['x-github-request-id']})`
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
if (getArtifactResp.data.artifacts.length === 0)
|
|
70
|
+
throw new ArtifactNotFoundError(
|
|
71
|
+
`Artifact not found for name: ${artifactName}
|
|
72
|
+
Please ensure that your artifact is not expired and the artifact was uploaded using a compatible version of toolkit/upload-artifact.
|
|
73
|
+
For more information, visit the GitHub Artifacts FAQ: https://github.com/actions/toolkit/blob/main/packages/artifact/docs/faq.md`
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
let artifact = getArtifactResp.data.artifacts[0]
|
|
77
|
+
if (getArtifactResp.data.artifacts.length > 1) {
|
|
78
|
+
artifact = getArtifactResp.data.artifacts.sort(
|
|
79
|
+
(a: Artifact, b: Artifact) => b.id - a.id
|
|
80
|
+
)[0]
|
|
81
|
+
core.debug(
|
|
82
|
+
`More than one artifact found for a single name, returning newest (id: ${artifact.id})`
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
artifact: {
|
|
88
|
+
name: artifact.name,
|
|
89
|
+
id: artifact.id,
|
|
90
|
+
size: artifact.size_in_bytes,
|
|
91
|
+
createdAt: artifact.created_at ? new Date(artifact.created_at) : undefined
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Gets the artifact from this workflow run.
|
|
98
|
+
*
|
|
99
|
+
* @remarks
|
|
100
|
+
*
|
|
101
|
+
* - Removed digest from the artifact interface.
|
|
102
|
+
* - Gets artifacts from environment metadata.
|
|
103
|
+
*
|
|
104
|
+
* @param artifactName Artifact Name
|
|
105
|
+
* @returns Get Artifact Response
|
|
106
|
+
*/
|
|
107
|
+
export async function getArtifactInternal(
|
|
108
|
+
artifactName: string
|
|
109
|
+
): Promise<GetArtifactResponse> {
|
|
110
|
+
// Get all artifacts with a matching name, sorted by latest (highest ID).
|
|
111
|
+
const artifacts = EnvMeta.artifacts
|
|
112
|
+
.filter(artifact => artifact.name === artifactName)
|
|
113
|
+
.sort((a, b) => Number(b.id) - Number(a.id))
|
|
114
|
+
|
|
115
|
+
if (artifacts.length === 0)
|
|
116
|
+
throw new ArtifactNotFoundError(
|
|
117
|
+
`Artifact not found for name: ${artifactName}
|
|
118
|
+
Please ensure that your artifact is not expired and the artifact was uploaded using a compatible version of toolkit/upload-artifact.
|
|
119
|
+
For more information, visit the GitHub Artifacts FAQ: https://github.com/actions/toolkit/blob/main/packages/artifact/docs/faq.md`
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
if (artifacts.length > 1)
|
|
123
|
+
core.debug(
|
|
124
|
+
`More than one artifact found for a single name, returning newest (id: ${artifacts[0].id})`
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
artifact: {
|
|
129
|
+
name: artifacts[0].name,
|
|
130
|
+
id: Number(artifacts[0].id),
|
|
131
|
+
size: Number(artifacts[0].size),
|
|
132
|
+
createdAt: artifacts[0].createdAt
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Last Reviewed Commit: fea4f6b5c527a8f231cfb9e2530a2f367e971faa
|
|
3
|
+
* Last Reviewed Date: 2026-01-16
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { OctokitOptions } from '@octokit/core'
|
|
7
|
+
import { requestLog } from '@octokit/plugin-request-log'
|
|
8
|
+
import { retry } from '@octokit/plugin-retry'
|
|
9
|
+
import { EnvMeta } from '../../../../stubs/env.js'
|
|
10
|
+
import * as core from '../../../core/core.js'
|
|
11
|
+
import { getOctokit } from '../../../github/github.js'
|
|
12
|
+
import { defaults as defaultGitHubOptions } from '../../../github/utils.js'
|
|
13
|
+
import { getMaxArtifactListCount } from '../shared/config.js'
|
|
14
|
+
import type { Artifact, ListArtifactsResponse } from '../shared/interfaces.js'
|
|
15
|
+
import { getUserAgentString } from '../shared/user-agent.js'
|
|
16
|
+
import { getRetryOptions } from './retry-options.js'
|
|
17
|
+
|
|
18
|
+
const paginationCount = 100
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Lists artifacts for a given workflow run.
|
|
22
|
+
*
|
|
23
|
+
* @remarks
|
|
24
|
+
*
|
|
25
|
+
* - Removed digest from the artifact interface.
|
|
26
|
+
*
|
|
27
|
+
* @param workflowRunId Workflow Run ID
|
|
28
|
+
* @param repositoryOwner Repository Owner
|
|
29
|
+
* @param repositoryName Repository Name
|
|
30
|
+
* @param token Token
|
|
31
|
+
* @param latest Latest
|
|
32
|
+
* @returns List Artifacts Response
|
|
33
|
+
*/
|
|
34
|
+
export async function listArtifactsPublic(
|
|
35
|
+
workflowRunId: number,
|
|
36
|
+
repositoryOwner: string,
|
|
37
|
+
repositoryName: string,
|
|
38
|
+
token: string,
|
|
39
|
+
latest = false
|
|
40
|
+
): Promise<ListArtifactsResponse> {
|
|
41
|
+
core.info(
|
|
42
|
+
`Fetching artifact list for workflow run ${workflowRunId} in repository ${repositoryOwner}/${repositoryName}`
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
let artifacts: Artifact[] = []
|
|
46
|
+
const [retryOpts, requestOpts] = getRetryOptions(defaultGitHubOptions)
|
|
47
|
+
|
|
48
|
+
const opts: OctokitOptions = {
|
|
49
|
+
log: undefined,
|
|
50
|
+
userAgent: getUserAgentString(),
|
|
51
|
+
previews: undefined,
|
|
52
|
+
retry: retryOpts,
|
|
53
|
+
request: requestOpts
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const github = getOctokit(token, opts, retry as any, requestLog as any)
|
|
57
|
+
|
|
58
|
+
let currentPageNumber = 1
|
|
59
|
+
|
|
60
|
+
const { data: listArtifactResponse } =
|
|
61
|
+
await github.rest.actions.listWorkflowRunArtifacts({
|
|
62
|
+
owner: repositoryOwner,
|
|
63
|
+
repo: repositoryName,
|
|
64
|
+
run_id: workflowRunId,
|
|
65
|
+
per_page: paginationCount,
|
|
66
|
+
page: currentPageNumber
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
let numberOfPages = Math.ceil(
|
|
70
|
+
listArtifactResponse.total_count / paginationCount
|
|
71
|
+
)
|
|
72
|
+
const totalArtifactCount = listArtifactResponse.total_count
|
|
73
|
+
if (totalArtifactCount > getMaxArtifactListCount()) {
|
|
74
|
+
core.warning(
|
|
75
|
+
`Workflow run ${workflowRunId} has more than 1000 artifacts. Results will be incomplete as only the first ${getMaxArtifactListCount()} artifacts will be returned`
|
|
76
|
+
)
|
|
77
|
+
numberOfPages = Math.ceil(getMaxArtifactListCount() / paginationCount)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Iterate over the first page
|
|
81
|
+
for (const artifact of listArtifactResponse.artifacts) {
|
|
82
|
+
artifacts.push({
|
|
83
|
+
name: artifact.name,
|
|
84
|
+
id: artifact.id,
|
|
85
|
+
size: artifact.size_in_bytes,
|
|
86
|
+
createdAt: artifact.created_at
|
|
87
|
+
? new Date(artifact.created_at)
|
|
88
|
+
: undefined,
|
|
89
|
+
digest: (artifact as ArtifactResponse).digest
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Move to the next page
|
|
94
|
+
currentPageNumber++
|
|
95
|
+
|
|
96
|
+
// Iterate over any remaining pages
|
|
97
|
+
/* istanbul ignore next */
|
|
98
|
+
for (
|
|
99
|
+
currentPageNumber;
|
|
100
|
+
currentPageNumber <= numberOfPages;
|
|
101
|
+
currentPageNumber++
|
|
102
|
+
) {
|
|
103
|
+
core.debug(`Fetching page ${currentPageNumber} of artifact list`)
|
|
104
|
+
|
|
105
|
+
const { data: listArtifactResponse } =
|
|
106
|
+
await github.rest.actions.listWorkflowRunArtifacts({
|
|
107
|
+
owner: repositoryOwner,
|
|
108
|
+
repo: repositoryName,
|
|
109
|
+
run_id: workflowRunId,
|
|
110
|
+
per_page: paginationCount,
|
|
111
|
+
page: currentPageNumber
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
for (const artifact of listArtifactResponse.artifacts) {
|
|
115
|
+
artifacts.push({
|
|
116
|
+
name: artifact.name,
|
|
117
|
+
id: artifact.id,
|
|
118
|
+
size: artifact.size_in_bytes,
|
|
119
|
+
createdAt: artifact.created_at
|
|
120
|
+
? new Date(artifact.created_at)
|
|
121
|
+
: undefined,
|
|
122
|
+
digest: (artifact as ArtifactResponse).digest
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (latest) artifacts = filterLatest(artifacts)
|
|
128
|
+
|
|
129
|
+
core.info(`Found ${artifacts.length} artifact(s)`)
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
artifacts
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* List artifacts for this workflow run.
|
|
138
|
+
*
|
|
139
|
+
* @remarks
|
|
140
|
+
*
|
|
141
|
+
* - Uses environment metadata for tracking artifacts.
|
|
142
|
+
*
|
|
143
|
+
* @param latest Latest
|
|
144
|
+
* @returns List Artifacts Response
|
|
145
|
+
*/
|
|
146
|
+
export async function listArtifactsInternal(
|
|
147
|
+
latest = false
|
|
148
|
+
): Promise<ListArtifactsResponse> {
|
|
149
|
+
const artifacts = latest ? filterLatest(EnvMeta.artifacts) : EnvMeta.artifacts
|
|
150
|
+
|
|
151
|
+
core.info(`Found ${artifacts.length} artifact(s)`)
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
artifacts
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* This exists so that we don't have to use 'any' when receiving the artifact
|
|
160
|
+
* list from the GitHub API. The digest field is not present in OpenAPI/types at
|
|
161
|
+
* time of writing, which necessitates this change.
|
|
162
|
+
*/
|
|
163
|
+
interface ArtifactResponse {
|
|
164
|
+
name: string
|
|
165
|
+
id: number
|
|
166
|
+
size_in_bytes: number
|
|
167
|
+
created_at?: string
|
|
168
|
+
digest?: string
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Filters a list of artifacts to only include the latest artifact for each name
|
|
173
|
+
*
|
|
174
|
+
* @param artifacts The artifacts to filter
|
|
175
|
+
* @returns The filtered list of artifacts
|
|
176
|
+
*/
|
|
177
|
+
function filterLatest(artifacts: Artifact[]): Artifact[] {
|
|
178
|
+
artifacts.sort((a, b) => b.id - a.id)
|
|
179
|
+
const latestArtifacts: Artifact[] = []
|
|
180
|
+
const seenArtifactNames = new Set<string>()
|
|
181
|
+
for (const artifact of artifacts) {
|
|
182
|
+
if (!seenArtifactNames.has(artifact.name)) {
|
|
183
|
+
latestArtifacts.push(artifact)
|
|
184
|
+
seenArtifactNames.add(artifact.name)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return latestArtifacts
|
|
188
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Last Reviewed Commit: 06e751600e2c016997ae8b1393bff0c4c79fc52f
|
|
3
|
+
* Last Reviewed Date: 2026-01-16
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { OctokitOptions } from '@octokit/core'
|
|
7
|
+
import type { RequestRequestOptions } from '@octokit/types'
|
|
8
|
+
import * as core from '../../../core/core.js'
|
|
9
|
+
|
|
10
|
+
export type RetryOptions = {
|
|
11
|
+
doNotRetry?: number[]
|
|
12
|
+
enabled?: boolean
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Defaults for fetching artifacts
|
|
16
|
+
const defaultMaxRetryNumber = 5
|
|
17
|
+
const defaultExemptStatusCodes = [400, 401, 403, 404, 422] // https://github.com/octokit/plugin-retry.js/blob/9a2443746c350b3beedec35cf26e197ea318a261/src/index.ts#L14
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get the retry options for the GitHub client.
|
|
21
|
+
*
|
|
22
|
+
* @param defaultOptions Default Options
|
|
23
|
+
* @param retries Retries
|
|
24
|
+
* @param exemptStatusCodes Exempt Status Codes
|
|
25
|
+
* @returns Retry Options
|
|
26
|
+
*/
|
|
27
|
+
export function getRetryOptions(
|
|
28
|
+
defaultOptions: OctokitOptions,
|
|
29
|
+
retries: number = defaultMaxRetryNumber,
|
|
30
|
+
exemptStatusCodes: number[] = defaultExemptStatusCodes
|
|
31
|
+
): [RetryOptions, RequestRequestOptions | undefined] {
|
|
32
|
+
if (retries <= 0) return [{ enabled: false }, defaultOptions.request]
|
|
33
|
+
|
|
34
|
+
const retryOptions: RetryOptions = {
|
|
35
|
+
enabled: true
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (exemptStatusCodes.length > 0) retryOptions.doNotRetry = exemptStatusCodes
|
|
39
|
+
|
|
40
|
+
// The GitHub type has some defaults for `options.request`
|
|
41
|
+
// see: https://github.com/actions/toolkit/blob/4fbc5c941a57249b19562015edbd72add14be93d/packages/github/src/utils.ts#L15
|
|
42
|
+
// We pass these in here so they are not overridden.
|
|
43
|
+
const requestOptions: RequestRequestOptions = {
|
|
44
|
+
...defaultOptions.request,
|
|
45
|
+
retries
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
core.debug(
|
|
49
|
+
`GitHub client configured with: (retries: ${
|
|
50
|
+
requestOptions.retries
|
|
51
|
+
}, retry-exempt-status-code: ${
|
|
52
|
+
retryOptions.doNotRetry ?? 'octokit default: [400, 401, 403, 404, 422]'
|
|
53
|
+
})`
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
return [retryOptions, requestOptions]
|
|
57
|
+
}
|