GitLab CI CD:跨项目触发pipeline
source link: https://dothinking.github.io/2022-01-27-GitLab-CI-CD%EF%BC%9A%E8%A7%A6%E5%8F%91%E8%B7%A8%E9%A1%B9%E7%9B%AEpipeline/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
GitLab CI CD:跨项目触发pipeline¶
发布于:2022-01-27 | 分类:devops
近期遇到一个问题,如何灵活管理分系统的版本号和最终产品的版本号。例如,对于前后端分离且分仓库管理的Web项目,前、后端维护各自的版本号(前端1.2.3,后端1.3.4),并且发布Web产品时自动根据tag
(1.0.0)作为产品的版本号编译到页面上。注意问题在于:最终产品的版本号很可能与前、后端都不相同,因此通过前端或者后端仓库提交tag
发布产品都不合适。
基本思路:创建发布仓库¶
因此考虑新建一个发布仓库,仅维护汇总后的前后端更新日志和发布版本号。同时考虑到产品发布后的hotfix
,也支持直接从受影响的前端或者后端仓库提交修复并部署。
综合来说,涉及两类自动化流程:
-
从发布仓库发布产品,同时触发前、后端仓库的部署,并根据提供的
tag
更新产品版本号 -
从前、后端发布
hotfix
,仅触发各自的部署,且不更新产品版本号,而是沿用发布仓库最新的tag
为简化表述,用A
表示发布仓库,分别用B1
、B2
表示前、后端仓库,则可用下图表示以上流程。
具体流程¶
基本设定:
-
仓库
B1
和B2
任意提交触发编译build
,忽略测试test
,如果是release
分支则触发部署deploy
-
仓库
A
仅在提交tag
后触发流程
考虑到模块化和就近原则,仓库A
负责获取当前最新的tag
作为产品版本号,仓库B1
、B2
负责各自的编译和发布,只不过编译前需要拿到产品版本号。参考下图具体流程:
-
如果从仓库
A
提交tag
触发流程,则直接获取最新版本号,然后分别触发仓库B1
和B2
的流程。以
B1
为例,注意此时直接到build
这个任务;B2
同理,不再赘述。 -
如果从仓库
B1
提交,由于编译前需要获取产品当前版本号,因此通过trigger A
任务触发仓库A
的流程。类似上文所述
A
的流程,只不过此时需要根据原始仓库(即B1
)确定只触发B1
的流程,进而来到B1
的build
。
最终效果¶
借助 GitLab CI/CD 的基本功能,执行效果参考下图,可见完整实现了上述流程。
- 从
A
发布版本1.1.0
- 从
B1
的release
分支提交hotfix
实现细节¶
总结几个关键点:
-
跨项目触发流程,例如上图中
B1
中trigger A
和A
中trigger B1
、trigger B2
-
执行任务的时机,例如
B1
中trigger A
仅在直接提交时执行,而build
仅当从上游流水pipeline
触发时执行。 -
跨项目触发流程时传递参数,例如通过
B1
的trigger A
进入A
的流程时,传递表明原始仓库即B1
的参数,以便选择性进入trigger B1
跨项目触发流程¶
这是本文的基础,具体说明参考官方文档 Multi-project pipelines。
downstream-job:
variables:
UPSTREAM_BRANCH: $CI_COMMIT_REF_NAME
trigger:
project: path/to/downstream/project
branch: stable-11-2
-
trigger
关键字指定将要触发的下游项目的具体路径,同时可以指定基于的分支branch
如果忽略分支即默认最新分支,则可以合并为
trigger: path/to/downstream/project
-
variables
关键字将当前流程的参数传递到下游流程的每个任务中去,例如此处$CI_COMMIT_REF_NAME
表示当前分支名更多内置参数参考 Predefined CI/CD variables
trigger:project
不支持变量输入,trigger:branch
支持变量输入。
任务执行条件¶
GitLab CI/CD通过 only / except
和 rules
关键字,以非常灵活的方式将任务加入或者排除当前流程。
本文相关的几个例子:
-
从上游仓库触发
B1
不执行trigger A
trigger_a: stage: trigger trigger: path/to/A except: - pipelines
-
当且仅当从上游仓库触发
B1
时才执行build
build: stage: build script: - ... only: - pipelines
-
从上游仓库触发
B1
且当前分支是release
时才执行deploy
deploy: stage: deploy script: - echo "Deploying application only if branch=release..." rules: - if: $CI_PIPELINE_SOURCE=="pipeline" && $SOURCE_BRANCH=="release"
其中,
CI_PIPELINE_SOURCE
也是默认CI/CD参数,表示流程的触发源,值pipeline
表明从上游流程触发而来;SOURCE_BRANCH
也是从上游流程传递过来的表明当前分支的自定义参数。 -
A
中get version number
任务只有在tag
提交或者从其他流程触发而来才执行get_version_number: stage: prepare script: - ... only: - /^([0-9]+)\.([0-9]+)\.([0-9]+)$/ - pipelines
-
A
中trigger B1
任务满足以下两种情形之一即可执行:-
直接从
A
仓库tag
提交 -
从其他流程触发且自定义参数
SOURCE_PROJECT
的值等于B1
即从B1
触发的流程
trigger_b1: stage: trigger trigger: project: path/to/B1 branch: $TARGET_BRANCH rules: - if: $CI_COMMIT_TAG =~ /^([0-9]+)\.([0-9]+)\.([0-9]+)$/ - if: $CI_PIPELINE_SOURCE=="pipeline" && $SOURCE_PROJECT=="B1"
-
完整ymal
文件¶
补充一点:本例的产品版本号是通过保存文件的形式在两个流程间传递的,因此需要保证各流程都在同一台gitlab-runner上执行。而这,可以通过设定相同的tags
来实现。
最后,分别列出各仓库的ymal文件。
# .gitlab-ci.yml for project A
variables:
PROJECT_B1: "B1"
PROJECT_B2: "B2"
VERSION_FILE: /tmp/version
TARGET_BRANCH: "release"
stages:
- prepare
- trigger
check_version:
stage: prepare
script:
- VERSION=$(git describe --tags $(git rev-list --tags --max-count=1)) # recent tag
- if [ "$VERSION" = "" ]; then VERSION="1.0.0"; fi
- VERSION="$VERSION.$(date +%Y%m%d)"
- echo $VERSION>$VERSION_FILE
only:
- /^([0-9]+)\.([0-9]+)\.([0-9]+)$/
- pipelines
tags:
- shell_runner
trigger_b1:
stage: trigger
variables:
SOURCE_BRANCH: $TARGET_BRANCH
trigger:
project: path/to/B1
branch: $TARGET_BRANCH
rules:
- if: $CI_COMMIT_TAG =~ /^([0-9]+)\.([0-9]+)\.([0-9]+)$/
- if: $CI_PIPELINE_SOURCE=="pipeline" && $SOURCE_PROJECT==$PROJECT_B1
trigger_b2:
stage: trigger
variables:
SOURCE_BRANCH: $TARGET_BRANCH
trigger:
project: path/to/B2
branch: $TARGET_BRANCH
rules:
- if: $CI_COMMIT_TAG =~ /^([0-9]+)\.([0-9]+)\.([0-9]+)$/
- if: $CI_PIPELINE_SOURCE=="pipeline" && $SOURCE_PROJECT==$PROJECT_B2
# .gitlab-ci.yml for project B1; same with B2
stages:
- trigger
- build
- deploy
trigger_a:
variables:
SOURCE_PROJECT: $CI_PROJECT_NAME
TARGET_BRANCH: $CI_COMMIT_REF_NAME
stage: trigger
trigger: path/to/A
except:
- pipelines
build:
stage: build
script:
- VERSION=$(cat $VERSION_FILE)
- echo $VERSION
only:
- pipelines
tags:
- shell_runner
deploy:
stage: deploy
script:
- echo "Deploying application only if branch=release..."
rules:
- if: $CI_PIPELINE_SOURCE=="pipeline" && $SOURCE_BRANCH=="release"
tags:
- shell_runner
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK