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:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
@ -25,8 +25,6 @@ const mockInputs = (overrides?: Partial<{[K in Inputs]?: any}>) => {
|
||||
[Inputs.Repository]: 'owner/some-repository',
|
||||
[Inputs.RunID]: 'some-run-id',
|
||||
[Inputs.Pattern]: 'some-pattern',
|
||||
[Inputs.MergeMultiple]: false,
|
||||
[Inputs.ArtifactIds]: '',
|
||||
...overrides
|
||||
}
|
||||
|
||||
@ -224,21 +222,126 @@ describe('download', () => {
|
||||
)
|
||||
})
|
||||
|
||||
test('throws error when both name and artifact-ids are provided', async () => {
|
||||
test('downloads a single artifact by ID', async () => {
|
||||
const mockArtifact = {
|
||||
id: 456,
|
||||
name: 'artifact-by-id',
|
||||
size: 1024,
|
||||
digest: 'def456'
|
||||
}
|
||||
|
||||
mockInputs({
|
||||
[Inputs.Name]: 'artifact-name',
|
||||
[Inputs.ArtifactIds]: '123'
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.Pattern]: '',
|
||||
[Inputs.ArtifactIds]: '456'
|
||||
})
|
||||
|
||||
jest.spyOn(artifact, 'listArtifacts').mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
artifacts: [mockArtifact]
|
||||
})
|
||||
)
|
||||
|
||||
await run()
|
||||
|
||||
expect(core.info).toHaveBeenCalledWith('Downloading artifacts by ID')
|
||||
expect(core.debug).toHaveBeenCalledWith('Parsed artifact IDs: ["456"]')
|
||||
expect(artifact.downloadArtifact).toHaveBeenCalledTimes(1)
|
||||
expect(artifact.downloadArtifact).toHaveBeenCalledWith(
|
||||
456,
|
||||
expect.objectContaining({
|
||||
expectedHash: mockArtifact.digest
|
||||
})
|
||||
)
|
||||
expect(core.info).toHaveBeenCalledWith('Total of 1 artifact(s) downloaded')
|
||||
})
|
||||
|
||||
test('downloads multiple artifacts by ID', async () => {
|
||||
const mockArtifacts = [
|
||||
{id: 123, name: 'first-artifact', size: 1024, digest: 'abc123'},
|
||||
{id: 456, name: 'second-artifact', size: 2048, digest: 'def456'},
|
||||
{id: 789, name: 'third-artifact', size: 3072, digest: 'ghi789'}
|
||||
]
|
||||
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.Pattern]: '',
|
||||
[Inputs.ArtifactIds]: '123, 456, 789'
|
||||
})
|
||||
|
||||
jest.spyOn(artifact, 'listArtifacts').mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
artifacts: mockArtifacts
|
||||
})
|
||||
)
|
||||
|
||||
await run()
|
||||
|
||||
expect(core.info).toHaveBeenCalledWith('Downloading artifacts by ID')
|
||||
expect(core.debug).toHaveBeenCalledWith(
|
||||
'Parsed artifact IDs: ["123","456","789"]'
|
||||
)
|
||||
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 () => {
|
||||
const mockArtifacts = [
|
||||
{id: 123, name: 'found-artifact', size: 1024, digest: 'abc123'}
|
||||
]
|
||||
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.Pattern]: '',
|
||||
[Inputs.ArtifactIds]: '123, 456, 789'
|
||||
})
|
||||
|
||||
jest.spyOn(artifact, 'listArtifacts').mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
artifacts: mockArtifacts
|
||||
})
|
||||
)
|
||||
|
||||
await run()
|
||||
|
||||
expect(core.warning).toHaveBeenCalledWith(
|
||||
'Could not find the following artifact IDs: 456, 789'
|
||||
)
|
||||
expect(core.debug).toHaveBeenCalledWith('Found 1 artifacts by ID')
|
||||
expect(artifact.downloadArtifact).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
test('throws error when no artifacts with requested IDs are found', async () => {
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.Pattern]: '',
|
||||
[Inputs.ArtifactIds]: '123, 456'
|
||||
})
|
||||
|
||||
jest.spyOn(artifact, 'listArtifacts').mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
artifacts: []
|
||||
})
|
||||
)
|
||||
|
||||
await expect(run()).rejects.toThrow(
|
||||
"Inputs 'name' and 'artifact-ids' cannot be used together. Please specify only one."
|
||||
'None of the provided artifact IDs were found'
|
||||
)
|
||||
})
|
||||
|
||||
test('throws error when artifact-ids is empty', async () => {
|
||||
test('throws error when artifact-ids input is empty', async () => {
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.ArtifactIds]: ' , '
|
||||
[Inputs.Pattern]: '',
|
||||
[Inputs.ArtifactIds]: ' '
|
||||
})
|
||||
|
||||
await expect(run()).rejects.toThrow(
|
||||
@ -246,9 +349,10 @@ describe('download', () => {
|
||||
)
|
||||
})
|
||||
|
||||
test('throws error when artifact-id is not a number', async () => {
|
||||
test('throws error when some artifact IDs are not valid numbers', async () => {
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.Pattern]: '',
|
||||
[Inputs.ArtifactIds]: '123, abc, 456'
|
||||
})
|
||||
|
||||
@ -257,130 +361,14 @@ describe('download', () => {
|
||||
)
|
||||
})
|
||||
|
||||
test('downloads a single artifact by ID', async () => {
|
||||
const mockArtifact = {
|
||||
id: 123,
|
||||
name: 'artifact-by-id',
|
||||
size: 1024,
|
||||
digest: 'def456'
|
||||
}
|
||||
|
||||
test('throws error when both name and artifact-ids are provided', async () => {
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.Name]: 'some-artifact',
|
||||
[Inputs.ArtifactIds]: '123'
|
||||
})
|
||||
|
||||
jest
|
||||
.spyOn(artifact, 'getArtifact')
|
||||
.mockImplementation(() => Promise.resolve({artifact: mockArtifact}))
|
||||
|
||||
await run()
|
||||
|
||||
expect(core.debug).toHaveBeenCalledWith(
|
||||
'Only one artifact ID provided. Fetching latest artifact by its name and checking the ID'
|
||||
)
|
||||
expect(artifact.getArtifact).toHaveBeenCalled()
|
||||
expect(artifact.downloadArtifact).toHaveBeenCalledWith(
|
||||
mockArtifact.id,
|
||||
expect.objectContaining({
|
||||
expectedHash: mockArtifact.digest
|
||||
})
|
||||
)
|
||||
expect(artifact.listArtifacts).not.toHaveBeenCalled()
|
||||
expect(core.info).toHaveBeenCalledWith('Total of 1 artifact(s) downloaded')
|
||||
})
|
||||
|
||||
test('throws error when single artifact ID is not found', 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 = [
|
||||
{id: 123, name: 'artifact1', size: 1024, digest: 'abc123'},
|
||||
{id: 456, name: 'artifact2', size: 2048, digest: 'def456'},
|
||||
{id: 789, name: 'artifact3', size: 3072, digest: 'ghi789'}
|
||||
]
|
||||
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.ArtifactIds]: '123, 456'
|
||||
})
|
||||
|
||||
jest
|
||||
.spyOn(artifact, 'listArtifacts')
|
||||
.mockImplementation(() => Promise.resolve({artifacts: mockArtifacts}))
|
||||
|
||||
await run()
|
||||
|
||||
expect(core.info).toHaveBeenCalledWith(
|
||||
'Multiple artifact IDs provided. Fetching all artifacts to filter by ID'
|
||||
)
|
||||
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()
|
||||
)
|
||||
})
|
||||
|
||||
test('warns when some artifact IDs are not found', async () => {
|
||||
const mockArtifacts = [
|
||||
{id: 123, name: 'artifact1', size: 1024, digest: 'abc123'}
|
||||
]
|
||||
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.ArtifactIds]: '123, 456, 789'
|
||||
})
|
||||
|
||||
jest
|
||||
.spyOn(artifact, 'listArtifacts')
|
||||
.mockImplementation(() => Promise.resolve({artifacts: mockArtifacts}))
|
||||
|
||||
await run()
|
||||
|
||||
expect(core.warning).toHaveBeenCalledWith(
|
||||
'Could not find the following artifact IDs: 456, 789'
|
||||
)
|
||||
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 () => {
|
||||
const mockArtifacts = [
|
||||
{id: 999, name: 'other-artifact', size: 1024, digest: 'xyz999'}
|
||||
]
|
||||
|
||||
mockInputs({
|
||||
[Inputs.Name]: '',
|
||||
[Inputs.ArtifactIds]: '123, 456'
|
||||
})
|
||||
|
||||
jest
|
||||
.spyOn(artifact, 'listArtifacts')
|
||||
.mockImplementation(() => Promise.resolve({artifacts: mockArtifacts}))
|
||||
|
||||
await expect(run()).rejects.toThrow(
|
||||
'None of the provided artifact IDs were found'
|
||||
"Inputs 'name' and 'artifact-ids' cannot be used together. Please specify only one."
|
||||
)
|
||||
})
|
||||
})
|
||||
|
14
dist/index.js
vendored
14
dist/index.js
vendored
@ -118845,23 +118845,9 @@ function run() {
|
||||
}
|
||||
return numericId;
|
||||
});
|
||||
// if the length of artifactIds exactly 1 fetch the latest artifact by its name and check the ID
|
||||
if (artifactIds.length === 1) {
|
||||
core.debug(`Only one artifact ID provided. Fetching latest artifact by its name and checking the 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) {
|
||||
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:
|
||||
upload:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Make the artifact ID available to the download job
|
||||
outputs:
|
||||
artifact-id: ${{ steps.upload-step.outputs.artifact-id }}
|
||||
|
||||
steps:
|
||||
- name: Create a file
|
||||
run: echo "hello world" > my-file.txt
|
||||
- name: Upload Artifact
|
||||
id: upload
|
||||
id: upload-step
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: my-artifact
|
||||
path: my-file.txt
|
||||
# The upload step outputs the 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:
|
||||
needs: upload
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Download Artifact by ID
|
||||
uses: actions/download-artifact@v4
|
||||
|
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "download-artifact",
|
||||
"version": "4.2.0",
|
||||
"version": "4.3.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "download-artifact",
|
||||
"version": "4.2.0",
|
||||
"version": "4.3.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/artifact": "^2.3.2",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "download-artifact",
|
||||
"version": "4.2.0",
|
||||
"version": "4.3.0",
|
||||
"description": "Download an Actions Artifact from a workflow run",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
|
@ -109,34 +109,6 @@ export async function run(): Promise<void> {
|
||||
return numericId
|
||||
})
|
||||
|
||||
// if the length of artifactIds exactly 1 fetch the latest artifact by its name and check the ID
|
||||
if (artifactIds.length === 1) {
|
||||
core.debug(
|
||||
`Only one artifact ID provided. Fetching latest artifact by its name and checking the ID`
|
||||
)
|
||||
const getArtifactResponse = await artifactClient.getArtifact(
|
||||
inputs.name,
|
||||
{...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 = await artifactClient.listArtifacts({
|
||||
latest: true,
|
||||
@ -146,7 +118,6 @@ export async function run(): Promise<void> {
|
||||
artifacts = listArtifactResponse.artifacts.filter(artifact =>
|
||||
artifactIds.includes(artifact.id)
|
||||
)
|
||||
}
|
||||
|
||||
if (artifacts.length === 0) {
|
||||
throw new Error(`None of the provided artifact IDs were found`)
|
||||
|
Loading…
Reference in New Issue
Block a user