VSTS copy files to : filenames with variables - azure-devops

I am configuring VSTS build and release process.
I have a scenario where I have DEV and QA environments. I have different config files for each of the environments, think of the naming convention Test.Dev.Config
Test.QA.Config
In the "Copy files to" step of the build process, in the "contents" field, are you able to use the BuildConfiguration variable in order to tell the build process to copy the configuration files relevant to the BuildConfiguration:
so that the output of the package contains the Test.DEV.config files for the Dev build step and the Test.QA.config file for the QA build step.
I am basically testing out a options for config transforms in VSTS

Using a VSO variable combined with a string literal often doesn't work as expected within a task like File Copy. Also, you don't want to do that in every task that requires build configuration specific config file. What you can do instead, is to have a separate variable in your build definition that derives from BuildConfiguration variable like so:
Variable Value
BuildConfigFile *.$(BuildConfiguration).config
And then, within the File Copy task, you can directly use this variable as:
_PublishedWebsites\App_Config\$(BuildConfigFile)
For more details on defining one variable in terms of the other, refer this SO post.

Related

How can I determine current directory of executing YAML pipeline in azure pipelines?

We have a large Azure DevOps monorepo, containing many applications and YAML pipelines.
We try to maximise autonomy of our solutions, so we define pipelines in a \Pipelines\ sub directory within the solution root directory. The solutions are in various depths from the repo root.
Every time we need to reference a source file from YAML to pass it to a built-in task such as MSBuild, DotNetCLI or NuGet, we refer to it as relative to $(Build.SourcesDirectory), which seems to indicate the repo root. For example, to pass my-solution.sln to a task, we refer to it as $(Build.SourcesDirectory)\path\to\my-solution.sln. This works, but makes the relation between the pipeline and the solution less atomic, as it requires to explicitly define the full path from the repo root to the solution. If a solution ever moves as a whole unit (which happens), this unit breaks if we don't update the YAML file. This as opposed to most other entities within our ecosystem (in our case .Net), which refer to other entities (e.g. solution --> project; project --> referenced project) by relative path from the source location.
My question:
Is there any pipeline variable (or any other accessible variable e.g. environment variable) which captures the location of the currently executing YAML pipeline? Or is that information lost when Azure compiles the pipelines for execution?
If there is no such variable, is there any other (simple) way to retrieve said location? I understand that I can query the Azure DevOps API, but this seems like it would add more code and maintenance than it would save in the long run.
I've looked here, but if any of those is what I want, then I must have missed it.
Every time we need to reference a source file from YAML to pass it to a built-in task such as MSBuild, DotNetCLI or NuGet, we refer to it as relative to $(Build.SourcesDirectory), which seems to indicate the repo root. For example, to pass my-solution.sln to a task, we refer to it as $(Build.SourcesDirectory)\path\to\my-solution.sln.
You can still use related path, don't need have to use full path. Accoridng to the folder/file structure, use ../ to parent folder, use ./ as current folder. For example:
- task: DotNetCoreCLI#2
displayName: 'dotnet build'
inputs:
projects: ../Bank/Bank.csproj # related path
arguments: '--configuration $(BuildConfiguration)'
In DevOps pipeline, your source code will be checked out to agent machine, by default it's $(Build.SourcesDirectory) which points to c:\agent_work\1\s for example. The pipeline tasks are executed with the files(source code) under this folder. Unless you define workingDirectory for some tasks, please check the doc description below:
In addition, DevOps support "File matching patterns reference", you can specify **/*.proj to match the files.
Hope it answers.

Using VSTS for Continuous Deployment, config transform not working

I am setting up Continuous Deployment for a web app and I'm having trouble doing config transformations. The build and release both work without config transforms, but I would like to add a config transform step to ensure the correct connection strings, storage accounts, etc are in the web config.
I am using the config transform task in VSTS. The artifact that is getting built during the build process is a zip file. I am then extracting those files, and it gives an extremely deep file structure. The config transform works if I hardcode the file structure, but I worry that this could change, so I'd like to generalize it. If I do $(mypath)/**/Web.config it does not error and the logs show that it is doing transforms, but once it finishes, I look at the file in Azure and can see that the transforms weren't actually done or saved.
My requirements for this are that I can't use xslt transforms or the XML transforms(web.environment.config) because we would like to keep the important values out of source control and in VSTS. We are also doing config transforms on NLog.config, and those transforms are setup the same way and seeing the same issues. Any help on getting this more general path to work, or a different way of solving this would be greatly appreciated.
Other potentially helpful information:
MSBuild Arguments in Build Solution step:
/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactstagingdirectory)\\"
Path Structure
$(My.Paths.InstallDirectory)\Content\d_C\a\1\s\Apps\ProjectName\ProjectName\obj\Release\Package\PackageTmp\Web.config
There is File Transforms & Variable Substituion Options in Azure App Service Deploy task, so you can use XML variable substitution or JSON variable substitution to do it without extracting the package file (zip file):
For example:
Add a new variable in Release definition (Scope: select an environment), for example: Name: DefaultConnection; Value: Data source=xxx…), clicking lock icon to change variable type to secret.
Check XML variable substitution option in Azure App Service Deploy task
Then during the deploying, any config and parameters.xml files will be updated with that variable value if the key or name entries in appSettings, applicationSettings and connectionStrings sections are matched the variable name
Related article: XML variable substitution
Another way is that you can change the value in web deploy parameters file (SetParameters.xml) through Token replace task (You also can specify the different file in Azure App Service Deploy task per to Environment of release, such as SetParameters.Dev.xml, SetParameters.QA.xml)
An article about Configuring Parameters for web package deployment
BTW: You can remove the source structure from web deploy package by specifying /P:PackageTempRootDir="" msbuild argument

Pre-defined variable is empty in when creating VSTS release

I have a Service Fabric project set up with CD in VSTS. The CD process have been set up from the CD wizard in visual studio. So far so good but when the release is made I'm not getting any value from the pre-defined variable called Build.DefinitionName that I use for naming the releases.
This is how my Release name is configured: $(Build.DefinitionName)-$(date:yyyyMM).$(rev:r)
If we look in the release log there is no value for the variables:
[BUILD_DEFINITIONNAME] --> []
[RELEASE_ARTIFACTS_{Primary artifact alias}*_DEFINITIONNAME] --> []
*This value is populated correctly.
And according to the docs of primary artifact variables the two variables above should be the same.
As a result of this my releases are named $(Build.DefinitionName)-201702.7
If I use Build.BuildNumber instead. I get the correct value.
How can I get the variables populated?
Update
When creating the Build and Release definitions manually the $(Build.DefinitionName) gets populated correctly on the Release side. But the problem seems to appear when you use the CD wizard from Visual Studio. I might be missing something but the settings of the Build Definition are identical. Or there is some funky stuff going on with the CD wizard.
The solution is to create the release definition manually on web access and set Continuous Deployment.
On the build number is passed from Build to a release, there is no out of the box way to pass more variables between build and release.
However I write a ser of build tasks to do this: https://marketplace.visualstudio.com/items?itemName=nkdagility.variablehydration
It consists of two tasks, the first saves the specified variables to a json file, which you should put in the build output.
The second restores the variables you want. Especially useful if you have multiple source build for your release.

Generate different artifacts team city

I have a project which I want to deploy via team city but when it builds I want to generate a number of different artifacts.
In my app.config file I have an app setting called "platform" which I want to change the value of for each artifact. For example on build I would get three artifacts, dev, test, staging which would have had the "platform" setting changed to the corresponding value.
I have created the powershell script and run it successfully outside of team city, but I have not been able to work out how to set the file directory where the app.config exists within team city.
Is there a system variable I can use to target the current builds app.config file? Or is there a different / better way that I can accomplish what I want to do?
Thanks
Or is there a different / better way that I can accomplish what I want to do?
While this sort of question can lead to an argument over which is better... Based on what you have described, I believe that Octopus Deploy would be a good fit. Octopus Deploy integrates very nicely with TeamCity, and it handles the transformation configurations that are required to allow deployment to each of your environments, i.e. Dev, Test, and Staging. You would simply configure these as Environments within your Octopus Configuration, and during installation, Octopus can modify the configuration files as required, based on variables that you define.
I would recommand to create 3 build steps inside your TeamCity configuration :
Inside the Parameters tab, you can define configuration parameters. Just define here the 3 values : ie: PlatformDev, PlatformTest, PlatformStaging
Using Visual Studio Runner
You might be using Visual Studio runner type. So, here you can add specific values from MSBuild properties:
Dev Step:
Passing the parameter Dev, and executing your code
/p:CustomPlatform="%PlatformDev%"
Test Step:
Passing the parameter Test, and executing your code.
/p:CustomPlatform="%PlatformTest%"
Staging Step:
Passing the parameter Staging, and executing your code.
/p:CustomPlatform="%PlatformStaging%"
Then, the value CustomPlatform would be accessible inside your MSBuild scripts.
Using Powershell hand-made scripts
If you are using a powershell script to run your compilation/artifact creation, you can just add this CustomPlatform as a parameter of your script, and use it directly.
Using XSLT
Another way to do this might be to use XSLT to transform you app.config file, using a specific value.

Configuring Hudson/Jenkins for staging and production

How do I configure Hudson/Jenkins to production and staging deploy with the same configuration?
I have a build and deploy workflow configured in Jenkins to do production pushes. Now I need to use the same configuration to do a staging push, expect that couple of folder & DB names will change to reflect stage. I.e. Say from /var/prod/html to /var/stage/html and db from companyname_table to companyname_table_stage.
I don’t want to do a copy of the configuration since I may have to change the configuration in one place then I will have to make duplicate changes to every copy. Ideally I want to attempt this by passing some parameter
You could configure the project to be parameterized, and add a parameter specifying where to deploy to (i.e. staging or production). How you do this depends on what build system you are using. E.g. if you are using ant, the parameter will be exposed as an environment variable, so you could just have one variable saying whether its staging vs production, and then within the ant script you would set properties to /var/prod/html and companyname_table or /var/stage/html and companyname_table_stage depending on what that parameter is.
If for some reason you have build logic that couldn't change the property value based on the parameter, you would need separate parameters for the different values (e.g. one parameter for the db table and one parameter for the html location)
If you need separate projects for staging vs deploying, you could then have a project structure like this:
Project X: contains all the configuration and build/deploy logic
Project Stage-X: triggers a parameterized build of Project X, with the parameter set to the staging value
Project Deploy-X: triggers a parameterized build of Project X, with the parameter set to the production value
This also has the advantage that it is easy to add additional staging servers or deployment configurations, its just a matter of changing those parameter values.