Continous deploy using Teamcity and Appharbor

First of all, this is how I did it and I might have done some parts not according to how the people at JetBrains think I should do it, but I didn’t find another way to do it. So if someone has some improvements just write a comment or two.

TeamCity, from JetBrains, is by far the easiest to use continous integration software I have used for .NET-projects. Just recently I found appharbor, which is a cloud hosting service like heroku but for .NET, I immediately began thinking about how I could combine these two services using github. So my goal with this post is to walk you through how we can set up a TeamCity server to trigger builds from checkins to github and automatically pushes the result to appharbor.

  1. Setup github repository
  2. Setup appharbor application
  3. Configure git repository on build server
  4. Configure TeamCity

1. Setup github repository

I could probably walk you through the process in setting up your github repository, but it is probably easier to just follow the instructions on github.

2. Setup appharbor application

Creating an application at appharbor is just as easy as setting up a repository at github. All you do is create an account on appharbor and then click the “applications” link and “Create new”.

3. Configure git repository on build server

This is one of the trickier parts and it has two steps we need to do. First, create repository so we can do a simple pull from github and push to appharbor, and configure the repository so we can do a push to appharbor without the need of providing a password. The first couple of steps is quite easy to understand and they are:

#> git clone ...path to github repository... YourRespositoryDir
#> cd YourRespositoryDir
#> git remote add appharbor ....path to appharbor application...

So what have you done here? First we clone the github repository so we can access the code, you can use the read-only url since we will not push to github from our buildserver. After that we set up one additional remote that is the remote to our appharbor where we will push the code.

The second step in the process of configuring the local git repository is to provide some kind of mechanism so we don’t have to provide the password manually when we run

#> git push appharbor master

Usually that will force you to provide the password manually since you can’t configure appharbor to use ssh stuff (I call it stuff since it is not of importance here). How can we provide a password without typing it? It turns out that git has a configure option called core.askpass which, if set, will call whatever program assigned to that property and take whatever that is written to the standard output and use it as password. Lucky for you I have created such a program that is quite useful for scenarios where you might have multiple builds environments and you can find the source to it here. To use it just download and build an executable for you and copy it to where you think it belongs. Run the following git command

git config core.askpass ... path to the executable...

Now git will ask that program of the password so how do you get your password in there? It is not trivial since we want to be safe and simple. To register a password you run the following command:

c:\pathtoexe\EasyPass.exe -a <project name> <password>

That will create an encrypted password using the Windows Data Protection API (DPAPI) (wikipedia link since the one on msdn is quite old) and store it in a file on the running users isolated storage. You can register multiple password, but only one per project name. To get the password from the program you need to set the ProjectName environment variable, as of the moment it is hard coded that the environment variable must be named ProjectName but I might add functionality so you can define the name of the environment variable later on. So if you run the following three commands in a row:

c:\pathtoexe\EasyPass.exe -a Proj1 password1
c:\pathtoexe\set ProjectName=Proj1
c:\pathtoexe\EasyPass.exe

You will get “password1″ as output to the console. There are a couple of additional options you can use:

  • -i – will give you an “interactive” mode so you don’t have to type “EasyPass” every time (use “q” to quit the “interactive” mode)
  • -a <project name> <password> – as above but you can also use it to update a password for a project
  • -l – will list all your registered project, their password and the encrypted string
  • -d <project name> – delete the project matching the project name
  • -g <project name> – will give you the password for the specified project without setting the environment variable.

Now we are getting close to the end of this step but there is one more thing to do. I am assuming that you have a standard installation running TeamCity, and this means that the user that will execute the git command will be the System User and not you. This means, since we are using DPAPI and isolated storage, that we must register all the passwords using the System User accound. To do that we use PsTools. When you have installed PsTools you run PsExec -s cmd.exe in the command prompt which will start a new instance of the command prompt but under the System User account. Now when we “are” the System User go to where you have the EasyPass.exe and register the password using the -a option as before. Note that you don’t have to specify an the environment variable, we will do that from TeamCity.

Now we are all set to start configuring TeamCity.

4. Configure TeamCity

I assume we are using a default installation, next-next-next-finish installation, of TeamCity, and that is why we needed to find a way to register passwords as the System User. There are three steps that needs to be done to get it working, where the first step will not be covered that much since I am using standard TeamCity functionality.

First of we need to configure the Version Control Settings for our Build Configuration. What you need to do is the following:

  • Create a VCS root that has your remote repository (github) as your fetch url
  • Set your VCS Checkout Mode to Do not checkout file automatically
    • We don’t want to checkout the file using the standard way since we don’t get the complete git information just the code (I might do something wrong here), we only want our build to be triggered by checkins to our repository then we will handle everyting from that point and on.

The second step is to create the first build step that will get the code for you, and for that we use PowerShell. So create a build step with the following input:

  • Set runner type to PowerShell
  • Set name to Checkout Code (or whatever)
  • Set the working directory to the path to your repository that you configured in Step 2
  • Set script to Source Code
  • Set the script execution mode to Put script into PowerShell stdin with “-Command -” arguments
  • Set script source to the following code

 

$gitExec = "c:\Program Files (x86)\Git\bin\git.exe"
$arguments = "pull origin master"
start-process -wait $gitExec $arguments

That will pull the code from github if your repository is configured correct.

The last step is to push the code to appharbor (of course you could have multiple build steps in between or even additional build configurations that you want to run). This step will also be using PowerShell, so the first four steps is the same as above, the only difference is the script source which should be:

$gitExec = "c:\Program Files (x86)\Git\bin\git.exe"
$arguments = "push appharbor master"
[Environment]::SetEnvironmentVariable("ProjectName", "Your project name you registered the password with", "Process")
start-process -wait $gitExec $arguments

The code above will set the environment variable ProjectName to the one you have registered your password with, so when git is asking for the password it will get the right one. The it will push the code to appharbor. It is basically not much more to it, if you want to know more about the PowerShell I am not the guy to ask but ask google.

Now there is one final step, and that is to add a build trigger that triggers on VCS changes. That is all there is to it, now you can go on setting up your continous deployment environment.

If someone from JetBrains is reading this and thinking about how this could be made easier I have some suggestions:

  • Some kind of password manager integration for handling appharbor passwords
  • Even better git integration, that get all the information from the git server and not just the code

Comments are closed.