forked from fjall-rs/lsm-tree
-
Notifications
You must be signed in to change notification settings - Fork 1
482 lines (472 loc) · 24.6 KB
/
Copy pathcoordinode-ci.yml
File metadata and controls
482 lines (472 loc) · 24.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# Hardening policy: every `uses:` ref is pinned to a full commit
# SHA with an inline `# vX.Y.Z` comment; every `actions/checkout`
# step sets `persist-credentials: false` unless a later step in
# the same job legitimately runs `git push`. Disabled/reference
# workflows live in `.github/disabled/`, not here, so audit
# scanners stay clean.
name: CoordiNode CI
on:
push:
branches:
- main
pull_request:
branches:
- main
# Manual re-run from any branch. Two use cases:
# (a) re-trigger a flaky cross-compile target after qemu
# hiccup — needs `full_cross_matrix: true` because the
# flaky ones (powerpc64, riscv64) live ONLY in the full
# matrix, not the PR/dispatch default;
# (b) maintainer wants a full CI cycle on a draft branch
# without opening a PR — also `full_cross_matrix: true`
# to mirror main-branch coverage.
# Without the input set (default), manual dispatch runs the
# same reduced 2-target cross matrix that PRs do (aarch64-gnu
# + i686-gnu) — useful for quick sanity-check re-runs.
# Triggering workflow_dispatch from the UI / API requires
# repository write access (not the workflow-token `actions:write`
# scope, which is a different thing). Fork PR authors don't
# have write on the upstream repo, so they can't fire this —
# full_cross_matrix has no fork-side attack surface.
workflow_dispatch:
inputs:
full_cross_matrix:
description: "Run the full 5-target cross-compile matrix (aarch64-gnu/musl, i686-gnu, powerpc64-gnu, riscv64gc-gnu) instead of the reduced 2-target subset"
type: boolean
default: false
required: false
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
jobs:
# Detect whether the change set touches code we want to validate.
# Used to gate the inner steps of `lint` and `test (stable,
# ubuntu-latest)` — both of which are REQUIRED checks in the
# branch ruleset — so their job names always surface to GitHub
# (satisfying the ruleset) while heavy work is skipped on
# docs-only / repo-meta-only PRs. Non-required downstream jobs
# (`no-std-check`, `cross-matrix`, `cross`,
# `codecov`) gate at the job level via `if:` and skip outright
# when no code changes — they aren't required so a "skipped"
# status is fine for them, but a required check that reports
# "skipped" is treated as "not yet satisfied" by the ruleset
# engine, hence the in-job conditional pattern below for the
# two required jobs.
changes:
runs-on: ubuntu-latest
# Bumped from the original 2 min — generous timeout so a slow
# `/pulls/{N}/files` page on a large PR can't run us into a
# hard wall. The job is also designed to NEVER fail (every
# path below resolves to a `code` output, even on API errors)
# so a missed deadline is the only remaining failure mode and
# 10 min gives plenty of margin.
timeout-minutes: 10
# Read-only token: the `pull_request` branch of the script
# below hits `/pulls/{N}/files`; non-PR events
# (`push` to main, `workflow_dispatch`) bypass the API
# entirely and just emit `code=true`. Either way, we never
# push and never write. Explicit `permissions:` block scopes
# the auto-provided GITHUB_TOKEN to exactly what this job
# needs, regardless of repo-default permission settings.
permissions:
contents: read
pull-requests: read
outputs:
code: ${{ steps.filter.outputs.code }}
steps:
# No `actions/checkout` step on purpose: the change predicate
# uses GitHub's REST API to list affected files via
# `/pulls/{N}/files` for the `pull_request` event. That
# avoids the `actions/checkout@v6 + fetch-depth: 0 +
# persist-credentials: false` 403 we hit on the first
# attempt, and skips the clone cost entirely for a job that
# only needs path names. Non-PR events (`push` to main,
# `workflow_dispatch`) bypass the path filter entirely and
# always emit `code=true` — see the inline rationale below.
- name: Detect code-touching changes
id: filter
# Override the runner's default `-eo pipefail` flags.
# GitHub Actions invokes the default `bash` step with
# `bash --noprofile --norc -eo pipefail {0}`, so a script
# that just adds `set -u` STILL inherits `-e` + pipefail
# from the runner. This job is a hard dependency of the
# required `lint` + `test (stable, ubuntu-latest)` checks
# (they `needs: changes`); any non-zero exit cascades to
# "required check never reports" and blocks merges, which
# is exactly the failure mode we built the safe-default
# output for. Keep `--noprofile --norc` so we still match
# the runner's clean-env defaults (no inherited dotfiles
# from a self-hosted runner with profile.d / bashrc) —
# we only drop the `-eo pipefail` half deliberately.
shell: bash --noprofile --norc {0}
env:
GH_TOKEN: ${{ github.token }}
EVENT_NAME: ${{ github.event_name }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
set -u
# Helper: emit a `code` output, log a reason, and exit 0
# so dependent jobs always have a valid value to consume.
emit_and_exit() {
local code_value="$1"
local reason="$2"
echo "::notice::changes job: code=$code_value ($reason)"
echo "code=$code_value" >> "$GITHUB_OUTPUT"
exit 0
}
if [ "$EVENT_NAME" = "pull_request" ]; then
# GitHub's own PR file list is the merge-base diff —
# exactly what we want, without resolving merge-base
# ourselves. Paginated to handle PRs touching >100 files
# (the API caps each page at 100, more pages auto-fetch).
# stdout / stderr are captured into SEPARATE variables:
# stdout (filename list) goes into CHANGED, stderr (any
# warnings or rate-limit messages) is preserved in
# API_ERR for the error notice. Mixing the two streams
# would let stderr noise leak into the CODE_RE predicate
# below and possibly mis-classify the run.
echo "Fetching PR #$PR_NUMBER file list via REST API..."
API_ERR_FILE=$(mktemp)
if ! CHANGED=$(gh api --paginate "repos/$REPO/pulls/$PR_NUMBER/files" --jq '.[].filename' 2>"$API_ERR_FILE"); then
# API/auth/rate-limit failure: don't cascade. Default
# to `code=true` so the real lint/test runs anyway.
# Surface the underlying error message in the notice
# so an operator debugging a flake sees what GitHub
# actually returned.
api_err=$(cat "$API_ERR_FILE" | tr '\n' ' ' | head -c 200)
rm -f "$API_ERR_FILE"
emit_and_exit "true" "REST /pulls/$PR_NUMBER/files failed (${api_err:-no stderr}), defaulting to full CI"
fi
rm -f "$API_ERR_FILE"
else
# Any non-`pull_request` event (push to main per the
# workflow trigger, plus `workflow_dispatch` for manual
# re-runs) bypasses the path filter and runs full CI.
#
# Rationale: the path-filter optimisation exists for
# developer iteration on PR branches (typical PR is
# N small commits, fast feedback matters). Merges to
# main are integration events validating what ships;
# manual workflow dispatches are operator-initiated and
# are by definition non-routine. Neither has an
# iteration loop to optimise. Skipping CI on a
# "docs-only" push to main would ALSO be structurally
# unsafe given the compare API's known 300-entry
# `.files` truncation cap — a large code-changing merge
# could be misclassified as `code=false` and silently
# skip validation.
emit_and_exit "true" "$EVENT_NAME event — always run full CI (no path filter outside PRs)"
fi
echo "Changed files:"
printf '%s\n' "$CHANGED" | sed 's/^/ /'
# Predicate: anything that affects compile / lint / test
# results counts as code. The workflow file is included so
# changes to CI logic itself always trigger the full matrix
# (avoids self-skipping a CI refactor PR). The lint/test
# config files (`.config/nextest.toml`, `.rustfmt.toml`,
# `clippy.toml`) and the in-repo test fixtures
# (`test_fixture/`) are included because changes to any of
# them can flip the lint/test outcome on otherwise-identical
# source code — skipping the real validation on a PR that
# touches only those files would defeat the purpose of the
# required-check gate.
CODE_RE='^(src/|tests/|benches/|examples/|test_fixture/|build\.rs$|Cargo\.toml$|Cargo\.lock$|tools/|\.github/workflows/coordinode-ci\.yml$|rust-toolchain(\.toml)?$|\.cargo/|\.config/nextest\.toml$|\.rustfmt\.toml$|clippy\.toml$)'
if printf '%s\n' "$CHANGED" | grep -qE "$CODE_RE"; then
emit_and_exit "true" "code paths affected — running real CI"
else
emit_and_exit "false" "no code paths affected — fast success"
fi
lint:
needs: changes
# `always() && !cancelled()` so the required `lint` check
# still runs (and emits its name to the ruleset) even if
# `changes` itself fails / is skipped — `!cancelled()` alone
# is NOT enough because GitHub's default needs-gating skips
# this job when a dependency fails. `always()` overrides that
# gating; the `!cancelled()` half lets a user-cancelled
# workflow run still report cancellation honestly. Empty
# `needs.changes.outputs.code` (changes job failed before
# emitting output) is caught below by the `!= 'false'` step
# guards, which default to running the real lint work (safe
# fallback).
if: ${{ always() && !cancelled() }}
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
# Surfaces a notice in the run log + summary so docs-only PRs
# leave an obvious trail explaining why the check passed
# without doing real work. Only fires on the explicit
# `code=false` signal — empty/unset (changes job failed)
# falls through to the real lint work below.
- name: Path-conditional skip notice
if: needs.changes.outputs.code == 'false'
run: |
echo "::notice::No code paths changed — skipping format + clippy. Required-check name still emitted as success."
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
if: needs.changes.outputs.code != 'false'
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
if: needs.changes.outputs.code != 'false'
with:
toolchain: stable
components: rustfmt, clippy
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
if: needs.changes.outputs.code != 'false'
- name: Format
if: needs.changes.outputs.code != 'false'
run: cargo fmt --all -- --check
- name: Clippy (strict)
if: needs.changes.outputs.code != 'false'
# `--all-targets` lints tests + benches too, not just the lib; without
# it, test-harness code under `--all-features` is never clippy-checked.
run: cargo clippy --all-features --all-targets -- -D warnings
test:
needs: [changes, lint]
# `always() && !cancelled()` so the matrix entries still
# emit their names to the ruleset even if `changes` or
# `lint` fails / is skipped. `!cancelled()` alone is NOT
# enough because GitHub's default needs-gating skips this
# job when a dependency fails; `always()` overrides that
# gating, the `!cancelled()` half lets a user-cancelled
# workflow run still report cancellation honestly. Empty
# `needs.changes.outputs.code` is treated as "run real
# tests" via the `!= 'false'` step guards.
#
# Matrix-aware skip (run only the required entry on docs-
# only PRs) was attempted via a job-level
# `matrix.rust == 'stable' && matrix.os == 'ubuntu-latest'`
# branch in this `if:`, but the `matrix` context is NOT
# available at job-level expression evaluation — only at
# step-level and in job names. All 6 matrix entries run on
# docs-only PRs and emit the skip notice from their own
# step-level guards; if optimising runner-minute waste is
# later required, the right shape is a dynamic matrix via
# `fromJSON(needs.changes.outputs.matrix)` (with `changes`
# emitting two pre-baked JSON values), not job-level `if:`.
if: ${{ always() && !cancelled() }}
timeout-minutes: 20
strategy:
fail-fast: true
matrix:
rust: [stable, "1.92.0"]
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
# Same path-conditional skip pattern as `lint`. ALL matrix
# entries emit their job name regardless of whether the inner
# steps ran, so `test (stable, ubuntu-latest)` — the entry
# listed in the branch ruleset as a required check — is
# always satisfied on docs-only PRs / lint-failed PRs
# without paying the full test cost.
#
# Three step-level cases for the inner work:
# - code == 'false' → skip notice (docs-only PR)
# - lint.result != 'success' → skip notice (lint broken; running tests adds noise on an already-failed PR)
# - code != 'false' AND lint.result == 'success' → real work
# The job-level `if: always() && !cancelled()` keeps the
# required check name surfacing in all three cases.
- name: Path-conditional skip notice
if: needs.changes.outputs.code == 'false'
run: |
echo "::notice::No code paths changed — skipping nextest + doc tests + tools/. Required-check name still emitted as success."
- name: Lint-failed skip notice
if: needs.changes.outputs.code != 'false' && needs.lint.result != 'success'
run: |
echo "::notice::Lint failed (result=${{ needs.lint.result }}) — skipping test work to avoid duplicate noise on an already-failed PR. Required-check name still emitted; fix the lint failure to unblock real test runs."
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
if: needs.changes.outputs.code != 'false' && needs.lint.result == 'success'
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
if: needs.changes.outputs.code != 'false' && needs.lint.result == 'success'
with:
toolchain: ${{ matrix.rust }}
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
if: needs.changes.outputs.code != 'false' && needs.lint.result == 'success'
with:
prefix-key: ${{ runner.os }}-cargo
- uses: taiki-e/install-action@1ef5c5f58e85d25baaaa1704478fdd6c2921f2b5 # nextest
if: needs.changes.outputs.code != 'false' && needs.lint.result == 'success'
- name: Run tests
if: needs.changes.outputs.code != 'false' && needs.lint.result == 'success'
# tools/db_bench is a standalone crate, not in workspace — built separately
env:
# 32 cases is plenty for CI; PROPTEST_MAX_SHRINK trims the
# shrink budget from 1000 → 100 because at this case count
# shrinking rarely exceeds 20–50 iterations and the extra
# budget is wasted CI time. See tests/common/mod.rs.
PROPTEST_CASES: "32"
PROPTEST_MAX_SHRINK: "100"
run: cargo nextest run --profile ci --all-features
- name: Run doc tests
if: needs.changes.outputs.code != 'false' && needs.lint.result == 'success'
run: cargo test --doc --features lz4
- name: Check db_bench crate
if: needs.changes.outputs.code != 'false' && needs.lint.result == 'success'
working-directory: tools/db_bench
run: cargo check --all-features
- name: Build + test sst-dump crate
if: needs.changes.outputs.code != 'false' && needs.lint.result == 'success'
# Standalone crate (not in workspace), exercise both the bin
# build and the integration smoke tests so any drift in the
# public verify::verify_sst_file API or the SST writer layout
# surfaces here instead of in production. No `--profile ci`:
# sst-dump has no .config/nextest.toml of its own and the
# parent crate's profile config is not visible from a
# non-workspace child.
working-directory: tools/sst-dump
run: cargo nextest run
no-std-check:
# Gates the `#![no_std]` + alloc engine path. The engine modules compile
# unconditionally; only the std default trait implementations (the system
# filesystem, the io_uring backend, the system clock) stay behind
# `#[cfg(feature = "std")]`. This job runs `cargo check --no-default-features
# --features alloc` on a true no-std-only target (the `thumbv7em-none-eabihf`
# cross-compile target has no std at all, so any leaked `std::*` import
# surfaces here even if the host toolchain has std available).
#
# This is a HARD GATE: the alloc build must stay clean. New code added to
# this crate MUST be no-std-friendly (prefer `core::*` / `alloc::*`, gate
# std-only behind `#[cfg(feature = "std")]`). A failure here means a
# `std::*` leak crept onto an engine path: fix the leak, do not relax the
# gate.
needs: [changes, lint]
if: ${{ always() && !cancelled() && needs.lint.result == 'success' && needs.changes.outputs.code != 'false' }}
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
toolchain: "1.92.0"
- name: Install no-std target
# Some versions of `dtolnay/rust-toolchain@stable` silently skip the
# `targets:` input when `toolchain:` is pinned to a specific version
# rather than a channel name. Install the cross target explicitly so
# the no-std check can never break for a target-not-installed reason
# (which would mask real migration progress).
run: rustup target add thumbv7em-none-eabihf
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
prefix-key: ubuntu-cargo-no-std
- name: Check (no_std + alloc)
run: cargo check --target thumbv7em-none-eabihf --no-default-features --features alloc
# Generates the cross-compile target matrix. The full 5-target
# sweep runs in either of two cases:
# - push to main (regression coverage on every merged change)
# - workflow_dispatch with `full_cross_matrix: true` (manual
# opt-in for re-testing flaky targets or for full coverage
# on a draft branch)
# Everything else — PR builds + default manual dispatches —
# uses the reduced 2-target subset (aarch64-gnu + i686-gnu)
# that covers the two canonical pointer-width / ABI mistakes:
# 64-bit aarch64 ABI quirks and 32-bit x86 pointer-width.
# Both targets are little-endian — endianness coverage (the
# big-endian powerpc64 target) is deferred to the full sweep
# on main, alongside musl libc differences and the qemu-
# emulated riscv64 path. The reduced run is ~30% of the
# full-sweep cost and keeps PR feedback under 5 min.
cross-matrix:
# No `needs: lint` — this job only inspects github.event_name
# / github.ref / inputs to emit a JSON target list. It doesn't
# touch source, doesn't compile, doesn't run lint-sensitive
# tooling. Running it in parallel with lint shaves ~10s off
# the PR critical path: the matrix is ready when lint
# finishes, and `cross` (which `needs: [changes, lint,
# cross-matrix]`) starts immediately rather than waiting for
# serial chain.
needs: changes
# cross-matrix doesn't depend on `lint` (it's a pure
# github.event_name / inputs lookup that emits a JSON target
# list), so the `needs.lint.result` gate the other downstream
# jobs carry doesn't apply here — the matrix-generation work
# is cheap (~2 s) and independent of lint passing. The
# `always() && !cancelled()` half still applies so a `changes`
# infra-failure doesn't silently skip the matrix generator
# (which would cascade into `cross` skipping for the wrong
# reason).
if: ${{ always() && !cancelled() && needs.changes.outputs.code != 'false' }}
runs-on: ubuntu-latest
outputs:
targets: ${{ steps.set.outputs.targets }}
steps:
- id: set
env:
IS_FULL: ${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'workflow_dispatch' && inputs.full_cross_matrix) }}
run: |
if [ "$IS_FULL" = "true" ]; then
echo 'targets=["aarch64-unknown-linux-gnu","aarch64-unknown-linux-musl","i686-unknown-linux-gnu","powerpc64-unknown-linux-gnu","riscv64gc-unknown-linux-gnu"]' >> "$GITHUB_OUTPUT"
else
echo 'targets=["aarch64-unknown-linux-gnu","i686-unknown-linux-gnu"]' >> "$GITHUB_OUTPUT"
fi
cross:
needs: [changes, lint, cross-matrix]
if: ${{ always() && !cancelled() && needs.lint.result == 'success' && needs.changes.outputs.code != 'false' }}
timeout-minutes: 15
strategy:
fail-fast: true
matrix:
# Bracket notation REQUIRED on the needs context key here:
# the job id `cross-matrix` contains a hyphen, so dot
# notation (`needs.cross-matrix.outputs.targets`) is parsed
# by the GitHub Actions expression engine as `needs.cross`
# minus `matrix.outputs.targets`, breaking the lookup.
target: ${{ fromJSON(needs['cross-matrix'].outputs.targets) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
toolchain: stable
- name: Install cross
run: cargo install cross
- name: Cross test
# proptest cases: 32 hardcoded in ProptestConfig
run: cross test -r --features lz4 --target ${{ matrix.target }}
codecov:
needs: [changes, lint]
if: ${{ always() && !cancelled() && needs.lint.result == 'success' && needs.changes.outputs.code != 'false' }}
timeout-minutes: 20
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # nightly
with:
components: llvm-tools-preview
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- uses: taiki-e/install-action@6bd9352acd589686fbc4cff533c083c3366dd444 # cargo-llvm-cov
- uses: taiki-e/install-action@1ef5c5f58e85d25baaaa1704478fdd6c2921f2b5 # nextest
- name: Run tests (all-features) with coverage
env:
# Same proptest budget as the regular test job — without
# these, the coverage job would default to proptest's
# built-in 256 cases and dominate CI time. See
# tests/common/mod.rs.
PROPTEST_CASES: "32"
PROPTEST_MAX_SHRINK: "100"
run: cargo +nightly llvm-cov --no-report nextest --all-features
# zstd feature: run with a narrower feature set (zstd + lz4, no defaults)
# to validate the zstd backend in isolation. --all-features already enables
# zstd (zstd-pure is an alias), so this step covers the non-default path.
- name: Run tests (zstd backend) with coverage
env:
PROPTEST_CASES: "32"
PROPTEST_MAX_SHRINK: "100"
run: cargo +nightly llvm-cov --no-report nextest --no-default-features --features zstd,lz4
- run: cargo +nightly llvm-cov --no-report --doc --features lz4
- run: cargo +nightly llvm-cov report --doctests --lcov --output-path lcov.info --ignore-filename-regex='registry'
- uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
files: lcov.info
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}