Ensuring Consistent Code Style with Job DSL Repos

Featured image for sharing metadata for article

We should generally treat our Job DSL projects with the same level of standards that our production code would be fulfilling.

Without enforcing code style, it's up to code review or engineers "just knowing" the changes to make which is a bit more of a burden than needs to be had, especially as there are tools like Spotless which fill this gap so perfectly, especially as you can locally configure Spotless to always run, ensuring your code style is always consistent.

This is also really important because you may have teams who are coming with different tech backgrounds, or who may not be as used to working in Groovy code, which our pipelines will be based on.

Applying Spotless

So how do we go about setting it up? In our build.gradle, we can make the following changes:

 plugins {
   id 'groovy'
+  id 'com.diffplug.spotless' version '5.11.0'
 }
+
+spotless {
+  groovy {
+    target '**/*.groovy', '**/*.Jenkinsfile'
+    greclipse()
+    trimTrailingWhitespace()
+    indentWithSpaces(2)
+    endWithNewline()
+  }
+  groovyGradle {
+    target '**/*.gradle'
+    greclipse()
+    trimTrailingWhitespace()
+    indentWithSpaces(2)
+    endWithNewline()
+  }
+}

 allprojects {
+  apply plugin: 'com.diffplug.spotless'

   repositories {
     mavenCentral()
     maven {
       url 'https://repo.jenkins-ci.org/releases/'
     }
   }
 }

The above code style choices are my preference, but you can tweak them as you need to. This allows us to keep all our Groovy, Jenkins jobs and Gradle configuration to the same standard.

We also apply the plugin across all projects, so any subprojects i.e. jobs, have code style enforced, too.

You'll notice that immediately after applying these changes, running a ./gradlew clean build will fail, as you need to apply the changes. We can do this with ./gradlew spotlessApply.

Adding a Multibranch Pipeline for this Repo

Although not super necessary, I'd really recommend having a multibranch pipeline set up for your Job DSL configuration, which will allow anyone raising changes to the repo to make sure they're compliant with the code style, as well as making sure that the code at least compiles.

We need to set this up in jobs/src/main/groovy/definitions/_seed.groovy to add our new job:

 import utilities.JobFactory

 JobFactory.seedJob(this)
+JobFactory.seedJobPrBuilder(this)

Which requires our jobs/src/main/groovy/utilities/JobFactory.groovy be updated to add the new multibranch pipeline:

static MultibranchWorkflowJob seedJobPrBuilder(DslFactory factory) {
  factory.multibranchPipelineJob("$BASE_BUILD_PATH/_Seed_PR_Builder") {
    branchSources {
      /* for example, when using GitHub */
      github {
        apiUri('...')
        buildForkPRMerge(true)
        buildOriginBranch(true)
        buildOriginBranchWithPR(true)
        buildOriginPRMerge(true)
        checkoutCredentialsId(SCM_CREDENTIALS_ID)
        repoOwner(PIPELINE_ORG)
        repository(PIPELINE_REPO_NAME)
        scanCredentialsId(SCM_CREDENTIALS_ID)
        /* id required to be unique, otherwise triggers won't work across duplicates in your Jenkins instance */
        id("$PIPELINE_ORG-$PIPELINE_REPO_NAME-seed-mb")
      }
    }
    factory {
      remoteJenkinsFileWorkflowBranchProjectFactory {
        scriptPath('jobs/build_seed.Jenkinsfile')
        localMarker('') /* everything is valid */
        remoteJenkinsFileSCM {
          gitSCM {
            userRemoteConfigs {
              userRemoteConfig {
                name('origin')
                url(PIPELINE_GIT_REPO_URL)
                refspec("+refs/heads/$PIPELINE_REPO_BRANCH:refs/remotes/origin/$PIPELINE_REPO_BRANCH")
                credentialsId(SCM_CREDENTIALS_ID)
              }
            }
            branches {
              branchSpec {
                name(PIPELINE_REPO_BRANCH)
              }
            }
            browser {}
            gitTool('/usr/bin/env git')
          }
        }
      }
    }
  }
}

And finally, we want our jobs/build_seed.Jenkinsfile to simply build the project:

node {
  stage('Checkout code') {
    checkout scm
  }
  stage('Compile') {
    sh './gradlew clean build'
  }
}

And that's it! We now will be able to get our jobs repo managed with a bit more quality, and can now set up PR builds on contributed changes!

Written by Jamie Tanna's profile image Jamie Tanna on , and last updated on .

Content for this article is shared under the terms of the Creative Commons Attribution Non Commercial Share Alike 4.0 International, and code is shared under the Apache License 2.0.

#jenkins #job-dsl #spotless.

This post was filed under articles.

Interactions with this post

Interactions with this post

Below you can find the interactions that this page has had using WebMention.

Have you written a response to this post? Let me know the URL:

Do you not have a website set up with WebMention capabilities? You can use Comment Parade.