Showing posts with label build & release. Show all posts
Showing posts with label build & release. Show all posts

Tuesday, 6 February 2018

TFS 2017 build & release with config transforms

I love config transforms. I do not love TFS environment variables.

These are notes on how to have two builds (debug and release) but multiple target environments (e.g. dev, test and prod) with different web.config settings applied during the release steps (which is done by web.config transforms).

The high level process is:

  • Setup a debug and release build. The debug build of the code goes to dev server, the release build goes to test and prod servers.
  • During the release to each environment the config transforms are applied to ensure the config is relevant to the environment it is going to (e.g. connects to right database/webservices, has right app settings)
You can do transforms during the build stage, but doing it during the release phase is better because:


  1. The code going to both test and prod is identical (with an altered config). 
  2. You don't have to do a build for each environment. You can just do a debug and release build which is quicker if you have a lot of environments
  3. You don't have to change the project file to add in a transform step. That step will actually apply to local builds which is a pain (you can create a 'localdebug' config and use that local but who can be bothered). Although I guess you could do an XDT Transform step during your build without changing the proj file (haven't tried this, but should work).




Do the build


Setup the BuildConfiguration to do a debug and release build by updating BuildConfiguration variable and turning on multi-configuration.



Configure artifact names so the different builds can be distinguished:

This means two builds happen:



Wow.

Do the release

The artifact can be copied to the final website location (e.g. the IIS directory) and the config transform applied there, but there will be a short time where the code will be deployed and the transform not applied - for that time users accessing will get the site with non-transformed (e.g. development) config. So process is: 
  1. stick the artifact files in a temp/working directory
  2. do the transform for the environment
  3. move the files to the final website directory

Create release definition(s)

Copy the files from the artifact to a working directory (create the directory manually (or add a step to do it) first or this copy step will fail)

Apply the config transform to the files in the working directory (this comes from the marketplace https://marketplace.visualstudio.com/items?itemName=qetza.xdttransform#overview)
How does this work when it doesn't have any credentials associated with the step? Dunno. Maybe because the previous copy files step does pass credentials, so the process is already considered authorised on the remove machine.


Copy the files from the working directory to the website directory



Optional: delete the config transforms and clean the working directory:
You have to get the remote delete step from the marketplace. There is a bug with it where if your path has a space you need to wrap it in single quotes.

Sunday, 30 April 2017

TFS 2015 build configurations and config transforms

How to get the same code deployed to different environments but deploy debug builds to dev and release builds to prod (and additional builds to other environments), also taking into account configuration transformations.


Using the Configuration Manager in Visual Studio setup the appropriate configurations e.g. add a Test configuration. Debug goes to dev, Test goes to test, Release goes to production. Test and Release should have the same build configuration (if you want test environment code same as prod env code) but will have different config transforms applied (e.g. the connection strings for dbs will be different).


In Visual Studio go to the Build tab on the project properties and configure each configuration e.g. make the test configuration the same as the release configuration


Add any additional web.config transform files that are needed.  For a web.config you can right click. For an app.config project add each file manually, then unload the project file and edit it.  Make each of the transforms dependent on the app.config file.



Update the transform configs to have environment specific values; the application of these are controlled by the transform attributes. Only include elements that need to be changed. Items in transform will be merged into the original config i.e. you don't have to repeat data in here that isn't changing


In TFS config transforms will not happen automatically. To get this to work we manually add a step into the project file. This won't effect local builds. In Visual Studio unload the project. Edit the project file and add the transform step - it differs for app.config and web.config so add appropriately.

Web.config

  <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
  <Target Name="ApplyTransform" Condition="Exists('Web.$(Configuration).config')">
    <TransformXml Source="web.config" Transform="Web.$(Configuration).config" Destination="Web.config" />
  </Target>
  <Target Name="BeforeBuild">
    <Exec Command="attrib -r Web.config" />
    <CallTarget Targets="ApplyTransform" />
  </Target>


  <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
  <Target Name="AfterCompile" Condition="exists('app.$(Configuration).config')">
    <!-- Generate transformed app config in the intermediate directory -->
    <TransformXml Source="app.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config" Transform="app.$(Configuration).config" />
    <!-- Force build process to use the transformed configuration file from now on. -->
    <ItemGroup>
      <AppConfigWithTargetPath Remove="app.config" />
      <AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
        <TargetPath>$(TargetFileName).config</TargetPath>
      </AppConfigWithTargetPath>
    </ItemGroup>
  </Target>



Create a build for the solution in TFS.  There is a variable on the build called BuildConfiguration - every time this build is run it will compile the code using that configuration. E.g. if it is set to debug then the debug code will be what is released (i.e. it will go to dev, test and prod :( ).
To make TFS build all configurations from the same code set update the BuildConfiguration to be debug,test,release (a comma delimited list)


On the Options tab select the 'Multi-configuration' option, and in Multipliers enter the value BuildConfiguration


On the Copy Files action make the target folder contain the value of the BuildConfiguration (each in their own dir)


On the Publish Build Artifacts action but the BuildConfiguration value into the artifact name


When the build is run it will do a build for all three configurations



Three properly named artifacts will be created


On the release each environment has a file copy action with the source (and target) being different for each environment. This will copy everything. This could be better.




Sources:
http://stackoverflow.com/questions/3004210/app-config-transformation-for-projects-which-are-not-web-projects-in-visual-stud
http://stackoverflow.com/questions/8082662/how-to-select-different-app-config-for-several-build-configurations
https://codepunk.io/team-foundation-server-build-and-release-with-web-config-transforms/