Dynamic Build Configurations created with Kotlin
I recently took an existing subproject that had two build configurations and switched to use the Versioned Settings, where the build configurations are now defined in Kotlin.
In reading https://blog.jetbrains.com/teamcity/2019/04/configuration-as-code-part-3-creating-build-configurations-dynamically/, there's a screen shot just above the "Summary" which shows a table of "Dynamic" build configurations -- those which the Kotlin script generates.
I have added to our Kotlin two new build configurations by going into our Project.kt and adding two new "buildType( ... )" statements.
We're running TeamCity 2017.2.3 (I've been asking to upgrade to the latest 2018.2 version...we'll see....).
I don't see any list of dynamic build configurations anywhere. Is that a feature that's only present in the 2018 TC release?
I know my script is being evaluated. I accidentally created the new build configurations and forgot to specify a 'uuid' property for them, and the build failed.
I also know that changes I make to the run configurations that were previously defined are also being applied. For those, I can go to the Artifacts tab and look at the buildSettings.xml to see that my changes have been applied.
However, I'm fairly certain the dynamically created run configurations are *not* be executed. One of them, for example, is supposed to upload an artifact but after the builds are complete, there's no sign of that artifact.
Could someone please point me in the right direction?
Please sign in to leave a comment.
Hi Jay,
I think there is a little misunderstanding with how the sample is produced. "Dynamic" is not a feature of having dynamic-style build configurations in that screenshot. It's the name of the project.
Creating UUID for your items should not be needed (you can use them to ensure that you keep control over the objects UUIDs)
The issues you have with your dynamically created run configurations have probably little to do with this, and you would need to share the specifics (how you have created them, what exactly should be happening and what is actually happening). The build log, on the build results of those pages, might have indications of errors.
OK, I'm laughing at myself now about the project name ;-)
I started with the exported Kotlin that looked something like this:
object Project : Project({
uuid = "696df14e-8fa6-4e19-a5f3-d84b11045b48"
id = "some_id"
parentId = "parent"
name = "name of project"
description = "Run configurations for future use."
buildType(build_config1)
buildType(build_config2)
features {
versionedSettings {
id = "PROJECT_EXT_20"
mode = VersionedSettings.Mode.ENABLED
buildSettingsMode = VersionedSettings.BuildSettingsMode.PREFER_CURRENT_SETTINGS
rootExtId = "jdk"
showChanges = true
settingsFormat = VersionedSettings.Format.KOTLIN
storeSecureParamsOutsideOfVcs = true
}
}
})
I then took some common "stuff" out of "build_config1" and "build_config2" and created a base class:
open class MyBuildType(init : BuildType.() -> Unit) : BuildType(init) {
init {
buildNumberPattern = ". . ."
params {
param("env.TEAMCITY_BUILD_VCS_BRANCH", "%teamcity.build.vcs.branch.jdk%")
param("system.build64bit", "true")
}
vcs {
root("jdk")
cleanCheckout = true
}
triggers {
vcs {
branchFilter = """
-:*
+:wip-some-branch
""".trimIndent()
}
trigger {
type = "remoteRunOnBranch"
enabled = false
param("branchy:mercurial", "pattern:mercurial")
}
}
failureConditions {
executionTimeoutMin = 180
}
features {
freeDiskSpace {
requiredSpace = "20gb"
failBuild = false
}
feature {
type = "perfmon"
}
feature {
type = "teamcity.graphite.status"
param("graphite_port", "2003")
param("graphite_host", "carbon-plain.service.discover")
param("graphite_prefix", "sandbox.build.project")
}
}
dependencies {
artifacts("bt2") {
buildRule = lastSuccessful()
artifactRules = "**=>build-tools"
}
}
requirements {
exists("system.ec2.ami-id")
}
}
}
And I changed "build_config1" and "build_config2" to be of the form "object build_config1 : MyBuildType( { . . . } )"
So far, so good.
Next, I created a new "build_config3" in a similar fashion to what the existing build_config1 and build_config2 look like:
object build_config3 : MyBuildType( {
// UUID does not, apparently, have to a GUID.
// See https://teamcity-support.jetbrains.com/hc/en-us/community/posts/360001409279-Kotlin-DSL-uuid-generation
uuid = "build_config3_id"
id = "build_config3_id" //yes, this is the same as the uuid...
name = "config 3 Code"
steps {
gradle {
name = "Compile, Unit Test, Upload"
tasks = "clean assemble check uploadArchives"
buildFile = ""
workingDir = "shared"
gradleHome = "%teamcity.build.checkoutDir%/build-tools/gradle/current"
gradleParams = "-i -PbuildToolsRoot=%teamcity.build.checkoutDir%/build-tools -DXmx=8g -Dmmap.cache.eviction.threshold=120m"
useGradleWrapper = true
enableStacktrace = true
jdkHome = "%env.JDK_11%"
param("teamcity.coverage.idea.includePatterns", "com.foo.*")
param("teamcity.coverage.idea.excludePatterns", """
#teamcity:patternsMode=regexp
.*UT_.*
""".trimIndent())
}
}
} )
...and added build_config3 to the project:
But I'm not seeing is any indication that build_config3 is actually getting executed. When I look at the TC page for my project, I only see build_config1 and build_config2.
I was expecting to see a new build_config3 on that page as well.
I cannot find any log file to look at that might give me an indication of what's gone wrong. The build logs for build_config1 and build_config2 are exactly what they ought to be. But, since there's no build_config3 anywhere to be found, I don't know where to find a log file that can point me in the right direction.
I won't be at all surprised to find that I've done something or made some assumption (perhaps even in the MyBuildType base class) which is causing a problem for build_config3. I just need some help figuring out where to look.
Thank you!
jay
As another test, I changed build_config3 to be as simple as I could make it:
object TestingBuild : BuildType( {
// UUID does not, apparently, have to a GUID.
// See https://teamcity-support.jetbrains.com/hc/en-us/community/posts/360001409279-Kotlin-DSL-uuid-generation
uuid = "build_config3_id"
id = "build_config3_id" // yes...the same
name = "Config 3 Code"
steps {
exec {
name = "Delete Version File"
path = "find"
arguments = """. -name "Version.java" """
print( "I'm done!" )
}
}
} )
Still, however, when I look at the TC page for my project, only the original 2 configs show up. And, again, I know TC is parsing my updated project settings because I originally forgot to add the 'path' and both of the build configs failed with an error letting me know that the required field 'path' was not specified.
Hi Jay,
I'd look into the teamcity-server.log file, maybe there is something. The build config looks fine from my view, I'm not sure why it's not showing up. I've copied your code, pasted it in my own environment, replaced the id = "…" with id("…") instead, and it has worked just fine.
OK. A teammate made some progress on this.
We had the wrong default branch configured in the project, and since the code on the default branch didn't know about the new run configurations (created only in the code), it wasn't running them on my branch.
It'd be really nice if the run configs could be truly created on the fly. That's the implication shown by the blog post https://blog.jetbrains.com/teamcity/2019/04/configuration-as-code-part-3-creating-build-configurations-dynamically/. But it seems like either we're missing something, or we're running into a limitation where the run configs have be available from the project's default branch.
Thank you,
jay