diff --git a/.codecov.yml b/.codecov.yml index ba771bc082..f4655afc02 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,6 +1,10 @@ comment: layout: "condensed_header, diff, flags, components" +flag_management: + default_rules: + carryforward: true + component_management: individual_components: - component_id: crashtracker # this is an identifier that should not be changed diff --git a/.github/actions/Cargo.lock b/.github/actions/Cargo.lock index f89dda4a45..cd4743a5cc 100644 --- a/.github/actions/Cargo.lock +++ b/.github/actions/Cargo.lock @@ -430,25 +430,12 @@ dependencies = [ "windows-link", ] -[[package]] -name = "ci-crates" -version = "0.1.0" -dependencies = [ - "anyhow", - "cargo_metadata", - "ci-shared", - "clap", - "env_logger 0.11.9", - "log", - "serde", - "serde_json", -] - [[package]] name = "ci-shared" version = "0.1.0" dependencies = [ "anyhow", + "cargo_metadata", "log", "serde", "serde_json", @@ -547,6 +534,20 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "crates-reporter" +version = "0.1.0" +dependencies = [ + "anyhow", + "cargo_metadata", + "ci-shared", + "clap", + "env_logger 0.11.9", + "log", + "serde", + "serde_json", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" diff --git a/.github/actions/Cargo.toml b/.github/actions/Cargo.toml index 3c798000f7..cdfde15441 100644 --- a/.github/actions/Cargo.toml +++ b/.github/actions/Cargo.toml @@ -4,7 +4,7 @@ [workspace] members = [ "ci-shared", - "ci-crates", + "crates-reporter", "clippy-annotation-reporter", ] resolver = "2" diff --git a/.github/actions/ci-crates/src/lib.rs b/.github/actions/ci-crates/src/lib.rs deleted file mode 100644 index a85f13e761..0000000000 --- a/.github/actions/ci-crates/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/ -// SPDX-License-Identifier: Apache-2.0 - -pub mod git; -pub mod workspace; diff --git a/.github/actions/ci-shared/Cargo.toml b/.github/actions/ci-shared/Cargo.toml index 265f227d28..f7ec22b9fb 100644 --- a/.github/actions/ci-shared/Cargo.toml +++ b/.github/actions/ci-shared/Cargo.toml @@ -10,6 +10,7 @@ publish = false [dependencies] anyhow = "1.0" +cargo_metadata = "0.23.1" log = "0.4" toml = "0.8" serde = { version = "1", features = ["derive"] } diff --git a/.github/actions/ci-crates/src/git.rs b/.github/actions/ci-shared/src/git.rs similarity index 80% rename from .github/actions/ci-crates/src/git.rs rename to .github/actions/ci-shared/src/git.rs index 2642dcc416..1732468b6a 100644 --- a/.github/actions/ci-crates/src/git.rs +++ b/.github/actions/ci-shared/src/git.rs @@ -4,7 +4,6 @@ use anyhow::{bail, Context, Result}; use std::process::Command; -/// Run `git fetch --depth=1 origin ` to ensure the base ref is available locally. pub fn fetch_base(base_ref: &str) -> Result<()> { log::info!("Fetching base branch: {base_ref}"); @@ -18,16 +17,12 @@ pub fn fetch_base(base_ref: &str) -> Result<()> { .context("Failed to run git fetch")?; if !status.success() { - // Non-fatal: warn but do not abort (mirrors `|| true` in the bash version) log::warn!("git fetch for {base_ref} returned non-zero exit code; continuing"); } Ok(()) } -/// Return the list of files changed between `origin/...HEAD` (three-dot diff). -/// -/// Uses `git diff --name-only origin/...HEAD`. pub fn changed_files(base_ref: &str) -> Result> { let output = Command::new("git") .args(["diff", "--name-only", &format!("origin/{base_ref}...HEAD")]) diff --git a/.github/actions/ci-shared/src/lib.rs b/.github/actions/ci-shared/src/lib.rs index ac3c51bfb1..b9d6fc68c2 100644 --- a/.github/actions/ci-shared/src/lib.rs +++ b/.github/actions/ci-shared/src/lib.rs @@ -3,3 +3,5 @@ pub mod crate_detection; pub mod github_output; +pub mod git; +pub mod workspace; diff --git a/.github/actions/ci-crates/src/workspace.rs b/.github/actions/ci-shared/src/workspace.rs similarity index 97% rename from .github/actions/ci-crates/src/workspace.rs rename to .github/actions/ci-shared/src/workspace.rs index f11a386ec3..67dda95990 100644 --- a/.github/actions/ci-crates/src/workspace.rs +++ b/.github/actions/ci-shared/src/workspace.rs @@ -9,7 +9,6 @@ use std::collections::{HashMap, HashSet, VecDeque}; /// Parsed workspace metadata with reverse-dependency index. pub struct WorkspaceMetadata { packages: Vec, - /// Maps each crate name to the list of workspace crates that depend on it. reverse_deps: HashMap>, workspace_root: Utf8PathBuf, } @@ -105,8 +104,6 @@ mod tests { s.iter().map(|s| s.to_string()).collect() } - // --- affected_from --- - #[test] fn affected_from_empty_seeds_returns_empty() { let meta = make_meta(&[]); @@ -171,8 +168,6 @@ mod tests { ); } - // --- load() integration --- - #[test] fn load_returns_non_empty_workspace() { let meta = load().expect("load() should succeed against the real workspace"); diff --git a/.github/actions/clippy-annotation-reporter/src/commenter.rs b/.github/actions/clippy-annotation-reporter/src/commenter.rs index 536f229f98..abb271b703 100644 --- a/.github/actions/clippy-annotation-reporter/src/commenter.rs +++ b/.github/actions/clippy-annotation-reporter/src/commenter.rs @@ -7,7 +7,7 @@ //! including finding existing comments and updating or creating comments. use anyhow::{Context as _, Result}; -use log::{error, info}; +use log::info; use octocrab::Octocrab; /// Post or update a comment on a PR with the given report diff --git a/.github/actions/ci-crates/Cargo.toml b/.github/actions/crates-reporter/Cargo.toml similarity index 59% rename from .github/actions/ci-crates/Cargo.toml rename to .github/actions/crates-reporter/Cargo.toml index f188a22ef2..f3d16c2a01 100644 --- a/.github/actions/ci-crates/Cargo.toml +++ b/.github/actions/crates-reporter/Cargo.toml @@ -2,16 +2,15 @@ # SPDX-License-Identifier: Apache-2.0 [package] -name = "ci-crates" +name = "crates-reporter" version = "0.1.0" edition = "2021" rust-version = "1.84.1" +description = "GitHub Action for reporting modified crates and transitive dependencies" +homepage = "https://github.com/DataDog/libdatadog/tree/main/.github/actions/changed-crates" +repository = "https://github.com/DataDog/libdatadog/tree/main/.github/actions/changed-crates" publish = false -[[bin]] -name = "changed-crates" -path = "src/bin/changed_crates.rs" - [dependencies] ci-shared = { path = "../ci-shared" } anyhow = "1.0" diff --git a/.github/actions/changed-crates/action.yml b/.github/actions/crates-reporter/action.yml similarity index 95% rename from .github/actions/changed-crates/action.yml rename to .github/actions/crates-reporter/action.yml index 02436b269e..d914b5ee3c 100644 --- a/.github/actions/changed-crates/action.yml +++ b/.github/actions/crates-reporter/action.yml @@ -45,7 +45,7 @@ runs: shell: bash run: | cd ${{ github.action_path }}/.. - cargo build --release -p ci-crates + cargo build --release -p crates-reporter - name: Run change reporter id: detect @@ -58,7 +58,7 @@ runs: echo "status=skipped" >> $GITHUB_OUTPUT exit 0 fi - if RUST_LOG=debug ${{ github.action_path }}/../target/release/changed-crates $PR_BASE_REF; then + if RUST_LOG=debug ${{ github.action_path }}/../target/release/crates-reporter $PR_BASE_REF; then echo "status=success" >> $GITHUB_OUTPUT else echo "status=skipped" >> $GITHUB_OUTPUT diff --git a/.github/actions/ci-crates/src/bin/changed_crates.rs b/.github/actions/crates-reporter/src/main.rs similarity index 94% rename from .github/actions/ci-crates/src/bin/changed_crates.rs rename to .github/actions/crates-reporter/src/main.rs index 3fc317307f..711f3474e1 100644 --- a/.github/actions/ci-crates/src/bin/changed_crates.rs +++ b/.github/actions/crates-reporter/src/main.rs @@ -14,15 +14,14 @@ use anyhow::{anyhow, Result}; use cargo_metadata::camino::Utf8Path; use cargo_metadata::Package; -use ci_crates::git; -use ci_crates::workspace; +use ci_shared::git; +use ci_shared::workspace; use ci_shared::crate_detection::CrateInfo; use ci_shared::github_output::set_output; use std::collections::HashSet; fn main() -> Result<()> { env_logger::init(); - // Parse args let args: Vec = std::env::args().collect(); if args.len() < 2 { return Err(anyhow!("A reference base needs to be passed")); @@ -35,13 +34,6 @@ fn main() -> Result<()> { let changed_files = git::changed_files(&base_ref)?; log::info!("Changed files: {:?}", changed_files); - // TODO: Check heuristics when workspace manifest (Cargo.toml) or config.toml changed. This could indicate a - // change in: - // * Rust version. - // * Edition. - // * Profile. - // * Compilation flags. - let workspace = workspace::load()?; let changed_crates = collect_changed_crates(&changed_files, workspace.members(), workspace.workspace_root()); diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index f9375476f5..63c6b664dd 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -1,13 +1,62 @@ name: Coverage on: - pull_request: push: branches: + # Allowing to generate coverage when pushes are made to main in order to generate all independent crate reports + # so we can establish a proper baseline without manual intervention or a manual workflow dispatch. - main + pull_request: + types: ['opened', 'edited', 'reopened', 'synchronize'] + branches-ignore: + - "v[0-9]+.[0-9]+.[0-9]+.[0-9]+" + - release jobs: + setup: + runs-on: ubuntu-latest + outputs: + packages: ${{ steps.set-packages.outputs.packages }} + packages-count: ${{ steps.set-packages.outputs.packages-count }} + crates-json: ${{ steps.set-packages.outputs.crates-json }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2 + with: + fetch-depth: 0 + - name: Get changed crates + if: ${{ github.event_name == 'pull_request' }} + id: changed-crates + uses: ./.github/actions/changed-crates + - name: Set packages to get coverage + id: set-packages + env: + CHANGED_CRATES_COUNT: ${{ steps.changed-crates.outputs.crates_count }} + AFFECTED_CRATES: ${{ steps.changed-crates.outputs.affected_crates }} + run: | + if [[ "${{ github.event_name }}" == "push" ]]; then + COUNT="1" + PACKAGES="" + CRATES_JSON="" + elif [[ "$CHANGED_CRATES_COUNT" == "0" ]]; then + COUNT="0" + PACKAGES="" + CRATES_JSON="" + else + COUNT=$(echo "$AFFECTED_CRATES" | jq 'length') + PACKAGES=$(echo "$AFFECTED_CRATES" | jq -r 'map("-p " + .) | join(" ")') + CRATES_JSON="$AFFECTED_CRATES" + fi + echo "packages-count=$COUNT" >> $GITHUB_OUTPUT + echo "packages=$PACKAGES" >> $GITHUB_OUTPUT + { + echo "crates-json<> $GITHUB_OUTPUT + coverage: + needs: setup + if: needs.setup.outputs.packages-count != '0' runs-on: labels: ubuntu-latest-16-cores group: APM Larger Runners @@ -40,13 +89,54 @@ jobs: cache-targets: true # cache build artifacts cache-bin: true # cache the ~/.cargo/bin directory - name: Generate code coverage (including doc tests) + env: + PACKAGES: ${{ needs.setup.outputs.packages }} + CRATES_JSON: ${{ needs.setup.outputs.crates-json }} run: | - cargo llvm-cov --all-features --workspace --no-report nextest - cargo llvm-cov --all-features --workspace --no-report --doc - cargo llvm-cov report --doctests --lcov --output-path lcov.info + if [[ -z "$PACKAGES" ]]; then + cargo llvm-cov --all-features --workspace --no-report nextest + cargo llvm-cov --all-features --workspace --no-report --doc + CRATES_JSON=$(cargo metadata --no-deps --format-version 1 | jq '[.packages[].name]') + else + # shellcheck disable=SC2086 - word splitting on $PACKAGES is intentional + cargo llvm-cov --all-features --no-report nextest $PACKAGES + # shellcheck disable=SC2086 + cargo llvm-cov --all-features --no-report --doc $PACKAGES + fi + for crate in $(echo "$CRATES_JSON" | jq -r '.[]'); do + if ! cargo llvm-cov report --doctests --lcov \ + --output-path "lcov-${crate}.info" \ + --package "${crate}"; then + if [[ -s "lcov-${crate}.info" ]]; then + echo "::error::Coverage report generation failed for ${crate}" + exit 1 + else + echo "No coverage data for ${crate}, skipping" + fi + fi + done + { + echo "CRATES_JSON_COMPUTED<> "$GITHUB_ENV" + - name: Install Codecov CLI + run: | + curl -Os https://cli.codecov.io/v10.4.0/linux/codecov + curl -Os https://cli.codecov.io/v10.4.0/linux/codecov.SHA256SUM + echo "0f7aadde579ebde1443ad2f977beada703f562997fdda603f213faf2a8559868 codecov" | shasum -a 256 -c + chmod +x codecov + sudo mv codecov /usr/local/bin/codecov - name: Upload coverage to Codecov - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # 5.5.1 - with: - token: ${{ secrets.CODECOV_TOKEN }} - files: lcov.info - fail_ci_if_error: true + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + run: | + for crate in $(echo "$CRATES_JSON_COMPUTED" | jq -r '.[]'); do + if [[ -s "lcov-${crate}.info" ]]; then + codecov upload-process \ + --token "$CODECOV_TOKEN" \ + --file "lcov-${crate}.info" \ + --flag "${crate}" \ + --fail-on-error + fi + done