Zuul, Jenkins, Gerrit and Git submodules

So, we got a Git -> Gerrit -> Zuul (w/ Gearman) -> Jenkins setup at work and we started to use Git submodules with one repository lately.

Setting up the quality gate with Zuul and Gerrit for a normal git repository is quite straight forward and I won’t mention that any further. We got the problem, that we wanted to do a build of the parent repository of our submodule repository, when a change is committed for review or merge.

Zuul doesn’t give you any options here, it just has a single project configuration, and doesn’t support project dependencies.

BUT it supports build job dependencies!

So the solution is to build your submodule standalone in the first job, which can be the standard review job, based on a Jenkinsfile inside the submodule repository. And then starting a build job with the parent repository which depends on the result of the submodule standalone build. This second job can’t be a standard review build job because it has to do some different things. The standard Jenkinsfile for the review of the parent repository can be used with minor modifications.

So for your parent repository, you’ll be already using a checkout method which also retrieves the submodule repository and may look like this:

def zuul_fetch_repo() {
    checkout changelog: true, poll: false, scm: [$class: 'GitSCM', branches: [[name: 'refs/heads/zuul']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[refspec: '+$ZUUL_REF:refs/heads/zuul', url: '$ZUUL_URL/$ZUUL_PROJECT']], extensions: [[$class: 'SubmoduleOption', disableSubmodules: false, parentCredentials: true, recursiveSubmodules: true, reference: '', trackingSubmodules: true], [$class: 'CleanBeforeCheckout']]]
}

Because of the fact that you have to use a special job for the task, you also have to change the fetch function away from the generic $ZUUL_URL/$ZUUL_REPO to a hardcoded checkout url.

These variables you have to use to update your submodule repository to the zuul change provided, the resulting fetch function could look like this:

def zuul_fetch_repo() {
    checkout changelog: true, poll: false, scm: [$class: 'GitSCM', branches: [[name: 'master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[url: 'ssh://<user>@your-gerrit.url:29418/parent-repo']], extensions: [[$class: 'SubmoduleOption', disableSubmodules: false, parentCredentials: true, recursiveSubmodules: true, reference: '', trackingSubmodules: true], [$class: 'CleanBeforeCheckout']]]

    sh '''
    cd path/to/your/submodule/repository
    git pull $ZUUL_URL/$ZUUL_PROJECT +$ZUUL_REF:refs/heads/zuul
    '''
}

And that’s it! You just have to somehow get the change from the project you configured in zuul into the submodule, and you have a build of the parent project with integrated change commit from the submodule. Of course you can do that a bit fancier, but that’s left as an exercise for the reader.

At last here a little snippet of the zuul config part reflecting that.

projects:
  - name: submodule-repo
    review:    # the zuul pipeline
      - review:    # standard review job, submodule standalone
        - review-parent-with-submodule    # parent project with submodule checkout