Gitlab CI:设置动态变量

时间:2017-05-22 20:47:28

标签: gitlab gitlab-ci

对于gitlab CI,我定义了一些像这样的变量:

variables:
  PROD: project_package
  STAGE: project_package_stage
  PACKAGE_PATH: /opt/project/build/package
  BUILD_PATH: /opt/project/build/package/bundle
  CONTAINER_IMAGE: registry.example.com/project/package:e2e

我想更动态地设置这些变量,因为主要只有两部分:projectpackage。其他一切都取决于这些值,这意味着我只需要改变两个值来获得所有其他变量。

所以我希望像

这样的东西
variables:
  PROJECT: project
  PACKAGE: package
  PROD: $PROJECT_$PACKAGE
  STAGE: $PROD_stage
  PACKAGE_PATH: /opt/$PROJECT/build/$PACKAGE
  BUILD_PATH: /opt/$PROJECT/build/$PACKAGE/bundle
  CONTAINER_IMAGE: registry.example.com/$PROJECT/$PACKAGE:e2e

但看起来,这样做的方式是错误的......

1 个答案:

答案 0 :(得分:3)

我不知道你的期望来自哪里,但在YAML中是trivial to check there is no special meaning for $, _, '/' nor : if not followed by a space。可能有gitlab,但我强烈怀疑你期望的方式。

为了形式化您的期望,您假设任何键(来自相同的映射)前面有$并且在标量结束后由_/终止将“扩展”到该键的价值。 _必须是终结者,否则$PROJECT_$PACKAGE将无法正确扩展。

现在考虑添加一个键值对:

 BREAKING_TEST: $PACKAGE_PATH

这应该扩展为:

 BREAKING_TEST: /opt/project/build/package/bundle

或遵循您暗示_是终结者的规则,只是扩展为:

 BREAKING_TEST: project_PATH

为了防止像bash这样的歧义程序使用引号来扩展变量名("$PROJECT"_PATH$PROJECT_PATH),但更明智,更现代的解决方案是使用钳制开始和结束字符(例如{}$%%),并使用一些特殊规则将钳位字符用作普通文本。

所以这不会起作用,因为你表示你做错了。

预处理YAML文件并不困难,并且可以用例如YAML文件来完成。 Python(但注意{在YAML中具有特殊含义),可以在jinja2的帮助下:加载变量,然后使用变量展开原始文本,直到无法再进行替换。

但这一切都始于智能地选择分隔符。还要记住,虽然你的“变量”似乎是在YAML文本中排序的,但是当你的程序中构造为dict / hash / mapping时,没有这样的保证。

你可以,例如使用<<>>

variables:
  PROJECT: project
  PACKAGE: package
  PROD: <<PROJECT>>_<<PACKAGE>>
  STAGE: <<PROD>>_stage
  PACKAGE_PATH: /opt/<<PROJECT>>/build/<<PACKAGE>>
  BUILD_PATH: /opt/<<PROJECT>>/build/<<PACKAGE>>/bundle
  CONTAINER_IMAGE: registry.example.com/<<PROJECT>>/<<PACKAGE>>:e2

使用以下程序(不处理转义<<以保持其正常含义)生成原始的,扩展的YAML。

import sys
from ruamel import yaml


def expand(s, d):
    max_recursion = 100
    while '<<' in s:
        res = ''
        max_recursion -= 1
        if max_recursion < 0:
            raise NotImplementedError('max recursion exceeded')
        for idx, chunk in enumerate(s.split('<<')):
            if idx == 0:
                res += chunk  # first chunk is before <<, just append
                continue
            try:
                var, rest = chunk.split('>>', 1)
            except ValueError:
                raise NotImplementedError('delimiters have to balance "{}"'.format(chunk))
            if var not in d:
                res += '<<' + chunk
            else:
                res += d[var] + rest
        s = res
    return s


with open('template.yaml') as fp:
    yaml_str = fp.read()
variables = yaml.safe_load(yaml_str)['variables']
data = yaml.round_trip_load(expand(yaml_str, variables))
yaml.round_trip_dump(data, sys.stdout, indent=2)