How do I pass MSBuild arguments from the build definition to a MSBuild workflow Activity - msbuild

I've defined an MSBuild activity in a TFS Workflow template, but currently I have to hard code the 'property' command line arguments directly into the template.
I'd like to be able to specify the arguments in the build definition, via the advanced setting, 'MSBuild Arguments'
I can see that I may have to build up the command line with string replace/concat, as mentioned here, but I can't see what I need to put, maybe something like this:

This is what the default MsBuild task uses:
String.Format("/p:SkipInvalidConfigurations=true {0}", MSBuildArguments)
You can change the MSBuildArguments variable in the build process template in multiple steps. For example, I added a Run Architecture Validation property to the process template and then edited the workflow to simply append /ValidateArchitecture=true to the MSBuildArguments before they're being passed to the MsBuild activity.
<If Condition="[PerformArchitectureValidation]" DisplayName="Configure Architecture Validation MSBuild Arguments">
<If.Then>
<Assign>
<Assign.To>
<OutArgument x:TypeArguments="x:String">[MSBuildArguments]</OutArgument>
</Assign.To>
<Assign.Value>
<InArgument x:TypeArguments="x:String">[MSBuildArguments + " /p:ValidateArchitecture=true"]</InArgument>
</Assign.Value>
</Assign>
</If.Then>
</If>
The PerformArchitectureValidation variable is defined as a Property on the Build Process Template level of type Boolean.
Update: Wrote a blogpost that explains this with steps and screenshots

Related

Using msbuild, how can I build once and then publish with multiple transform profiles?

I have a .net solution that I can build with msbuild and successfully generate a deploy package with a PublishProfile.pubxml transform for deploying to a single web server.
I need to take that build and generate deploy packages for different environments, which are set up as transforms using various .pubxml profile files.
I know I could build each profile separately, and it'd be negligible risk of injecting a change into a build, but it's time and space that aren't necessary to consume. I would only end up keeping one of them anyway, and just copying the unique web.configs from each transform into their own deploy package's folder (sorry if this isn't clear, happy to clarify).
I'm looking for something like this pseudocode, which I know is syntactically incorrect but should get the point across:
// step 1
msbuild myapp.csproj target=Build
// step 2
foreach ($profile in $profileList) {
msbuild myapp.csproj outputdir="releaseDir/$profile" target=Publish publishProfile=$profile
}
I am working in a Jenkins context and can't use Visual Studio functions unless they're available as command-line options.
I've also tried desperately to get msdeploy to work, which I think might simplify some of this, but for the life of me I can't get it to work with the tempAgent option, which is really the only way I want to go in my environment. Details on that particular struggle here.
Thanks in advance!
Update 1: This post works well for me, but as I say in a comment, it's still creating multiple deploy packages that take up a ton of space and aren't necessary. What I'd really like is a way to use a single build artifact and create multiple transforms of the Web.config files. Then on deploy, copy that build artifact and the appropriate config file. That would really be build-once/deploy-many!
FWIW, this is the code i came up with using the link above:
function Initialize-Build {
$ErrorActionPreference = 'Stop'
$appName = 'myApp'
$projsToBuild = 'Ui', 'DataService'
$projPath = "$appName/$appName"
$buildPath = 'obj/Release/Package/'
$releasePath = 'Release-Packages'
$commonArgs = '/p:Configuration=Release',
'/nologo',
'/verbosity:quiet'
}
function Invoke-Build {
foreach ($proj in $projsToBuild) {
$projName = $proj -eq 'Ui' ? 'WebUi' : $proj
$p = "$projPath.$proj/$appName.$projName.csproj"
$buildArgs = '/t:Clean,Build',
'/p:AutoParameterizationWebConfigConnectionStrings=False'
Write-Output "Building $p"
msbuild $p #commonArgs #buildArgs
if ($LASTEXITCODE) { exit 1 }
}
}
function Invoke-Transform {
$xformArgs = "/p:deployOnBuild=True", "/p:Targets=Publish"
foreach ($proj in $projsToBuild) {
$p = "$projPath.$proj/$appName.$projName.csproj"
$pubProfiles = 'Dev', 'QA', 'UAT', 'Prod'
foreach ($prof in $pubProfiles) {
Write-Output "Building $p ($prof)"
$pubProfileArg = "/p:PublishProfile=$prof"
msbuild $p #commonArgs #xformArgs $pubProfileArg
if ($LASTEXITCODE) { exit 1 }
}
}
}
. Initialize-PrivLogBuild
Invoke-Build
Invoke-Transform
I realized I wasn't really asking the right question. When I started searching for msbuild transform posts, I found a way to do what I need.
I landed on updating the .csproj files of the apps I'm building with an AfterBuild target.
There are 4 transforms required, each with their own .config file as the transform source. I was fortunate that these files had already been created by the application developer.
This is the code I ended up with, placed at the end of the .csproj file, inside the </project> tag. To reduce repetition of paths and filenames, I created configDir and xformFile properties. I like this pattern because it's easily scalable and generic!
<!-- all the rest of the .csproj above this -->
<UsingTask TaskName="TransformXml"
AssemblyFile="$(MSBuildExtensionsPath32)/Microsoft/VisualStudio/v16.0/Web/Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterBuild">
<PropertyGroup>
<configDir>../../Release-Packages/configs</configDir>
<xformFile>Web.config</xformFile>
</PropertyGroup>
<MakeDir Directories="$(configDir)" />
<TransformXml Source="$(xformFile)"
Transform="Web.Dev.config"
Destination="$(configDir)/$(AssemblyName).$(xformFile).DEV" />
<TransformXml Source="$(xformFile)"
Transform="Web.QA.config"
Destination="$(configDir)/$(AssemblyName).$(xformFile).QA" />
<TransformXml Source="$(xformFile)"
Transform="Web.Prod.config"
Destination="$(configDir)/$(AssemblyName).$(xformFile).Prod" />
<TransformXml Source="$(xformFile)"
Transform="Web.UAT.config"
Destination="$(configDir)/$(AssemblyName).$(xformFile).UAT" />
</Target>
</Project>
many thanks to these posts for lighting the way to this solution
https://dougrathbone.com/blog/2011/09/14/using-custom-webconfig-transformations-in-msbuild
How do I use custom variables in MSBuild scripts?
https://github.com/sayedihashimi/sayed-samples/blob/master/TransformMultipleWebConfigs/transform.proj
https://www.locktar.nl/general/use-config-transforms-when-debugging-your-web-application/
https://johan.driessen.se/posts/Applying-MSBuild-Config-Transformations-to-any-config-file-without-using-any-Visual-Studio-extensions/
Package multiple publish profiles .pubxml after a successful build in Jenkins CI
https://bartlomiejmucha.com/en/blog/msbuild/how-to-extend-msbuild-publish-pipeline-to-apply-transform-files/

jboss-cli property format for path attribute

As explained in JBoss EAP 7 documentation, one can pass in a properties file to the CLI instance with the --properties flag.
I'm trying to create a generic script for logging profiles.
This is my properties file:
profilename=myProfileName
filepath=/some/dir/somefile.log
And this is my script:
set profilename=${profilename}
set filepath=${filepath}
/profile=full-ha/subsystem=logging/logging-profile=$profilename:add
/profile=full-ha/subsystem=logging/logging-profile=$profilename/periodic-size-rotating-file-handler=myHandler:add(file={"relative-to" => "some.dir","path" => $filepath},suffix=.yyyy-MM-dd,max-backup-index=50,rotate-on-boot=true,rotate-size=20m)
The script doesn't generate any error and completes successfully, and the $profilename variable is correctly replaced by its value.
But the $filepath variable seems to be a problem:
<logging-profile name="myProfileName">
<periodic-size-rotating-file-handler name="myHandler" rotate-on-boot="true">
<file relative-to="some.dir" path="$filepath}"/>
<rotate-size value="20m"/>
<max-backup-index value="50"/>
<suffix value=".yyyy-MM-dd"/>
</periodic-size-rotating-file-handler>
</logging-profile>
What is the specific format to use so that a variable can be used for the path attribute?
Edit: tested with JBoss EAP 7.2, and now it works as expected, so I guess it was indeed a bug.
I know this is very late answer, but is the filepath variable last one in your list ?
Because this seems like a line ending issue if add new line at the end this would get picked up correctly.

vstest.console.exe with ClassName as /testcasefilter

I am looking for executing the unit test by ClassName using vstes.console.exe, any help
I tried like
/TestCaseFilter:"ClassName=ProgressTests"
but that throws this error:
Error: No tests matched the filter because it contains one or more
properties that are not valid (ClassName). Specify filter expression
containing valid properties (TestCategory, Priority,
FullyQualifiedName, Name) and try again.
Thanks
You can run the tests by specifying the fully qualified class name:
vstest.console MyBusinessDomain.Tests.dll /testcasefilter:FullyQualifiedName~MyBusinessDomain.Tests.Shopping.Cart
where:
MyBusinessDomain.Tests.dll is the test dll
MyBusinessDomain.Tests.Shopping.Cart is the fully qualified class name
Or you can run the tests classes by namespace:
vstest.console MyBusinessDomain.Tests.dll /testcasefilter:FullyQualifiedName~MyBusinessDomain.Tests.Shopping
This command will run all the tests under MyBusinessDomain.Tests.Shopping namespace.
NOTE: FYI, vstest.console is newer than mstest and is preferred for running via the command line. It can be added to the environment path with this location(for VS2015) :
C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow
According to https://blogs.msdn.microsoft.com/vikramagrawal/2012/07/23/running-selective-unit-tests-in-vs-2012-rc-using-testcasefilter/ - "ClassName is only valid for unit tests for Windows store apps, currently not available for classic MSTest" although that blog post is from years ago now though.
You could just use the FullyQualifiedName filter type as in /testcasefilter:FullyQualifiedName~NameSpace.Class
The tilda ~ means "contains", so if Foobar is the name of your class:
vstest.console bin\Debug\MyTests.dll /TestCaseFilter:FullyQualifiedName~Foobar
See https://msdn.microsoft.com/en-us/library/jj155800.aspx

How to get BuildId in MSBuild?

When I build my project, I can get ${BuildNumber} variable.
BuildNumber can be customized by "UpdateBuildNumber" activity. In this activity we can use ${BuildId} to formate ${BuildNumber}.
But how to get separately ${BuildId} variable?
If you're looking for the BuildNumber:
Use the BuildDetail's BuildNumber property when setting the BuildNumberFormat property of the UpdateBuildNumber build step.
In the example build XAML below, the BuildNumberFormat property is set to:
newBuildString + BuildDetail.BuildNumber
newBuildString is a variable, but could also be a string:
"v1.2.0." + BuildDetail.BuildNumber
If you're looking for the BuildID:
The TFS internal BuildID can be extracted from the URI for the build, as accessed from the IBuildDetail object (see above).
This can be accessed using the following code:
LinkingUtilities.DecodeUri(BuildDetail.Uri.ToString()).ToolSpecificId;
See: https://social.msdn.microsoft.com/Forums/vstudio/en-US/ab8140a2-a236-40d0-b146-dd8f6f4eb4ce/getting-buildid-value-in-a-tfs-2010-build-workflow-activity?forum=tfsbuild

Logging additional custom information in PHPUnit for reports

I am using PHPUnit Selenium for functional testing of my project.
I am using junit for logging and using the log file to gnerate the report. Following is the log tag in phpunit.xml
<phpunit>
<logging>
<log type="junit" target="reports/logfile.xml" logIncompleteSkipped="false" />
</logging>
</phpunit>
Then I use the logfile.xml to generate the report.
What I am looking for is the ability to log additional information (information telling what exactly is getting tested in assertion, in both cases i.e. in both pass/fail of assertion).
Basically in reports I want to tell what is being asserted. And that information will be written by the test writer in the test case manually along with assertion.
assert functions comes with the third optional parameter as message but that is shown only on failure.
Eg:
<?php
// $accountExists is the dummy variable which wil probably checking in database for the existence of the record
$this->assertEquals(true, $accountExists, 'Expecting for accountExists to be true');
?>
Above will return message on failure but not when test is passed.
you must use the
--printer command line argument to point to a custom printer class
http://www.phpunit.de/manual/3.6/en/extending-phpunit.html#extending-phpunit.PHPUnit_Framework_TestListener
in your endTest function whatever you put in printf will show up in your log file.