Line data Source code
1 0 : \cond NEVER 2 : Distributed under the MIT License. 3 : See LICENSE.txt for details. 4 : \endcond 5 : 6 : # GitHub Actions Continuous Integration {#github_actions_guide} 7 : 8 : \tableofcontents 9 : 10 : # Testing SpECTRE with GitHub Actions CI {#github_actions_ci} 11 : 12 : SpECTRE uses 13 : [GitHub Actions](https://github.com/features/actions) for 14 : testing the code. Multiple build jobs (described below) are launched 15 : each time a pull request is submitted or updated. GitHub Actions will also 16 : launch these build jobs each time you push to a branch on your fork of SpECTRE 17 : if you enable it. GitHub Actions is also used to deploy releases of the code. 18 : 19 : For pull requests, you can view the GitHub Actions CI build by clicking on the 20 : `Checks` tab. Near the bottom of the `Conversation` tab a summary of the CI 21 : results are presented. You can view all of the GitHub Actions runs by clicking 22 : on the `Actions` section. 23 : 24 : ## What is tested {#what-is-tested} 25 : 26 : The GitHub Actions report lists the build jobs which will each have either a 27 : green check mark if it passes, a red `X` if it has failed, or a yellow 28 : dot with a circle if the build is in progress. Clicking on a build job will 29 : display the log of the build. 30 : 31 : The following build jobs are launched: 32 : * CHECK_COMMITS runs the script `tools/CheckCommits.sh` and fails the build if 33 : any casing of the words in the list below is the first word of the commit 34 : message. This allows developers to flag their commits with these keywords to 35 : indicate that a pull request should not be merged in its current state. 36 : - fixup 37 : - wip (for work in progress) 38 : - fixme 39 : - deleteme 40 : - rebaseme 41 : - testing 42 : - rebase 43 : * CHECK_FILES runs the script `tools/CheckFiles.sh` (which also runs the script 44 : `tools/FileTestDefs.sh`). The checks fail if any of the following are true: 45 : - Any file, 46 : * contains a line over 80 characters (We allow exceptions for certain file 47 : types and inherently long strings like URLs and include lines. 48 : See `tools/FileTestDefs.sh` for the full list of exceptions.) 49 : * is missing the license line 50 : * does not end with a newline 51 : * contains a tab character 52 : * contains white space at the end of a line 53 : * contains a carriage return character 54 : - A `c++` header file (i.e., `*.hpp` or `*.tpp`) is missing `#%pragma once` 55 : - A `c++` file (i.e., `*.hpp`, `*.tpp`, or `*.cpp`) file, 56 : * includes `<iostream>` (useless when running in parallel) 57 : * includes `<lrtslock.h>` (use `<converse.h>` instead) 58 : * includes `"Utilities/TmplDebugging.hpp"` (used only for debugging) 59 : * includes any non-header `*.cpp` file 60 : * contains a `namespace` ending in `_details` (use `_detail`) 61 : * contains a `struct TD` or `class TD` (used only for debugging) 62 : * contains `std::enable_if` (use `requires` instead) 63 : * contains `Ls` (use `List` instead) 64 : * contains additional text after `/*!` (does not render correctly in 65 : Doxygen) 66 : * contains the string `return Py_None;` (bug prone, use `Py_RETURN_NONE` 67 : instead) 68 : * contains `.ckLocal()` or `.ckLocalBranch()` (use `Parallel::local` or 69 : `Parallel::local_branch` instead) 70 : - A `c++` test, 71 : * uses `TEST_CASE` (use `SPECTRE_TEST_CASE` instead) 72 : * uses `Approx` (use `approx` instead) 73 : - A `CMakeLists.txt` file in `src`, but not in an Executables or 74 : Python-binding directory, 75 : * does not list a `C++` file that is present in the directory 76 : * lists a `C++` file that is not present in the directory 77 : - A `c++` or `python` file contains a `TODO` (case-insensitive) comment 78 : In addition, the CHECK_FILES job tests Python formatting, the release 79 : workflow, and other tools in `tools/`. 80 : * "Check Python formatting" runs the `black` and `isort` formatters over the 81 : source code. 82 : * RUN_CLANG_TIDY runs clang-tidy on the source code. This is done for both 83 : `Release` and `Debug` builds. 84 : * TEST_CHECK_FILES runs `tools/CheckFiles.sh --test` which tests the checks 85 : performed in the CHECK_FILES build. 86 : * The other builds compile the code and run the tests for both 87 : `Release` and `Debug` builds, for the `gcc` and `clang` compilers 88 : using a Linux OS, and the `AppleClang` compiler for `OS X`. 89 : * Verify the documentation builds successfully. Builds of `develop` deploy the 90 : documentation to GitHub pages. 91 : 92 : ## How to perform the checks locally {#perform-checks-locally} 93 : 94 : Before pushing to GitHub and waiting for GitHub Actions to perform the checks it 95 : is useful to perform at least the following tests locally: 96 : - **Unit tests:** Perform a `make unit-tests` and then execute `ctest -L Unit` 97 : to run all unit tests. As for `make` you can append a `-jN` flag to `ctest` to 98 : run in parallel on `N` cores. To run only a subset of the tests you can use 99 : one of the other keywords that the tests are labeled with, such as `ctest -L 100 : datastructures`. To run only particular tests you can also execute `ctest -R 101 : TEST_NAME` instead, where `TEST_NAME` is a regular expression matching the 102 : test identifiers such as `Unit.DataStructures.Mesh`. Pass the flag 103 : `--output-on-failure` to get output from failed tests. Consult `ctest -h` for 104 : further options. 105 : 106 : To run the input file tests you must build the executables using 107 : `make test-executables`. You can then run `ctest -LE unit` to run everything 108 : except for the unit tests, or `ctest` to run all tests. 109 : - **clang-tidy:** In a clang build directory, run `make clang-tidy 110 : FILE=SOURCE_FILE` where `SOURCE_FILE` is a relative or absolute path to a 111 : `.cpp` file. To perform this check for all source files that changed in your 112 : pull request, `make clang-tidy-hash HASH=UPSTREAM_HEAD` where `UPSTREAM_HEAD` 113 : is the hash of the commit that your pull request is based on, usually the 114 : `HEAD` of the `upstream/develop` branch. 115 : - **Python formatting:** Run `black --check .` and `isort --check-only .` over 116 : the repository. You can install these tools with `pip3 install -r 117 : support/Python/dev_requirements.txt` 118 : - **Documentation:** To render the documentation for the current state 119 : of the source tree the command `make doc` (or `make doc-check` to 120 : highlight warnings) can be used, placing its result in the `docs` 121 : directory in the build tree. Once code has been made into a pull 122 : request to GitHub, the documentation can be rendered locally using 123 : the `tools/pr-docs` script. To view the documentation, simply open the 124 : `index.html` file in the `html` subdirectory in a browser. Some functionality 125 : requires a web server (e.g. citation popovers), so just run a 126 : `python3 -m http.server` in the `html` directory to enable this. 127 : - The `gcc Debug` build runs code coverage for each GitHub Actions build. 128 : 129 : ## Troubleshooting {#github-actions-troubleshooting} 130 : 131 : * Occasionally, a build job will fail because of a problem with GitHub Actions 132 : (e.g. it times out). On the `Checks` tab you can restart all or only the 133 : failed jobs. In the top right corner there's a `Re-run jobs` menu, which also 134 : has `Re-run failed jobs`. This button is `Cancel workflow` during the build 135 : process. Note that these buttons are only available if you have write access 136 : to the repository (core developer status). 137 : * GitHub Actions caches some things between builds. Occasionally this may 138 : cause a problem leading to strange build failures. For example, inexplicable 139 : segfaults on seemingly random tests or `Illegal instruction` failures. We have 140 : to be fairly lax with our caching policies, and so the cache can become stale 141 : and outdated when a new container is pushed, among other difficult to 142 : understand situations. You can rebuild the ccache by going to `Actions`, then 143 : select the `Tests` workflow on the left, click the `Run workflow` drop-down 144 : menu, and enter `yes` in the input field below the ccache discussion. 145 : 146 : If clearing the ccache doesn't help, it could be that a Docker image layer is 147 : not being updated. GitHub doesn't (yet) have a way to clear the cache, so 148 : instead we clobber it to force GitHub to eject all old caches, both ccache and 149 : Docker images, along with anything else. To do this go to `Actions`, select 150 : the `Clobber Cache` workflow, then run it on develop. This will dump 9.9GB of 151 : random data into the cache. The amount is specified in the `ClobberCache.yaml` 152 : workflow file and needs to be updated if GitHub increases their cache 153 : size. The current cache size limit is 10GB per repository. 154 : 155 : Note that starting these workflows is only possible if you have write access 156 : to the repository (core developer status). 157 : 158 : ## Precompiled Headers and ccache {#precompiled-headers-ccache} 159 : 160 : Getting ccache to work with precompiled headers on GitHub Actions is a little 161 : challenging. The header to be precompiled is 162 : `${SPECTRE_SOURCE_DIR}/tools/SpectrePch.hpp` and is symbolically linked to 163 : `${SPECTRE_BUILD_DIR}/SpectrePch.hpp`. The configuration that seems to work is 164 : specifying the environment variables: 165 : 166 : \code{.sh} 167 : CCACHE_COMPILERCHECK=content 168 : CCACHE_EXTRAFILES="${SPECTRE_SOURCE_DIR}/tools/SpectrePch.hpp" 169 : CCACHE_IGNOREHEADERS=\ 170 : "${SPECTRE_BUILD_DIR}/SpectrePch.hpp:${SPECTRE_BUILD_DIR}/SpectrePch.hpp.gch" 171 : \endcode 172 : 173 : ## Caching Dependencies on macOS Builds {#caching-mac-os} 174 : 175 : On macOS builds we cache all of our dependencies, like LIBXSMM and 176 : Charm++. These are cached in `$HOME/mac_cache`. Ultimately this saves about 177 : 10-12 minutes even when compared to using ccache to cache the object files from 178 : building the dependencies. We also cache `$HOME/Library/Caches/Homebrew`, which 179 : is where Homebrew keeps the downloaded formulas. By caching the Homebrew bottles 180 : we are able to avoid brew formulas building from source because a tarball of the 181 : package was not available at the time.