如何告诉Jenkins"在文件夹X"中构建每个项目?

时间:2016-05-24 22:38:13

标签: jenkins build jenkins-plugins

我已设置了一些文件夹(使用Cloudbees Folder Plugin)。

这听起来像是能够告诉Jenkins最简单的命令:在Folder X中构建每个作业。

我不想手动创建文件夹中每个作业的逗号分隔列表。每当我想要将作业添加到此文件夹时,我不想添加到此列表。我只是希望它在运行时找到文件夹中的所有作业,并尝试构建它们。

我找不到允许我这样做的插件。

我已尝试使用Build Pipeline PluginBulk Builder PluginMultiJob plugin和其他一些人。似乎没有人支持我之后的用例。我只想在文件夹中建立任何Job。换句话说,向此构建添加作业就像在此文件夹中创建作业一样简单。

我怎样才能做到这一点?

6 个答案:

答案 0 :(得分:4)

我一直在使用Jenkins多年,而且我找不到一种方法来做你想要的事情。

我所管理的最好的是: 我有一个“运行每个工作”的工作(包含所有你想要的工作的逗号分隔列表)。 然后我有一个单独的工作,定期运行并在新项目进出时更新“运行每个工作”工作。

答案 1 :(得分:2)

执行此操作的一种方法是创建一个管道作业,该作业运行Groovy脚本以枚举当前文件夹中的所有作业,然后启动它们。

以下版本要求禁用沙箱(因此可以访问Jenkins.instance)。

def names = jobNames()
for (i = 0; i < names.size(); i++) {
    build job: names[i], wait: false
}

@NonCPS
def jobNames() {
  def project = Jenkins.instance.getItemByFullName(currentBuild.fullProjectName)
  def childItems = project.parent.items

  def targets = []
  for (i = 0; i < childItems.size(); i++) {
      def childItem = childItems[i]
      if (!childItem instanceof AbstractProject) continue;
      if (childItem.fullName == project.fullName) continue;

      targets.add(childItem.fullName)
  }

  return targets
}

如果您使用Pipeline库,那么以下内容更好(并且不要求您允许Groovy沙箱转义:

将以下内容添加到您的库中:

package myorg;

public String runAllSiblings(jobName) {
  def names = siblingProjects(jobName)
  for (def i = 0; i < names.size(); i++) {
    build job: names[i], wait: false
  }
}

@NonCPS
private List siblingProjects(jobName) {
  def project = Jenkins.instance.getItemByFullName(jobName)
  def childItems = project.parent.items

  def targets = []
  for (def i = 0; i < childItems.size(); i++) {
    def childItem = childItems[i]
    if (!childItem instanceof AbstractProject) continue;
    if (childItem.fullName == jobName) continue;

    targets.add(childItem.fullName)
  }
  return targets
}

然后使用以下代码创建管道:

(new myorg.JobUtil()).runAllSiblings(currentBuild.fullProjectName)

是的,有一些方法可以进一步简化这一点,但它应该给你一些想法。

答案 2 :(得分:0)

我开发了一个Groovy脚本来执行此操作。它非常好用。有两个作业,initBuildAll,它运行groovy脚本,然后启动'buildAllJobs'作业。在我的设置中,我每天都会启动InitBuildAll脚本。你可以用另一种适合你的方式触发它。我们没有充满CI,所以每天对我们来说已经足够了。

有一点需要注意:这些工作都是彼此独立的。如果那不是你的情况,这可能需要一些调整。

这些作业位于名为MultiBuild的单独文件夹中。要构建的作业位于名为Projects的文件夹中。

import com.cloudbees.hudson.plugins.folder.Folder
import javax.xml.transform.stream.StreamSource
import hudson.model.AbstractItem
import hudson.XmlFile
import jenkins.model.Jenkins


    Folder findFolder(String folderName) {
      for (folder in Jenkins.instance.items) {
        if (folder.name == folderName) {
          return folder
        }
      }
      return null
    }

    AbstractItem findItem(Folder folder, String itemName) {
      for (item in folder.items) {
        if (item.name == itemName) {
          return item
        }
      }
      null
    }


    AbstractItem findItem(String folderName, String itemName) {
      Folder folder = findFolder(folderName)
      folder ? findItem(folder, itemName) : null
    }

    String listProjectItems() {
      Folder projectFolder = findFolder('Projects')
      StringBuilder b = new StringBuilder()
      if (projectFolder) {

        for (job in projectFolder.items.sort{it.name.toUpperCase()}) {
          b.append(',').append(job.fullName)
        }
        return b.substring(1) // dump the initial comma
      }
      return b.toString()
    }

    File backupConfig(XmlFile config) {
      File backup = new File("${config.file.absolutePath}.bak")
      FileWriter fw = new FileWriter(backup)
      config.writeRawTo(fw)
      fw.close()
      backup
    }


    boolean updateMultiBuildXmlConfigFile() {
      AbstractItem buildItemsJob = findItem('MultiBuild', 'buildAllProjects')
      XmlFile oldConfig = buildItemsJob.getConfigFile()

      String latestProjectItems = listProjectItems()
      String oldXml = oldConfig.asString()
      String newXml = oldXml;
      println latestProjectItems
      println oldXml

      def mat = newXml =~ '\\<projects\\>(.*)\\<\\/projects\\>'
      if (mat){
        println mat.group(1)
        if (mat.group(1) == latestProjectItems) {
           println 'no Change'
           return false;
        } else {
          // there's a change
             File backup = backupConfig(oldConfig)
           def newProjects = "<projects>${latestProjectItems}</projects>"
           newXml = mat.replaceFirst(newProjects)
           XmlFile newConfig = new XmlFile(oldConfig.file)
           FileWriter nw = new FileWriter(newConfig.file)
           nw.write(newXml)
           nw.close()
           println newXml
           println 'file updated'
           return true
        }
      }
      false
    }

    void reloadMultiBuildConfig() {
      AbstractItem job = findItem('MultiBuild', 'buildAllProjects')

      def configXMLFile = job.getConfigFile();
      def file = configXMLFile.getFile();

      InputStream is = new FileInputStream(file);

      job.updateByXml(new StreamSource(is));
      job.save();

      println "MultiBuild Job updated"

    }

    if (updateMultiBuildXmlConfigFile()) {
      reloadMultiBuildConfig()
    }

答案 3 :(得分:0)

Wayne Booth的“运行每项工作”方法略有不同。经过一番小小的讨论,我能够在Job DSL format中定义一个“运行每一份工作”。

优点是我可以在版本控制中维护我的作业配置。 e.g。

job('myfolder/build-all'){
   publishers {
         downstream('myfolder/job1')
         downstream('myfolder/job2')
         downstream('myfolder/job2')
   }
}

答案 4 :(得分:0)

可以从脚本控制台使用以下代码片段来计划某个文件夹中的所有作业:

import hudson.model.AbstractProject

Jenkins.instance.getAllItems(AbstractProject.class).each {
  if(it.fullName =~ 'path/to/folder') {
    (it as AbstractProject).scheduleBuild2(0)
  }
}

通过一些修改,您将能够创建jenkins共享库方法(要求在沙盒外运行并需要@NonCPS),例如:

import hudson.model.AbstractProject

@NonCPS
def triggerItemsInFolder(String folderPath) {
  Jenkins.instance.getAllItems(AbstractProject.class).each {
    if(it.fullName =~ folderPath) {
      (it as AbstractProject).scheduleBuild2(0)
    }
  }
}

答案 5 :(得分:0)

参考管道脚本来运行父作业,该脚本将触发 @WayneBooth 建议的其他作业

pipeline {
    agent any
    stages {
 
        stage('Parallel Stage') {
            parallel {
                stage('Parallel 1') {
                    steps {
                        build(job: "jenkins_job_1")
                    }
                }
                stage('Parallel 2') {
                    steps {
                        build(job: "jenkins_job_2")
                    }
                }
            }
        }
}