Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
210e7f8
docs: update CLAUDE.md testing requirements for Phase 5 prep
joshsmithxrm Jan 3, 2026
ef44ead
feat: add local test environment setup
joshsmithxrm Jan 3, 2026
9c80d6c
docs: update CLAUDE.md testing requirements for Phase 5 prep
joshsmithxrm Jan 3, 2026
2c282d8
feat: add local test environment setup
joshsmithxrm Jan 3, 2026
1a82784
feat: add test coverage check script for pre-PR validation
joshsmithxrm Jan 3, 2026
20176c1
Merge branch 'feature/testing-phase5-unit-tests' of https://github.co…
joshsmithxrm Jan 3, 2026
c4f03f4
docs: add Codecov badge and baseline coverage documentation
joshsmithxrm Jan 3, 2026
a2d6cfe
test: add comprehensive unit tests for Auth and Migration, CLI E2E tests
joshsmithxrm Jan 3, 2026
ede68a3
docs: update COVERAGE_BASELINE.md with Phase 5 completion
joshsmithxrm Jan 3, 2026
306d9f5
docs: remove manual dates from COVERAGE_BASELINE.md
joshsmithxrm Jan 3, 2026
b240868
fix: add --framework to CLI E2E tests for multi-targeted project
joshsmithxrm Jan 3, 2026
cf14b15
fix: address bot review findings for PR #106
joshsmithxrm Jan 3, 2026
8f5162f
chore: remove Preview labels and PAC CLI references
joshsmithxrm Jan 3, 2026
61ea852
fix: correct API endpoint for replying to PR review comments
joshsmithxrm Jan 3, 2026
914c7b9
fix: add --configuration Release to CLI E2E tests
joshsmithxrm Jan 3, 2026
7dad6d3
fix: ensure ServiceClient disposal on exception in credential providers
joshsmithxrm Jan 3, 2026
4e7bf07
fix: resolve CLI E2E test failures and add test isolation
joshsmithxrm Jan 3, 2026
4006997
perf: run CLI E2E tests on net8.0 only to eliminate redundancy
joshsmithxrm Jan 3, 2026
4c22f5b
fix: remove env list test that times out with service principal
joshsmithxrm Jan 3, 2026
4ac0708
fix: fail fast when service principal tries to use Global Discovery
joshsmithxrm Jan 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 62 additions & 14 deletions .claude/commands/pre-pr.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,33 +26,81 @@ dotnet test --no-build -c Release

### 4. Changelog
- Verify CHANGELOG.md in affected package(s) is updated
- If not, prompt: "Update changelog for [package]?"
- Skip for non-user-facing changes (tests, docs, internal refactoring)

### 5. Test Coverage (New Code)
- For each new class: does corresponding test file exist?
- Prompt: "No tests for [ClassName]. Add tests?" β†’ Generate test stubs
### 5. Test Coverage (New Code) β€” BLOCKING

Run the test coverage check script:
```powershell
.\scripts\Test-NewCodeCoverage.ps1
```

**If tests are missing, this is a blocker.** Do NOT proceed without tests.

**Action when tests are missing:**
1. Read each source file that needs tests
2. Create the test project if it doesn't exist (e.g., `PPDS.Auth.Tests`)
3. Write complete, meaningful unit tests β€” NOT stubs
4. Tests must have real assertions that verify behavior
5. Run the tests to confirm they pass

**What constitutes a real test:**
```csharp
// ❌ WRONG - This is a stub, provides no value
[Fact]
public void SomeMethod_ShouldWork()
{
// TODO: Implement test
}

// ❌ WRONG - Tests existence, not behavior
[Fact]
public void Constructor_DoesNotThrow()
{
var sut = new ProfileCollection();
Assert.NotNull(sut);
}

// βœ… CORRECT - Tests actual behavior
[Fact]
public void Add_FirstProfile_SetsAsActive()
{
var collection = new ProfileCollection();
var profile = new AuthProfile { Name = "test" };

collection.Add(profile);

Assert.Equal(profile, collection.ActiveProfile);
}
```

**Only skip tests if:**
- File is genuinely untestable (tight external coupling)
- File is already covered by integration tests in PPDS.LiveTests
- User explicitly confirms "this doesn't need unit tests because [reason]"

## Output

```
Pre-PR Validation
=================
[x] Build: PASS
[x] Tests: PASS (42 passed)
[βœ“] Build: PASS
[βœ“] Tests: PASS (42 passed)
[!] Missing XML docs: MsalClientBuilder.CreateClient()
[x] No TODOs found
[!] Changelog not updated for PPDS.Auth
[!] No tests for: ThrottleDetector, MsalClientBuilder
[βœ“] No TODOs found
[βœ—] Missing tests for: EnvironmentResolutionService, ProfileValidator

Fix issues? [Y/n]
Missing tests is a blocker. Writing tests now...
```

## Behavior

- On first failure: stop and report
- On warnings: list all, ask whether to fix
- Auto-fix what's possible (changelog stubs, test file creation)
- Manual fix guidance for others
1. Run all checks
2. Report results
3. **If tests are missing: write them** (do not ask, do not generate stubs)
4. If unable to write tests, explain why and get user confirmation to skip
5. Run tests again after writing new ones
6. Only proceed to PR when all checks pass

## When to Use

Expand Down
9 changes: 4 additions & 5 deletions .claude/commands/review-bot-comments.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,12 @@ After user approval:
After changes are committed, reply to each bot comment. Do NOT batch responses into a single PR comment.

```bash
# Reply to a specific review comment
gh api repos/joshsmithxrm/ppds-sdk/pulls/{pr}/comments \
-f body="Fixed in abc123" \
-F in_reply_to={comment_id}
# Reply to a specific review comment (note: uses /replies endpoint)
gh api repos/joshsmithxrm/ppds-sdk/pulls/{pr}/comments/{comment_id}/replies \
-f body="Fixed in abc123"
```

**Important:** The `in_reply_to` parameter must be the comment ID (numeric), not a URL. Get IDs from the fetch step.
**Important:** Use the `/comments/{comment_id}/replies` endpoint, NOT the base comments endpoint with `in_reply_to`. The comment ID is numeric - get IDs from the fetch step.

| Verdict | Reply Template |
|---------|----------------|
Expand Down
16 changes: 16 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# PPDS SDK - Local Test Environment Configuration
# Copy this file to .env.local and fill in your values
# .env.local is gitignored and will not be committed

# Required for integration tests (LiveTests, CLI E2E)
DATAVERSE_URL=https://yourorg.crm.dynamics.com
PPDS_TEST_APP_ID=00000000-0000-0000-0000-000000000000
PPDS_TEST_CLIENT_SECRET=your-client-secret-here
PPDS_TEST_TENANT_ID=00000000-0000-0000-0000-000000000000

# Optional: Certificate-based authentication (alternative to client secret)
# PPDS_TEST_CERT_PATH=C:\path\to\certificate.pfx
# PPDS_TEST_CERT_PASSWORD=certificate-password

# Optional: Certificate as base64 (used in CI, can also use locally)
# PPDS_TEST_CERT_BASE64=base64-encoded-pfx-content
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,7 @@ schema.xml

# Code coverage
coverage/

# Local environment secrets
.env.local
.env.*.local
61 changes: 51 additions & 10 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,14 @@ ppds-sdk/
β”‚ β”œβ”€β”€ PPDS.Auth/ # Authentication profiles and credentials
β”‚ └── PPDS.Cli/ # Unified CLI tool (ppds command)
β”œβ”€β”€ tests/
β”‚ β”œβ”€β”€ PPDS.Plugins.Tests/
β”‚ β”œβ”€β”€ PPDS.Dataverse.Tests/
β”‚ └── PPDS.Cli.Tests/
β”‚ β”œβ”€β”€ PPDS.Plugins.Tests/ # Unit tests
β”‚ β”œβ”€β”€ PPDS.Dataverse.Tests/ # Unit tests
β”‚ β”œβ”€β”€ PPDS.Cli.Tests/ # Unit tests
β”‚ β”œβ”€β”€ PPDS.Auth.Tests/ # Unit tests
β”‚ β”œβ”€β”€ PPDS.Migration.Tests/ # Unit tests
β”‚ β”œβ”€β”€ PPDS.Auth.IntegrationTests/ # Auth smoke tests
β”‚ β”œβ”€β”€ PPDS.Dataverse.IntegrationTests/ # FakeXrmEasy mocked tests
β”‚ └── PPDS.LiveTests/ # Live Dataverse + CLI E2E tests
β”œβ”€β”€ docs/
β”‚ β”œβ”€β”€ adr/ # Architecture Decision Records
β”‚ └── architecture/ # Pattern documentation
Expand Down Expand Up @@ -377,13 +382,24 @@ See [CLI README](src/PPDS.Cli/README.md) for full documentation.

## πŸ§ͺ Testing Requirements

| Package | Test Project | Status |
|---------|--------------|--------|
| PPDS.Plugins | PPDS.Plugins.Tests | βœ… |
| PPDS.Dataverse | PPDS.Dataverse.Tests | βœ… |
| PPDS.Cli | PPDS.Cli.Tests | βœ… |
| PPDS.Auth | **Needs test project** | ❌ |
| PPDS.Migration | **Needs test project** | ❌ |
### Test Projects

| Package | Unit Tests | Integration Tests | Status |
|---------|------------|-------------------|--------|
| PPDS.Plugins | PPDS.Plugins.Tests | - | βœ… |
| PPDS.Dataverse | PPDS.Dataverse.Tests | PPDS.Dataverse.IntegrationTests (FakeXrmEasy) | βœ… |
| PPDS.Cli | PPDS.Cli.Tests | PPDS.LiveTests/Cli (E2E) | βœ… |
| PPDS.Auth | PPDS.Auth.Tests | PPDS.LiveTests/Authentication | βœ… |
| PPDS.Migration | PPDS.Migration.Tests | - | βœ… |

### Live Tests (PPDS.LiveTests)

Live integration tests against real Dataverse environment:
- `Authentication/` - Client secret, certificate, GitHub OIDC, Azure DevOps OIDC
- `Pooling/` - Connection pool, DOP detection
- `Resilience/` - Throttle detection
- `BulkOperations/` - Live bulk operation execution
- `Cli/` - CLI E2E tests (auth, env, data schema commands)

**Rules:**
- New public class β†’ must have corresponding test class
Expand All @@ -394,6 +410,31 @@ See [CLI README](src/PPDS.Cli/README.md) for full documentation.
- **Commits:** Unit tests only (`--filter Category!=Integration`)
- **PRs:** All tests including integration

### Local Integration Test Setup

Integration tests require Dataverse credentials. Setup:

1. **Copy environment template:**
```powershell
Copy-Item .env.example .env.local
```

2. **Edit `.env.local`** with your values:
```
DATAVERSE_URL=https://yourorg.crm.dynamics.com
PPDS_TEST_APP_ID=your-app-id
PPDS_TEST_CLIENT_SECRET=your-secret
PPDS_TEST_TENANT_ID=your-tenant-id
```

3. **Load into session and run tests:**
```powershell
. .\scripts\Load-TestEnv.ps1
dotnet test --filter "Category=Integration"
```

**Note:** `.env.local` is gitignored. Tests skip gracefully when credentials are missing.

---

## πŸ€– Bot Review Handling
Expand Down
30 changes: 30 additions & 0 deletions PPDS.Sdk.sln
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PPDS.Auth.IntegrationTests"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PPDS.LiveTests", "tests\PPDS.LiveTests\PPDS.LiveTests.csproj", "{EF193372-AD19-4918-87F2-5B875AC840E1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PPDS.Migration.Tests", "tests\PPDS.Migration.Tests\PPDS.Migration.Tests.csproj", "{8EC120F4-EB87-4C2F-B12F-3AD14C857BA9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PPDS.Auth.Tests", "tests\PPDS.Auth.Tests\PPDS.Auth.Tests.csproj", "{B1D38F8D-67C5-431F-BB47-BF02AE1E4AEB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -171,6 +175,30 @@ Global
{EF193372-AD19-4918-87F2-5B875AC840E1}.Release|x64.Build.0 = Release|Any CPU
{EF193372-AD19-4918-87F2-5B875AC840E1}.Release|x86.ActiveCfg = Release|Any CPU
{EF193372-AD19-4918-87F2-5B875AC840E1}.Release|x86.Build.0 = Release|Any CPU
{8EC120F4-EB87-4C2F-B12F-3AD14C857BA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8EC120F4-EB87-4C2F-B12F-3AD14C857BA9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8EC120F4-EB87-4C2F-B12F-3AD14C857BA9}.Debug|x64.ActiveCfg = Debug|Any CPU
{8EC120F4-EB87-4C2F-B12F-3AD14C857BA9}.Debug|x64.Build.0 = Debug|Any CPU
{8EC120F4-EB87-4C2F-B12F-3AD14C857BA9}.Debug|x86.ActiveCfg = Debug|Any CPU
{8EC120F4-EB87-4C2F-B12F-3AD14C857BA9}.Debug|x86.Build.0 = Debug|Any CPU
{8EC120F4-EB87-4C2F-B12F-3AD14C857BA9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8EC120F4-EB87-4C2F-B12F-3AD14C857BA9}.Release|Any CPU.Build.0 = Release|Any CPU
{8EC120F4-EB87-4C2F-B12F-3AD14C857BA9}.Release|x64.ActiveCfg = Release|Any CPU
{8EC120F4-EB87-4C2F-B12F-3AD14C857BA9}.Release|x64.Build.0 = Release|Any CPU
{8EC120F4-EB87-4C2F-B12F-3AD14C857BA9}.Release|x86.ActiveCfg = Release|Any CPU
{8EC120F4-EB87-4C2F-B12F-3AD14C857BA9}.Release|x86.Build.0 = Release|Any CPU
{B1D38F8D-67C5-431F-BB47-BF02AE1E4AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B1D38F8D-67C5-431F-BB47-BF02AE1E4AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B1D38F8D-67C5-431F-BB47-BF02AE1E4AEB}.Debug|x64.ActiveCfg = Debug|Any CPU
{B1D38F8D-67C5-431F-BB47-BF02AE1E4AEB}.Debug|x64.Build.0 = Debug|Any CPU
{B1D38F8D-67C5-431F-BB47-BF02AE1E4AEB}.Debug|x86.ActiveCfg = Debug|Any CPU
{B1D38F8D-67C5-431F-BB47-BF02AE1E4AEB}.Debug|x86.Build.0 = Debug|Any CPU
{B1D38F8D-67C5-431F-BB47-BF02AE1E4AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B1D38F8D-67C5-431F-BB47-BF02AE1E4AEB}.Release|Any CPU.Build.0 = Release|Any CPU
{B1D38F8D-67C5-431F-BB47-BF02AE1E4AEB}.Release|x64.ActiveCfg = Release|Any CPU
{B1D38F8D-67C5-431F-BB47-BF02AE1E4AEB}.Release|x64.Build.0 = Release|Any CPU
{B1D38F8D-67C5-431F-BB47-BF02AE1E4AEB}.Release|x86.ActiveCfg = Release|Any CPU
{B1D38F8D-67C5-431F-BB47-BF02AE1E4AEB}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -187,5 +215,7 @@ Global
{4CA09022-5929-44B8-9777-CA824EC9A8EE} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
{9C52B513-E62D-49D4-9D5A-3F8C5BAB2876} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
{EF193372-AD19-4918-87F2-5B875AC840E1} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
{8EC120F4-EB87-4C2F-B12F-3AD14C857BA9} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
{B1D38F8D-67C5-431F-BB47-BF02AE1E4AEB} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
EndGlobalSection
EndGlobal
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# PPDS SDK

[![Build](https://github.com/joshsmithxrm/ppds-sdk/actions/workflows/build.yml/badge.svg)](https://github.com/joshsmithxrm/ppds-sdk/actions/workflows/build.yml)
[![codecov](https://codecov.io/gh/joshsmithxrm/ppds-sdk/graph/badge.svg)](https://codecov.io/gh/joshsmithxrm/ppds-sdk)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

NuGet packages for Microsoft Dataverse development. Part of the [Power Platform Developer Suite](https://github.com/joshsmithxrm/power-platform-developer-suite) ecosystem.
Expand Down
117 changes: 117 additions & 0 deletions docs/COVERAGE_BASELINE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Code Coverage Baseline

## Overview

This document records the baseline code coverage for each PPDS SDK package, used to track progress toward the targets defined in [Issue #55](https://github.com/joshsmithxrm/ppds-sdk/issues/55).

## Current Baseline

| Package | Unit Tests | Estimated Coverage | Target | Status | Notes |
|---------|------------|-------------------|--------|--------|-------|
| **PPDS.Plugins** | 77 | ~95% | 95% | βœ… Met | Core attributes fully tested |
| **PPDS.Dataverse** | 351 | ~65% | 60% | βœ… Met | Unit + FakeXrmEasy mocked tests |
| **PPDS.Cli** | 210 + 27 E2E | ~45% | 60% | ⏳ Gap | Unit tests cover parsing; E2E covers auth/env/schema |
| **PPDS.Auth** | 282 | ~65% | 70% | βœ… Near | Profiles, credentials, discovery covered; credential providers in LiveTests |
| **PPDS.Migration** | 200 | ~55% | 50% | βœ… Met | Models, formats, analysis covered; orchestrators need integration |
| **Overall** | 1,147 | ~58% | 60% | ⏳ Near | Significant improvement from Phase 5 |

### Coverage Notes

- **Estimated Coverage**: Percentages are estimates based on test file coverage of source files. Run `dotnet test --collect:"XPlat Code Coverage"` for actual metrics.
- **PPDS.Auth**: Credential providers (ClientSecretCredentialProvider, etc.) are integration-heavy and tested via `PPDS.LiveTests/Authentication/`.
- **PPDS.Migration**: Orchestrators (TieredImporter, ParallelExporter) require Dataverse connections and are not unit-tested.
- **PPDS.Cli**: E2E tests cover auth, env, and schema commands. Data migration commands pending (see [Future Work](#future-work-cli-e2e-expansion)).

## Test Project Summary

| Test Project | Test Count | Scope |
|--------------|------------|-------|
| PPDS.Plugins.Tests | 77 | Attributes, enums |
| PPDS.Dataverse.Tests | 351 | Client, pooling, bulk operations, resilience |
| PPDS.Dataverse.IntegrationTests | ~50 | FakeXrmEasy mocked Dataverse operations |
| PPDS.Cli.Tests | 210 | Command structure, argument parsing |
| PPDS.Auth.Tests | 282 | Profiles, credentials, discovery, cloud |
| PPDS.Migration.Tests | 200 | Models, formats, analysis, import/export |
| PPDS.LiveTests | ~40 + 27 CLI | Live Dataverse + CLI E2E tests |

## Measurement Method

Coverage is collected using:
- **Collector**: `coverlet.collector` via `dotnet test --collect:"XPlat Code Coverage"`
- **Reporter**: [Codecov](https://codecov.io/gh/joshsmithxrm/ppds-sdk)
- **Frameworks**: Merged from net8.0, net9.0, net10.0 test runs

## Targets by Package

From [Issue #55 - Integration Testing Infrastructure](https://github.com/joshsmithxrm/ppds-sdk/issues/55):

| Package | Unit Target | Integration Target | Rationale |
|---------|-------------|-------------------|-----------|
| PPDS.Plugins | 95% | N/A | Core attributes, simple logic |
| PPDS.Auth | 70% | Live auth tests | Complex auth flows; credential providers need real auth |
| PPDS.Dataverse | 60% | 80% mocked | Heavy external dependencies |
| PPDS.Migration | 50% | N/A | Orchestration code; importers/exporters need Dataverse |
| PPDS.Cli | 60% | E2E tests | Command parsing (unit) + execution (E2E) |

## Improvement Plan

### Phase 5 (Complete)
- [x] Create PPDS.Auth.Tests unit test project (282 tests)
- [x] Create PPDS.Migration.Tests unit test project (200 tests)
- [x] Add CLI E2E tests to PPDS.LiveTests (auth, env, schema commands)

### Future Work: CLI E2E Expansion

CLI E2E tests currently cover:
- `auth` commands (list, who, create, delete, select, clear)
- `env` commands (list, who, select)
- `data schema` command

**Not yet covered:**
- `data export` / `data import` / `data copy` / `data analyze` / `data users`
- `plugins deploy` / `plugins diff` / `plugins list` / `plugins extract` / `plugins clean`

**Plan**: Data migration E2E tests require known test data in the environment. These tests will be added when data import functionality is enhanced, following this sequence:

1. Create test data file (accounts for seeding)
2. Import test seeds environment with known data
3. Export test exports that known data
4. Workflow test validates round-trip

See [Issue #104](https://github.com/joshsmithxrm/ppds-sdk/issues/104) for details.

### Future: Coverage Gates
- [ ] Enable patch coverage enforcement (80% for new code)
- [ ] Add project-level coverage gates after baseline improvement

## CLI E2E Test Coverage Matrix

| Command Group | Commands | Unit Tests | E2E Tests | Status |
|---------------|----------|------------|-----------|--------|
| `auth` | create, delete, select, list, who, clear, update, name | βœ… Structure | βœ… 11 tests | Complete |
| `env` | list, select, who | βœ… Structure | βœ… 9 tests | Complete |
| `data schema` | generate | βœ… Structure | βœ… 7 tests | Complete |
| `data export` | export | βœ… Parsing | ❌ Pending | Needs test data |
| `data import` | import | βœ… Parsing | ❌ Pending | Needs test data |
| `data copy` | copy | βœ… Parsing | ❌ Pending | Needs test data |
| `data analyze` | analyze | βœ… Parsing | ❌ Pending | Lower priority |
| `data users` | generate | βœ… Parsing | ❌ Pending | Lower priority |
| `plugins deploy` | deploy | βœ… Parsing | ❌ Pending | Needs config |
| `plugins diff` | diff | βœ… Parsing | ❌ Pending | Lower priority |
| `plugins list` | list | βœ… Parsing | ❌ Pending | Lower priority |
| `plugins extract` | extract | βœ… Parsing | ❌ Pending | Unit tests sufficient |
| `plugins clean` | clean | βœ… Parsing | ❌ Pending | Only --what-if |

## Codecov Configuration

Coverage thresholds are configured in [`codecov.yml`](../codecov.yml):
- **Project coverage**: Informational (no PR blocking)
- **Patch coverage**: Informational (no PR blocking)
- **Components**: Per-package tracking with individual targets

## References

- [Codecov Dashboard](https://codecov.io/gh/joshsmithxrm/ppds-sdk)
- [Issue #55 - Integration Testing Infrastructure](https://github.com/joshsmithxrm/ppds-sdk/issues/55)
- [Issue #84 - Code Coverage Reporting](https://github.com/joshsmithxrm/ppds-sdk/issues/84)
- [Demo Test Scripts](../demo/scripts/) - PowerShell scripts for manual CLI validation
Loading
Loading