From 61eb988d37f3de6cfe569b0603e5349e40b7d785 Mon Sep 17 00:00:00 2001 From: Dario Curreri Date: Sat, 16 Dec 2023 14:53:22 +0100 Subject: [PATCH] Add `if-not-found` parameter --- .github/workflows/test.yml | 93 ++++++++++++++++++++++++++++++++++++++ README.md | 9 ++++ action.yml | 4 ++ dist/index.js | 58 +++++++++++++++++++++--- src/constants.ts | 20 +++++++- src/download-artifact.ts | 61 +++++++++++++++++++------ 6 files changed, 222 insertions(+), 23 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3209828..60b5edd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -106,3 +106,96 @@ jobs: Write-Error "File contents of downloaded artifacts are incorrect" } shell: pwsh + + if-not-found-with-name: + name: Test `if-not-found` param wih name specified + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v3 + + - name: Verify not existing artifact with default value + id: default + continue-on-error: true + uses: ./ + with: + name: not-existing-name + + - name: Check default + run: ${{ steps.default.outcome == 'failure' }} + + - name: Verify not existing artifact `error` + id: error + continue-on-error: true + uses: ./ + with: + name: not-existing-name + if-not-found: error + + - name: Check `error` + run: ${{ steps.error.outcome == 'failure' }} + + - name: Verify not existing artifact `warning` + id: warning + uses: ./ + with: + name: not-existing-name + if-not-found: warn + + - name: Check `warning` + run: ${{ steps.warning.outcome == 'success' }} + + - name: Verify not existing artifact `ignore` + id: ignore + uses: ./ + with: + name: not-existing-name + if-not-found: ignore + + - name: Check `ignore` + run: ${{ steps.ignore.outcome == 'success' }} + + if-not-found-without-name: + name: Test `if-not-found` param wih name specified + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v3 + + - name: Verify not existing artifact with default value + id: default + continue-on-error: true + uses: ./ + + - name: Check default + run: ${{ steps.default.outcome == 'failure' }} + + - name: Verify not existing artifact `error` + id: error + continue-on-error: true + uses: ./ + with: + if-not-found: error + + - name: Check `error` + run: ${{ steps.error.outcome == 'failure' }} + + - name: Verify not existing artifact `warning` + id: warning + uses: ./ + with: + if-not-found: warn + + - name: Check `warning` + run: ${{ steps.warning.outcome == 'success' }} + + - name: Verify not existing artifact `ignore` + id: ignore + uses: ./ + with: + if-not-found: ignore + + - name: Check `ignore` + run: ${{ steps.ignore.outcome == 'success' }} diff --git a/README.md b/README.md index 7c0e3f7..6984e9c 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,15 @@ steps: run: ls -R your/destination/dir ``` +## Name not found + +By default, if the name you provided doesn't exists or there are no artifacts, the action will raise an error. +It is possible to change this behavior using the `if-not-found` optional parameter: + +- `error`: output a warning but do not fail the action (default) +- `warning`: fail the action with an error message +- `ignore`: do not output any warnings or errors, the action does not fail + ### Download All Artifacts diff --git a/action.yml b/action.yml index fdae197..9c1c9ec 100644 --- a/action.yml +++ b/action.yml @@ -23,6 +23,10 @@ inputs: If github-token is specified, this is the run that artifacts will be downloaded from.' required: false default: ${{ github.run_id }} + if-not-found: + description: 'How to behave if no artifact(s) is(are) found' + required: false + default: error outputs: download-path: description: 'Path of artifact download' diff --git a/dist/index.js b/dist/index.js index 6fbe82f..ce54ba4 100644 --- a/dist/index.js +++ b/dist/index.js @@ -120958,7 +120958,7 @@ utils.walkdir = function(dirpath, base, callback) { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.Outputs = exports.Inputs = void 0; +exports.NotFoundOptions = exports.Outputs = exports.Inputs = void 0; var Inputs; (function (Inputs) { Inputs["Name"] = "name"; @@ -120966,11 +120966,27 @@ var Inputs; Inputs["GitHubToken"] = "github-token"; Inputs["Repository"] = "repository"; Inputs["RunID"] = "run-id"; + Inputs["IfNotFound"] = "if-not-found"; })(Inputs = exports.Inputs || (exports.Inputs = {})); var Outputs; (function (Outputs) { Outputs["DownloadPath"] = "download-path"; })(Outputs = exports.Outputs || (exports.Outputs = {})); +var NotFoundOptions; +(function (NotFoundOptions) { + /** + * Default. Output a warning but do not fail the action + */ + NotFoundOptions["warn"] = "warn"; + /** + * Fail the action with an error message + */ + NotFoundOptions["error"] = "error"; + /** + * Do not output any warnings or errors, the action does not fail + */ + NotFoundOptions["ignore"] = "ignore"; +})(NotFoundOptions = exports.NotFoundOptions || (exports.NotFoundOptions = {})); /***/ }), @@ -121024,6 +121040,33 @@ exports.chunk = (arr, n) => arr.reduce((acc, cur, i) => { acc[index] = [...(acc[index] || []), cur]; return acc; }, []); +function checkIfNotFoundOption(if_not_found, message) { + switch (if_not_found) { + case constants_1.NotFoundOptions.warn: { + core.warning(message); + break; + } + case constants_1.NotFoundOptions.error: { + core.setFailed(message); + break; + } + case constants_1.NotFoundOptions.ignore: { + core.info(message); + break; + } + } +} +function getArtifact(name, if_not_found, options) { + return __awaiter(this, void 0, void 0, function* () { + try { + return yield artifact_1.default.getArtifact(name, options); + } + catch (err) { + const message = `Artifact '${name}' not found`; + checkIfNotFoundOption(if_not_found, message); + } + }); +} function run() { return __awaiter(this, void 0, void 0, function* () { const inputs = { @@ -121031,6 +121074,7 @@ function run() { path: core.getInput(constants_1.Inputs.Path, { required: false }), token: core.getInput(constants_1.Inputs.GitHubToken, { required: false }), repository: core.getInput(constants_1.Inputs.Repository, { required: false }), + if_not_found: core.getInput(constants_1.Inputs.IfNotFound, { required: false }), runID: parseInt(core.getInput(constants_1.Inputs.RunID, { required: false })) }; if (!inputs.path) { @@ -121058,18 +121102,18 @@ function run() { let artifacts = []; if (isSingleArtifactDownload) { core.info(`Downloading single artifact`); - const { artifact: targetArtifact } = yield artifact_1.default.getArtifact(inputs.name, options); - if (!targetArtifact) { - throw new Error(`Artifact '${inputs.name}' not found`); + const targetArtifact = yield getArtifact(inputs.name, inputs.if_not_found, options); + if (targetArtifact) { + core.debug(`Found named artifact '${inputs.name}' (ID: ${targetArtifact.artifact.id}, Size: ${targetArtifact.artifact.size})`); + artifacts = [targetArtifact.artifact]; } - core.debug(`Found named artifact '${inputs.name}' (ID: ${targetArtifact.id}, Size: ${targetArtifact.size})`); - artifacts = [targetArtifact]; } else { core.info(`No input name specified, downloading all artifacts. Extra directory with the artifact name will be created for each download`); const listArtifactResponse = yield artifact_1.default.listArtifacts(Object.assign({ latest: true }, options)); if (listArtifactResponse.artifacts.length === 0) { - throw new Error(`No artifacts found for run '${inputs.runID}' in '${inputs.repository}'`); + const message = `No artifacts found for run '${inputs.runID}' in '${inputs.repository}'`; + checkIfNotFoundOption(inputs.if_not_found, message); } core.debug(`Found ${listArtifactResponse.artifacts.length} artifacts`); artifacts = listArtifactResponse.artifacts; diff --git a/src/constants.ts b/src/constants.ts index 440d1dc..7669482 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -3,9 +3,27 @@ export enum Inputs { Path = 'path', GitHubToken = 'github-token', Repository = 'repository', - RunID = 'run-id' + RunID = 'run-id', + IfNotFound = 'if-not-found' } export enum Outputs { DownloadPath = 'download-path' } + +export enum NotFoundOptions { + /** + * Default. Output a warning but do not fail the action + */ + warn = 'warn', + + /** + * Fail the action with an error message + */ + error = 'error', + + /** + * Do not output any warnings or errors, the action does not fail + */ + ignore = 'ignore' +} diff --git a/src/download-artifact.ts b/src/download-artifact.ts index 4055762..f94fa65 100644 --- a/src/download-artifact.ts +++ b/src/download-artifact.ts @@ -2,8 +2,12 @@ import * as os from 'os' import * as path from 'path' import * as core from '@actions/core' import artifactClient from '@actions/artifact' -import type {Artifact, FindOptions} from '@actions/artifact' -import {Inputs, Outputs} from './constants' +import type { + Artifact, + FindOptions, + GetArtifactResponse +} from '@actions/artifact' +import {Inputs, Outputs, NotFoundOptions} from './constants' const PARALLEL_DOWNLOADS = 5 @@ -14,12 +18,43 @@ export const chunk = (arr: T[], n: number): T[][] => return acc }, [] as T[][]) +function checkIfNotFoundOption(if_not_found: string, message: string) { + switch (if_not_found) { + case NotFoundOptions.warn: { + core.warning(message) + break + } + case NotFoundOptions.error: { + core.setFailed(message) + break + } + case NotFoundOptions.ignore: { + core.info(message) + break + } + } +} + +async function getArtifact( + name: string, + if_not_found: string, + options: FindOptions +): Promise { + try { + return await artifactClient.getArtifact(name, options) + } catch (err) { + const message = `Artifact '${name}' not found` + checkIfNotFoundOption(if_not_found, message) + } +} + async function run(): Promise { const inputs = { name: core.getInput(Inputs.Name, {required: false}), path: core.getInput(Inputs.Path, {required: false}), token: core.getInput(Inputs.GitHubToken, {required: false}), repository: core.getInput(Inputs.Repository, {required: false}), + if_not_found: core.getInput(Inputs.IfNotFound, {required: false}), runID: parseInt(core.getInput(Inputs.RunID, {required: false})) } @@ -57,20 +92,18 @@ async function run(): Promise { if (isSingleArtifactDownload) { core.info(`Downloading single artifact`) - const {artifact: targetArtifact} = await artifactClient.getArtifact( + const targetArtifact = await getArtifact( inputs.name, + inputs.if_not_found, options ) - if (!targetArtifact) { - throw new Error(`Artifact '${inputs.name}' not found`) + if (targetArtifact) { + core.debug( + `Found named artifact '${inputs.name}' (ID: ${targetArtifact.artifact.id}, Size: ${targetArtifact.artifact.size})` + ) + artifacts = [targetArtifact.artifact] } - - core.debug( - `Found named artifact '${inputs.name}' (ID: ${targetArtifact.id}, Size: ${targetArtifact.size})` - ) - - artifacts = [targetArtifact] } else { core.info( `No input name specified, downloading all artifacts. Extra directory with the artifact name will be created for each download` @@ -82,11 +115,9 @@ async function run(): Promise { }) if (listArtifactResponse.artifacts.length === 0) { - throw new Error( - `No artifacts found for run '${inputs.runID}' in '${inputs.repository}'` - ) + const message = `No artifacts found for run '${inputs.runID}' in '${inputs.repository}'` + checkIfNotFoundOption(inputs.if_not_found, message) } - core.debug(`Found ${listArtifactResponse.artifacts.length} artifacts`) artifacts = listArtifactResponse.artifacts }