【问题标题】:Gitlab CI: Run Pipeline job only for tagged commits that exist on protected branchesGitlab CI:仅为受保护分支上存在的标记提交运行管道作业
【发布时间】:2020-10-26 14:43:40
【问题描述】:

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

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

我试过了:

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 with release tag onlyHow to run a gitlab-ci.yml job only on a tagged branch?

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

一般的问题似乎是在 gitlab 中无法确定在给定分支上提交是否可靠,因为没有给出相关信息(git 历史记录)。

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

【问题讨论】:

    标签: tags conditional-statements gitlab-ci


    【解决方案1】:

    将问题中的workaround mentioned 与新的gitlab ruleworkflow 功能结合起来,我想出了一个令我满意的答案。

    最初发布解决方法的人提到在某些情况下git branch contains 没有给出正确的结果。 所以请确保git fetch 不会进行浅拷贝(请注意,开始时将GIT_STRATEGY 更改为clone 会很有用,这样可能会删除旧的浅拷贝)。

    我没有使用 CI_COMMIT_REF_PROTECTED 这也适用于受保护的标签,而是将主分支硬编码为受保护的。

    # 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 master
        - export IS_ON_MASTER=$(echo $CI_LOG_LINE | grep -qso "origin/master, " && echo 1 || echo 0)
        # var = 1 if current commit is on any remote commit that is part of masters history
        - export COMMIT_ON_MASTER=$(git branch -r --contains $CI_COMMIT_SHA | grep -Eq '^[ ]+origin/master$'  && echo 1 || echo 0)
    
    
    stages:
      - check_update_environment
    
    check_update_environment:
      stage: check_update_environment
      script:
        # Lets print some debug stuff
        - echo $CI_JOB_TRIGGERED
        - echo $CI_PIPELINE_SOURCE
        - echo $CI_COMMIT_SHA
        - echo $CI_COMMIT_REF_NAME
        - echo $CI_BUILD_REF
        - echo $CI_COMMIT_BRANCH
        - echo $CI_COMMIT_TAG
        # Get the information about the state of the current commit
        - git log --decorate=full| grep "^commit $CI_COMMIT_SHA[ ]" || echo "Failed???"
        - git status
        - git remote show
        # Show current branch --> normally fails - only for kept for reference
        - git symbolic-ref --short HEAD || echo "Doesn't work"
        # Some more possible debug information
        - git branch --contains $CI_BUILD_REF
        - git tag --contains $CI_BUILD_REF
        - env
        # **Finally the important part**
        # Exit if tag is given on none master branch early
        - if [[ ! -z "$CI_COMMIT_TAG" && $COMMIT_ON_MASTER != 1 ]]; then
             echo "Tags should never be applied to non master branches!" >&2;
             echo "We quit early! Please delete the tag, merge the branch to master 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 master
        - if: $CI_COMMIT_TAG
      dependencies:
        - test
    

    【讨论】:

    • 嘿@Kound 你还在使用这个解决方法,还是你开发了更好的方法?顺便说一句,我没有硬编码掌握,而是使用if: $CI_COMMIT_REF_NAME != $CI_DEFAULT_BRANCH。这让我可以在任何项目中重复使用它(我们已经开始将 main 作为默认分支名称,因此可以混合使用名称)。
    • 嘿@Gostega 感谢您的提示。我会尽快测试并更新答案。我没有开发更复杂的解决方案,而这个解决方案仍在运行中。顺便说一句:$CI_COMMIT_REF_NAME 将是由标签触发的管道标签。因此,这对于检查标记管道是否在 master 上没有用。 (另见docs.gitlab.com/ee/ci/variables/predefined_variables.html
    猜你喜欢
    • 2022-11-04
    • 2022-01-03
    • 1970-01-01
    • 2022-11-19
    • 2019-05-28
    • 2022-01-16
    • 2020-05-05
    • 1970-01-01
    • 2015-03-17
    相关资源
    最近更新 更多