-
-
Notifications
You must be signed in to change notification settings - Fork 259
282 lines (258 loc) · 14.2 KB
/
Copy pathci.yml
File metadata and controls
282 lines (258 loc) · 14.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
name: CI (Spack-based)
on:
# Uncomment the below 'push' to trigger on push
push:
branches:
- release
pull_request:
branches:
- main
workflow_dispatch:
# Cancel superseded runs: a new commit on a pull request makes the
# previous run's result irrelevant. Pushes to 'main' and 'release' are
# left to finish, since they populate caches and publish artefacts.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
GITHUB_USER: ${{ github.actor }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OMPI_ALLOW_RUN_AS_ROOT: 1
OMPI_ALLOW_RUN_AS_ROOT_CONFIRM: 1
PRTE_MCA_rmaps_default_mapping_policy: :oversubscribe
jobs:
ci-build:
name: ci-build (${{ matrix.mpi }}${{ matrix.petsc && format(', petsc {0}/{1}', matrix.scalar, matrix.index) || ', no petsc' }})
runs-on: ubuntu-26.04
container: ubuntu:26.04
permissions:
contents: read
packages: write
strategy:
fail-fast: false
# PETSc scalar/index combinations are covered on OpenMPI; MPICH
# repeats the two most common ones, as it exercises the MPI layer
# rather than the scalar type. The PETSc-free build tests the
# optional-PETSc code paths and needs only one MPI.
matrix:
include:
- {mpi: openmpi, petsc: true, scalar: float32, index: int32,
petsc_dep: "^petsc+mpi+metis+mumps+ptscotch+scalapack+superlu-dist~hypre~suite-sparse~double~complex~int64"}
- {mpi: openmpi, petsc: true, scalar: float64, index: int32,
petsc_dep: "^petsc+mpi+hypre+metis+mumps+ptscotch+scalapack+suite-sparse+superlu-dist+double~complex~int64"}
- {mpi: openmpi, petsc: true, scalar: complex64, index: int32,
petsc_dep: "^petsc+mpi+metis+mumps+ptscotch+scalapack~hypre~suite-sparse~superlu-dist~double+complex~int64"}
- {mpi: openmpi, petsc: true, scalar: complex128, index: int32,
petsc_dep: "^petsc+mpi+hypre+metis+mumps+ptscotch+scalapack+suite-sparse+superlu-dist+double+complex~int64"}
- {mpi: openmpi, petsc: true, scalar: float64, index: int64,
petsc_dep: "^petsc+mpi+hypre+mumps+ptscotch+scalapack+suite-sparse+superlu-dist~metis+double~complex+int64"}
- {mpi: openmpi, petsc: true, scalar: complex128, index: int64,
petsc_dep: "^petsc+mpi+hypre+mumps+ptscotch+scalapack+suite-sparse+superlu-dist~metis+double+complex+int64"}
- {mpi: mpich, petsc: true, scalar: float64, index: int32,
petsc_dep: "^petsc+mpi+hypre+metis+mumps+ptscotch+scalapack+suite-sparse+superlu-dist+double~complex~int64"}
- {mpi: mpich, petsc: true, scalar: complex128, index: int32,
petsc_dep: "^petsc+mpi+hypre+metis+mumps+ptscotch+scalapack+suite-sparse+superlu-dist+double+complex~int64"}
- {mpi: openmpi, petsc: false}
steps:
- name: Branch and commit SHA
run: |
echo "Branch and commit SHA: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }}, ${{ github.sha }}"
- name: Install Spack requirements
run: |
apt-get -y update
apt-get install -y --no-install-recommends file bzip2 ca-certificates g++ gcc gfortran git gzip \
libgl-dev libosmesa6-dev lsb-release patch python3 tar unzip xz-utils zstd
- name: Set up Spack
uses: spack/setup-spack@16b756799ede8b28951287f89bcd3fdb32ec1ca3 # v3.0.0
with:
spack_ref: v1.2.2
# spack-packages 'develop' at 2026-08-17. Bumping re-solves the
# graph and can invalidate cached binaries; warm the cache first.
packages_ref: 1ccf95574922e2a7f7ef0351bd67758ad4634b7a
# Pinned, like spack itself and its packages repo above: an unpinned
# 'main' changes what CI builds with no commit here, which makes a
# failure impossible to attribute. Bump deliberately.
- name: Get FEniCS Spack packages
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: fenics/spack-fenics
ref: 55b14e0301eb64d4adc86c213046824f2b17e20c # main, 2026-08-15
path: spack-fenics
# Add FEniCS Spack packages on top of the upstream Spack packages
- name: Add FEniCS Spack packages repo
run: |
spack repo add --name fenics $GITHUB_WORKSPACE/spack-fenics/spack_repo/fenics
- name: Get DOLFINx code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: dolfinx-src
- name: Load dev branch environment variables
run: cat dolfinx-src/.github/workflows/fenicsx-refs.env >> $GITHUB_ENV
- name: Get UFL code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ${{ env.ufl_repository }}
ref: ${{ env.ufl_ref }}
path: ufl-src
- name: Get FFCx code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ${{ env.ffcx_repository }}
ref: ${{ env.ffcx_ref }}
path: ffcx-src
- name: Get Basix code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ${{ env.basix_repository }}
ref: ${{ env.basix_ref }}
path: basix-src
- name: Record source commit SHAs
run: |
echo "BASIX_SHA=$(git -C $GITHUB_WORKSPACE/basix-src rev-parse HEAD)" >> $GITHUB_ENV
echo "UFL_SHA=$(git -C $GITHUB_WORKSPACE/ufl-src rev-parse HEAD)" >> $GITHUB_ENV
echo "FFCX_SHA=$(git -C $GITHUB_WORKSPACE/ffcx-src rev-parse HEAD)" >> $GITHUB_ENV
- name: Prepare Spack environment
run: |
spack env create ci dolfinx-src/.github/workflows/spack-config/gh-actions-env-test.yml
spack -e ci config add "packages:mpi:require:${{ matrix.mpi }}"
for pkg in fenics-basix:basix py-fenics-basix:basix py-fenics-ufl:ufl \
py-fenics-ffcx:ffcx fenics-ufcx:ffcx fenics-dolfinx:dolfinx py-fenics-dolfinx:dolfinx; do
spack -e ci develop --no-clone --path $GITHUB_WORKSPACE/${pkg#*:}-src ${pkg%%:*}@main
done
# A single environment builds DOLFINx once for both the C++ and the
# Python test steps. Separate environments resolve to an identical
# runtime spec and differ only in build-time dependencies, so the
# second build produces the same library at a different hash.
- name: Build DOLFINx and test dependencies
run: |
# Ensure build provenance by adding manually and providing git sha
spack -e ci add fenics-basix@main commit=$BASIX_SHA build_type=Developer
spack -e ci add py-fenics-basix@main commit=$BASIX_SHA build_type=Developer
spack -e ci add py-fenics-ufl@main commit=$UFL_SHA
spack -e ci add fenics-ufcx@main commit=$FFCX_SHA
spack -e ci add py-fenics-ffcx@main commit=$FFCX_SHA
# NOTE: adios2~sz drops the SZ2 compression dependency. 'sz'
# installs its own unversioned libzstd.so, which interposes on the
# real zstd once libdolfinx is loaded; a ZSTD_DCtx then gets
# allocated in one zstd and freed in the other. This segfaults
# Mesa's llvmpipe shader disk cache, so any PyVista render
# following 'import dolfinx' crashes (see 'Run Python demos').
spack -e ci add fenics-dolfinx@main+adios2${{ matrix.petsc && '+petsc+slepc' || '~petsc~slepc+superlu-dist' }} commit=${{ github.sha }} build_type=Developer partitioners=parmetis \
${{ matrix.petsc_dep }} ^adios2~libcatalyst~fortran~sz
spack -e ci add py-fenics-dolfinx@main${{ matrix.petsc && '+petsc4py+slepc4py' || '~petsc4py~slepc4py' }} commit=${{ github.sha }} build_type=Developer
spack -e ci add py-gmsh ^gmsh~med~fltk+external ^opencascade~draw py-pyamg py-matplotlib \
py-networkx \
py-numba ^llvm~clang~lldb~lld~offload~libomptarget~polly targets=x86 \
py-pytest py-pytest-xdist py-scipy \
"py-pyvista ^[virtuals=gl] osmesa"
spack -e ci add catch2 ninja
spack -e ci concretize -j $(nproc)
spack -e ci install -j $(nproc) --use-buildcache auto
# Pushed before the test steps so the artifacts are cached even if a
# later step fails. The index is rebuilt by the final push.
#
# Both pushes are skipped for pull requests from forks: those run
# with a read-only GITHUB_TOKEN whatever 'permissions' asks for, so
# the push would 401 as soon as it had anything to upload, failing a
# contributor's job on a step that tests nothing. Reads are
# anonymous, so their builds still take from the cache.
- name: Push packages to cache
if: >-
${{ !cancelled() && (github.event_name != 'pull_request'
|| github.event.pull_request.head.repo.full_name == github.repository) }}
run: |
spack -e ci buildcache push --base-image ubuntu:26.04 --only dependencies \
--with-build-dependencies --allow-missing local-buildcache
- name: Build and run C++ unit tests (serial and MPI)
shell: spack-bash {0}
run: |
spack env activate ci
spack load catch2 cmake ninja py-fenics-ffcx
cmake -Werror=dev --warn-uninitialized -G Ninja -DCMAKE_BUILD_TYPE=Developer -B build/test/ -S dolfinx-src/cpp/test/
cmake --build build/test
cd build/test
ctest --output-on-failure -R unittests_np_1
ctest --output-on-failure -R unittests_np_3
# Skipped without PETSc: several demo CMakeLists reference
# PETSC_INCLUDE_DIRS unconditionally, which --warn-uninitialized
# turns into an error, and the top-level demo CMakeLists adds every
# subdirectory, so configuration fails as a whole.
- name: Build and run C++ demos (serial and MPI)
if: ${{ matrix.petsc }}
shell: spack-bash {0}
run: |
spack env activate ci
spack load cmake ninja py-fenics-ffcx
cmake -Werror=dev --warn-uninitialized -G Ninja -DCMAKE_BUILD_TYPE=Developer -B build/demo/ -S dolfinx-src/cpp/demo/
cmake --build build/demo
cd build/demo
ctest --output-on-failure -R "demo_.*_np_1"
ctest --output-on-failure -R "demo_.*_np_2"
# Guard against a mis-specified variant silently building PETSc into
# the PETSc-free leg, which would make it test nothing new.
- name: Check PETSc configuration matches the matrix
shell: spack-bash {0}
run: |
spack env activate ci
python -c "import dolfinx; assert dolfinx.has_petsc is ${{ matrix.petsc && 'True' || 'False' }}, dolfinx.has_petsc"
# ccpp.yml runs mypy only in a build without PETSc, which excludes
# the modules needing petsc4py. This leg has petsc4py, gmsh and
# pyvista, so it checks them, on the project config alone. One leg
# only: the result does not vary with the scalar type.
- name: mypy checks (with petsc4py)
if: ${{ matrix.petsc && matrix.mpi == 'openmpi' && matrix.scalar == 'float64' && matrix.index == 'int32' }}
shell: spack-bash {0}
run: |
spack env activate ci
# mypy checks the sources, so keep it out of the environment and
# the build cache. The environment's python has no pip, hence the
# venv; '--python-executable' points mypy back at it to resolve
# dolfinx, petsc4py and the rest.
apt-get install -y --no-install-recommends python3-venv
python3 -m venv /tmp/mypy-venv
# types-cffi, types-setuptools and scipy-stubs mirror the `typing`
# extra in python/pyproject.toml; installed by name rather than via
# '.[typing]' to avoid triggering a full DOLFINx build in this venv.
/tmp/mypy-venv/bin/pip install --quiet mypy types-cffi types-setuptools scipy-stubs
# Distinguishes a broken install from mypy reporting errors.
/tmp/mypy-venv/bin/mypy --version
ENV_PYTHON=$(command -v python)
MYPY="/tmp/mypy-venv/bin/mypy --python-executable $ENV_PYTHON"
# No --disable-error-code: unlike the other mypy invocations in
# CI, this one can import everything it checks.
cd dolfinx-src/python
$MYPY --config-file pyproject.toml -p dolfinx
$MYPY demo
$MYPY test
- name: Set default DOLFINx JIT options
run: |
mkdir -p ~/.config/dolfinx
echo '{ "cffi_extra_compile_args": ["-g0", "-O0" ] }' > ~/.config/dolfinx/dolfinx_jit_options.json
- name: Run Python demos (serial and MPI)
shell: spack-bash {0}
run: |
spack env activate ci
spack load gcc
python -m pytest -n=auto -m serial --durations=10 dolfinx-src/python/demo/test.py
python -m pytest -m mpi --num-proc=3 dolfinx-src/python/demo/test.py
# NOTE: the marker expression is written '!matrix.petsc && X || Y'
# rather than 'matrix.petsc && Y || X'. GitHub expressions treat the
# empty string as false, so the latter form falls through to X on
# every leg and silently skips the petsc4py tests everywhere.
- name: Run Python unit tests (serial and MPI)
shell: spack-bash {0}
run: |
spack env activate ci
spack load gcc
python -m pytest -n=auto --durations=50 ${{ !matrix.petsc && '-m "not petsc4py"' || '' }} dolfinx-src/python/test/unit/
mpiexec -np 3 python -m pytest --durations=50 ${{ !matrix.petsc && '-m "not petsc4py"' || '' }} dolfinx-src/python/test/unit/
# The test tools are environment roots, so '--only dependencies'
# skips them and they need naming explicitly. Only the final push
# rebuilds the index, which is the expensive part.
- name: Push test packages to cache and update index
if: >-
${{ !cancelled() && (github.event_name != 'pull_request'
|| github.event.pull_request.head.repo.full_name == github.repository) }}
run: |
spack -e ci buildcache push --base-image ubuntu:26.04 --allow-missing --update-index local-buildcache \
catch2 py-gmsh py-matplotlib py-networkx py-numba py-pyamg py-pytest py-pytest-xdist py-scipy py-pyvista