Update lifecycle from v0.21.14 to v0.21.16 #2762
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build, Test, Publish | |
| on: | |
| pull_request: | |
| push: | |
| branches: ["main"] | |
| schedule: | |
| - cron: "0 0 * * 1-5" | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| id-token: write | |
| defaults: | |
| run: | |
| # Setting an explicit bash shell ensures GitHub Actions enables pipefail mode too, rather | |
| # than only error on exit. This is important for UX since this workflow uses pipes. See: | |
| # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsshell | |
| shell: bash | |
| jobs: | |
| create: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| builder: ["builder-22", "builder-24", "builder-26"] | |
| arch: ["amd64", "arm64"] | |
| exclude: | |
| # Builders prior to Heroku-24 don't support ARM. We're using an exclude rather than | |
| # an include so that the ARM jobs don't appear out of sequence in the GitHub UI. | |
| - builder: builder-22 | |
| arch: arm64 | |
| runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - name: Install Pack CLI | |
| uses: buildpacks/github-actions/setup-pack@c1c71086a0e89a65c04ea113390227fd7f05d9df # v6.0.0 | |
| - name: Create builder image | |
| run: pack builder create ${{ matrix.builder }} --config ${{ matrix.builder }}/builder.toml --pull-policy always | |
| # We export the run image too (and not just the generated builder image), since it adds virtually | |
| # no size to the archive (since the layers are mostly duplicates), and it ends up being quicker | |
| # than docker pulling the run image in the jobs that perform the pack build. | |
| # We manually compress the archive rather than relying upon actions/cache's compression, since | |
| # it ends up being faster both in this job and also later when the images are consumed. | |
| - name: Export Docker images from the Docker daemon | |
| # Using sed rather than yq until this yq bug is fixed: | |
| # https://github.com/mikefarah/yq/issues/1758 | |
| run: | | |
| RUN_IMAGE_TAG=$(sed --quiet --regexp-extended --expression 's/run-image\s*=\s*"(.+)"/\1/p' ${{ matrix.builder }}/builder.toml) | |
| docker save ${{ matrix.builder }} ${RUN_IMAGE_TAG} | zstd -T0 --long=31 -o images.tar.zst | |
| # We use a cache here rather than artifacts because it's 4x faster and we | |
| # don't need the builder archive outside of this workflow run anyway. | |
| - name: Save Docker images to the cache | |
| uses: actions/cache/save@v6 | |
| with: | |
| key: ${{ github.run_id}}-${{ matrix.builder }}-${{ matrix.arch }} | |
| path: images.tar.zst | |
| test: | |
| runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} | |
| needs: create | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| language: | |
| [ | |
| "dotnet", | |
| "go", | |
| "gradle", | |
| "java", | |
| "nodejs", | |
| "php", | |
| "python", | |
| "ruby", | |
| "scala", | |
| ] | |
| builder: ["builder-22", "builder-24", "builder-26"] | |
| arch: ["amd64", "arm64"] | |
| exclude: | |
| - builder: builder-22 | |
| arch: arm64 | |
| steps: | |
| - name: Checkout getting started guide | |
| uses: actions/checkout@v7 | |
| with: | |
| ref: main | |
| repository: heroku/${{ matrix.language }}-getting-started.git | |
| - name: Install Pack CLI | |
| uses: buildpacks/github-actions/setup-pack@c1c71086a0e89a65c04ea113390227fd7f05d9df # v6.0.0 | |
| - name: Restore Docker images from the cache | |
| uses: actions/cache/restore@v6 | |
| with: | |
| fail-on-cache-miss: true | |
| key: ${{ github.run_id}}-${{ matrix.builder }}-${{ matrix.arch }} | |
| path: images.tar.zst | |
| env: | |
| SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 | |
| - name: Load Docker images into the Docker daemon | |
| run: zstd -dc --long=31 images.tar.zst | docker load | |
| - name: Build getting started guide image | |
| run: pack build getting-started --force-color --builder ${{ matrix.builder }} --trust-builder --pull-policy never | |
| - name: Start getting started guide image | |
| run: docker run --name getting-started --detach -p 8080:8080 --env PORT=8080 getting-started | |
| - name: Test getting started web server response | |
| run: | | |
| if curl -sSfL --retry 10 --retry-delay 1 --retry-all-errors --connect-timeout 3 http://localhost:8080 -o response.txt; then | |
| echo "Successful response from server" | |
| else | |
| echo "Server did not respond successfully" | |
| docker logs getting-started | |
| [[ -f response.txt ]] && cat response.txt | |
| exit 1 | |
| fi | |
| publish-image: | |
| runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} | |
| if: success() && github.ref == 'refs/heads/main' | |
| needs: test | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - builder: builder-22 | |
| arch: amd64 | |
| tag_docker_hub: heroku/builder:22 | |
| tag_ecr_public: heroku/builder:22 | |
| - builder: builder-24 | |
| arch: amd64 | |
| tag_docker_hub: heroku/builder:24_linux-amd64 | |
| tag_ecr_public: heroku/builder:24_linux-amd64 | |
| - builder: builder-24 | |
| arch: arm64 | |
| tag_docker_hub: heroku/builder:24_linux-arm64 | |
| tag_ecr_public: heroku/builder:24_linux-arm64 | |
| - builder: builder-26 | |
| arch: amd64 | |
| tag_docker_hub: heroku/builder:26_linux-amd64 | |
| tag_ecr_public: heroku/builder:26_linux-amd64 | |
| - builder: builder-26 | |
| arch: arm64 | |
| tag_docker_hub: heroku/builder:26_linux-arm64 | |
| tag_ecr_public: heroku/builder:26_linux-arm64 | |
| steps: | |
| - name: Restore Docker images from the cache | |
| uses: actions/cache/restore@v6 | |
| with: | |
| fail-on-cache-miss: true | |
| key: ${{ github.run_id}}-${{ matrix.builder }}-${{ matrix.arch }} | |
| path: images.tar.zst | |
| env: | |
| SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1 | |
| - name: Load Docker images into the Docker daemon | |
| run: zstd -dc --long=31 images.tar.zst | docker load | |
| - name: Log into Docker Hub | |
| if: matrix.tag_docker_hub != '' | |
| run: echo '${{ secrets.DOCKER_HUB_TOKEN }}' | docker login -u '${{ secrets.DOCKER_HUB_USER }}' --password-stdin | |
| - name: Configure AWS credentials | |
| if: matrix.tag_ecr_public != '' | |
| uses: aws-actions/configure-aws-credentials@e6de054238d6b7531b4efff3b6587d9aade6a06c # v6.2.3 | |
| with: | |
| role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ECR_ROLE }} | |
| aws-region: ${{ vars.AWS_REGION }} | |
| - name: Log in to Amazon ECR Public | |
| if: matrix.tag_ecr_public != '' | |
| id: login-ecr-public | |
| uses: aws-actions/amazon-ecr-login@d539f0932e70871a027e9d5a9d8fc38589180a64 # v2.1.6 | |
| with: | |
| registry-type: public | |
| - name: Tag builder and push to Docker Hub | |
| if: matrix.tag_docker_hub != '' | |
| run: | | |
| DOCKER_HUB_IMAGE_URI='${{ matrix.tag_docker_hub }}' | |
| set -x | |
| docker tag '${{ matrix.builder }}' "${DOCKER_HUB_IMAGE_URI}" | |
| docker push "${DOCKER_HUB_IMAGE_URI}" | |
| - name: Tag builder and push to public ECR | |
| if: matrix.tag_ecr_public != '' | |
| run: | | |
| ECR_PUBLIC_IMAGE_URI='public.ecr.aws/${{ matrix.tag_ecr_public }}' | |
| set -x | |
| docker tag '${{ matrix.builder }}' "${ECR_PUBLIC_IMAGE_URI}" | |
| docker push "${ECR_PUBLIC_IMAGE_URI}" | |
| publish-manifest: | |
| runs-on: ubuntu-24.04 | |
| needs: publish-image | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - tag_uri: "docker.io/heroku/builder:24" | |
| manifest_uris: "docker.io/heroku/builder:24_linux-amd64 docker.io/heroku/builder:24_linux-arm64" | |
| - tag_uri: "public.ecr.aws/heroku/builder:24" | |
| manifest_uris: "public.ecr.aws/heroku/builder:24_linux-amd64 public.ecr.aws/heroku/builder:24_linux-arm64" | |
| - tag_uri: "docker.io/heroku/builder:26" | |
| manifest_uris: "docker.io/heroku/builder:26_linux-amd64 docker.io/heroku/builder:26_linux-arm64" | |
| - tag_uri: "public.ecr.aws/heroku/builder:26" | |
| manifest_uris: "public.ecr.aws/heroku/builder:26_linux-amd64 public.ecr.aws/heroku/builder:26_linux-arm64" | |
| steps: | |
| - name: Log in to Docker Hub | |
| run: echo '${{ secrets.DOCKER_HUB_TOKEN }}' | docker login -u '${{ secrets.DOCKER_HUB_USER }}' --password-stdin | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@e6de054238d6b7531b4efff3b6587d9aade6a06c # v6.2.3 | |
| with: | |
| role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ECR_ROLE }} | |
| aws-region: ${{ vars.AWS_REGION }} | |
| - name: Log in to Amazon ECR Public | |
| id: login-ecr-public | |
| uses: aws-actions/amazon-ecr-login@d539f0932e70871a027e9d5a9d8fc38589180a64 # v2.1.6 | |
| with: | |
| registry-type: public | |
| - name: Create and push manifest lists | |
| run: | | |
| set -x | |
| docker manifest create "${{ matrix.tag_uri }}" ${{ matrix.manifest_uris }} | |
| docker manifest push "${{ matrix.tag_uri }}" | |
| post-honeycomb-marker: | |
| name: Post Honeycomb release marker | |
| needs: publish-manifest | |
| # Every push to main rebuilds and republishes the builder, so each one is a genuine | |
| # release worth tracking. Excludes the nightly `schedule` rebuild and `workflow_dispatch`, | |
| # both of which republish unchanged images. | |
| if: success() && github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| # Only the tip commit's subject and timestamp are needed to label the release. | |
| with: | |
| fetch-depth: 1 | |
| - name: Post Honeycomb release marker | |
| env: | |
| HONEYCOMB_API_KEY: ${{ secrets.HONEYCOMB_API_KEY }} | |
| HONEYCOMB_DATASET: heroku-builds-production | |
| COMMIT_URL: ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }} | |
| run: | | |
| msg=$(git log -1 --format=%s) | |
| # Anchor the marker to the release commit time, not "now": this job may run delayed | |
| # after a re-trigger, and the commit timestamp is stable across re-runs. | |
| start_time=$(git log -1 --format=%ct) | |
| api="https://api.honeycomb.io/1/markers/${HONEYCOMB_DATASET}" | |
| curl=(curl -sS --fail --connect-timeout 10 --retry 3 --retry-all-errors --max-time 30 | |
| -H "X-Honeycomb-Team: ${HONEYCOMB_API_KEY}" -H "Content-Type: application/json") | |
| # One marker per builder release; dedup on the commit URL (stable identity for this | |
| # release). If a marker already exists (e.g. a re-run of the workflow), skip — the | |
| # marker is unchanged, so there's nothing to update. This job is the last in the | |
| # workflow and runs after the release has already published, so letting it fail red | |
| # on a Honeycomb error surfaces the problem (retry/bug) without blocking the release. | |
| existing=$("${curl[@]}" "${api}" \ | |
| | jq -r --arg url "$COMMIT_URL" 'map(select(.url == $url)) | first | .id // empty') | |
| if [[ -n "$existing" ]]; then | |
| echo "Release marker already exists (${existing}) — skipping." | |
| exit 0 | |
| fi | |
| body=$(jq -n --arg msg "$msg" --arg url "$COMMIT_URL" --argjson start "$start_time" \ | |
| '{message: $msg, type: "deploy", url: $url, start_time: $start}') | |
| "${curl[@]}" -X POST "${api}" -d "${body}" | |
| echo "Created release marker for ${msg}" |