Passing values within a TeamCity metarunner - powershell

I have a TeamCity metarunner that consolidates two runners. The first runner does a bunch of Powershell stuff to get the right Octopus release to deploy, and it works fine. The second runner tries to deploy that.
<build-runners>
<runner name="Get project release for current branch" type="jetbrains_powershell">
<parameters>
<param name="jetbrains_powershell_bitness" value="x86" />
<param name="jetbrains_powershell_execution" value="PS1" />
<param name="jetbrains_powershell_minVersion" value="4.0" />
<param name="jetbrains_powershell_script_code"><![CDATA[
#Do some powershell stuff here to get the right release
$ProjectRelease="1.2.3.45"
Write-Output "##teamcity[setParameter name='ProjectRelease' value='$ProjectRelease']"
Start-Sleep -s 10
]]></param>
<param name="jetbrains_powershell_script_mode" value="CODE" />
<param name="teamcity.step.mode" value="default" />
</parameters>
</runner>
<runner name="Deploy Project" type="octopus.deploy.release">
<parameters>
<param name="octopus_additionalcommandlinearguments" value="--specificmachines=%AgentList%" />
<param name="octopus_deployto" value="%Octopus.EnvironmentName%" />
<param name="octopus_host" value="%system.Octopus-prod_ServerUrl%" />
<param name="octopus_project_name" value="%ProjectName%" />
<param name="octopus_releasenumber" value="%ProjectRelease%" />
<param name="octopus_version" value="3.0+" />
<param name="octopus_waitfordeployments" value="true" />
<param name="secure:octopus_apikey" value="zxx318ab49dce685b0ae65d94a963ff326672f51fb87c685575c3b6ed4f6eb8a569" />
<param name="teamcity.step.mode" value="default" />
</parameters>
</runner>
</build-runners>
So you can see %ProjectRelease% gets set to 1.2.3.45, and this value can then be used in subsequent build steps - all good there. However for the second runner, on the line:
<param name="octopus_releasenumber" value="%ProjectRelease%" />
%ProjectRelease% is still equal to the default value ("To be populated" and not "1.2.3.45"). How can I pass this value to the Deploy Project runner?

OK, so I found a solution to this, but it is kind of hacky.
By naming ProjectRelease to env.ProjectRelease (and don't forget to add it as a parameter) it becomes an environment parameter which is updated in real time, and thus will work.
Apparently the line:
Write-Output "##teamcity[setParameter name='ProjectRelease' value='$ProjectRelease']"
...doesn't set the parameter until after the whole script has finished. Please let me know if there is a more elegant solution than this!

You should be able to set parameters for the whole metarunner farther up in the xml.
For example:
<?xml version="1.0" encoding="UTF-8"?>
<meta-runner name="YourMetaRunnerName">
<description>YourMetaRunner Description </description>
<settings>
<parameters>
<!-- meta-runner parameters accessible in all build runners
below -->
<param name="ProjectRelease"value="Release.1.2.3.45"/>
You will then be able to use these parameters in subsequent build runners within the MetaRunner. This should be a more contained solution.

Related

Controlling the sequence of events in a Wixtoolset (.msi) installer

I am creating a Microsoft Installer (.msi file) using the Wixtoolset (Windows Installer XML). This installer must automate the installation of an existing .exe program (named installer.exe below) and copy a custom configuration file (named settings.conf below) to the target directory. In addition the installer must modify the configuration file using the InstallFiles command below. But the timing of events is critical. If the executable installer runs too early, it fails or exhibits strange behavior. And if the executable installer run too late in the install sequence, it overwrites my modified configuration file with the generic values. I believe this can be done by assigning a string to the Before or After property value. What Before or After property assignment will allow the executable to run properly but not overwrite the configuration file I moved by the CopyFile element? Here is my Wixtoolset XML code.
<Property Id="CONFIGFOLDER" Value="C:\acme\config" >
<Feature
Id="ConfigurationFile"
Title="Configuration File"
Level="1"
<ComponentRef Id="CMP_ACME_Config_File" />
</Feature>
<DirectoryRef Id="TARGETDIR">
<Component Id="CMP_ACME_Config_File" Guid="">
<File
Id="ACME_Config"
Source="MySettings.conf"
KeyPath="yes"
<CopyFile Id="Copy_ACME_Config"
DestinationProperty="CONFIGFOLDER"
DestinationName="settings.conf" />
</File>
</Component>
</DirectoryRef>
<Binary
Id="InstallerEXE"
SourceFile="installer.exe" />
<CustomAction
Id="Launch_Installer"
BinaryKey="InstallerEXE"
Impersonate="yes"
Execute="deferred"
ExeCommand=""
Return="check" />
<InstallExecuteSequence>
<Custom Action="Launch_Installer"
Before="InstallFiles">
</Custom>
</InstallExecuteSequence>
</Property>
I can't explain exactly why this works but assigning "InstallFiles" to the "After" property in the "Custom" element seems to do the trick.
<InstallExecuteSequence>
<Custom Action="Launch_Installer"
After="InstallFiles">
</Custom>
</InstallExecuteSequence>

Teamcity meta-runner with multiple runners - exiting a runner without failing the build

OK, so here's a TeamCity meta-runner with 2 separate runners inside. Essentially the first runner will have a bunch of logic in it that determines if a deploy should occur or not.
<build-runners>
<runner name="Step 1" type="jetbrains_powershell">
<parameters>
<param name="jetbrains_powershell_bitness" value="x86" />
<param name="jetbrains_powershell_execution" value="PS1" />
<param name="jetbrains_powershell_minVersion" value="4.0" />
<param name="jetbrains_powershell_script_code"><![CDATA[
#Bunch of powershell logic here... under some conditions we want nothing deployed
#Now I want to exit the whole build step, not just this single runner
Exit #<- Fails the whole build, not what I want
]"]]></param>
<param name="jetbrains_powershell_script_mode" value="CODE" />
<param name="teamcity.step.mode" value="default" />
</parameters>
</runner>
<runner name="Deploy Project" type="octopus.deploy.release">
<parameters>
<param name="octopus_additionalcommandlinearguments" value="" />
<param name="octopus_deployto" value="%Octopus.EnvironmentName%" />
<param name="octopus_host" value="%system.Octopus-ServerUrl%" />
<param name="octopus_project_name" value="%ProjectName%" />
<param name="octopus_releasenumber" value="%ProjectRelease%" />
<param name="octopus_version" value="3.0+" />
<param name="octopus_waitfordeployments" value="true" />
<param name="secure:octopus_apikey" value="123123" />
<param name="teamcity.step.mode" value="default" />
</parameters>
</runner>
</build-runners>
What is a way I can exit the whole meta-runner step so it continues just fine with the next build step?
Response from vendor:
"It seems there is no clean way to skip remaining meta-runner steps without affecting build (successful) status. If you do not mind settings build to failed, you can try Execute "If all previous steps finished successfully" in the meta-runner steps to skip."
While the meta-runner feature is quite good in TeamCity, it does have its limitations.

WiX Bootstrapper: How do I set burn variables from the command line?

Using WiX 3.7 and .NET 4.0.
How does one set burn variables when running a WiX bootstrapper EXE from the command line?
First of all, the burn variables that you wish to set need to be set as Overridable. To do this you must include the follow namespace in your WXS: xmlns:bal="http://schemas.microsoft.com/wix/BalExtension" and if you're using Visual Studio like me you need to include WixBalExtension.dll in your project references. Next you need to add the following attribute to all of the burn variables that you want to set via the command line: bal:Overridable="yes".
Now you can set the variables via the command line in this fashion:
BootstrapperSetup.exe /i /passive MyBurnVariable1=1 MyBurnVariable2=2
Below is an example of a WXS file that satifies all of the conditions described above:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
<Bundle Name="MyProduct" Version="1.0.0" Manufacturer="MyManufacturer" UpgradeCode="PUT-UPGRADE-CODE-HERE">
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.HyperlinkLicense">
<bal:WixStandardBootstrapperApplication LicenseUrl="MyLicense.htm" ThemeFile="MyThemeFile.xml" LocalizationFile="MyLocFile.wxl" />
</BootstrapperApplicationRef>
<Variable Name="MyBurnVariable1" bal:Overridable="yes" Type="numeric" Value="0" />
<Variable Name="MyBurnVariable2" bal:Overridable="yes" Type="numeric" Value="0" />
<Chain>
<MsiPackage Id="MyFirstMsiPackage"
SourceFile="first.msi"
InstallCondition="MyBurnVariable1 = 1" />
<MsiPackage Id="MySecondMsiPackage"
SourceFile="second.msi">
<MsiProperty Name="MY_PROPERTY" Value="[MyBurnVariable2]" />
</MsiPackage>
</Chain>
</Bundle>
</Wix>

Using xmlpeek in Nant script gives odd error

As part of a CI process I am trying to create a buildlabel which consists of the content of an xml element within an xml structure. For this purpose I am using nant and xmlpeek. My problem is that I get an odd error stating:
"Nodeindex '0' is out of range"
This is only the case if the xml file I am xmlpeeking contains a namespace definition in the root node.
Removing the namespace from the xml file gives me the output I expect.
The nant target that generates the error can be boild down to:
<target name="TDSLabel">
<property name="element" value=""/>
<echo message="Getting element" />
<xmlpeek file="C:\xxx\test1.xml" xpath="//Project/PropertyGroup/ProductVersion" property="element"/>
<echo message="The found element value was: ${element}" />
</target>
and the test1.xml file looks like this:
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProductVersion>9.0.21022</ProductVersion>
</PropertyGroup>
</Project>
You already gave the right hint yourself. It's about the namespace. This should fix it:
<target name="TDSLabel">
<property name="element" value=""/>
<echo message="Getting element" />
<xmlpeek
file="C:\xxx\test1.xml"
xpath="//x:Project/x:PropertyGroup/x:ProductVersion"
property="element"
verbose="true">
<namespaces>
<namespace prefix="x" uri="http://schemas.microsoft.com/developer/msbuild/2003" />
</namespaces>
</xmlpeek>
<echo message="The found element value was: ${element}" />
</target>
Found a similar problem and the anwser to my problem here: XmlPoke and unique nodes. The problem was that I did not include the namespace definition within the xmlpeek element and afterwards omitted the necessary reference to the namespace in my xpath statement:
<xmlpeek file="C:\xxx\test1.xml" xpath="//x:Project/x:PropertyGroup/x:ProductVersion" property="element">
<namespaces>
<namespace prefix="x" uri="http://schemas.microsoft.com/developer/msbuild/2003" />
</namespaces>
</xmlpeek>

nant: expanding properties in a string

Summary:
How do I expand a property with value "download\${bulidmode}\project\setup.msi" to "download\Debug\project\setup.msi" if the property buildmode contained debug so I can use it as the file="" part of < copy >
Detail:
I have a bit of a requirement to be able to expand properties within a string in nant.
For example I have a target that is copying file A to B. A and B both come from a simple two field CSV file which I'm iterating through using
<foreach item="Line" in="filelist.csv" delim="," property="source.file,target.file">
<property name="sourcefile" value="${path::combine(source.dir,source)}" />
<property name="targetfile" value="${path::combine(download.dir,destination)}" />
<echo message="Copy ${sourcefile} to ${targetfile}" />
<copy file="${sourcefile" tofile="${destination}" />
</foreach>
and the filelist.csv will be
build\manifest.xml
solutiondirectory\setup-proj-directory\Release\setupproj.msi,ProductA\ProductA.msi
solutiondirectory\another-proj-dir\Release\setupproj.msi,ProductB\ProductB.msi
(The reason we split these out is that we write multi-tiered applications and deploy by MSI to each tier - so one product has multiple msi's all built with the same version numbers)
Anyway - I want to change this to that I no longer have "Release" in the filelist.csv file but something like ${build.mode}. I would wrap the above code with a
<foreach item="String" in="Release,Debug" delim="," property="build.mode">
....as above
</foreach>
and the property embedded within the string in the file gets expanded.
I've been beating my head against a brick wall for a few hours, but just can't figure it out.
Thanks
It is possible with a custom function :
<?xml version="1.0"?>
<project>
<script language="C#" prefix="vbfox" >
<code>
<![CDATA[
[Function("expand")]
public string ExpandString(string str)
{
return Project.Properties.ExpandProperties(str, Location.UnknownLocation);
}
]]>
</code>
</script>
<property name="hello" value="{path::combine('_hello_', '_world_')}" />
<property name="hello" value="${'$' + hello}" />
<echo message="${hello}" />
<echo message="${vbfox::expand(hello)}" />
</project>