From af50bc808a7bb8e13d71f18d8a33c55da00f114f Mon Sep 17 00:00:00 2001 From: Thomas Krause Date: Tue, 31 Oct 2023 18:35:52 +0100 Subject: [PATCH 1/5] Remove old release GH action --- .github/workflows/deploy-release.yml | 192 --------------------------- 1 file changed, 192 deletions(-) delete mode 100644 .github/workflows/deploy-release.yml diff --git a/.github/workflows/deploy-release.yml b/.github/workflows/deploy-release.yml deleted file mode 100644 index 41a278f12..000000000 --- a/.github/workflows/deploy-release.yml +++ /dev/null @@ -1,192 +0,0 @@ -on: - release: - types: - - published -name: Deploy released binaries -jobs: - deploy_linux_binaries: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1.0.6 - with: - toolchain: stable - profile: minimal - - uses: Swatinem/rust-cache@v2.2.1 - - run: cargo build --release --bin annis --bin graphannis-webservice --lib - - run: ls target/release - - name: Set release version - run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - - uses: octokit/request-action@v2.x - id: get_release - with: - route: GET /repos/${{ github.repository }}/releases/tags/${{env.RELEASE_VERSION}} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - id: get_upload_url - run: | - url=$(echo "$response" | jq -r '.upload_url') - echo "::set-output name=url::$url" - env: - response: ${{ steps.get_release.outputs.data }} - - name: Upload graphANNIS shared library - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{steps.get_upload_url.outputs.url}} - asset_path: ./target/release/libgraphannis_capi.so - asset_name: libgraphannis.so - asset_content_type: application/x-sharedlib - - name: Upload graphANNIS CLI - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{steps.get_upload_url.outputs.url}} - asset_path: ./target/release/annis - asset_name: annis - asset_content_type: application/x-sharedlib - - name: Upload graphANNIS webservice - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{steps.get_upload_url.outputs.url}} - asset_path: ./target/release/graphannis-webservice - asset_name: graphannis-webservice - asset_content_type: application/x-sharedlib - deploy_windows_binaries: - runs-on: windows-2019 - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1.0.6 - with: - toolchain: stable - profile: minimal - - uses: Swatinem/rust-cache@v2.2.1 - - name: Set release version - run: | - $version = $env:GITHUB_REF.replace('refs/tags/', '') - echo "RELEASE_VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - uses: octokit/request-action@v2.x - id: get_release - with: - route: GET /repos/${{ github.repository }}/releases/tags/${{env.RELEASE_VERSION}} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - id: get_upload_url - run: | - $found = "$env:response" -match '"upload_url": "([^"]*)",' - $url = $matches[1] - echo "ASSET_UPLOAD_URL=$url" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - env: - response: ${{ steps.get_release.outputs.data }} - - run: cargo build --release --bin annis --bin graphannis-webservice --lib - - run: dir target/release - - name: Upload graphANNIS shared library - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{env.ASSET_UPLOAD_URL}} - asset_path: ./target/release/graphannis_capi.dll - asset_name: graphannis.dll - asset_content_type: application/x-dosexec - - name: Upload graphANNIS CLI - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{env.ASSET_UPLOAD_URL}} - asset_path: ./target/release/annis.exe - asset_name: annis.exe - asset_content_type: application/x-dosexec - - name: Upload graphANNIS webservice - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{env.ASSET_UPLOAD_URL}} - asset_path: ./target/release/graphannis-webservice.exe - asset_name: graphannis-webservice.exe - asset_content_type: application/x-dosexec - deploy_macos_binaries: - runs-on: macos-11 - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1.0.6 - with: - toolchain: stable - profile: minimal - - uses: Swatinem/rust-cache@v2.2.1 - - run: cargo build --release --bin annis --bin graphannis-webservice --lib - - run: ls target/release - - name: Set release version - run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - - uses: octokit/request-action@v2.x - id: get_release - with: - route: GET /repos/${{ github.repository }}/releases/tags/${{env.RELEASE_VERSION}} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - id: get_upload_url - run: | - url=$(echo "$response" | jq -r '.upload_url') - echo "::set-output name=url::$url" - env: - response: ${{ steps.get_release.outputs.data }} - - name: Upload graphANNIS shared library - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{steps.get_upload_url.outputs.url}} - asset_path: ./target/release/libgraphannis_capi.dylib - asset_name: libgraphannis.dylib - asset_content_type: application/x-mach-binary - - name: Upload graphANNIS CLI - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{steps.get_upload_url.outputs.url}} - asset_path: ./target/release/annis - asset_name: annis.osx - asset_content_type: application/x-mach-binary - - name: Upload graphANNIS webservice - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{steps.get_upload_url.outputs.url}} - asset_path: ./target/release/graphannis-webservice - asset_name: graphannis-webservice.osx - asset_content_type: application/x-mach-binary - deploy_documentation: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v1 - - name: Get the release version from the GITHUB_REF variable as new SHORT_VERSION variable - run: echo "SHORT_VERSION=$(echo ${GITHUB_REF} | sed -E 's/^refs\/heads\/.*/develop/' | sed -E 's/^(refs\/tags\/v)?(.*)(\.[0-9]+\.[0-9]+)$/\2/')" >> $GITHUB_ENV - - run: misc/download-mdbook.sh 0.3.5 - env: - OS_NAME: linux - - name: Generate the documentation - run: mdbook build --dest-dir book/v${SHORT_VERSION} docs/ - - run: git clone -q -b gh-pages https://github.com/$GITHUB_REPOSITORY gh-pages - - name: Remove old files for this version - run: rm -Rf gh-pages/docs/v$SHORT_VERSION - - name: copy the documentation content - run: cp -R docs/book/* gh-pages/docs/ - - run: git add docs/v$SHORT_VERSION - working-directory: gh-pages - - run: git -c user.name='gh-actions' -c user.email='gh-actions' commit --allow-empty -m "add documentation for version $SHORT_VERSION" - working-directory: gh-pages - - name: Push changes - uses: ad-m/github-push-action@v0.6.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - directory: gh-pages - branch: gh-pages From ebe3cfbb04efd85771d4f49a26bbbf6260228b38 Mon Sep 17 00:00:00 2001 From: Thomas Krause Date: Tue, 31 Oct 2023 18:49:37 +0100 Subject: [PATCH 2/5] Create code coverage report using codecov.io --- .github/workflows/code_coverage.yml | 107 +++++++--------------------- 1 file changed, 26 insertions(+), 81 deletions(-) diff --git a/.github/workflows/code_coverage.yml b/.github/workflows/code_coverage.yml index f379a9788..e315832bd 100644 --- a/.github/workflows/code_coverage.yml +++ b/.github/workflows/code_coverage.yml @@ -1,81 +1,24 @@ name: Code Coverage on: + push: + branches: + - main pull_request: - branches: [main] - merge_group: jobs: - base_branch_cov: + coverage: + name: Execute tests with code coverage runs-on: ubuntu-latest + env: + CARGO_TERM_COLOR: always steps: - - uses: actions/checkout@v2 - with: - ref: ${{ github.base_ref }} - - uses: actions-rs/toolchain@v1.0.6 - with: - toolchain: stable - profile: minimal - components: llvm-tools-preview - - uses: Swatinem/rust-cache@v2.2.1 - - uses: SierraSoftworks/setup-grcov@v1 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - version: latest - - uses: actions/cache@v2 - id: code-coverage-corpus-cache - with: - path: | - relannis - data - data_ondisk - key: ${{ runner.os }}-codecov-${{ hashFiles('graphannis/tests/searchtest.rs','graphannis/tests/searchtest_queries.csv', 'graphannis/build.rs') }} - - name: Download test corpora - if: steps.corpus-cache.outputs.cache-hit != 'true' - run: test -d relannis/GUM/ -a -d relannis/pcc2.1/ -a -d relannis/subtok.demo || "./misc/download-test-corpora.sh" - - name: Build CLI binary - if: steps.corpus-cache.outputs.cache-hit != 'true' - run: cargo build --release --bin annis - - name: Import GUM corpus (memory) - if: steps.corpus-cache.outputs.cache-hit != 'true' - run: ./target/release/annis data --cmd 'import relannis/GUM' - - name: Import pcc2.1 corpus (memory) - if: steps.corpus-cache.outputs.cache-hit != 'true' - run: ./target/release/annis data --cmd 'import relannis/pcc2.1' - - name: Import subtok.demo corpus (memory) - if: steps.corpus-cache.outputs.cache-hit != 'true' - run: ./target/release/annis data --cmd 'import relannis/subtok.demo' - - name: Run tests with code coverage - run: misc/test_coverage.sh - - - name: Upload code coverage for ref branch - uses: actions/upload-artifact@v2 - with: - name: ref-lcov.info - path: ./target/coverage/tests.lcov - - checks: - runs-on: ubuntu-latest - needs: base_branch_cov - steps: - - uses: actions/checkout@v2 - - name: Download code coverage report from base branch - uses: actions/download-artifact@v2 - with: - name: ref-lcov.info - - - uses: actions-rs/toolchain@v1.0.6 + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1.4.4 with: toolchain: stable - profile: minimal - components: llvm-tools-preview - - uses: Swatinem/rust-cache@v2.2.1 - - uses: SierraSoftworks/setup-grcov@v1 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - version: latest - uses: actions/cache@v2 - id: code-coverage-corpus-cache + id: corpus-cache with: path: | relannis @@ -97,17 +40,19 @@ jobs: - name: Import subtok.demo corpus (memory) if: steps.corpus-cache.outputs.cache-hit != 'true' run: ./target/release/annis data --cmd 'import relannis/subtok.demo' - - name: Run tests with code coverage - run: misc/test_coverage.sh - - # Compares two code coverage files and generates report as a comment - - name: Generate Code Coverage report - id: code-coverage - uses: barecheck/code-coverage-action@v1 - with: - barecheck-github-app-token: ${{ secrets.BARECHECK_GITHUB_APP_TOKEN }} - lcov-file: "./target/coverage/tests.lcov" - base-lcov-file: "./tests.lcov" - minimum-ratio: -0.05 # Fails Github action once code coverage is decreasing too much - send-summary-comment: true - show-annotations: "warning" # Possible options warning|error + - name: Install cargo-llvm-cov + uses: taiki-e/install-action@cargo-llvm-cov + - name: Remove old code coverage artifacts + run: cargo llvm-cov clean --workspace + - name: Run tests code coverage (standard tests) + run: cargo llvm-cov --no-report --release + - name: Run tests code coverage (ignored tests) + run: cargo llvm-cov --no-report --release -- --ignored + - name: Merge code coverage reports + run: cargo llvm-cov report --ignore-filename-regex '(tests?\.rs)|(capi/.*) --release --codecov --output-path codecov.json + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos + files: codecov.json + fail_ci_if_error: true From 012ec4778e4afa99efaceee84283c037229c9db5 Mon Sep 17 00:00:00 2001 From: Thomas Krause Date: Tue, 31 Oct 2023 18:52:34 +0100 Subject: [PATCH 3/5] Replace old test coverage file --- misc/test_coverage.sh | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/misc/test_coverage.sh b/misc/test_coverage.sh index 9c594d15f..1c4f672f9 100755 --- a/misc/test_coverage.sh +++ b/misc/test_coverage.sh @@ -1,31 +1,4 @@ -# Make sure you installed grcov via cargo first and that the llvm tools are available -# -# cargo install grcov -# rustup component add llvm-tools-preview - -# Set some environment variables needed by grcov -export RUSTFLAGS='-Cinstrument-coverage' -export CARGO_INCREMENTAL=0 -# Because these build flags are different, there will -# be a conflict between the build files generated by -# this script and other cargo processes. Thus, store -# the build artifacts into a different directory. -export CARGO_TARGET_DIR='target/coverage/' - -# Clean and create build folder for coverage. -# If we don't clean the folder, there might be a mixup between previous runs -# and the reported coverage is incosistent -rm -rf target/coverage -mkdir -p target/coverage/ - -# Run all tests -LLVM_PROFILE_FILE='cargo-test-%p-%m.profraw' cargo test -LLVM_PROFILE_FILE='cargo-ignored-test-%p-%m.profraw' cargo test -- --ignored - -# Generate HTML report in target/debug/coverage/index.html -grcov . --binary-path ./target/coverage/debug/deps/ -s . -t html --branch --ignore-not-existing --ignore 'target/*' --ignore '../*' --ignore '/*' --ignore '**/tests.rs' -o target/coverage/html/ -# Also generate a lcov file for further processing -grcov . --binary-path ./target/coverage/debug/deps/ -s . -t lcov --branch --ignore-not-existing --ignore 'target/*' --ignore '../*' --ignore '/*' --ignore '**/tests.rs' -o target/coverage/tests.lcov - -# Cleanup -find . -name '*.profraw' -delete +cargo llvm-cov clean --workspace +cargo llvm-cov --no-report --release +cargo llvm-cov --no-report --release -- --ignored +cargo llvm-cov report --ignore-filename-regex '(tests?\.rs)|(capi/.*) --release --open \ No newline at end of file From b58f45536101c8a45b592806bb8f511ebc44ae07 Mon Sep 17 00:00:00 2001 From: Thomas Krause Date: Tue, 31 Oct 2023 18:56:13 +0100 Subject: [PATCH 4/5] Add new cargo-dist config for releases --- .github/workflows/release.yml | 168 ++++++++++++++++++++++++++++++++++ Cargo.toml | 18 ++++ 2 files changed, 186 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..2c6fd9747 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,168 @@ +# Copyright 2022-2023, axodotdev +# SPDX-License-Identifier: MIT or Apache-2.0 +# +# CI that: +# +# * checks for a Git Tag that looks like a release +# * builds artifacts with cargo-dist (archives, installers, hashes) +# * uploads those artifacts to temporary workflow zip +# * on success, uploads the artifacts to a Github Release™ +# +# Note that the Github Release™ will be created with a generated +# title/body based on your changelogs. +name: Release + +permissions: + contents: write + +# This task will run whenever you push a git tag that looks like a version +# like "1.0.0", "v0.1.0-prerelease.1", "my-app/0.1.0", "releases/v1.0.0", etc. +# Various formats will be parsed into a VERSION and an optional PACKAGE_NAME, where +# PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION +# must be a Cargo-style SemVer Version (must have at least major.minor.patch). +# +# If PACKAGE_NAME is specified, then the release will be for that +# package (erroring out if it doesn't have the given version or isn't cargo-dist-able). +# +# If PACKAGE_NAME isn't specified, then the release will be for all +# (cargo-dist-able) packages in the workspace with that version (this mode is +# intended for workspaces with only one dist-able package, or with all dist-able +# packages versioned/released in lockstep). +# +# If you push multiple tags at once, separate instances of this workflow will +# spin up, creating an independent Github Release™ for each one. However Github +# will hard limit this to 3 tags per commit, as it will assume more tags is a +# mistake. +# +# If there's a prerelease-style suffix to the version, then the Github Release™ +# will be marked as a prerelease. +on: + push: + tags: + - '**[0-9]+.[0-9]+.[0-9]+*' + pull_request: + +jobs: + # Run 'cargo dist plan' to determine what tasks we need to do + plan: + runs-on: ubuntu-latest + outputs: + val: ${{ steps.plan.outputs.manifest }} + tag: ${{ !github.event.pull_request && github.ref_name || '' }} + tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }} + publishing: ${{ !github.event.pull_request }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Install cargo-dist + run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.4.2/cargo-dist-installer.sh | sh" + - id: plan + run: | + cargo dist plan ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }} --output-format=json > dist-manifest.json + echo "cargo dist plan ran successfully" + cat dist-manifest.json + echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT" + - name: "Upload dist-manifest.json" + uses: actions/upload-artifact@v3 + with: + name: artifacts + path: dist-manifest.json + + # Build and packages all the platform-specific things + upload-local-artifacts: + # Let the initial task tell us to not run (currently very blunt) + needs: plan + if: ${{ fromJson(needs.plan.outputs.val).releases != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }} + strategy: + fail-fast: false + # Target platforms/runners are computed by cargo-dist in create-release. + # Each member of the matrix has the following arguments: + # + # - runner: the github runner + # - dist-args: cli flags to pass to cargo dist + # - install-dist: expression to run to install cargo-dist on the runner + # + # Typically there will be: + # - 1 "global" task that builds universal installers + # - N "local" tasks that build each platform's binaries and platform-specific installers + matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }} + runs-on: ${{ matrix.runner }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: swatinem/rust-cache@v2 + - name: Install cargo-dist + run: ${{ matrix.install_dist }} + - name: Install dependencies + run: | + ${{ matrix.packages_install }} + - name: Build artifacts + run: | + # Actually do builds and make zips and whatnot + cargo dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json + echo "cargo dist ran successfully" + - id: cargo-dist + name: Post-build + # We force bash here just because github makes it really hard to get values up + # to "real" actions without writing to env-vars, and writing to env-vars has + # inconsistent syntax between shell and powershell. + shell: bash + run: | + # Parse out what we just built and upload it to the Github Release™ + echo "paths<> "$GITHUB_OUTPUT" + jq --raw-output ".artifacts[]?.path | select( . != null )" dist-manifest.json >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + + cp dist-manifest.json "$BUILD_MANIFEST_NAME" + - name: "Upload artifacts" + uses: actions/upload-artifact@v3 + with: + name: artifacts + path: | + ${{ steps.cargo-dist.outputs.paths }} + ${{ env.BUILD_MANIFEST_NAME }} + + should-publish: + needs: + - plan + - upload-local-artifacts + if: ${{ needs.plan.outputs.publishing == 'true' }} + runs-on: ubuntu-latest + steps: + - name: print tag + run: echo "ok we're publishing!" + + # Create a Github Release with all the results once everything is done + publish-release: + needs: [plan, should-publish] + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: "Download artifacts" + uses: actions/download-artifact@v3 + with: + name: artifacts + path: artifacts + - name: Cleanup + run: | + # Remove the granular manifests + rm artifacts/*-dist-manifest.json + - name: Create Release + uses: ncipollo/release-action@v1 + with: + tag: ${{ needs.plan.outputs.tag }} + name: ${{ fromJson(needs.plan.outputs.val).announcement_title }} + body: ${{ fromJson(needs.plan.outputs.val).announcement_github_body }} + prerelease: ${{ fromJson(needs.plan.outputs.val).announcement_is_prerelease }} + artifacts: "artifacts/*" diff --git a/Cargo.toml b/Cargo.toml index b2e197bc5..f4a7c0b44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,19 @@ members = [ "examples/tutorial", ] +# Config for 'cargo dist' +[workspace.metadata.dist] +# The preferred cargo-dist version to use in CI (Cargo.toml SemVer syntax) +cargo-dist-version = "0.4.2" +# CI backends to support +ci = ["github"] +# The installers to generate for each app +installers = [] +# Target platforms to build apps for (Rust target-triple syntax) +targets = ["x86_64-unknown-linux-gnu", "aarch64-apple-darwin", "x86_64-apple-darwin", "x86_64-pc-windows-msvc"] +# Publish jobs to run in CI +pr-run-mode = "plan" + # Use release optimization of some of the performance sensitive crates even for debug builds. # This allows faster builds and debugging of our own code, while balancing performance. [profile.dev.package.bincode] @@ -30,3 +43,8 @@ opt-level = 3 [profile.dev.package.zip] opt-level = 3 + +# The profile that 'cargo dist' will build with +[profile.dist] +inherits = "release" +lto = "thin" From 8ff06a28950bbe95ccb667de68e4809fbecf541f Mon Sep 17 00:00:00 2001 From: Thomas Krause Date: Tue, 31 Oct 2023 19:02:43 +0100 Subject: [PATCH 5/5] Missing closing quote --- misc/test_coverage.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/test_coverage.sh b/misc/test_coverage.sh index 1c4f672f9..f026d7bc7 100755 --- a/misc/test_coverage.sh +++ b/misc/test_coverage.sh @@ -1,4 +1,4 @@ cargo llvm-cov clean --workspace cargo llvm-cov --no-report --release cargo llvm-cov --no-report --release -- --ignored -cargo llvm-cov report --ignore-filename-regex '(tests?\.rs)|(capi/.*) --release --open \ No newline at end of file +cargo llvm-cov report --ignore-filename-regex '(tests?\.rs)|(capi/.*)' --release --open \ No newline at end of file