info@clear-measure.com (512) 298-1232

March 17, 2017 | Yujie Wu @WujuBReady | Blog

Versioned Settings?

Our TeamCity configuration may not change often depending on the project, but when they do they could introduce a slew of headaches when “things don’t work no mo”. So to deal with our anxiety of updating our configuration in TeamCity when “things don’t work no mo” a week later and we forget who changed what, we need to have some mechanism of tracking our changes.

Storing our configuration in version control is ideally what we want to achieve on software projects. In “Continuous Delivery” by Jez Humble and David Farley, they advocate for keeping everything in version control, with the mindset that your configuration should be treated with just as much care as your code.

Since TeamCity 9, Jetbrains has provided developers Versioned Settings, the option to store the entire TeamCity snapshot as xml files in any target repo. This adds tremendous value to our CI pipeline because we now can keep track of all the changes made to our build configurations and rollback to a working state any time.

With Teamcity 10, Jetbrains is taking Versioned Settings a step further by making configuration programmatic with their hand rolled DSL called Kotlin, a concise java-esque programming language that runs on the JVM and builds out of Maven.

object Project : Project({
    uuid = "my_project_id" // uuid should be some constant, never changing string; it is important for preserving history, new id means new entity with new history
    extId = "ExampleOfDSL"
    parentId = "_Root" // id of the parent project
    name = "Example of DSL"
  
    val vcsRoot = GitVcsRoot({
        uuid = "my_vcs_root_id"
        extId = "ExampleOfDSL_VcsRoot"
        name = "Example of DSL VCS Root"
        url = ""
    })
    buildType {
        uuid = "my_build_type_id"
        extId = "ExampleOfDSL_Build"
        name = "Build"
        buildNumberPattern = "%build.counter%"
        vcs {
            root(vcsRoot) // thanks to Kotlin, here we can have static reference to project VCS root
        }
        steps {
            maven {
                goals = "clean test"
            }
        }
        requirements {
            contains("teamcity.agent.jvm.os.name", "Linux")
        }
    }
})  

This introduces visibility to our configuration snapshot since we’re no long reading XML, but more importantly gives us the ability to refactor our configuration in a variety of ways, first one that comes to mind is making build steps reusable across different build configurations, because we can identify that these build steps are very similar with the differences residing in a couple of parameters. We can extend our refactoring to build features, or even entire build configurations. Another great practice is to house strings and magic numbers with constants inside our configuration classes, so we can reuse and change them across our Kotlin project.

Getting Started

To get started with Versioned Settings with Kotlin, go to Edit Project Settings on the top right of your TeamCity project page.

Go to Versioned Settings and check “Synchronization enabled”, choose a VCS root that you want to save the settings in, preferably the same repository that you are targeting for your CI. When we hit apply at the end, TeamCity will make an initial commit plus anytime a change a saved in TeamCity to the <default> branch set for the VCS root we’ve chosen. A “.teamcity” folder will be created at the root level of our repository, this contains all of our Kotlin code.

For our exercise we will choose “Use current settings by default” and the format should be “Kotlin”, this way we are saving our settings in Kotlin in version control as well as being able to run a build with from any given commit, but more importantly still allow us to make changes via the TeamCity. Consider this a happy medium until we are fully comfortable with governing our configuration entirely with Kotlin.

Cool! Is it better now?

At this point we have the ability to monitor any changes to our Teamcity configuration just like we do everyday with conventional code, as well as rollback to a snapshot of Teamcity that was working. To rollback, we just need to run a build on a commit we think is healthy, confirm that it is indeed working, then revert the commits made from Teamcity that broke our CI. 🙂

In the my next blog, we’ll be diving into Kotlin code and how we can refactor our configuration code with conventions to make our configuration reusable and resilient.

Your Turn To Talk

Leave a reply:

Your email address will not be published.