From 35e561c49c0fae30302d9ae9c4af790e333db66a Mon Sep 17 00:00:00 2001 From: initdc Date: Sat, 15 Oct 2022 10:03:48 +0000 Subject: [PATCH 1/4] feat: add upload one artifact per file Signed-off-by: initdc --- .github/workflows/test-per-file.yml | 98 +++++++++++++++++++++ dist/index.js | 129 ++++++++++++++++++++++++---- src/constants.ts | 4 +- src/input-helper.ts | 71 +++++++++++---- src/upload-artifact.ts | 94 +++++++++++++++++--- src/upload-inputs.ts | 19 +++- 6 files changed, 366 insertions(+), 49 deletions(-) create mode 100644 .github/workflows/test-per-file.yml diff --git a/.github/workflows/test-per-file.yml b/.github/workflows/test-per-file.yml new file mode 100644 index 00000000..1b56e1b3 --- /dev/null +++ b/.github/workflows/test-per-file.yml @@ -0,0 +1,98 @@ +name: Test Artifact Per File +on: + workflow_dispatch: + push: + branches: + - main + paths-ignore: + - '**.md' + pull_request: + paths-ignore: + - '**.md' + +jobs: + + build: + name: Build + + strategy: + matrix: + runs-on: [ubuntu-latest, macos-latest, windows-latest] + fail-fast: false + + runs-on: ${{ matrix.runs-on }} + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Set Node.js 12.x + uses: actions/setup-node@v1 + with: + node-version: 12.x + + - name: Install dependencies + run: npm ci + + - name: Compile + run: npm run build + + - name: npm test + run: npm test + + - name: Lint + run: npm run lint + + - name: Format + run: npm run format-check + + # Test end-to-end by uploading two artifacts and then downloading them + - name: Create artifact files + run: | + mkdir -p path/to/dir-1 + mkdir -p path/to/dir-2 + mkdir -p path/to/dir-3 + mkdir -p path/from/dir-1 + + echo > path/to/dir-1/file1.txt "path/to/dir-1/file1.txt" + echo > path/to/dir-2/file1.txt "path/to/dir-2/file1.txt" + echo > path/to/dir-2/file2.txt "path/to/dir-2/file2.txt" + echo > path/to/dir-3/file1.txt "path/to/dir-3/file1.txt" + echo > path/to/dir-3/file2.txt "path/to/dir-3/file2.txt" + echo > path/to/dir-3/file3.txt "path/to/dir-3/file3.txt" + echo > path/from/dir-1/file1.txt "path/from/dir-1/file1.txt" + + tar -zvcf path/to/dir-3/all.gz path/to/dir-3/* + + # Upload a single file artifact + - name: 'Upload artifact #1' + uses: ./ + with: + path: path/to/dir-1/file1.txt + artifact-per-file: true + + # Upload using a wildcard pattern, name should default to 'artifact' if not provided + - name: 'Upload artifact #2' + uses: ./ + with: + path: path/to/dir-2/* + artifact-per-file: true + artifact-name-rule: ${dir}-${base} + + # Upload a directory that contains a file that will be uploaded with GZip + - name: 'Upload artifact #3' + uses: ./ + with: + path: path/to/dir-3/*.gz + artifact-per-file: true + artifact-name-rule: ${dir}-${name}${ext} + + # Upload a directory that contains a file that will be uploaded with GZip + - name: 'Upload artifact #4' + uses: ./ + with: + path: | + path/**/dir*/ + !path/to/dir-3/*.gz + artifact-per-file: true + artifact-name-rule: ${{ matrix.runs-on }}-${base} diff --git a/dist/index.js b/dist/index.js index 2be9f506..68e2cd22 100644 --- a/dist/index.js +++ b/dist/index.js @@ -4733,12 +4733,16 @@ var __importStar = (this && this.__importStar) || function (mod) { result["default"] = mod; return result; }; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); const core = __importStar(__webpack_require__(470)); const artifact_1 = __webpack_require__(214); const search_1 = __webpack_require__(575); const input_helper_1 = __webpack_require__(583); const constants_1 = __webpack_require__(694); +const path_1 = __importDefault(__webpack_require__(622)); function run() { return __awaiter(this, void 0, void 0, function* () { try { @@ -4775,12 +4779,68 @@ function run() { if (inputs.retentionDays) { options.retentionDays = inputs.retentionDays; } - 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.`); + const artifactsName = inputs['artifactsName'] || 'artifacts'; + const artifactPerFile = inputs['artifactPerFile'] || false; + if (!artifactPerFile) { + const uploadResponse = yield artifactClient.uploadArtifact(artifactsName, 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.`); + } + else { + core.info(`Artifact ${uploadResponse.artifactName} has been successfully uploaded!`); + } } else { - core.info(`Artifact ${uploadResponse.artifactName} has been successfully uploaded!`); + const filesToUpload = searchResult.filesToUpload; + const SuccessedItems = []; + const FailedItems = []; + const artifactNameRule = inputs['artifactNameRule']; + for (let i = 0; i < filesToUpload.length; i++) { + const file = filesToUpload[i]; + core.info(file); + const pathObject = path_1.default.parse(file); + let artifactName = artifactNameRule; + for (const key of Object.keys(pathObject)) { + const re = `$\{${key}}`; + if (artifactNameRule.includes(re)) { + const value = pathObject[key] || ''; + artifactName = artifactName.replace(re, value); + } + } + if (artifactName.includes(path_1.default.sep)) { + core.warning(`${artifactName} includes ${path_1.default.sep}`); + artifactName = artifactName.split(path_1.default.sep).join('_'); + } + if (artifactName.includes(':')) { + core.warning(`${artifactName} includes :`); + artifactName = artifactName.split(':').join('-'); + } + core.info(artifactName); + const artifactItemExist = SuccessedItems.includes(artifactName); + if (artifactItemExist) { + const oldArtifactName = artifactName; + core.warning(`${artifactName} artifact alreay exist`); + artifactName = `${i}__${artifactName}`; + core.warning(`${oldArtifactName} => ${artifactName}`); + } + const uploadResponse = yield artifactClient.uploadArtifact(artifactName, [file], searchResult.rootDirectory, options); + if (uploadResponse.failedItems.length > 0) { + FailedItems.push(artifactName); + } + else { + SuccessedItems.push(artifactName); + } + } + if (FailedItems.length > 0) { + let errMsg = `${FailedItems.length} artifacts failed to upload, they were:\n`; + errMsg += FailedItems.join('\n'); + core.setFailed(errMsg); + } + if (SuccessedItems.length > 0) { + let infoMsg = `${SuccessedItems.length} artifacts has been successfully uploaded! They were:\n`; + infoMsg += SuccessedItems.join('\n'); + core.info(infoMsg); + } } } } @@ -7174,26 +7234,59 @@ 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 TRUE_MAP = ['true', 'True', 'TRUE']; + let artifactPerFile = false; + const artifactPerFileStr = core.getInput(constants_1.Inputs.ArtifactPerFile); + if (artifactPerFileStr) { + artifactPerFile = TRUE_MAP.includes(artifactPerFileStr) ? true : false; + } + let name = ''; + let artifactNameRule = ''; + if (!artifactPerFile) { + name = core.getInput(constants_1.Inputs.Name); + } + else { + artifactNameRule = core.getInput(constants_1.Inputs.ArtifactNameRule) || '${base}'; + } 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)}`); } - const inputs = { - artifactName: name, - searchPath: path, - 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'); + const typedInputs = (artifactPerFile) => { + const retentionDaysStr = core.getInput(constants_1.Inputs.RetentionDays); + if (!artifactPerFile) { + const inputs = { + artifactsName: name, + searchPath: path, + ifNoFilesFound: noFileBehavior + }; + if (retentionDaysStr) { + inputs.retentionDays = parseInt(retentionDaysStr); + if (isNaN(inputs.retentionDays)) { + core.setFailed('Invalid retention-days'); + } + } + return inputs; } - } - return inputs; + else { + const inputs = { + searchPath: path, + ifNoFilesFound: noFileBehavior, + artifactPerFile: artifactPerFile, + artifactNameRule: artifactNameRule + }; + if (retentionDaysStr) { + inputs.retentionDays = parseInt(retentionDaysStr); + if (isNaN(inputs.retentionDays)) { + core.setFailed('Invalid retention-days'); + } + } + return inputs; + } + }; + return typedInputs(artifactPerFile); } exports.getInputs = getInputs; @@ -8196,6 +8289,8 @@ var Inputs; Inputs["Path"] = "path"; Inputs["IfNoFilesFound"] = "if-no-files-found"; Inputs["RetentionDays"] = "retention-days"; + Inputs["ArtifactPerFile"] = "artifact-per-file"; + Inputs["ArtifactNameRule"] = "artifact-name-rule"; })(Inputs = exports.Inputs || (exports.Inputs = {})); var NoFileOptions; (function (NoFileOptions) { diff --git a/src/constants.ts b/src/constants.ts index 894ff4c0..b5c9fb0c 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -2,7 +2,9 @@ export enum Inputs { Name = 'name', Path = 'path', IfNoFilesFound = 'if-no-files-found', - RetentionDays = 'retention-days' + RetentionDays = 'retention-days', + ArtifactPerFile = 'artifact-per-file', + ArtifactNameRule = 'artifact-name-rule' } export enum NoFileOptions { diff --git a/src/input-helper.ts b/src/input-helper.ts index 83448236..5c381867 100644 --- a/src/input-helper.ts +++ b/src/input-helper.ts @@ -1,14 +1,28 @@ import * as core from '@actions/core' import {Inputs, NoFileOptions} from './constants' -import {UploadInputs} from './upload-inputs' +import {UploadInputs, UploadPerFile} 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}) +export function getInputs(): UploadInputs | UploadPerFile { + const TRUE_MAP = ['true', 'True', 'TRUE'] + + let artifactPerFile = false + const artifactPerFileStr = core.getInput(Inputs.ArtifactPerFile) + if (artifactPerFileStr) { + artifactPerFile = TRUE_MAP.includes(artifactPerFileStr) ? true : false + } + let name = '' + let artifactNameRule = '' + if (!artifactPerFile) { + name = core.getInput(Inputs.Name) + } else { + artifactNameRule = core.getInput(Inputs.ArtifactNameRule) || '${base}' + } + + const path = core.getInput(Inputs.Path, {required: true}) const ifNoFilesFound = core.getInput(Inputs.IfNoFilesFound) const noFileBehavior: NoFileOptions = NoFileOptions[ifNoFilesFound] @@ -22,19 +36,44 @@ export function getInputs(): UploadInputs { ) } - const inputs = { - artifactName: name, - searchPath: path, - ifNoFilesFound: noFileBehavior - } as UploadInputs - - const retentionDaysStr = core.getInput(Inputs.RetentionDays) - if (retentionDaysStr) { - inputs.retentionDays = parseInt(retentionDaysStr) - if (isNaN(inputs.retentionDays)) { - core.setFailed('Invalid retention-days') + const typedInputs = ( + artifactPerFile: boolean + ): UploadInputs | UploadPerFile => { + const retentionDaysStr = core.getInput(Inputs.RetentionDays) + + if (!artifactPerFile) { + const inputs = { + artifactsName: name, + searchPath: path, + ifNoFilesFound: noFileBehavior + } as UploadInputs + + if (retentionDaysStr) { + inputs.retentionDays = parseInt(retentionDaysStr) + if (isNaN(inputs.retentionDays)) { + core.setFailed('Invalid retention-days') + } + } + + return inputs + } else { + const inputs = { + searchPath: path, + ifNoFilesFound: noFileBehavior, + artifactPerFile: artifactPerFile, + artifactNameRule: artifactNameRule + } as UploadPerFile + + if (retentionDaysStr) { + inputs.retentionDays = parseInt(retentionDaysStr) + if (isNaN(inputs.retentionDays)) { + core.setFailed('Invalid retention-days') + } + } + + return inputs } } - return inputs + return typedInputs(artifactPerFile) } diff --git a/src/upload-artifact.ts b/src/upload-artifact.ts index d78e0691..b09e33e1 100644 --- a/src/upload-artifact.ts +++ b/src/upload-artifact.ts @@ -3,10 +3,12 @@ import {create, UploadOptions} from '@actions/artifact' import {findFilesToUpload} from './search' import {getInputs} from './input-helper' import {NoFileOptions} from './constants' +import {UploadInputs, UploadPerFile} from './upload-inputs' +import path from 'path' async function run(): Promise { try { - const inputs = getInputs() + const inputs: UploadInputs | UploadPerFile = getInputs() const searchResult = await findFilesToUpload(inputs.searchPath) if (searchResult.filesToUpload.length === 0) { // No files were found, different use cases warrant different types of behavior if nothing is found @@ -51,21 +53,85 @@ async function run(): Promise { options.retentionDays = inputs.retentionDays } - const uploadResponse = await 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.` + const artifactsName = inputs['artifactsName'] || 'artifacts' + const artifactPerFile = inputs['artifactPerFile'] || false + if (!artifactPerFile) { + const uploadResponse = await artifactClient.uploadArtifact( + artifactsName, + 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.` + ) + } else { + core.info( + `Artifact ${uploadResponse.artifactName} has been successfully uploaded!` + ) + } } else { - core.info( - `Artifact ${uploadResponse.artifactName} has been successfully uploaded!` - ) + const filesToUpload = searchResult.filesToUpload + const SuccessedItems: string[] = [] + const FailedItems: string[] = [] + + const artifactNameRule = inputs['artifactNameRule'] + for (let i = 0; i < filesToUpload.length; i++) { + const file = filesToUpload[i] + core.info(file) + + const pathObject = path.parse(file) + let artifactName = artifactNameRule + for (const key of Object.keys(pathObject)) { + const re = `$\{${key}}` + if (artifactNameRule.includes(re)) { + const value = pathObject[key] || '' + artifactName = artifactName.replace(re, value) + } + } + if (artifactName.includes(path.sep)) { + core.warning(`${artifactName} includes ${path.sep}`) + artifactName = artifactName.split(path.sep).join('_') + } + if (artifactName.includes(':')) { + core.warning(`${artifactName} includes :`) + artifactName = artifactName.split(':').join('-') + } + core.info(artifactName) + + const artifactItemExist = SuccessedItems.includes(artifactName) + if (artifactItemExist) { + const oldArtifactName = artifactName + core.warning(`${artifactName} artifact alreay exist`) + artifactName = `${i}__${artifactName}` + core.warning(`${oldArtifactName} => ${artifactName}`) + } + + const uploadResponse = await artifactClient.uploadArtifact( + artifactName, + [file], + searchResult.rootDirectory, + options + ) + if (uploadResponse.failedItems.length > 0) { + FailedItems.push(artifactName) + } else { + SuccessedItems.push(artifactName) + } + } + + if (FailedItems.length > 0) { + let errMsg = `${FailedItems.length} artifacts failed to upload, they were:\n` + errMsg += FailedItems.join('\n') + core.setFailed(errMsg) + } + if (SuccessedItems.length > 0) { + let infoMsg = `${SuccessedItems.length} artifacts has been successfully uploaded! They were:\n` + infoMsg += SuccessedItems.join('\n') + core.info(infoMsg) + } } } } catch (err) { diff --git a/src/upload-inputs.ts b/src/upload-inputs.ts index 37325df3..8e3fa09e 100644 --- a/src/upload-inputs.ts +++ b/src/upload-inputs.ts @@ -4,7 +4,7 @@ export interface UploadInputs { /** * The name of the artifact that will be uploaded */ - artifactName: string + artifactsName: string /** * The search path used to describe what to upload as part of the artifact @@ -21,3 +21,20 @@ export interface UploadInputs { */ retentionDays: number } + +export interface UploadPerFile { + searchPath: string + ifNoFilesFound: NoFileOptions + retentionDays: number + + // artifact-per-file: {true | false} + // @default: false + artifactPerFile: boolean + + // https://nodejs.org/docs/latest-v16.x/api/path.html#pathparsepath + // @args: searchResult.filesToUpload + // @return: String.replace() + // @default: pathObject.base + // @default rule: "${base}" + artifactNameRule: string +} From 7f0c9eaa6d0a13c28f59b6f792479ea9052ba3f3 Mon Sep 17 00:00:00 2001 From: initdc Date: Sat, 15 Oct 2022 13:44:59 +0000 Subject: [PATCH 2/4] fix: update actions.yml --- action.yml | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/action.yml b/action.yml index 94a583af..1d21f6fa 100644 --- a/action.yml +++ b/action.yml @@ -3,8 +3,8 @@ description: 'Upload a build artifact that can be used by subsequent workflow st author: 'GitHub' inputs: name: - description: 'Artifact name' - default: 'artifact' + description: 'Artifacts name' + default: 'artifacts' path: description: 'A file, directory or wildcard pattern that describes what to upload' required: true @@ -23,6 +23,31 @@ inputs: Minimum 1 day. Maximum 90 days unless changed from the repository settings page. + artifact-per-file: + description: enable otption for uploading one artifact per file + default: "false" + artifact-name-rule: + description: > + https://nodejs.org/docs/latest-v16.x/api/path.html#pathparsepath + + path.parse('/home/user/dir/file.txt'); + // Returns: + // { root: '/', + // dir: '/home/user/dir', + // base: 'file.txt', + // ext: '.txt', + // name: 'file' } + + ┌─────────────────────┬────────────┐ + │ dir │ base │ + ├──────┬ ├──────┬─────┤ + │ root │ │ name │ ext │ + " / home/user/dir / file .txt " + └──────┴──────────────┴──────┴─────┘ + (All spaces in the "" line should be ignored. They are purely for formatting.) + + Every key need in wrapper: ${} + default: ${base} runs: using: 'node16' main: 'dist/index.js' From bbe450472946813f4373c74a5b8321d6a8a78366 Mon Sep 17 00:00:00 2001 From: initdc Date: Sat, 15 Oct 2022 14:39:03 +0000 Subject: [PATCH 3/4] fix: add path key for pathObject --- .github/workflows/test-per-file.yml | 10 +++------ action.yml | 11 ++++++---- dist/index.js | 26 +++++++++++++++++------ src/upload-artifact.ts | 33 +++++++++++++++++++++++------ 4 files changed, 55 insertions(+), 25 deletions(-) diff --git a/.github/workflows/test-per-file.yml b/.github/workflows/test-per-file.yml index 1b56e1b3..447e13f0 100644 --- a/.github/workflows/test-per-file.yml +++ b/.github/workflows/test-per-file.yml @@ -64,14 +64,12 @@ jobs: tar -zvcf path/to/dir-3/all.gz path/to/dir-3/* - # Upload a single file artifact - name: 'Upload artifact #1' uses: ./ with: path: path/to/dir-1/file1.txt artifact-per-file: true - # Upload using a wildcard pattern, name should default to 'artifact' if not provided - name: 'Upload artifact #2' uses: ./ with: @@ -79,20 +77,18 @@ jobs: artifact-per-file: true artifact-name-rule: ${dir}-${base} - # Upload a directory that contains a file that will be uploaded with GZip - name: 'Upload artifact #3' uses: ./ with: path: path/to/dir-3/*.gz artifact-per-file: true - artifact-name-rule: ${dir}-${name}${ext} + artifact-name-rule: ${path}-${name}${ext} - # Upload a directory that contains a file that will be uploaded with GZip - name: 'Upload artifact #4' uses: ./ with: path: | - path/**/dir*/ + path/**/dir-1/ !path/to/dir-3/*.gz artifact-per-file: true - artifact-name-rule: ${{ matrix.runs-on }}-${base} + artifact-name-rule: ${{ matrix.runs-on }}-${name} diff --git a/action.yml b/action.yml index 1d21f6fa..188957db 100644 --- a/action.yml +++ b/action.yml @@ -28,25 +28,28 @@ inputs: default: "false" artifact-name-rule: description: > - https://nodejs.org/docs/latest-v16.x/api/path.html#pathparsepath + // https://nodejs.org/docs/latest-v16.x/api/path.html#pathparsepath + // Modified from path.parse() path.parse('/home/user/dir/file.txt'); // Returns: // { root: '/', // dir: '/home/user/dir', + // path: 'home/user/dir' // base: 'file.txt', // ext: '.txt', // name: 'file' } ┌─────────────────────┬────────────┐ - │ dir │ base │ - ├──────┬ ├──────┬─────┤ - │ root │ │ name │ ext │ + │ dir sep base │ + ├──────┬──────────────┼──────┬─────┤ + │ root │ path │ name │ ext │ " / home/user/dir / file .txt " └──────┴──────────────┴──────┴─────┘ (All spaces in the "" line should be ignored. They are purely for formatting.) Every key need in wrapper: ${} + sep just for prompt, can't be used default: ${base} runs: using: 'node16' diff --git a/dist/index.js b/dist/index.js index 68e2cd22..3dd6b320 100644 --- a/dist/index.js +++ b/dist/index.js @@ -4781,8 +4781,10 @@ function run() { } const artifactsName = inputs['artifactsName'] || 'artifacts'; const artifactPerFile = inputs['artifactPerFile'] || false; + const rootDirectory = searchResult.rootDirectory; + core.info('rootDirectory: ' + rootDirectory); if (!artifactPerFile) { - const uploadResponse = yield artifactClient.uploadArtifact(artifactsName, searchResult.filesToUpload, searchResult.rootDirectory, options); + const uploadResponse = yield artifactClient.uploadArtifact(artifactsName, searchResult.filesToUpload, 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.`); } @@ -4797,8 +4799,14 @@ function run() { const artifactNameRule = inputs['artifactNameRule']; for (let i = 0; i < filesToUpload.length; i++) { const file = filesToUpload[i]; - core.info(file); - const pathObject = path_1.default.parse(file); + core.info('file: ' + file); + const pathObject = Object.assign({}, path_1.default.parse(file)); + const pathBase = pathObject.base; + const pathRoot = path_1.default.parse(rootDirectory).dir; + pathObject.root = pathRoot; + core.info('root: ' + pathRoot); + pathObject['path'] = file.slice(pathRoot.length, file.length - path_1.default.sep.length - pathBase.length); + core.info('path: ' + pathObject['path']); let artifactName = artifactNameRule; for (const key of Object.keys(pathObject)) { const re = `$\{${key}}`; @@ -4807,15 +4815,19 @@ function run() { artifactName = artifactName.replace(re, value); } } - if (artifactName.includes(path_1.default.sep)) { - core.warning(`${artifactName} includes ${path_1.default.sep}`); - artifactName = artifactName.split(path_1.default.sep).join('_'); + if (artifactName.startsWith(path_1.default.sep)) { + core.warning(`${artifactName} startsWith ${path_1.default.sep}`); + artifactName = artifactName.slice(path_1.default.sep.length); } if (artifactName.includes(':')) { core.warning(`${artifactName} includes :`); artifactName = artifactName.split(':').join('-'); } - core.info(artifactName); + if (artifactName.includes(path_1.default.sep)) { + core.warning(`${artifactName} includes ${path_1.default.sep}`); + artifactName = artifactName.split(path_1.default.sep).join('_'); + } + core.debug(artifactName); const artifactItemExist = SuccessedItems.includes(artifactName); if (artifactItemExist) { const oldArtifactName = artifactName; diff --git a/src/upload-artifact.ts b/src/upload-artifact.ts index b09e33e1..1714a85b 100644 --- a/src/upload-artifact.ts +++ b/src/upload-artifact.ts @@ -55,11 +55,14 @@ async function run(): Promise { const artifactsName = inputs['artifactsName'] || 'artifacts' const artifactPerFile = inputs['artifactPerFile'] || false + const rootDirectory = searchResult.rootDirectory + core.info('rootDirectory: ' + rootDirectory) + if (!artifactPerFile) { const uploadResponse = await artifactClient.uploadArtifact( artifactsName, searchResult.filesToUpload, - searchResult.rootDirectory, + rootDirectory, options ) @@ -80,9 +83,20 @@ async function run(): Promise { const artifactNameRule = inputs['artifactNameRule'] for (let i = 0; i < filesToUpload.length; i++) { const file = filesToUpload[i] - core.info(file) + core.info('file: ' + file) + + const pathObject = Object.assign({}, path.parse(file)) + const pathBase = pathObject.base + const pathRoot = path.parse(rootDirectory).dir + pathObject.root = pathRoot + core.info('root: ' + pathRoot) + + pathObject['path'] = file.slice( + pathRoot.length, + file.length - path.sep.length - pathBase.length + ) + core.info('path: ' + pathObject['path']) - const pathObject = path.parse(file) let artifactName = artifactNameRule for (const key of Object.keys(pathObject)) { const re = `$\{${key}}` @@ -91,15 +105,20 @@ async function run(): Promise { artifactName = artifactName.replace(re, value) } } - if (artifactName.includes(path.sep)) { - core.warning(`${artifactName} includes ${path.sep}`) - artifactName = artifactName.split(path.sep).join('_') + + if (artifactName.startsWith(path.sep)) { + core.warning(`${artifactName} startsWith ${path.sep}`) + artifactName = artifactName.slice(path.sep.length) } if (artifactName.includes(':')) { core.warning(`${artifactName} includes :`) artifactName = artifactName.split(':').join('-') } - core.info(artifactName) + if (artifactName.includes(path.sep)) { + core.warning(`${artifactName} includes ${path.sep}`) + artifactName = artifactName.split(path.sep).join('_') + } + core.debug(artifactName) const artifactItemExist = SuccessedItems.includes(artifactName) if (artifactItemExist) { From baac12d9f85834b2f8baa26a08ff97c27cc82cd9 Mon Sep 17 00:00:00 2001 From: initdc Date: Tue, 18 Oct 2022 09:43:45 +0000 Subject: [PATCH 4/4] fix: get path root from `github.workspace` --- .github/workflows/test-per-file.yml | 2 +- dist/index.js | 15 +++++++++++++-- src/upload-artifact.ts | 16 ++++++++++++++-- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test-per-file.yml b/.github/workflows/test-per-file.yml index 447e13f0..51623c68 100644 --- a/.github/workflows/test-per-file.yml +++ b/.github/workflows/test-per-file.yml @@ -91,4 +91,4 @@ jobs: path/**/dir-1/ !path/to/dir-3/*.gz artifact-per-file: true - artifact-name-rule: ${{ matrix.runs-on }}-${name} + artifact-name-rule: ${{ matrix.runs-on }}-${path}-${name} diff --git a/dist/index.js b/dist/index.js index 3dd6b320..c994e441 100644 --- a/dist/index.js +++ b/dist/index.js @@ -4781,6 +4781,15 @@ function run() { } const artifactsName = inputs['artifactsName'] || 'artifacts'; const artifactPerFile = inputs['artifactPerFile'] || false; + // GitHub workspace + let githubWorkspacePath = process.env['GITHUB_WORKSPACE'] || undefined; + if (!githubWorkspacePath) { + core.warning('GITHUB_WORKSPACE not defined'); + } + else { + githubWorkspacePath = path_1.default.resolve(githubWorkspacePath); + core.info(`GITHUB_WORKSPACE = '${githubWorkspacePath}'`); + } const rootDirectory = searchResult.rootDirectory; core.info('rootDirectory: ' + rootDirectory); if (!artifactPerFile) { @@ -4802,7 +4811,9 @@ function run() { core.info('file: ' + file); const pathObject = Object.assign({}, path_1.default.parse(file)); const pathBase = pathObject.base; - const pathRoot = path_1.default.parse(rootDirectory).dir; + const pathRoot = githubWorkspacePath + ? githubWorkspacePath + : path_1.default.parse(rootDirectory).dir; pathObject.root = pathRoot; core.info('root: ' + pathRoot); pathObject['path'] = file.slice(pathRoot.length, file.length - path_1.default.sep.length - pathBase.length); @@ -4835,7 +4846,7 @@ function run() { artifactName = `${i}__${artifactName}`; core.warning(`${oldArtifactName} => ${artifactName}`); } - const uploadResponse = yield artifactClient.uploadArtifact(artifactName, [file], searchResult.rootDirectory, options); + const uploadResponse = yield artifactClient.uploadArtifact(artifactName, [file], rootDirectory, options); if (uploadResponse.failedItems.length > 0) { FailedItems.push(artifactName); } diff --git a/src/upload-artifact.ts b/src/upload-artifact.ts index 1714a85b..98440b13 100644 --- a/src/upload-artifact.ts +++ b/src/upload-artifact.ts @@ -55,6 +55,16 @@ async function run(): Promise { const artifactsName = inputs['artifactsName'] || 'artifacts' const artifactPerFile = inputs['artifactPerFile'] || false + + // GitHub workspace + let githubWorkspacePath = process.env['GITHUB_WORKSPACE'] || undefined + if (!githubWorkspacePath) { + core.warning('GITHUB_WORKSPACE not defined') + } else { + githubWorkspacePath = path.resolve(githubWorkspacePath) + core.info(`GITHUB_WORKSPACE = '${githubWorkspacePath}'`) + } + const rootDirectory = searchResult.rootDirectory core.info('rootDirectory: ' + rootDirectory) @@ -87,7 +97,9 @@ async function run(): Promise { const pathObject = Object.assign({}, path.parse(file)) const pathBase = pathObject.base - const pathRoot = path.parse(rootDirectory).dir + const pathRoot = githubWorkspacePath + ? githubWorkspacePath + : path.parse(rootDirectory).dir pathObject.root = pathRoot core.info('root: ' + pathRoot) @@ -131,7 +143,7 @@ async function run(): Promise { const uploadResponse = await artifactClient.uploadArtifact( artifactName, [file], - searchResult.rootDirectory, + rootDirectory, options ) if (uploadResponse.failedItems.length > 0) {