From 31f755f1edab26b5ce6a12a35fb220a6c6479ad9 Mon Sep 17 00:00:00 2001 From: snowiow Date: Wed, 28 Jul 2021 14:41:36 +0200 Subject: [PATCH] Handle Cancelled State --- README.md | 8 ++++++-- dist/index.js | 42 +++++++++++++++++++++++++++++------------- dist/index.js.map | 2 +- src/index.ts | 40 ++++++++++++++++++++++++++++------------ 4 files changed, 64 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 129a9c366..68f845892 100644 --- a/README.md +++ b/README.md @@ -25,14 +25,18 @@ user or role you login to needs the following permissions: "Statement": [ { "Effect": "Allow", - "Action": ["codepipeline:StartPipelineExecution", "codepipeline:GetPipelineExecution"], + "Action": [ + "codepipeline:StartPipelineExecution", + "codepipeline:GetPipelineExecution", + "codepipeline:ListPipelineExecutions" + ], "Resource": ["arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${PipelineName}"] } ] } ``` -`codepipeline:GetPipelineExecution` is only necessary, if you set `wait: true`, +`codepipeline:GetPipelineExecution` and `codepipeline:ListPipelineExecutions` are only necessary, if you set `wait: true`, otherwise the GitHub Action Workflow continues without checking the pipeline state. diff --git a/dist/index.js b/dist/index.js index 4d124de84..26d943941 100644 --- a/dist/index.js +++ b/dist/index.js @@ -23,6 +23,18 @@ const core = __importStar(require("@actions/core")); const client_codepipeline_1 = require("@aws-sdk/client-codepipeline"); const CLIENT = new client_codepipeline_1.CodePipelineClient({}); const sleep = (s) => new Promise((resolve) => setTimeout(resolve, s * 1000)); +const getNewestExecutionId = async (pipelineName) => { + const command = new client_codepipeline_1.ListPipelineExecutionsCommand({ pipelineName, maxResults: 1 }); + const data = await CLIENT.send(command); + if (data.pipelineExecutionSummaries && data.pipelineExecutionSummaries.length > 0) { + const executionId = data.pipelineExecutionSummaries[0].pipelineExecutionId; + if (executionId) { + return executionId; + } + throw new Error(`Newest pipeline execution of '${pipelineName}' has no ID`); + } + throw new Error('No Pipeline executions found'); +}; const waitForPipeline = async (pipelineName, pipelineExecutionId) => { await sleep(10); const command = new client_codepipeline_1.GetPipelineExecutionCommand({ pipelineName, pipelineExecutionId }); @@ -37,24 +49,27 @@ const waitForPipeline = async (pipelineName, pipelineExecutionId) => { case client_codepipeline_1.PipelineExecutionStatus.InProgress: core.info(`Pipeline '${pipelineName}' in progress waiting for 10 more seconds.`); return await waitForPipeline(pipelineName, pipelineExecutionId); + case client_codepipeline_1.PipelineExecutionStatus.Cancelled: { + core.info(`Pipeline '${pipelineName}' was canceled. Trying to get new execution ID.`); + const newExecutionId = await getNewestExecutionId(pipelineName); + core.info(`Waiting on pipeline '${pipelineName}' with new execution id '${newExecutionId}`); + return await waitForPipeline(pipelineName, newExecutionId); + } + case client_codepipeline_1.PipelineExecutionStatus.Succeeded: + core.info(`Pipeline '${pipelineName}' succeeded.`); + return true; case client_codepipeline_1.PipelineExecutionStatus.Failed: - core.info(`Pipeline '${pipelineName}' failed.`); + core.error(`Pipeline '${pipelineName}' failed.`); return false; case client_codepipeline_1.PipelineExecutionStatus.Stopping || client_codepipeline_1.PipelineExecutionStatus.Stopped: - core.info(`Pipeline '${pipelineName}' stopped.`); + core.error(`Pipeline '${pipelineName}' stopped.`); return false; case client_codepipeline_1.PipelineExecutionStatus.Superseded: - core.info(`Pipeline '${pipelineName}' was superseded.`); - return false; - case client_codepipeline_1.PipelineExecutionStatus.Cancelled: - core.info(`Pipeline '${pipelineName}' was canceled. Trying to get new execution ID.`); - // TODO: To implement + core.error(`Pipeline '${pipelineName}' was superseded.`); return false; - case client_codepipeline_1.PipelineExecutionStatus.Succeeded: - core.info(`Pipeline '${pipelineName}' succeeded.`); - return true; default: - throw new Error(`Unexpected status: ${status} given.`); + core.error(`Unexpected status: ${status} given.`); + return false; } } catch (error) { @@ -74,12 +89,13 @@ const run = async () => { if (wait) { const executionResult = await waitForPipeline(pipelineName, data.pipelineExecutionId); if (!executionResult) { - throw new Error('Execution was unsucessful.'); + core.setFailed('Execution was unsucessful.'); + return; } } } catch (error) { - core.error(`An error occured while starting Codepipeline '${pipelineName}'`); + core.setFailed(`An error occured while starting Codepipeline '${pipelineName}'`); throw error; } }; diff --git a/dist/index.js.map b/dist/index.js.map index 6a9c7235c..273a16c2c 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA,oDAAsC;AACtC,sEAMsC;AAEtC,MAAM,MAAM,GAAG,IAAI,wCAAkB,CAAC,EAAE,CAAC,CAAC;AAE1C,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AAErF,MAAM,oBAAoB,GAAG,KAAK,EAAE,YAAoB,EAAmB,EAAE;IAC3E,MAAM,OAAO,GAAG,IAAI,mDAA6B,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;IACnF,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxC,IAAI,IAAI,CAAC,0BAA0B,IAAI,IAAI,CAAC,0BAA0B,CAAC,MAAM,GAAG,CAAC,EAAE;QACjF,MAAM,WAAW,GAAG,IAAI,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC;QAC3E,IAAI,WAAW,EAAE;YACf,OAAO,WAAW,CAAC;SACpB;QACD,MAAM,IAAI,KAAK,CAAC,iCAAiC,YAAY,aAAa,CAAC,CAAC;KAC7E;IACD,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;AAClD,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,KAAK,EAAE,YAAoB,EAAE,mBAA2B,EAAoB,EAAE;IACpG,MAAM,KAAK,CAAC,EAAE,CAAC,CAAC;IAChB,MAAM,OAAO,GAAG,IAAI,iDAA2B,CAAC,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC,CAAC;IACvF,IAAI;QACF,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAExC,IAAI,IAAI,CAAC,iBAAiB,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE;YAC1E,IAAI,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;YACrC,OAAO,KAAK,CAAC;SACd;QACD,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC;QAC1C,QAAQ,MAAM,EAAE;YACd,KAAK,6CAAuB,CAAC,UAAU;gBACrC,IAAI,CAAC,IAAI,CAAC,aAAa,YAAY,4CAA4C,CAAC,CAAC;gBACjF,OAAO,MAAM,eAAe,CAAC,YAAY,EAAE,mBAAmB,CAAC,CAAC;YAClE,KAAK,6CAAuB,CAAC,SAAS,CAAC,CAAC;gBACtC,IAAI,CAAC,IAAI,CAAC,aAAa,YAAY,iDAAiD,CAAC,CAAC;gBACtF,MAAM,cAAc,GAAG,MAAM,oBAAoB,CAAC,YAAY,CAAC,CAAC;gBAChE,IAAI,CAAC,IAAI,CAAC,wBAAwB,YAAY,4BAA4B,cAAc,EAAE,CAAC,CAAC;gBAC5F,OAAO,MAAM,eAAe,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;aAC5D;YACD,KAAK,6CAAuB,CAAC,SAAS;gBACpC,IAAI,CAAC,IAAI,CAAC,aAAa,YAAY,cAAc,CAAC,CAAC;gBACnD,OAAO,IAAI,CAAC;YACd,KAAK,6CAAuB,CAAC,MAAM;gBACjC,IAAI,CAAC,KAAK,CAAC,aAAa,YAAY,WAAW,CAAC,CAAC;gBACjD,OAAO,KAAK,CAAC;YACf,KAAK,6CAAuB,CAAC,QAAQ,IAAI,6CAAuB,CAAC,OAAO;gBACtE,IAAI,CAAC,KAAK,CAAC,aAAa,YAAY,YAAY,CAAC,CAAC;gBAClD,OAAO,KAAK,CAAC;YACf,KAAK,6CAAuB,CAAC,UAAU;gBACrC,IAAI,CAAC,KAAK,CAAC,aAAa,YAAY,mBAAmB,CAAC,CAAC;gBACzD,OAAO,KAAK,CAAC;YACf;gBACE,IAAI,CAAC,KAAK,CAAC,sBAAsB,MAAM,SAAS,CAAC,CAAC;gBAClD,OAAO,KAAK,CAAC;SAChB;KACF;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,CAAC,KAAK,CACR,0DAA0D,YAAY,iBAAiB,mBAAmB,IAAI,CAC/G,CAAC;QACF,MAAM,KAAK,CAAC;KACb;AACH,CAAC,CAAC;AAEF,MAAM,GAAG,GAAG,KAAK,IAAmB,EAAE;IACpC,MAAM,YAAY,GAAW,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3E,MAAM,IAAI,GAAY,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;IAExE,MAAM,OAAO,GAAG,IAAI,mDAA6B,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;IAE1E,IAAI;QACF,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE;YAC7B,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;SACpC;QACD,IAAI,IAAI,EAAE;YACR,MAAM,eAAe,GAAG,MAAM,eAAe,CAAC,YAAY,EAAE,IAAI,CAAC,mBAAmB,CAAC,CAAC;YACtF,IAAI,CAAC,eAAe,EAAE;gBACpB,IAAI,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC;gBAC7C,OAAO;aACR;SACF;KACF;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,CAAC,SAAS,CAAC,iDAAiD,YAAY,GAAG,CAAC,CAAC;QACjF,MAAM,KAAK,CAAC;KACb;AACH,CAAC,CAAC;AAEF,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC"} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 373a31b1f..56c7bfbcc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,12 +4,26 @@ import { StartPipelineExecutionCommand, GetPipelineExecutionCommand, PipelineExecutionStatus, + ListPipelineExecutionsCommand, } from '@aws-sdk/client-codepipeline'; const CLIENT = new CodePipelineClient({}); const sleep = (s: number) => new Promise((resolve) => setTimeout(resolve, s * 1000)); +const getNewestExecutionId = async (pipelineName: string): Promise => { + const command = new ListPipelineExecutionsCommand({ pipelineName, maxResults: 1 }); + const data = await CLIENT.send(command); + if (data.pipelineExecutionSummaries && data.pipelineExecutionSummaries.length > 0) { + const executionId = data.pipelineExecutionSummaries[0].pipelineExecutionId; + if (executionId) { + return executionId; + } + throw new Error(`Newest pipeline execution of '${pipelineName}' has no ID`); + } + throw new Error('No Pipeline executions found'); +}; + const waitForPipeline = async (pipelineName: string, pipelineExecutionId: string): Promise => { await sleep(10); const command = new GetPipelineExecutionCommand({ pipelineName, pipelineExecutionId }); @@ -25,25 +39,27 @@ const waitForPipeline = async (pipelineName: string, pipelineExecutionId: string case PipelineExecutionStatus.InProgress: core.info(`Pipeline '${pipelineName}' in progress waiting for 10 more seconds.`); return await waitForPipeline(pipelineName, pipelineExecutionId); + case PipelineExecutionStatus.Cancelled: { + core.info(`Pipeline '${pipelineName}' was canceled. Trying to get new execution ID.`); + const newExecutionId = await getNewestExecutionId(pipelineName); + core.info(`Waiting on pipeline '${pipelineName}' with new execution id '${newExecutionId}`); + return await waitForPipeline(pipelineName, newExecutionId); + } + case PipelineExecutionStatus.Succeeded: + core.info(`Pipeline '${pipelineName}' succeeded.`); + return true; case PipelineExecutionStatus.Failed: - core.info(`Pipeline '${pipelineName}' failed.`); + core.error(`Pipeline '${pipelineName}' failed.`); return false; case PipelineExecutionStatus.Stopping || PipelineExecutionStatus.Stopped: - core.info(`Pipeline '${pipelineName}' stopped.`); + core.error(`Pipeline '${pipelineName}' stopped.`); return false; case PipelineExecutionStatus.Superseded: - core.info(`Pipeline '${pipelineName}' was superseded.`); - return false; - case PipelineExecutionStatus.Cancelled: - core.info(`Pipeline '${pipelineName}' was canceled. Trying to get new execution ID.`); - // TODO: To implement + core.error(`Pipeline '${pipelineName}' was superseded.`); return false; - - case PipelineExecutionStatus.Succeeded: - core.info(`Pipeline '${pipelineName}' succeeded.`); - return true; default: - throw new Error(`Unexpected status: ${status} given.`); + core.error(`Unexpected status: ${status} given.`); + return false; } } catch (error) { core.error(