CircleCI configuration¶
This page describes how to setup CircleCI version 2.0 for a project built on top of DOLFIN. Tests are run using FEniCS docker images, in particular using an image with the development version of FEniCS. Note that modern FEniCS Docker images have both Python version 2 and 3. Hence it is easy to change a Python version of the below commands or even run both versions.
For details, see also the FEniCS Docker reference manual.
Use CircleCI 2.0. It has native support for Docker images.:
version: 2
Specify build jobs:
jobs:
build:
image
specifies a Docker image with the development
version of FEniCS. Inside of a container we will be using
a user fenics
which has an installation of FEniCS.
But we will work in a different directory derived from
the name of the project. The environment
needs to
be adjusted to allow importing C++ DOLFIN libraries and
finding necessary files for just-in-time compilation.
This is done because CircleCI bypasses environment setup
specified in the FEniCS image.:
docker:
- image: quay.io/fenicsproject/stable:2017.2.0.r3
user: fenics
environment:
LD_LIBRARY_PATH: /home/fenics/local/lib
CMAKE_PREFIX_PATH: /home/fenics/local
working_directory: /home/fenics/fenapack
First step is checking out the source code into the working directory:
steps:
- checkout
Then print some diagnostic information to a build log:
- run:
name: Environment and FEniCS version info
command: |
echo $USER $HOME $PWD $PATH $LD_LIBRARY_PATH $CMAKE_PREFIX_PATH
python3 -c'import ffc; print(ffc.git_commit_hash(), ffc.ufc_signature())'
python3 -c'import dolfin; print(dolfin.git_commit_hash())'
Install the project from the working directory. (Note that
the download-meshes
script should be invoked during
installation but that does not work because of some
directories mismatch.):
- run:
name: Install FENaPack
command: |
./download-meshes
pip3 install -v --user .
Try to import the project. That involves some just-in-time compilation which we test and measure as a separate build step.:
- run:
name: Import FENaPack first time (JIT)
command: python3 -c"import fenapack"
Run the unit tests using the pytest framework. By -svl
options we make a test
output more verbose and using --junitxml
we save a
test result in machine-readable format. In a later step
we tell to CircleCI where the result is. CircleCI is able
to provide various information based on the results on
its web UI.:
- run:
name: Unit tests
command: py.test-3 test/unit -svl --junitxml /tmp/circle/unit.xml
Now we run parallel unit tests. This would normally be
done by just prefixing a py.test
command by an
mpirun
command. Here we wrap it in the bash
instance to figure out an MPI rank number using the
${OMPI_COMM_WORLD_RANK:-$PMI_RANK}
variable, which
should work both with MPICH and OpenMPI, and use it
to generate separate test result files. Other issue is
that the Python 3 hash randomization together with
unordered dicts make order of object destruction during
garbage collection non-deterministic and different across
MPI processes. When a destructor of any object is
collective this may cause a deadlock. By forcing the same
PYTHONHASHSEED
for all processes we prevent this
problem. The chance is that this will not be necessary
with Python 3.6 where dicts are ordered.:
- run:
name: Unit tests MPI
command: >
PYTHONHASHSEED=0 mpirun -n 3 bash -c '
py.test-3 test/unit -svl
--junitxml /tmp/circle/unit-mpi-${OMPI_COMM_WORLD_RANK:-$PMI_RANK}.xml
'
Now we run the benchmarking suite and store generated PDF
files for later use. Note that we tell to a shell (note
that every build step is run in a separate shell) not to
exit on first failure by set +e
. Instead we only want
to eventually fail only on the py.test
command by
returning its exit code by exit $rc
.:
- run:
name: Bench
command: |
set +e
py.test-3 test/bench -svl --junitxml /tmp/circle/bench.xml
rc=$?
mv *.pdf /tmp/circle
exit $rc
Now we run the regression tests implemented by a homebrew
Python script test.py
. The script invokes also
parallel tests so again we enforce the same hash seed
across MPI processes. We copy resulting figures to directory
where CircleCI collects artifacts.:
- run:
name: Regression tests
command: |
set +e
cd test/regression
PYTHONHASHSEED=0 NP=3 python3 -u test.py
rc=$?
cd ../../demo; find -name "*.pdf" -exec cp --parents {} /tmp/circle \;
exit $rc
Finally we tell to CircleCI to store build artifacts and test results, which both can be accessed on CircleCI website.:
- store_artifacts:
path: /tmp/circle
destination: build
- store_test_results:
path: /tmp/circle
Download the complete configuration file
circle.yml
.