提问人:Misiu 提问时间:11/16/2023 更新时间:11/17/2023 访问量:44
仅当推送到主 main 上的开发或标记时才运行作业
Run job only when push to develop or tag on main
问:
我正在尝试配置我的第一个 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_script
IMAGE_TAG
BUILD
我尝试过使用规则或,但是当我添加这些变量时,我的作业被跳过了。BRANCH
BUILD
我怎样才能运行,并且只有在以下情况下运行:完成推送以开发或在 main 上创建标签?build_image
push_image
最糟糕的部分是在我创建标签时获取分支名称,因为根据 https://docs.gitlab.com/ee/ci/variables/predefined_variables.html 在标签管道中不可用。CI_COMMIT_BRANCH
我已经检查了多个问题,其中一些建议在规则中使用多个 if,但请记住,问题是:
- 在创建标签时获取分支名称
- 使用在规则中before_script设置的变量
答:
使用在规则中before_script设置的变量
这是不可能的,因为所有内容都是在 GitLab 服务器上评估的,以便首先创建管道。因此,不能在同一管道中使用在作业中创建的变量。rules:
rules:
在创建标签时获取分支名称
这并不是一回事,因为标签一开始就没有与分支关联;标签仅与提交相关联。推送标签时,推送事件不包含任何分支信息,标签本身也不包含任何分支信息。这就是 git 的工作方式。
从技术上讲,您可以使用它来确定哪些分支(如果有)包含与标签关联的提交。(例如,请参阅:如何列出包含给定提交的分支?-- 不幸的是,GitLab 并没有以一种可以使用的方式提供这些信息 -- 即使你能够使用脚本来确定你想知道的内容,如前所述,在创建管道之前就对其进行了评估,所以你不能运行脚本来确定这一点,然后在git
rules:
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.yml
calculate_something
rules:
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 调用)来计算分支上是否存在与标签关联的提交,并将该信息传递给下游管道:git
main
# .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:
main
exit 0
job:
rules:
- if: $CI_COMMIT_TAG
needs: [check_if_tag_is_on_main]
script:
- if [ "$TAG_ON_MAIN" != "true" ]; then exit 0; fi
评论
before_script
exit 0
评论