Skip to content

Build base images on native hardware #377

Build base images on native hardware

Build base images on native hardware #377

Workflow file for this run

name: CI
on:
push:
# Avoid duplicate builds on PRs.
branches:
- main
tags:
- v*
pull_request:
permissions:
contents: read
jobs:
shellcheck:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run shellcheck
run: find . -type f \( -name "*.sh" -o -path "*/bin/*" \) ! -name '*.jq' | xargs -t shellcheck
build-images:
name: "Build heroku-${{ matrix.stack-version }} (${{ matrix.arch }})"
needs:
- shellcheck
runs-on: ${{ matrix.arch == 'arm64' && 'pub-hk-ubuntu-24.04-arm-medium' || 'ubuntu-24.04' }}
strategy:
fail-fast: false
matrix:
arch: ["amd64", "arm64"]
stack-version: ["20", "22", "24"]
exclude:
- arch: "arm64"
stack-version: "20"
- arch: "arm64"
stack-version: "22"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build images
run: bin/build.sh "${{ matrix.stack-version }}" "${{ matrix.arch }}"
- name: Check that the generated files are in sync
run: |-
status="$(git status --porcelain)"
if [[ -n "$status" ]]; then
echo "Generated files differ from checked-in versions! Run bin/build.sh to regenerate them locally."
echo -e "\nChanged files:\n${status}\n"
git diff
exit 1
fi
- name: Export base images from the Docker daemon
if: github.ref_name == 'main' || github.ref_type == 'tag'
run: |
docker save $(docker images --format '{{.Repository}}:{{.Tag}}' | grep "heroku/heroku:${{ matrix.stack-version }}") | zstd -T0 --long=31 -o images.tar.zst
- name: Save base images to the cache
if: github.ref_name == 'main' || github.ref_type == 'tag'
uses: actions/cache/save@v4
with:
key: ${{ github.run_id}}-${{ matrix.stack-version }}-${{ matrix.arch }}
path: images.tar.zst
publish-images:
if: github.ref_name == 'main' || github.ref_type == 'tag'
name: "Publish heroku-${{ matrix.stack-version }} (${{ matrix.arch }})"
needs:
- build-images
runs-on: ${{ matrix.arch == 'arm64' && 'pub-hk-ubuntu-24.04-arm-medium' || 'ubuntu-24.04' }}
env:
TAG_SUFFIX: ".${{ github.ref_type == 'tag' && github.ref_name || 'nightly' }}"
strategy:
fail-fast: false
matrix:
arch: ["amd64", "arm64"]
stack-version: ["20", "22", "24"]
exclude:
- arch: "arm64"
stack-version: "20"
- arch: "arm64"
stack-version: "22"
steps:
- name: Restore base images from the cache
uses: actions/cache/restore@v4
with:
fail-on-cache-miss: true
key: ${{ github.run_id}}-${{ matrix.stack-version }}-${{ 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
run: echo '${{ secrets.DOCKER_HUB_TOKEN }}' | docker login -u '${{ secrets.DOCKER_HUB_USERNAME }}' --password-stdin
- name: Publish base images to registries
run: |
variants=("" "-build")
platformSuffix=""
if (( ${{ matrix.stack-version }} >= 24 )); then
platformSuffix="_linux-${{ matrix.arch }}"
else
variants+=("-cnb" "-cnb-build")
fi
for variant in "${variants[@]}"; do
srcTag="heroku/heroku:${{ matrix.stack-version}}${variant}"
destTag="${srcTag}${platformSuffix}${TAG_SUFFIX}"
docker tag "${srcTag}" "${destTag}"
docker push "${destTag}"
done
publish-indicies:
if: github.ref_name == 'main' || github.ref_type == 'tag'
name: "Publish heroku-${{ matrix.stack-version }} indicies"
needs:
- publish-images
runs-on: ubuntu-24.04
env:
TAG_SUFFIX: ".${{ github.ref_type == 'tag' && github.ref_name || 'nightly' }}"
strategy:
fail-fast: false
matrix:
stack-version: ["24"]
steps:
- name: Log into Docker Hub
run: echo '${{ secrets.DOCKER_HUB_TOKEN }}' | docker login -u '${{ secrets.DOCKER_HUB_USERNAME }}' --password-stdin
- name: Publish multi-arch image index
run: |
for variant in '' '-build'; do
indexTag="heroku/heroku:${{ matrix.stack-version }}${variant}${TAG_SUFFIX}"
armTag="heroku/heroku:${{ matrix.stack-version }}${variant}_linux-arm64${TAG_SUFFIX}"
amdTag="heroku/heroku:${{ matrix.stack-version }}${variant}_linux-amd64${TAG_SUFFIX}"
docker manifest create "$indexTag" "$amdTag" "$armTag"
docker manifest push "$indexTag"
done
promote-tags:
if: github.ref_type == 'tag'
name: "Promote heroku-${{ matrix.stack-version }} tags"
needs:
- publish-images
- publish-indicies
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
stack-version: ["20", "22", "24"]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Log into Docker Hub
run: echo '${{ secrets.DOCKER_HUB_TOKEN }}' | docker login -u '${{ secrets.DOCKER_HUB_USERNAME }}' --password-stdin
- name: Install crane
uses: buildpacks/github-actions/[email protected]
- name: Promote images to stable tag
run: |
destTags=( )
if (( ${{ matrix.stack-version }} >= 24 )); then
for variant in '' '-build'; do
for arch in 'amd64' 'arm64'; do
destTags+=("heroku/heroku:${{ matrix.stack-version }}${variant}_linux-${arch}")
done
destTags+=("heroku/heroku:${{ matrix.stack-version }}${variant}")
done
else
for variant in '' '-build' '-cnb' '-cnb-build'; do
destTags+=("heroku/heroku:${{ matrix.stack-version }}${variant}")
done
fi
for destTag in "${destTags[@]}"; do
srcTag="${destTag}.${{ github.ref_name }}"
echo "${srcTag}" "${destTag}"
done
publish-stack:
if: github.ref_type == 'tag'
name: "Publish heroku-${{ matrix.stack-version }} stack"
needs:
- promote-tags
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
stack-version: ["20", "22", "24"]
env:
STACK: heroku-${{ matrix.stack-version }}
MANIFEST_APP_TOKEN: "${{ secrets.MANIFEST_APP_TOKEN }}"
MANIFEST_APP_URL: "${{ secrets.MANIFEST_APP_URL }}"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Pull base images
run: |
docker pull heroku/heroku:${{matrix.stack-version}}
docker pull heroku/heroku:${{matrix.stack-version}}-build
- name: Convert docker image and for Git tags release to Heroku staging
run: bin/convert-and-publish-to-heroku.sh