常规作业的“if”语句中的 $CI_COMMIT_TAG

Art*_*kov 7 deployment docker gitlab-ci gitlab-ci-runner devops

我尝试做一个非常基本的 GitLab CI 工作。
我想要:
当我推送到开发时,gitlab 会使用标签“develop”构建 docker 镜像
当我推送到 main 时,gitlab 检查当前提交是否有标签,并用它构建镜像,否则不会触发作业。

Build and publish docker image:
  stage: build
  rules:
    - if:
        ($CI_COMMIT_BRANCH == "main" && $CI_COMMIT_TAG && $CI_PIPELINE_SOURCE == "push")
      variables:
        TAG: $CI_COMMIT_TAG
    - if:
        ($CI_COMMIT_BRANCH == "develop" && $CI_PIPELINE_SOURCE == "push")
      variables:
        TAG: develop
  script:
    - echo $TAG
    - ...<another commands>
Run Code Online (Sandbox Code Playgroud)

但它并没有按预期工作。$CI_COMMIT_TAG - 为空。尽管触发作业(合并提交)的提交有标签。

我发现我发现的解释并不能帮助使用“if”语句实现我的目标。基于此处建议的工作流程的
解决方案也没有帮助。

使用名为 COMMIT_TAG 的变量的直观方式似乎很常见。
但它就是行不通。请好心人向我解释如何实现我的目标吗?

Ada*_*all 14

Gitlab CI/CD 有多个“管道源”,并且某些预定义变量仅存在于某些源。

例如,如果您只是将新提交送到远程,则 的值CI_PIPELINE_SOURCE将为push。对于push管道来说,许多预定义变量将不存在,例如CI_COMMIT_TAGCI_MERGE_REQUEST_SOURCE_BRANCH_NAMECI_EXTERNAL_PULL_REQUEST_SOURCE_BRANCH_NAME等。

但是,如果您在 GitLab UI 中或通过git push --tags命令创建 Git 标签,它将创建一个标签管道,并且类似的变量CI_COMMIT_TAG将存在,但CI_COMMIT_BRANCH不会存在。

无论触发管道的原因是什么,都会存在一个始终存在的变量CI_COMMIT_REF_NAME。对于提交与分支绑定的推送源,此变量将保存分支名称。如果提交未绑定到分支(即,该提交曾经有一个分支,但现在已被删除),它将保留完整的提交 SHA。或者,如果管道用于标签,它将保存标签名称。

有关更多信息,请仔细阅读不同的管道源(在变量的描述中CI_PIPELINE_SOURCE)以及上面链接的文档中的其他变量。

我要做的就是将此检查移至该script部分,以便我们可以使其变得更加复杂以利于我们的利益,并且要么立即exit 0使作业不会运行并且不会失败,要么运行脚本的其余部分。

Build and publish docker image:
  stage: build
  image: alpine:latest
  script:
    - if [ $CI_PIPELINE_SOURCE != 'push' ]; then exit 0 fi
    - if [ $CI_COMMIT_REF_NAME != 'develop' && $CI_COMMIT_TAG == '' ]; then exit 0 fi
    - if [ $CI_COMMIT_TAG != '' ]; then git branch --contains $CI_COMMIT_TAG | grep main; TAG_ON_MAIN=$? fi
    - if [ $TAG_ON_MAIN -ne 0 ]; then exit 0 fi
    - echo $TAG
    - ...<other commands>
Run Code Online (Sandbox Code Playgroud)

这有点令人困惑,所以这里逐行说明:

  1. 如果$CI_PIPELINE_SOURCE变量不是“推”,我们exit 0.
  2. 如果$CI_COMMIT_REF_NAME(再次强调,提交 SHA、标记名称或分支名称)不是develop$CI_COMMIT_TAG为空,exit 0
  3. 如果$CI_COMMIT_TAG不为空,我们运行一个命令来查看标签是否基于main, git branch --contains <tag_name>。这将返回该标签所属的所有分支(即创建该标签的分支以及创建该标签后存在的所有分支)。然后我们将结果传递出去grep寻找main。如果main是在结果列表中,则退出代码是0我们可以通过特殊变量获得的$?(始终返回上一个命令的退出代码)。然后,我们将此退出代码设置为一个变量,以便在下一个条件中使用。
  4. 我们检查grepfrom 步骤3.退出代码是否为非 0(即,如果main不在分支列表中),并且我们.<tag_name>exit 0

在完成所有这些之后,我们可以确定 Pipeline Source 是push,或者有标签并且它位于main分支上,或者没有标签并且管道用于分支develop

  • 谢谢。你的文字和我的尝试有助于理解一点。从我的水平来看,有不同的推送(标签、分支)只是令人困惑,因为……好吧,我标记提交并执行 git 推送。提交被上传到带有标签和提交更改的存储库,所以......为什么 CI 无法识别该标签是不可理解的。但现在我只接受“ASIS”。将来随着更多的经验,可能会对它有更深入的了解。 (2认同)
  • 我必须在 `fi` 之后添加 `;`,否则我会得到 `/bin/sh: eval: line 136: 语法错误:意外的文件结尾(期望“fi”)` (2认同)