TeamCity On-Premises 2024.03 Help

在构建链中使用参数

这个主题演示了您如何使用 TeamCity 构建参数构建链 的配置之间交换简单数据。

访问前序链构建的参数

依赖构建可以访问前一个链构建的预定义和自定义参数,形式为 dep.<bcID>.<parameter_name> ,其中 bcID 是您需要访问其参数值的源构建配置的名称。

依赖构建中的参数

您可以使用 dep... 参数,即使当前配置仅具有间接依赖关系,也可以从配置中访问参数。 例如,在 A → B → C 的链中,C 依赖于 B,B 依赖于 A,配置 C 可以访问 A 的参数。

以下构建配置用于构建并推送 Docker 镜像。 这个镜像的名称被写入到 DockerImageName 参数中。

TAG=v1 docker build -f Dockerfile --tag your.registry/MyApp:${TAG} docker push your.registry/MyApp:v1 echo "##teamcity[setParameter name='DockerImageName' value='MyApp:${TAG}']"

如果此配置的名称是 "ConfigA",则进一步沿着构建链执行的构建可以访问镜像名称为 dep.ConfigA.DockerImageName

docker run -d your.registry/%dep.ConfigA.DockerImageName%

覆盖前置配置的参数

在目标配置中添加一个带有 reverse.dep.<build_conf_ID>.<parameter_name> 名称语法的参数,以覆盖在当前配置之前定义的 <parameter_name> 参数。

例如,以下的 Kotlin 代码定义了一个项目,该项目包含三个构建配置,这些配置在一个单一的构建链中统一(ConfigA → ConfigB → ConfigC)。 每个构建配置都有一个 chain.ConfigX.param 参数,并带有其自定义值。 最后的配置有额外的 reverse.dep.ChainConfigA.chain.ConfigA.param 参数。

import jetbrains.buildServer.configs.kotlin.* project { buildType(ChainConfigA) buildType(ChainConfigB) buildType(ChainConfigC) } object ChainConfigA : BuildType({ name = "ChainConfigA" params { param("chain.ConfigA.param", "Config A") } steps { script { scriptContent = """echo "Parameter value is: %chain.ConfigA.param%"""" } } }) object ChainConfigB : BuildType({ name = "ChainConfigB" params { param("chain.ConfigB.param", "Config B") } steps { script { scriptContent = """echo "Parameter value is: %chain.ConfigB.param%"""" } } dependencies { snapshot(ChainConfigA) { reuseBuilds = ReuseBuilds.NO } } }) object ChainConfigC : BuildType({ name = "ChainConfigC" params { param("chain.ConfigC.param", "Config C") param("reverse.dep.ChainConfigA.chain.ConfigA.param", "Value Overridden in ConfigC") } steps { script { scriptContent = """echo "Parameter value is: %chain.ConfigC.param%"""" } } dependencies { snapshot(ChainConfigB) { reuseBuilds = ReuseBuilds.NO } } })

如果您运行 ConfigA 或 ConfigA → ConfigB 子链,第一个配置将会报告其原始参数值。

# ConfigA build log Parameter value is: Config A

然而,如果您运行一个以 ConfigC 结束的完整构建链,这最后的配置将为 ConfigA 提供一个定制的参数值。

# ConfigA build log Parameter value is: Value Overridden in ConfigC

您可以在参数名称中使用 * 通配符,以便在多个前面的配置中使用相同的参数。 例如,以下示例中的 ConfigC 具有 reverse.dep.ChainConfig*.MyParam 参数,该参数覆盖了 ConfigA 和 ConfigB 中的 MyParam

object ChainConfigA : BuildType({ params { param("MyParam", "OriginalValue_A") } }) object ChainConfigB : BuildType({ params { param("MyParam", "OriginalValue_B") } dependencies { snapshot(ChainConfigA) { reuseBuilds = ReuseBuilds.NO } } }) object ChainConfigC : BuildType({ params { param("reverse.dep.ChainConfig*.MyParam", "CustomValue_C") } dependencies { snapshot(ChainConfigB) { reuseBuilds = ReuseBuilds.NO } } })

冲突的参数覆盖

如果在 ConfigA → … → ConfigB → … → ConfigC 配置链中,ConfigB 和 ConfigC 配置试图覆盖 ConfigA 的参数,由于 ConfigC 依赖于 ConfigB (直接或通过中间配置),所以 ConfigC 有更高的优先级。

object ChainConfigA : BuildType({ params { param("MyParam", "OriginalValue_A") } }) object ChainConfigB : BuildType({ params { // Lower priority param("reverse.dep.ChainConfigA.MyParam", "CustomValue_B") } // Depends on config A dependencies { snapshot(ChainConfigA) { reuseBuilds = ReuseBuilds.NO } } }) object ChainConfigC : BuildType({ params { // Higher priority param("reverse.dep.ChainConfigA.MyParam", "CustomValue_C") } // Depends on config B dependencies { snapshot(ChainConfigB) { reuseBuilds = ReuseBuilds.NO } } })

然而,如果 ConfigB 和 ConfigC 彼此间没有依赖关系,关于哪种配置应具有优先级的问题就会出现。 TeamCity 试图通过比较参数名称并优先考虑具有最具体构建配置 ID 的参数来解决这种歧义。

  • 最高优先级:构建配置 ID 中没有通配符的参数(例如, reverse.dep.ChainConfigA.MyParam)。

  • 中等优先级:具有部分配置 ID 的参数(例如, reverse.dep.Chain*A.MyParam)。 目标配置 ID 越具体,此参数的优先级就越高。 例如, ChainConf*A ID 优先于 Chain*A ID,因为它被认为更为特定。

  • 最低优先级:参数使用 * 通配符,而非配置 ID (例如, reverse.dep.*.MyParam)。

如果所有冲突的配置都有相似的参数名称,且没有一个明显的赢家,那么 TeamCity 就会报告一个冲突并创建额外的 conflict.<build_config_ID>.<parameter_name>=<value> 参数(每个冲突的配置都有一个)。

object ChainConfigA : BuildType({ params { param("MyParam", "OriginalValue_A") } }) object ChainConfigB : BuildType({ params { // Equal priority param("reverse.dep.ChainConfigA.MyParam", "CustomValue_B") } // Depends on config A dependencies { snapshot(ChainConfigA) { reuseBuilds = ReuseBuilds.NO } } }) object ChainConfigC : BuildType({ params { // Equal priority param("reverse.dep.ChainConfigA.MyParam", "CustomValue_C") } // Depends on config A dependencies { snapshot(ChainConfigA) { reuseBuilds = ReuseBuilds.NO } } }) // Composite build configuration that runs the entire chain object ChainABC : BuildType({ type = BuildTypeSettings.Type.COMPOSITE dependencies { snapshot(ChainConfigB) {} snapshot(ChainConfigC) {} } })
冲突的覆盖

其他考虑因素

  • 在队列构建中处理 reverse.dep.* 参数,这些参数在此处定义。 既然此阶段应已知道参数值,那么必须在构建配置或者 自定义构建对话框 中分配这些值。 将参数设置为在构建期间计算的值将无效。

  • 将新参数推送到构建中会覆盖 "如果存在合适的版本,则不运行新版本 " 快照依赖项选项,并可能在参数设置为非默认值时触发新的构建。

  • reverse.dep. 参数的值会“原样”推送到依赖性构建中,没有 引用解析%-引用,如果有的话,将在目标(target)构建的范围内得到解决。

最后修改日期: 16日 7月 2024年