Gitlab CI:仅对受保护分支上存在的标记提交运行管道作业

问题描述 投票:0回答:1

我想创建一个仅在满足以下条件两个时才运行的管道:

  • 标签引用给定的提交
  • 提交存在于任何受保护的分支(即主分支)
  • 可选:只要将标记的未受保护分支合并(通过合并请求)到受保护分支或将标签添加到受保护分支,就应运行该作业。

我已经尝试过:

publish:
  stage: publish
  script:
    - echo "Publish!"
  rules:
    # Only publish if tag given and commit is present on a protected branch
    - if: '$CI_COMMIT_TAG && $CI_COMMIT_REF_PROTECTED == "true"'

这不起作用,因为

$CI_COMMIT_TAG
设置为
$CI_COMMIT_REF_PROTECTED
设置为true。

我知道类似的问题:Gitlab ci run job on master only withrelease tagHow to run a gitlab-ci.yml job only on a taggedbranch?.

我还知道 gitlab 对问题进行了广泛的讨论,有一些解决方案(或类似的解决方案),例如this

一般的问题似乎是,在 gitlab 中不可能确定给定分支上的提交是否可靠,因为未给出此信息(git 历史记录)。

这个问题是为了在 gitlab CI 中跟踪这个常见用例的正确解决方案。

tags conditional-statements gitlab-ci
1个回答
22
投票

将问题中提到的解决方法与新的gitlab规则工作流程功能相结合,我想出了一个令我满意的答案。

最初发布解决方法的人提到,在某些情况下

git branch contains
不会给出正确的结果。 所以我确保
git fetch
不会进行浅拷贝(请注意,一开始将
GIT_STRATEGY
更改为 clone 可能很有用,以便删除旧的可能的浅拷贝)。

我没有使用

CI_COMMIT_REF_PROTECTED
(这也适用于受保护的标签),而是将
$CI_DEFAULT_BRANCH
(感谢 [Gostega)硬编码为受保护。

# Be quite strict in what can trigger a pipeline, actually only pushes of
# branches or version tags should trigger anything - otherwise we need to catch
# too many edge cases.
workflow:
  rules:
    # Do no allow manually triggered pipelines to prevent duplicates!
    # Instead rerun the pipeline created with the last push
    - if: $CI_PIPELINE_SOURCE != "push"
      when: never
    # Only execute when a valid version tag like v1.0, 2.3 or similar is given
    # Required is always one point like 1.0
    - if: $CI_COMMIT_TAG =~ /^v?[0-9]+[.][0-9]+([.][0-9]+)?$/
    - if: $CI_COMMIT_BRANCH
variables:
  # Make sure we don't get a shallow copy
  GIT_DEPTH: 0
  # Fetch is default just to make clear what is used
  GIT_STRATEGY: fetch
  # make sure we fetch everything and also see what is happening
  GIT_FETCH_EXTRA_FLAGS: -f --tags --prune --update-head-ok

default:
  before_script:
    - export CI_LOG_LINE=$(git log --decorate=full| grep "^commit $CI_COMMIT_SHA[ ]")
    # var = 1 if the current commit is the **latest** on the default branch
    - export IS_ON_MAIN=$(echo $CI_LOG_LINE | grep -qso "origin/${CI_DEFAULT_BRANCH}, " && echo 1 || echo 0)
    # var = 1 if current commit is on any remote commit that is part of default branchs history
    - export COMMIT_ON_MAIN=$(git branch -r --contains $CI_COMMIT_SHA | grep -Eq "^[ ]+origin/${CI_DEFAULT_BRANCH}$"  && echo 1 || echo 0)


stages:
  - check_update_environment
  - test
  - publish

check_update_environment:
  stage: check_update_environment
  script:
    # Exit if tag is given on none main branch early
    # Check for 
    - if [[ ! -z "$CI_COMMIT_TAG" && $COMMIT_ON_MAIN != 1 ]]; then
         echo "Tags should never be applied to non main branches!" >&2;
         echo "We quit early! Please delete the tag, merge the branch to main and recreate the tag to continue" >&2;
         exit 1;
      fi

test:
  stage: test
  script:
    - echo "Doing testing..."
  dependencies:
    - check_update_environment

publish:
  stage: publish
  script:
    - echo "Publishing..."
  rules:
    # Run always if there is version tag. The version tag is defined
    #   in the workflow rules
    # Due to the fail early in the environment check this is never done for
    # branches that aren't the default branch
    - if: $CI_COMMIT_TAG
  dependencies:
    - test
© www.soinside.com 2019 - 2024. All rights reserved.