|
| 1 | +# Rust CI with GitHub Actions |
| 2 | + |
| 3 | +  [](https://codecov.io/gh/BamPeers/rust-ci-github-actions-workflow) |
| 4 | + |
| 5 | + |
| 6 | +## Table of Contents |
| 7 | +1. [Workflows](#workflows) |
| 8 | + - [Check and Lint (check-and-lint.yaml)](#check-and-lint) |
| 9 | + - [Test with Code Coverage (test.yaml)](#test-with-code-coverage) |
| 10 | + - [Release Packaging (release-packaging.yaml)](#release-packaging) |
| 11 | +2. [How to Use](#how-to-use) |
| 12 | +3. [License](#license) |
| 13 | + |
| 14 | + |
| 15 | +## Workflows |
| 16 | +The CI process is separated into 3 workflows: Check and Lint, Test, and Release Packaging. |
| 17 | + |
| 18 | +All jobs run on `ubuntu-latest`, and are run in parallel. |
| 19 | + |
| 20 | +All jobs use [actions/checkout@v2](https://github.com/actions/checkout) and [actions-rs/toolchain@v1](https://github.com/actions-rs/toolchain). |
| 21 | + |
| 22 | +<a name="check-and-lint"></a> |
| 23 | + |
| 24 | +### Check and Lint (check-and-lint.yaml) |
| 25 | +This workflow checks for compiler errors and code style inconsistencies. |
| 26 | +It runs on pull requests and main branch push. |
| 27 | + |
| 28 | + |
| 29 | +#### Check job |
| 30 | +This job runs `cargo check` on the stable toolchain. |
| 31 | + |
| 32 | +It checks if there are compiler errors. |
| 33 | + |
| 34 | + |
| 35 | +#### Rustfmt job |
| 36 | +This job runs [rustfmt](https://github.com/rust-lang/rustfmt) with the `--check` option through `cargo fmt` on the stable toolchain. |
| 37 | + |
| 38 | +By default, it checks inconsistencies with the [Rust style guide](https://github.com/rust-lang-nursery/fmt-rfcs/blob/master/guide/guide.md). |
| 39 | +You can add a `rustfmt.toml` or `.rustfmt.toml` to configure the style. |
| 40 | + |
| 41 | +#### Clippy job |
| 42 | +This job runs [clippy](https://github.com/rust-lang/rust-clippy) on the stable toolchain through [actions-rs/clippy-check@v1](https://github.com/actions-rs/clippy-check). |
| 43 | +You can add a `clippy.toml` or `.clippy.toml` to configure the style. |
| 44 | +- The action outputs result (**Clippy Output** added to a random workflow), and |
| 45 | +- For pull requests, it adds annotations on the diff. |
| 46 | + |
| 47 | +<a name="test-with-code-coverage"></a> |
| 48 | + |
| 49 | +### Test with Code Coverage (test.yaml) |
| 50 | +This workflow run tests, outputs test results, publishes code coverage results on [CodeCov](https://codecov.io/). |
| 51 | +Publishing test results and code coverage data is in one job to avoid running the tests twice. |
| 52 | +It runs on pull requests and main branch push. |
| 53 | + |
| 54 | + |
| 55 | +#### Test job |
| 56 | +This job: |
| 57 | +1. Caches dependencies, |
| 58 | +2. Runs tests and generate test results and code coverage data, |
| 59 | +3. Uploads test results, and |
| 60 | +4. Uploads to CodeCov. |
| 61 | + |
| 62 | +Environment variables used in this job: |
| 63 | +- `PROJECT_NAME_UNDERSCORE` - project name with hyphens(-) as underscores(_) needed for code coverage |
| 64 | +- `CARGO_INCREMENTAL`, `RUSTFLAGS`, `RUSTDOCFLAGS` - added to `CARGO_OPTIONS` in cargo test needed for code coverage |
| 65 | + |
| 66 | +Steps: |
| 67 | +1. Cache dependencies. |
| 68 | + It caches download and compilation of dependencies based on a hash of Cargo.lock to shorten build time |
| 69 | + with [actions/cache@v2](https://github.com/actions/cache). |
| 70 | + - The key is `${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('Cargo.lock') }}` |
| 71 | + where `env.cache-name`: `cache-dependencies`. |
| 72 | + - Cache is stored at the end of the job on cache miss. Cache is not updated on cache hit. |
| 73 | + |
| 74 | +2. Generate test results and code coverage data. |
| 75 | + 1. It installs [cargo2junit](https://github.com/johnterickson/cargo2junit) needed for formatting the test result and [grcov](https://github.com/mozilla/grcov) and [rust-covfix](https://github.com/Kogia-sima/rust-covfix) for code coverage. |
| 76 | + 3. It runs `cargo test` in the nightly toolchain. |
| 77 | + - `--features coverage` adds a `rust-covfix` feature that allows disabling inlining functions for code coverage. [Learn more.](https://github.com/Kogia-sima/rust-covfix#1-avoid-inlining-the-functions-optional) |
| 78 | + - `$CARGO_OPTIONS` includes `CARGO_INCREMENTAL`, `RUSTFLAGS`, and `RUSTDOCFLAGS` options needed for code coverage. |
| 79 | + - `-Z unstable-options --format json` formats the test result into json. |
| 80 | + - ` | cargo2junit > results.xml` converts the json result into junit format for `EnricoMi/publish-unit-test-result-action` to understand and saves it as `results.xml`. |
| 81 | + 4. It generates code coverage data in lcov format through `grcov` saved as `lcov.info`. |
| 82 | + 5. It runs `rust-covfix` to fix incorrect Rust coverage data and saves the corrected data as `lcov_correct.info`. |
| 83 | + |
| 84 | +3. Upload test results. |
| 85 | + It uploads the test result (`results.xml`) through [EnricoMi/publish-unit-test-result-action@v1](https://github.com/EnricoMi/publish-unit-test-result-action). |
| 86 | + - The action outputs the test result (**Test Results** added to a random workflow). |
| 87 | + - For pull requests, the action adds a comment containing the test results. |
| 88 | + |
| 89 | +4. Upload to CodeCov. |
| 90 | + It uploads the code coverage result (`lcov_correct.info`) to CodeCov through [codecov/codecov-action@v1](https://github.com/codecov/codecov-action). |
| 91 | + - For pull requests, the actions adds a comment containing the code coverage report. |
| 92 | + - For private repositories, add your token from CodeCov repository setting on GitHub Secrets and uncomment the line: `token: ${{ secrets.CODECOV_TOKEN }}`. |
| 93 | + |
| 94 | +<a name="release-packaging"></a> |
| 95 | + |
| 96 | +### Release Packaging (release-packaging.yaml) |
| 97 | +This workflow builds the package in release mode and uploads resulting file as a GitHub artifact. |
| 98 | +It runs on main branch push. |
| 99 | + |
| 100 | +#### Release Packaging job |
| 101 | +This job builds the project in release mode and uploads the binary as an artifact through [actions/upload-artifact@v2](https://github.com/actions/upload-artifact). |
| 102 | + |
| 103 | +The binary `target/release/${{ env.PROJECT_NAME_UNDERSCORE }}` is uploaded as `${{ env.PROJECT_NAME_UNDERSCORE }}`. |
| 104 | + |
| 105 | +## How to Use |
| 106 | +1. Replace the value of `PROJECT_NAME_UNDERSCORE` with your project name (replace hyphens(-) as underscores(_)). |
| 107 | + |
| 108 | +2. Customize when to call the workflows (like branch names) |
| 109 | + |
| 110 | +3. Customize options: |
| 111 | + - Configure rustfmt and clippy with TOML files. |
| 112 | + - Customize cargo test options (like excluding certain tests). |
| 113 | + - Configure paths to upload from release build (like uploading multiple binary artifacts). |
| 114 | + |
| 115 | +Notes: |
| 116 | +- `secrets.GITHUB_TOKEN` is needed by some actions to create GitHub checks & annotations. it is added automatically by GitHub. |
| 117 | +- uses cache for GitHub actions. |
| 118 | +- clippy html output and test result output are added to random workflows for a certain commit due to limitations in the GitHub Actions API. |
| 119 | + |
| 120 | +## License |
| 121 | +MIT |
0 commit comments