diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml new file mode 100644 index 00000000..5f492e8f --- /dev/null +++ b/.github/workflows/coverage.yaml @@ -0,0 +1,71 @@ +name: Code Coverage + +on: + workflow_call: + inputs: + web-prover-circuits-cache-key: + required: true + type: string + outputs: + coverage-report: + description: "Path to the coverage report" + value: ${{ jobs.coverage.outputs.coverage-report }} + +jobs: + coverage: + name: Generate code coverage + runs-on: ubuntu-latest + permissions: + contents: read + checks: write + pull-requests: write # Needed for coverage comments + outputs: + coverage-report: ${{ steps.upload-coverage.outputs.artifact-url }} + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 2 # Needed for coverage comparison in PRs + + - uses: ./.github/actions/setup-rust-ubuntu + with: + rust-cache-key: coverage + + - name: Install tarpaulin + run: cargo install cargo-tarpaulin --version "^0.27" # Pin version for stability + + - name: Run tarpaulin + id: run-tarpaulin + run: | + cargo tarpaulin --workspace \ + --exclude client_wasm \ + --timeout 360 \ + --out Xml \ + --out Html \ + --output-dir coverage \ + --exclude-files 'tests/*' \ + --fail-under 70 # Fail if coverage drops below 70% + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./coverage/cobertura.xml + fail_ci_if_error: true # Fail if upload fails + verbose: true # Better debugging + + - name: Upload coverage report + id: upload-coverage + uses: actions/upload-artifact@v4 + with: + name: coverage-report + path: coverage/ + retention-days: 7 + if-no-files-found: error # Fail if no coverage files generated + + - name: Check coverage report exists + run: | + if [ ! -f coverage/tarpaulin-report.html ]; then + echo "Coverage report not generated" + exit 1 + fi diff --git a/.github/workflows/web-prover.yaml b/.github/workflows/web-prover.yaml index 800afc87..50494cee 100644 --- a/.github/workflows/web-prover.yaml +++ b/.github/workflows/web-prover.yaml @@ -15,6 +15,13 @@ jobs: check: uses: ./.github/workflows/check.yaml + coverage: + needs: ["check"] + uses: ./.github/workflows/coverage.yaml + with: + web-prover-circuits-cache-key: ${{ needs.web-prover-circuits.outputs.cache-key }} + secrets: inherit + build_notary: uses: ./.github/workflows/build_notary.yaml diff --git a/.gitignore b/.gitignore index 2cecc59d..2553f152 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,9 @@ book/**/*.html rustls_acme_cache # rust tools -bacon.toml \ No newline at end of file +bacon.toml + +# coverage reports +coverage/ +cobertura.xml +tarpaulin-report.html \ No newline at end of file diff --git a/README.md b/README.md index f1d6a003..3b949c83 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ # Web Prover [![web-prover workflow](https://github.com/pluto/web-prover/actions/workflows/web-prover.yaml/badge.svg)](https://github.com/pluto/web-prover/actions/workflows/web-prover.yaml) +[![codecov](https://codecov.io/gh/pluto/web-prover/branch/main/graph/badge.svg)](https://codecov.io/gh/pluto/web-prover) [![docs](https://img.shields.io/badge/docs-e28f00)](https://docs.pluto.xyz) The Web Prover is infrastructure for generating Web Proofs with [Trusted Execution Environments (TEEs)](https://pluto.xyz/blog/web-proof-techniques-tee-mode). diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..bade78af --- /dev/null +++ b/codecov.yml @@ -0,0 +1,45 @@ +codecov: + require_ci_to_pass: true + notify: + wait_for_ci: true + +coverage: + precision: 2 + round: down + range: "70...100" + status: + project: + default: + target: auto + threshold: 1% + base: auto + if_ci_failed: error + informational: false + only_pulls: false + patch: + default: + target: auto + threshold: 1% + base: auto + if_ci_failed: error + only_pulls: true + +parsers: + gcov: + branch_detection: + conditional: true + loop: true + method: false + macro: false + +comment: + layout: "reach,diff,flags,files,footer" + behavior: default + require_changes: false + require_base: false + require_head: true + +ignore: + - "**/*.md" + - "**/*.yml" + - "**/*.yaml" \ No newline at end of file diff --git a/core/src/http.rs b/core/src/http.rs index 7fa42f6c..8a51feac 100644 --- a/core/src/http.rs +++ b/core/src/http.rs @@ -696,7 +696,7 @@ pub mod tests { use serde_json::json; use super::*; - use crate::http::{ManifestRequest, ManifestResponse}; + use crate::http::{ManifestRequest}; /// Creates a new HTTP request with optional parameters. #[macro_export] @@ -705,7 +705,7 @@ pub mod tests { ($($key:ident: $value:expr),* $(,)?) => {{ // Make clippy happy #[allow(unused_mut) ] - let mut request = ManifestRequest { + let mut request = crate::http::ManifestRequest { method: "GET".to_string(), url: "https://example.com".to_string(), version: "HTTP/1.1".to_string(), @@ -739,18 +739,18 @@ pub mod tests { // Match with optional parameters ($($key:ident: $value:expr),* $(,)?) => {{ #[allow(unused_mut)] - let mut response = ManifestResponse { + let mut response = crate::http::ManifestResponse { status: "200".to_string(), version: "HTTP/1.1".to_string(), message: "OK".to_string(), headers: std::collections::HashMap::from([ ("Content-Type".to_string(), "application/json".to_string()) ]), - body: ManifestResponseBody { + body: crate::http::ManifestResponseBody { json_path: vec![ - JsonKey::String("key1".to_string()), - JsonKey::String("key2".to_string()), - JsonKey::Num(3) + crate::http::JsonKey::String("key1".to_string()), + crate::http::JsonKey::String("key2".to_string()), + crate::http::JsonKey::Num(3) ] }, }; diff --git a/core/src/manifest.rs b/core/src/manifest.rs index 5ca2e821..36aceda9 100644 --- a/core/src/manifest.rs +++ b/core/src/manifest.rs @@ -79,7 +79,7 @@ mod tests { use crate::{ error::WebProverCoreError, http::{ - JsonKey, ManifestRequest, ManifestResponse, ManifestResponseBody, TemplateVar, HTTP_1_1, + TemplateVar, HTTP_1_1, }, manifest::Manifest, request, response, @@ -92,7 +92,7 @@ mod tests { $response:expr $(, $field:ident = $value:expr)* $(,)? ) => {{ - Manifest { + crate::manifest::Manifest { // manifest_version: "1".to_string(), // id: "Default Manifest ID".to_string(), // title: "Default Manifest Title".to_string(),