Closed
Conversation
…gets - Add JaCoCo plugin to root and all submodules - Configure coverage report generation (XML, HTML, CSV) - Set module-specific coverage targets without enforcing build failure * profanity-api: 70% line, 65% branch, 70% instruction * profanity-domain: 80% line, 75% branch, 80% instruction * profanity-shared: 60% line, 55% branch, 60% instruction * profanity-storage:rdb: 70% line, 65% branch, 70% instruction * profanity-storage:redis: 70% line, 65% branch, 70% instruction * Overall project: 75% line, 70% branch, 75% instruction - Add checkCoverageTargets task for each module to display target achievement - Add jacocoRootReport task for unified multi-module coverage report - Add checkOverallCoverageTarget task for overall project coverage check - Update GitHub Actions workflow to generate coverage reports and add PR comments - Add coverage badge generation for main branch - Update CLAUDE.md with coverage commands and targets - Add coverage badges to README.md The coverage targets are informational only and do not fail the build, allowing gradual improvement while tracking progress toward goals.
- Create dedicated coverage.yml workflow for code coverage reporting - Remove coverage steps from build_and_health_check.yml to keep it focused on testing - Update README.md badge links to point to the new coverage workflow Benefits: - Cleaner separation of concerns (testing vs coverage reporting) - Coverage workflow can be run independently - Faster test workflow execution - Better maintainability and reusability Coverage workflow includes: - JaCoCo report generation with module-specific and overall targets - PR comments with coverage changes (madrapps/jacoco-report) - Coverage badge generation for main branch (cicirello/jacoco-badge-generator) - Artifact upload for coverage reports
Contributor
There was a problem hiding this comment.
Pull Request Overview
This PR adds comprehensive code coverage measurement to the project using JaCoCo, with module-specific coverage targets and GitHub Actions integration for automated reporting and badge generation. The coverage targets are informational and don't enforce build failures, allowing gradual improvement while tracking progress.
Key Changes
- Configured JaCoCo plugin (v0.8.11) across all modules with XML, HTML, and CSV report generation
- Implemented module-specific coverage targets (60-80% depending on module) with custom tasks to display achievement status
- Integrated coverage reporting into CI/CD pipeline with PR comments and badge generation for the main branch
Reviewed Changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| build.gradle | Added JaCoCo plugin configuration, coverage report tasks, module-specific targets, and unified reporting functionality |
| .github/workflows/build_and_health_check.yml | Added coverage report generation, PR comment action, and automated badge updates |
| README.md | Added coverage and branch badges linking to workflow results |
| CLAUDE.md | Documented coverage commands, report locations, and target specifications |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Change afterEvaluate to doFirst in jacocoTestReport for subprojects - Change afterEvaluate to doFirst in jacocoRootReport task - This fixes the Gradle configuration error where afterEvaluate cannot be executed in the current context within tasks.register The doFirst approach achieves the same result by applying filters just before task execution, which is compatible with tasks.register lazy configuration. Resolves the build failure: "Project#afterEvaluate(Closure) on root project cannot be executed in the current context"
Root Causes Identified: 1. tasks.register() cannot use afterEvaluate internally (Gradle 8.x Configuration Avoidance API) 2. test.finalizedBy checkCoverageTargets was causing test failures 3. Missing error handling in coverage check tasks Changes Made: - Revert subprojects jacocoTestReport to use afterEvaluate (works for existing tasks) - Move jacocoRootReport configuration to project.afterEvaluate with tasks.named() - Remove test.finalizedBy checkCoverageTargets (run coverage checks separately) - Add try-catch error handling in checkCoverageTargets tasks - Add try-catch error handling in checkOverallCoverageTarget task This ensures: - Tests run successfully without coverage interference - Coverage reports are generated correctly - Build doesn't fail if coverage XML parsing fails - Gradle 8.8 Configuration Avoidance API is properly respected Reference: - Gradle docs: Configuration Avoidance API - Issue: Project#afterEvaluate cannot be executed in tasks.register context
Problem: - Gradle wrapper download failing with 503 Service Unavailable error - setup-java with cache: gradle only caches dependencies, not wrapper - First-time builds fail when GitHub's Gradle distribution CDN has issues Solution: - Add gradle/actions/setup-gradle@v3 action to both workflows - This action provides: * Automatic Gradle wrapper caching and downloading * Build cache management * Better reliability with built-in retry logic * Faster subsequent builds Changed workflows: - .github/workflows/coverage.yml - .github/workflows/build_and_health_check.yml References: - https://github.com/gradle/actions/tree/main/setup-gradle - Gradle wrapper version: 8.8 (from gradle-wrapper.properties)
Problem: - 1Password service returning 502 Bad Gateway errors intermittently - Test and coverage workflows failing completely when 1Password unavailable - Tests don't actually require .env secrets to run (only health-check does) Solution: - Add continue-on-error: true to 1Password steps in test and coverage jobs - Create empty .env file as fallback when secrets unavailable - Tests use @WebMvcTest with mocked dependencies, don't need real DB/mail config Changes: 1. coverage.yml: - Make 1Password steps optional with continue-on-error - Create empty .env if secrets load fails - Tests can run without actual environment variables 2. build_and_health_check.yml (test job only): - Make 1Password steps optional for test job - health-check job still requires secrets (needs to run actual app) Benefits: - Tests run even when 1Password has temporary outages - Coverage reports generated regardless of secret service status - Health check properly validates with real environment (still requires secrets) - Reduces dependency on external service availability for CI This approach prioritizes test execution reliability while maintaining proper integration testing with real secrets in health-check job.
Problem:
Gradle 8.8 detected implicit dependencies without explicit declarations:
- Task ':jacocoRootReport' uses outputs from ':test' and various
':jacocoTestReport' tasks without declaring dependencies
- This violates Gradle's task dependency validation rules
Solution:
- Move dependsOn declarations into project.afterEvaluate block
- Add explicit dependencies on all subproject Test tasks
- Add explicit dependencies on all subproject jacocoTestReport tasks
- Use tasks.withType(Test) and tasks.named('jacocoTestReport')
for proper task collection
Changes:
```groovy
project.afterEvaluate {
tasks.named('jacocoRootReport').configure {
dependsOn subprojects.collect { it.tasks.withType(Test) }
dependsOn subprojects.collect { it.tasks.named('jacocoTestReport') }
...
}
}
```
This ensures proper task execution order and satisfies Gradle 8.8's
validation requirements for task output dependencies.
Reference: https://docs.gradle.org/8.8/userguide/validation_problems.html#implicit_dependency
…s.jacocoTestReport Problem: Previous approach using tasks.withType(Test) and tasks.named() was still missing the root project's :test task dependency, causing the same error. Solution: Use simpler and more direct approach: - dependsOn subprojects.test (all subproject test tasks) - dependsOn subprojects.jacocoTestReport (all subproject report tasks) This is more idiomatic Gradle code and ensures all necessary task dependencies are properly declared without needing collect() operations. Benefits: - Cleaner, more readable code - Gradle automatically resolves all subproject tasks - No missing dependencies - Works with Gradle 8.8's strict validation
Problem: - Using outdated @V3 version of setup-gradle action - Added unnecessary wrapper validation retry logic - 503 errors from services.gradle.org during wrapper download Solution: - Upgrade to official latest version @v5 - Remove custom retry logic (not needed with v5) - Use official recommended configuration from Gradle team Benefits of @v5: - Improved caching of wrapper distributions - Better stability and reliability - Official support and updates - Automatic wrapper distribution caching (default behavior) Reference: - https://github.com/gradle/actions/tree/main/setup-gradle - Official Gradle documentation for GitHub Actions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…gets
The coverage targets are informational only and do not fail the build, allowing gradual improvement while tracking progress toward goals.