{"id":47976439,"url":"https://github.com/evansims/coverlint","last_synced_at":"2026-04-04T10:56:03.056Z","repository":{"id":343108779,"uuid":"1176308180","full_name":"evansims/coverlint","owner":"evansims","description":"Coverage checks for GitHub Actions — no external services, secrets, or accounts required. Supports Go, Rust, TypeScript, Python, PHP, Java, and more.","archived":false,"fork":false,"pushed_at":"2026-03-29T22:53:01.000Z","size":241,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-04T10:55:58.474Z","etag":null,"topics":["ci","cobertura","code-coverage","coverage-threshold","github-actions","jacoco","lcov","pull-requests"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/evansims.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-08T22:10:08.000Z","updated_at":"2026-03-16T03:19:57.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/evansims/coverlint","commit_stats":null,"previous_names":["evansims/coverage"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/evansims/coverlint","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evansims%2Fcoverlint","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evansims%2Fcoverlint/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evansims%2Fcoverlint/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evansims%2Fcoverlint/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evansims","download_url":"https://codeload.github.com/evansims/coverlint/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evansims%2Fcoverlint/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31397056,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ci","cobertura","code-coverage","coverage-threshold","github-actions","jacoco","lcov","pull-requests"],"created_at":"2026-04-04T10:56:00.802Z","updated_at":"2026-04-04T10:56:03.043Z","avatar_url":"https://github.com/evansims.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Coverlint\n\n![Coverage](https://raw.githubusercontent.com/evansims/coverlint/badges/coverage.svg)\n\nCoverage checks for GitHub Actions — no external services, no secrets, no accounts. Add one step to your workflow, set a threshold, and get pass/fail results with annotations and a job summary.\n\nCoverlint parses coverage reports in [all major formats](#supported-formats), enforces configurable thresholds, and runs entirely within your GitHub Actions runner. Supports Linux, macOS, and Windows.\n\n## Supported Formats\n\n- **LCOV** (`lcov`) — `cargo llvm-cov`, `c8`, `istanbul`, `jest`, `vitest`\n- **Go cover profile** (`gocover`) — `go test -coverprofile`\n- **Cobertura XML** (`cobertura`) — `pytest-cov`, `istanbul`, `cargo tarpaulin`\n- **Clover XML** (`clover`) — `phpunit`, some JS tools\n- **JaCoCo XML** (`jacoco`) — Gradle/Maven JaCoCo plugin\n\n## Usage\n\nAdd coverlint after your test step. Without any inputs, it auto-detects the format, finds your report, and shows coverage without enforcing a threshold — handy for tracking trends before you commit to a minimum:\n\n```yaml\n- uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n```\n\nTo enforce a minimum, set `min-coverage` — a combined score across line, branch, and function coverage (see [Custom Weights](#custom-weights) for how the score is computed):\n\n```yaml\n- uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n  with:\n    min-coverage: 80\n```\n\nSet `format` explicitly for faster runs and to avoid ambiguity when files share names (e.g. `coverage.xml` could be Cobertura or Clover):\n\n```yaml\n- uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n  with:\n    format: lcov\n    min-coverage: 80\n```\n\n## Quick Start by Language\n\n\u003cdetails\u003e\n\u003csummary\u003eGo\u003c/summary\u003e\n\n```yaml\n- run: go test -coverprofile=cover.out ./...\n\n- uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n  with:\n    format: gocover\n    min-coverage: 80\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eRust\u003c/summary\u003e\n\n```yaml\n- run: cargo llvm-cov --lcov --output-path lcov.info\n\n- uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n  with:\n    format: lcov\n    min-coverage: 80\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eTypeScript / JavaScript\u003c/summary\u003e\n\n```yaml\n- run: npx vitest run --coverage --coverage.reporter=lcov\n\n- uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n  with:\n    format: lcov\n    min-coverage: 80\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003ePython\u003c/summary\u003e\n\n```yaml\n- run: pytest --cov --cov-report=xml:coverage.xml\n\n- uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n  with:\n    format: cobertura\n    min-coverage: 80\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003ePHP\u003c/summary\u003e\n\n```yaml\n- run: vendor/bin/phpunit --coverage-clover=coverage.xml\n\n- uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n  with:\n    format: clover\n    min-coverage: 80\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eJava (Gradle)\u003c/summary\u003e\n\n```yaml\n- run: ./gradlew test jacocoTestReport\n\n- uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n  with:\n    format: jacoco\n    min-coverage: 80\n```\n\n\u003c/details\u003e\n\n## Thresholds\n\n### Coverage Score\n\nWhen you set `min-coverage`, coverlint computes a weighted score from line (50), branch (30), and function (20) coverage. If your format doesn't report a metric — like branch and function in `gocover` — its weight redistributes to the rest.\n\n### Custom Weights\n\nWeights are relative — adjust them to match what matters to your project:\n\n```yaml\n- uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n  with:\n    format: lcov\n    min-coverage: 80\n    weight-line: 100 # only line coverage counts toward the score\n    weight-branch: 0\n    weight-function: 0\n```\n\n### Per-Metric Floors\n\nSet `min-line`, `min-branch`, or `min-function` to require a minimum for a single metric, regardless of the overall score. Combine with `min-coverage` to enforce both:\n\n```yaml\n- uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n  with:\n    format: lcov\n    min-coverage: 80\n    min-branch: 60 # fails if branch drops below 60%, even if the overall score passes\n```\n\n\u003e [!NOTE]\n\u003e If you set a floor that your format doesn't support (e.g. `min-branch` with `gocover`), it's skipped with a warning annotation.\n\n### Per-Area Thresholds\n\nUse separate steps when parts of your project need different bars:\n\n```yaml\n- uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n  with:\n    format: gocover\n    path: cover.out\n    min-coverage: 80\n\n- uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n  with:\n    format: lcov\n    path: coverage/lcov.info\n    min-coverage: 90\n```\n\n## Monorepo\n\nCombine coverage from multiple languages in one step — you'll get a job summary that breaks down each format with a combined total. Use YAML block scalars (`|`) to pass multiple values:\n\n```yaml\n- uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n  with:\n    format: |\n      gocover\n      lcov\n      cobertura\n    path: |\n      go-service/cover.out\n      node-service/coverage/lcov.info\n      python-service/coverage.xml\n    min-coverage: 80\n```\n\n## Auto-Detection and Discovery\n\nYou don't need to specify `format` or `path` — coverlint can figure both out. It tries each parser until one succeeds, and looks for reports in common locations:\n\n| Format      | Searched Paths                                                                                  |\n| ----------- | ----------------------------------------------------------------------------------------------- |\n| `lcov`      | `coverage/lcov.info`, `lcov.info`, `coverage.lcov`                                              |\n| `gocover`   | `cover.out`, `coverage.out`, `c.out`                                                            |\n| `cobertura` | `coverage.xml`, `cobertura.xml`, `cobertura-coverage.xml`                                       |\n| `clover`    | `coverage.xml`, `clover.xml`                                                                    |\n| `jacoco`    | `build/reports/jacoco/test/jacocoTestReport.xml`, `target/site/jacoco/jacoco.xml`, `jacoco.xml` |\n\n## Baseline \u0026 Regression Detection\n\nCatch coverage regressions before they land. Pass a previous run's baseline as JSON and set `min-delta` to control how far the score can drop — `0` fails on any decrease, `-2` allows up to a 2-point drop. Skip `baseline` entirely if you don't need delta comparison yet.\n\nEach run emits its own `baseline` output as JSON — store it and feed it back next time. The workflow below keeps the baseline on an orphan branch, loading it before each run and updating it after merges to `main`:\n\n```yaml\non:\n  push:\n    branches: [main]\n  pull_request:\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n    outputs:\n      baseline: ${{ steps.coverage.outputs.baseline }}\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n\n      # ... your test steps ...\n\n      - name: Load previous baseline\n        id: load-baseline\n        env:\n          REPO: ${{ github.repository }}\n        run: |\n          baseline=$(curl -fsL \"https://raw.githubusercontent.com/${REPO}/coverlint/coverage-baseline.json\" 2\u003e/dev/null || true)\n          echo \"baseline=${baseline}\" \u003e\u003e \"$GITHUB_OUTPUT\"\n\n      - uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n        id: coverage\n        with:\n          format: gocover\n          min-coverage: 80\n          baseline: ${{ steps.load-baseline.outputs.baseline }}\n          min-delta: -2\n\n  update-baseline:\n    needs: test\n    if: github.ref == 'refs/heads/main' \u0026\u0026 github.event_name == 'push'\n    runs-on: ubuntu-latest\n    concurrency:\n      group: coverlint-update\n      cancel-in-progress: false\n    permissions:\n      contents: write\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n\n      - name: Push baseline\n        env:\n          BASELINE: ${{ needs.test.outputs.baseline }}\n        run: |\n          tmpdir=$(mktemp -d)\n          printf '%s' \"$BASELINE\" \u003e \"$tmpdir/coverage-baseline.json\"\n\n          git config user.name \"github-actions[bot]\"\n          git config user.email \"41898282+github-actions[bot]@users.noreply.github.com\"\n\n          if git ls-remote --exit-code origin coverlint \u0026\u003e/dev/null; then\n            git fetch origin coverlint\n            git checkout coverlint\n          else\n            git checkout --orphan coverlint\n            git rm -rf . 2\u003e/dev/null || true\n          fi\n\n          cp \"$tmpdir/coverage-baseline.json\" .\n          git add coverage-baseline.json\n          git diff --cached --quiet \u0026\u0026 exit 0\n          git commit -m \"Update coverage baseline\"\n          git push origin coverlint\n```\n\n## Code Scanning Integration\n\nSee uncovered lines and blocks right in GitHub's Code Scanning tab. Enable `sarif: true` and upload the [SARIF](https://sarifweb.azurewebsites.net/) output alongside your test results:\n\n```yaml\njobs:\n  test:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n    outputs:\n      sarif: ${{ steps.coverage.outputs.sarif }}\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n\n      # ... your test steps ...\n\n      - uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n        id: coverage\n        with:\n          format: lcov\n          sarif: true\n\n  upload-sarif:\n    needs: test\n    runs-on: ubuntu-latest\n    permissions:\n      security-events: write\n    steps:\n      - name: Write SARIF file\n        env:\n          SARIF: ${{ needs.test.outputs.sarif }}\n        run: printf '%s' \"$SARIF\" \u003e coverage.sarif\n\n      - uses: github/codeql-action/upload-sarif@820e3160e279568db735cee8ed8f8e77a6da7818 # v3\n        with:\n          sarif_file: coverage.sarif\n```\n\nResults are capped at 500 by default. For large codebases, lower the cap to stay within GitHub's 1 MB action output limit — pass a number instead of `true` (e.g. `sarif: 200`).\n\n## PR Comments\n\nGive reviewers coverage context without leaving the PR. Use the `results` output to post a summary comment:\n\n```yaml\njobs:\n  test:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n    outputs:\n      results: ${{ steps.coverage.outputs.results }}\n      passed: ${{ steps.coverage.outputs.passed }}\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n\n      # ... your test steps ...\n\n      - uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n        id: coverage\n        with:\n          format: gocover\n          min-coverage: 80\n\n  comment:\n    needs: test\n    if: github.event_name == 'pull_request'\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n      - name: Comment on PR\n        env:\n          GH_TOKEN: ${{ github.token }}\n          RESULTS: ${{ needs.test.outputs.results }}\n          PASSED: ${{ needs.test.outputs.passed }}\n          PR_NUMBER: ${{ github.event.pull_request.number }}\n        run: |\n          score=$(echo \"$RESULTS\" | jq -r '.[-1].score // empty') || exit 0\n          status=\"Pass\"\n          if [[ \"$PASSED\" != \"true\" ]]; then status=\"**Fail**\"; fi\n\n          body=\"\u003c!-- coverlint-coverage --\u003e**Coverage:** ${score}% — ${status}\"\n          gh pr comment \"$PR_NUMBER\" --edit-last --body \"$body\" 2\u003e/dev/null || \\\n            gh pr comment \"$PR_NUMBER\" --body \"$body\"\n```\n\n## Coverage Badges\n\nShow live coverage in your README — no external services or secrets needed:\n\n```yaml\non:\n  push:\n    branches: [main]\n  pull_request:\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n    outputs:\n      badge-svg: ${{ steps.coverage.outputs.badge-svg }}\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n\n      # ... your test steps ...\n\n      - uses: evansims/coverlint@aa15ba0901ffaad70113c3ab5a54bf2e676614f8 # v1.2.5\n        id: coverage\n        with:\n          format: gocover\n          min-coverage: 80\n\n  update-badges:\n    needs: test\n    if: github.ref == 'refs/heads/main' \u0026\u0026 github.event_name == 'push'\n    runs-on: ubuntu-latest\n    concurrency:\n      group: coverlint-update\n      cancel-in-progress: false\n    permissions:\n      contents: write\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n\n      - name: Push coverage badge\n        env:\n          BADGE_SVG: ${{ needs.test.outputs.badge-svg }}\n        run: |\n          tmpdir=$(mktemp -d)\n          printf '%s' \"$BADGE_SVG\" \u003e \"$tmpdir/coverage.svg\"\n\n          git config user.name \"github-actions[bot]\"\n          git config user.email \"41898282+github-actions[bot]@users.noreply.github.com\"\n\n          if git ls-remote --exit-code origin coverlint \u0026\u003e/dev/null; then\n            git fetch origin coverlint\n            git checkout coverlint\n          else\n            git checkout --orphan coverlint\n            git rm -rf . 2\u003e/dev/null || true\n          fi\n\n          cp \"$tmpdir/coverage.svg\" .\n          git add coverage.svg\n          git diff --cached --quiet \u0026\u0026 exit 0\n          git commit -m \"Update coverage badge\"\n          git push origin coverlint\n```\n\nAdd to your README:\n\n```markdown\n![Coverage](https://raw.githubusercontent.com/OWNER/REPO/coverlint/coverage.svg)\n```\n\nPrefer [shields.io](https://shields.io) styling? Use `badge-json` instead:\n\n```markdown\n![Coverage](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/OWNER/REPO/coverlint/coverage.json)\n```\n\n## Inputs\n\n| Input               | Description                                                                                            |\n| ------------------- | ------------------------------------------------------------------------------------------------------ |\n| `format`            | Coverage format(s), one per line or comma-separated. Auto-detected if omitted                          |\n| `path`              | Path(s) to coverage files, one per line or comma-separated. Supports globs. Auto-discovered if omitted |\n| `min-coverage`      | Minimum weighted coverage score (0-100), computed from line, branch, and function coverage             |\n| `min-line`          | Minimum line coverage (0-100), checked independently of the weighted score                             |\n| `min-branch`        | Minimum branch coverage (0-100), checked independently                                                 |\n| `min-function`      | Minimum function coverage (0-100), checked independently                                               |\n| `weight-line`       | Relative weight for line coverage in score (default: `50`)                                             |\n| `weight-branch`     | Relative weight for branch coverage in score (default: `30`)                                           |\n| `weight-function`   | Relative weight for function coverage in score (default: `20`)                                         |\n| `working-directory` | Working directory for resolving relative paths (default: `.`)                                          |\n| `fail-on-error`     | Fail the action when thresholds are not met (default: `true`)                                          |\n| `suggestions`       | Show top coverage improvement opportunities in job summary (default: `true`)                           |\n| `annotations`       | Annotation output: `true` (default), `false`, or a max count                                           |\n| `baseline`          | JSON string of previous baseline data for delta comparison                                             |\n| `min-delta`         | Minimum allowed score change (e.g. `0` = no regression, `-2` = max 2pt drop). Ignored without `baseline` |\n| `sarif`             | SARIF output: `true` (default max 500 results), `false`, or a number (default: `false`)                |\n\n## Outputs\n\n| Output       | Description                                                                |\n| ------------ | -------------------------------------------------------------------------- |\n| `passed`     | Whether all thresholds were met (`true` or `false`)                        |\n| `results`    | Coverage data as JSON                                                      |\n| `badge-svg`  | Ready-to-use SVG coverage badge                                            |\n| `badge-json` | Coverage badge as [shields.io](https://shields.io) endpoint JSON           |\n| `baseline`   | Current run's baseline as JSON — store and feed back as the `baseline` input next run |\n| `sarif`      | SARIF JSON for uploading to GitHub Code Scanning                           |\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eExample \u003ccode\u003eresults\u003c/code\u003e output\u003c/strong\u003e\u003c/summary\u003e\n\nThe `results` JSON has one entry per format, each with a weighted `score` and available metrics. Multi-format runs include a `Total`:\n\n```json\n[\n  { \"name\": \"gocover\", \"score\": 85, \"line\": 85, \"passed\": true },\n  {\n    \"name\": \"lcov\",\n    \"score\": 77,\n    \"line\": 78.3,\n    \"branch\": 65.2,\n    \"function\": 90.1,\n    \"passed\": true\n  },\n  {\n    \"name\": \"Total\",\n    \"score\": 79,\n    \"line\": 81.1,\n    \"branch\": 65.2,\n    \"function\": 90.1,\n    \"passed\": true\n  }\n]\n```\n\nUse GitHub Actions' `fromJSON()` expression to read values in later steps:\n\n```yaml\n- env:\n    LINE: ${{ fromJSON(steps.coverage.outputs.results)[0].line }}\n  run: echo \"Line coverage is ${LINE}%\"\n```\n\n\u003c/details\u003e\n\n## Exit Codes\n\n| Code | Meaning                                   |\n| ---- | ----------------------------------------- |\n| 0    | All checks passed                         |\n| 1    | Coverage below threshold                  |\n| 2    | Configuration, parse, or unexpected error |\n\nThis distinction helps you tell apart \"coverage is too low\" from \"something is broken.\" If you see exit 1, your tests ran fine but coverage fell short. Exit 2 usually means the action step itself needs fixing.\n\n## Pinning\n\n[Pin actions by commit SHA](https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#using-third-party-actions) in production workflows and use [Dependabot](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/about-dependabot-version-updates) to keep them current. All releases use [immutable tags](https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases), and the binary is checksum-verified on every download.\n\n## Contributing\n\nClone and run the tests — standard Go tooling, nothing extra needed:\n\n```bash\ngit clone https://github.com/evansims/coverlint.git \u0026\u0026 cd coverlint\ngo test -race -cover ./...\ngo vet ./...\n```\n\n## License\n\nDual-licensed under [Apache 2.0](LICENSE-APACHE) and [MIT](LICENSE-MIT). Choose whichever you prefer.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevansims%2Fcoverlint","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevansims%2Fcoverlint","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevansims%2Fcoverlint/lists"}