如何使用And组合多个GitLab规则?

huangapple go评论59阅读模式
英文:

How to combine multiple GitLab rules with And?

问题

根据文档,多个规则使用OR操作进行组合,确实表现出这种方式。但我有一个特定的情况。

所以我有一组用于PCF平台的作业,另一组用于Kubernetes平台。它们通过设置变量简单地进行管理。可能需要同时激活两者:

.pcf-platform:
  rules:
    - if: $PLATFORM_PCF == "true"

.k8s-platform:
  rules:
    - if: $PLATFORM_K8S == "true"

.manual-feature-branch-optional:
  rules:
    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE != "schedule" && $CI_PIPELINE_SOURCE != "merge_request_event"
      when: manual
      allow_failure: true

.manual-default-branch-optional:
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE != "schedule"
      when: manual
      allow_failure: true

现在我们想象有这些作业:


deploy-dev-pcf:
  extends:
    - .manual-feature-branch-optional
    - .pcf-platform
  script:
    - do deploy

deploy-dev-k8s:
  extends:
    - .manual-feature-branch-optional
    - .k8s-platform
  script:
    - do deploy

deploy-prod-pcf:
  extends:
    - .manual-default-branch-optional
    - .pcf-platform
  script:
    - do deploy

现在,假设PLATFORM_K8SPLATFORM_PCF都设置为true,并且当前分支是功能分支(非默认);如预期,将deploy-dev-pcfdeploy-dev-k8s添加到流水线,以及deploy-prod-pcf

似乎第一个规则检查当前分支是否为默认分支的解决方式是false,但然后它评估下一个规则,检查PLATFORM_PCF是否等于true,因为它为true,所以在我们仍然在功能分支时添加了该作业。

我需要以某种方式使这两个单独的规则成为And,这样我就可以根据所需的平台和分支类型启用/禁用作业。

我可以为Kubernetes创建一组规则,为PCF创建一组规则,但这会不合理地增加规则数量,我对这种方法不情愿。

文档中说only子句正在使用And进行评估,但似乎only正在被弃用,而rules正在取而代之。

我该如何实现这一点?

英文:

According to the documentation, multiple rules are being combined with OR operation, and indeed it behaves that way. But I have a specific situation.

So I have a set of jobs that are used for PCF platform and another set for Kubernetes platform. They are managed simply by setting variables. And it is possible that we may need both to be active:

.pcf-platform:
  rules:
    - if: $PLATFORM_PCF == "true"

.k8s-platform:
  rules:
    - if: $PLATFORM_K8S == "true"

.manual-feature-branch-optional:
  rules:
    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE != "schedule" && $CI_PIPELINE_SOURCE != "merge_request_event"
      when: manual
      allow_failure: true

.manual-default-branch-optional:
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE != "schedule"
      when: manual
      allow_failure: true

Now we imagine we have these jobs:


deploy-dev-pcf:
  extends:
    - .manual-feature-branch-optional
    - .pcf-platform
  script:
    - do deploy

deploy-dev-k8s:
  extends:
    - .manual-feature-branch-optional
    - .k8s-platform
  script:
    - do deploy

deploy-prod-pcf:
  extends:
    - .manual-default-branch-optional
    - .pcf-platform
  script:
    - do deploy
  

Now, imagine both PLATFORM_K8S and PLATFORM_PCF are set to true and the current branch is a feature branch (not default); as expected, both deploy-dev-pcf and deploy-dev-k8s are added to the pipeline but so as deploy-prod-pcf.

It seems the first rule that checks if the current branch is default branch is resolved to false but then it evaluates the next rule that checks PLATFORM_PCF equals to true and since it is true it adds the job while we are still in a feature branch.

I need to somehow make these two separate rules being And-ed so I can turn on/off jobs depending on the desired platform as well as the type of branch.

I could create one set of rules for Kubernetes and one set for PCF but that increases the number of rules unreasonably and I am reluctant to that approach.

In the documentation it is saying that only clauses are being evaluated with And but it seems only is being deprecated in favour of rules.

How can I achieve this?

答案1

得分: 2

为了正确理解这一点,您需要了解:

  • 如何将作业合并在一起;
  • 如何评估规则

或者您可以直接跳到最后一个标题来获取答案 如何使用And组合多个GitLab规则?

如何将作业合并在一起

您在这里的问题的一部分似乎是您对extends:在这种情况下的期望的问题。当数组值通过extends:相遇时,它们会互相覆盖,而不是组合在一起。请参阅合并详情以获取额外的上下文。

例如,考虑到这个配置:

.foo:
  rules:
    - if: $FOO == "foo"

.bar:
  rules:
    - if: $BAR == "bar"
job:
  extends:
    - foo
    - bar  # 这里的规则数组将覆盖之前的声明
  

换句话说,在这种情况下,只有这些规则中的一个集合将在最终的配置中生效,就像这样写的一样:

job:
  rules:
    - if: $BAR == "bar"

所以,在您的示例中,只有平台规则被应用,这导致了您观察到的行为。

一个解决方法是使用!reference来构建您的规则数组:

rules:
  - !reference [.foo, rules]
  - !reference [.bar, rules]

如何评估规则

这里需要理解的另一个方面是如何评估规则。GitLab将按顺序评估每个规则,并在第一个评估为true的规则处停止。最多只能有一个规则生效!如果没有规则匹配,该作业将被排除在管道之外。

因此,您可以以AND评估的方式有两种方法。

您可以将它们合并为单个规则,并使用&&运算符组合:

rules:
  - if: $FOO == "foo" && $BAR == "bar"

您还可以通过将不同规则按特定顺序排序并使用与when: never组合的逆逻辑来获得所需的效果。例如,这些规则具有与上述相同的效果:

rules:
  - if: $FOO != "foo"
    when: never
  - if: $BAR != "bar"
    when: never
  - when: on_success  # 基础情况很重要!

在这里反转逻辑(使用!=而不是==),我们允许评估继续到后续规则。如果您想要单独定义和重用规则,这一点非常重要。

在实践中

应用上述解释的理解,使用您的示例,您可以像这样做,这样您可以只定义每个规则一次:


# 定义不同的规则集
.rules:
  pcf-only:
    - if: $PCF_PLATFORM != "true"
      when: never
  k8s-only:
    - if: $K8S_PLATFORM != "true"
      when: never
  manual-feature-branch-optional:
    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE != "schedule" && $CI_PIPELINE_SOURCE != "merge_request_event"
      when: manual
      allow_failure: true

# 将这些规则以不同的方式组合在一起,以便重用
.k8s-deploy:
  rules: # 顺序很重要!
    - !reference [.rules, k8s-only]
    - !reference [.rules, manual-feature-branch-optional]

.pcf-deploy:
  rules:
    - !reference [.rules, pcf-only]
    - !reference [.rules, manual-feature-branch-optional]

# 根据需要使用`extends:`来扩展每个规则组合
deploy-dev-pcf:
  extends:
    - .pcf-deploy  
  script:
    - 进行部署

# 或者,您可以直接定义规则,而不是使用`extends:`  
deploy-dev-k8s:
  rules:
    - !reference [.rules, k8s-only]
    - !reference [.rules, manual-feature-branch-optional]
  script:
    - 进行部署

# ...等等

在这里,您可能还有其他的重构机会,但这可能不是问题的关键点 如何使用And组合多个GitLab规则?

英文:

In order to get this right, you'll need to understand:

  • How jobs are merged together; and
  • How rules are evaluated

Or you can just skip to the last heading for your answer 如何使用And组合多个GitLab规则?

How jobs are merged together

Part of your problem here seems to be your expectation of what extends: does in this case. When array values meet through extends:, they override one another and do not combine. See merge details for additional context.

For example, given this configuration:

.foo:
  rules:
    - if: $FOO == "foo"

.bar:
  rules:
    - if: $BAR == "bar"
job:
  extends:
    - foo
    - bar  # array of rules here will override the previous declarations
  

In other words, only one set of those rules will be effective in the resulting configuration in this case, as if written like so:

job:
  rules:
    - if: $BAR == "bar"

So, in your example, only the platform rule is being applied, which results in the behavior you are observing.

One way to get around this is to use !reference instead to build your rules array:

rules:
  - !reference [.foo, rules]
  - !reference [.bar, rules]

How rules are evaluated

Another aspect that needs understanding here is how rules are evaluated. GitLab will evaluate each rule in order and stop at the first rule that evaluates true. There can be at most, one rule that takes effect! If no rules match, the job is excluded from the pipeline.

So, there are a couple ways you can get the effect of AND evaluation.

You can combine it into a single rule and combine with && operators:

rules:
  - if: $FOO == "foo" && $BAR == "bar"

You can also get the effect you want by ordering different rules in a particular order and using the inverse logic combined with when: never. For example, these rules have the same effect as above:

rules:
  - if: $FOO != "foo"
    when: never
  - if: $BAR != "bar"
    when: never
  - when: on_success  # base case is important!

Inverting the logic here (checking != instead of ==), we allow evaluation to continue to subsequent rules. This is important if you want to define and re-use rules separately.

In practice

Applying the understandings explained above, using your example, you might do something like this which allows you to define each rule just once:


# define different sets of rules
.rules:
  pcf-only:
    - if: $PCF_PLATFORM != "true"
      when: never
  k8s-only:
    - if: $K8S_PLATFORM != "true"
      when: never
  manual-feature-branch-optional:
    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE != "schedule" && $CI_PIPELINE_SOURCE != "merge_request_event"
      when: manual
      allow_failure: true

# Combine these rules in different ways that can be reused
.k8s-deploy:
  rules: # Order matters!
    - !reference [.rules, k8s-only]
    - !reference [.rules, manual-feature-branch-optional]

.pcf-deploy:
  rules:
    - !reference [.rules, pcf-only]
    - !reference [.rules, manual-feature-branch-optional]

# Use `extends:` for each combination of rules as-needed
deploy-dev-pcf:
  extends:
    - .pcf-deploy  
  script:
    - do deploy

# alternatively, you can define rules directly instead of using `extends:`
deploy-dev-k8s:
  rules:
    - !reference [.rules, k8s-only]
    - !reference [.rules, manual-feature-branch-optional]
  script:
    - do deploy

# ... and so on

There's probably other refactoring opportunities for you here, but that's perhaps beside the point of the question 如何使用And组合多个GitLab规则?

huangapple
  • 本文由 发表于 2023年4月20日 09:18:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76059880.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定