Skip to content

Commit f48e551

Browse files
committed
ci: add preflight and verification to testing image release
1 parent a7ee0a9 commit f48e551

1 file changed

Lines changed: 153 additions & 11 deletions

File tree

.github/workflows/ecr-release.yml

Lines changed: 153 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,108 @@ env:
1313
ecr_repository_name: durable-functions/aws-durable-execution-emulator
1414

1515
jobs:
16+
preflight:
17+
# Decide whether to publish before building anything.
18+
runs-on: ubuntu-latest
19+
permissions:
20+
contents: read
21+
id-token: write # ECR Public reads require an assumed role
22+
outputs:
23+
should_publish: ${{ steps.plan.outputs.should_publish }}
24+
version: ${{ steps.plan.outputs.version }}
25+
steps:
26+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
27+
with:
28+
ref: ${{ github.event.release.tag_name }}
29+
30+
- name: Parse testing version from the release tag
31+
id: tag
32+
shell: bash
33+
env:
34+
RELEASE_TAG: ${{ github.event.release.tag_name }}
35+
run: |
36+
tag_version="$(printf '%s' "$RELEASE_TAG" | grep -oE 'testing-v[0-9]+\.[0-9]+\.[0-9]+([^,]*)' | head -n1 | sed 's/^testing-v//' || true)"
37+
if [[ -z "$tag_version" ]]; then
38+
echo "Release tag does not name the testing package. Nothing to publish."
39+
echo "tag_version=" >> "$GITHUB_OUTPUT"
40+
exit 0
41+
fi
42+
echo "tag names testing version: $tag_version"
43+
echo "tag_version=$tag_version" >> "$GITHUB_OUTPUT"
44+
45+
- name: Verify the tag version matches the source
46+
id: verify
47+
if: steps.tag.outputs.tag_version != ''
48+
shell: bash
49+
env:
50+
TAG_VERSION: ${{ steps.tag.outputs.tag_version }}
51+
ABOUT_PATH: ${{ env.package_path }}/src/aws_durable_execution_sdk_python_testing/__about__.py
52+
run: |
53+
source_version="$(grep "^__version__" "$ABOUT_PATH" | cut -d'"' -f2)"
54+
echo "source version: $source_version"
55+
if [[ "$TAG_VERSION" != "$source_version" ]]; then
56+
echo "::error::Release tag names testing-v$TAG_VERSION but __about__.py is $source_version. Aborting before any publish."
57+
exit 1
58+
fi
59+
echo "version=$source_version" >> "$GITHUB_OUTPUT"
60+
61+
- name: Configure AWS Credentials
62+
if: steps.tag.outputs.tag_version != ''
63+
uses: aws-actions/configure-aws-credentials@cbe3b392738ccf3f987d68400dafcf4b0624a56c # v6.2.4
64+
with:
65+
role-to-assume: ${{ secrets.ECR_UPLOAD_IAM_ROLE_ARN }}
66+
aws-region: ${{ env.aws_region }}
67+
68+
- name: Check whether the image tag already exists
69+
id: exists
70+
if: steps.tag.outputs.tag_version != ''
71+
shell: bash
72+
env:
73+
VERSION: ${{ steps.verify.outputs.version }}
74+
ECR_REPOSITORY: ${{ env.ecr_repository_name }}
75+
run: |
76+
repo_name="${ECR_REPOSITORY##*/}"
77+
if aws ecr-public describe-images \
78+
--region "${{ env.aws_region }}" \
79+
--repository-name "$repo_name" \
80+
--image-ids imageTag="v${VERSION}" >/dev/null 2>&1; then
81+
echo "exists=true" >> "$GITHUB_OUTPUT"
82+
else
83+
echo "exists=false" >> "$GITHUB_OUTPUT"
84+
fi
85+
86+
- name: Emit release plan
87+
id: plan
88+
shell: bash
89+
env:
90+
TAG_VERSION: ${{ steps.tag.outputs.tag_version }}
91+
VERSION: ${{ steps.verify.outputs.version }}
92+
EXISTS: ${{ steps.exists.outputs.exists }}
93+
run: |
94+
echo "## Emulator image release plan" >> "$GITHUB_STEP_SUMMARY"
95+
96+
if [[ -z "$TAG_VERSION" ]]; then
97+
echo "- decision: **skip** (release does not name the testing package)" >> "$GITHUB_STEP_SUMMARY"
98+
echo "should_publish=false" >> "$GITHUB_OUTPUT"
99+
echo "version=" >> "$GITHUB_OUTPUT"
100+
exit 0
101+
fi
102+
103+
echo "- testing version: $VERSION" >> "$GITHUB_STEP_SUMMARY"
104+
if [[ "$EXISTS" == "true" ]]; then
105+
echo "- image tag v$VERSION: already present in public ECR" >> "$GITHUB_STEP_SUMMARY"
106+
echo "- decision: **skip** (version already published)" >> "$GITHUB_STEP_SUMMARY"
107+
echo "should_publish=false" >> "$GITHUB_OUTPUT"
108+
else
109+
echo "- image tag v$VERSION: not present in public ECR" >> "$GITHUB_STEP_SUMMARY"
110+
echo "- decision: **publish**" >> "$GITHUB_STEP_SUMMARY"
111+
echo "should_publish=true" >> "$GITHUB_OUTPUT"
112+
fi
113+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
114+
16115
build-and-upload-image-to-ecr:
17-
# Only publish when the release includes a new testing package version.
18-
if: contains(github.event.release.tag_name, 'testing-v')
116+
needs: preflight
117+
if: needs.preflight.outputs.should_publish == 'true'
19118
runs-on: ubuntu-latest
20119
permissions:
21120
contents: read
@@ -24,7 +123,7 @@ jobs:
24123
full_image_arm64: ${{ steps.build-publish.outputs.full_image_arm64 }}
25124
full_image_x86_64: ${{ steps.build-publish.outputs.full_image_x86_64 }}
26125
ecr_registry_repository: ${{ steps.build-publish.outputs.ecr_registry_repository }}
27-
version: ${{ steps.version.outputs.VERSION }}
126+
version: ${{ needs.preflight.outputs.version }}
28127
strategy:
29128
matrix:
30129
include:
@@ -56,13 +155,6 @@ jobs:
56155
working-directory: ${{ env.package_path }}
57156
run: hatch build
58157

59-
- name: Get version from __about__.py
60-
id: version
61-
run: |
62-
VERSION=$(grep "^__version__" "${{ env.package_path }}/src/aws_durable_execution_sdk_python_testing/__about__.py" | cut -d'"' -f2)
63-
echo "VERSION=$VERSION"
64-
echo "VERSION=${VERSION}" >> "$GITHUB_OUTPUT"
65-
66158
- name: Configure AWS Credentials
67159
uses: aws-actions/configure-aws-credentials@cbe3b392738ccf3f987d68400dafcf4b0624a56c # v6.2.4
68160
with:
@@ -81,7 +173,7 @@ jobs:
81173
env:
82174
ECR_REGISTRY: ${{ steps.login-ecr-public.outputs.registry }}
83175
ECR_REPOSITORY: ${{ env.ecr_repository_name }}
84-
PER_ARCH_IMAGE_TAG: v${{ steps.version.outputs.VERSION }}-${{ matrix.arch }}
176+
PER_ARCH_IMAGE_TAG: v${{ needs.preflight.outputs.version }}-${{ matrix.arch }}
85177
run: |
86178
docker build --platform "${{ matrix.platform }}" --provenance false "${{ env.package_path }}" -f "${{ env.package_path }}/Dockerfile" -t "$ECR_REGISTRY/$ECR_REPOSITORY:$PER_ARCH_IMAGE_TAG"
87179
docker push "$ECR_REGISTRY/$ECR_REPOSITORY:$PER_ARCH_IMAGE_TAG"
@@ -134,3 +226,53 @@ jobs:
134226
--arch amd64 \
135227
--os linux
136228
docker manifest push "${{ needs.build-and-upload-image-to-ecr.outputs.ecr_registry_repository }}"
229+
230+
verify-publish:
231+
needs: [preflight, create-ecr-manifest-per-arch]
232+
runs-on: ubuntu-latest
233+
permissions:
234+
id-token: write
235+
steps:
236+
- name: Configure AWS Credentials
237+
uses: aws-actions/configure-aws-credentials@cbe3b392738ccf3f987d68400dafcf4b0624a56c # v6.2.4
238+
with:
239+
role-to-assume: ${{ secrets.ECR_UPLOAD_IAM_ROLE_ARN }}
240+
aws-region: ${{ env.aws_region }}
241+
242+
- name: Verify the version and latest tags on public ECR
243+
shell: bash
244+
env:
245+
VERSION: ${{ needs.preflight.outputs.version }}
246+
ECR_REPOSITORY: ${{ env.ecr_repository_name }}
247+
run: |
248+
repo_name="${ECR_REPOSITORY##*/}"
249+
version_digest=""
250+
for attempt in $(seq 1 10); do
251+
version_digest="$(aws ecr-public describe-images \
252+
--region "${{ env.aws_region }}" \
253+
--repository-name "$repo_name" \
254+
--image-ids imageTag="v${VERSION}" \
255+
--query 'imageDetails[0].imageDigest' --output text 2>/dev/null || true)"
256+
if [[ -n "$version_digest" && "$version_digest" != "None" ]]; then
257+
echo "v$VERSION is visible in public ECR ($version_digest)."
258+
break
259+
fi
260+
echo "attempt $attempt: v$VERSION not visible in public ECR yet, retrying."
261+
version_digest=""
262+
sleep 15
263+
done
264+
if [[ -z "$version_digest" ]]; then
265+
echo "::error::v$VERSION did not become visible in public ECR after publishing."
266+
exit 1
267+
fi
268+
269+
latest_digest="$(aws ecr-public describe-images \
270+
--region "${{ env.aws_region }}" \
271+
--repository-name "$repo_name" \
272+
--image-ids imageTag="latest" \
273+
--query 'imageDetails[0].imageDigest' --output text 2>/dev/null || true)"
274+
if [[ "$latest_digest" != "$version_digest" ]]; then
275+
echo "::error::latest on public ECR points at $latest_digest but v$VERSION is $version_digest."
276+
exit 1
277+
fi
278+
echo "latest on public ECR points at v$VERSION."

0 commit comments

Comments
 (0)