如何动态选择要在Jenkins构建中使用的git分支

时间:2017-04-03 11:30:02

标签: git jenkins build continuous-integration

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

ComponentA

  • 此组件中的更改会触发在CI服务器上构建此项目。
  • CI服务器已静态配置分支以监视更改和构建。例如。掌握或发展分支。
  • 此组件包含一个配置文件,其中包含所需的ComponentB版本。

以componentB

  • 对此组件的更改不会触发在CI服务器上构建此项目(还有另一个项目将涵盖ComponentB的开发)。
  • 标记组件的各个版本
  • ComponentA在其配置文件
  • 中需要ComponentB版本
  • 在以某种方式解析ComponentA的配置文件之前,CI服务器不知道要检出的分支(标记)。

在Jenkins上实现这一目标的正确方法是什么?我试图找出如何添加解析配置文件的动态行为,并使Git插件根据Co​​mponentB的预期版本检出分支,但到目前为止我没有任何线索。

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

修改

现在我看到我过多地简化了我的问题,并且由于简化,主要限制不再存在。

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

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

  • ComponentA:原生平台特定代码
  • ComponentB:与原始平台无关的代码

可能有许多组件为 - 每个平台一个,但只有一个组件B.将特定A与B合并为单个平台生成完整的源代码但不是每个平台都可以更新到最新版本的B,因此它需要控制哪个版本的B应该用于构建。

3 个答案:

答案 0 :(得分:18)

实现目标的一个选择是使用以下设置:

创建两个Jenkins作业:

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

步骤#1

为“组件B”定义branch build parameter

enter image description here

将此参数用作“Git插件”分支说明符:

enter image description here

现在,您应该能够通过为其指定适当的分支(标记)参数来手动触发“组件B”构建,例如, tags/5.3.0

步骤#2

向“Component A”构建添加一个新的“Execute Shell”构建步骤,该构建将从工作区中的配置文件中提取“Component B”版本,并使用“Component B”准备b.properties文件“建立参数。

enter image description here

安装Parameterized Trigger Jenkins插件,并在“其他项目”上添加新的“触发/调用构建”构建步骤到“组件A”作业:

enter image description here

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

现在每次重新构建“组件A”时,将触发新的“组件B”构建,目标分支/标记作为构建参数。

添加通配符支持

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

#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

这将在远程“组件B”存储库中列出匹配“B”版本模式的所有标记,并将最新版本号保存在LATEST变量中。

将此添加到“组件A”作业的“执行Shell”步骤, 它应该能够处理版本号模式,如:5.3.*

问题是shell脚本将作为Jenkins守护程序用户运行, 因此必须配置适当的凭据才能访问远程Git存储库(例如通过ssh pubkey)。

或者,您可能需要查看Credentials Binding Plugin,以重用存储在Jenkins中的Git凭据。

使用Jenkins 2.0样式管道

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

你的管道看起来像这样:

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
   }

}

这里我们使用“readProperties”命令,它是Pipeline Utility Steps Plugin的一部分,用于从meta.properties中提取“Component B”版本模式。还有readYaml,readJSON命令可用。

接下来,我们使用changelog: false, poll: false标志获取/克隆“Component B”,以防止它被注册为SCM轮询,进入当前工作空间的“module / b”文件夹。

然后根据我们上面获得的版本模式调用一个shell命令来选择标签,然后结帐(5.3。*样式通配符也应该有效)。

sh调用包含在sshagent中,以使其重用相应的内容 来自Jenkins凭证商店的凭证。

答案 1 :(得分:2)

使用Credentials Binding Plugin对我来说效果很好(@zeppelin也提到过)

步骤:

全局凭据部分中:

  1. Add Credentials类型:“用户名密码”。这应该是使用 HTTPS 协议的组件B存储库git服务器的用户名和密码(SSH选项不适用于此目的)
  2. enter image description here

    在Jenkins作业配置中:

    1. 将组件A放在Git部分所有必填字段(存储库分支等)下的常规源代码管理中)。
      • 将存储库放在子目录中会更清晰,更清晰:在附加行为下选择Check out to a sub-directory并写入:component_a
    2. 请务必检查构建触发器 Build when a change is pushed to GitHub
    3. 在构建环境部分,勾选Use secret text(s) or file(s)

      • 输入Variable某个名称:MY_CRED
      • Credentials中选择您在步骤1中创建的特定凭据

      enter image description here

    4. 现在使用执行shell 代码中的MY_CRED,您将可以访问组件B存储库:

      DIR="component_b"
      if [ "$(ls -A $DIR/.git)" ]; then
          cd $DIR
          git fetch
      else
          git clone https://$MY_CRED@github.com/proj/component_b.git $DIR 
          cd $DIR
      fi
      git show
      

      enter image description here

      • 注意:您不会在日志中看到用户和密码,因此应该是安全的。你会看到:git clone 'https://****@github.com/proj/component_b.git' component_b
    5. 从组件A解析配置以获取所需的标记:TAG=$(cat ./component_a/config.cfg | grep ... | sed ...)

    6. 结帐所需代码:cd component_b; git checkout -f $TAG
      • 注意:-f强制标记。
    7. 现在运行代码并根据需要进行测试......

答案 2 :(得分:1)

1 - 将项目B添加为项目A的子仓库是否可能成为解决方案?

2-(如果真的要避免包含B的完整源代码):将B的构建推送到某个B_builds repo,并将此repo添加为A的子仓库一种可能的解决方案?

基本原理:使AB之间的依赖关系更加明确的一种方法是在存储库的依赖项中表示它。

这需要在管理A项目时添加额外的步骤:

update `B` sub repo in `A` project, and push this to `A`

每次为B生成新版本。

但是,您可以从A清楚地了解B的版本何时被整合(例如:&#34;我们仅从{{{}开始使用B 2.0.1 1}}&#34;),推送到A 4.3.2会触发你常用的Jenkins流程。