Configuration Transforms

Last updated

The Configuration Transforms feature is one of the configuration features you can enable as you define the steps in your deployment process.

If this feature is enabled, Tentacle will also look for any files that follow the Microsoft web.config transformation process – even files that are not web.config files! Keep reading for examples.

Configuration Transforms screenshot

An example web.config transformation that removes the <compilation debug="true"> attribute is below:

<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <system.web>
    <compilation xdt:Transform="RemoveAttributes(debug)" />
  </system.web>
</configuration>

Testing configuration transforms
The team at AppHarbor created a useful tool to help test configuration file transformations.

Naming Configuration Transform Files

This feature will run your configuration transforms based on looking for transform files named with the following conventions. The configuration transformation files can either be named *.Release.config, *.<Environment>.config, or *.<Tenant>.config and will be executed in this order:

  1. *.Release.config
  2. *.<Environment>.config
  3. *.<Tenant>.config

For an ASP.NET Web Application, suppose you have the following files in your package:

  • Web.config
  • Web.Release.config
  • Web.Production.config
  • Web.Test.config

When deploying to an environment named "Production", Octopus will execute the transforms in this order: Web.Release.config, followed by Web.Production.config.

For other applications, like Console or Windows Service applications, suppose you have the following in your package:

  • YourService.exe.config
  • YourService.exe.Release.config
  • YourService.exe.Production.config
  • YourService.exe.Test.config

When deploying to an environment named "Test", Octopus will execute the transforms in this order: YourService.exe.Release.config, followed by YourService.exe.Test.config.

You can see how this is actually done by our open source Calamari project.

Windows Service and Console Application configuration transforms need special treatment
Octopus looks for configuration transform files that match your executable's configuration file. Visual Studio has built-in support for this scenario for ASP.NET Web Applications, but it doesn't offer the same support for Windows Services and Console applications - you will need to take care of this yourself.

In Visual Studio your configuration file will be app.config and is renamed during the build process to match the executable - e.g., The app.config file for YourService.exe is renamed to YourService.exe.config.

To make sure Octopus can run the configuration transforms for your Windows Services and Console Applications:

  1. Make sure you name your configuration transform files properly based on the target executable filename e.g., YourService.exe.Release.config, YourService.exe.Production.config
  2. Set the Copy to Output Directory property for the configuration transform files to Copy If Newer.
  3. Double-check the package you build for deployment actually contains the YourService.exe.config and all of the expected configuration transform files.

Additional Configuration Transforms

You might have additional transforms to run outside of Debug, Environment or Release. You can define these in the Additional transforms box. If defined, these transforms will run regardless of the state of the Automatically run configuration transformation files checkbox.

Octopus supports explicit, wildcard and relative path configuration transform definitions on any XML file with any file extension. Octopus will iterate through all files in all directories (ie, recursively) of your deployed application to find any matching files. Your target file also must exist; it will not be created by Octopus. As a general rule, you should not include the path to the files unless the transform file is in a different directory to the target, in which case it needs to be relative to the target file (as explained below in the relative path scenario). Absolute paths are supported for transform files, but not for target files.

Explicit

Explicit config transform

Transform.config => Target.config

The above transform definition will apply Transform.config to Target.config when the files are in the same directory.

Relative Path

Relative path config transform

Path\Transform.config => Target.config

The above transform definition will apply Transform.config to Target.config when Transform.config is in the directory Path relative to Target.config.

Wildcard

Wildcards can be used to select any matching file. For example, *.config will match app.config as well as web.config.

They can be used anywhere in the transform filename (the left side), but only at the start of the destination filename (the right side).

Wildcard config transform

*.Transform.config => *.config

The above transform definition will apply foo.Transform.config to foo.config and bar.Transform.config to bar.config.

Wildcard config transform

*.Transform.config => Target.config

The above transform definition will apply foo.Transform.config and bar.Transform.config to Target.config.

Wildcard config transform

Transform.config => Path\*.config

The above transform definition will apply Transform.config to foo.config and bar.config when foo.config and bar.config are in the directory Path relative to Transform.config.

If you would like to define the order of all of your transformations, if you list them in the order of transformation inside the Additional transforms feature then Octopus will use that order to run the transforms.

Suppressing Configuration Transformation Errors

As of Octopus 3.0, any exceptions that are thrown by the Microsoft config transformation process will be treated as errors by Octopus, failing the deployment. This typically involves explicit transformations for elements that don't exist in the source .config file and will surface with errors similar to the below:

Warning    14:56:06
(31:18) Argument 'debug' did not match any attributes
Error    14:56:06
Object reference not set to an instance of an object.
System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.Web.XmlTransform.XmlTransformationLogger.LogWarning(XmlNode referenceNode, String message, Object[] messageArgs)
   at Microsoft.Web.XmlTransform.RemoveAttributes.Apply()
   at Microsoft.Web.XmlTransform.Transform.ApplyOnAllTargetNodes()
Fatal    14:56:06
One or more errors were encountered when applying the XML configuration transformation file: e:\Octopus\Applications\MyEnv\MyApp\1.0.0.1234\Web.Release.config. View the deployment log for more details, or set the special variable Octopus.Action.Package.IgnoreConfigTranformationErrors to True to ignore this error.

To suppress these errors and report them as informational only, use the Octopus.Action.Package.IgnoreConfigTransformationErrors variable defined in the System Variables section of the documentation.

PowerShell

If these conventions aren’t enough to configure your application, you can always use PowerShell to perform custom configuration tasks. Variables will be passed to your PowerShell script, and PowerShell has rich XML API's.

Troubleshooting

If you're new to configuration transformation, first check the package(s) part of the deployment are structured and contain what you expect. Following on from that review the deployment logs and output of the package(s) on your deployment targets to get investigate any unexpected behavior. You can try using the Octopus.Action.Package.TreatConfigTransformationWarningsAsErrors variable defined in the System Variables section of the documentation while you set it up the first time.

Advanced Configuration Transforms Examples

Configuration transforms can sometimes be complicated to setup. As a general rule, its best to have both configuration file and transform file in the same directory, however, this is not always achievable.

This page lists the supported scenarios and the transform definitions required to apply the transform.

Supported scenarios





Target
Absolute Path Relative Path Filename

Wildcard Prefixed

Absolute Path

Wildcard Prefixed

Relative Path

Wildcard Prefixed

Filename




Transform




Absolute Path not supported not supported Example not supported Example Example
Relative Path not supported Example Example not supported Example Example
Filename not supported Example Example not supported Example Example
Wildcard Absolute Path not supported not supported Example not supported Example Example
Wildcard Relative Path not supported Example Example not supported Example Example
Wildcard Filename not supported Example Example not supported Example Example

Wildcard support
Please note that wildcards can be used anywhere in the transform filename (eg *.mytransform.config or web.*.config), but can only be used at the start of the target filename (eg *.mytransform.config, but not web.*.config)

Enable detailed transform diagnostics logging
To enable detailed logging of the process that searches for config transformations, add the variable Octopus.Action.Package.EnableDiagnosticsConfigTransformationLoggingand set its value to True.

Transform and target are in the same directory

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─web.config
└─web.mytransform.config

Then the transform web.mytransform.config => web.config will:

  • Apply the transform web.mytransform.config to file web.config

Applying a transform against a target in a different folder

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─config
| └─web.config
└─web.mytransform.config

Then the transform web.mytransform.config => config\web.config will:

  • Apply the transform web.mytransform.config to file config\web.config

Transform and multiple targets are in the same directory

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─app.config
├─connstrings.mytransform.config
└─web.config

Then the transform connstrings.mytransform.config => *.config will:

  • Apply the transform connstrings.mytransform.config to file web.config

  • Apply the transform connstrings.mytransform.config to file app.config

Applying a transform against multiple targets in a different directory

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─config
| ├─app.config
| └─web.config
└─connstrings.mytransform.config

Then the transform connstrings.mytransform.config => config\*.config will:

  • Apply the transform connstrings.mytransform.config to file config\web.config

  • Apply the transform connstrings.mytransform.config to file config\app.config

Using an absolute path to the transform

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─subdir
| └─web.config
└─web.config

And the following files exist:

c:\
└─transforms
  └─web.mytransform.config

Then the transform c:\transforms\web.mytransform.config => web.config will:

  • Apply the transform c:\transforms\web.mytransform.config to file web.config
  • Apply the transform c:\transforms\web.mytransform.config to file subdir\web.config

Applying a transform with an absolute path to a target in the extraction path root

This transform is available in Octopus Server 3.8.8 (Calamari 3.6.43) or later

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─subdir
| └─web.config
└─web.config

And the following files exist:

c:\
└─transforms
  └─web.mytransform.config

Then the transform c:\transforms\web.mytransform.config => .\web.config will:

  • Apply the transform c:\transforms\web.mytransform.config to file web.config

Applying a transform with an absolute path to a target relative to the extraction path

This transform is available in Octopus Server 3.8.8 (Calamari 3.6.43) or later

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─subdir
| └─web.config
└─web.config

And the following files exist:

c:\
└─transforms
  └─web.mytransform.config

Then the transform c:\transforms\web.mytransform.config => .\subdir\web.config will:

  • Apply the transform c:\transforms\web.mytransform.config to file subdir\web.config

Applying a transform with an absolute path against multiple files in a different directory

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
└─config
  ├─app.config
  └─web.config

And the following files exist:

c:\
└─transforms
  └─connstrings.mytransform.config

Then the transform c:\transforms\connstrings.mytransform.config => config\*.config will:

  • Apply the transform c:\transforms\connstrings.mytransform.config to file config\web.config

  • Apply the transform c:\transforms\connstrings.mytransform.config to file config\app.config

Using an absolute path to the transform, and applying it against multiple files

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─app.config
└─web.config

And the following files exist:

c:\
└─transforms
  └─connstrings.mytransform.config

Then the transform c:\transforms\connstrings.mytransform.config => *.config will:

  • Apply the transform c:\transforms\connstrings.mytransform.config to file web.config

  • Apply the transform c:\transforms\connstrings.mytransform.config to file app.config

Applying a transform from a different directory

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─transforms
| └─web.mytransform.config
└─web.config

Then the transform transforms\web.mytransform.config => web.config will:

  • Apply the transform transforms\web.mytransform.config to file web.config

Applying a transform to a target in a sibling directory

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─config
| └─web.config
└─transforms
  └─web.mytransform.config

Then the transform transforms\web.mytransform.config => config\web.config will:

  • Apply the transform transforms\web.mytransform.config to file config\web.config

Applying a transform from a different directory against multiple files

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─app.config
├─transforms
| └─connstrings.mytransform.config
└─web.config

Then the transform transforms\connstrings.mytransform.config => *.config will:

  • Apply the transform transforms\connstrings.mytransform.config to file web.config

  • Apply the transform transforms\connstrings.mytransform.config to file app.config

Applying a transform to multiple targets in a sibling directory

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─config
| ├─app.config
| └─web.config
└─transforms
  └─connstrings.mytransform.config

Then the transform transforms\connstrings.mytransform.config => config\*.config will:

  • Apply the transform transforms\connstrings.mytransform.config to file config\web.config

  • Apply the transform transforms\connstrings.mytransform.config to file config\app.config

Applying multiple transforms to a single target where both are in the same directory

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─connstrings.mytransform.config
├─security.mytransform.config
└─web.config

Then the transform *.mytransform.config => web.config will:

  • Apply the transform security.mytransform.config to file web.config

  • Apply the transform connstrings.mytransform.config to file web.config

Wildcard transform with wildcard in the middle of the filename to a single target where both are in the same directory

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─MyApp.connstrings.octopus.config
├─MyApp.nlog_octopus.config
└─MyApp.WinSvc.exe.config

Then the transform MyApp.*.octopus.config => MyApp.WinSvc.exe.config will:

  • Apply the transform MyApp.connstrings.octopus.config to file MyApp.WinSvc.exe.config

Applying multiple transforms to a single target in a different directory

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─config
| └─web.config
├─connstrings.mytransform.config
└─security.mytransform.config

Then the transform *.mytransform.config => config\web.config will:

  • Apply the transform security.mytransform.config to file config\web.config

  • Apply the transform connstrings.mytransform.config to file config\web.config

Applying multiple transforms against multiple targets

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─app.config
├─app.mytransform.config
├─web.config
└─web.mytransform.config

Then the transform *.mytransform.config => *.config will:

  • Apply the transform web.mytransform.config to file web.config

  • Apply the transform app.mytransform.config to file app.config

Applying multiple transforms against multiple targets in a different directory

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─app.mytransform.config
├─config
| ├─App.config
| └─web.config
└─web.mytransform.config

Then the transform *.mytransform.config => config\*.config will:

  • Apply the transform web.mytransform.config to file config\web.config

  • Apply the transform app.mytransform.config to file config\app.config

Applying multiple absolute path transforms to the same target file

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─subdir
| └─web.config
└─web.config

And the following files exist:

c:\
└─transforms
  ├─connstrings.mytransform.config
  └─security.mytransform.config

Then the transform c:\transforms\*.mytransform.config => web.config will:

  • Apply the transform c:\transforms\connstrings.mytransform.config to file web.config

  • Apply the transform c:\transforms\security.mytransform.config to file web.config

  • Apply the transform c:\transforms\connstrings.mytransform.config to file subdir\web.config

  • Apply the transform c:\transforms\security.mytransform.config to file subdir\web.config

Using an absolute path wildcard transform and multiple targets

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─app.config
├─subdir
| ├─app.config
| └─web.config
└─web.config

And the following files exist:

c:\
└─transforms
  ├─app.mytransform.config
  └─web.mytransform.config

Then the transform c:\transforms\*.mytransform.config => *.config will:

  • Apply the transform c:\transforms\web.mytransform.config to file web.config

  • Apply the transform c:\transforms\app.mytransform.config to file app.config

  • Apply the transform c:\transforms\web.mytransform.config to file subdir\web.config

  • Apply the transform c:\transforms\app.mytransform.config to file subdir\app.config

Using an absolute path for multiple transforms against multiple relative files

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
└─config
  ├─app.config
  └─web.config

And the following files exist:

c:\
└─transforms
  ├─app.mytransform.config
  └─web.mytransform.config

Then the transform c:\transforms\*.mytransform.config => config\*.config will:

  • Apply the transform c:\transforms\web.mytransform.config to file config\web.config

  • Apply the transform c:\transforms\app.mytransform.config to file config\app.config

Applying multiple relative transforms against a specific target

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─transforms
| ├─connstrings.mytransform.config
| └─security.mytransform.config
└─web.config

Then the transform transforms\*.mytransform.config => web.config will:

  • Apply the transform transforms\connstrings.mytransform.config to file web.config

  • Apply the transform transforms\security.mytransform.config to file web.config

Applying multiple transforms in a different directory to a single target in a different directory

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─config
| └─web.config
└─transforms
  ├─connstrings.mytransform.config
  └─security.mytransform.config

Then the transform transforms\*.mytransform.config => config\web.config will:

  • Apply the transform transforms\connstrings.mytransform.config to file config\web.config

  • Apply the transform transforms\security.mytransform.config to file config\web.config

Applying transforms from a different directory to multiple targets

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─app.config
├─transforms
| ├─app.mytransform.config
| └─web.mytransform.config
└─web.config

Then the transform transforms\*.mytransform.config => *.config will:

  • Apply the transform transforms\web.mytransform.config to file web.config

  • Apply the transform transforms\app.mytransform.config to file app.config

Applying transforms from a different directory to targets in a different directory

Given a package which has the structure:

Acme.Core.1.0.0.nupkg
├─config
| ├─app.config
| └─web.config
└─transforms
  ├─app.mytransform.config
  └─web.mytransform.config

Then the transform transforms\.mytransform.config => config\.config will:

  • Apply the transform transforms\web.mytransform.config to file config\web.config

  • Apply the transform transforms\app.mytransform.config to file config\app.config