仅当推送到主 main 上的开发或标记时才运行作业

Run job only when push to develop or tag on main

提问人:Misiu 提问时间:11/16/2023 更新时间:11/17/2023 访问量:44

问:

我正在尝试配置我的第一个 gitlab ci。
我的想法是,只有当我在主分支上使用 git tag 作为 docker 标签创建标签时,或者当我推送开发时,才会构建 docker 映像。

这是我的文件:.gitlab-ci.yml

# global variables - can't be change using before_script
variables:
  IMAGE_NAME: "backupchecker"
  PORTAINER_WEBHOOK_KEY: "b1b9c532-0cfa-609b-92dc-7af3767bd9a1"

# variables
before_script:
  - apk --no-cache add git
  # bet branch name
  - git fetch &> /dev/null
  - CI_COMMIT_BRANCHES=$(git for-each-ref | grep $CI_COMMIT_SHA | grep /remotes/origin/ | sed "s/.*\///")
  - >
    for CI_COMMIT_BRANCH in $CI_COMMIT_BRANCHES; do
      export BRANCH=$CI_COMMIT_BRANCH
    done

  - |
    if [ "$BRANCH" == "main" ] && [ -n "$CI_COMMIT_TAG" ]; then
      export IMAGE_TAG=$CI_COMMIT_TAG
    else
      export IMAGE_TAG="${CI_COMMIT_BRANCH}-latest"
    fi

    #if on main and there is a tag or on develop and there is push
  - |
    if [ "$BRANCH" == "main" ] && [ $CI_COMMIT_TAG ]; then
      export BUILD="true"
    elif [ "$BRANCH" == "develop" ] && [ $CI_PIPELINE_SOURCE == "push" ]; then
      export BUILD="true"
    else
      export BUILD="false"
    fi

  - echo $BUILD
  - echo $IMAGE_TAG

stages:
  - build
  - push
  - deploy

build_image:
  stage: build
  rules:
    - if: '($CI_COMMIT_REF_NAME == "main" || $CI_COMMIT_REF_NAME == "develop" || $CI_COMMIT_TAG) && $CI_COMMIT_MESSAGE !~ /(no|skip)-build/'
  script:
    - docker build -t ${docker_registry}/${IMAGE_NAME}:${IMAGE_TAG} -f BackupChecker/Dockerfile .

push_image:
  stage: push
  rules:
    - if: '($CI_COMMIT_REF_NAME == "main" || $CI_COMMIT_REF_NAME == "develop" || $CI_COMMIT_TAG) && $CI_COMMIT_MESSAGE !~ /(no|skip)-build/'
  script:
    - docker login ${docker_registry} -u docker -p ${docker_registry_pass}
    - docker push ${docker_registry}/${IMAGE_NAME}:${IMAGE_TAG}

portainer:
  stage: deploy
  rules:
    - if: '$CI_COMMIT_REF_NAME == "develop" && $CI_COMMIT_MESSAGE !~ /(no|skip)-(build|deploy)/'
  before_script:
    - apk add --update curl && rm -rf /var/cache/apk/*
  script:
    - 'curl -X POST "https://portainer.example.com/api/webhooks/${PORTAINER_WEBHOOK_KEY}"'

在全局部分中,我获得了分支名称(我不知道是否有更好的方法),并在此基础上创建变量。
我也在设置变量。
before_scriptIMAGE_TAGBUILD

我尝试过使用规则或,但是当我添加这些变量时,我的作业被跳过了。BRANCHBUILD

我怎样才能运行,并且只有在以下情况下运行:完成推送以开发或在 main 上创建标签?build_imagepush_image

最糟糕的部分是在我创建标签时获取分支名称,因为根据 https://docs.gitlab.com/ee/ci/variables/predefined_variables.html 在标签管道中不可用。CI_COMMIT_BRANCH

我已经检查了多个问题,其中一些建议在规则中使用多个 if,但请记住,问题是:

  • 在创建标签时获取分支名称
  • 使用在规则中before_script设置的变量
GitLab-CI

评论


答:

1赞 sytech 11/17/2023 #1

使用在规则中before_script设置的变量

这是不可能的,因为所有内容都是在 GitLab 服务器上评估的,以便首先创建管道。因此,不能在同一管道中使用在作业中创建的变量。rules:rules:

在创建标签时获取分支名称

这并不是一回事,因为标签一开始就没有与分支关联;标签仅与提交相关联。推送标签时,推送事件不包含任何分支信息,标签本身也不包含任何分支信息。这就是 git 的工作方式。

从技术上讲,您可以使用它来确定哪些分支(如果有)包含与标签关联的提交。(例如,请参阅:如何列出包含给定提交的分支?-- 不幸的是,GitLab 并没有以一种可以使用的方式提供这些信息 -- 即使你能够使用脚本来确定你想知道的内容,如前所述,在创建管道之前就对其进行了评估,所以你不能运行脚本来确定这一点,然后在gitrules:rules:rules:


唯一可能的解决方法是使用父管道来计算作业中所需的信息,然后触发子管道,传递随后可在子管道中使用的变量。rules:

作为一般示例,父管道 yaml 可能包含如下内容:

calculate_something:
  # calculate a value so it can be passed to the trigger job
  # for the sake of the demo, it's just a static value
  # you would need to implement a script to generate the value(s) you want
  script:
    - something="value"
    - echo "SOMETHING=$something" > vars.env
  artifacts:
    reports:
      dotenv: vars.env

trigger_downstream:
  needs: [calculate_something]
  variables:  # gets the value from dotenv artifact
    SOMETHING: $SOMETHING
  # trigger another pipeline that can use `$SOMETHING` in its `rules:`
  trigger:
    include: downstream.gitlab-ci.yml
    forward:
      pipeline_variables: true
    strategy: depend

这将允许 中定义的子管道在其downstream.gitlab-ci.ymlcalculate_somethingrules:

some_job:
  rules:
    - if: $SOMETHING == "value"
  script:
    - echo '$SOMETHING was "value"'

another_job:
  rules:
    - if: $SOMETHING != "value"
  script:
    - echo '$SOMETHING was not "value" it was "'"$SOMETHING\""

将其应用于您的案例,您可以使用命令(或 GitLab API 调用)来计算分支上是否存在与标签关联的提交,并将该信息传递给下游管道:gitmain

# .gitlab-ci.yml
check_if_tag_is_on_main:
  rules:
    - if: $CI_COMMIT_TAG
  script: 
    - git remote set-url origin "https://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git"
    - git fetch origin
    - tag_branches="$(git branch -a --contains $CI_COMMIT_SHA)"
    - |
      if grep -E '^(\*)?(\s+)?(remotes/origin/)?main$' <<< $tag_branches; then
          tag_on_main="true"
      else
          tag_on_main="false"
      fi
    - echo "TAG_ON_MAIN=$tag_on_main" > $CI_PROJECT_DIR/vars.env
  artifacts:
    reports:
      dotenv: vars.env

trigger_downstream:
  rules:
    - if: $CI_COMMIT_TAG
  needs: [check_if_tag_is_on_main]
  variables:
    TAG_ON_MAIN: $TAG_ON_MAIN
  trigger:
    include: downstream.gitlab-ci.yml
    forward:
      pipeline_variables: true
    strategy: depend
# downstram.gitlab-ci.yml
some_job:
  rules:
    - if: $TAG_ON_MAIN == "true"
  script:
    - echo "tag was on main"
    - echo "tag ${CI_COMMIT_TAG}"

another_job:
  rules:
    - if: $TAG_ON_MAIN != "true"
  script:
    - echo "tag was not on main"
    - echo "tag ${CI_COMMIT_TAG}"

如果不想使用子管道方法,也可以完全不使用,而只是在管道中对此进行评估。您可以使用相同的脚本逻辑来检查分支是否打开,以及它是否未打开。rules:mainexit 0

job:
  rules:
    - if: $CI_COMMIT_TAG
  needs: [check_if_tag_is_on_main]
  script:
    - if [ "$TAG_ON_MAIN" != "true" ]; then exit 0; fi

评论

0赞 Misiu 11/17/2023
感谢您如此详细的回答。我能够在全局中添加分支计算逻辑,在未满足条件时调用的最后一步中。before_scriptexit 0