Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/smoke-test-runners.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,46 @@ jobs:
fail-fast: false
matrix:
include:
- image: ubuntu22.04-gfortran11
declares: ubuntu22.04/gfortran11
- image: ubuntu22.04-gfortran11-boost-qt6
declares: ubuntu22.04/gfortran11-boost-qt6
- image: ubuntu24.04-gfortran13-boost-qt6
declares: ubuntu24.04/gfortran13-boost-qt6
- image: ubuntu24.04-clang18-gfortran13
declares: ubuntu24.04/clang18-gfortran13
- image: ubuntu26.04-gfortran15
declares: ubuntu26.04/gfortran15
- image: ubuntu26.04-gfortran15-boost-qt6
declares: ubuntu26.04/gfortran15-boost-qt6
- image: rocky8-gfortran8-boost-qt5
declares: rocky8/gfortran8-boost-qt5
- image: rocky9-gfortran11
declares: rocky9/gfortran11
- image: rocky9-gfortran11-boost-qt5
declares: rocky9/gfortran11-boost-qt5
- image: rocky10-gfortran14
declares: rocky10/gfortran14
- image: rocky10-gfortran14-boost-qt6
declares: rocky10/gfortran14-boost-qt6
- image: debian11-gfortran10-boost-qt5
declares: debian11/gfortran10-boost-qt5
- image: debian12-gfortran12
declares: debian12/gfortran12
- image: debian12-gfortran12-boost-qt6
declares: debian12/gfortran12-boost-qt6
- image: debian13-gfortran14
declares: debian13/gfortran14
- image: debian13-gfortran14-boost-qt6
declares: debian13/gfortran14-boost-qt6
- image: fedora43-gfortran15
declares: fedora43/gfortran15
- image: fedora43-gfortran15-boost-qt6
declares: fedora43/gfortran15-boost-qt6
- image: fedora44-gfortran16
declares: fedora44/gfortran16
- image: fedora44-gfortran16-boost-qt6
declares: fedora44/gfortran16-boost-qt6
name: image (${{ matrix.image }})
runs-on: arc-runner-normal
container:
Expand Down
71 changes: 54 additions & 17 deletions IMAGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,41 @@ The `/` becomes `-` because Harbor supports only two-level repository paths

| Directory | Image |
|---|---|
| `public-images/ubuntu22.04/base` | `…/ubuntu22.04-base` |
| `public-images/ubuntu22.04/gfortran11` | `…/ubuntu22.04-gfortran11` |
| `public-images/ubuntu22.04/gfortran11-boost-qt6` | `…/ubuntu22.04-gfortran11-boost-qt6` |
| `public-images/ubuntu24.04/base` | `…/ubuntu24.04-base` |
| `public-images/ubuntu24.04/gfortran13` | `…/ubuntu24.04-gfortran13` |
| `public-images/ubuntu24.04/clang18-gfortran12` | `…/ubuntu24.04-clang18-gfortran12` |
| `public-images/ubuntu24.04/clang18-gfortran13` | `…/ubuntu24.04-clang18-gfortran13` |
| `public-images/ubuntu24.04/gfortran13-boost-qt6` | `…/ubuntu24.04-gfortran13-boost-qt6` |
| `public-images/ubuntu26.04/base` | `…/ubuntu26.04-base` |
| `public-images/ubuntu26.04/gfortran15` | `…/ubuntu26.04-gfortran15` |
| `public-images/ubuntu26.04/gfortran15-boost-qt6` | `…/ubuntu26.04-gfortran15-boost-qt6` |
| `public-images/rocky8/base` | `…/rocky8-base` |
| `public-images/rocky8/gfortran8` | `…/rocky8-gfortran8` |
| `public-images/rocky8/gfortran8-boost-qt5` | `…/rocky8-gfortran8-boost-qt5` |
| `public-images/rocky9/base` | `…/rocky9-base` |
| `public-images/rocky9/gfortran11` | `…/rocky9-gfortran11` |
| `public-images/rocky9/gfortran11-boost-qt5` | `…/rocky9-gfortran11-boost-qt5` |
| `public-images/rocky10/base` | `…/rocky10-base` |
| `public-images/rocky10/gfortran14` | `…/rocky10-gfortran14` |
| `public-images/rocky10/gfortran14-boost-qt6` | `…/rocky10-gfortran14-boost-qt6` |
| `public-images/debian11/base` | `…/debian11-base` |
| `public-images/debian11/gfortran10` | `…/debian11-gfortran10` |
| `public-images/debian11/gfortran10-boost-qt5` | `…/debian11-gfortran10-boost-qt5` |
| `public-images/debian12/base` | `…/debian12-base` |
| `public-images/debian12/gfortran12` | `…/debian12-gfortran12` |
| `public-images/debian12/gfortran12-boost-qt6` | `…/debian12-gfortran12-boost-qt6` |
| `public-images/debian13/base` | `…/debian13-base` |
| `public-images/debian13/gfortran14` | `…/debian13-gfortran14` |
| `public-images/debian13/gfortran14-boost-qt6` | `…/debian13-gfortran14-boost-qt6` |
| `public-images/fedora43/base` | `…/fedora43-base` |
| `public-images/fedora43/gfortran15` | `…/fedora43-gfortran15` |
| `public-images/fedora43/gfortran15-boost-qt6` | `…/fedora43-gfortran15-boost-qt6` |
| `public-images/fedora44/base` | `…/fedora44-base` |
| `public-images/fedora44/gfortran16` | `…/fedora44-gfortran16` |
| `public-images/fedora44/gfortran16-boost-qt6` | `…/fedora44-gfortran16-boost-qt6` |
Comment thread
Copilot marked this conversation as resolved.
| `public-images/rolling-arch/base` | `…/rolling-arch-base` |
| `public-images/rolling-arch/gfortran` | `…/rolling-arch-gfortran` |
| `public-images/rolling-arch/gfortran-boost-qt6` | `…/rolling-arch-gfortran-boost-qt6` |
Expand All @@ -55,9 +79,10 @@ all dependents in one parallel matrix, so a chain would race on `:latest`.
`scripts/build_image.py` refuses a deeper chain.

Boost and Qt are deliberately not in the base: both are large and wanted by one
package, so they live in `gfortran13-boost-qt6`, whose name then says exactly
what it adds. Qt is there because ecflow builds ecFlowUI by default
(`ENABLE_UI=ON`) and its configure step is a hard error without Qt6.
package, so they live in the `gfortran<N>-boost-qt<M>` variant, whose name says
which compiler and Qt major version it adds. Qt is there because ecflow builds
ecFlowUI by default (`ENABLE_UI=ON`) and its configure step requires a supported
Qt version. Most platforms provide Qt6; the exceptions below provide Qt5.

## Platforms

Expand All @@ -67,17 +92,25 @@ is in the *name*, so what you get is never a surprise:

| Platform | gcc | Qt | boost | cmake | `CI_INFRASTRUCTURE_PYTHON` |
|---|---|---|---|---|---|
| `ubuntu22.04` | 11 | 6 | 1.74 | 3.31.6 | `/usr/local/bin/python3.11` (built from source) |
Comment thread
Copilot marked this conversation as resolved.
| `ubuntu24.04` | 12, 13 | 6 | 1.83 | 3.28 | `/usr/bin/python3` (3.12) |
| `ubuntu26.04` | 15 | 6 | 1.90 | 4.2 | `/usr/bin/python3` (3.14) |
| `rocky8` | 8.5 (distro default) | **5** | 1.66 | 3.26 | `/usr/bin/python3.12` |
| `rocky9` | 11 | **5** | 1.75 | 3.31 | `/usr/bin/python3.12` |
Comment thread
Copilot marked this conversation as resolved.
| `rocky10` | 14 | 6 | 1.83 | 3.31 | `/usr/bin/python3` (3.12) |
Comment thread
Copilot marked this conversation as resolved.
| `debian11` | 10 | **5** | 1.74 | 3.18 | `/usr/local/bin/python3.11` (built from source) |
| `debian12` | 12 | 6 | 1.74 | 3.31.6 | `/usr/bin/python3` (3.11) |
| `debian13` | 14 | 6 | 1.83 | 3.31 | `/usr/bin/python3` (3.13) |
| `fedora43` | 15 | 6 | 1.83 | 3.31 | `/usr/bin/python3` (3.14) |
| `fedora44` | 16 | 6 | 1.90 | 4.3 | `/usr/bin/python3` (3.14) |
| `rolling-arch` | newest | 6 | newest | newest | `/usr/bin/python3` |

Three consequences worth knowing before you pick one:

**Qt5, not Qt6, on `rocky8` and `debian11`.** Neither distro has Qt6 at all —
bullseye predates it, and rocky 8 has it in no repo. ecflow's
`cmake/Dependencies.cmake` accepts either, so these are real substitutions, and
the image name says which you get.
**Qt5, not Qt6, on `rocky8`, `rocky9`, and `debian11`.** These platforms use
their supported Qt5 packages rather than the Qt6 used by the other platforms.
ecflow's `cmake/Dependencies.cmake` accepts either, so these are real
substitutions, and the image name says which you get.

**`rocky8` uses the distro's own gcc, 8.5.** Not a `gcc-toolset-N` SCL under
`/opt/rh`: 8.5 is what the distro gives you by default and what the Atos HPC GNU
Expand All @@ -88,17 +121,21 @@ every package here requires, is there. The variants symlink `gcc-8`/`g++-8`/
`gfortran-8` into `/usr/local/bin`, because the rocky RPMs ship only unversioned
names and every manifest asks CMake for a versioned one.

**`debian11` builds its own Python.** `ci_infrastructure` needs >= 3.11
(`pyproject.toml`) and bullseye's ceiling is 3.10, backports included. The base
compiles a pinned, checksummed 3.11 with `--enable-shared` (for
**`debian11` and `ubuntu22.04` build their own Python.** `ci_infrastructure`
needs >= 3.11 (`pyproject.toml`), but bullseye provides Python 3.9 and Jammy's
Python 3.11 package is only a release candidate. Both bases therefore compile a
pinned, checksummed Python 3.11 from python.org with `--enable-shared` (for
`find_package(Python3 COMPONENTS Development)`) and `make altinstall`, leaving
the system 3.9 alone. It is the only image here that fetches anything from
outside a distro archive.

`rocky8` and `debian11` also take their pytest from pip rather than the distro,
because in both cases the distro package targets an interpreter (3.6, 3.9) that
is not the one those images run anything with. `ubuntu24.04` and `rolling-arch` use
the distro package.
the system interpreter alone. These are the only images that fetch and build a
CPython source tarball directly; both pin its checksum for provenance and
repeatable builds.

`ubuntu22.04`, `rocky8`, `rocky9`, `rocky10`, and `debian11` take pytest from
pip. On Ubuntu 22.04, Rocky 8, Rocky 9, and Debian 11, the selected CI Python is
newer than the distro's default interpreter and its pytest package. Rocky 10
also installs pytest with the selected system Python's pip. `ubuntu24.04`,
`ubuntu26.04`, `debian12`, `debian13`, `fedora43`, `fedora44`, and
`rolling-arch` use their distro pytest package.

### `rolling-arch` — newest of everything, rebuilt nightly

Expand Down
84 changes: 84 additions & 0 deletions public-images/debian12/base/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# syntax=docker/dockerfile:1
# SPDX-FileCopyrightText: 2026 European Centre for Medium-Range Weather Forecasts (ECMWF)
#
# SPDX-License-Identifier: Apache-2.0
# Published as eccr.ecmwf.int/public-ci-images/debian12-base
# Shared foundation: every other public-images/debian12/* image FROMs this.
# Built/pushed by .github/workflows/images.yml (see IMAGES.md).
FROM debian:12

ENV DEBIAN_FRONTEND=noninteractive
ENV PIP_BREAK_SYSTEM_PACKAGES=1

# Debian 12 provides Python 3.11, which meets ci-infrastructure's minimum.
# Its CMake 3.25 does not meet the 3.26 floor required by the submodules, so a
# pinned CMake is installed with pip below and takes precedence from /usr/local.
RUN apt-get update && apt-get install -y \
sudo \
git \
bison \
flex \
curl \
wget \
ca-certificates \
gnupg \
cmake \
ninja-build \
jq \
unzip \
zstd \
lsb-release \
software-properties-common \
build-essential \
python3 \
python3-dev \
python3-pip \
python3-venv \
python3-pytest \
python-is-python3 \
libssl-dev \
&& rm -rf /var/lib/apt/lists/*

RUN python3 -m pip install --no-cache-dir cmake==3.31.6

# Install GitHub CLI (gh) from its upstream apt repository.
RUN mkdir -p /etc/apt/keyrings \
&& curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
| tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \
&& chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) \
signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] \
https://cli.github.com/packages stable main" \
> /etc/apt/sources.list.d/github-cli.list \
&& apt-get update \
&& apt-get install -y gh \
&& rm -rf /var/lib/apt/lists/*

# Install ci-infrastructure from the repository build context. Keep this
# non-editable so the installed package remains after the source tree is removed.
COPY pyproject.toml LICENSE /opt/ci-infrastructure/
COPY src /opt/ci-infrastructure/src
RUN python3 -m pip install --no-cache-dir "/opt/ci-infrastructure[all]" \
&& rm -rf /opt/ci-infrastructure

ENV CI_INFRASTRUCTURE_PYTHON=/usr/bin/python3

ARG SOURCE_REVISION=""
ENV CI_INFRASTRUCTURE_BAKED_REF=${SOURCE_REVISION}

ENTRYPOINT []
CMD []
WORKDIR /workspace

COPY public-images/announce-image.sh /opt/ci/announce-image.sh
ENV BASH_ENV=/opt/ci/announce-image.sh

# Self-description must be re-declared by every descendant image.
ARG IMAGE_NAME=""
ARG IMAGE_TAG=""
ARG IMAGE_CREATED=""
ARG IMAGE_DOCKERFILE_URL=""
ENV CI_IMAGE_NAME=${IMAGE_NAME} \
CI_IMAGE_TAG=${IMAGE_TAG} \
CI_IMAGE_CREATED=${IMAGE_CREATED} \
CI_IMAGE_DOCKERFILE_URL=${IMAGE_DOCKERFILE_URL}
36 changes: 36 additions & 0 deletions public-images/debian12/gfortran12-boost-qt6/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# syntax=docker/dockerfile:1
# SPDX-FileCopyrightText: 2026 European Centre for Medium-Range Weather Forecasts (ECMWF)
#
# SPDX-License-Identifier: Apache-2.0
# Published as eccr.ecmwf.int/public-ci-images/debian12-gfortran12-boost-qt6
# Built/pushed by .github/workflows/images.yml (see IMAGES.md).
#
# This variant installs its complete toolchain directly on the shared base. The
# image workflow supports only base -> variant dependency chains.
FROM eccr.ecmwf.int/public-ci-images/debian12-base:latest

ENV DEBIAN_FRONTEND=noninteractive
ENV PIP_BREAK_SYSTEM_PACKAGES=1

# Debian 12 provides the required Qt 6 components, including Charts for
# ECFLOW_LOGVIEW and Core5Compat for APIs retained from Qt 5.
RUN apt-get update && apt-get install -y \
gcc-12 \
g++-12 \
gfortran-12 \
libboost-all-dev \
qt6-base-dev \
qt6-svg-dev \
qt6-5compat-dev \
qt6-charts-dev \
&& rm -rf /var/lib/apt/lists/*

# Self-description must be re-declared by every descendant image.
ARG IMAGE_NAME=""
ARG IMAGE_TAG=""
ARG IMAGE_CREATED=""
ARG IMAGE_DOCKERFILE_URL=""
ENV CI_IMAGE_NAME=${IMAGE_NAME} \
CI_IMAGE_TAG=${IMAGE_TAG} \
CI_IMAGE_CREATED=${IMAGE_CREATED} \
CI_IMAGE_DOCKERFILE_URL=${IMAGE_DOCKERFILE_URL}
28 changes: 28 additions & 0 deletions public-images/debian12/gfortran12/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# syntax=docker/dockerfile:1
# SPDX-FileCopyrightText: 2026 European Centre for Medium-Range Weather Forecasts (ECMWF)
#
# SPDX-License-Identifier: Apache-2.0
# Published as eccr.ecmwf.int/public-ci-images/debian12-gfortran12
# Built/pushed by .github/workflows/images.yml (see IMAGES.md).
FROM eccr.ecmwf.int/public-ci-images/debian12-base:latest

ENV DEBIAN_FRONTEND=noninteractive
ENV PIP_BREAK_SYSTEM_PACKAGES=1

# Bookworm's native compiler generation, exposed under the versioned names used
# by downstream manifests.
RUN apt-get update && apt-get install -y \
gcc-12 \
g++-12 \
gfortran-12 \
&& rm -rf /var/lib/apt/lists/*

# Self-description must be re-declared by every descendant image.
ARG IMAGE_NAME=""
ARG IMAGE_TAG=""
ARG IMAGE_CREATED=""
ARG IMAGE_DOCKERFILE_URL=""
ENV CI_IMAGE_NAME=${IMAGE_NAME} \
CI_IMAGE_TAG=${IMAGE_TAG} \
CI_IMAGE_CREATED=${IMAGE_CREATED} \
CI_IMAGE_DOCKERFILE_URL=${IMAGE_DOCKERFILE_URL}
80 changes: 80 additions & 0 deletions public-images/debian13/base/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# syntax=docker/dockerfile:1
# SPDX-FileCopyrightText: 2026 European Centre for Medium-Range Weather Forecasts (ECMWF)
#
# SPDX-License-Identifier: Apache-2.0
# Published as eccr.ecmwf.int/public-ci-images/debian13-base
# Shared foundation: every other public-images/debian13/* image FROMs this.
# Built/pushed by .github/workflows/images.yml (see IMAGES.md).
FROM debian:13

ENV DEBIAN_FRONTEND=noninteractive
ENV PIP_BREAK_SYSTEM_PACKAGES=1

# Debian 13 provides Python 3.13 and CMake 3.31, so the complete base toolchain
# can come from the distribution repositories.
RUN apt-get update && apt-get install -y \
sudo \
git \
bison \
flex \
curl \
wget \
ca-certificates \
gnupg \
cmake \
ninja-build \
jq \
unzip \
zstd \
lsb-release \
build-essential \
python3 \
python3-dev \
python3-pip \
python3-venv \
python3-pytest \
python-is-python3 \
libssl-dev \
&& rm -rf /var/lib/apt/lists/*

# Install GitHub CLI (gh) from its upstream apt repository.
RUN mkdir -p /etc/apt/keyrings \
&& curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
| tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \
&& chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) \
signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] \
https://cli.github.com/packages stable main" \
> /etc/apt/sources.list.d/github-cli.list \
&& apt-get update \
&& apt-get install -y gh \
&& rm -rf /var/lib/apt/lists/*

# Install ci-infrastructure from the repository build context. Keep this
# non-editable so the installed package remains after the source tree is removed.
COPY pyproject.toml LICENSE /opt/ci-infrastructure/
COPY src /opt/ci-infrastructure/src
RUN python3 -m pip install --no-cache-dir "/opt/ci-infrastructure[all]" \
&& rm -rf /opt/ci-infrastructure

ENV CI_INFRASTRUCTURE_PYTHON=/usr/bin/python3

ARG SOURCE_REVISION=""
ENV CI_INFRASTRUCTURE_BAKED_REF=${SOURCE_REVISION}

ENTRYPOINT []
CMD []
WORKDIR /workspace

COPY public-images/announce-image.sh /opt/ci/announce-image.sh
ENV BASH_ENV=/opt/ci/announce-image.sh

# Self-description must be re-declared by every descendant image.
ARG IMAGE_NAME=""
ARG IMAGE_TAG=""
ARG IMAGE_CREATED=""
ARG IMAGE_DOCKERFILE_URL=""
ENV CI_IMAGE_NAME=${IMAGE_NAME} \
CI_IMAGE_TAG=${IMAGE_TAG} \
CI_IMAGE_CREATED=${IMAGE_CREATED} \
CI_IMAGE_DOCKERFILE_URL=${IMAGE_DOCKERFILE_URL}
Loading
Loading