Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
03c777b
feat(auth): add PPDS.Auth package with profile storage and credentials
joshsmithxrm Dec 27, 2025
83b9bd2
feat(cli): rename to PPDS.Cli, restructure commands, add auth commands
joshsmithxrm Dec 28, 2025
db0ec23
feat(cli): add environment discovery via Global Discovery Service
joshsmithxrm Dec 28, 2025
63d57a9
feat(auth): add certificate and managed identity authentication
joshsmithxrm Dec 28, 2025
56cb666
feat(cli): integrate data commands with profile-based auth
joshsmithxrm Dec 28, 2025
34c650a
feat(auth): add interactive browser authentication (PAC CLI parity)
joshsmithxrm Dec 28, 2025
ea1a4d5
feat(cli): complete unified CLI implementation (all phases)
joshsmithxrm Dec 28, 2025
c9f36cc
chore: clean up comments and remove PAC CLI references
joshsmithxrm Dec 28, 2025
87bca6c
fix(cli): env who now executes WhoAmI request, auth who shows more info
joshsmithxrm Dec 28, 2025
4483f9a
fix(cli): env who uses client properties instead of Retrieve calls
joshsmithxrm Dec 28, 2025
4fc4c77
chore: add dev scripts for CLI testing
joshsmithxrm Dec 28, 2025
3587536
wip: prefer interactive browser auth, add force flag to update
joshsmithxrm Dec 28, 2025
774c006
fix(cli): align auth behavior with pac patterns
joshsmithxrm Dec 28, 2025
aa0a0a2
fix(cli): add InteractiveBrowser auth method, remove clear confirmation
joshsmithxrm Dec 28, 2025
c4f2a9d
feat(cli): improve auth list to match pac format
joshsmithxrm Dec 28, 2025
598a74f
fix(cli): align auth update with pac interface
joshsmithxrm Dec 28, 2025
4b3a487
fix(cli): align env select with pac interface
joshsmithxrm Dec 28, 2025
3638196
feat(cli): align auth commands with pac CLI interface
joshsmithxrm Dec 28, 2025
2ecedc5
fix(cli): remove confirmation from auth delete to match pac
joshsmithxrm Dec 28, 2025
e369250
fix(cli): add -ct alias and fix environment URL resolution
joshsmithxrm Dec 28, 2025
53e67a7
feat(cli): align auth who output with pac fields
joshsmithxrm Dec 28, 2025
a205c39
feat(auth): extract JWT claims for additional user info in auth who
joshsmithxrm Dec 28, 2025
aa9d378
fix(auth): correct OrganizationType enum mapping for environment types
joshsmithxrm Dec 28, 2025
1d795e0
fix(cli): align env who and auth who output with pac CLI
joshsmithxrm Dec 28, 2025
6ab69b4
chore: add nul to gitignore
joshsmithxrm Dec 28, 2025
204e4fe
feat(auth): add IdTokenClaims support for JWT claim extraction
joshsmithxrm Dec 28, 2025
04d4b51
refactor(auth): remove unsupported country claims and debug code
joshsmithxrm Dec 28, 2025
51d6d8b
chore: remove 'Unified' from CLI description
joshsmithxrm Dec 28, 2025
2aa3c56
feat(cli): standardize 'Connected as' header across all Dataverse com…
joshsmithxrm Dec 28, 2025
6fe30c3
fix(progress): prevent empty export/import progress lines
joshsmithxrm Dec 28, 2025
649b1f1
fix(auth): require full URL for service principal authentication
joshsmithxrm Dec 28, 2025
c91f5d2
fix(pooling): prevent premature disposal of connection sources
joshsmithxrm Dec 28, 2025
f4c5752
chore: remove accidentally committed data files
joshsmithxrm Dec 28, 2025
e0b576f
fix(cli): use active profile when no profile specified
joshsmithxrm Dec 28, 2025
5f24956
chore: gitignore data files
joshsmithxrm Dec 28, 2025
0c72183
feat(cli): show profile name with client ID for service principals
joshsmithxrm Dec 28, 2025
d81317c
fix(cli): allow paths with directories in output option
joshsmithxrm Dec 28, 2025
a78d160
refactor(cli): standardize logging, options, and completion output
joshsmithxrm Dec 28, 2025
ad05825
feat(cli): add --parallel, --batch-size to copy command, fix tests
joshsmithxrm Dec 28, 2025
d344999
docs: update README to remove dead CompressOutput option
joshsmithxrm Dec 28, 2025
a93e237
fix(tests): update ExportCommand tests for --batch-size rename
joshsmithxrm Dec 28, 2025
03a18bc
feat(cli): add --rate-preset option, fix DI pattern, add logging docs
joshsmithxrm Dec 28, 2025
2bae532
refactor(cli): modernize output headers and document display patterns
joshsmithxrm Dec 28, 2025
d993d6f
feat(cli): display [Required] inline instead of (REQUIRED) suffix
joshsmithxrm Dec 28, 2025
4ebcd22
docs: add code comment guidelines to CLAUDE.md
joshsmithxrm Dec 28, 2025
c29ef12
fix(cli): remove AcceptLegalFileNamesOnly from path option
joshsmithxrm Dec 28, 2025
837060a
feat(cli): add environment name resolution for users and copy commands
joshsmithxrm Dec 28, 2025
8b6e15f
fix(cli): analyze command no longer requires Dataverse connection
joshsmithxrm Dec 28, 2025
edc53e5
feat(cli): add -j and -m short aliases for common options
joshsmithxrm Dec 28, 2025
9d9c0c2
refactor(cli): centralize environment resolution in ProfileServiceFac…
joshsmithxrm Dec 28, 2025
ddf19b2
fix(migration): use ObjectTypeCode for plugin step query
joshsmithxrm Dec 28, 2025
b8372e2
feat(migration): metadata-driven field validity filtering
joshsmithxrm Dec 28, 2025
c80baf8
refactor(pool): centralize connection display name formatting
joshsmithxrm Dec 28, 2025
de519fb
fix(pool): handle token expiration with seed invalidation
joshsmithxrm Dec 28, 2025
ba7a42e
fix(pool): make DisplayName safe when org metadata unavailable
joshsmithxrm Dec 28, 2025
da45282
feat(rate-control): add request rate ceiling for fast batch protection
joshsmithxrm Dec 28, 2025
32c1575
refactor(rate-control): pool-level tracking for all connections
joshsmithxrm Dec 28, 2025
57b00b5
fix(pool): include environment name in connection display for all aut…
joshsmithxrm Dec 28, 2025
f1aeb4c
fix(rate-control): prevent throttle cascade with conservative ramp-up
joshsmithxrm Dec 29, 2025
afbf699
fix(rate-control): tune execution time ceiling factor to prevent thro…
joshsmithxrm Dec 29, 2025
c002464
fix(rate-control): scale execution time ceiling by connection count
joshsmithxrm Dec 29, 2025
b062371
refactor(rate-control): replace adaptive AIMD with DOP-based parallelism
joshsmithxrm Dec 29, 2025
9e73022
fix(pool): use server DOP for pool sizing instead of MinPoolSize
joshsmithxrm Dec 29, 2025
e1e0a7e
feat(pool): adaptive per-source DOP control for bulk operations
joshsmithxrm Dec 29, 2025
0fedfd2
feat(cli): expose granular plugin bypass options (sync/async/all)
joshsmithxrm Dec 29, 2025
3452197
fix(pool): remove double-checkout and add seed creation locking
joshsmithxrm Dec 29, 2025
354b45f
feat(import): detect schema mismatches and fail fast with clear report
joshsmithxrm Dec 29, 2025
2513ac1
feat(copy): support comma-separated target profiles for parallel imports
joshsmithxrm Dec 29, 2025
ed8cef4
feat(copy): add user-mapping, strip-owner-fields, and continue-on-err…
joshsmithxrm Dec 29, 2025
fa35706
test: update and expand test coverage after DOP refactor
joshsmithxrm Dec 29, 2025
7ea2844
fix(copy): reset progress reporter stopwatch between export and import
joshsmithxrm Dec 29, 2025
e9a5e39
docs: update benchmarks and patterns for DOP-based parallelism
joshsmithxrm Dec 29, 2025
28a5e08
feat(cli): enhance import output with ETA and created/updated breakdown
joshsmithxrm Dec 29, 2025
fd07a3d
refactor(schema): metadata-driven field filtering with audit fields
joshsmithxrm Dec 29, 2025
7ffdb66
refactor(schema): remove --include-relationships option
joshsmithxrm Dec 29, 2025
6cf2129
feat(cli): add entity detail view to schema list command
joshsmithxrm Dec 29, 2025
45bc674
fix(schema): exclude non-migratable system fields that pass IsCustomi…
joshsmithxrm Dec 29, 2025
365d913
deps: Bump Microsoft.Extensions.Options.ConfigurationExtensions from …
dependabot[bot] Dec 29, 2025
ad58d3a
deps: Bump Microsoft.Identity.Client and Microsoft.Identity.Client.Ex…
dependabot[bot] Dec 29, 2025
b844d98
deps: Bump MinVer from 6.0.0 to 6.1.0
dependabot[bot] Dec 29, 2025
5f59e7f
deps: Bump System.Security.Cryptography.Pkcs from 8.0.1 to 10.0.1
dependabot[bot] Dec 29, 2025
1590224
deps: Bump xunit.runner.visualstudio from 3.0.2 to 3.1.5
dependabot[bot] Dec 29, 2025
4cefe30
docs: update documentation and changelogs for unified CLI release
joshsmithxrm Dec 29, 2025
dec2f29
fix: update target frameworks for broader runtime compatibility
joshsmithxrm Dec 29, 2025
82fdd3d
Merge dependabot: Microsoft.Extensions.Options.ConfigurationExtension…
joshsmithxrm Dec 29, 2025
d320df9
Merge dependabot: Microsoft.Identity.Client and Extensions.Msal updates
joshsmithxrm Dec 29, 2025
352f18c
Merge dependabot: MinVer 6.0.0 → 6.1.0
joshsmithxrm Dec 29, 2025
a9b2ff5
Merge dependabot: System.Security.Cryptography.Pkcs 8.0.1 → 10.0.1
joshsmithxrm Dec 29, 2025
6605cb9
Merge dependabot: xunit.runner.visualstudio 3.0.2 → 3.1.5
joshsmithxrm Dec 29, 2025
9027a69
fix: address PR review feedback
joshsmithxrm Dec 29, 2025
5f95ad6
ci: update workflows for new packages and .NET 9.0
joshsmithxrm Dec 29, 2025
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
5 changes: 5 additions & 0 deletions .config/dotnet-tools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"version": 1,
"isRoot": true,
"tools": {}
}
3 changes: 2 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ jobs:
uses: actions/setup-dotnet@v5
with:
dotnet-version: |
6.0.x
8.0.x
9.0.x
10.0.x

- name: Restore dependencies
run: dotnet restore
Expand Down
11 changes: 10 additions & 1 deletion .github/workflows/publish-nuget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ on:
- 'Plugins-v*'
- 'Dataverse-v*'
- 'Migration-v*'
- 'Auth-v*'
- 'Cli-v*'

jobs:
publish:
Expand All @@ -21,6 +23,7 @@ jobs:
with:
dotnet-version: |
8.0.x
9.0.x
10.0.x

- name: Determine package to publish
Expand All @@ -38,7 +41,13 @@ jobs:
echo "projects=src/PPDS.Dataverse/PPDS.Dataverse.csproj" >> $GITHUB_OUTPUT
elif [[ $TAG == Migration-v* ]]; then
echo "package=PPDS.Migration" >> $GITHUB_OUTPUT
echo "projects=src/PPDS.Migration/PPDS.Migration.csproj src/PPDS.Migration.Cli/PPDS.Migration.Cli.csproj" >> $GITHUB_OUTPUT
echo "projects=src/PPDS.Migration/PPDS.Migration.csproj" >> $GITHUB_OUTPUT
elif [[ $TAG == Auth-v* ]]; then
echo "package=PPDS.Auth" >> $GITHUB_OUTPUT
echo "projects=src/PPDS.Auth/PPDS.Auth.csproj" >> $GITHUB_OUTPUT
elif [[ $TAG == Cli-v* ]]; then
echo "package=PPDS.Cli" >> $GITHUB_OUTPUT
echo "projects=src/PPDS.Cli/PPDS.Cli.csproj" >> $GITHUB_OUTPUT
else
echo "Unknown tag format: $TAG"
exit 1
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ jobs:
uses: actions/setup-dotnet@v5
with:
dotnet-version: |
6.0.x
8.0.x
9.0.x
10.0.x

- name: Restore dependencies
run: dotnet restore
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,7 @@ Thumbs.db

# Temporary artifacts (testing, exports, logs)
tmp/
nul
data.zip
data/
schema.xml
147 changes: 104 additions & 43 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,23 @@
|------|-----|
| Strong name all assemblies | Required for Dataverse plugin sandbox |
| XML documentation for public APIs | IntelliSense support for consumers |
| Multi-target appropriately | PPDS.Plugins: 4.6.2, 8.0, 10.0; PPDS.Dataverse: 8.0, 10.0 |
| Multi-target appropriately | PPDS.Plugins: 4.6.2 only; libraries: 8.0, 9.0, 10.0 |
| Run `dotnet test` before PR | Ensures no regressions |
| Update `CHANGELOG.md` with changes | Release notes for consumers |
| Follow SemVer versioning | Clear compatibility expectations |
| Use connection pool for multi-request scenarios | Reuses connections, applies performance settings automatically |
| Dispose pooled clients with `await using` | Returns connections to pool; prevents leaks |
| Use bulk APIs (`CreateMultiple`, `UpdateMultiple`, `UpsertMultiple`) | 5x faster than `ExecuteMultiple` (~10M vs ~2M records/hour) |
| Reference Microsoft Learn docs in ADRs | Authoritative source for Dataverse best practices |
| Use `Conservative` preset for production bulk operations | Prevents throttle cascades; slightly lower throughput but zero throttles |
| Scale throughput by adding Application Users | Each user has independent API quota; DOP × connections = total parallelism |

---

## 💻 Tech Stack

| Technology | Version | Purpose |
|------------|---------|---------|
| .NET | 4.6.2, 8.0, 10.0 | Multi-targeting (Plugins: 4.6.2+, Dataverse: 8.0+) |
| .NET | 4.6.2, 8.0, 9.0, 10.0 | Plugins: 4.6.2 only; libraries/CLI: 8.0, 9.0, 10.0 |
| C# | Latest (LangVersion) | Primary language |
| NuGet | - | Package distribution |
| Strong Naming | .snk file | Required for Dataverse plugin assemblies |
Expand All @@ -70,10 +70,12 @@ ppds-sdk/
│ │ ├── Resilience/ # Throttle tracking, retry logic
│ │ └── PPDS.Dataverse.csproj
│ ├── PPDS.Migration/ # Migration engine library
│ └── PPDS.Migration.Cli/ # CLI tool (ppds-migrate)
│ ├── PPDS.Auth/ # Authentication profiles and credentials
│ └── PPDS.Cli/ # Unified CLI tool (ppds command)
├── tests/
│ ├── PPDS.Plugins.Tests/
│ └── PPDS.Dataverse.Tests/
│ ├── PPDS.Dataverse.Tests/
│ └── PPDS.Cli.Tests/
├── docs/
│ ├── adr/ # Architecture Decision Records
│ └── architecture/ # Pattern documentation
Expand Down Expand Up @@ -140,6 +142,29 @@ public class PluginStepAttribute : Attribute { }
public class PluginStepAttribute : Attribute { }
```

### Code Comments

Comments explain WHY, not WHAT. The code documents what it does.

```csharp
// ❌ Bad - explains what (the code already shows this)
// Loop through all options and check if required
foreach (var option in command.Options)

// ❌ Bad - references external tool as justification
// Use [Required] prefix like Azure CLI does
option.Description = $"[Required] {desc}";

// ✅ Good - explains why (non-obvious side effect)
// Required=false hides the default suffix; we show [Required] in description instead
option.Required = false;

// ✅ Good - explains why (workaround for framework limitation)
// Option validators only run when the option is present on command line,
// so we need command-level validation to catch missing required options
command.Validators.Add(result => { ... });
```

### Namespaces

```csharp
Expand All @@ -152,11 +177,23 @@ namespace PPDS.Plugins.Enums; // Enums
namespace PPDS.Dataverse.Pooling; // Connection pool, IConnectionSource
namespace PPDS.Dataverse.BulkOperations; // Bulk API wrappers
namespace PPDS.Dataverse.Configuration; // Options, connection config
namespace PPDS.Dataverse.Resilience; // Throttle tracking, rate control
namespace PPDS.Dataverse.Resilience; // Throttle tracking, service protection

// PPDS.Migration
namespace PPDS.Migration.Export; // IExporter
namespace PPDS.Migration.Import; // IImporter

// PPDS.Auth
namespace PPDS.Auth.Profiles; // AuthProfile, ProfileStore, ProfileCollection
namespace PPDS.Auth.Credentials; // ICredentialProvider, credential implementations
namespace PPDS.Auth.Discovery; // GlobalDiscoveryService, EnvironmentResolver
namespace PPDS.Auth.Cloud; // CloudEnvironment, CloudEndpoints

// PPDS.Cli
namespace PPDS.Cli.Commands.Auth; // Auth command group
namespace PPDS.Cli.Commands.Env; // Environment command group
namespace PPDS.Cli.Commands.Data; // Data command group (export, import, copy)
namespace PPDS.Cli.Infrastructure; // ServiceFactory, ProfileServiceFactory
```

---
Expand All @@ -169,7 +206,9 @@ Each package has independent versioning using [MinVer](https://github.com/adamra
|---------|------------|---------|
| PPDS.Plugins | `Plugins-v{version}` | `Plugins-v1.2.0` |
| PPDS.Dataverse | `Dataverse-v{version}` | `Dataverse-v1.0.0` |
| PPDS.Migration + CLI | `Migration-v{version}` | `Migration-v1.0.0` |
| PPDS.Migration | `Migration-v{version}` | `Migration-v1.0.0` |
| PPDS.Auth | `Auth-v{version}` | `Auth-v1.0.0` |
| PPDS.Cli | `Cli-v{version}` | `Cli-v1.0.0` |

- Follow SemVer: `MAJOR.MINOR.PATCH`
- Pre-release: `-alpha.N`, `-beta.N`, `-rc.N` suffix
Expand Down Expand Up @@ -201,6 +240,8 @@ See per-package changelogs:
- [PPDS.Plugins](src/PPDS.Plugins/CHANGELOG.md)
- [PPDS.Dataverse](src/PPDS.Dataverse/CHANGELOG.md)
- [PPDS.Migration](src/PPDS.Migration/CHANGELOG.md)
- [PPDS.Auth](src/PPDS.Auth/CHANGELOG.md)
- [PPDS.Cli](src/PPDS.Cli/CHANGELOG.md)

---

Expand All @@ -213,14 +254,15 @@ See per-package changelogs:
| PPDS.Plugins | NuGet |
| PPDS.Dataverse | NuGet |
| PPDS.Migration | NuGet |
| PPDS.Migration.Cli | .NET Tool |
| PPDS.Auth | NuGet |
| PPDS.Cli | .NET Tool |

### Consumed By

| Consumer | How | Breaking Change Impact |
|----------|-----|------------------------|
| ppds-tools | Reflects on attributes | Must update reflection code |
| ppds-tools | Shells to `ppds-migrate` CLI | Must update CLI calls |
| ppds-tools | Shells to `ppds` CLI | Must update CLI calls |
| ppds-demo | NuGet reference | Must update package reference |

### Version Sync Rules
Expand All @@ -235,7 +277,7 @@ See per-package changelogs:

- Adding required properties to `PluginStepAttribute` or `PluginImageAttribute`
- Changing attribute property types or names
- Changing `ppds-migrate` CLI arguments or output format
- Changing `ppds` CLI arguments or output format

---

Expand Down Expand Up @@ -288,30 +330,26 @@ ServicePointManager.UseNagleAlgorithm = false;
- [Service protection API limits](https://learn.microsoft.com/en-us/power-apps/developer/data-platform/api-limits)
- [Use bulk operation messages](https://learn.microsoft.com/en-us/power-apps/developer/data-platform/bulk-operations)

### Adaptive Rate Control
### DOP-Based Parallelism

The pool implements AIMD-based (Additive Increase, Multiplicative Decrease) rate control that:
- Starts at server-recommended parallelism
- Increases gradually after sustained success
- Backs off aggressively on throttle (50% reduction)
- Applies execution time-aware ceiling for slow operations
The pool uses Microsoft's `RecommendedDegreesOfParallelism` (from `x-ms-dop-hint` header) as the parallelism limit:

### Rate Control Presets
```
Total Parallelism = sum(DOP per connection)
```

| Preset | Use Case | Behavior |
|--------|----------|----------|
| `Conservative` | Production bulk jobs, migrations | Lower ceiling, avoids all throttles |
| `Balanced` | General purpose (default) | Balanced throughput vs safety |
| `Aggressive` | Dev/test with monitoring | Higher ceiling, accepts some throttles |
- **DOP varies by environment**: Trial environments report ~4, production can report up to 50
- **Hard cap of 52 per user**: Microsoft's enforced limit per Application User
- **Scale by adding connections**: 2 users at DOP=4 = 8 parallel requests

**Configuration:**
```json
{"Dataverse": {"AdaptiveRate": {"Preset": "Conservative"}}}
**Scaling Strategy:**
```
1 Application User @ DOP=4 → 4 parallel requests
2 Application Users @ DOP=4 → 8 parallel requests
4 Application Users @ DOP=4 → 16 parallel requests
```

**For production bulk operations, always use `Conservative`** to prevent throttle cascades.

See [ADR-0006](docs/adr/0006_EXECUTION_TIME_CEILING.md) for execution time ceiling details.
See [ADR-0005](docs/adr/0005_DOP_BASED_PARALLELISM.md) for details.

### Architecture Decision Records

Expand All @@ -321,30 +359,53 @@ See [ADR-0006](docs/adr/0006_EXECUTION_TIME_CEILING.md) for execution time ceili
| [0002](docs/adr/0002_MULTI_CONNECTION_POOLING.md) | Multiple Application Users multiply API quota |
| [0003](docs/adr/0003_THROTTLE_AWARE_SELECTION.md) | Route away from throttled connections |
| [0004](docs/adr/0004_THROTTLE_RECOVERY_STRATEGY.md) | Transparent throttle waiting without blocking |
| [0005](docs/adr/0005_POOL_SIZING_PER_CONNECTION.md) | Per-user pool sizing (52 per Application User) |
| [0006](docs/adr/0006_EXECUTION_TIME_CEILING.md) | Execution time-aware parallelism ceiling |
| [0007](docs/adr/0007_CONNECTION_SOURCE_ABSTRACTION.md) | IConnectionSource for custom auth methods |
| [0005](docs/adr/0005_DOP_BASED_PARALLELISM.md) | DOP-based parallelism (server-recommended limits) |
| [0006](docs/adr/0006_CONNECTION_SOURCE_ABSTRACTION.md) | IConnectionSource for custom auth methods |
| [0007](docs/adr/0007_UNIFIED_CLI_AND_AUTH.md) | Unified CLI and shared authentication profiles |

---

## 🖥️ CLI (PPDS.Migration.Cli)
## 🖥️ CLI (PPDS.Cli)

The unified CLI (`ppds`) uses stored authentication profiles. Create a profile once, then all commands use it automatically.

### Command Structure

### Authentication Modes
```
ppds
├── auth Authentication profile management
├── env Environment discovery and selection
├── data Data operations (export, import, copy, analyze)
├── schema Schema generation and entity listing
└── users User mapping for cross-environment migrations
```

| Mode | Flag | Use Case |
|------|------|----------|
| Interactive | `--auth interactive` (default) | Development, ad-hoc usage |
| Environment | `--auth env` | CI/CD pipelines |
| Managed Identity | `--auth managed` | Azure-hosted workloads |
### Quick Start

**CI/CD environment variables:**
```bash
DATAVERSE__URL=https://org.crm.dynamics.com
DATAVERSE__CLIENTID=your-client-id
DATAVERSE__CLIENTSECRET=your-secret
# Create profile (opens browser)
ppds auth create --name dev

# Select environment
ppds env select --environment "My Environment"

# Run commands
ppds data export --schema schema.xml --output data.zip
```

See [CLI README](src/PPDS.Migration.Cli/README.md) for full documentation.
### Authentication Methods

| Method | Flags | Use Case |
|--------|-------|----------|
| Interactive Browser | (default) | Development |
| Device Code | `--deviceCode` | Headless/SSH |
| Client Secret | `--applicationId` + `--clientSecret` + `--tenant` | CI/CD |
| Certificate | `--applicationId` + `--certificateDiskPath` + `--tenant` | Automated |
| Managed Identity | `--managedIdentity` | Azure-hosted |
| GitHub OIDC | `--githubFederated` + `--applicationId` + `--tenant` | GitHub Actions |
| Azure DevOps OIDC | `--azureDevOpsFederated` + `--applicationId` + `--tenant` | Azure Pipelines |

See [CLI README](src/PPDS.Cli/README.md) for full documentation.

---

Expand Down
19 changes: 17 additions & 2 deletions PPDS.Sdk.sln
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PPDS.Dataverse", "src\PPDS.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PPDS.Dataverse.Tests", "tests\PPDS.Dataverse.Tests\PPDS.Dataverse.Tests.csproj", "{738F9CC6-9EAC-4EA0-9B8B-DD6A5157A1F1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PPDS.Migration.Cli", "src\PPDS.Migration.Cli\PPDS.Migration.Cli.csproj", "{10DA306C-4AB2-464D-B090-3DA7B18B1C08}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PPDS.Cli", "src\PPDS.Cli\PPDS.Cli.csproj", "{10DA306C-4AB2-464D-B090-3DA7B18B1C08}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PPDS.Migration.Cli.Tests", "tests\PPDS.Migration.Cli.Tests\PPDS.Migration.Cli.Tests.csproj", "{45DB0E17-0355-4342-8218-2FD8FA545157}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PPDS.Cli.Tests", "tests\PPDS.Cli.Tests\PPDS.Cli.Tests.csproj", "{45DB0E17-0355-4342-8218-2FD8FA545157}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PPDS.Migration", "src\PPDS.Migration\PPDS.Migration.csproj", "{1642C0BD-0B5B-476D-86EB-73BE3CD9BD67}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PPDS.Auth", "src\PPDS.Auth\PPDS.Auth.csproj", "{5B3662DC-7BC8-4981-8F0F-30FB12CFD3F7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -115,6 +117,18 @@ Global
{1642C0BD-0B5B-476D-86EB-73BE3CD9BD67}.Release|x64.Build.0 = Release|Any CPU
{1642C0BD-0B5B-476D-86EB-73BE3CD9BD67}.Release|x86.ActiveCfg = Release|Any CPU
{1642C0BD-0B5B-476D-86EB-73BE3CD9BD67}.Release|x86.Build.0 = Release|Any CPU
{5B3662DC-7BC8-4981-8F0F-30FB12CFD3F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5B3662DC-7BC8-4981-8F0F-30FB12CFD3F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B3662DC-7BC8-4981-8F0F-30FB12CFD3F7}.Debug|x64.ActiveCfg = Debug|Any CPU
{5B3662DC-7BC8-4981-8F0F-30FB12CFD3F7}.Debug|x64.Build.0 = Debug|Any CPU
{5B3662DC-7BC8-4981-8F0F-30FB12CFD3F7}.Debug|x86.ActiveCfg = Debug|Any CPU
{5B3662DC-7BC8-4981-8F0F-30FB12CFD3F7}.Debug|x86.Build.0 = Debug|Any CPU
{5B3662DC-7BC8-4981-8F0F-30FB12CFD3F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5B3662DC-7BC8-4981-8F0F-30FB12CFD3F7}.Release|Any CPU.Build.0 = Release|Any CPU
{5B3662DC-7BC8-4981-8F0F-30FB12CFD3F7}.Release|x64.ActiveCfg = Release|Any CPU
{5B3662DC-7BC8-4981-8F0F-30FB12CFD3F7}.Release|x64.Build.0 = Release|Any CPU
{5B3662DC-7BC8-4981-8F0F-30FB12CFD3F7}.Release|x86.ActiveCfg = Release|Any CPU
{5B3662DC-7BC8-4981-8F0F-30FB12CFD3F7}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -127,5 +141,6 @@ Global
{10DA306C-4AB2-464D-B090-3DA7B18B1C08} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{45DB0E17-0355-4342-8218-2FD8FA545157} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
{1642C0BD-0B5B-476D-86EB-73BE3CD9BD67} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{5B3662DC-7BC8-4981-8F0F-30FB12CFD3F7} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
EndGlobalSection
EndGlobal
Loading
Loading