TeamCity Artefact Dependency Woes

A key feature of TeamCity is the ability to define properties in a build. TeamCity implements a form of inheritance for properties. If you add a dependency to another build, you can reference properties on the referenced build just as if they belong to the build you’re configuring. This is extremely handy when you’re implementing any sort of pipeline as you can allow the source build (i.e. the build which triggered a build chain etc) to define a set of properties and then simply re-use these properties throughout your subsequent builds.

There is a gotcha in all this however, and it’s as follows; your dependency configuration is absolutely critical to being able to reference inherited parameters. By this I mean, if – when you’re configuring your dependant build configuration – it cannot resolve a suitable build at the time you’re configuring it, it won’t allow you to reference the dependency parameters. This is probably best illustrated with an example:

Say you’re defining a new build configuration for your new application Foo:

foo-build

You define a couple of properties on your configuration, one to store a semantic version number and another to store the build configuration (e.g. Debug or Release):

foo-build-properties

Lets ignore the fact that these would probably be better placed in a template which your configuration implemented. Whilst good practise, it’s not all that relevant for this example.

Now lets say you want to define another build configuration to actually deploy your builds of Foo:

foo-deploy

Now, lets say you don’t want all builds of Foo to be deployed, only the ones which the developers have marked up with a tag called “stable”. So you configure an artefact dependency which picks up the last successful build with that tag:

foo-deploy-dependency

I realise this isn’t an entirely realistic scenario, but not outside of the realms of possibility. For reference; a better solution is to have the developers use the “Promote” functionality to promote the build they’d like to the deployment build configuration.

At this point you realise that you want to reuse the semantic version property you defined in your Foo build configuration so that your deployment builds of Foo show which version was deployed. Since you’ve already defined an artefact dependency, you try and reference the property using the normal syntax (e.g. “%dep.” etc):

foo-deploy-property-resolve

Now, what you’d probably expect to see at this point is a list of properties which you could reference, but instead you get the dreaded “No suggestions found” tooltip. Odd. For the sake of the example, lets assume that this might just be a UI thing and manually type out the property as you expect it to be referred to in the dependant build:

foo-deploy-property-typed

However; now when you move to the properties of the deployment build configuration, you notice this:

foo-deploy-unresolved-property

This happens because TeamCity doesn’t understand how to resolve the property you’ve referenced so assumes you want to define it in this build! This is actually a very handy feature of TeamCity that means you can define all your build steps without having to think about all your properties first, but in this instance it just confuses things.

So what’s going on? Well, despite properties being defined on build templates/configurations, as far as dependencies are concerned properties actually exist on builds themselves (as in, a “run” of a build configuration). In our fictitious scenario, there aren’t actually any builds with the “stable” tag, so it doesn’t have anything to interrogate to work out which properties are available.

Lets run a quick build of Foo and mark it as stable:

foo-build-stable

And now, if we go back to the Deploy build configuration and try and resolve the property again:

foo-deploy-resolved-property

Everything is good in the world!

When I first encountered this, I was utterly stumped as to why my properties weren’t showing up. It took a long time and many hours of frustration to work this behaviour out. I was so convinced that this wasn’t intentional that I raised a bug with JetBrains. The response was that this was “by design”. Obviously this is JetBrains’ prerogative, but – in my opinion – it doesn’t make a whole lot of sense. I understand that properties aren’t all defined in the build configuration or template itself and that some are only actually present once you run a build, but it seems like at least displaying the list of properties which are defined for the user to select would have been a half-way-house and avoid this confusion.