@@ -81,10 +81,39 @@ while [ -z "$DEPLOYMENT_ID" ] || [ "$DEPLOYMENT_ID" = 'None' ]; do
8181 InProgress|Succeeded) ;;
8282 * ) log " ERROR: unexpected pipeline status: $status " ; exit 1 ;;
8383 esac
84- DEPLOYMENT_ID=$( aws_read codepipeline list-action-executions \
84+ # Action history does not publish the external deployment ID until cleanup
85+ # finishes. Live state exposes it while traffic is shifting. Correlate both
86+ # the stage execution and action attempt so old state cannot satisfy this run.
87+ deploy_state=$( aws_read codepipeline get-pipeline-state --name " $PIPELINE " \
88+ --query " stageStates[?stageName=='Deploy'] | [0]" --output json)
89+ deploy_actions=$( aws_read codepipeline list-action-executions \
8590 --pipeline-name " $PIPELINE " --filter pipelineExecutionId=" $EXECUTION_ID " \
86- --query " actionExecutionDetails[?stageName=='Deploy'].output.executionResult.externalExecutionId | [0]" \
87- --output text)
91+ --query " actionExecutionDetails[?stageName=='Deploy']" --output json)
92+ DEPLOYMENT_ID=$( printf ' %s\n' " $deploy_actions " | DEPLOY_STATE=" $deploy_state " EXECUTION_ID=" $EXECUTION_ID " python3 -c '
93+ import json, os, re, sys
94+ state = json.loads(os.environ["DEPLOY_STATE"])
95+ actions = json.load(sys.stdin)
96+ if not state or state.get("latestExecution", {}).get("pipelineExecutionId") != os.environ["EXECUTION_ID"] or not actions:
97+ print("")
98+ sys.exit(0)
99+ if len({a["actionName"] for a in actions}) != 1:
100+ raise SystemExit("ERROR: expected one Deploy action in the app pipeline")
101+ latest = max(actions, key=lambda a: a["startTime"])
102+ matches = [a["latestExecution"] for a in state.get("actionStates", [])
103+ if a["actionName"] == latest["actionName"]
104+ and a.get("latestExecution", {}).get("actionExecutionId") == latest["actionExecutionId"]]
105+ if len(matches) > 1:
106+ raise SystemExit("ERROR: ambiguous live Deploy action")
107+ if not matches:
108+ print("")
109+ sys.exit(0)
110+ if latest["status"] not in ("InProgress", "Succeeded"):
111+ raise SystemExit("ERROR: Deploy action ended in " + latest["status"])
112+ deployment_id = matches[0].get("externalExecutionId", "")
113+ if deployment_id and not re.fullmatch(r"d-[A-Za-z0-9]+", deployment_id):
114+ raise SystemExit("ERROR: invalid CodeDeploy deployment ID in pipeline state")
115+ print(deployment_id)
116+ ' )
88117 if [ -z " $DEPLOYMENT_ID " ] || [ " $DEPLOYMENT_ID " = ' None' ]; then
89118 if [ " $status " = ' Succeeded' ]; then
90119 log ' ERROR: successful pipeline has no CodeDeploy deployment' ; exit 1
0 commit comments