Skip to content

Add XML configuration transforms (XDT) to IIS deploy (Phase 7)

Placeholder ppxd requested to merge feat/iis-deploy-config-transforms into main

Summary

Mirrors Octopus's Octopus.Features.ConfigurationTransforms feature (ConfigurationTransformsBehaviour.cs:84-101). When enabled, the deploy script applies XDT (XML Document Transform) overlays to every *.config file under WebRoot:

  • Auto-discovery: <base>.Release.config over <base>.config
  • Auto-discovery: <base>.{EnvironmentName}.config over <base>.config
  • Explicit: CSV of transform.config => target.config entries

Pairs with Phase 6 (.NET Configuration Variables). PS1 hook order matches Octopus pipeline: ConfigurationTransforms → ConfigurationVariables → IIS configure.

What ships

Production (+200 LOC across 3 files + 1 workflow update)

Change Notes
3 new constants in IISDeployProperties ConfigurationTransformsEnabled + EnvironmentName + AdditionalTransforms
Builder routes AdditionalTransforms through base64 Multi-line CSV needs newline preservation; reused the existing base64 emission path
Update-IISConfigurationTransforms PS1 function Probes for Microsoft.Web.XmlTransform.dll (GAC + NuGet global cache); auto-discovers Release + env overlays; processes explicit CSV transforms; skip-itself logic for <base>.Release
Workflow installs Microsoft.Web.Xdt 3.0.0 NuGet global cache → PS1 probe resolves it

Test code (+435 LOC, 10 new tests across 3 tiers)

Tier New What
🟢 Drift detector 1 XDT function presence + type references + auto-transform name list + ordering BEFORE ConfigurationVariables (Octopus pipeline)
🟢 Unit 3 3 new properties in preamble; AdditionalTransforms via base64 (CSV with newlines preserved); empty defaults
🟡 Pipeline E2E 1 Theory × 2 Variable substitution: #{EnvName} resolves to literal env name before serialisation
🟢 Real-host 4 Auto Release transform; env-specific transform (Staging); explicit AdditionalTransforms with non-standard naming; feature-disabled gate

Test infrastructure

IsMicrosoftWebXmlTransformAvailable() probe — tests skip cleanly when the DLL isn't installed (dev hosts without VS Build Tools); CI installs the package so tests run there.

Octopus alignment notes

The agent-side function mirrors ConfigurationTransformsBehaviour.cs:80-117 semantically: auto-discovery iterates Release + environment-name overlays; explicit transforms via CSV => separator; uses the IDENTICAL Microsoft.Web.XmlTransform.dll Octopus uses, so transform semantics (SetAttributes, Insert, Replace, Locator=Match/Condition/XPath) are byte-for-byte the same.

Squid Phase 7 covers Release + EnvironmentName. Octopus also auto-discovers <base>.{TenantName}.config — deferred because Squid doesn't have a tenant concept yet.

Cumulative state

  • Unit: 63 → 67 (+4)
  • Pipeline E2E: 12 → 14 (+2)
  • Real-host: 42 → 46 (+4)

Test plan

  • dotnet test --filter FullyQualifiedName~IISDeploy on macOS — 67 unit tests green
  • dotnet test --filter Category=IISDeployE2E on macOS — 46 real-host tests skip cleanly
  • dotnet build 0 errors
  • CI run on windows-latest: workflow installs Microsoft.Web.Xdt → 4 new XDT tests against real config files

Out of scope

Phase Scope
8 SubstituteInFiles — #{X} token replacement INSIDE files
9 JSON/YAML structured configuration variables
10 Package extraction
11 Custom installation directory + purge
12 IIS certificate auto-import + private-key ACL

Breaking-change risk

None. Pure additive: 3 new properties, new builder routing (existing tests pass unchanged), new PS1 function + gate (no-op when disabled), new workflow step (idempotent NuGet install).

Merge request reports

Loading