name: Build build-tools image on: workflow_call: inputs: image-tag: description: "build-tools image tag" required: true type: string outputs: image-tag: description: "build-tools tag" value: ${{ inputs.image-tag }} image: description: "build-tools image" value: neondatabase/build-tools:${{ inputs.image-tag }} defaults: run: shell: bash -euo pipefail {0} # The initial idea was to prevent the waste of resources by not re-building the `build-tools` image # for the same tag in parallel workflow runs, and queue them to be skipped once we have # the first image pushed to Docker registry, but GitHub's concurrency mechanism is not working as expected. # GitHub can't have more than 1 job in a queue and removes the previous one, it causes failures if the dependent jobs. # # Ref https://github.com/orgs/community/discussions/41518 # # concurrency: # group: build-build-tools-image-${{ inputs.image-tag }} # cancel-in-progress: false # No permission for GITHUB_TOKEN by default; the **minimal required** set of permissions should be granted in each job. permissions: {} jobs: check-image: uses: ./.github/workflows/check-build-tools-image.yml build-image: needs: [ check-image ] if: needs.check-image.outputs.found == 'false' strategy: matrix: debian-version: [ bullseye, bookworm ] arch: [ x64, arm64 ] runs-on: ${{ fromJson(format('["self-hosted", "{0}"]', matrix.arch == 'arm64' && 'large-arm64' || 'large')) }} env: IMAGE_TAG: ${{ inputs.image-tag }} steps: - name: Check `input.tag` is correct env: INPUTS_IMAGE_TAG: ${{ inputs.image-tag }} CHECK_IMAGE_TAG : ${{ needs.check-image.outputs.image-tag }} run: | if [ "${INPUTS_IMAGE_TAG}" != "${CHECK_IMAGE_TAG}" ]; then echo "'inputs.image-tag' (${INPUTS_IMAGE_TAG}) does not match the tag of the latest build-tools image 'inputs.image-tag' (${CHECK_IMAGE_TAG})" exit 1 fi - uses: actions/checkout@v4 - uses: ./.github/actions/set-docker-config-dir - uses: docker/setup-buildx-action@v3 with: cache-binary: false - uses: docker/login-action@v3 with: username: ${{ secrets.NEON_DOCKERHUB_USERNAME }} password: ${{ secrets.NEON_DOCKERHUB_PASSWORD }} - uses: docker/login-action@v3 with: registry: cache.neon.build username: ${{ secrets.NEON_CI_DOCKERCACHE_USERNAME }} password: ${{ secrets.NEON_CI_DOCKERCACHE_PASSWORD }} - uses: docker/build-push-action@v6 with: file: build-tools.Dockerfile context: . provenance: false push: true pull: true build-args: | DEBIAN_VERSION=${{ matrix.debian-version }} cache-from: type=registry,ref=cache.neon.build/build-tools:cache-${{ matrix.debian-version }}-${{ matrix.arch }} cache-to: ${{ github.ref_name == 'main' && format('type=registry,ref=cache.neon.build/build-tools:cache-{0}-{1},mode=max', matrix.debian-version, matrix.arch) || '' }} tags: | neondatabase/build-tools:${{ inputs.image-tag }}-${{ matrix.debian-version }}-${{ matrix.arch }} merge-images: needs: [ build-image ] runs-on: ubuntu-22.04 steps: - uses: docker/login-action@v3 with: username: ${{ secrets.NEON_DOCKERHUB_USERNAME }} password: ${{ secrets.NEON_DOCKERHUB_PASSWORD }} - name: Create multi-arch image env: DEFAULT_DEBIAN_VERSION: bullseye IMAGE_TAG: ${{ inputs.image-tag }} run: | for debian_version in bullseye bookworm; do tags=("-t" "neondatabase/build-tools:${IMAGE_TAG}-${debian_version}") if [ "${debian_version}" == "${DEFAULT_DEBIAN_VERSION}" ]; then tags+=("-t" "neondatabase/build-tools:${IMAGE_TAG}") fi docker buildx imagetools create "${tags[@]}" \ neondatabase/build-tools:${IMAGE_TAG}-${debian_version}-x64 \ neondatabase/build-tools:${IMAGE_TAG}-${debian_version}-arm64 done