Portable Kotlin DSL: Where to store environment-specific settings?
Dear community,
this is more a conceptual rather than a technical question. In our current project, we maintain two TeamCity installations, one in-house and one on-site at our customer. So far, the two instances have been kept in sync manually, which is an error-prone and cumbersome process. I have recently learned about Kotlin DSL, especially the new portable format introduced in TeamCity 2018.1, which seems to be a perfect fit for our setup. With that format, DSL scripts are supposed to be server and project independent. However, we have dozens of build configurations with environment-specific settings such as host names or API endpoints. Where are we supposed to store these settings?
Obviously, we cannot store them at the project configuration level as they would end up in the DSL script, rendering the entire script non-portable. We also consider configuring all these settings at the root level to be rather impractical, because we have hundreds of different parameters scattered across dozens of project configurations. Moving all settings to the root level sounds like maintenance hell to me, as there is apparently no grouping mechanisms for parameters. We also contemplated the idea of wrapping every versioned project configuration in a non-versioned project that contains the environment-specific parameters for the enclosed project. But given that we have dozens of TC projects, it seems again overly complex.
Are we missing something? Is there an established "best practice" approach towards managing environment-specific settings in combination with portable DSL scripts? Your help is greatly appreciated.
Please sign in to leave a comment.
Hi Matt,
Well, you could store the settings for both in the DSL, then set up the code in a way that the generated configurations pull the properties from the correct server. That shouldn't be too hard to set up, simply identify the server on the script, and map each set of settings to the appropriate server, so you can pull the correct ones.
Hi Denis,
thanks a lot for your suggestion. We tried to differentiate between current execution environments within our Kotlin DSL scripts, but have been unsuccessful so far. For example, we attempted to read TeamCity parameters from parent projects. Unfortunately, if I understand it correctly, these parameters are not initialized during the execution of Kotlin DSL. As far as I can tell, the current implementation of the portable version of Kotlin DSL only allows the retrieval of the project name.
Or did you mean that we should use other means to identify the server, for example its hostname or a server-specific environment variable at the operating system level?
I indeed meant using server-specific environment parameters to identify them. The Kotlin DSL will be run within the local JVM at the server, so it might be possible to identify it that way. Processing of the DSL is what generates the projects and project parameters, so it's expected that they will not still be up and running to identify from there. Something like the hostname seems to be the best way to tackle this situation. Could you try that out?
I wonder if a good solution to this issue was found, as the Kotlin DSL is run in a context where no server-specific environment parameters are available.
For us it would suffice to get the COMPUTERNAME environment variable, but the SecurityManager prevents us from calling getenv() and getProperties().
Also the file system is sandboxed, so we are also unable to read any files belonging to for instance the service user running the TeamCity instance.
After having giving this some more thought, trying to store server-specific settings in the Kotlin DSL is the wrong way to go. The Kotlin DSL configuration should be portable and thus free of any server-specific settings.
What you can do instead, is a storing server-specific settings as environment variables for the service user running the TeamCity service. Those environment variables can then be parsed by the GroovyPropertiesProvider.groovy script and subsequently be placed into TeamCity build parameters, to be used with the configuration.
I'm running into this issue as we want to have portable Kotlin DSL based config, using gitflow to manage how we develop build configuration changes. Everyone on my team has TeamCity running locally with Versioned Settings enabled, but pointing to separate branches. Our development workflow is to merge down from `master` to make our local instance of TeamCity identical to our production TeamCity. We then make changes and test them locally before creating a pull request back to `master`.
The problem though is that we have settings that must vary on each instance, for example the login for our Issue Tracker. I don't want everyone's instances using our production service account, our local instances should be connecting as ourselves. Same goes for the credentials of the VCS Root our Versioned Settings is using, because we want the branch to vary by TeamCity instance.
I can extract these differences to configuration parameters, how can I encode these differences in a portable Kotlin DSL configuration? Conditionals based on hostname? Read an external file? Read internal properties?
TeamCity 2019.2 RC has a new feature called "Context parameters in portable Kotlin DSL" which might do what you want.
The announcement can be found here : https://confluence.jetbrains.com/display/TW/Kanpur+2019.2+RC+%28build+71364%29+Release+Notes#Kanpur2019.2RC(build71364)ReleaseNotes-ContextparametersinportableKotlinDSL