Learn to use Visual Studio, Visual Studio Online, Application Insights and Team Foundation Server to decrease rework, increase transparency into your application and increase the rate at which you can ship high quality software throughout the application lifecycle
You want to run some of your business logic during your TFBuild process. Maybe before, or maybe after Team Foundation Build (TFBuild) compiles or tests your code. For example, before you compile, you want to set the version of your assembly files. Or after you compile, you want to control the build outputs that get dropped to your staging location.
Until recently, you would have to customize your build process. Plenty has been written about how to develop a custom build process. I recently released a topic that I hope makes getting started on this kind of effort a bit easier: Create a custom build process. Regardless, developing and using custom build process activities of any complexity can be tricky and requires a learning curve.
What if you just want to run a simple batch (.bat) file? Or maybe you need a bit more power and you want to run a PowerShell script, perhaps to leverage even a bit of .Net code. Well, I'm here to share some good news: with Visual Studio and Team Foundation Server 2013 you can do it! In fact, to help you kick off your adventure in TFBuild scripting, following are a few examples you can literally copy, paste, and check in to your team project and use today.
As you can see, the following build definition is based on the default template; no customizations up my sleeve:
Before you begin using these scripts, a few bits about how they work:
To use these scripts, simply copy the code below into .ps1 files, check them into your codebase, and then reference them from your build process as shown above. Also make sure to include the folder that contains your script on the build definition Workspace tab.
While there are many tasks you might want to perform before MSBuild compiles your code, one of the most common of these might be to apply a version to your assemblies. Jim Lamb wrote a canonical blog post on build process customization: Create a Custom WF Activity to Sync Version and Build Numbers. I patterned the following script using his approach to assembly versioning.
You can get this script here: https://tfsbuildextensions.codeplex.com/SourceControl/latest#Scripts/ApplyVersionToAssemblies.ps1
When you set Output location to AsConfigured, TFBuild yields control of which binaries are dropped to you. The binaries are compiled and left in the source directory, organized essentially the same way as if you used Visual Studio to compile them locally on your dev machine. The following script gathers some of the typical binary types from the typical locations and copies them to the folder from which TFBuild copies and drops to your staging location.
You can get this script here: https://tfsbuildextensions.codeplex.com/SourceControl/latest#Scripts/GatherItemsForDrop.ps1
You'll notice that these scripts leverage some environment variables to get the key bits of data they need to perform their functions. I've cataloged these and all the other environment variables that are available to your scripts: Run your scripts in a default build process. (Note: there is a known bug with the TF_BUILD_TESTRESULTSDIRECTORY not being correctly handled by TFS 2013 Preview. This bug will be fixed in the next release.)
To debug the script while logged on to your dev machine or on the build server, you can manually set the TF_BUILD environment variables in your PowerShell console session. In fact, you'll notice the scripts automatically prompts you to do so. Use the -verbose parameter if you want to get details about what the script is doing and view them from the diagnostic log. Specify -disable if you want to disable any changes the script might make while leaving it referenced by your build process.
I invite you to post your comments here. For questions, I encourage you to post them on our forums: http://social.msdn.microsoft.com/forums/en-us/home.
Thank you for providing the script, I've looked at the ranger guidance and having more script examples provided would be more useful than long paragraphs of text and images. +1 on having on the order of 2 dozen build script template examples being provided.
Thanks for the feedback. Please feel free to leave requests for specific kinds of scripts here. Please be as specific as possible on what you require the script to do. For example, make sure to include the type of code project, file match patterns, and even a bit of pseudo-code if you can.
Hi Andy, this was really helpful and having more would be very helpful. I'd like to see build scripts for C# SSDT database projects that version the schema, checkin updated schema, run Microsoft Source Code Analyzer for SQL Injection tool, check the report file into TFS version control, copy the report file to an SMTP server for email relay to the team.
I have a feeling inside your development teams there are similiar scripts all over the place...it'd be very helpful to have a library of existing scripts to leverage, extend, and reuse.
I also have teams doing a fair amount of web part development on SharePoint so SharePoint build script examples would be incredibly helpful!
@Andy, I need to have a build process that sends and email and gets approval from our QA manager once the QA team's manual tests (in MTM) have all been run manually and are passing and that updates the build quality in TFS. I've seen some scripts but is there someway to have the build script have a timer function that can wait for like 48-72 hours and verify the results of the test runs in MTM?
Working with DAPAC project types and deploying schema changes via Tem Build would be very helpful examples.
I'm trying to build a new build process script that requires human sign off / approval via an email and then compiling can continue. Are there any examples of how to build such a build script?
The scripts are not valid. I provided fixed versions here:
Furthermore i added the "My Project" (VB folder for AssemblyInfo.*) folder to ApplyVersionToAssemblies.ps1 to support VB projects.
@Peter P.: Thank you for finding and sharing the fixes for these errors that somehow crept into the published versions of the scripts! Also, thanks to Mike Fourie for checking in the fixes.
Hi Andy, I think you posted the wrong link for your "environment variables that are available to your scripts: Run your scripts in a default build process". I can't find any environment variables on the linked page. Also, do you know if the environmental variables are only accessible with TFS 2013? Or could we leverage them in our TFS 2012 builds too until we upgrade? Thanks.
@deadlydog: Thanks for the heads up. The link broke after I restructured our content. I just fixed it. These environment variables are new in TFS 2013.
I've done some testing and adding the -Verbose switch to the script arguments fields is not necessary; it logs the same information to the Diagnostics log regardless. It's also worth mentioning that using Write-Host, Write-Output, Write-Warning, and Write-Error in your PowerShell script will write information to the Diagnostics log, but Write-Verbose and Write-Debug do not, even if you provide the -Verbose and -Debug switches. This is from my own testing (see stackoverflow.com/.../23547586)
It's been a long time coming, but we finally upgraded to TFS2013. I know this article is old but I hope someone is still paying attention.
I have a build definition used defined with a trigger for gated check ins.
i have a pre-build script written that performs a couple of tasks.
One of these tasks is to alter the HintPath on the Nuget references in the .CSPROJ files to \Nuget\packages, instead of the relative paths VS uses.
When the build def runs as a normal build it works as expected. the HintPaths are altered and the build is successful.
however, when the gate is enabled, i can see that the .CSPROJ files are read, but when i look at the files in the src folder they are unchanged.
it's worth mentioning, one of the .CSPROJ files i am trying to change is also a file that is being checked in.
it's almost as if the script is making the change, then the change is being overwritten by a get operation.
Any idea what's going on here? why this works as a normal build, but not as a gated?
Thanks in advanced.
Hi Andy, am getting an error like this, while using the script from build definition:
"The argument '$/path/GatherItemsForDrop.ps1' to the -File parameter does not exist. Provide the path to an existing '.ps1' file as an argument to the -File parameter."
Exception Message: TF270015: 'GatherItemsForDrop.ps1' returned an unexpected exit code. Expected '0'; actual '-196608'. See the build logs for more details. (type UnexpectedExitCodeException)
Exception Stack Trace: at System.Activities.Statements.Throw.Execute(CodeActivityContext context)
at System.Activities.CodeActivity.InternalExecute(ActivityInstance instance, ActivityExecutor executor, BookmarkManager bookmarkManager)
at System.Activities.Runtime.ActivityExecutor.ExecuteActivityWorkItem.ExecuteBody(ActivityExecutor executor, BookmarkManager bookmarkManager, Location resultLocation)
Any thoughts on this? Thanks in Advance.