Skip to main content

Configurable static quality and coverage gates for C#/.NET repositories.

Project description

.NET Quality Enforcer

CI License Latest release GitHub release downloads

Installable, configuration-driven quality gates for C# and .NET repositories.

This project is pre-1.0 and welcomes feedback from teams trying incremental quality enforcement in real repositories. The latest release is shown by the badge above.

What it does

.NET Quality Enforcer provides reusable checks for:

  • architectural dependency boundaries
  • code size and complexity
  • source and namespace layout
  • public API XML documentation
  • test architecture and naming conventions
  • Cobertura repository, diff, and branch coverage

The package owns the analysis engine and its tests. Consuming repositories own their policies, baselines, source layout, layer names, thresholds, and CI-specific paths.

The checks run against an explicit repository working directory. A policy file is optional for commands that provide defaults, but it is recommended for repeatable CI configuration.

Quality metrics and rules

The enforcer combines numeric maintainability metrics with structural quality rules. Thresholds below are built-in defaults and can be overridden in .quality/quality_policy.json.

Area What is measured or enforced Built-in default
Code size Physical lines in each method, type, and source file; partial types are also aggregated across files. Warn at 40/250/300 lines and fail at 60/350/450 lines for methods/types/files respectively.
Diff complexity Changed production methods are checked for cyclomatic complexity, cognitive complexity, and CRAP score. Cyclomatic <= 10, cognitive <= 10, CRAP <= 30.00. No file-count limit by default.
CRAP score Combines cyclomatic complexity with method coverage: complexity² × (1 - coverage)³ + complexity. Higher complexity and lower coverage produce a higher risk score. Maximum 30.00. Coverage comes from the supplied Cobertura report.
Diff coverage Executable changed-line coverage and, when configured, changed-branch coverage. Line coverage >= 80%; branch coverage is optional. No file-count limit by default.
Repository coverage Cobertura line coverage, plus optional branch coverage, for configured packages and classes. Line coverage defaults to 100% for configured expected packages; branch coverage is optional.
Structural rules Architectural dependency boundaries, namespace-to-path alignment, source type/file layout, public API XML summaries, test project placement, and source-to-test naming/target conventions. Repository policy defines the expected layers, roots, mappings, and exclusions.

The diff-complexity gate uses cyclomatic complexity to count independent decision paths, cognitive complexity to account for nesting and control-flow readability, and CRAP to combine complexity with test coverage. These metrics are evaluated against changed code so existing legacy complexity can be managed with baselines and incremental enforcement.

For example, the complexity and coverage limits can be configured as follows:

{
  "diff_quality": {
    "cyclomatic_complexity_max": 10,
    "cognitive_complexity_max": 10,
    "crap_score_max": 30,
    "line_coverage_threshold": 0.8,
    "branch_coverage_threshold": 0.8,
    "max_files_for_gate": 40
  }
}

Diff complexity and diff coverage analyze the full changed production set by default. Set max_files_for_gate to a positive integer only when a repository explicitly wants a maintenance cap; the setting applies to both diff gates.

Requirements

  • Python 3.10 or newer
  • A C#/.NET repository to analyze
  • .NET 8 SDK only when using the optional Roslyn parser
  • ReportGenerator only when using coverage-report

The package has no runtime Python dependencies outside the standard library.

GitHub Action

This repository can be used directly as a cross-platform composite action. Pin consumers to a release tag or, preferably, an immutable commit SHA:

steps:
  - uses: actions/checkout@v7
  - id: quality
    uses: KaramTNC/dotnet-quality-enforcer@v0
    with:
      command: code-size
      arguments: --scope full
      parser: auto

The v0 compatibility tag tracks the latest 0.x release. For production workflows, replace it with the release you have reviewed or an immutable commit SHA.

The action installs the package, runs the selected gate, and exposes result, status, returncode, violations, and warnings outputs. Set install-roslyn: true to install the .NET 8 SDK and build the bundled Roslyn helper before running a Roslyn-enabled gate. The coverage-report command still requires ReportGenerator to be available on the runner.

The action's result output uses the same schema_version: 1 JSON envelope as the command-line interface:

- name: Fail on quality violations
  if: steps.quality.outputs.status == 'failed'
  run: echo '${{ steps.quality.outputs.violations }}'

The release-download badge above counts downloads of GitHub Release assets. It does not count workflow executions that reference this repository with uses:. GitHub Actions usage is tracked separately through GitHub's Actions usage metrics; no telemetry is sent by this action.

Installation

The current public distributions are attached to GitHub Releases. Download the wheel that matches the release you want, or install from a source checkout:

git clone https://github.com/KaramTNC/dotnet-quality-enforcer.git
cd dotnet-quality-enforcer
python -m pip install .

The versioned release workflow also supports publishing the package to PyPI through trusted publishing. Once the repository's pypi environment is connected to a PyPI trusted publisher, install the CLI with:

python -m pip install dotnet-quality-gates

The one-time PyPI trusted-publisher configuration should use owner KaramTNC, repository dotnet-quality-enforcer, workflow package.yml, and environment pypi. The workflow uses short-lived OIDC credentials; no PyPI token is stored in the repository.

For local development, install the development tools as well:

python -m pip install -e ".[dev]"

For a copyable GitHub Actions workflow and starter policy, see examples/starter.

Usage

Run the top-level help to see every command and its options:

dotnet-quality --help

Commands can analyze the current directory or another repository with --repo-root:

dotnet-quality --repo-root path/to/repository code-size \
  --scope full \
  --policy-path .quality/quality_policy.json

dotnet-quality public-api-documentation \
  --policy-path .quality/quality_policy.json \
  --baseline-path .quality/baselines/public_api_documentation_baseline.txt

Available commands:

Command Purpose
architectural-boundaries Validate project and namespace dependency boundaries.
code-size Validate C# method, type, and file size.
diff-complexity Validate changed-method complexity and CRAP scores.
diff-coverage Validate changed-line and changed-branch coverage.
namespace-layout Validate source namespaces against their paths.
public-api-documentation Validate XML documentation for public C# APIs.
repo-coverage Validate Cobertura repository and package coverage.
source-type-layout Validate C# source type/file layout.
test-architecture Validate source and test project placement.
test-conventions Validate source-to-test naming and convention rules.
coverage-report Generate a ReportGenerator coverage report.

For automation, request a structured result envelope:

dotnet-quality --output json code-size --scope full

The JSON envelope has schema_version: 1, a status, returncode, violations, warnings, repository metadata, and the original stdout/stderr for compatibility.

Most commands use .quality/quality_policy.json by default when it exists. The top-level command validates known policy keys before starting a gate and reports the exact invalid key. Baseline files contain known violations that are intentionally accepted by the consuming repository; keep those files in the consuming repository rather than in this package.

The top-level options also support --timeout SECONDS for external tools and --parser auto|python|roslyn. The default auto mode uses Roslyn only when configured; python forces the dependency-free parser, and roslyn fails if the helper is unavailable or cannot analyze a file.

Optional Roslyn parsing

The built-in parser has no .NET runtime dependency. For modern C# syntax, build the optional Roslyn helper and set its command before running a gate:

dotnet build tools/roslyn-analyzer/DotnetQualityRoslyn.csproj -c Release
export DOTNET_QUALITY_ROSLYN_COMMAND="dotnet tools/roslyn-analyzer/bin/Release/net8.0/DotnetQualityRoslyn.dll"

When configured, source-type and unit-test convention analysis uses Roslyn. If the helper is unavailable or returns an error, the built-in parser is used instead.

Versioned releases also include a framework-dependent Roslyn helper archive. It still requires the .NET 8 runtime, but avoids rebuilding the helper locally. Release assets include SHA-256 checksums, an SBOM, build metadata, and GitHub artifact provenance.

Download tracking

The badge at the top of this page tracks downloads of the wheel and source-distribution assets attached to this repository's GitHub Releases. It does not include Git clones, source-archive downloads, or installations from other channels. See the release download statistics for the individual assets and releases.

Development and CI

Run the local checks with:

python -m unittest discover -s tests -p "test_*.py"
ruff check src tests action_runner.py
mypy src action_runner.py
pip-audit .

Pull requests targeting staging or main run the test suite on Python 3.10 through 3.13, plus static analysis and a Roslyn helper smoke test. Successful pushes to main build distributions and create a GitHub Release named main-<commit-sha>. Version tags matching vX.Y.Z create versioned releases and publish the Python package when PyPI trusted publishing is configured. The release workflow requires GitHub Actions permission to write repository contents.

The package version is derived from Git tags with setuptools-scm: a tag such as v0.2.0 produces version 0.2.0. Source checkouts without package metadata use 0.0.0+unknown.

Contributing

Please read CONTRIBUTING.md before opening a pull request. Issues and feature requests can be submitted through the GitHub issue tracker, and usage questions can be asked in Discussions.

Security issues should follow the process in SECURITY.md.

License

This project is available under the MIT License.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dotnet_quality_gates-0.2.2.tar.gz (74.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dotnet_quality_gates-0.2.2-py3-none-any.whl (65.4 kB view details)

Uploaded Python 3

File details

Details for the file dotnet_quality_gates-0.2.2.tar.gz.

File metadata

  • Download URL: dotnet_quality_gates-0.2.2.tar.gz
  • Upload date:
  • Size: 74.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dotnet_quality_gates-0.2.2.tar.gz
Algorithm Hash digest
SHA256 1544db674eacc6bf78ba75c613af9efa3999f342201f42ab878bc5228de0e247
MD5 990b71e52f28de5fe3aa7818a2d3463c
BLAKE2b-256 f9ab0f109c784cd8fcc2b11c7db34dd065c4d4e46194378f19760082ad40ae12

See more details on using hashes here.

Provenance

The following attestation bundles were made for dotnet_quality_gates-0.2.2.tar.gz:

Publisher: package.yml on KaramTNC/dotnet-quality-enforcer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dotnet_quality_gates-0.2.2-py3-none-any.whl.

File metadata

File hashes

Hashes for dotnet_quality_gates-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 961892091b4f81d26fb98f34123104bd2f24c8bd7b05a18b34325f3fe1af36ec
MD5 27c75beea34a0218eb2959758e8b4bf3
BLAKE2b-256 7a5d6c2483a6deff92d1329d00a5b676de7379ec65a900f5bd850f527438c527

See more details on using hashes here.

Provenance

The following attestation bundles were made for dotnet_quality_gates-0.2.2-py3-none-any.whl:

Publisher: package.yml on KaramTNC/dotnet-quality-enforcer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page