Merge 5442a4e8a3867a1c14be1ee3a04c4f47b261d632 into 9243a41f9771b17cd9810058d578db51f5962d1e
This commit is contained in:
commit
5b73ce3676
@ -67,6 +67,14 @@ steps:
|
|||||||
!path/**/*.tmp
|
!path/**/*.tmp
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Upload multiple artifacts using a JSON string
|
||||||
|
```yaml
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: '["my-artifact", "my-artifact-2"]'
|
||||||
|
path: '["path/to/artifact/1/", "path/to/artifact/2/"]'
|
||||||
|
```
|
||||||
|
|
||||||
For supported wildcards along with behavior and documentation, see [@actions/glob](https://github.com/actions/toolkit/tree/main/packages/glob) which is used internally to search for files.
|
For supported wildcards along with behavior and documentation, see [@actions/glob](https://github.com/actions/toolkit/tree/main/packages/glob) which is used internally to search for files.
|
||||||
|
|
||||||
If a wildcard pattern is used, the path hierarchy will be preserved after the first wildcard pattern.
|
If a wildcard pattern is used, the path hierarchy will be preserved after the first wildcard pattern.
|
||||||
|
@ -3,8 +3,7 @@ description: 'Upload a build artifact that can be used by subsequent workflow st
|
|||||||
author: 'GitHub'
|
author: 'GitHub'
|
||||||
inputs:
|
inputs:
|
||||||
name:
|
name:
|
||||||
description: 'Artifact name'
|
description: 'Artifact name, default is "artifact"'
|
||||||
default: 'artifact'
|
|
||||||
path:
|
path:
|
||||||
description: 'A file, directory or wildcard pattern that describes what to upload'
|
description: 'A file, directory or wildcard pattern that describes what to upload'
|
||||||
required: true
|
required: true
|
||||||
|
73
dist/index.js
vendored
73
dist/index.js
vendored
@ -4028,20 +4028,24 @@ function run() {
|
|||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
const inputs = input_helper_1.getInputs();
|
const inputs = input_helper_1.getInputs();
|
||||||
const searchResult = yield search_1.findFilesToUpload(inputs.searchPath);
|
for (let i = 0; i < inputs.searchPath.length; i++) {
|
||||||
|
const searchPath = inputs.searchPath[i];
|
||||||
|
const artifactName = inputs.artifactName[i];
|
||||||
|
const retentionDays = inputs.retentionDays[i];
|
||||||
|
const searchResult = yield search_1.findFilesToUpload(searchPath);
|
||||||
if (searchResult.filesToUpload.length === 0) {
|
if (searchResult.filesToUpload.length === 0) {
|
||||||
// No files were found, different use cases warrant different types of behavior if nothing is found
|
// No files were found, different use cases warrant different types of behavior if nothing is found
|
||||||
switch (inputs.ifNoFilesFound) {
|
switch (inputs.ifNoFilesFound) {
|
||||||
case constants_1.NoFileOptions.warn: {
|
case constants_1.NoFileOptions.warn: {
|
||||||
core.warning(`No files were found with the provided path: ${inputs.searchPath}. No artifacts will be uploaded.`);
|
core.warning(`No files were found with the provided path: ${searchPath}. No artifacts will be uploaded.`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case constants_1.NoFileOptions.error: {
|
case constants_1.NoFileOptions.error: {
|
||||||
core.setFailed(`No files were found with the provided path: ${inputs.searchPath}. No artifacts will be uploaded.`);
|
core.setFailed(`No files were found with the provided path: ${searchPath}. No artifacts will be uploaded.`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case constants_1.NoFileOptions.ignore: {
|
case constants_1.NoFileOptions.ignore: {
|
||||||
core.info(`No files were found with the provided path: ${inputs.searchPath}. No artifacts will be uploaded.`);
|
core.info(`No files were found with the provided path: ${searchPath}. No artifacts will be uploaded.`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4057,10 +4061,10 @@ function run() {
|
|||||||
const options = {
|
const options = {
|
||||||
continueOnError: false
|
continueOnError: false
|
||||||
};
|
};
|
||||||
if (inputs.retentionDays) {
|
if (retentionDays) {
|
||||||
options.retentionDays = inputs.retentionDays;
|
options.retentionDays = retentionDays;
|
||||||
}
|
}
|
||||||
const uploadResponse = yield artifactClient.uploadArtifact(inputs.artifactName, searchResult.filesToUpload, searchResult.rootDirectory, options);
|
const uploadResponse = yield artifactClient.uploadArtifact(artifactName, searchResult.filesToUpload, searchResult.rootDirectory, options);
|
||||||
if (uploadResponse.failedItems.length > 0) {
|
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.`);
|
core.setFailed(`An error was encountered when uploading ${uploadResponse.artifactName}. There were ${uploadResponse.failedItems.length} items that failed to upload.`);
|
||||||
}
|
}
|
||||||
@ -4069,6 +4073,7 @@ function run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
core.setFailed(err.message);
|
core.setFailed(err.message);
|
||||||
}
|
}
|
||||||
@ -6576,26 +6581,62 @@ const constants_1 = __webpack_require__(694);
|
|||||||
function getInputs() {
|
function getInputs() {
|
||||||
const name = core.getInput(constants_1.Inputs.Name);
|
const name = core.getInput(constants_1.Inputs.Name);
|
||||||
const path = core.getInput(constants_1.Inputs.Path, { required: true });
|
const path = core.getInput(constants_1.Inputs.Path, { required: true });
|
||||||
|
const searchPath = parseFromJSON(path) || [path];
|
||||||
|
const defaultArtifactName = 'artifact';
|
||||||
|
// Accepts an individual value or an array as input, if array sizes don't match, use default value instead
|
||||||
|
const artifactName = parseParamaterToArrayFromInput(name, searchPath.length, defaultArtifactName, (defaultInput, index) => {
|
||||||
|
const artifactIndexStr = index == 0 ? '' : `_${index + 1}`;
|
||||||
|
return `${defaultInput}${artifactIndexStr}`;
|
||||||
|
});
|
||||||
|
// Accepts an individual value or an array as input
|
||||||
|
const retention = core.getInput(constants_1.Inputs.RetentionDays);
|
||||||
|
const retentionDays = parseParamaterToArrayFromInput(retention, searchPath.length, undefined, defaultInput => defaultInput).map(parseRetentionDays);
|
||||||
const ifNoFilesFound = core.getInput(constants_1.Inputs.IfNoFilesFound);
|
const ifNoFilesFound = core.getInput(constants_1.Inputs.IfNoFilesFound);
|
||||||
const noFileBehavior = constants_1.NoFileOptions[ifNoFilesFound];
|
const noFileBehavior = constants_1.NoFileOptions[ifNoFilesFound];
|
||||||
if (!noFileBehavior) {
|
if (!noFileBehavior) {
|
||||||
core.setFailed(`Unrecognized ${constants_1.Inputs.IfNoFilesFound} input. Provided: ${ifNoFilesFound}. Available options: ${Object.keys(constants_1.NoFileOptions)}`);
|
core.setFailed(`Unrecognized ${constants_1.Inputs.IfNoFilesFound} input. Provided: ${ifNoFilesFound}. Available options: ${Object.keys(constants_1.NoFileOptions)}`);
|
||||||
}
|
}
|
||||||
const inputs = {
|
const inputs = {
|
||||||
artifactName: name,
|
artifactName,
|
||||||
searchPath: path,
|
searchPath,
|
||||||
|
retentionDays,
|
||||||
ifNoFilesFound: noFileBehavior
|
ifNoFilesFound: noFileBehavior
|
||||||
};
|
};
|
||||||
const retentionDaysStr = core.getInput(constants_1.Inputs.RetentionDays);
|
|
||||||
if (retentionDaysStr) {
|
|
||||||
inputs.retentionDays = parseInt(retentionDaysStr);
|
|
||||||
if (isNaN(inputs.retentionDays)) {
|
|
||||||
core.setFailed('Invalid retention-days');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return inputs;
|
return inputs;
|
||||||
}
|
}
|
||||||
exports.getInputs = getInputs;
|
exports.getInputs = getInputs;
|
||||||
|
function parseParamaterToArrayFromInput(input, requiredLength, defaultInput, defaultFunc) {
|
||||||
|
// Accepts an individual value or an array as input, if array size doesn't match the required length, fill the rest with a default value
|
||||||
|
const inputArray = parseFromJSON(input || '[]');
|
||||||
|
if (inputArray != null) {
|
||||||
|
// If a stringified JSON array is provided, use it and concat it with the default when required
|
||||||
|
return inputArray.concat(Array.from({ length: Math.max(0, requiredLength - inputArray.length) }, (_, index) => defaultFunc(defaultInput, index)));
|
||||||
|
}
|
||||||
|
// If a string is provided, fill the array with that value
|
||||||
|
return Array.from({ length: Math.max(0, requiredLength) }, (_, index) => defaultFunc(input || defaultInput, index));
|
||||||
|
}
|
||||||
|
function parseFromJSON(jsonStr) {
|
||||||
|
try {
|
||||||
|
const json = JSON.parse(jsonStr);
|
||||||
|
if (Array.isArray(json)) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (_err) {
|
||||||
|
// Input wasn't a stringified JSON array (string[]), return undefined to signal an invalid JSON was provided
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
function parseRetentionDays(retentionDaysStr) {
|
||||||
|
if (retentionDaysStr != null) {
|
||||||
|
const retentionDays = parseInt(retentionDaysStr);
|
||||||
|
if (isNaN(retentionDays)) {
|
||||||
|
core.setFailed('Invalid retention-days');
|
||||||
|
}
|
||||||
|
return retentionDays;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
@ -9,6 +9,29 @@ export function getInputs(): UploadInputs {
|
|||||||
const name = core.getInput(Inputs.Name)
|
const name = core.getInput(Inputs.Name)
|
||||||
const path = core.getInput(Inputs.Path, {required: true})
|
const path = core.getInput(Inputs.Path, {required: true})
|
||||||
|
|
||||||
|
const searchPath = parseFromJSON(path) || [path]
|
||||||
|
|
||||||
|
const defaultArtifactName = 'artifact'
|
||||||
|
// Accepts an individual value or an array as input, if array sizes don't match, use default value instead
|
||||||
|
const artifactName = parseParamaterToArrayFromInput(
|
||||||
|
name,
|
||||||
|
searchPath.length,
|
||||||
|
defaultArtifactName,
|
||||||
|
(defaultInput, index) => {
|
||||||
|
const artifactIndexStr = index == 0 ? '' : `_${index + 1}`
|
||||||
|
return `${defaultInput}${artifactIndexStr}`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Accepts an individual value or an array as input
|
||||||
|
const retention = core.getInput(Inputs.RetentionDays)
|
||||||
|
const retentionDays = parseParamaterToArrayFromInput(
|
||||||
|
retention,
|
||||||
|
searchPath.length,
|
||||||
|
undefined,
|
||||||
|
defaultInput => defaultInput
|
||||||
|
).map(parseRetentionDays)
|
||||||
|
|
||||||
const ifNoFilesFound = core.getInput(Inputs.IfNoFilesFound)
|
const ifNoFilesFound = core.getInput(Inputs.IfNoFilesFound)
|
||||||
const noFileBehavior: NoFileOptions = NoFileOptions[ifNoFilesFound]
|
const noFileBehavior: NoFileOptions = NoFileOptions[ifNoFilesFound]
|
||||||
|
|
||||||
@ -23,18 +46,62 @@ export function getInputs(): UploadInputs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const inputs = {
|
const inputs = {
|
||||||
artifactName: name,
|
artifactName,
|
||||||
searchPath: path,
|
searchPath,
|
||||||
|
retentionDays,
|
||||||
ifNoFilesFound: noFileBehavior
|
ifNoFilesFound: noFileBehavior
|
||||||
} as UploadInputs
|
} as UploadInputs
|
||||||
|
|
||||||
const retentionDaysStr = core.getInput(Inputs.RetentionDays)
|
|
||||||
if (retentionDaysStr) {
|
|
||||||
inputs.retentionDays = parseInt(retentionDaysStr)
|
|
||||||
if (isNaN(inputs.retentionDays)) {
|
|
||||||
core.setFailed('Invalid retention-days')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return inputs
|
return inputs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseParamaterToArrayFromInput(
|
||||||
|
input: string | undefined,
|
||||||
|
requiredLength: number,
|
||||||
|
defaultInput: string | undefined,
|
||||||
|
defaultFunc: (
|
||||||
|
defaultInput: string | undefined,
|
||||||
|
index: number
|
||||||
|
) => string | undefined
|
||||||
|
): (string | undefined)[] {
|
||||||
|
// Accepts an individual value or an array as input, if array size doesn't match the required length, fill the rest with a default value
|
||||||
|
const inputArray = parseFromJSON(input || '[]')
|
||||||
|
if (inputArray != null) {
|
||||||
|
// If a stringified JSON array is provided, use it and concat it with the default when required
|
||||||
|
return (<(string | undefined)[]>inputArray).concat(
|
||||||
|
Array.from(
|
||||||
|
{length: Math.max(0, requiredLength - inputArray.length)},
|
||||||
|
(_, index) => defaultFunc(defaultInput, index)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// If a string is provided, fill the array with that value
|
||||||
|
return Array.from({length: Math.max(0, requiredLength)}, (_, index) =>
|
||||||
|
defaultFunc(input || defaultInput, index)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseFromJSON(jsonStr: string): string[] | undefined {
|
||||||
|
try {
|
||||||
|
const json = <string[]>JSON.parse(jsonStr)
|
||||||
|
if (Array.isArray(json)) {
|
||||||
|
return json
|
||||||
|
}
|
||||||
|
} catch (_err) {
|
||||||
|
// Input wasn't a stringified JSON array (string[]), return undefined to signal an invalid JSON was provided
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseRetentionDays(
|
||||||
|
retentionDaysStr: string | undefined
|
||||||
|
): number | undefined {
|
||||||
|
if (retentionDaysStr != null) {
|
||||||
|
const retentionDays = parseInt(retentionDaysStr)
|
||||||
|
if (isNaN(retentionDays)) {
|
||||||
|
core.setFailed('Invalid retention-days')
|
||||||
|
}
|
||||||
|
return retentionDays
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
@ -7,25 +7,31 @@ import {NoFileOptions} from './constants'
|
|||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const inputs = getInputs()
|
const inputs = getInputs()
|
||||||
const searchResult = await findFilesToUpload(inputs.searchPath)
|
|
||||||
|
for (let i = 0; i < inputs.searchPath.length; i++) {
|
||||||
|
const searchPath = inputs.searchPath[i]
|
||||||
|
const artifactName = inputs.artifactName[i]
|
||||||
|
const retentionDays = inputs.retentionDays[i]
|
||||||
|
|
||||||
|
const searchResult = await findFilesToUpload(searchPath)
|
||||||
if (searchResult.filesToUpload.length === 0) {
|
if (searchResult.filesToUpload.length === 0) {
|
||||||
// No files were found, different use cases warrant different types of behavior if nothing is found
|
// No files were found, different use cases warrant different types of behavior if nothing is found
|
||||||
switch (inputs.ifNoFilesFound) {
|
switch (inputs.ifNoFilesFound) {
|
||||||
case NoFileOptions.warn: {
|
case NoFileOptions.warn: {
|
||||||
core.warning(
|
core.warning(
|
||||||
`No files were found with the provided path: ${inputs.searchPath}. No artifacts will be uploaded.`
|
`No files were found with the provided path: ${searchPath}. No artifacts will be uploaded.`
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case NoFileOptions.error: {
|
case NoFileOptions.error: {
|
||||||
core.setFailed(
|
core.setFailed(
|
||||||
`No files were found with the provided path: ${inputs.searchPath}. No artifacts will be uploaded.`
|
`No files were found with the provided path: ${searchPath}. No artifacts will be uploaded.`
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case NoFileOptions.ignore: {
|
case NoFileOptions.ignore: {
|
||||||
core.info(
|
core.info(
|
||||||
`No files were found with the provided path: ${inputs.searchPath}. No artifacts will be uploaded.`
|
`No files were found with the provided path: ${searchPath}. No artifacts will be uploaded.`
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -47,12 +53,12 @@ async function run(): Promise<void> {
|
|||||||
const options: UploadOptions = {
|
const options: UploadOptions = {
|
||||||
continueOnError: false
|
continueOnError: false
|
||||||
}
|
}
|
||||||
if (inputs.retentionDays) {
|
if (retentionDays) {
|
||||||
options.retentionDays = inputs.retentionDays
|
options.retentionDays = retentionDays
|
||||||
}
|
}
|
||||||
|
|
||||||
const uploadResponse = await artifactClient.uploadArtifact(
|
const uploadResponse = await artifactClient.uploadArtifact(
|
||||||
inputs.artifactName,
|
artifactName,
|
||||||
searchResult.filesToUpload,
|
searchResult.filesToUpload,
|
||||||
searchResult.rootDirectory,
|
searchResult.rootDirectory,
|
||||||
options
|
options
|
||||||
@ -68,6 +74,7 @@ async function run(): Promise<void> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
core.setFailed(err.message)
|
core.setFailed(err.message)
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,12 @@ export interface UploadInputs {
|
|||||||
/**
|
/**
|
||||||
* The name of the artifact that will be uploaded
|
* The name of the artifact that will be uploaded
|
||||||
*/
|
*/
|
||||||
artifactName: string
|
artifactName: string[]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The search path used to describe what to upload as part of the artifact
|
* The search path used to describe what to upload as part of the artifact
|
||||||
*/
|
*/
|
||||||
searchPath: string
|
searchPath: string[]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The desired behavior if no files are found with the provided search path
|
* The desired behavior if no files are found with the provided search path
|
||||||
@ -19,5 +19,5 @@ export interface UploadInputs {
|
|||||||
/**
|
/**
|
||||||
* Duration after which artifact will expire in days
|
* Duration after which artifact will expire in days
|
||||||
*/
|
*/
|
||||||
retentionDays: number
|
retentionDays: (number | undefined)[]
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user