0 Comments

Some time ago I have shown how to configure automatic build of SSIS projects (SQL Server Integration Services). Unfortunately they require full version of Visual Studio installed on a build machine as it’s an overwhelming plugin (not only a toolset), what potentially could hit me back.

And well, of course it failed and hit me after 30 days! Turned out Visual Studio 2017 Community Edition expired and was refusing to cooperate more, producing this nice error log:


[12:08:30][Step 2/3] Starting: C:\TeamCity\buildAgent\temp\agentTmp\custom_script7138984668293949066.cmd
[12:08:30][Step 2/3] in directory: C:\TeamCity\buildAgent\work\2906b7d01f979ef5
[12:08:51][Step 2/3] 
[12:08:51][Step 2/3] Microsoft Visual Studio 2017 Version 15.0.27428.2027.
[12:08:51][Step 2/3] Copyright (C) Microsoft Corp. All rights reserved.
[12:08:51][Step 2/3] 
[12:08:51][Step 2/3] The license for Visual Studio has expired.
[12:08:51][Step 2/3] 
[12:08:52][Step 2/3] The evaluation period for this product has ended.
[12:08:52][Step 2/3] Process exited with code 1


Nothing simpler, I run Visual Studio and entered my credentials, that created a proper license etc. All the warnings on UI were gone. All was supposed to go back to normal, but somehow the same log appeared again.

Till now, it was actually my naïve thinking, as Visual Studio was launched in a context of a totally different user than the one used when I double-clicked the shortcut icon. Build system operated as the local system account, since it was the “TeamCity Build Agent” service that was configured to start it.

I tried to use RunAs plugin for TeamCity. I installed it, created dedicated BuildTool user, even configured in “Build Features” section of the build configuration. Of course I run Visual Studio as this user and entered obtained again the license. But automatic build process was still failing with this log:

[13:12:58][Step 1/3] MSBuild output
[13:12:58][MSBuild output] Access is denied.
[13:12:58][MSBuild output] The current directory is invalid.

I should have probably focused more on this message and grant read/write access for new user to the buildAgent folder (as this is the place, where the sources gets populated and processed) and that would be probably the final solution (even mentioned here). But since I am hot-tempered, I moved to another try.

Next, I reconfigured the whole TeamCity Build Agent service to start as BuildTool user. I added proper login permissions (to allow it to boot the machine, login as a service etc., more here), along with access to mentioned above folder.

TeamCity Build Agent service log-on properties

Since now on, I had no issue anymore and all builds successfully again.


Congrats!

0 Comments

It should be simple, it should be quick. And as usual it turned out to be hard, painful and forced me to install Visual Studio 2017 back on a build machine. I’ve cried a lot that hour. Now I am just waiting, what will fail next, once I see this comment in TC build logs, even though I logged-in and obtained permanent license.

[13:05:08][Step 3/3] Starting: C:\TeamCity\buildAgent\temp\agentTmp\custom_script5352870621326270693.cmd
[13:05:08][Step 3/3] in directory: C:\TeamCity\buildAgent\work\2906b7d01f979ef5

[13:05:12][Step 3/3]
[13:05:12][Step 3/3] Microsoft Visual Studio 2017 Version 15.0.27428.2027.
[13:05:12][Step 3/3] Copyright (C) Microsoft Corp. All rights reserved.
[13:05:12][Step 3/3]
[13:05:12][Step 3/3] The license for Visual Studio expires in 30 days.


Anyway, it makes me to loose even more hairs, due to the fact, that not so long ago I happily removed Visual Studio 2010 from it (check this post)! And simply Visual Studio 2017 build-tools were not enough for the SQL Server Data Tools (SSDT) installer including SQL Server Integration Services (SSIS). Somehow documentation stays, it should be possible to continue and that it will install minimal version of Visual Studio (Shell or something?), but at 85% it tried to apply some VSIX package, failed and roll backed everything.

What’s even worse, is that .dtproj project format is incompatible with MSBuild and it’s impossible to build it without essentially Visual Studio IDE (i.e. devenv.com, check here). Even if you wish to build it using VSTS Online/TFS you still need some tricks.

I hope I linked all stuff, that helped me to understand the subject. So let’s stop weeping and wailing and let’s get something done!


TL;DR


Prerequisites:

  1. Install Visual Studio 2017 Community
  2. Install SQL Server Data Tools (SSDT) (with checked option for SQL Server Integration Services)


Now in TeamCity:

  1. Create a build configuration (here named “Bazy Win32” on figures below)
  2. Add new parameter that points to the location of devenv.com of the Visual Studio

    TeamCity build parameters

    i.e.: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\devenv.com

  3. Add a command-line build step, that will invoke Visual Studio and instruct it to build the solution

    TeamCity build step

    The command is:
    "%env.vs2017_devenv_path%"  <path_to_solution> /rebuild "Development"

    (variable is taken in quotation marks, since it contains spaces etc. as its value)

  4. Remember to put generated .ispac (from bin/Development folder) among other artifacts of the build configuration.
  5. DONE!

0 Comments

I am a really big fan of JetBrain’s TeamCity product. I use it a lot at work and also for my hobby projects. But unfortunately I found it lacks one important, yet very basic feature – proper (and easy) application version management. Someone might say, that this is not totally true, there is a build-in AssemblyInfo Patcher. Yes, OK, although this one is extremely limited and can mostly be used for very simple projects, created by Visual Studio New Project Wizard and never modified.

 

What are my special requirements then?

Well, in my world I really wish to:

 

#1. Make TeamCity fully responsible for assigning versions to all the software components.

Let’s say the hardcoded version inside the application and its libraries is “0.1.*”, so the builds created on developers’ machines are quickly discoverable. Just in case someone totally accidentally with all the good reasons in mind tries to install it on customer’s machine. All official public builds should at least be greater than “1.0.*“ though.

 

#2. Each code branch should have a different build version.

For example the current application version build on ‘master’ branch is ‘1.7.*’, while artifacts of ‘develop’ branch should be ‘1.5.*’, comparing to feature branches, could be even lower, alike ‘0.9.*’.

This plays nicely with the #1 requirement stated above, as since all versioning management is handled by TeamCity, there should never be a merge conflicts between any of those branches and versions, nor any other manual source-code plumbing required.

 

#3. It should be possible to set BuildNumer to default, what C# compiler does.

BuildNumber is third part (number after second dot) of the version string. By default, if left as a star (1.0.*) C# compiler will put there today’s date, counted as days elapsed since 1st January 2000. It is extremely useful information, what I would love to preserve. This value automatically increases each day, and at any time can help find, how old any public release package used by customer was.

 

#4. It should be possible to also store the version info inside regular text file.

For a Web (or Web API) project, it’s much easier to store the current version inside a static file (as it never changes until the new release, so can be server-side cached) and let the client apps (that actually communicate with mentioned server part) download at startup to check, if there are any updates etc. Also it might play a label role, if resides next to compiled binaries.

 

Implementation

This is the very quick way of saying, how I’ve chosen to complete this task:

I designed a PowerShell script, launched as the very-first work item, just after the sources being downloaded from repository and NuGet packages updated.

 

TeamCity.steps

 

It’s flexible enough (as accepting lots of startup parameters from TeamCity) to locate the AssemblyInfo.cs file (or other variants), read current version stored there, update it according to wishes and project spec. Then it stores newly generated version back into the original file, optionally also into a text file and most importantly sends this new info back to TeamCity. Version is then generated in one place, simply based on given inputs and then spread to all required locations.

 

TeamCity.run.ps1

 

Of course to avoid any influences, repository checkout is configured to always load full sources from remote, so any local changes done previously during this process are reversed and never included into the current run.

 

Check the code at my gist and have fun using it!

 

Sample calls

 

PS> .\update-buildnumber.ps1 -ProjectPath 'src/ToolsApp' -BuildRevision 15

##teamcity[buildNumber '1.0.0.15']

 

PS>  .\update-buildnumber.ps1 -ProjectPath 'src/Apps/DevToolsApp' -BuildNumber 0 -BuildRevision 21

##teamcity[buildNumber '1.0.6162.21']

 

PS> .\update-buildnumber.ps1 -ProjectPath 'src/Apps/DevToolsApp' -BuildNumber 0 -BuildRevision 29 -SkipAssemblyFileVersionUpdate $True

##teamcity[buildNumber '1.0.6162.29']