If you ever has need to customize build process in Team Foundation Build 2010, you may noticed that there is several ways to do it while each way is suitable for a specific range of requirements:
1. Running external tools like batch files or ftp.exe or MSBuild Community Tasks via InvokeProcess or via MSBuild Activity.
2. Invoke .Net classes and methods like System.IO.File.Delete() via InvokeMethod.
3. Creating your own custom workflow activity for TFS Build 2010.
For our specific need that is synchronizing a remote server via FTP, none of first 2 ways is suitable. In first way, running external programs, this is very hard to synchronize a whole remote directory and its sub-directories just via ftp.exe and a bunch of batch file commands like FOR. In addition, this may impose dependency to external tools in the server.
In the second way, running .Net classes and methods, we have to create our own ftp utility or use third party tools like ftp.exe or MSBuild Community Tasks. In addition this causes using intensive usage of TF Build activities that’s not easy to copy to new Team Foundation builds in new projects.
Third and last way, creating your own activity is harder to implement but has many advantages over other ways including:
1. High flexibility because this is entirely written by yourself.
2. Maintaining is easier because all of your work is kept in a single Visual Studio project.
3. It is easier to deploy it in new team builds because it is simply just one single workflow activity.
4. It is easier to configure. You configure it via its arguments and variables. No need to modify template process itself.
It was a while that I was searching a way increasing version number of a .Net assembly by each build. In the beginning there were very ambiguity for myself that I tried to solve one by one:
1. When to increase assemblies version? Each time that developer builds the project on his (her) machine? Or each time that a build occurs in Team Build? Very soon I realized that is better to use Team Build because version number in each development machine may increase separately. Additionally Team Build maintains a database of all previous build for future uses.
2. By using Team Build based solutions I was unable to use patterns such as “1.0.*” for AssemblyVersion. I was forced to modify/generate AssemblyInfo.cs or some files like VersionInfo.cs. The question was if Team Build or something like MSBuild would change AssemblyInfo.cs, how can I see version information? There are two ways: get latest version, check-out AssemblyInfo.cs/VersionInfo.cs, modify, check-in and cause build based on them or get latest version, modify AssemblyInfo.cs/VersionInfo.cs without check-out/check-in, cause build based on them. Jimb Lamb says it’s a best practice to not check-in/check-out any changes during a build. I chose Jim’s approach.
3. Should I use MSBuild or Team Build? Use MSBuild’s tasks or Team Build’s process templates and activities? The answer was dependent on how I want generate build numbers. As I wanted to use Team Build’s build number in versioning and I wanted to access the history of a each assembly version, I chose Team Build because MSBuild’s tasks are not able to save history of builds in a database.
4. How can I use Team Build 2010 to do the versioning for me? By using TfsSdk: ActivityPack. There is an activity named “UpdateVersionInfo” in the pack. You should put in the bottom of “Overall Build ProcessRun On AgentInitialize Workspace” activity just after “Get Workspace” activity. Don’t forget to add arguments FileSpec, RegularExpression and VersionInfo with proper default values. Use “$(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)” as build definition’s Build Number Format as “UpdateVersionInfo” needs those extra periods. For more info refer to Jim Lamb’s blog post describing it thoroughly.
Also see this blog posts and StackOverflow’s questions: link, link, link, link, link, link, link.