Skip to content

ci: add CodeCov integration for code coverage reporting - #20

Closed
steingran wants to merge 32 commits into
mainfrom
add-codecov-reporting
Closed

ci: add CodeCov integration for code coverage reporting#20
steingran wants to merge 32 commits into
mainfrom
add-codecov-reporting

Conversation

@steingran

Copy link
Copy Markdown
Owner

Description

Add CodeCov integration for code coverage reporting to this repo

Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • 🚀 New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🧪 Test improvements
  • ⚡ Performance improvement
  • ♻️ Code refactoring
  • 🔧 Maintenance/chore

Related Issue

Changes Made

  • Add code coverage collection to build-and-test workflow
  • Add code coverage collection to publish-nuget workflow
  • Upload coverage reports to CodeCov in both workflows
  • Create codecov.yml to configure coverage targets and exclusions
  • Add CodeCov badge to README.md

Coverage is collected using coverlet's XPlat Code Coverage and uploaded to CodeCov for tracking and PR comments. Test and sample projects are excluded from coverage calculations.

Testing

  • Unit tests pass locally
  • Integration tests pass locally
  • Added new tests for new functionality
  • All existing tests still pass

Checklist

  • My code follows the code style of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published

Labels

Additional Notes

steingran and others added 30 commits November 1, 2025 12:51
Adding impelmentation of leader election for Azure Blob Storage, Consul, FileSystem, InMemory, PostgreSQL, Redis, SqlServer and ZooKeeper. Adding tests. Adding Github Action for build and running tests. Adding MinVer versioning. Adding .eidtorconfig file, .gitattributes and .gitignore.

Fixes #1
…s workflow

Replace docker-compose with docker compose in Github Actions workflow since Github Action runners no longer have the docker-compose command installed by default.

Fixes #1
Adding health checks in docker-compose.yml file, renaming container names, added timeouts for running tests in the Github Action workflow

Fixes #1
Ensure the directorypath exists in the tests, and create it if it does not exist

Fixes #1
Resolving possible race condition in the FileSystem provider, consecutive await using statements could cause disposal problems and could cause hangs

Fixes #1
…topAsync is called before disposal

IHost instance is not being properly disposed when StopAsync is called before disposal, leaving background services running and causing tests to hang. Changed the entire approach in the IsZooKeeperAvailableAsync() method to create an instance of the ZooKeeperLeaderElectionProvider class and calling the health check method to check whether ZooKeeper is available.

Fixes #1
…ed when StopAsync is called before disposal

Similar to the issue for ZooKeeper. IHost instance is not being properly disposed when StopAsync is called before disposal, leaving background services running and causing tests to hang. Changed the entire approach in the IsPostgreSqlAvailableAsync() and IsSqlServerAvailableAsync() methods to create an instance of the LeaderElextion provider classes and calling the health check method to check whether PostgreSQL and SqlServer are available.

Fixes #1
…nto the tests

Changed a GetAwaiter().GetResult() call that had snuck into the tests, and created a version of the WaitForConditionAsync method which takes a Func<Task<bool>> instead of just Func<bool> to properly handle async conditions without blocking. Removed properties not used in Is*AvailableAsync() methods

Fixes #1
Correct Github Action workflow permissions:
- added contents:read for the workflow to read repository contents
- added checks:write for the workflow to create check runs (required by dorny/test-reporter)
- added pull-requests:write for the workflow to comment on pull requests with test results

Fixes #1
Collections were still being modified by background tasks(s) when test assertions were enumerating the collection, causing trouble. A total of four tests were fixed.

Fixes #3
…fied

Even after awaiting eventTask the collection could still be modified, correcting this by taking a thread-safe snapshot of the collection before making assertions

Fixes #3
Apply thread-safe snapshot pattern to all tests that access the shared events collection to prevent "Collection was modified; enumeration operation may not execute" errors in Github Actions.

Changes:
- Take array snapshot of events collection while holding lock before making assertions in 6 tests: Where_ShouldFilterEvents, Take_ShouldLimitNumberOfEvents, Skip_ShouldSkipEvents, DistinctUntilChanged_ShouldFilterConsecutiveDuplicates,  Throttle_ShouldLimitEventRate, and Debounce_ShouldDelayEvents
- Reorder cleanup and assertions to ensure background tasks complete before accessing the collection
- Use .Length property instead of .Count for array assertions
- Add explanatory comments for exception handling during cleanup

This ensures complete thread-safety by creating immutable snapshots of the collection while holding the lock, eliminating any possibility of race conditions during enumeration. All 16 tests now pass reliably in both local and GitHub Actions environments.

Fixes #3
Implemented IAsyncDisposable to prevent ObjectDisposedException when timer callbacks execute during disposal. Added active callback tracking with atomic operations and wait mechanism to ensure safe shutdown.

Includes 8 new tests covering concurrent disposal scenarios.
Add centralized parameter validation to prevent invalid inputs across all provider implementations and service extensions.

Changes:
- Created ParameterValidation helper class with validation methods for election groups, participant IDs, metadata, and lock timeouts
- Added validation to all 8 provider implementations (PostgreSQL, SQL Server, Redis, FileSystem, InMemory, Consul, ZooKeeper, Azure Blob Storage)
- Added null checks to LeaderElectionServiceExtensions methods
- Updated ILeaderElectionProvider XML documentation with validation requirements and exception details
- Added 108 comprehensive validation tests covering all scenarios

Validation enforces:
- Non-null, non-empty, non-whitespace identifiers
- Alphanumeric characters, underscores, hyphens, and periods only
- Maximum length limits (255 chars for identifiers, 4000 for metadata values)
- Positive lock timeouts not exceeding 1 day
- Metadata entry limits (max 100 entries)
Improve disposal patterns across all provider implementations to ensure consistent, safe, and non-blocking resource cleanup.

Changes:
- Implemented IAsyncDisposable for Consul and ZooKeeper providers to properly handle async cleanup operations without blocking threads
- Standardized disposal pattern across all 8 providers to use early return pattern for consistency
- Added 11 comprehensive disposal tests covering basic disposal, double disposal safety, and ObjectDisposedException after disposal
- Added detailed XML documentation for DisposeAsync() and Dispose() methods in providers with async cleanup

Providers modified:
- ConsulLeaderElectionProvider: Added IAsyncDisposable, replaced blocking .Wait() with proper async disposal of Consul sessions
- ZooKeeperLeaderElectionProvider: Added IAsyncDisposable, replaced blocking .Wait() with proper async disposal of ZooKeeper connection
- SqlServerLeaderElectionProvider: Standardized disposal pattern
- RedisLeaderElectionProvider: Standardized disposal pattern

Test coverage:
- All providers now have disposal tests ensuring idempotent disposal
- All providers verify methods throw ObjectDisposedException after disposal
- Async-disposable providers have dedicated DisposeAsync() tests
- Total: 217 tests
…y descriptions

Add comprehensive concurrent scenario tests validating thread-safety and
race condition handling across multiple participants.

- Add ConcurrentScenarioTests.cs with tests for:
  - Multiple participants competing for leadership
  - Rapid acquire/release cycles
  - Concurrent heartbeat updates
  - Leader failover scenarios

- Update README.md:
  - Rename all "LeaderElection.Net" references to "MultiLock"
  - Add "Concurrency and Thread-Safety" documentation section
  - Update package names, namespaces, and project paths

- Enhance disposal patterns in provider tests
…Drafter

Implement comprehensive CI/CD infrastructure for automated NuGet package publishing and release management to prepare MultiLock for production deployment.

### NuGet Publishing Workflow
- Add automated NuGet publishing workflow with manual and tag-based triggers
- Configure package validation using dotnet-validate tool
- Implement selective publishing to exclude core MultiLock package (embedded in providers)
- Add dry-run mode for testing without actual publication
- Include symbol package (.snupkg) publishing for debugging support
- Integrate with Release Drafter for automatic changelog updates

### Package Configuration & Standardization
- Centralize package metadata in Directory.Build.props
- Implement MinVer for semantic versioning from Git tags (v-prefix, 1.0 minimum)
- Enable SourceLink for source code debugging support
- Configure deterministic builds for reproducibility
- Add XML documentation generation for all packages
- Standardize package metadata (authors, license, repository, tags)
- Optimize package logo to NuGet standards (128x128px, 27.65 KB)

### Release Automation
- Add Release Drafter for PR-based automatic changelog generation
- Configure 9 changelog categories (Breaking Changes, Features, Bug Fixes, etc.)
- Implement auto-labeling based on files, branches, and PR titles
- Create comprehensive label definitions (215 labels across all categories)
- Add PR template to guide contributors on proper labeling

### Project Structure Improvements
- Clean up all .csproj files by removing redundant properties
- Standardize provider package configuration across all 8 providers
- Update .gitignore to exclude build artifacts and temporary files

### Documentation
- Add comprehensive Release Drafter usage guide
- Document GitHub Actions workflows and their purposes
- Create label setup automation script

This implementation provides a production-ready CI/CD pipeline that ensures consistent versioning, automated changelog generation, and reliable package publishing to NuGet.org for all 8 MultiLock provider packages.
Adding CONTRIBUTING.ms and CODE_OF_CONDUCT.md file, correcting minor issue in the setup-labels.ps1 powershell file
Fixes validation error when updating draft releases. The pull_request_target event provides valid commit references instead of PR merge refs.
Correcting minor language issue in the CODE_OF_CONDUCT.md file, and correcting sample code in the CONTRIBUTING.md file
Setting up Dependabot for version updates
…oft.Extensions.Logging.Abstractions

Bumps Microsoft.Extensions.DependencyInjection.Abstractions from 8.0.0 to 9.0.10
Bumps Microsoft.Extensions.Logging.Abstractions from 8.0.0 to 9.0.10

---
updated-dependencies:
- dependency-name: Microsoft.Extensions.DependencyInjection.Abstractions
  dependency-version: 9.0.10
  dependency-type: direct:production
  update-type: version-update:semver-major
- dependency-name: Microsoft.Extensions.Logging.Abstractions
  dependency-version: 9.0.10
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
steingran and others added 2 commits November 9, 2025 21:19
Refactor the multi-provider demo sample to align with the MultiLock naming convention:

- Rename project from LeaderElection.MultiProvider to MultiLock.MultiProvider
- Extract DemoBackgroundService into separate file
- Update project references to use MultiLock namespace (MultiLock.csproj, MultiLock.InMemory, MultiLock.FileSystem)
- Update using statements to match new namespace structure
- Update console output and temp path to use MultiLock branding
- Add project to solution file
- Apply modern C# syntax improvements (var to explicit types, simplified method calls)
- Add code coverage collection to build-and-test workflow
- Add code coverage collection to publish-nuget workflow
- Upload coverage reports to CodeCov in both workflows
- Create codecov.yml to configure coverage targets and exclusions
- Add CodeCov badge to README.md

Coverage is collected using coverlet's XPlat Code Coverage and
uploaded to CodeCov for tracking and PR comments. Test and sample
projects are excluded from coverage calculations.
Copilot AI review requested due to automatic review settings November 9, 2025 20:53
@steingran steingran added the maintenance Repository maintenance label Nov 9, 2025
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Nov 9, 2025

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR integrates CodeCov for code coverage reporting into the MultiLock project. It adds configuration for coverage tracking, updates CI workflows to collect and upload coverage data, and adds a coverage badge to the README.

  • Adds codecov.yml configuration file with coverage thresholds and ignore patterns
  • Updates both CI workflows (build-and-test.yml and publish-nuget.yml) to collect code coverage using XPlat Code Coverage and upload results to CodeCov
  • Adds CodeCov badge to README.md

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
codecov.yml Configuration file defining coverage requirements, ignore patterns, and reporting behavior
README.md Adds CodeCov badge linking to coverage reports
.github/workflows/build-and-test.yml Adds code coverage collection and CodeCov upload step
.github/workflows/publish-nuget.yml Adds code coverage collection and CodeCov upload step

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

with:
files: '**/coverage.cobertura.xml'
fail_ci_if_error: false
verbose: true

Copilot AI Nov 9, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The codecov-action@v4 requires a token for authentication. Add the 'token' parameter with a reference to a CODECOV_TOKEN secret: token: ${{ secrets.CODECOV_TOKEN }}. Without this token, uploads may fail or have limited functionality.

Suggested change
verbose: true
verbose: true
token: ${{ secrets.CODECOV_TOKEN }}

Copilot uses AI. Check for mistakes.
with:
files: '**/coverage.cobertura.xml'
fail_ci_if_error: false
verbose: true

Copilot AI Nov 9, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The codecov-action@v4 requires a token for authentication. Add the 'token' parameter with a reference to a CODECOV_TOKEN secret: token: ${{ secrets.CODECOV_TOKEN }}. Without this token, uploads may fail or have limited functionality.

Suggested change
verbose: true
verbose: true
token: ${{ secrets.CODECOV_TOKEN }}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation maintenance Repository maintenance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants