How to integrate TeamCity with remote Mercurial through SSH

I have a couple of Merurial repos on BitBucket. And I have a CI TeamCity server on Windows. I want to integrate my local TeamCity with remote repos on BitBucket through SSH.

Ok, let’s start. As a precondition we should have PuTTY installed and added to PATH on TeamCity Windows server and a generated public/private SSH keys pair.

1. Download a fresh Mercurial together with TortoiseHg and install it on TeamCity Windows server.

2. Add a new VCS type Mercurial to our build project in TeamCity.

To the field Pull Changes from insert Hg-SSH address of our repo: ssh://hg@bitbucket.org/username/projectname
Now press button [Test connection]. TeamCity should show an error that Merurial did not found SSH application.

3. As an SSH application we will use plink.exe from PuTTY pack. We should point Mercurial where is plink and where is our private SSH-key. For a simple user this should be written in a mercurial.ini file in user’s profile folder. But here is the difficulty – TeamCity runs by default from SYSTEM account that does not have a normal profile folder under C:\Users\.

3.a First of all ensure that TeamCity is actually running from SYSTEM account. In Windows command line run command sc qc TeamCity to look for TeamCity service details.

C:\inetpub\wwwroot\php\a>sc qc TeamCity
[SC] QueryServiceConfig SUCCESS

SERVICE_NAME: TeamCity
        TYPE               : 10  WIN32_OWN_PROCESS
        START_TYPE         : 2   AUTO_START
        ERROR_CONTROL      : 1   NORMAL
        BINARY_PATH_NAME   : "c:\TeamCity\bin\TeamCityService.exe" jetservice "
settings=c:\TeamCity\conf\teamcity-server-service.xml" "/LogFile=c:\TeamCity\lo
s\teamcity-winservice.log"
        LOAD_ORDER_GROUP   :
        TAG                : 0
        DISPLAY_NAME       : TeamCity Server
        DEPENDENCIES       :
        SERVICE_START_NAME : LocalSystem

Look at the last line here: SERVICE_START_NAME : LocalSystem. This means that TeamCity uses SYSTEM account.

3.b As a user profile folder for SYSTEM account Windows uses folder C:\Windows\System32\config\systemprofile
On x64 bits systems for 32-bit programs it should be folder C:\Windows\SysWOW64\config\systemprofile
Let’s say we have a x64 bit Windows and we use 64-bit Mercurial. This means Mercurial running under SYSTEM account will looking for user’s configuration in C:\Windows\System32\config\systemprofile\mercurial.ini
Full path to plink should be placed in this configuration file under [ui] section

[ui]
ssh = "C:\Program Files (x86)\PuTTY\plink.exe" -ssh -2 -batch -C -v -i c:\[path-to-key]\my_teamcity_private_key.ppk

3.c Now TeamCity knows what is SSH. And we can test it by again pressing the [Test connection] button. But it will not work again and we get a new error message, something like: “The server’s host key is not cached in the registry”.

4. Message “The server’s host key is not cached in the registry” means that the SSH connection was established but key need to be cached. If we try to connect in an interactive command line mode then we would be asked to confirm to cache the key. But since this time we run plink is running through TeamCity it can not interact with a user in command line and ask y/n about caching. Then we need to run plink in console under SYSTEM account and confirm caching.
We will use a remarkable utility psExec by Marc Russinovic. Download psExec and console window from SYSTEM account:

psexec.exe -s cmd.exe

Now run plink in this console and point plink to BitBucket.org

plink -agent -i c:\[path-to-key]\my_teamcity_private_key.ppk bitbucket.org

Confirm caching ‘y’

Now in the same SYSTEM-console windows we can check that Mercurial client works through ssh

C:\hg --config ui.interactive=False identify ssh://hg@bitbucket.org/user/project
xxxxxxxx

5. Test VCS connection in project setup in TeamCity and everything should work now.