From bc48c183aa5de7d20b13509d3470ff39604dc14a Mon Sep 17 00:00:00 2001 From: Harsh Mishra Date: Tue, 13 Oct 2026 07:44:52 +0530 Subject: [PATCH 1/4] Fail fast on pipeline errors and add CI for both samples Fail fast on pipeline errors and add CI for both samples Claude-Session: https://claude.ai/code/session_01DZfDmzUBPqNAu3yFKyfCNM --- .github/workflows/main.yml | 64 ++++++++++++++++++++ 1-codebuild-compile-s3-upload/run.sh | 18 +++++- 2-codebuild-test-codeartifact-publish/run.sh | 21 ++++++- README.md | 4 ++ 4 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..c1f73b7 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,64 @@ +name: Run on LocalStack + +on: + push: + paths-ignore: + - '**.md' + branches: + - master + pull_request: + branches: + - master + workflow_dispatch: + +permissions: + contents: read + +jobs: + pipeline: + name: ${{ matrix.sample }} + runs-on: ubuntu-latest + timeout-minutes: 45 + strategy: + fail-fast: false + matrix: + sample: + - 1-codebuild-compile-s3-upload + - 2-codebuild-test-codeartifact-publish + defaults: + run: + working-directory: ${{ matrix.sample }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + # The CodeBuild image LocalStack runs builds in is over 6 GB compressed + - name: Free disk space + working-directory: . + run: | + sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache/CodeQL + df -h / + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Install lstk + run: | + npm install -g @localstack/lstk + lstk setup aws --force --non-interactive + + - name: Start LocalStack + env: + LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }} + # Forwarded as CODEPIPELINE_GH_TOKEN, used to download the source archives from GitHub + LOCALSTACK_CODEPIPELINE_GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: lstk start + + - name: Run the pipeline + run: bash run.sh + + - name: Show LocalStack logs + if: failure() + run: lstk logs | tail -300 diff --git a/1-codebuild-compile-s3-upload/run.sh b/1-codebuild-compile-s3-upload/run.sh index a6ae52d..88f483f 100755 --- a/1-codebuild-compile-s3-upload/run.sh +++ b/1-codebuild-compile-s3-upload/run.sh @@ -30,10 +30,22 @@ lstk aws codepipeline create-pipeline --pipeline file://./pipeline.json lstk aws codepipeline list-pipeline-executions --pipeline-name demo-pipeline # Wait for pipeline to finish +MAX_WAIT_SECONDS=${MAX_WAIT_SECONDS:-1800} status= -until [[ $status =~ Succeeded ]]; do - status=$(lstk aws codepipeline list-pipeline-executions --pipeline-name demo-pipeline --output text --query pipelineExecutionSummaries[0].status) +waited=0 +until [[ $status == Succeeded ]]; do + if [[ $status =~ ^(Failed|Stopped|Superseded)$ ]]; then + echo "Pipeline execution ended with status $status" + lstk aws codepipeline get-pipeline-state --name demo-pipeline + exit 1 + fi + if (( waited >= MAX_WAIT_SECONDS )); then + echo "Pipeline did not finish within ${MAX_WAIT_SECONDS}s, last status: $status" + exit 1 + fi sleep 5 + waited=$((waited + 5)) + status=$(lstk aws codepipeline list-pipeline-executions --pipeline-name demo-pipeline --output text --query 'pipelineExecutionSummaries[0].status') done # Retrieve build @@ -42,4 +54,4 @@ lstk aws s3 cp s3://output-bucket/fzf/fzf . # Try build file fzf chmod +x fzf -./fzf --version +./fzf --version | grep '^0.62 ' diff --git a/2-codebuild-test-codeartifact-publish/run.sh b/2-codebuild-test-codeartifact-publish/run.sh index 9c14207..b264ba5 100755 --- a/2-codebuild-test-codeartifact-publish/run.sh +++ b/2-codebuild-test-codeartifact-publish/run.sh @@ -1,4 +1,4 @@ -#!/bin/env bash +#!/usr/bin/env bash set -xeuo pipefail @@ -40,10 +40,22 @@ lstk aws s3 mb s3://demo-artif-bucket lstk aws codepipeline create-pipeline --pipeline file://./demo-pipeline.json # Wait for the pipeline to finish +MAX_WAIT_SECONDS=${MAX_WAIT_SECONDS:-1800} status= -until [[ $status =~ Succeeded ]]; do - status=$(lstk aws codepipeline list-pipeline-executions --pipeline-name demo-pipeline --output text --query pipelineExecutionSummaries[0].status) +waited=0 +until [[ $status == Succeeded ]]; do + if [[ $status =~ ^(Failed|Stopped|Superseded)$ ]]; then + echo "Pipeline execution ended with status $status" + lstk aws codepipeline get-pipeline-state --name demo-pipeline + exit 1 + fi + if (( waited >= MAX_WAIT_SECONDS )); then + echo "Pipeline did not finish within ${MAX_WAIT_SECONDS}s, last status: $status" + exit 1 + fi sleep 5 + waited=$((waited + 5)) + status=$(lstk aws codepipeline list-pipeline-executions --pipeline-name demo-pipeline --output text --query 'pipelineExecutionSummaries[0].status') done # Configure NPM to work with the local CodeArtifact repository @@ -52,3 +64,6 @@ lstk aws codeartifact login --tool npm --domain demo-domain --repository demo-re # Try to download the NPM package npm pack my-lodash-fork + +# Check the downloaded package is the fork published by the pipeline +tar -xzOf my-lodash-fork-*.tgz package/package.json | grep '"name": "my-lodash-fork"' diff --git a/README.md b/README.md index 8f79bf9..319773f 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,10 @@ export LOCALSTACK_AUTH_TOKEN= export CODEPIPELINE_GH_TOKEN= ``` +If you start LocalStack with `lstk start`, export the token as `LOCALSTACK_CODEPIPELINE_GH_TOKEN` instead. `lstk` only forwards `LOCALSTACK_`-prefixed variables to the container, which strips the prefix. + +Each `run.sh` fails if the pipeline execution fails or takes longer than `MAX_WAIT_SECONDS` (default 1800). + ## Samples - [1-codebuild-compile-s3-upload](1-codebuild-compile-s3-upload/README.md): Builds `fzf` with CodeBuild and uploads the resulting binary to S3 through CodePipeline. From 678240eb0838d492fdf3c4fafdb4462954639bd9 Mon Sep 17 00:00:00 2001 From: Harsh Mishra Date: Tue, 13 Oct 2026 08:24:18 +0530 Subject: [PATCH 2/4] Show pipeline state when CI fails Dump the pipeline state, action executions, CodeBuild phases and LocalStack logs without the polling noise. Drop the free disk step, the runner has over 100 GB free. Claude-Session: https://claude.ai/code/session_01DZfDmzUBPqNAu3yFKyfCNM --- .github/workflows/main.yml | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c1f73b7..64e24fa 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -32,13 +32,6 @@ jobs: - name: Checkout uses: actions/checkout@v4 - # The CodeBuild image LocalStack runs builds in is over 6 GB compressed - - name: Free disk space - working-directory: . - run: | - sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache/CodeQL - df -h / - - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -57,8 +50,19 @@ jobs: run: lstk start - name: Run the pipeline + env: + MAX_WAIT_SECONDS: 1200 run: bash run.sh - - name: Show LocalStack logs + - name: Show pipeline state and LocalStack logs if: failure() - run: lstk logs | tail -300 + run: | + lstk aws codepipeline get-pipeline-state --name demo-pipeline || true + lstk aws codepipeline list-action-executions --pipeline-name demo-pipeline || true + builds=$(lstk aws codebuild list-builds --query 'ids' --output text || true) + [ -n "$builds" ] && lstk aws codebuild batch-get-builds --ids $builds \ + --query 'builds[].{id: id, status: buildStatus, phases: phases[].[phaseType, phaseStatus, contexts[0].message]}' || true + docker ps -a + docker images + df -h / + lstk logs | grep -vE 'ListPipelineExecutions|ListActionExecutions' | tail -400 From b65f74f5dd62897db3e133cf1a7851f5b6ba7a8e Mon Sep 17 00:00:00 2001 From: Harsh Mishra Date: Tue, 13 Oct 2026 08:49:43 +0530 Subject: [PATCH 3/4] Pull the CodeBuild images before running the pipelines LocalStack checks the build container about 10 seconds after a build starts. If the image is still downloading, the check fails with 'Container not yet started', the build stays IN_PROGRESS and the pipeline never finishes. Claude-Session: https://claude.ai/code/session_01DZfDmzUBPqNAu3yFKyfCNM --- .github/workflows/main.yml | 7 +++++++ README.md | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 64e24fa..ef07ea6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -32,6 +32,13 @@ jobs: - name: Checkout uses: actions/checkout@v4 + # LocalStack stops tracking a build whose image is still downloading, + # so pull the CodeBuild images (about 17 GB) before starting the pipeline + - name: Pull the CodeBuild images + run: | + docker pull -q public.ecr.aws/codebuild/amazonlinux-x86_64-standard:5.0 + docker pull -q localstack/aws-codebuild-local:2 + - name: Setup Node.js uses: actions/setup-node@v4 with: diff --git a/README.md b/README.md index 319773f..30d82da 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,15 @@ If you start LocalStack with `lstk start`, export the token as `LOCALSTACK_CODEP Each `run.sh` fails if the pipeline execution fails or takes longer than `MAX_WAIT_SECONDS` (default 1800). +Pull the CodeBuild images before the first run: + +```bash +docker pull public.ecr.aws/codebuild/amazonlinux-x86_64-standard:5.0 +docker pull localstack/aws-codebuild-local:2 +``` + +LocalStack stops tracking a build if its image is still downloading a few seconds after the build starts, and the pipeline then stays `InProgress`. + ## Samples - [1-codebuild-compile-s3-upload](1-codebuild-compile-s3-upload/README.md): Builds `fzf` with CodeBuild and uploads the resulting binary to S3 through CodePipeline. From 1d97e47ba3fb99be5287f3bd896f7f2503727705 Mon Sep 17 00:00:00 2001 From: Harsh Mishra Date: Tue, 13 Oct 2026 08:56:33 +0530 Subject: [PATCH 4/4] Retry the CodeBuild image pulls ECR Public answered 'toomanyrequests: Data limit exceeded' for an anonymous pull from a shared runner IP. Claude-Session: https://claude.ai/code/session_01DZfDmzUBPqNAu3yFKyfCNM --- .github/workflows/main.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ef07ea6..259df18 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,8 +36,15 @@ jobs: # so pull the CodeBuild images (about 17 GB) before starting the pipeline - name: Pull the CodeBuild images run: | - docker pull -q public.ecr.aws/codebuild/amazonlinux-x86_64-standard:5.0 - docker pull -q localstack/aws-codebuild-local:2 + # Anonymous ECR Public pulls are rate limited per IP, which runners share + for image in public.ecr.aws/codebuild/amazonlinux-x86_64-standard:5.0 localstack/aws-codebuild-local:2; do + for attempt in 1 2 3 4 5; do + docker pull -q "$image" && break + [ "$attempt" = 5 ] && exit 1 + echo "Pull of $image failed, retrying in 60s" + sleep 60 + done + done - name: Setup Node.js uses: actions/setup-node@v4