Compare commits
10 Commits
e463631f66
...
d3f86a106a
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d3f86a106a | ||
![]() |
fc02353415 | ||
![]() |
77454371a4 | ||
![]() |
84fc7a0a35 | ||
![]() |
67f2bc382f | ||
![]() |
8ea3c2c174 | ||
![]() |
d219c630f6 | ||
![]() |
54124fbd88 | ||
![]() |
b83057b90d | ||
![]() |
171183c7dc |
4
.github/workflows/check-dist.yml
vendored
4
.github/workflows/check-dist.yml
vendored
@ -10,11 +10,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
paths-ignore:
|
|
||||||
- '**.md'
|
|
||||||
pull_request:
|
pull_request:
|
||||||
paths-ignore:
|
|
||||||
- '**.md'
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
@ -25,8 +25,6 @@ const mockInputs = (overrides?: Partial<{[K in Inputs]?: any}>) => {
|
|||||||
[Inputs.Repository]: 'owner/some-repository',
|
[Inputs.Repository]: 'owner/some-repository',
|
||||||
[Inputs.RunID]: 'some-run-id',
|
[Inputs.RunID]: 'some-run-id',
|
||||||
[Inputs.Pattern]: 'some-pattern',
|
[Inputs.Pattern]: 'some-pattern',
|
||||||
[Inputs.MergeMultiple]: false,
|
|
||||||
[Inputs.ArtifactIds]: '',
|
|
||||||
...overrides
|
...overrides
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,42 +222,9 @@ describe('download', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('throws error when both name and artifact-ids are provided', async () => {
|
|
||||||
mockInputs({
|
|
||||||
[Inputs.Name]: 'artifact-name',
|
|
||||||
[Inputs.ArtifactIds]: '123'
|
|
||||||
})
|
|
||||||
|
|
||||||
await expect(run()).rejects.toThrow(
|
|
||||||
"Inputs 'name' and 'artifact-ids' cannot be used together. Please specify only one."
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('throws error when artifact-ids is empty', async () => {
|
|
||||||
mockInputs({
|
|
||||||
[Inputs.Name]: '',
|
|
||||||
[Inputs.ArtifactIds]: ' , '
|
|
||||||
})
|
|
||||||
|
|
||||||
await expect(run()).rejects.toThrow(
|
|
||||||
"No valid artifact IDs provided in 'artifact-ids' input"
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('throws error when artifact-id is not a number', async () => {
|
|
||||||
mockInputs({
|
|
||||||
[Inputs.Name]: '',
|
|
||||||
[Inputs.ArtifactIds]: '123,abc,456'
|
|
||||||
})
|
|
||||||
|
|
||||||
await expect(run()).rejects.toThrow(
|
|
||||||
"Invalid artifact ID: 'abc'. Must be a number."
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('downloads a single artifact by ID', async () => {
|
test('downloads a single artifact by ID', async () => {
|
||||||
const mockArtifact = {
|
const mockArtifact = {
|
||||||
id: 123,
|
id: 456,
|
||||||
name: 'artifact-by-id',
|
name: 'artifact-by-id',
|
||||||
size: 1024,
|
size: 1024,
|
||||||
digest: 'def456'
|
digest: 'def456'
|
||||||
@ -267,120 +232,143 @@ describe('download', () => {
|
|||||||
|
|
||||||
mockInputs({
|
mockInputs({
|
||||||
[Inputs.Name]: '',
|
[Inputs.Name]: '',
|
||||||
[Inputs.ArtifactIds]: '123'
|
[Inputs.Pattern]: '',
|
||||||
|
[Inputs.ArtifactIds]: '456'
|
||||||
})
|
})
|
||||||
|
|
||||||
jest
|
jest.spyOn(artifact, 'listArtifacts').mockImplementation(() =>
|
||||||
.spyOn(artifact, 'getArtifact')
|
Promise.resolve({
|
||||||
.mockImplementation(() => Promise.resolve({artifact: mockArtifact}))
|
artifacts: [mockArtifact]
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
await run()
|
await run()
|
||||||
|
|
||||||
expect(core.debug).toHaveBeenCalledWith(
|
expect(core.info).toHaveBeenCalledWith('Downloading artifacts by ID')
|
||||||
'Only one artifact ID provided. Fetching latest artifact by its name and checking the ID'
|
expect(core.debug).toHaveBeenCalledWith('Parsed artifact IDs: ["456"]')
|
||||||
)
|
expect(artifact.downloadArtifact).toHaveBeenCalledTimes(1)
|
||||||
expect(artifact.getArtifact).toHaveBeenCalled()
|
|
||||||
expect(artifact.downloadArtifact).toHaveBeenCalledWith(
|
expect(artifact.downloadArtifact).toHaveBeenCalledWith(
|
||||||
mockArtifact.id,
|
456,
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
expectedHash: mockArtifact.digest
|
expectedHash: mockArtifact.digest
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
expect(artifact.listArtifacts).not.toHaveBeenCalled()
|
|
||||||
expect(core.info).toHaveBeenCalledWith('Total of 1 artifact(s) downloaded')
|
expect(core.info).toHaveBeenCalledWith('Total of 1 artifact(s) downloaded')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('throws error when single artifact ID is not found', async () => {
|
test('downloads multiple artifacts by ID', async () => {
|
||||||
mockInputs({
|
|
||||||
[Inputs.Name]: '',
|
|
||||||
[Inputs.ArtifactIds]: '999'
|
|
||||||
})
|
|
||||||
|
|
||||||
jest.spyOn(artifact, 'getArtifact').mockImplementation(() => {
|
|
||||||
return Promise.resolve({artifact: null} as any)
|
|
||||||
})
|
|
||||||
|
|
||||||
await expect(run()).rejects.toThrow(
|
|
||||||
"Artifact with ID '999' not found. Please check the ID."
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('downloads multiple artifacts by IDs', async () => {
|
|
||||||
const mockArtifacts = [
|
const mockArtifacts = [
|
||||||
{id: 123, name: 'artifact1', size: 1024, digest: 'abc123'},
|
{id: 123, name: 'first-artifact', size: 1024, digest: 'abc123'},
|
||||||
{id: 456, name: 'artifact2', size: 2048, digest: 'def456'},
|
{id: 456, name: 'second-artifact', size: 2048, digest: 'def456'},
|
||||||
{id: 789, name: 'artifact3', size: 3072, digest: 'ghi789'}
|
{id: 789, name: 'third-artifact', size: 3072, digest: 'ghi789'}
|
||||||
]
|
]
|
||||||
|
|
||||||
mockInputs({
|
mockInputs({
|
||||||
[Inputs.Name]: '',
|
[Inputs.Name]: '',
|
||||||
[Inputs.ArtifactIds]: '123, 456'
|
[Inputs.Pattern]: '',
|
||||||
|
[Inputs.ArtifactIds]: '123, 456, 789'
|
||||||
})
|
})
|
||||||
|
|
||||||
jest
|
jest.spyOn(artifact, 'listArtifacts').mockImplementation(() =>
|
||||||
.spyOn(artifact, 'listArtifacts')
|
Promise.resolve({
|
||||||
.mockImplementation(() => Promise.resolve({artifacts: mockArtifacts}))
|
artifacts: mockArtifacts
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
await run()
|
await run()
|
||||||
|
|
||||||
expect(core.info).toHaveBeenCalledWith(
|
expect(core.info).toHaveBeenCalledWith('Downloading artifacts by ID')
|
||||||
'Multiple artifact IDs provided. Fetching all artifacts to filter by ID'
|
expect(core.debug).toHaveBeenCalledWith(
|
||||||
)
|
'Parsed artifact IDs: ["123","456","789"]'
|
||||||
expect(artifact.getArtifact).not.toHaveBeenCalled()
|
|
||||||
expect(artifact.listArtifacts).toHaveBeenCalled()
|
|
||||||
expect(artifact.downloadArtifact).toHaveBeenCalledTimes(2)
|
|
||||||
expect(artifact.downloadArtifact).toHaveBeenCalledWith(
|
|
||||||
123,
|
|
||||||
expect.anything()
|
|
||||||
)
|
|
||||||
expect(artifact.downloadArtifact).toHaveBeenCalledWith(
|
|
||||||
456,
|
|
||||||
expect.anything()
|
|
||||||
)
|
)
|
||||||
|
expect(artifact.downloadArtifact).toHaveBeenCalledTimes(3)
|
||||||
|
mockArtifacts.forEach(mockArtifact => {
|
||||||
|
expect(artifact.downloadArtifact).toHaveBeenCalledWith(
|
||||||
|
mockArtifact.id,
|
||||||
|
expect.objectContaining({
|
||||||
|
expectedHash: mockArtifact.digest
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
expect(core.info).toHaveBeenCalledWith('Total of 3 artifact(s) downloaded')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('warns when some artifact IDs are not found', async () => {
|
test('warns when some artifact IDs are not found', async () => {
|
||||||
const mockArtifacts = [
|
const mockArtifacts = [
|
||||||
{id: 123, name: 'artifact1', size: 1024, digest: 'abc123'}
|
{id: 123, name: 'found-artifact', size: 1024, digest: 'abc123'}
|
||||||
]
|
]
|
||||||
|
|
||||||
mockInputs({
|
mockInputs({
|
||||||
[Inputs.Name]: '',
|
[Inputs.Name]: '',
|
||||||
|
[Inputs.Pattern]: '',
|
||||||
[Inputs.ArtifactIds]: '123, 456, 789'
|
[Inputs.ArtifactIds]: '123, 456, 789'
|
||||||
})
|
})
|
||||||
|
|
||||||
jest
|
jest.spyOn(artifact, 'listArtifacts').mockImplementation(() =>
|
||||||
.spyOn(artifact, 'listArtifacts')
|
Promise.resolve({
|
||||||
.mockImplementation(() => Promise.resolve({artifacts: mockArtifacts}))
|
artifacts: mockArtifacts
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
await run()
|
await run()
|
||||||
|
|
||||||
expect(core.warning).toHaveBeenCalledWith(
|
expect(core.warning).toHaveBeenCalledWith(
|
||||||
'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(artifact.downloadArtifact).toHaveBeenCalledTimes(1)
|
expect(artifact.downloadArtifact).toHaveBeenCalledTimes(1)
|
||||||
expect(artifact.downloadArtifact).toHaveBeenCalledWith(
|
|
||||||
123,
|
|
||||||
expect.anything()
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('throws error when none of the provided artifact IDs are found', async () => {
|
test('throws error when no artifacts with requested IDs are found', async () => {
|
||||||
const mockArtifacts = [
|
|
||||||
{id: 999, name: 'other-artifact', size: 1024, digest: 'xyz999'}
|
|
||||||
]
|
|
||||||
|
|
||||||
mockInputs({
|
mockInputs({
|
||||||
[Inputs.Name]: '',
|
[Inputs.Name]: '',
|
||||||
|
[Inputs.Pattern]: '',
|
||||||
[Inputs.ArtifactIds]: '123, 456'
|
[Inputs.ArtifactIds]: '123, 456'
|
||||||
})
|
})
|
||||||
|
|
||||||
jest
|
jest.spyOn(artifact, 'listArtifacts').mockImplementation(() =>
|
||||||
.spyOn(artifact, 'listArtifacts')
|
Promise.resolve({
|
||||||
.mockImplementation(() => Promise.resolve({artifacts: mockArtifacts}))
|
artifacts: []
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
await expect(run()).rejects.toThrow(
|
await expect(run()).rejects.toThrow(
|
||||||
'None of the provided artifact IDs were found'
|
'None of the provided artifact IDs were found'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('throws error when artifact-ids input is empty', async () => {
|
||||||
|
mockInputs({
|
||||||
|
[Inputs.Name]: '',
|
||||||
|
[Inputs.Pattern]: '',
|
||||||
|
[Inputs.ArtifactIds]: ' '
|
||||||
|
})
|
||||||
|
|
||||||
|
await expect(run()).rejects.toThrow(
|
||||||
|
"No valid artifact IDs provided in 'artifact-ids' input"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('throws error when some artifact IDs are not valid numbers', async () => {
|
||||||
|
mockInputs({
|
||||||
|
[Inputs.Name]: '',
|
||||||
|
[Inputs.Pattern]: '',
|
||||||
|
[Inputs.ArtifactIds]: '123, abc, 456'
|
||||||
|
})
|
||||||
|
|
||||||
|
await expect(run()).rejects.toThrow(
|
||||||
|
"Invalid artifact ID: 'abc'. Must be a number."
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('throws error when both name and artifact-ids are provided', async () => {
|
||||||
|
mockInputs({
|
||||||
|
[Inputs.Name]: 'some-artifact',
|
||||||
|
[Inputs.ArtifactIds]: '123'
|
||||||
|
})
|
||||||
|
|
||||||
|
await expect(run()).rejects.toThrow(
|
||||||
|
"Inputs 'name' and 'artifact-ids' cannot be used together. Please specify only one."
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
20
dist/index.js
vendored
20
dist/index.js
vendored
@ -118845,23 +118845,9 @@ function run() {
|
|||||||
}
|
}
|
||||||
return numericId;
|
return numericId;
|
||||||
});
|
});
|
||||||
// if the length of artifactIds exactly 1 fetch the latest artifact by its name and check the ID
|
// We need to fetch all artifacts to get metadata for the specified IDs
|
||||||
if (artifactIds.length === 1) {
|
const listArtifactResponse = yield artifact_1.default.listArtifacts(Object.assign({ latest: true }, options));
|
||||||
core.debug(`Only one artifact ID provided. Fetching latest artifact by its name and checking the ID`);
|
artifacts = listArtifactResponse.artifacts.filter(artifact => artifactIds.includes(artifact.id));
|
||||||
const getArtifactResponse = yield artifact_1.default.getArtifact(inputs.name, Object.assign({}, options));
|
|
||||||
if (!getArtifactResponse || !getArtifactResponse.artifact) {
|
|
||||||
throw new Error(`Artifact with ID '${artifactIds[0]}' not found. Please check the ID.`);
|
|
||||||
}
|
|
||||||
const artifact = getArtifactResponse.artifact;
|
|
||||||
core.debug(`Found artifact by ID '${artifact.name}' (ID: ${artifact.id}, Size: ${artifact.size})`);
|
|
||||||
artifacts = [artifact];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
core.info(`Multiple artifact IDs provided. Fetching all artifacts to filter by ID`);
|
|
||||||
// We need to fetch all artifacts to get metadata for the specified IDs
|
|
||||||
const listArtifactResponse = yield artifact_1.default.listArtifacts(Object.assign({ latest: true }, options));
|
|
||||||
artifacts = listArtifactResponse.artifacts.filter(artifact => artifactIds.includes(artifact.id));
|
|
||||||
}
|
|
||||||
if (artifacts.length === 0) {
|
if (artifacts.length === 0) {
|
||||||
throw new Error(`None of the provided artifact IDs were found`);
|
throw new Error(`None of the provided artifact IDs were found`);
|
||||||
}
|
}
|
||||||
|
@ -219,21 +219,29 @@ To take advantage of this immutability for security purposes (to avoid potential
|
|||||||
jobs:
|
jobs:
|
||||||
upload:
|
upload:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
# Make the artifact ID available to the download job
|
||||||
|
outputs:
|
||||||
|
artifact-id: ${{ steps.upload-step.outputs.artifact-id }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Create a file
|
- name: Create a file
|
||||||
run: echo "hello world" > my-file.txt
|
run: echo "hello world" > my-file.txt
|
||||||
- name: Upload Artifact
|
- name: Upload Artifact
|
||||||
id: upload
|
id: upload-step
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: my-artifact
|
name: my-artifact
|
||||||
path: my-file.txt
|
path: my-file.txt
|
||||||
# The upload step outputs the artifact ID
|
# The upload step outputs the artifact ID
|
||||||
- name: Print Artifact ID
|
- name: Print Artifact ID
|
||||||
run: echo "Artifact ID is ${{ steps.upload.outputs.artifact-id }}"
|
run: echo "Artifact ID is ${{ steps.upload-step.outputs.artifact-id }}"
|
||||||
|
|
||||||
download:
|
download:
|
||||||
needs: upload
|
needs: upload
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Download Artifact by ID
|
- name: Download Artifact by ID
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
|
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "download-artifact",
|
"name": "download-artifact",
|
||||||
"version": "4.2.0",
|
"version": "4.3.0",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "download-artifact",
|
"name": "download-artifact",
|
||||||
"version": "4.2.0",
|
"version": "4.3.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/artifact": "^2.3.2",
|
"@actions/artifact": "^2.3.2",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "download-artifact",
|
"name": "download-artifact",
|
||||||
"version": "4.2.0",
|
"version": "4.3.0",
|
||||||
"description": "Download an Actions Artifact from a workflow run",
|
"description": "Download an Actions Artifact from a workflow run",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -109,44 +109,15 @@ export async function run(): Promise<void> {
|
|||||||
return numericId
|
return numericId
|
||||||
})
|
})
|
||||||
|
|
||||||
// if the length of artifactIds exactly 1 fetch the latest artifact by its name and check the ID
|
// We need to fetch all artifacts to get metadata for the specified IDs
|
||||||
if (artifactIds.length === 1) {
|
const listArtifactResponse = await artifactClient.listArtifacts({
|
||||||
core.debug(
|
latest: true,
|
||||||
`Only one artifact ID provided. Fetching latest artifact by its name and checking the ID`
|
...options
|
||||||
)
|
})
|
||||||
const getArtifactResponse = await artifactClient.getArtifact(
|
|
||||||
inputs.name,
|
|
||||||
{...options}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!getArtifactResponse || !getArtifactResponse.artifact) {
|
artifacts = listArtifactResponse.artifacts.filter(artifact =>
|
||||||
throw new Error(
|
artifactIds.includes(artifact.id)
|
||||||
`Artifact with ID '${artifactIds[0]}' not found. Please check the ID.`
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const artifact = getArtifactResponse.artifact
|
|
||||||
|
|
||||||
core.debug(
|
|
||||||
`Found artifact by ID '${artifact.name}' (ID: ${artifact.id}, Size: ${artifact.size})`
|
|
||||||
)
|
|
||||||
|
|
||||||
artifacts = [artifact]
|
|
||||||
} else {
|
|
||||||
core.info(
|
|
||||||
`Multiple artifact IDs provided. Fetching all artifacts to filter by ID`
|
|
||||||
)
|
|
||||||
|
|
||||||
// We need to fetch all artifacts to get metadata for the specified IDs
|
|
||||||
const listArtifactResponse = await artifactClient.listArtifacts({
|
|
||||||
latest: true,
|
|
||||||
...options
|
|
||||||
})
|
|
||||||
|
|
||||||
artifacts = listArtifactResponse.artifacts.filter(artifact =>
|
|
||||||
artifactIds.includes(artifact.id)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (artifacts.length === 0) {
|
if (artifacts.length === 0) {
|
||||||
throw new Error(`None of the provided artifact IDs were found`)
|
throw new Error(`None of the provided artifact IDs were found`)
|
||||||
|
Loading…
Reference in New Issue
Block a user