Skip to content

Commit eb9f446

Browse files
committed
Coverage html (#46)
* Revert "Allow nativelink flake module to upload results (TraceMachina#1369)" (TraceMachina#1372) This partially reverts commit 9600839. The original idea was to implement a `readonly` setting to dynamically configure `--remote_upload_local_results`. While this is fairly straightforward to implement it turned out that the UX implications around the environment variables/scripts/files to configure this are nontrivial and we need to evaluate the different approaches in more depth first. For now, revert to readonly by default and also add a small modifier to the relevant workflow so that the write-access workflow retains the ability to write artifacts on pushes to main. Fixes TraceMachina#1371 * Introduce reproducible branch-based coverage Reports may now be build via: ```nix nix build .#nativelinkCoverageForHost ``` The `result` symlink then contains the contents of a webpage to view the existing reports. Pushes to main publish the site at tracemachina.github.io/nativelink. Reports are built in release mode to closely resemble production coverage of the testsuite. This also means that most worker tests are ignored via a new `nix` feature to make the testsuite run in nix sandboxes. It's not ideal, but accurately reflects our production coverage guarantees. A future resolution for this might be to implement more elaborate mocking functionality for `nativelink-worker`. Coverage leverages nix caching, but not Bazel caching. While Bazel has builtin support for coverage, the reports were not satisfactory as they rely on outdated gcov toolchains with vague hermeticity guarantees and unsatisfactory implementations for llvm-cov-based workflows (e.g. no branch-based coverage for rust and no story around coverage for heterogeneous code). Mid-term we should implement "fast development" coverage via Bazel alongside the "slow production" coverage via Nix. As next steps we should continuously publish the generated HTML pages via the web infrastructure and add hooks to report regressions.
1 parent 68753c6 commit eb9f446

File tree

12 files changed

+141
-4
lines changed

12 files changed

+141
-4
lines changed

.github/workflows/coverage.yaml

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
---
2+
name: Coverage
3+
4+
on:
5+
push:
6+
branches: [main]
7+
pull_request:
8+
branches: [main]
9+
paths-ignore:
10+
- 'docs/**'
11+
12+
permissions: read-all
13+
14+
concurrency:
15+
group: ${{ github.workflow }}-${{ github.ref }}
16+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
17+
18+
jobs:
19+
coverage:
20+
strategy:
21+
fail-fast: false
22+
matrix:
23+
os: [ubuntu-24.04, macos-14]
24+
name: Coverage / ${{ matrix.os }}
25+
runs-on: ${{ matrix.os }}
26+
timeout-minutes: 45
27+
steps:
28+
- name: Checkout
29+
uses: >- # v4.1.1
30+
actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
31+
32+
- name: Install Nix
33+
uses: >- # v10
34+
DeterminateSystems/nix-installer-action@de22e16c4711fca50c816cc9081563429d1cf563
35+
36+
- name: Free disk space
37+
uses: >- # v2.0.0
38+
endersonmenezes/free-disk-space@3f9ec39ebae520864ac93467ee395f5237585c21
39+
with:
40+
remove_android: true
41+
remove_dotnet: true
42+
remove_haskell: true
43+
remove_tool_cache: false
44+
45+
- name: Cache Nix derivations
46+
uses: >- # v4
47+
DeterminateSystems/magic-nix-cache-action@fc6aaceb40b9845a02b91e059ec147e78d1b4e41
48+
49+
- name: Generate coverage
50+
run: |
51+
nix build -L .#nativelinkCoverageForHost
52+
53+
- name: Upload coverage artifact
54+
if: matrix.os == 'ubuntu-24.04'
55+
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa
56+
with:
57+
path: result/html
58+
59+
deploy:
60+
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
61+
name: Deploy Coverage
62+
needs: coverage
63+
runs-on: ubuntu-latest
64+
permissions:
65+
pages: write # to deploy to GitHub Pages
66+
id-token: write # to authenticate to GitHub Pages
67+
steps:
68+
- name: Deploy to GitHub Pages
69+
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e

.github/workflows/main.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ jobs:
101101
--bes_backend=grpcs://bes-tracemachina-shared.build-faster.nativelink.net \
102102
--bes_header=x-nativelink-api-key=$NL_COM_API_KEY \
103103
--bes_results_url=https://app.nativelink.com/a/e3b1e0e0-4b73-45d6-85bc-5cb7b02edea5/build \
104-
${{ github.ref == 'refs/heads/main' && ' ' || '--nogenerate_json_trace_profile --remote_upload_local_results=false' }} \
104+
${{ github.ref == 'refs/heads/main' && '--remote_upload_local_results=true' || '--nogenerate_json_trace_profile --remote_upload_local_results=false' }} \
105105
//..."
106106
107107
docker-compose-compiles-nativelink:

CONTRIBUTING.md

+10
Original file line numberDiff line numberDiff line change
@@ -468,3 +468,13 @@ most automatically generated changelogs provide.
468468

469469
NativeLink Code of Conduct is available in the
470470
[CODE_OF_CONDUCT](https://github.com/tracemachina/nativelink/tree/main/CODE_OF_CONDUCT.md) file.
471+
472+
## Generating code coverage
473+
474+
You can generate branch-based coverage reports via:
475+
476+
```
477+
nix run .#nativelinkCoverageForHost
478+
```
479+
480+
The `result` symlink contains a webpage with the visualized report.

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ name = "nativelink"
3232
enable_tokio_console = [
3333
"nativelink-util/enable_tokio_console"
3434
]
35+
nix = [
36+
"nativelink-worker/nix"
37+
]
3538

3639
[dependencies]
3740
nativelink-error = { path = "nativelink-error" }

flake.nix

+40-1
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,21 @@
117117
];
118118
};
119119

120+
nightlyRustFor = p:
121+
p.rust-bin.nightly.${nightly-rust-version}.default.override {
122+
extensions = ["llvm-tools"];
123+
targets = [
124+
"${nixSystemToRustTriple p.stdenv.targetPlatform.system}"
125+
];
126+
};
127+
120128
craneLibFor = p: (crane.mkLib p).overrideToolchain stableRustFor;
129+
nightlyCraneLibFor = p: (crane.mkLib p).overrideToolchain nightlyRustFor;
121130

122131
src = pkgs.lib.cleanSourceWith {
123132
src = (craneLibFor pkgs).path ./.;
124133
filter = path: type:
125-
(builtins.match "^.*(data/SekienSkashita\.jpg|nativelink-config/README\.md)" path != null)
134+
(builtins.match "^.*(data/SekienAkashita\.jpg|nativelink-config/README\.md)" path != null)
126135
|| ((craneLibFor pkgs).filterCargoSources path type);
127136
};
128137

@@ -184,6 +193,7 @@
184193

185194
# Additional target for external dependencies to simplify caching.
186195
cargoArtifactsFor = p: (craneLibFor p).buildDepsOnly (commonArgsFor p);
196+
nightlyCargoArtifactsFor = p: (craneLibFor p).buildDepsOnly (commonArgsFor p);
187197

188198
nativelinkFor = p:
189199
(craneLibFor p).buildPackage ((commonArgsFor p)
@@ -334,6 +344,34 @@
334344
os = "linux";
335345
};
336346
};
347+
348+
nativelinkCoverageFor = p: let
349+
coverageArgs =
350+
(commonArgsFor p)
351+
// {
352+
# TODO(aaronmondal): For some reason we're triggering an edgecase where
353+
# mimalloc builds against glibc headers in coverage
354+
# builds. This leads to nonexistend __memcpy_chk and
355+
# __memset_chk symbols if fortification is enabled.
356+
# Our regular builds also have this issue, but we
357+
# should investigate further.
358+
hardeningDisable = ["fortify"];
359+
};
360+
in
361+
(nightlyCraneLibFor p).cargoLlvmCov (coverageArgs
362+
// {
363+
cargoArtifacts = nightlyCargoArtifactsFor p;
364+
cargoExtraArgs = builtins.concatStringsSep " " [
365+
"--all"
366+
"--locked"
367+
"--features nix"
368+
"--branch"
369+
"--ignore-filename-regex '.*(genproto|vendor-cargo-deps|crates).*'"
370+
];
371+
cargoLlvmCovExtraArgs = "--html --output-dir $out";
372+
});
373+
374+
nativelinkCoverageForHost = nativelinkCoverageFor pkgs;
337375
in rec {
338376
_module.args.pkgs = let
339377
nixpkgs-patched = (import self.inputs.nixpkgs {inherit system;}).applyPatches {
@@ -366,6 +404,7 @@
366404
lre-cc
367405
native-cli
368406
nativelink
407+
nativelinkCoverageForHost
369408
nativelink-aarch64-linux
370409
nativelink-debug
371410
nativelink-image

modules/nativelink.nix

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"--remote_instance_name=main"
2121
"--remote_header=x-nativelink-project=nativelink-ci"
2222
"--nogenerate_json_trace_profile"
23+
"--remote_upload_local_results=false"
2324
"--experimental_remote_cache_async"
2425
];
2526

nativelink-metric/nativelink-metric-macro-derive/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "nativelink-metric-macro-derive"
3-
version = "0.4.0"
3+
version = "0.5.3"
44
edition = "2021"
55

66
[lib]

nativelink-worker/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ name = "nativelink-worker"
33
version = "0.5.3"
44
edition = "2021"
55

6+
[features]
7+
nix = []
8+
69
[dependencies]
710
nativelink-error = { path = "../nativelink-error" }
811
nativelink-proto = { path = "../nativelink-proto" }

nativelink-worker/tests/local_worker_test.rs

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ fn make_temp_path(data: &str) -> String {
7373
)
7474
}
7575

76+
#[cfg_attr(feature = "nix", ignore)]
7677
#[nativelink_test]
7778
async fn platform_properties_smoke_test() -> Result<(), Error> {
7879
let mut platform_properties = HashMap::new();

nativelink-worker/tests/running_actions_manager_test.rs

+9
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,7 @@ async fn upload_files_from_above_cwd_test() -> Result<(), Box<dyn std::error::Er
989989

990990
// Windows does not support symlinks.
991991
#[cfg(not(target_family = "windows"))]
992+
#[cfg_attr(feature = "nix", ignore)]
992993
#[nativelink_test]
993994
async fn upload_dir_and_symlink_test() -> Result<(), Box<dyn std::error::Error>> {
994995
const WORKER_ID: &str = "foo_worker_id";
@@ -1321,6 +1322,7 @@ async fn cleanup_happens_on_job_failure() -> Result<(), Box<dyn std::error::Erro
13211322
Ok(())
13221323
}
13231324

1325+
#[cfg_attr(feature = "nix", ignore)]
13241326
#[nativelink_test]
13251327
async fn kill_ends_action() -> Result<(), Box<dyn std::error::Error>> {
13261328
const WORKER_ID: &str = "foo_worker_id";
@@ -1429,6 +1431,7 @@ async fn kill_ends_action() -> Result<(), Box<dyn std::error::Error>> {
14291431
// The wrapper script will print a constant string to stderr, and the test itself will
14301432
// print to stdout. We then check the results of both to make sure the shell script was
14311433
// invoked and the actual command was invoked under the shell script.
1434+
#[cfg_attr(feature = "nix", ignore)]
14321435
#[nativelink_test]
14331436
async fn entrypoint_does_invoke_if_set() -> Result<(), Box<dyn std::error::Error>> {
14341437
#[cfg(target_family = "unix")]
@@ -1572,6 +1575,7 @@ exit 0
15721575
Ok(())
15731576
}
15741577

1578+
#[cfg_attr(feature = "nix", ignore)]
15751579
#[nativelink_test]
15761580
async fn entrypoint_injects_properties() -> Result<(), Box<dyn std::error::Error>> {
15771581
#[cfg(target_family = "unix")]
@@ -1747,6 +1751,7 @@ exit 0
17471751
Ok(())
17481752
}
17491753

1754+
#[cfg_attr(feature = "nix", ignore)]
17501755
#[nativelink_test]
17511756
async fn entrypoint_sends_timeout_via_side_channel() -> Result<(), Box<dyn std::error::Error>> {
17521757
#[cfg(target_family = "unix")]
@@ -2268,6 +2273,7 @@ async fn action_result_has_used_in_message() -> Result<(), Box<dyn std::error::E
22682273
Ok(())
22692274
}
22702275

2276+
#[cfg_attr(feature = "nix", ignore)]
22712277
#[nativelink_test]
22722278
async fn ensure_worker_timeout_chooses_correct_values() -> Result<(), Box<dyn std::error::Error>> {
22732279
const WORKER_ID: &str = "foo_worker_id";
@@ -2681,6 +2687,7 @@ async fn worker_times_out() -> Result<(), Box<dyn std::error::Error>> {
26812687
Ok(())
26822688
}
26832689

2690+
#[cfg_attr(feature = "nix", ignore)]
26842691
#[nativelink_test]
26852692
async fn kill_all_waits_for_all_tasks_to_finish() -> Result<(), Box<dyn std::error::Error>> {
26862693
const WORKER_ID: &str = "foo_worker_id";
@@ -2841,6 +2848,7 @@ async fn kill_all_waits_for_all_tasks_to_finish() -> Result<(), Box<dyn std::err
28412848

28422849
/// Regression Test for Issue #675
28432850
#[cfg(target_family = "unix")]
2851+
#[cfg_attr(feature = "nix", ignore)]
28442852
#[nativelink_test]
28452853
async fn unix_executable_file_test() -> Result<(), Box<dyn std::error::Error>> {
28462854
const WORKER_ID: &str = "foo_worker_id";
@@ -3219,6 +3227,7 @@ async fn upload_with_single_permit() -> Result<(), Box<dyn std::error::Error>> {
32193227
Ok(())
32203228
}
32213229

3230+
#[cfg_attr(feature = "nix", ignore)]
32223231
#[nativelink_test]
32233232
async fn running_actions_manager_respects_action_timeout() -> Result<(), Box<dyn std::error::Error>>
32243233
{

web/platform/src/content/docs/docs/nativelink-cloud/nix.mdx

+2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ build --remote_header=x-nativelink-api-key=065f02f53f26a12331d5cfd00a778fb243bfb
9595
build --remote_instance_name=main
9696
build --remote_header=x-nativelink-project=nativelink-ci
9797
build --nogenerate_json_trace_profile
98+
build --remote_upload_local_results=false
9899
build --experimental_remote_cache_async
99100
```
100101
@@ -116,5 +117,6 @@ build:nativelink --remote_cache=grpcs://my-custom-endpoints.com
116117
build:nativelink --remote_header=x-nativelink-api-key=my-custom-readonly-api-key
117118
build:nativelink --remote_header=x-nativelink-project=nativelink-ci
118119
build:nativelink --nogenerate_json_trace_profile
120+
build:nativelink --remote_upload_local_results=false
119121
build:nativelink --experimental_remote_cache_async
120122
```

0 commit comments

Comments
 (0)