feat: add txc env list/create/update/delete commands#149
Open
TomProkop wants to merge 6 commits into
Open
Conversation
Implement tenant-level environment listing and creation via the Power Platform BAP admin API: - txc env list: lists Dataverse-backed environments with --filter and --type options, table/JSON output - txc env create: provisions environments with full option parity (type, region, currency, language, domain, templates, security group, user), fire-and-forget by default with --wait opt-in New backend infrastructure: - BapAdminApiClient: shared authenticated BAP transport (DRY) - BapEndpointProvider: cloud-to-BAP-host mapping - PowerPlatformEnvironmentProvisioner: validation, catalog lookups, create POST, async polling - EnvironmentManagementService: profile-resolving orchestrator - IEnvironmentManagementService: Core-level abstraction + DTOs Extends EnvironmentType enum with Teams (5) and SubscriptionBasedTrial (6). Refactors PowerPlatformEnvironmentCatalog to use shared BapAdminApiClient. Adds 5 provisioner unit tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Re-acquire bearer token on each poll iteration in PollUntilCompleteAsync so long-running waits (up to 60 min) don't fail with 401 when the initial token expires. MSAL cache makes this a no-op when the token is still valid. - Add explanatory comment on [CliIdempotent] for env create: not truly idempotent but matches all other create commands and avoids the wrong UX of [CliDestructive] + --yes for a create operation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Permanently deletes a Power Platform environment via the BAP admin API. Follows the PAC CLI pattern: pre-flight validateDelete check, then DELETE with async polling. - [CliDestructive] + IDestructiveCommand with --yes confirmation - --wait/--max-wait-minutes for blocking mode - --allow-production safety guard inherited from ProfiledCliCommand - Token refresh on each poll iteration (same fix as create) - Docs updated with delete section and MCP tool mapping Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update environment properties via PATCH: display name, type (SKU conversion e.g. Sandbox→Production), and security group. Only supplied options are patched — omitted fields are left unchanged. - [CliIdempotent] — same values produce the same result - Passing empty GUID to --security-group-id clears the restriction - Domain update intentionally excluded (breaks environment URLs) - Docs updated with update section and examples Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- EnvironmentDeleteCliCommand now overrides PreExecuteAsync to resolve the *target* environment's type from the tenant catalog, instead of checking the profile's connection (which is unrelated to the environment being deleted). This prevents false negatives (deleting production via sandbox profile) and false positives (blocking sandbox deletion via production profile). - Remove --max-wait-minutes from env create and env delete to match SolutionImportCliCommand which only exposes --wait with a hardcoded timeout. Consistent surface across all long-running commands. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix intro to mention all 4 CRUD commands (was only list/create)
- Fix auth and MCP sections ('Both commands' → 'All commands')
- Remove internal API references (BAP admin API) from user-facing
docs — users shouldn't need to know which Microsoft API powers
the commands
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds tenant-scoped Power Platform environment lifecycle support to txc by introducing txc env list/create/update/delete, backed by a shared BAP admin API transport plus an orchestration service that resolves the active profile for admin identity.
Changes:
- Introduces
IEnvironmentManagementService+EnvironmentManagementServiceand wires new CLI commands for env list/create/update/delete. - Adds BAP admin API infrastructure (
BapAdminApiClient, endpoint provider, JSON options) and a newPowerPlatformEnvironmentProvisionerfor create/update/delete with optional long-polling. - Refactors
PowerPlatformEnvironmentCatalogto reuse the shared BAP client and centralizes SKU parsing.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/TALXIS.CLI.Tests/Config/Providers/Dataverse/PowerPlatformEnvironmentProvisionerTests.cs | Adds unit tests for environment provisioning flows and validation. |
| src/TALXIS.CLI.Platform.PowerPlatform.Control/PowerPlatformEnvironmentProvisioner.cs | Implements create/update/delete via BAP admin API including polling and catalog validation. |
| src/TALXIS.CLI.Platform.PowerPlatform.Control/PowerPlatformEnvironmentCatalog.cs | Refactors list/get to use shared BAP transport + centralized SKU parsing. |
| src/TALXIS.CLI.Platform.PowerPlatform.Control/EnvironmentSkuParser.cs | Centralizes admin API environmentSku → EnvironmentType mapping. |
| src/TALXIS.CLI.Platform.PowerPlatform.Control/EnvironmentProvisioning.cs | Adds request/response DTOs + provisioner interface for env lifecycle operations. |
| src/TALXIS.CLI.Platform.PowerPlatform.Control/EnvironmentManagementService.cs | Orchestrates profile resolution and delegates to catalog/provisioner for env lifecycle. |
| src/TALXIS.CLI.Platform.PowerPlatform.Control/Bap/BapJsonOptions.cs | Adds dedicated JSON serialization options for BAP request bodies. |
| src/TALXIS.CLI.Platform.PowerPlatform.Control/Bap/BapEndpointProvider.cs | Centralizes cloud→host mapping, token audience, and API versions for BAP calls. |
| src/TALXIS.CLI.Platform.PowerPlatform.Control/Bap/BapAdminApiClient.cs | Adds shared authenticated HTTP transport for BAP admin API calls. |
| src/TALXIS.CLI.Platform.Dataverse.Runtime/DependencyInjection/DataverseProviderServiceCollectionExtensions.cs | Registers the new provisioner and environment management service in DI. |
| src/TALXIS.CLI.Features.Environment/EnvironmentListCliCommand.cs | Adds txc env list with filter/type output. |
| src/TALXIS.CLI.Features.Environment/EnvironmentCreateCliCommand.cs | Adds txc env create with optional wait and catalog-validated inputs. |
| src/TALXIS.CLI.Features.Environment/EnvironmentUpdateCliCommand.cs | Adds txc env update sparse patch support. |
| src/TALXIS.CLI.Features.Environment/EnvironmentDeleteCliCommand.cs | Adds txc env delete with --yes, optional wait, and production safety guard. |
| src/TALXIS.CLI.Features.Environment/EnvironmentCliCommand.cs | Registers the new env subcommands under txc environment / txc env. |
| src/TALXIS.CLI.Core/Platforms/PowerPlatform/IEnvironmentManagementService.cs | Adds Core-level abstraction + DTOs for env lifecycle commands. |
| src/TALXIS.CLI.Core/Model/EnvironmentType.cs | Extends EnvironmentType with Teams and SubscriptionBasedTrial. |
| docs/environment-lifecycle.md | Documents the new txc env lifecycle commands and MCP tool exposure. |
| docs/architecture.md | Updates architecture docs to mention env lifecycle under Features.Environment. |
Comment on lines
+64
to
+66
| Assert.NotNull(capturedBody); | ||
| using var doc = JsonDocument.Parse(capturedBody!); | ||
| var props = doc.RootElement.GetProperty("properties"); |
Comment on lines
+167
to
+187
| private static void ValidateRequest(EnvironmentCreateRequest request) | ||
| { | ||
| if (request.EnvironmentType == EnvironmentType.Default) | ||
| throw new ArgumentException("Environment type 'Default' cannot be created — it is the tenant's auto-provisioned environment."); | ||
|
|
||
| if (request.EnvironmentType == EnvironmentType.Teams) | ||
| { | ||
| if (request.SecurityGroupId is null || request.SecurityGroupId == Guid.Empty) | ||
| throw new ArgumentException("A '--security-group-id' is required when creating a 'Teams' environment."); | ||
| } | ||
| else if (string.IsNullOrWhiteSpace(request.DisplayName)) | ||
| { | ||
| throw new ArgumentException("A display name ('--name') is required for this environment type."); | ||
| } | ||
|
|
||
| if (request.UserObjectId is { } userId && userId != Guid.Empty | ||
| && request.EnvironmentType != EnvironmentType.Developer) | ||
| { | ||
| throw new ArgumentException("'--user' is only supported when creating a 'Developer' environment."); | ||
| } | ||
| } |
Comment on lines
+33
to
+50
| string? capturedBody = null; | ||
| var operationLocation = new Uri("https://api.bap.microsoft.com/operations/op-1"); | ||
|
|
||
| var http = new FakeHttpClientFactoryWrapper(req => | ||
| { | ||
| if (req.Method == HttpMethod.Get && req.RequestUri!.AbsolutePath.Contains("environmentCurrencies")) | ||
| return Json(HttpStatusCode.OK, CurrencyCatalog()); | ||
|
|
||
| if (req.Method == HttpMethod.Post) | ||
| { | ||
| capturedBody = req.Content!.ReadAsStringAsync().Result; | ||
| var resp = Json(HttpStatusCode.Accepted, EnvironmentBody("Provisioning")); | ||
| resp.Headers.Location = operationLocation; | ||
| return resp; | ||
| } | ||
|
|
||
| return new HttpResponseMessage(HttpStatusCode.BadRequest); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds full CRUD for tenant-level Power Platform environment management:
txc env list--filterand--typefilteringtxc env create--waitto block.txc env updatetxc env delete--yesconfirmation required,--allow-productionsafety guard resolves the target environment's type.Architecture
Key design decisions
--allow-productionon delete resolves the target environment's type from the tenant catalog (not the profile's connection), since these are tenant-level commands where profile ≠ target.--waitfollows the same pattern asSolutionImportCliCommand— no--max-wait-minutes, hardcoded 60-min timeout.[CliIdempotent]on create matches all other create commands (PublisherCreate, SolutionCreate). Documented that env creation is not truly idempotent.[CliDestructive]on delete withIDestructiveCommand+--yes, matching PublisherDelete, SolutionDelete, etc.--domainon update — changing the domain breaks environment URLs.Changes
EnvironmentTypeenum withTeams(5) andSubscriptionBasedTrial(6)PowerPlatformEnvironmentCatalogto use sharedBapAdminApiClientEnvironmentCliCommand.Children(MCP auto-exposesenvironment_list/environment_create/environment_update/environment_delete)docs/environment-lifecycle.mdMCP integration
txc env listenvironment_listReadOnlyHinttxc env createenvironment_createIdempotentHinttxc env updateenvironment_updateIdempotentHinttxc env deleteenvironment_deleteDestructiveHint