$CI_COMMIT_TAG in "if" statemets of regular job

$CI_COMMIT_TAG in "if" statemets of regular job

我尝试做一个非常基本的 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>

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

我找到的解释 that i found 无助于使用“if”语句实现我的目标。
此处建议的解决方案 也无济于事。

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

Gitlab CI/CD 有多个 'pipeline sources',其中一些 Predefined Variables 只存在于某些来源。

例如,如果您只是 push 一个新的提交到远程,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
  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>

这有点混乱,所以这里一行一行:

  1. 如果 $CI_PIPELINE_SOURCE 变量不是 'push',我们 exit 0.
  2. 如果 $CI_COMMIT_REF_NAME(同样,提交 SHA、标记名称或分支名称)不是 develop 并且 $CI_COMMIT_TAG 为空,exit 0
  3. 如果 $CI_COMMIT_TAG 不为空,我们 运行 一个命令来查看标签是否基于 maingit branch --contains <tag_name>。这将 return 该标签所属的所有分支(即创建它的分支,以及创建标签后存在的所有分支)。然后我们通过 grep 传递结果来寻找 main。如果 main 在结果列表中,退出代码是 0 我们可以用特殊变量 $? 得到它(总是 return 是前一个命令的退出代码)。然后我们将此退出代码设置为一个变量以在下一个条件中使用。
  4. 我们检查 grep 的退出代码是否来自步骤 3. 是非 0(也就是说,如果 mainnot[=分支列表中的74=]是<tag_name>的一部分),而我们exit 0.

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