如何动态选择要在 Jenkins 构建中使用的 git 分支 [英] How to dynamically pick a git branch to use in Jenkins build

查看:78
本文介绍了如何动态选择要在 Jenkins 构建中使用的 git 分支的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为 Jenkins 构建服务器创建一个新的项目配置.为了简化我正在尝试做的事情,我将仅使用两个组件来描述问题.

组件A

  • 此组件的更改会触发此项目在 CI 服务器上的构建.
  • CI 服务器具有静态配置的分支来监控更改和构建.例如.master 或 development 分支.
  • 此组件包含一个配置文件,其中包含它所依赖的 ComponentB 的所需版本.

组件B

  • 对此组件的更改不会触发在 CI 服务器上构建此项目(将有另一个项目来涵盖 ComponentB 的开发).
  • 标记各个版本的组件
  • ComponentA 在其配置文件中有所需的 ComponentB 版本
  • 在 ComponentA 的配置文件被解析之前,CI 服务器不知道要检查哪个分支(标签).

在 Jenkins 上实现这一目标的正确方法是什么?我试图找出如何添加这种解析配置文件的动态行为,并使 Git 插件根据预期版本的 ComponentB 检查分支,但到目前为止我不知道.

在下一步中,我什至可能希望在配置文件中包含通配符(如 5.3.*),因此我必须找到与通配符匹配的最新 ComponentB 标记.

编辑

现在我发现我过于简化了我的问题,并且由于简化,主要限制不再存在.

主要限制是组件 A 和 B 必须一起构建.无法单独构建它们,因为它们形成一个可执行文件/库,并且构建脚本需要来自两个组件的源文件.

如果你问为什么这么奇怪的配置,让我们给组件 A 和 B 一些描述:

  • ComponentA:本机平台特定代码
  • ComponentB:与本机平台无关的代码

可能有许多 Component As - 每个平台一个,但只有一个 Component B.将特定 A 与 B 合并会为单个平台生成完整的源代码,但并非每个平台都可以更新到 B 的最新版本,因此需要可以控制应该使用哪个版本的 B 进行构建.

解决方案

实现您想要的一个选项是使用以下设置:

创建两个 Jenkins 作业:

  • 组件 A"(在 SCM 更改时自动触发)
  • 组件 B"(手动"触发)

步骤 #1

定义分支

将此参数用作Git 插件";分支说明符:

现在您应该可以手动触发组件 B"了.通过为其指定适当的分支(标签)参数来构建,例如tags/5.3.0.

步骤 #2

添加一个新的Execute Shell"构建组件 A"的步骤build,它将提取组件 B";从工作区中的配置文件中获取版本,并使用组件 B"准备 b.properties 文件构建参数.

安装

使用您的 b.properties 文件作为构建参数的来源.

现在每次组件 A"正在重建,一个新的组件 B";构建将被触发,目标分支/标签作为构建参数.

添加通配符支持

如果要支持通配符版本,可以使用 git ls-remote 命令查找最新标签,如下所示:

#B=$(按常规方式从配置文件中获取B版本)最新=$(git ls-remote --tags YOUR_REPOSITORY_URL "$B"|cut -d/-f3|sort -r --version-sort|head -1)猫<<EOF>b. 属性分支=标签/$LATESTEOF

这将列出所有标签,匹配B";版本模式,在远程组件 B"中;存储库,并将最新版本号保存在 LATEST 变量中.

将此添加到您的执行 Shell"中组分A"的步骤;工作,它应该能够处理版本号模式,例如:5.3.*

需要注意的是,shell 脚本将以 Jenkins 守护程序用户身份运行,所以它必须配置正确的凭据,才能访问远程 Git 存储库(例如,通过 ssh pubkey).

或者,您可能需要查看 凭据绑定插件,以重用存储在 Jenkins 本身中的 Git 凭据.

使用 Jenkins 2.0 风格的管道

您还可以使用 Jenkins 2.0 风格的 Pipeline 来解决手头的任务,这将允许您将组件 A 和 B 的代码签出到单个工作区中,然后对它们应用一些常见的构建步骤.

您的管道可能如下所示:

节点{//设置def credentialsId = '8fd28e34-b04e-4bc5-874a-87f4c0e05a03'def repositoryA = 'ssh://git@stash.com/projects/a.git'def repositoryB = 'ssh://git@stash.com/projects/b.git'stage('结帐组件 A') {git credentialsId: credentialsId ,url:repositoryA,分支:master"}stage(解决并检查组件 B") {def deps = readProperties 文件:'meta.properties'echo "已解决 B 版本 = ${deps['b']}"目录(模块/b"){//克隆/获取组件B结帐单片机:[$class: 'GitSCM',userRemoteConfigs:[[url:repositoryB,credentialsId:credentialsId]],分支:[[名称:'refs/tags/*']]],变更日志:假,民意调查:假//签出标签,匹配deps['b']模式sshagent([credentialsId]) {sh "git checkout $(git tag -l "${deps['b']}" |sort -r --version-sort|head -1)"}}}阶段(构建 A+B"){//应用一个通用的构建步骤}}

这里我们使用readProperties";命令,它是 管道实用程序步骤插件的一部分提取组分B";meta.properties 中的版本模式.还有 readYaml、readJSON 命令可用.

接下来,我们使用 changelog: false, poll: false 标志获取/克隆组件 B",以防止它被注册为 SCM 轮询,进入模块/b"当前工作区的文件夹.

然后调用shell命令选择标签,根据我们上面获得的版本模式,并检查它(5.3.*风格的通配符也应该工作).

sh 调用包含在 sshagent,使其重用适当的来自 Jenkins 凭据存储的凭据.

I'm trying to create a new project configuration for Jenkins build server. To simplify what I'm trying to do, I will use only two components to describe the problem.

ComponentA

  • Change in this component triggers the build of this project on CI server.
  • CI server has statically configured branch to monitor for changes and build. Eg. master or develop branch.
  • This component contains a configuration file with required version of ComponentB it depends on.

ComponentB

  • Changes to this component don't trigger build of this project on CI server (there will be another project to cover development of ComponentB).
  • Individual versions of component are tagged
  • ComponentA has required version of ComponentB in its configuration file
  • CI server does not know what branch (tag) to checkout until configuration file of ComponentA is somehow parsed.

What is the right way to achieve this on Jenkins? I was trying to find out how to add this dynamic behavior of parsing the config file and making Git Plugin to check out branch based on expected version of ComponentB but so far I have no clue.

In the next step I may even want to have wildcards (like 5.3.*) in configuration file so I will have to find a the newest ComponentB's tag matching the wildcard.

EDIT

Now I see that I simplified my problem too much and due to the simplification, the main limitation is no longer present.

The main limitation is that Component A and B must be built together. It is not possible to build them separately as they form one executable / library and the build script needs source files from both components.

If you ask why such a strange configuration, let's give Component A and B some description:

  • ComponentA: Native platform specific code
  • ComponentB: Native platform independent code

There may be many Component As - one for each platform, but just single Component B. Merging particular A with B produces full source code for single platform but not every platform may be updated to the latest version of B so it needs to have control over which version of B should be used for built.

解决方案

One option to achieve what you want is to use the following setup:

Create two Jenkins jobs:

  • "Component A" (automatically triggered on SCM changes)
  • "Component B" ("manually" triggered)

Step #1

Define the branch build parameter for "Component B":

Use this parameter as the "Git Plugin" branch specifier:

Now you should be able to manually trigger "Component B" build, by specifying a proper branch (tag) parameter to it, e.g. tags/5.3.0.

Step #2

Add a new "Execute Shell" build step to your "Component A" build, which will extract the "Component B" version from the configuration file in the workspace, and prepare b.properties file with the "Component B" build parameters.

Install a Parameterized Trigger Jenkins plugin, and add a new "Trigger/call builds on other projects" build step to "Component A" job:

Using your b.properties file as the source of build parameters.

Now each time "Component A" is re-build, a new "Component B" build will get triggered, with the target branch/tag as a build parameter.

Adding wildcard support

If you want to support wildcard versions, you can use git ls-remote command to find the latest tag, like that:

#B=$(obtain B version from the config file in a usual way)   

LATEST=$(
    git ls-remote --tags YOUR_REPOSITORY_URL "$B"
    |cut -d / -f3|sort -r --version-sort|head -1
)
 
cat <<EOF > b.properties
    branch=tags/$LATEST
EOF

This will list all the tags, matching "B" version pattern, in the remote "Component B" repository, and save the latest version number in the LATEST variable.

Add this to your "Execute Shell" step of the "Component A" job, and it should be able to handle version numbers patterns like: 5.3.*

The catch is that the shell script will run as the Jenkins daemon user, so it must have proper credentials configured, to access the remote Git repository (e.g. via the ssh pubkey).

Alternatively you may want to look into the Credentials Binding Plugin, to reuse the Git credentials stored in Jenkins itself.

Using Jenkins 2.0 style pipeline

You can also solve the task at hand by using a Jenkins 2.0-style Pipeline, which will allow you to checkout the code for components A and B, into a single workspace, and then apply some common build step to them.

Your pipeline could look something like this:

node {

   //Settings
   def credentialsId = '8fd28e34-b04e-4bc5-874a-87f4c0e05a03'    
   def repositoryA = 'ssh://git@stash.com/projects/a.git'
   def repositoryB = 'ssh://git@stash.com/projects/b.git'

   stage('Checkout component A') {
      git credentialsId: credentialsId , 
      url: repositoryA , branch : "master"
   }
   
   stage("Resolve and checkout component B") {
      def deps = readProperties file: 'meta.properties'
      echo "Resolved B version = ${deps['b']}"
      
      dir("module/b") {
           //Clone/Fetch Component B 
           checkout scm:[
                $class: 'GitSCM', 
                userRemoteConfigs: [[url: repositoryB, credentialsId: credentialsId]], 
                branches: [[name: 'refs/tags/*']]
           ], 
           changelog: false, poll: false

           //Checkout the tag, matching deps['b'] pattern     
           sshagent([credentialsId]) {
                sh "git checkout $(git tag -l "${deps['b']}" |sort -r --version-sort|head -1)"
           }
      }
   }
   
   stage("Build A+B") {
        //Apply a common build step
   }

}

Here we use the "readProperties" command, which is part of the Pipeline Utility Steps Plugin to extract the "Component B" version pattern from meta.properties. There are also readYaml, readJSON commands available.

Next we fetch/clone the "Component B", with the changelog: false, poll: false flags, to prevent it from being registered for the SCM poll, into the "module/b" folder of the current workspace.

Then invoke a shell command to select the tag, based on the version pattern, we have obtained above, and checkout it (5.3.* style wildcards should also work).

The sh invocation, is wrapped in the sshagent, to make it reuse the appropriate credentials from the Jenkins credential store.

这篇关于如何动态选择要在 Jenkins 构建中使用的 git 分支的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆