Add new option to specify behavior if no files found (#104)

* Add new option to specify behavior if no files found
pull/108/head
Konrad Pabjan 2020-07-31 17:27:37 +02:00 committed by GitHub
parent 5f948bc1f0
commit 5ba29a7d5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 188 additions and 25 deletions

View File

@ -88,6 +88,18 @@ Relative and absolute file paths are both allowed. Relative paths are rooted aga
The [@actions/artifact](https://github.com/actions/toolkit/tree/main/packages/artifact) package is used internally to handle most of the logic around uploading an artifact. There is extra documentation around upload limitations and behavior in the toolkit repo that is worth checking out.
### Customization if no files are found
If a path (or paths), result in no files being found for the artifact, the action will succeed but print out a warning. In certain scenarios it may be desirable to fail the action or suppress the warning. The `if-no-files-found` option allows you to customize the behavior of the action if no files are found.
```yaml
- uses: actions/upload-artifact@v2
with:
name: my-artifact
path: path/to/artifact/
if-no-files-found: error # 'warn' or 'ignore' are also available, defaults to `warn`
```
### Conditional Artifact Upload
To upload artifacts only when the previous step of a job failed, use [`if: failure()`](https://help.github.com/en/articles/contexts-and-expression-syntax-for-github-actions#job-status-check-functions):

View File

@ -4,10 +4,19 @@ author: 'GitHub'
inputs:
name:
description: 'Artifact name'
required: false
default: 'artifact'
path:
description: 'A file, directory or wildcard pattern that describes what to upload'
required: true
if-no-files-found:
description: >
The desired behavior if no files are found using the provided path.
Available Options:
warn: Output a warning but do not fail the action
error: Fail the action with an error message
ignore: Do not output any warnings or errors, the action does not fail
default: 'warn'
runs:
using: 'node12'
main: 'dist/index.js'

85
dist/index.js vendored
View File

@ -3987,25 +3987,39 @@ var __importStar = (this && this.__importStar) || function (mod) {
Object.defineProperty(exports, "__esModule", { value: true });
const core = __importStar(__webpack_require__(470));
const artifact_1 = __webpack_require__(214);
const constants_1 = __webpack_require__(694);
const search_1 = __webpack_require__(575);
const input_helper_1 = __webpack_require__(583);
const constants_1 = __webpack_require__(694);
function run() {
return __awaiter(this, void 0, void 0, function* () {
try {
const name = core.getInput(constants_1.Inputs.Name, { required: false });
const path = core.getInput(constants_1.Inputs.Path, { required: true });
const searchResult = yield search_1.findFilesToUpload(path);
const inputs = input_helper_1.getInputs();
const searchResult = yield search_1.findFilesToUpload(inputs.searchPath);
if (searchResult.filesToUpload.length === 0) {
core.warning(`No files were found for the provided path: ${path}. No artifacts will be uploaded.`);
// No files were found, different use cases warrant different types of behavior if nothing is found
switch (inputs.ifNoFilesFound) {
case constants_1.NoFileOptions.warn: {
core.warning(`No files were found with the provided path: ${inputs.searchPath}. No artifacts will be uploaded.`);
break;
}
case constants_1.NoFileOptions.error: {
core.setFailed(`No files were found with the provided path: ${inputs.searchPath}. No artifacts will be uploaded.`);
break;
}
case constants_1.NoFileOptions.ignore: {
core.info(`No files were found with the provided path: ${inputs.searchPath}. No artifacts will be uploaded.`);
break;
}
}
}
else {
core.info(`With the provided path, there will be ${searchResult.filesToUpload.length} files uploaded`);
core.info(`With the provided path, there will be ${searchResult.filesToUpload.length} file(s) uploaded`);
core.debug(`Root artifact directory is ${searchResult.rootDirectory}`);
const artifactClient = artifact_1.create();
const options = {
continueOnError: false
};
const uploadResponse = yield artifactClient.uploadArtifact(name || constants_1.getDefaultArtifactName(), searchResult.filesToUpload, searchResult.rootDirectory, options);
const uploadResponse = yield artifactClient.uploadArtifact(inputs.artifactName, searchResult.filesToUpload, searchResult.rootDirectory, options);
if (uploadResponse.failedItems.length > 0) {
core.setFailed(`An error was encountered when uploading ${uploadResponse.artifactName}. There were ${uploadResponse.failedItems.length} items that failed to upload.`);
}
@ -6335,6 +6349,43 @@ function findFilesToUpload(searchPath, globOptions) {
exports.findFilesToUpload = findFilesToUpload;
/***/ }),
/***/ 583:
/***/ (function(__unusedmodule, exports, __webpack_require__) {
"use strict";
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const core = __importStar(__webpack_require__(470));
const constants_1 = __webpack_require__(694);
/**
* Helper to get all the inputs for the action
*/
function getInputs() {
const name = core.getInput(constants_1.Inputs.Name);
const path = core.getInput(constants_1.Inputs.Path, { required: true });
const ifNoFilesFound = core.getInput(constants_1.Inputs.IfNoFilesFound);
const noFileBehavior = constants_1.NoFileOptions[ifNoFilesFound];
if (!noFileBehavior) {
core.setFailed(`Unrecognized ${constants_1.Inputs.IfNoFilesFound} input. Provided: ${ifNoFilesFound}. Available options: ${Object.keys(constants_1.NoFileOptions)}`);
}
return {
artifactName: name,
searchPath: path,
ifNoFilesFound: noFileBehavior
};
}
exports.getInputs = getInputs;
/***/ }),
/***/ 590:
@ -7249,11 +7300,23 @@ var Inputs;
(function (Inputs) {
Inputs["Name"] = "name";
Inputs["Path"] = "path";
Inputs["IfNoFilesFound"] = "if-no-files-found";
})(Inputs = exports.Inputs || (exports.Inputs = {}));
function getDefaultArtifactName() {
return 'artifact';
}
exports.getDefaultArtifactName = getDefaultArtifactName;
var NoFileOptions;
(function (NoFileOptions) {
/**
* Default. Output a warning but do not fail the action
*/
NoFileOptions["warn"] = "warn";
/**
* Fail the action with an error message
*/
NoFileOptions["error"] = "error";
/**
* Do not output any warnings or errors, the action does not fail
*/
NoFileOptions["ignore"] = "ignore";
})(NoFileOptions = exports.NoFileOptions || (exports.NoFileOptions = {}));
/***/ }),

View File

@ -1,8 +1,22 @@
export enum Inputs {
Name = 'name',
Path = 'path'
Path = 'path',
IfNoFilesFound = 'if-no-files-found'
}
export function getDefaultArtifactName(): string {
return 'artifact'
export enum NoFileOptions {
/**
* 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'
}

30
src/input-helper.ts Normal file
View File

@ -0,0 +1,30 @@
import * as core from '@actions/core'
import {Inputs, NoFileOptions} from './constants'
import {UploadInputs} from './upload-inputs'
/**
* Helper to get all the inputs for the action
*/
export function getInputs(): UploadInputs {
const name = core.getInput(Inputs.Name)
const path = core.getInput(Inputs.Path, {required: true})
const ifNoFilesFound = core.getInput(Inputs.IfNoFilesFound)
const noFileBehavior: NoFileOptions = NoFileOptions[ifNoFilesFound]
if (!noFileBehavior) {
core.setFailed(
`Unrecognized ${
Inputs.IfNoFilesFound
} input. Provided: ${ifNoFilesFound}. Available options: ${Object.keys(
NoFileOptions
)}`
)
}
return {
artifactName: name,
searchPath: path,
ifNoFilesFound: noFileBehavior
}
}

View File

@ -1,21 +1,38 @@
import * as core from '@actions/core'
import {create, UploadOptions} from '@actions/artifact'
import {Inputs, getDefaultArtifactName} from './constants'
import {findFilesToUpload} from './search'
import {getInputs} from './input-helper'
import {NoFileOptions} from './constants'
async function run(): Promise<void> {
try {
const name = core.getInput(Inputs.Name, {required: false})
const path = core.getInput(Inputs.Path, {required: true})
const searchResult = await findFilesToUpload(path)
const inputs = getInputs()
const searchResult = await findFilesToUpload(inputs.searchPath)
if (searchResult.filesToUpload.length === 0) {
core.warning(
`No files were found for the provided path: ${path}. No artifacts will be uploaded.`
)
// No files were found, different use cases warrant different types of behavior if nothing is found
switch (inputs.ifNoFilesFound) {
case NoFileOptions.warn: {
core.warning(
`No files were found with the provided path: ${inputs.searchPath}. No artifacts will be uploaded.`
)
break
}
case NoFileOptions.error: {
core.setFailed(
`No files were found with the provided path: ${inputs.searchPath}. No artifacts will be uploaded.`
)
break
}
case NoFileOptions.ignore: {
core.info(
`No files were found with the provided path: ${inputs.searchPath}. No artifacts will be uploaded.`
)
break
}
}
} else {
core.info(
`With the provided path, there will be ${searchResult.filesToUpload.length} files uploaded`
`With the provided path, there will be ${searchResult.filesToUpload.length} file(s) uploaded`
)
core.debug(`Root artifact directory is ${searchResult.rootDirectory}`)
@ -24,7 +41,7 @@ async function run(): Promise<void> {
continueOnError: false
}
const uploadResponse = await artifactClient.uploadArtifact(
name || getDefaultArtifactName(),
inputs.artifactName,
searchResult.filesToUpload,
searchResult.rootDirectory,
options

18
src/upload-inputs.ts Normal file
View File

@ -0,0 +1,18 @@
import {NoFileOptions} from './constants'
export interface UploadInputs {
/**
* The name of the artifact that will be uploaded
*/
artifactName: string
/**
* The search path used to describe what to upload as part of the artifact
*/
searchPath: string
/**
* The desired behavior if no files are found with the provided search path
*/
ifNoFilesFound: NoFileOptions
}