diff --git a/.github/workflows/timeout.yml b/.github/workflows/timeout.yml index 1d42aac..c2fe75b 100644 --- a/.github/workflows/timeout.yml +++ b/.github/workflows/timeout.yml @@ -8,4 +8,4 @@ jobs: runs-on: ubuntu-latest steps: - name: Sleep - run: sleep 1200s + run: sleep 120s diff --git a/.gitignore b/.gitignore index 3ec544c..a90bea0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ -.env \ No newline at end of file +.env +.idea \ No newline at end of file diff --git a/README.md b/README.md index 8a99544..d45a513 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ For details of the `workflow_dispatch` even see [this blog post introducing this *Note 2.* If you want to reference the target workflow by ID, you will need to list them with the following REST API call `curl https://api.github.com/repos/{{owner}}/{{repo}}/actions/workflows -H "Authorization: token {{pat-token}}"` -*This action is a fork of `benc-uk/workflow-dispatch` to add support for waiting for workflow completion.* +*This action is a fork of `aurelien-baudet/workflow-dispatch` with a better management of run-name option and node20 support.* ## Inputs @@ -105,16 +105,16 @@ For details of the `workflow_dispatch` even see [this blog post introducing this > Based on the value, result will be: > > * `output`: Multiline string -> -> ```log + > + > ```log > | > | > ... > ``` > > * `json-output`: JSON string -> -> ```json + > + > ```json > { > "": [ > { @@ -135,7 +135,7 @@ For details of the `workflow_dispatch` even see [this blog post introducing this ```yaml - name: Invoke workflow without inputs. Wait for result - uses: aurelien-baudet/workflow-dispatch@v2 + uses: the-actions-org/workflow-dispatch@v4 with: workflow: My Workflow token: ${{ secrets.PERSONAL_TOKEN }} @@ -145,7 +145,7 @@ For details of the `workflow_dispatch` even see [this blog post introducing this ```yaml - name: Invoke workflow without inputs. Don't wait for result - uses: aurelien-baudet/workflow-dispatch@v2 + uses: the-actions-org/workflow-dispatch@v4 with: workflow: My Workflow token: ${{ secrets.PERSONAL_TOKEN }} @@ -156,7 +156,7 @@ For details of the `workflow_dispatch` even see [this blog post introducing this ```yaml - name: Invoke workflow with inputs - uses: aurelien-baudet/workflow-dispatch@v2 + uses: the-actions-org/workflow-dispatch@v4 with: workflow: Another Workflow token: ${{ secrets.PERSONAL_TOKEN }} @@ -167,7 +167,7 @@ For details of the `workflow_dispatch` even see [this blog post introducing this ```yaml - name: Invoke workflow in another repo with inputs - uses: aurelien-baudet/workflow-dispatch@v2 + uses: the-actions-org/workflow-dispatch@v4 with: workflow: Some Workflow repo: benc-uk/example @@ -180,7 +180,7 @@ For details of the `workflow_dispatch` even see [this blog post introducing this ```yaml - name: Invoke workflow and handle result id: trigger-step - uses: aurelien-baudet/workflow-dispatch@v2 + uses: the-actions-org/workflow-dispatch@v4 with: workflow: Another Workflow token: ${{ secrets.PERSONAL_TOKEN }} @@ -194,7 +194,7 @@ For details of the `workflow_dispatch` even see [this blog post introducing this ```yaml - name: Invoke workflow and scrap output id: trigger-step - uses: aurelien-baudet/workflow-dispatch@v2 + uses: the-actions-org/workflow-dispatch@v4 with: workflow: Another Workflow token: ${{ secrets.PERSONAL_TOKEN }} @@ -220,7 +220,7 @@ jobs: ```yaml - name: Invoke workflow and handle result id: trigger-step - uses: aurelien-baudet/workflow-dispatch@v3 + uses: the-actions-org/workflow-dispatch@v4 env: RUN_NAME: ${{ github.repository }}/actions/runs/${{ github.run_id }} with: @@ -252,6 +252,9 @@ on: Thanks to: +* [LudovicTOURMAN](https://github.com/LudovicTOURMAN ) +* [Djontleman](https://github.com/Djontleman) +* [aurelien-baudet](https://github.com/aurelien-baudet) * [samirergaibi](https://github.com/samirergaibi) * [rui-ferreira](https://github.com/rui-ferreira) * [robbertvdg](https://github.com/robbertvdg) diff --git a/dist/index.js b/dist/index.js index ce598ca..6d55bcf 100644 --- a/dist/index.js +++ b/dist/index.js @@ -29323,7 +29323,7 @@ function waitForCompletionOrTimeout(workflowHandler, checkStatusInterval, waitFo } function computeConclusion(start, waitForCompletionTimeout, result) { if ((0, utils_1.isTimedOut)(start, waitForCompletionTimeout)) { - core.info(`Workflow wait timed out`); + core.info('Workflow wait timed out'); core.setOutput('workflow-conclusion', workflow_handler_1.WorkflowRunConclusion.TIMED_OUT); throw new Error('Workflow run has failed due to timeout'); } @@ -29358,7 +29358,7 @@ function run() { const workflowHandler = new workflow_handler_1.WorkflowHandler(args.token, args.workflowRef, args.owner, args.repo, args.ref, args.runName); // Trigger workflow run yield workflowHandler.triggerWorkflow(args.inputs); - core.info(`Workflow triggered 🚀`); + core.info('Workflow triggered 🚀'); if (args.displayWorkflowUrl) { const url = yield getFollowUrl(workflowHandler, args.displayWorkflowUrlInterval, args.displayWorkflowUrlTimeout); core.info(`You can follow the running workflow here: ${url}`); @@ -29367,7 +29367,7 @@ function run() { if (!args.waitForCompletion) { return; } - core.info(`Waiting for workflow completion`); + core.info('Waiting for workflow completion'); const { result, start } = yield waitForCompletionOrTimeout(workflowHandler, args.checkStatusInterval, args.waitForCompletionTimeout); yield handleLogs(args, workflowHandler); core.setOutput('workflow-id', result === null || result === void 0 ? void 0 : result.id); @@ -29455,7 +29455,7 @@ function getArgs() { ? core.getInput('repo').split('/') : [github.context.repo.owner, github.context.repo.repo]; // Decode inputs, this MUST be a valid JSON string - let inputs = parse(core.getInput('inputs')); + const inputs = parse(core.getInput('inputs')); const displayWorkflowUrlStr = core.getInput('display-workflow-run-url'); const displayWorkflowUrl = displayWorkflowUrlStr && displayWorkflowUrlStr === 'true'; const displayWorkflowUrlTimeout = toMilliseconds(core.getInput('display-workflow-run-url-timeout')); @@ -29501,13 +29501,13 @@ function formatDuration(duration) { let minutesStr = minutes + ''; let secondsStr = seconds + ''; if (hours < 10) { - hoursStr = "0" + hoursStr; + hoursStr = '0' + hoursStr; } if (minutes < 10) { - minutesStr = "0" + minutesStr; + minutesStr = '0' + minutesStr; } if (seconds < 10) { - secondsStr = "0" + secondsStr; + secondsStr = '0' + secondsStr; } return hoursStr + 'h ' + minutesStr + 'm ' + secondsStr + 's'; } @@ -29727,7 +29727,7 @@ class WorkflowHandler { repo: this.repo }); const workflows = workflowsResp.data.workflows; - (0, debug_1.debug)(`List Workflows`, workflows); + (0, debug_1.debug)('List Workflows', workflows); // Locate workflow either by name or id const workflowFind = workflows.find((workflow) => workflow.name === this.workflowRef || workflow.id.toString() === this.workflowRef); if (!workflowFind) @@ -29926,8 +29926,8 @@ function logHandlerFactory(mode) { } } function escapeImportedLogs(str) { - return str.replace(/^/mg, "| ") - .replace(/##\[([^\]]+)\]/gm, "##<$1>"); + return str.replace(/^/mg, '| ') + .replace(/##\[([^\]]+)\]/gm, '##<$1>'); } diff --git a/package.json b/package.json index ee461c0..44d362a 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "dist/index.js", "scripts": { "build": "ncc build src/main.ts -o dist", - "lint": "eslint src/" + "lint": "eslint src/", + "lint-fix": "eslint src/ --fix" }, "keywords": [ "github", diff --git a/src/debug.ts b/src/debug.ts index 956b5c4..5fa12e0 100644 --- a/src/debug.ts +++ b/src/debug.ts @@ -4,10 +4,10 @@ export function debug(title: string, content: any) { if (core.isDebug()) { core.info(`::group::${title}`) try { - core.debug(JSON.stringify(content, null, 3)); + core.debug(JSON.stringify(content, null, 3)) } catch(e) { core.debug(`Failed to serialize object, trying toString. Cause: ${e}`) - core.debug(content?.toString()); + core.debug(content?.toString()) } core.info('::endgroup::') } diff --git a/src/main.ts b/src/main.ts index 21357b2..c31e2ad 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,67 +6,66 @@ // ---------------------------------------------------------------------------- import * as core from '@actions/core' -import * as github from '@actions/github' -import { formatDuration, getArgs, isTimedOut, sleep } from './utils'; -import { WorkflowHandler, WorkflowRunConclusion, WorkflowRunResult, WorkflowRunStatus } from './workflow-handler'; -import { handleWorkflowLogsPerJob } from './workflow-logs-handler'; +import { formatDuration, getArgs, isTimedOut, sleep } from './utils' +import { WorkflowHandler, WorkflowRunConclusion, WorkflowRunResult, WorkflowRunStatus } from './workflow-handler' +import { handleWorkflowLogsPerJob } from './workflow-logs-handler' async function getFollowUrl(workflowHandler: WorkflowHandler, interval: number, timeout: number) { - const start = Date.now(); - let url; + const start = Date.now() + let url do { - await sleep(interval); + await sleep(interval) try { - const result = await workflowHandler.getWorkflowRunStatus(); - url = result.url; + const result = await workflowHandler.getWorkflowRunStatus() + url = result.url } catch(e: any) { - core.debug(`Failed to get workflow url: ${e.message}`); + core.debug(`Failed to get workflow url: ${e.message}`) } - } while (!url && !isTimedOut(start, timeout)); - return url; + } while (!url && !isTimedOut(start, timeout)) + return url } async function waitForCompletionOrTimeout(workflowHandler: WorkflowHandler, checkStatusInterval: number, waitForCompletionTimeout: number) { - const start = Date.now(); - let status; - let result; + const start = Date.now() + let status + let result do { - await sleep(checkStatusInterval); + await sleep(checkStatusInterval) try { - result = await workflowHandler.getWorkflowRunStatus(); - status = result.status; + result = await workflowHandler.getWorkflowRunStatus() + status = result.status core.debug(`Worflow is running for ${formatDuration(Date.now() - start)}. Current status=${status}`) } catch(e: any) { - core.warning(`Failed to get workflow status: ${e.message}`); + core.warning(`Failed to get workflow status: ${e.message}`) } - } while (status !== WorkflowRunStatus.COMPLETED && !isTimedOut(start, waitForCompletionTimeout)); + } while (status !== WorkflowRunStatus.COMPLETED && !isTimedOut(start, waitForCompletionTimeout)) return { result, start } } function computeConclusion(start: number, waitForCompletionTimeout: number, result?: WorkflowRunResult) { if (isTimedOut(start, waitForCompletionTimeout)) { - core.info(`Workflow wait timed out`); - core.setOutput('workflow-conclusion', WorkflowRunConclusion.TIMED_OUT); - throw new Error('Workflow run has failed due to timeout'); + core.info('Workflow wait timed out') + core.setOutput('workflow-conclusion', WorkflowRunConclusion.TIMED_OUT) + throw new Error('Workflow run has failed due to timeout') } - core.info(`Workflow completed with conclusion=${result?.conclusion}`); - const conclusion = result?.conclusion; - core.setOutput('workflow-conclusion', conclusion); + core.info(`Workflow completed with conclusion=${result?.conclusion}`) + const conclusion = result?.conclusion + core.setOutput('workflow-conclusion', conclusion) - if (conclusion === WorkflowRunConclusion.FAILURE) throw new Error('Workflow run has failed'); - if (conclusion === WorkflowRunConclusion.CANCELLED) throw new Error('Workflow run was cancelled'); - if (conclusion === WorkflowRunConclusion.TIMED_OUT) throw new Error('Workflow run has failed due to timeout'); + if (conclusion === WorkflowRunConclusion.FAILURE) throw new Error('Workflow run has failed') + if (conclusion === WorkflowRunConclusion.CANCELLED) throw new Error('Workflow run was cancelled') + if (conclusion === WorkflowRunConclusion.TIMED_OUT) throw new Error('Workflow run has failed due to timeout') } async function handleLogs(args: any, workflowHandler: WorkflowHandler) { try { const workflowRunId = await workflowHandler.getWorkflowRunId() - await handleWorkflowLogsPerJob(args, workflowRunId); + await handleWorkflowLogsPerJob(args, workflowRunId) } catch(e: any) { - core.error(`Failed to handle logs of triggered workflow. Cause: ${e}`); + core.error(`Failed to handle logs of triggered workflow. Cause: ${e}`) } } @@ -75,34 +74,34 @@ async function handleLogs(args: any, workflowHandler: WorkflowHandler) { // async function run(): Promise { try { - const args = getArgs(); - const workflowHandler = new WorkflowHandler(args.token, args.workflowRef, args.owner, args.repo, args.ref, args.runName); + const args = getArgs() + const workflowHandler = new WorkflowHandler(args.token, args.workflowRef, args.owner, args.repo, args.ref, args.runName) // Trigger workflow run - await workflowHandler.triggerWorkflow(args.inputs); - core.info(`Workflow triggered 🚀`); + await workflowHandler.triggerWorkflow(args.inputs) + core.info('Workflow triggered 🚀') if (args.displayWorkflowUrl) { const url = await getFollowUrl(workflowHandler, args.displayWorkflowUrlInterval, args.displayWorkflowUrlTimeout) - core.info(`You can follow the running workflow here: ${url}`); - core.setOutput('workflow-url', url); + core.info(`You can follow the running workflow here: ${url}`) + core.setOutput('workflow-url', url) } if (!args.waitForCompletion) { - return; + return } - core.info(`Waiting for workflow completion`); - const { result, start } = await waitForCompletionOrTimeout(workflowHandler, args.checkStatusInterval, args.waitForCompletionTimeout); + core.info('Waiting for workflow completion') + const { result, start } = await waitForCompletionOrTimeout(workflowHandler, args.checkStatusInterval, args.waitForCompletionTimeout) - await handleLogs(args, workflowHandler); + await handleLogs(args, workflowHandler) - core.setOutput('workflow-id', result?.id); - core.setOutput('workflow-url', result?.url); - computeConclusion(start, args.waitForCompletionTimeout, result); + core.setOutput('workflow-id', result?.id) + core.setOutput('workflow-url', result?.url) + computeConclusion(start, args.waitForCompletionTimeout, result) } catch (error: any) { - core.setFailed(error.message); + core.setFailed(error.message) } } diff --git a/src/utils.ts b/src/utils.ts index 9ac7011..c888a51 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -8,19 +8,19 @@ enum TimeUnit { } function toMilliseconds(timeWithUnit: string): number { - const unitStr = timeWithUnit.substring(timeWithUnit.length-1); - const unit = TimeUnit[unitStr.toUpperCase() as keyof typeof TimeUnit]; + const unitStr = timeWithUnit.substring(timeWithUnit.length-1) + const unit = TimeUnit[unitStr.toUpperCase() as keyof typeof TimeUnit] if (!unit) { - throw new Error('Unknown time unit '+unitStr); + throw new Error('Unknown time unit '+unitStr) } - const time = parseFloat(timeWithUnit); - return time * unit; + const time = parseFloat(timeWithUnit) + return time * unit } function parse(inputsJson: string) { if(inputsJson) { try { - return JSON.parse(inputsJson); + return JSON.parse(inputsJson) } catch(e) { throw new Error(`Failed to parse 'inputs' parameter. Must be a valid JSON.\nCause: ${e}`) } @@ -29,28 +29,28 @@ function parse(inputsJson: string) { } export function getArgs() { // Required inputs - const token = core.getInput('token'); - const workflowRef = core.getInput('workflow'); + const token = core.getInput('token') + const workflowRef = core.getInput('workflow') // Optional inputs, with defaults - const ref = core.getInput('ref') || github.context.ref; + const ref = core.getInput('ref') || github.context.ref const [owner, repo] = core.getInput('repo') ? core.getInput('repo').split('/') - : [github.context.repo.owner, github.context.repo.repo]; + : [github.context.repo.owner, github.context.repo.repo] // Decode inputs, this MUST be a valid JSON string - let inputs = parse(core.getInput('inputs')); + const inputs = parse(core.getInput('inputs')) - const displayWorkflowUrlStr = core.getInput('display-workflow-run-url'); - const displayWorkflowUrl = displayWorkflowUrlStr && displayWorkflowUrlStr === 'true'; - const displayWorkflowUrlTimeout = toMilliseconds(core.getInput('display-workflow-run-url-timeout')); - const displayWorkflowUrlInterval = toMilliseconds(core.getInput('display-workflow-run-url-interval')); + const displayWorkflowUrlStr = core.getInput('display-workflow-run-url') + const displayWorkflowUrl = displayWorkflowUrlStr && displayWorkflowUrlStr === 'true' + const displayWorkflowUrlTimeout = toMilliseconds(core.getInput('display-workflow-run-url-timeout')) + const displayWorkflowUrlInterval = toMilliseconds(core.getInput('display-workflow-run-url-interval')) - const waitForCompletionStr = core.getInput('wait-for-completion'); - const waitForCompletion = waitForCompletionStr && waitForCompletionStr === 'true'; - const waitForCompletionTimeout = toMilliseconds(core.getInput('wait-for-completion-timeout')); - const checkStatusInterval = toMilliseconds(core.getInput('wait-for-completion-interval')); - const runName = core.getInput('run-name'); - const workflowLogMode = core.getInput('workflow-logs'); + const waitForCompletionStr = core.getInput('wait-for-completion') + const waitForCompletion = waitForCompletionStr && waitForCompletionStr === 'true' + const waitForCompletionTimeout = toMilliseconds(core.getInput('wait-for-completion-timeout')) + const checkStatusInterval = toMilliseconds(core.getInput('wait-for-completion-interval')) + const runName = core.getInput('run-name') + const workflowLogMode = core.getInput('workflow-logs') return { token, @@ -67,29 +67,29 @@ export function getArgs() { waitForCompletionTimeout, runName, workflowLogMode - }; + } } export function sleep(ms: number) { - return new Promise(resolve => setTimeout(resolve, ms)); + return new Promise(resolve => setTimeout(resolve, ms)) } export function isTimedOut(start: number, waitForCompletionTimeout: number) { - return Date.now() > start + waitForCompletionTimeout; + return Date.now() > start + waitForCompletionTimeout } export function formatDuration(duration: number) { - const durationSeconds = duration / 1000; - const hours = Math.floor(durationSeconds / 3600); - const minutes = Math.floor((durationSeconds - (hours * 3600)) / 60); - const seconds = durationSeconds - (hours * 3600) - (minutes * 60); + const durationSeconds = duration / 1000 + const hours = Math.floor(durationSeconds / 3600) + const minutes = Math.floor((durationSeconds - (hours * 3600)) / 60) + const seconds = durationSeconds - (hours * 3600) - (minutes * 60) - let hoursStr = hours + ''; - let minutesStr = minutes + ''; - let secondsStr = seconds + ''; + let hoursStr = hours + '' + let minutesStr = minutes + '' + let secondsStr = seconds + '' - if (hours < 10) {hoursStr = "0"+hoursStr;} - if (minutes < 10) {minutesStr = "0"+minutesStr;} - if (seconds < 10) {secondsStr = "0"+secondsStr;} - return hoursStr+'h '+minutesStr+'m '+secondsStr+'s'; + if (hours < 10) {hoursStr = '0'+hoursStr} + if (minutes < 10) {minutesStr = '0'+minutesStr} + if (seconds < 10) {secondsStr = '0'+secondsStr} + return hoursStr+'h '+minutesStr+'m '+secondsStr+'s' } diff --git a/src/workflow-handler.ts b/src/workflow-handler.ts index 93f4491..6d90160 100644 --- a/src/workflow-handler.ts +++ b/src/workflow-handler.ts @@ -1,7 +1,7 @@ import * as core from '@actions/core' import * as github from '@actions/github' -import { debug } from './debug'; +import { debug } from './debug' export enum WorkflowRunStatus { QUEUED = 'queued', @@ -11,10 +11,10 @@ export enum WorkflowRunStatus { const ofStatus = (status: string | null): WorkflowRunStatus => { if (!status) { - return WorkflowRunStatus.QUEUED; + return WorkflowRunStatus.QUEUED } - const key = status.toUpperCase() as keyof typeof WorkflowRunStatus; - return WorkflowRunStatus[key]; + const key = status.toUpperCase() as keyof typeof WorkflowRunStatus + return WorkflowRunStatus[key] } export enum WorkflowRunConclusion { @@ -29,10 +29,10 @@ export enum WorkflowRunConclusion { const ofConclusion = (conclusion: string | null): WorkflowRunConclusion => { if (!conclusion) { - return WorkflowRunConclusion.NEUTRAL; + return WorkflowRunConclusion.NEUTRAL } - const key = conclusion.toUpperCase() as keyof typeof WorkflowRunConclusion; - return WorkflowRunConclusion[key]; + const key = conclusion.toUpperCase() as keyof typeof WorkflowRunConclusion + return WorkflowRunConclusion[key] } export interface WorkflowRunResult { @@ -44,165 +44,165 @@ export interface WorkflowRunResult { export class WorkflowHandler { - private octokit: any; - private workflowId?: number | string; - private workflowRunId?: number; - private triggerDate = 0; + private octokit: any + private workflowId?: number | string + private workflowRunId?: number + private triggerDate = 0 constructor(token: string, - private workflowRef: string, - private owner: string, - private repo: string, - private ref: string, - private runName: string) { + private workflowRef: string, + private owner: string, + private repo: string, + private ref: string, + private runName: string) { // Get octokit client for making API calls - this.octokit = github.getOctokit(token); + this.octokit = github.getOctokit(token) } async triggerWorkflow(inputs: any) { try { - const workflowId = await this.getWorkflowId(); - this.triggerDate = new Date().setMilliseconds(0); + const workflowId = await this.getWorkflowId() + this.triggerDate = new Date().setMilliseconds(0) const dispatchResp = await this.octokit.rest.actions.createWorkflowDispatch({ owner: this.owner, repo: this.repo, workflow_id: workflowId, ref: this.ref, inputs - }); - debug('Workflow Dispatch', dispatchResp); + }) + debug('Workflow Dispatch', dispatchResp) } catch (error: any) { - debug('Workflow Dispatch error', error.message); - throw error; + debug('Workflow Dispatch error', error.message) + throw error } } async getWorkflowRunStatus(): Promise { try { - const runId = await this.getWorkflowRunId(); + const runId = await this.getWorkflowRunId() const response = await this.octokit.rest.actions.getWorkflowRun({ owner: this.owner, repo: this.repo, run_id: runId - }); - debug('Workflow Run status', response); + }) + debug('Workflow Run status', response) return { id: runId, url: response.data.html_url, status: ofStatus(response.data.status), conclusion: ofConclusion(response.data.conclusion) - }; + } } catch (error: any) { - debug('Workflow Run status error', error); - throw error; + debug('Workflow Run status error', error) + throw error } } async getWorkflowRunArtifacts(): Promise { try { - const runId = await this.getWorkflowRunId(); + const runId = await this.getWorkflowRunId() const response = await this.octokit.rest.actions.getWorkflowRunArtifacts({ owner: this.owner, repo: this.repo, run_id: runId - }); - debug('Workflow Run artifacts', response); + }) + debug('Workflow Run artifacts', response) return { id: runId, url: response.data.html_url, status: ofStatus(response.data.status), conclusion: ofConclusion(response.data.conclusion) - }; + } } catch (error) { - debug('Workflow Run artifacts error', error); - throw error; + debug('Workflow Run artifacts error', error) + throw error } } private async findAllWorkflowRuns() { try { - const workflowId = await this.getWorkflowId(); + const workflowId = await this.getWorkflowId() const response = await this.octokit.rest.actions.listWorkflowRuns({ owner: this.owner, repo: this.repo, workflow_id: workflowId, event: 'workflow_dispatch', created: `>=${new Date(this.triggerDate).toISOString()}` - }); + }) - debug('List Workflow Runs', response); + debug('List Workflow Runs', response) return response.data.workflow_runs } catch (error) { - debug('Fin all workflow runs error', error); + debug('Fin all workflow runs error', error) throw new Error(`Failed to list workflow runs. Cause: ${error}`) } } async getWorkflowRunId(): Promise { if (this.workflowRunId) { - return this.workflowRunId; + return this.workflowRunId } try { - let runs = await this.findAllWorkflowRuns(); + let runs = await this.findAllWorkflowRuns() if (this.runName) { runs = runs.filter((r: any) => r.name == this.runName) } if (runs.length == 0) { - throw new Error('Run not found'); + throw new Error('Run not found') } if (runs.length > 1) { - core.warning(`Found ${runs.length} runs. Using the last one.`); - await this.debugFoundWorkflowRuns(runs); + core.warning(`Found ${runs.length} runs. Using the last one.`) + await this.debugFoundWorkflowRuns(runs) } - this.workflowRunId = runs[0].id as number; + this.workflowRunId = runs[0].id as number - return this.workflowRunId; + return this.workflowRunId } catch (error) { - debug('Get workflow run id error', error); - throw error; + debug('Get workflow run id error', error) + throw error } } private async getWorkflowId(): Promise { if (this.workflowId) { - return this.workflowId; + return this.workflowId } if (this.isFilename(this.workflowRef)) { - this.workflowId = this.workflowRef; - core.debug(`Workflow id is: ${this.workflowRef}`); - return this.workflowId; + this.workflowId = this.workflowRef + core.debug(`Workflow id is: ${this.workflowRef}`) + return this.workflowId } try { const workflowsResp = await this.octokit.rest.actions.listRepoWorkflows({ owner: this.owner, repo: this.repo - }); - const workflows = workflowsResp.data.workflows; - debug(`List Workflows`, workflows); + }) + const workflows = workflowsResp.data.workflows + debug('List Workflows', workflows) // Locate workflow either by name or id - const workflowFind = workflows.find((workflow: any) => workflow.name === this.workflowRef || workflow.id.toString() === this.workflowRef); - if(!workflowFind) throw new Error(`Unable to find workflow '${this.workflowRef}' in ${this.owner}/${this.repo} 😥`); - core.debug(`Workflow id is: ${workflowFind.id}`); - this.workflowId = workflowFind.id as number; - return this.workflowId; + const workflowFind = workflows.find((workflow: any) => workflow.name === this.workflowRef || workflow.id.toString() === this.workflowRef) + if(!workflowFind) throw new Error(`Unable to find workflow '${this.workflowRef}' in ${this.owner}/${this.repo} 😥`) + core.debug(`Workflow id is: ${workflowFind.id}`) + this.workflowId = workflowFind.id as number + return this.workflowId } catch(error) { - debug('List workflows error', error); - throw error; + debug('List workflows error', error) + throw error } } private isFilename(workflowRef: string) { - return /.+\.ya?ml$/.test(workflowRef); + return /.+\.ya?ml$/.test(workflowRef) } private debugFoundWorkflowRuns(runs: any){ @@ -213,7 +213,7 @@ export class WorkflowHandler { triggerDate: new Date(this.triggerDate).toISOString(), created_at_ts: new Date(r.created_at).valueOf(), triggerDateTs: this.triggerDate - }))); + }))) } } diff --git a/src/workflow-logs-handler.ts b/src/workflow-logs-handler.ts index 75bd26a..2e8da97 100644 --- a/src/workflow-logs-handler.ts +++ b/src/workflow-logs-handler.ts @@ -1,6 +1,6 @@ import * as core from '@actions/core' import * as github from '@actions/github' -import { debug } from './debug'; +import { debug } from './debug' interface JobInfo { name: string, @@ -9,25 +9,25 @@ interface JobInfo { export async function handleWorkflowLogsPerJob(args: any, workflowRunId: number): Promise { - const mode = args.workflowLogMode; - const token = args.token; - const owner = args.owner; - const repo = args.repo; + const mode = args.workflowLogMode + const token = args.token + const owner = args.owner + const repo = args.repo - const handler = logHandlerFactory(mode); + const handler = logHandlerFactory(mode) if (handler == null) { - return; + return } - const octokit = github.getOctokit(token); - const runId = workflowRunId; + const octokit = github.getOctokit(token) + const runId = workflowRunId const response = await octokit.rest.actions.listJobsForWorkflowRun({ owner: owner, repo: repo, run_id: runId - }); + }) - await handler.handleJobList(response.data.jobs); + await handler.handleJobList(response.data.jobs) for (const job of response.data.jobs) { try { @@ -35,22 +35,22 @@ export async function handleWorkflowLogsPerJob(args: any, workflowRunId: number) owner: owner, repo: repo, job_id: job.id, - }); - await handler.handleJobLogs(job, jobLog.data as string); + }) + await handler.handleJobLogs(job, jobLog.data as string) } catch (error: any) { - await handler.handleError(job, error); + await handler.handleError(job, error) } } switch (mode) { case 'json-output': - core.setOutput('workflow-logs', (handler as OutputLogsHandler).getJsonLogs()); - break; + core.setOutput('workflow-logs', (handler as OutputLogsHandler).getJsonLogs()) + break case 'output': - core.setOutput('workflow-logs', (handler as OutputLogsHandler).getRawLogs()); - break; + core.setOutput('workflow-logs', (handler as OutputLogsHandler).getRawLogs()) + break default: - break; + break } } @@ -63,80 +63,80 @@ interface WorkflowLogHandler { class PrintLogsHandler implements WorkflowLogHandler { async handleJobList(jobs: Array): Promise { - debug('Retrieving logs for jobs in workflow', jobs); + debug('Retrieving logs for jobs in workflow', jobs) } async handleJobLogs(job: JobInfo, logs: string): Promise { - core.startGroup(`Logs of job '${job.name}'`); - core.info(escapeImportedLogs(logs)); - core.endGroup(); + core.startGroup(`Logs of job '${job.name}'`) + core.info(escapeImportedLogs(logs)) + core.endGroup() } async handleError(job: JobInfo, error: Error): Promise { - core.warning(escapeImportedLogs(error.message)); + core.warning(escapeImportedLogs(error.message)) } } class OutputLogsHandler implements WorkflowLogHandler { - private logs: Map = new Map(); + private logs: Map = new Map() async handleJobList(jobs: Array): Promise { - debug('Retrieving logs for jobs in workflow', jobs); + debug('Retrieving logs for jobs in workflow', jobs) } async handleJobLogs(job: JobInfo, logs: string): Promise { - this.logs.set(job.name, logs); + this.logs.set(job.name, logs) } async handleError(job: JobInfo, error: Error): Promise { - core.warning(escapeImportedLogs(error.message)); + core.warning(escapeImportedLogs(error.message)) } getJsonLogs(): string { - const result: any = {}; - const logPattern = /(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{7}Z)\s+(.*)/; + const result: any = {} + const logPattern = /(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{7}Z)\s+(.*)/ this.logs.forEach((logs: string, jobName: string) => { - result[jobName] = []; + result[jobName] = [] for (const line of logs.split('\n')) { if (line === '') { - continue; + continue } - const splitted = line.split(logPattern); + const splitted = line.split(logPattern) result[jobName].push({ datetime: splitted[1], message: splitted[2] - }); + }) } // result[jobName] = logs; - }); - return JSON.stringify(result); + }) + return JSON.stringify(result) } getRawLogs(): string { - let result = ''; + let result = '' this.logs.forEach((logs: string, jobName: string) => { for (const line of logs.split('\n')) { - result += `${jobName} | ${line}\n`; + result += `${jobName} | ${line}\n` } - }); - return result; + }) + return result } } function logHandlerFactory(mode: string): WorkflowLogHandler | null { switch(mode) { case 'print': - return new PrintLogsHandler(); + return new PrintLogsHandler() case 'output': case 'json-output': - return new OutputLogsHandler(); + return new OutputLogsHandler() default: - return null; + return null } } function escapeImportedLogs(str: string): string { - return str.replace(/^/mg, "| ") - .replace(/##\[([^\]]+)\]/gm, "##<$1>") + return str.replace(/^/mg, '| ') + .replace(/##\[([^\]]+)\]/gm, '##<$1>') }