6. Continuous integration
A CI job runs the same commands as you do, and reads their results. With --json a command writes one JSON document on its standard output, and its messages on the standard error: a script reads facts, not log lines.
Checking the sources
fobis check resolves the dependencies of every file without compiling anything: a quick first step for a job.
$ fobis check --json
{
"status": "ok",
"files": 241,
"unresolved": [],
"cycles": [],
"warnings": []
}Building
$ fobis build --mode release --json
{
"status": "ok",
"target": "src/integrate.F90",
"objects_compiled": 0,
"errors": []
}When a build fails, the document carries the compiler's messages parsed (diagnostics) and what FoBiS concludes from the project's facts (diagnoses). A file that uses a module nobody defines:
$ fobis build --mode release --json
{
"status": "error",
"target": "src/integrate.F90",
"objects_compiled": 0,
"errors": [
"warning: the file 'src/residual.F90' depends on 'quad_errors' that is unreachable",
"src/residual.F90:4:5:\n\n 4 | use quad_errors, only : R8P\n | 1\nFatal Error: Cannot open module file 'quad_errors.mod' for reading at (1): No such file or directory\ncompilation terminated.\n"
],
"diagnostics": [
{
"tool": "gnu",
"severity": "fatal",
"message": "Cannot open module file 'quad_errors.mod' for reading at (1): No such file or directory",
"file": "src/residual.F90",
"line": 4,
"column": 5
}
],
"diagnoses": [
{
"kind": "missing-module",
"summary": "module quad_errors is not available when src/residual.F90 is compiled",
"diagnostic": {
"tool": "gnu",
"severity": "fatal",
"message": "Cannot open module file 'quad_errors.mod' for reading at (1): No such file or directory",
"file": "src/residual.F90",
"line": 4,
"column": 5
},
"facts": [
"no project source defines module quad_errors, and it is not a known library module."
],
"advice": [
"declare the project that provides it in fobos `[dependencies]` and run `fobis fetch`, or add the directory of its .mod files to `cflags` (`-I...`)"
],
"consequences": 0
}
]
}
[exit status 1]Testing
$ fobis test --json 2> /dev/null
{
"status": "ok",
"test_dir": "test",
"passed": 2,
"failed": 0,
"results": [
{
"name": "test_exactness",
"suite": "",
"exit_code": 0,
"duration": 0.001,
"stdout": "exact on polynomials of its degree",
"stderr": "",
"status": "passed"
},
{
"name": "test_order",
"suite": "",
"exit_code": 0,
"duration": 0.001,
"stdout": "observed orders: trapezoid 2.001, simpson 4.005",
"stderr": "",
"status": "passed"
}
]
}Every result carries its status, exit code and output; a failed one also the crash (here an error stop), located in the sources.
A workflow
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Tools
run: |
sudo apt-get install -y gfortran
pip install FoBiS.py gcovr
- name: Dependencies, at the tags the fobos pins
run: fobis fetch
- name: Build
run: fobis build --mode release
- name: Tests
run: fobis test --json > tests.json
- name: Coverage
run: |
fobis test --mode coverage
fobis coverage --mode coverage --format xml --fail-under 90fobis fetchclones the dependencies at the tags the fobos pins. The lock file stays in.fobis_deps/, which is not committed: a fresh checkout has none, so--frozenbelongs on machines that keep their fetched dependencies.- The coverage step fails the job below 90% of the lines.
tests.jsoncan be uploaded as an artifact, or read by a later step.
What you learned
fobis check, --json on build, check, test (also on clean, fetch, tree and the verification commands), and a CI workflow. Reference: JSON output.
Next: 7. Other build systems.