2016-02-26 76 views
3

我正在测试Jenkins的使用Github pull request builder plugin我已经成功地在Github上设置了一个玩具项目,并且开发了Jenkins的安装程序,以便提高PR或将更改推送到PR分支会触发构建。大多数情况下,这是按照要求工作的 - 有些东西与首选工作流程不匹配,但是自由编写和维护我们自己的插件是一件大事。如何跨多个合并请求并行运行持续集成?

我有一个潜在的showstopper。该插件将所有推送到所有PR中的所有推送排队,并且似乎一次只运行一项作业,即使有可用的备用执行程序。在现实世界的项目中,我们可能会有10个活跃的PR,每个可能会在一天内得到一些推动的更新以回应QC评论,并且完整的CI运行需要> 30分钟。但是,我们确实有足够的构建执行程序供应,可以同时运行多个作业。

我看不到任何方式来配置PR请求生成器来同时在同一个触发器上处理多个作业,但我可能会在Jenkins的其他地方丢失一些基本的东西。有没有办法做到这一点,而无需自定义插件?

我已经安装了Jenkins ver。 1.649在一个新的Ubuntu 14.04服务器上(在一个VirtualBox客户端上),并遵循ghprb plugin(当前版本为1.30.5)的README,包括在Github上设置一个jenkins“bot”账户作为协作者,以运行所有集成API调用Github上。

我想知道如果我克隆作业(创建新项目和“复制现有项目”)会有什么样的行为,并且可能会尝试下一步,但我预计这会导致作业同时运行多个作业没有任何好处,而不是与其他工作轮询同一个PR池的智能交互。

回答

4

我已经找到配置设置,同时探索更多的问题。

当你知道它是哪个配置项时,真的很容易,但Jenkins有很多配置可以解决,尤其是当你在探索插件时。

关键是,并行服务排队作业的选项(可用的执行程序允许)是核心Jenkins配置,而不是Github PR构建器的一部分。

所以,只需检查选项如有必要,执行并发构建。这个选项应该在配置的第一个未命名部分的底部找到。这是一个非常基本的詹金斯选择,像我这样的新手因为其他选择的高峰而错过了。

+1

谢谢!我也忽略了这个复选框! _“jenkins并行作业”_的90%命中_告诉我使用Build Flow插件或其他插件。你可能是世界上唯一一个发现这个复选框的人。 –

+0

我不知道它是如何工作的,因为每个工作只有一个工作空间。如果检查出没有涉及git仓库,这些工作可以并行运行。不过,在这种情况下,git仓库被检出到工作区中。 如果有多个PR和2个作业并行运行,最后检出的PR是有效代码,但测试将对最后一个PR并行运行。 – puneeth

+0

@ user2283864:当作业同时运行时,Jenkins会自动创建多个工作区(附加例如'@ 2'这个名称)。 –

1

可能回答这个问题为时已晚,但经过几天的研究,我找到了一种方法在github中为每个PR创建多个作业。 我在这里展示的代码适用于github企业版,但它对于一般github(bitbucket)以及url和git命令中的一些调整已经足够好了。

针对其永久居民的创建需要有一个文件的主线库,我把它叫做PRJob.groovy并包含

import groovy.json.JsonSlurper 


gitUrl = GIT_URL 

repoRestUrl = "${GITHUB_WEB_URL}/repos/${project}/${repo}" 

def getJSON(url) { 
    def conn = (HttpURLConnection) new URL(url).openConnection() 
    conn.setRequestProperty("Authorization", "token ${OAUTH_TOKEN}"); 
    return new JsonSlurper().parse(new InputStreamReader(conn.getInputStream())) 
} 


def createPipeline(name, description, branch, prId) { 

    return pipelineJob(name) { 
     delegate.description description 
     if (ENABLE_TRIGGERS == 'true') { 
     triggers { 
      cron 'H H/8 * * *' 
      scm 'H/5 * * * *' 
     } 
     } 
     quietPeriod(60) 
     environmentVariables { 
     env 'BRANCH_NAME', branch 
     env 'PULL_REQUEST', prId 
     env 'GITHUB_WEB_URL', GITHUB_WEB_URL 
     env 'OAUTH_TOKEN', OAUTH_TOKEN 
     env 'PROJECT', project 
     env 'REPO', repo 
     } 
     definition { 
     cpsScm { 
      scriptPath "Jenkinsfile" 
      scm { 
      git { 
       remote { 
       credentials "jenkins-ssh-key" 
       delegate.url gitUrl 
       if (prId != "") { 
        refspec "+refs/pull/${prId}/*:refs/remotes/origin/pr/${prId}/*" 
       } 
       } 
       delegate.branch branch 
      } 
      } 
     } 
     } 
    } 
} 




def createPRJobs() { 

    def prs = getJSON("${repoRestUrl}/pulls?state=open") 

    if (prs.size() == 0) { 

    def mergedPrs = getJSON("${repoRestUrl}/pulls?state=closed") 
    if (mergedPrs.size() == 0) { 
     throw new RuntimeException("No pull-requests found; auth token has likely expired") 
    } 
    } 

    prs.each { pr -> 
    def id = pr.get("number") 
    def title = pr.get("title") 
    def fromRef = pr.get("head") 
    def fromBranchName = fromRef.get("ref") 
    def prRepo = fromRef.get("repo") 
    def repoName = prRepo.get("name") 
    def prHref = pr.get("url") 

    createPipeline("${repo}-PR-${id}-${fromBranchName}", 
     "${prHref} Pull Request ${id}: ${title}", "origin/pr/${id}/head", id) 
    } 

} 

createPRJobs() 

这就造成每个PR 1个詹金斯工作。 这依赖于项目有Jenkinsfile可以拿起来运行peipeline工作。示例Jenkinsfile将如下所示:

//Jenkinsfile for building and creating jobs 
commitId = null 
repoRestUrl = "${GITHUB_WEB_URL}/repos/${PROJECT}/${REPO}" 

try{ 
    stage('Install and Tests') { 
     runTest("Hello") 
    } 
    notify_github 'success' 
}catch (Exception e) { 
    notify_github 'failure' 
    print e 
    throw e 
} 

def runTest(String someDummyVariable) { 
    node { 
    checkout scm 
    sh 'git clean -qdf' 
    if (env.PULL_REQUEST == ""){ 
     sh 'git rev-parse --verify HEAD > commit.txt' 
    } else { 
     // We check out PR after it is merged with master, but we need to report the result against the commit before merge 
     sh "git rev-parse refs/remotes/origin/pr/${env.PULL_REQUEST}/head^{commit} > commit.txt" 

    } 
    commitId = readFile 'commit.txt' 
    echo commitId 
    sh 'rm -f commit.txt' 

    //Here goes your code for doing anything 
    sh 'echo "Hello World!!!!!"' 


    } 
} 


def http_post(url, rawJson) { 
    def conn = (HttpURLConnection) new URL(url).openConnection() 
    conn.setRequestProperty("Authorization", "token ${OAUTH_TOKEN}"); 
    conn.doOutput = true 
    conn.requestMethod = "POST" 
    conn.setRequestProperty("Content-Type", "application/json") 
    def wr = new OutputStreamWriter(conn.getOutputStream()); 
    wr.write(rawJson); 
    wr.close() 

    def code = conn.getResponseCode() 
    if (code < 200 || code >= 300){ 
    println 'Failed to post to ' + url 
    def es = conn.getErrorStream(); 
    if (es != null) { 
     println es.getText() 
    } 
    } 
} 


def notify_github(state) { 

    http_post(
    "${repoRestUrl}/statuses/${commitId}", 
    """ 
     { "state": "${state}", 
     "target_url": "${env.BUILD_URL}", 
     "description": "Build Pipeline", 
     "context": "Build Pipeline" 
     } 
    """ 
) 
} 

希望这可以帮助某人。

相关问题