Skip to content

feat: add txc env list/create/update/delete commands#149

Open
TomProkop wants to merge 6 commits into
masterfrom
feat/env-list-create
Open

feat: add txc env list/create/update/delete commands#149
TomProkop wants to merge 6 commits into
masterfrom
feat/env-list-create

Conversation

@TomProkop

@TomProkop TomProkop commented Jun 12, 2026

Copy link
Copy Markdown
Member

Summary

Adds full CRUD for tenant-level Power Platform environment management:

Command Description
txc env list Lists Dataverse-backed environments with --filter and --type filtering
txc env create Provisions environments (type, region, currency, language, domain, templates, security group, user). Fire-and-forget by default, --wait to block.
txc env update Updates environment properties: name, type (SKU conversion), security group. Sparse patch — only supplied options are changed.
txc env delete Permanently deletes an environment. --yes confirmation required, --allow-production safety guard resolves the target environment's type.

Architecture

  • BapAdminApiClient — shared authenticated transport (DRY across catalog, provisioner, update, delete)
  • PowerPlatformEnvironmentProvisioner — validation, per-region catalog lookups (currency/language/templates), create/update/delete + async polling
  • EnvironmentManagementService — profile-resolving orchestrator bridging Core DTOs ↔ control-plane types
  • IEnvironmentManagementService — Core-level abstraction so CLI commands don't depend on control-plane internals

Key design decisions

  • --allow-production on 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.
  • --wait follows the same pattern as SolutionImportCliCommand — 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 with IDestructiveCommand + --yes, matching PublisherDelete, SolutionDelete, etc.
  • Token refresh during long polling loops — re-acquires on each iteration so tokens don't expire during 60-min waits.
  • No --domain on update — changing the domain breaks environment URLs.
  • No API internals leaked — docs and help text never mention BAP, admin API, etc.

Changes

  • 16 new files, 5 modified
  • Extends EnvironmentType enum with Teams (5) and SubscriptionBasedTrial (6)
  • Refactors PowerPlatformEnvironmentCatalog to use shared BapAdminApiClient
  • Registers all commands in EnvironmentCliCommand.Children (MCP auto-exposes environment_list / environment_create / environment_update / environment_delete)
  • 5 provisioner unit tests; all 582 existing tests pass
  • New doc: docs/environment-lifecycle.md

MCP integration

CLI command MCP tool name Access hint
txc env list environment_list ReadOnlyHint
txc env create environment_create IdempotentHint
txc env update environment_update IdempotentHint
txc env delete environment_delete DestructiveHint

TomProkop and others added 6 commits June 12, 2026 16:24
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>
@TomProkop TomProkop changed the title feat: add txc env list and txc env create commands feat: add txc env list/create/update/delete commands Jun 12, 2026
@honzakostejn honzakostejn requested a review from Copilot June 12, 2026 15:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 + EnvironmentManagementService and wires new CLI commands for env list/create/update/delete.
  • Adds BAP admin API infrastructure (BapAdminApiClient, endpoint provider, JSON options) and a new PowerPlatformEnvironmentProvisioner for create/update/delete with optional long-polling.
  • Refactors PowerPlatformEnvironmentCatalog to 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 environmentSkuEnvironmentType 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);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants