This file contains 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
# Copyright (C) 2022 Roberto Rossini (roberros@uio.no) | |
# SPDX-License-Identifier: MIT | |
name: "Build Ubuntu Docker images for CXX development/testing" | |
on: | |
push: | |
branches: [ main, devel, ci-devel ] | |
paths: | |
- ".github/workflows/build-cxx-ubuntu-images.yml" | |
- "assets/settings.yml" | |
- "dockerfiles/ubuntu-cxx.Dockerfile" | |
pull_request: | |
branches: [ main, devel, ci-devel ] | |
paths: | |
- ".github/workflows/build-cxx-ubuntu-images.yml" | |
- "assets/settings.yml" | |
- "dockerfiles/ubuntu-cxx.Dockerfile" | |
workflow_dispatch: | |
schedule: | |
# Run weekly | |
- cron: "15 0 * * 0" | |
defaults: | |
run: | |
shell: bash | |
permissions: | |
contents: read | |
packages: write | |
jobs: | |
matrix-factory: | |
name: Generate job matrix | |
runs-on: ubuntu-latest | |
outputs: | |
matrix: ${{ steps.generate-matrix.outputs.matrix }} | |
matrix-amd64: ${{ steps.generate-matrix.outputs.matrix-amd64 }} | |
matrix-arm64: ${{ steps.generate-matrix.outputs.matrix-arm64 }} | |
steps: | |
- name: Generate matrix | |
id: generate-matrix | |
shell: python | |
run: | | |
import json | |
import os | |
import sys | |
os_name = "ubuntu" | |
cmake_version = "3.31.*" | |
conan_version = "2.11.*" | |
templates = ( | |
{ | |
"compiler-name": "gcc", | |
"compiler-version": 8, | |
"os-version": "20.04", | |
"python-version": "3.9", | |
}, | |
{ | |
"compiler-name": "gcc", | |
"compiler-version": 9, | |
"os-version": "22.04", | |
"python-version": "3.11", | |
}, | |
{ | |
"compiler-name": "gcc", | |
"compiler-version": 10, | |
"os-version": "24.04", | |
"python-version": "3.12", | |
}, | |
{ | |
"compiler-name": "gcc", | |
"compiler-version": 11, | |
"os-version": "24.04", | |
"python-version": "3.12", | |
}, | |
{ | |
"compiler-name": "gcc", | |
"compiler-version": 12, | |
"os-version": "24.04", | |
"python-version": "3.12", | |
}, | |
{ | |
"compiler-name": "gcc", | |
"compiler-version": 13, | |
"os-version": "24.04", | |
"python-version": "3.12", | |
}, | |
{ | |
"compiler-name": "gcc", | |
"compiler-version": 14, | |
"os-version": "24.04", | |
"python-version": "3.12", | |
}, | |
{ | |
"compiler-name": "clang", | |
"compiler-version": 8, | |
"os-version": "20.04", | |
"python-version": "3.9", | |
}, | |
{ | |
"compiler-name": "clang", | |
"compiler-version": 9, | |
"os-version": "20.04", | |
"python-version": "3.9", | |
}, | |
{ | |
"compiler-name": "clang", | |
"compiler-version": 10, | |
"os-version": "20.04", | |
"python-version": "3.9", | |
}, | |
{ | |
"compiler-name": "clang", | |
"compiler-version": 11, | |
"os-version": "22.04", | |
"python-version": "3.11", | |
}, | |
{ | |
"compiler-name": "clang", | |
"compiler-version": 12, | |
"os-version": "22.04", | |
"python-version": "3.11", | |
}, | |
{ | |
"compiler-name": "clang", | |
"compiler-version": 13, | |
"os-version": "22.04", | |
"python-version": "3.11", | |
}, | |
{ | |
"compiler-name": "clang", | |
"compiler-version": 14, | |
"os-version": "24.04", | |
"python-version": "3.12", | |
}, | |
{ | |
"compiler-name": "clang", | |
"compiler-version": 15, | |
"os-version": "24.04", | |
"python-version": "3.12", | |
}, | |
{ | |
"compiler-name": "clang", | |
"compiler-version": 16, | |
"os-version": "24.04", | |
"python-version": "3.12", | |
}, | |
{ | |
"compiler-name": "clang", | |
"compiler-version": 17, | |
"os-version": "24.04", | |
"python-version": "3.12", | |
}, | |
{ | |
"compiler-name": "clang", | |
"compiler-version": 18, | |
"os-version": "24.04", | |
"python-version": "3.12", | |
}, | |
{ | |
"compiler-name": "clang", | |
"compiler-version": 19, | |
"os-version": "20.04", | |
"python-version": "3.9", | |
}, | |
{ | |
"compiler-name": "clang", | |
"compiler-version": 19, | |
"os-version": "22.04", | |
"python-version": "3.11", | |
}, | |
{ | |
"compiler-name": "clang", | |
"compiler-version": 19, | |
"os-version": "24.04", | |
"python-version": "3.12", | |
}, | |
) | |
includes_amd64 = [] | |
includes_arm64 = [] | |
for t in templates: | |
t |= {"os-name": os_name, "cmake-version": cmake_version, "conan-version": conan_version} | |
includes_amd64.append(t | {"runner": "ubuntu-24.04", "platform": "linux/amd64"}) | |
includes_arm64.append(t | {"runner": "ubuntu-24.04-arm", "platform": "linux/arm64"}) | |
# TODO remove me | |
includes_amd64 = includes_amd64[-2:] | |
includes_arm64 = includes_arm64[-2:] | |
includes = includes_amd64 + includes_arm64 | |
json.dump( | |
{"include": includes}, | |
fp=sys.stdout, | |
indent=2, | |
sort_keys=True, | |
) | |
def write_output(key, data, f): | |
data = json.dumps( | |
{"include": data}, | |
sort_keys=True, | |
) | |
print(f"{key}={data}", file=f) | |
with open(os.environ.get("GITHUB_OUTPUT"), "a") as f: | |
write_output("matrix-amd64", includes_amd64, f) | |
write_output("matrix-arm64", includes_arm64, f) | |
write_output("matrix", includes, f) | |
build-dockerfile: | |
name: Build Dockerfile | |
needs: [matrix-factory] | |
outputs: | |
image: ${{ steps.metadata.outputs.image }} | |
tag: ${{ steps.metadata.outputs.build-date }} | |
strategy: | |
fail-fast: false | |
matrix: ${{ fromJson(needs.matrix-factory.outputs.matrix) }} | |
runs-on: ${{ matrix.runner }} | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Extract metadata | |
id: metadata | |
run: | | |
cdate="$(git show -s --format='%as' HEAD | tr -d '-')" | |
_date="$(date +%Y%m%d)" | |
image='ghcr.io/${{ github.repository }}/${{ matrix.os-name }}-${{ matrix.os-version }}-cxx-${{ matrix.compiler-name }}-${{ matrix.compiler-version }}' | |
echo "commit-date=$cdate" | tee -a "$GITHUB_OUTPUT" | |
echo "build-date=$_date" | tee -a "$GITHUB_OUTPUT" | |
echo "image=$image" | tee -a "$GITHUB_OUTPUT" | |
- name: Docker meta | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: ${{ steps.metadata.outputs.image }} | |
flavor: latest=true | |
tags: type=raw,value=${{ steps.metadata.outputs.build-date }} | |
- name: Login to GitHub Container Registry | |
if: github.event_name != 'pull_request' | |
uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.repository_owner }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Build Docker image | |
uses: docker/build-push-action@v6 | |
id: build-image | |
with: | |
load: true | |
push: false | |
file: dockerfiles/ubuntu-cxx.Dockerfile | |
labels: ${{ steps.meta.outputs.labels }} | |
platforms: ${{ matrix.platform }} | |
tags: tmp:latest | |
build-args: | | |
BASE_OS=${{ matrix.os-name }}:${{ matrix.os-version }} | |
COMPILER_NAME=${{ matrix.compiler-name }} | |
COMPILER_VERSION=${{ matrix.compiler-version }} | |
CMAKE_VERSION=${{ matrix.cmake-version }} | |
CONAN_VERSION=${{ matrix.conan-version }} | |
PYTHON_VERSION=${{ matrix.python-version }} | |
- name: Test Docker image | |
run: test/test_docker_image.sh tmp:latest | |
- name: Push image to registries | |
if: github.event_name != 'pull_request' | |
uses: docker/build-push-action@v6 | |
id: push-image | |
with: | |
context: ${{ github.workspace }} | |
push: true | |
file: dockerfiles/ubuntu-cxx.Dockerfile | |
labels: ${{ steps.meta.outputs.labels }} | |
platforms: ${{ matrix.platform }} | |
outputs: type=image,"name=${{ steps.metadata.outputs.image }}",push-by-digest=true,name-canonical=true,push=true | |
build-args: | | |
BASE_OS=${{ matrix.os-name }}:${{ matrix.os-version }} | |
COMPILER_NAME=${{ matrix.compiler-name }} | |
COMPILER_VERSION=${{ matrix.compiler-version }} | |
CMAKE_VERSION=${{ matrix.cmake-version }} | |
CONAN_VERSION=${{ matrix.conan-version }} | |
PYTHON_VERSION=${{ matrix.python-version }} | |
- name: Export digest | |
if: github.event_name != 'pull_request' | |
run: | | |
mkdir -p ${{ runner.temp }}/digests | |
digest="${{ steps.push-image.outputs.digest }}" | |
touch "${{ runner.temp }}/digests/${digest#sha256:}" | |
- name: Generate artifact name | |
if: github.event_name != 'pull_request' | |
id: generate-artifact-name | |
run: | | |
echo 'name=${{ steps.metadata.outputs.image }}-${{ matrix.platform }}' | | |
sed 's|[^[:alnum:]=-]\+|-|g' | | |
tee -a $GITHUB_OUTPUT | |
- name: Upload digest | |
if: github.event_name != 'pull_request' | |
uses: actions/upload-artifact@v4 | |
with: | |
name: digests-${{ steps.generate-artifact-name.outputs.name }} | |
path: ${{ runner.temp }}/digests/* | |
if-no-files-found: error | |
retention-days: 1 | |
merge-images: | |
name: Merge images | |
runs-on: ubuntu-latest | |
needs: | |
- matrix-factory | |
- build-dockerfile | |
strategy: | |
fail-fast: false | |
matrix: ${{ fromJson(needs.matrix-factory.outputs.matrix-amd64) }} | |
if: github.event_name != 'pull_request' | |
steps: | |
- name: Collect metadata | |
id: metadata | |
run: | | |
image='ghcr.io/${{ github.repository }}/${{ matrix.os-name }}-${{ matrix.os-version }}-cxx-${{ matrix.compiler-name }}-${{ matrix.compiler-version }}' | |
artifact_name="$(echo "$image" | sed 's|[^[:alnum:]=-]\+|-|g')" | |
tags='${{ needs.build-dockerfile.outputs.tag }}' # This is ok because all jobs output the same tag | |
echo "image=$image" | tee -a "$GITHUB_OUTPUT" | |
echo "artifact-name=$artifact_name" | tee -a $GITHUB_OUTPUT | |
echo "tags=$tag" | tee -a $GITHUB_OUTPUT | |
- name: Download digests | |
uses: actions/download-artifact@v4 | |
with: | |
path: ${{ runner.temp }}/digests | |
pattern: digests-${{ steps.metadata.outputs.artifact-name }}-* | |
merge-multiple: true | |
- name: Login to GitHub Container Registry | |
uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.repository_owner }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Docker meta | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
flavor: latest=true | |
images: ${{ steps.metadata.outputs.image }} | |
tags: ${{ steps.metadata.outputs.tags }} | |
- name: Create manifest list and push | |
working-directory: ${{ runner.temp }}/digests | |
run: | | |
# https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners | |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
$(printf ' ${{ steps.metadata.outputs.image }}@sha256:%s ' *) | |
- name: Inspect image | |
run: docker buildx imagetools inspect ${{ steps.metadata.outputs.image }}:${{ steps.meta.outputs.version }} | |
build-cxx-ubuntu-images-status-check: | |
name: Status Check (Build Ubuntu Docker images for CXX development/testing) | |
if: ${{ always() }} | |
runs-on: ubuntu-latest | |
needs: | |
- matrix-factory | |
- build-dockerfile | |
- merge-images | |
steps: | |
- name: Collect job results | |
if: | | |
needs.matrix-factory.result != 'success' || | |
needs.build-dockerfile.result != 'success' || | |
( | |
needs.merge-images.result != 'success' && | |
needs.merge-images.result != 'skipped' | |
) | |
run: exit 1 |