Recently in Geek Stuff Category

Category: Geek Stuff » Phew. Crisis Averted!

| | Comments (0)

Over the weekend I went to log into this blog to check some historical dates and was greeted with a big red scary Google “This Website Is Evil!” message. The blog had been blacklisted for having links to malware. It took me awhile to track down and delete the offending code, but I was able to resubmit the blog for testing later that day. Today, I opened the Google Webmaster Tools to find this: No Malware.png

Queue huge sigh of relief… ahhhhhhh. I’m amazed at how quickly they turned that around. It’s interesting to reflect on how little care and maintenance this blog has needed in more than eight years. I guess I should count myself as lucky!

Category: Geek Stuff » Blog Upgraded To MT5

| | Comments (0)

Today I upgraded the blog to the latest version from Movable Type: MT 5.04. It was a pretty painless upgrade. That’s pretty much all I’ve got to say. Mostly, I just wanted to document this so I could have a reference point whenever I upgrade to MT6. Now back to your regularly scheduled internet.

Recently at my job I had to figure out how to publish a Windows app with ClickOnce deployments from a centralized build server running JetBrains TeamCity. This might be kind of an esoteric use for TeamCity, but I wanted to get my process down in my blog to perhaps save some future generations some time and Google searching.

Here’s a list of ingredients:

  1. A fresh TeamCity server running on Windows.
  2. Visual Studio 2010 installed on the build server (with the MSBuild 4.0 bits).
  3. The MSBuild Extension pack.
  4. The MSBuild Community Tasks.

I’m going to assume you already know how to set up your project in TeamCity and check out the sources from the version control software of your choosing.

The first build step I have is a little orthogonal to the ultimate deployment process, but I will include it because ultimately I wanted the Windows app and the ClickOnce deployment to all share the same version number that can be tied back to the TeamCity build. One thing to keep in mind is to call MSBuild in TeamCity with command line parameters of: /p:Configuration=Debug (if you are doing a debug build). This way I can have the compilation configuration type stamped in the binary’s metadata.
Here is a sample MSBuild file called SetVersion.proj that I use:

<Project DefaultTargets="SetVersion" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Version>$(BUILD_NUMBER)</Version>
  </PropertyGroup>
  <Import Project="$(MSBuildExtensionsPath)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks"/>
  <Target Name="SetVersion">
    <ItemGroup>
      <AssemblyInfoFilesFirst Include="$(MSBuildProjectDirectory)\FIRST_PROJECT\Properties\AssemblyInfo.cs"/>
      <AssemblyInfoFilesSecond Include="$(MSBuildProjectDirectory)\SECOND_PROJECT\Properties\AssemblyInfo.cs"/>
    </ItemGroup>
    <AssemblyInfo AssemblyInfoFiles="@(AssemblyInfoFilesFirst)"
                  AssemblyVersion="$(Version)"
                  AssemblyFileVersion="$(Version)"
                  AssemblyConfiguration="$(Configuration)"
                  AssemblyCopyright="© 2011 YOUR COMPANY. All rights reserved."
                  AssemblyProduct="First Project Name - $(Configuration)"/>
    <AssemblyInfo AssemblyInfoFiles="@(AssemblyInfoFilesSecond)"
                  AssemblyVersion="$(Version)"
                  AssemblyFileVersion="$(Version)"
                  AssemblyConfiguration="$(Configuration)"
                  AssemblyCopyright="© 2011 YOUR COMPANY. All rights reserved."
                  AssemblyProduct="Second Project - $(Configuration)"/>
  </Target>
</Project>

Note the use of the Extension Pack’s AssemblyInfo task which enabled me to set values in the AssemblyInfo.cs files prior to compilation.

Next, I needed to clean and build the sources and call the Publish target in the Winforms project. To do this, I used another MSBuild build step that targets a file called Publish.proj, listed below:

<Project DefaultTargets="DoPublish" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
  <PropertyGroup>
    <Version>$(BUILD_NUMBER)</Version>
    <ClickOnceBuildDirectory>$(MSBuildProjectDirectory)\PROJECT1\bin\$(Configuration)\app.publish</ClickOnceBuildDirectory>
    <ClickOnceInstallDirectory>$(MSBuildProjectDirectory)\Publish</ClickOnceInstallDirectory>
    <ClickOnceHtmFileLocation>$(MSBuildProjectDirectory)\Build\publish.htm</ClickOnceHtmFileLocation>
    <ClickOnceFinalLocation>$(env_PublishUrl)</ClickOnceFinalLocation>
  </PropertyGroup>
  <Target Name="DoPublish">
    <RemoveDir Directories="$(ClickOnceInstallDirectory)" ContinueOnError="true" />
    <MSBuild Projects="MY SOLUTION FILE.sln" Targets="Clean;Build" Properties="ApplicationVersion=$(Version);Configuration=$(Configuration)"/>
    <MSBuild Projects="PROJECT1\CLICKONCE PROJECT.csproj" Targets="Publish" Properties="ApplicationVersion=$(Version);Configuration=$(Configuration);InstallUrl=$(ClickOnceFinalLocation);PublishUrl=$(ClickOnceFinalLocation)" />
    <MakeDir Directories="$(ClickOnceInstallDirectory)"/>
    <Copy SourceFiles="$(ClickOnceHtmFileLocation)" DestinationFiles="$(ClickOnceInstallDirectory)\publish.htm"/>
    <Exec Command="xcopy /E $(ClickOnceBuildDirectory) $(ClickOnceInstallDirectory)" />
    <FileUpdate Files="$(ClickOnceInstallDirectory)\publish.htm"
                IgnoreCase="true"
                Multiline="true"
                Singleline="false"
                Regex="{VERSION}"
                ReplacementText="$(Version)" />
  </Target>
</Project>

In order to get this to work, I needed to save a copy of the publish.htm file because this is not generated as part of the Publish target. In fact, it can only be generated when clicking Publish within the Visual Studio IDE. This is not acceptable for an automated build: bad Microsoft! No cookie for you! During the build, I needed to edit the publish.htm file so that I could tamper with it’s version number. I stored a copy of this file in my source tree in a Build folder. Note also the $(env_PublishUrl) variable. This is coming from the build properties in TeamCity. The value is the full UNC location to the ultimate resting place of the ClickOnce deployment. MSBuild needs this because when it generates the ClickOnce manifest, it uses the fully qualified location (FTP/HTTP or file) so that all clients can refer to that location for future for updates. Basically, MSBuild file does the following actions in order:

  1. Remove the place where it is going to assemble the ClickOnce package (in case an prior artifacts exist).
  2. Do a Clean and Build on the entire solution to compile the the source code into binaries.
  3. Call the Publish target within the WinForms project and set the InstallUrl and PublishUrl locations to be the final package location.
  4. Create the local folder where it’s going to assemble the package.
  5. Copy the publish.htm file from the source archive to the package location.
  6. Use xcopy to copy the output of the Publish target that ends up in the bin\Debug\app.publish folder.
  7. Use the FileUpdate task to put our version number in the right spots in the publish.htm file.

BIG HAIRY CAVEAT: To make this work, I had to remove the following PropertyGroup properties from the WinForm’s .csproj file:

  • MinimumRequiredVersion
  • PublishUrl
  • ApplicationRevision
  • ApplicationVersion

Finally, I needed to move the resultant build package out onto a network share for consumption by clients. My build machine was not a member of the AD domain, so I had to manually map and delete network drives. Fortunately, the Command Line build step’s Custom Script mode handled this wonderfully. Think of it as a way to write a batch file on the fly using environment variables set up during the build.

NET USE P: "%env.PublishShare%" /USER:domain\username **password**
ROBOCOPY "%system.teamcity.build.workingDir%\Publish" "P:%env.PublishFolder%" /MIR
NET USE P: /DELETE

Note how I referenced the build’s working directory to find the published package, and two different Environment Variables that were set as part of the build configuration. This allowed me to target different network shares and folder structures without changing the script or any other build artifacts.

This wasn’t a difficult solution to arrive at, but it did give me the opportunity to learn a lot about MSBuild and both the Extension Pack and the Community Tasks add-on packages. After trying to accomplish a similar task with Cruise Control.net and a WCF webservice project, and giving up; I have become a huge fan of TeamCity and it’s ease of use. It only took three or four hours to get a brand new Windows Server 2008 Standard x86 (a requirement for WCF packages with COM dependencies) virtual machine stood up with TeamCity installed and working. That includes all the Windows Updates!

Happy Automated Building!

Category: Diet » Help Fight Diabetes

| | Comments (0) | TrackBacks (0)

Team Hanselman Banner

Now I’ve only been diabetic for a few years now, but every day (or meal, or test) I am reminded of it’s impact on my life. Please help the fight to end diabetes by sponsoring this Microsoft programmer dude I admire.

Thanks!

Category: Geek Stuff » Thoughts On Coding

| | Comments (5)

The other day I had a very lively conversation about programming with my friends Pat & Warren. To paraphrase: Warren put forth the idea that coding is a lot like playing a game, and that game theory can be loosely applied to it. This led us to the idea that programmers play at building software, and in doing so, fall into two basic categories. Bear in mind, these are not absolutes, but merely ends of a spectrum that a coder can shift along over time.

  1. The first type of coder/gamer is a person who likes the result of the game. They like the feeling that comes along with winning, or completing a level. If you played a dungeon-type discovery game such as Diablo with this person, generally they would be the person to reach the end of a level first. And then probably complain that you are taking too long. They enjoy the completion more than the act of playing. In fact, to them, the idea of playing is just the sum of all the completed levels so far. These types shall be known as the Completors.

  2. The second type of coder/gamer is a person who likes the exploration and interaction of the game. Winning or completing a level is a secondary or nth-erary aspect of the game. These people will want to explorer every possible room in a dungeon, possibly returning to visited rooms just to check “if anything new has shown up”. Obviously, this drives the type 1s crazy, as these archetypes enjoy the act of playing more than completion. Personally, this is the group I tend to fall into. These types shall be known as the Wanderers.

So which is better? I don’t believe the question is nearly as cut and dried as that. From a business point of view, results matter, and it would seem that a gang of Completors would the best team to create a business-critical on-time and under-budget enterprise-level highly-available software solution. Let me pause for a moment here, to let my jargon buffer refill. I think that a good level of success can be had with a group of coders more toward the Completor end of the spectrum. But that comes with a price. Because Completors are so results-oriented, once they find a good solution or strategy to beat “the game”, they will just continue to apply it over and over. Why fix it if it ain’t broke?

The problem with the security of these repeatable results is that the world of software (and the world of games) marches on at a blistering pace. New technologies and methodologies spring up like dandelions in the summer. I personally spend a good deal of time just trying to keep up with a small amount of the New Stuff. Completors tend to shy away from personal growth and exploration because that’s their nature. Over a career, or many careers, this can lead to a certain amount of software stagnation.

Now let’s look at the Wanderers. You might think after that last paragraph, that you really want a team of Wanderers! Unfortunately, that group has some downsides as well: They tend to be the worst estimators ever. Some projects, because the game space is so large, will never actually reach completion. When faced with a very structured deadline or result, Wanderers may fail (for certain values of failure). Because the idea of exploration and self growth is very important, Wanderers tend to not have as much loyalty or “team spirit” as Completors.

So what’s the final answer? Just like in many things in life— I believe that moderation is key. A group that is a well-mixed solution of different levels of these elements will reap benefits greater than the sum of it’s parts. Wanderers will inspire and enlighten the Completors, The Completors will keep the Wanderers on the right track, possibly dragging them over the finish line with them. As a manager, or project leader, I think that understanding these two archetypes and using their strengths and weaknesses together can make for a most potent team. After all, who wants to play Diablo with a group solely consisting of Barbarians?

Powered by Movable Type 5.04

Content Licensing

Creative Commons License
This weblog is licensed under a Creative Commons License.