-
Notifications
You must be signed in to change notification settings - Fork 0
Run samples on arm64 as well as amd64 in CI #108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -78,9 +78,82 @@ BICEP_SAMPLES=( | |||||||||||||||||||||||
| ALL_SAMPLES=("${SAMPLES[@]}" "${TERRAFORM_SAMPLES[@]}" "${BICEP_SAMPLES[@]}") | ||||||||||||||||||||||||
| TOTAL=${#ALL_SAMPLES[@]} | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # 1c. Architecture support | ||||||||||||||||||||||||
| # Samples listed here run *natively* on both amd64 and arm64 (Apple Silicon, arm64 CI | ||||||||||||||||||||||||
| # runners). For everything else, the container image the emulator starts is published by | ||||||||||||||||||||||||
| # Microsoft for amd64 alone — there is no arm64 manifest: | ||||||||||||||||||||||||
| # - `az webapp create --runtime ...` (code deployment) runs the app on | ||||||||||||||||||||||||
| # mcr.microsoft.com/oryx/<platform>, which is amd64-only. That rules out every | ||||||||||||||||||||||||
| # web-app-* sample, plus eventhubs (it deploys a dashboard web app). | ||||||||||||||||||||||||
| # - Java App Service uses mcr.microsoft.com/azure-app-service/java — amd64-only. | ||||||||||||||||||||||||
| # - SQL Database is backed by mcr.microsoft.com/mssql/server — amd64-only. | ||||||||||||||||||||||||
| # The samples below avoid all of those: Function Apps get an image built from a | ||||||||||||||||||||||||
| # multi-arch base (arm64 support added in localstack-pro#8102), and the custom-image | ||||||||||||||||||||||||
| # Web App and ACI samples run an image the sample itself builds. Their Cosmos DB, | ||||||||||||||||||||||||
| # Service Bus, Storage and Front Door dependencies all publish arm64 manifests. | ||||||||||||||||||||||||
| # | ||||||||||||||||||||||||
| # "amd64-only" means *not native* — not "cannot run". The emulator never pins | ||||||||||||||||||||||||
| # --platform, so on an arm64 host Docker pulls the amd64 manifest and runs it under | ||||||||||||||||||||||||
| # whatever emulation the runtime provides. Docker Desktop on Apple Silicon emulates it | ||||||||||||||||||||||||
| # via Rosetta, which is why these samples do work on a Mac, just more slowly. They fail | ||||||||||||||||||||||||
| # on an arm64 host with no emulation registered, such as GitHub's ubuntu-*-arm runners, | ||||||||||||||||||||||||
| # so CI schedules only the natively-supported samples below on arm64. | ||||||||||||||||||||||||
| # | ||||||||||||||||||||||||
| # LocalStack's own test suite draws the same line: after localstack-pro#8102, Web App | ||||||||||||||||||||||||
| # tests that only assert SCM/deployment records run on arm64, while the ones that | ||||||||||||||||||||||||
| # exercise a *running* Oryx app (test_deploy_zip_that_accesses_storage, | ||||||||||||||||||||||||
| # test_deploy_zip_without_basic_auth) are still marked @only_on_amd64. | ||||||||||||||||||||||||
| ARM64_SAMPLE_DIRS=( | ||||||||||||||||||||||||
| "samples/aci-blob-storage/python" | ||||||||||||||||||||||||
| "samples/function-app-front-door/python" | ||||||||||||||||||||||||
| "samples/function-app-managed-identity/python" | ||||||||||||||||||||||||
| "samples/function-app-service-bus/dotnet" | ||||||||||||||||||||||||
| "samples/function-app-storage-http/dotnet" | ||||||||||||||||||||||||
| "samples/web-app-custom-image/python" | ||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. LOW | A stale Description: Rules applied: Verified: passes unchanged on the current list, and fails with the message below when an entry no longer matches a registered sample.
Suggested change
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Fail loudly if an entry no longer matches a registered sample: a rename would otherwise | ||||||||||||||||||||||||
| # silently drop that sample's arm64 coverage while CI stays green. | ||||||||||||||||||||||||
| for _arm64_dir in "${ARM64_SAMPLE_DIRS[@]}"; do | ||||||||||||||||||||||||
| if ! printf '%s\n' "${ALL_SAMPLES[@]}" | cut -d'|' -f1 | sed -E 's#/(terraform|bicep)$##' | grep -qxF "$_arm64_dir"; then | ||||||||||||||||||||||||
| echo >&2 "ARM64_SAMPLE_DIRS entry '$_arm64_dir' matches no registered sample - fix the path or remove the entry." | ||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
| done | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Architecture support is a property of the sample itself, not of the deployment method, | ||||||||||||||||||||||||
| # so strip the /terraform or /bicep suffix before matching against ARM64_SAMPLE_DIRS. | ||||||||||||||||||||||||
| supports_arm64() { | ||||||||||||||||||||||||
| local path="$1" family dir | ||||||||||||||||||||||||
| case "$path" in | ||||||||||||||||||||||||
| */terraform | */bicep) family=$(dirname "$path") ;; | ||||||||||||||||||||||||
| *) family="$path" ;; | ||||||||||||||||||||||||
| esac | ||||||||||||||||||||||||
| for dir in "${ARM64_SAMPLE_DIRS[@]}"; do | ||||||||||||||||||||||||
| [[ "$dir" == "$family" ]] && return 0 | ||||||||||||||||||||||||
| done | ||||||||||||||||||||||||
| return 1 | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Normalise `uname -m` to the architecture names used above. Anything not recognisably | ||||||||||||||||||||||||
| # arm64 is reported as amd64, so an exotic host (armv7l, ppc64le, ...) takes the amd64 | ||||||||||||||||||||||||
| # path and gets no arm64 warning: it errs toward "run it and let the deployment fail" | ||||||||||||||||||||||||
| # rather than skipping silently. | ||||||||||||||||||||||||
| host_arch() { | ||||||||||||||||||||||||
| case "$(uname -m)" in | ||||||||||||||||||||||||
| aarch64 | arm64) echo "arm64" ;; | ||||||||||||||||||||||||
| x86_64 | amd64) echo "amd64" ;; | ||||||||||||||||||||||||
| *) | ||||||||||||||||||||||||
| echo >&2 "Note: unrecognised architecture '$(uname -m)'; treating it as amd64." | ||||||||||||||||||||||||
| echo "amd64" | ||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||
| esac | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # 2. Handle --list flag: output JSON metadata for CI matrix generation (no tools required) | ||||||||||||||||||||||||
| # Each entry has: shard (1-based index), splits (total count), name, and watch_folders. | ||||||||||||||||||||||||
| # CI uses watch_folders to detect which tests are affected by changed files. | ||||||||||||||||||||||||
| # Each entry has: shard (1-based index), splits (total count), name, watch_folders, | ||||||||||||||||||||||||
| # and arches. CI uses watch_folders to detect which tests are affected by changed | ||||||||||||||||||||||||
| # files, and arches to decide which architectures to run the test on. | ||||||||||||||||||||||||
| if [[ "${1:-}" == "--list" ]]; then | ||||||||||||||||||||||||
| echo "[" | ||||||||||||||||||||||||
| for (( i=0; i<TOTAL; i++ )); do | ||||||||||||||||||||||||
|
|
@@ -98,8 +171,15 @@ if [[ "${1:-}" == "--list" ]]; then | |||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| folders=$(printf '"%s",' "${watch[@]}") | ||||||||||||||||||||||||
| printf ' {"shard":%d,"splits":%d,"name":"%s","watch_folders":[%s]}' \ | ||||||||||||||||||||||||
| $((i+1)) "$TOTAL" "$name" "${folders%,}" | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| if supports_arm64 "$path"; then | ||||||||||||||||||||||||
| arches='"amd64","arm64"' | ||||||||||||||||||||||||
| else | ||||||||||||||||||||||||
| arches='"amd64"' | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| printf ' {"shard":%d,"splits":%d,"name":"%s","watch_folders":[%s],"arches":[%s]}' \ | ||||||||||||||||||||||||
| $((i+1)) "$TOTAL" "$name" "${folders%,}" "$arches" | ||||||||||||||||||||||||
| (( i < TOTAL-1 )) && echo "," || echo "" | ||||||||||||||||||||||||
| done | ||||||||||||||||||||||||
| echo "]" | ||||||||||||||||||||||||
|
|
@@ -164,8 +244,11 @@ if [ "$SHARD" -eq "$SPLITS" ]; then | |||||||||||||||||||||||
| COUNT=$(( TOTAL - START )) | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| HOST_ARCH=$(host_arch) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| echo "Running samples shard $SHARD of $SPLITS (index $START, count $COUNT)" | ||||||||||||||||||||||||
| echo "Total samples (scripts + terraform + bicep): $TOTAL" | ||||||||||||||||||||||||
| echo "Host architecture: $HOST_ARCH" | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # 7. Run Samples — deploy each test, then run its validation if defined | ||||||||||||||||||||||||
| for (( i=START; i<START+COUNT; i++ )); do | ||||||||||||||||||||||||
|
|
@@ -175,6 +258,20 @@ for (( i=START; i<START+COUNT; i++ )); do | |||||||||||||||||||||||
| echo "Testing Sample: $path" | ||||||||||||||||||||||||
| echo "============================================================" | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Warn rather than skip: on an arm64 host these still run under amd64 emulation | ||||||||||||||||||||||||
| # (Rosetta on Docker Desktop), just slowly. Set SKIP_AMD64_ONLY=1 to skip them | ||||||||||||||||||||||||
| # instead — useful on an arm64 host with no emulation registered, where they would | ||||||||||||||||||||||||
| # otherwise fail with an opaque error deep inside a deployment. | ||||||||||||||||||||||||
| if [[ "$HOST_ARCH" == "arm64" ]] && ! supports_arm64 "$path"; then | ||||||||||||||||||||||||
| if [[ "${SKIP_AMD64_ONLY:-0}" == "1" ]]; then | ||||||||||||||||||||||||
| echo "Skipped: $path needs an amd64-only container image (SKIP_AMD64_ONLY=1)." | ||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
| echo "Note: $path needs an amd64-only container image; on arm64 it runs under" | ||||||||||||||||||||||||
| echo " emulation (slower) and fails outright if the runtime cannot emulate" | ||||||||||||||||||||||||
| echo " amd64. Set SKIP_AMD64_ONLY=1 to skip these instead." | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| pushd "$path" > /dev/null | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| echo "Deploying..." | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MEDIUM | An unrecognised arch filter yields zero jobs and a green workflow
Description: An
ARCH_FILTERvalue that is not exactlyboth/amd64/arm64matches no arch in theselect, so the expansion produces an empty matrix,has_tests=false, and the wholescriptsjob is skipped while the workflow still reports success. I confirmed it by running the script directly:The new
JOB_COUNTcheck is the right call for a genuine no-match, but it also makes a typo indistinguishable from the legitimate "nothing changed" outcome, so the failure is silent instead of loud. In CI thechoicedropdown constrains the value, so the realistic triggers are a local invocation, a future caller, or a typo inDEFAULT_ARCH.Rules applied:
.claude/rules/azure/common/coding-style.md, "Error Handling — Handle errors explicitly at every level / Never silently swallow exceptions".Verified this suggestion keeps
both/amd64/arm64at 48/34/14 jobs, still defaults an empty$3toboth, and exits 1 on anything else: