Setup Project in IntellJ IDEA for Working with Jenkins Plugins Groovy Init Scripts

From Bonus Bits
Jump to: navigation, search

Purpose

This article gives the steps to setup a project in Jetbrains IntelliJ IDEA to work on Groovy Init scripts for Jenkins 2.x. Basically how to get the Jenkins Plugin libraries available so we can use the IDE to help with discovering classes, methods and code interrogation. Especially since a lot of plugins do even have Java Docs to help understand their options. The example I will be using is creating a Groovy init script for configuring the Amazon ECS plugin programmatically when the Jenkins Master starts. In the examples, we will be using Gradle and not Maven poms.


Prerequisites


Example Environment

  • macOS 10.11.6
  • Jetbrains IntelliJ IDEA 2016.3.4
  • Java 1.8.0_121
  • Groovy 2.4.8
  • Gradle 3.3


Create New Gradle, Java, Groovy Project

If starting from scratch we can do the following.

  1. Select File | New Project...
  2. Select Gradle
  3. Select Java + Groovy
  4. Select Next
    Jetbrains intellij idea new gradle groovy project01
  5. Enter GroupId and ArtifactId
    Jetbrains intellij idea new gradle groovy project02
  6. Select Next
  7. Enter path to gradle.
    1. Current Example (Recommended) We can switch versions with SDKman and file level configs
      /Users/username/.sdkman/candidates/gradle/current
    2. Specific Example (To hard code to a specific version in IntelliJ)
      /Users/username/.sdkman/candidates/gradle/3.3
    Jetbrains intellij idea add gradle to project04
  8. Select Next
  9. Enter Project name and Project Location
    Jetbrains intellij idea new gradle groovy project03
  10. Select Finish
    Jetbrains intellij idea new gradle groovy project04


Set hpi and jpi File Types

The Jenkins Plugin files are basically zip files with a proprietary file extension of either .hpi or .jpi. We need to inform Jetbrains IntelliJ IDEA of the file type.

  1. Select IntelliJ IDEA | Preferences | Editor | File Types
    1. Or search for File Types in Preferences menu
  2. Select Archive
  3. Select +
  4. Add both *.hpi and *.jpi
  5. Select Apply | OK
    Jetbrains intellij idea new gradle groovy project04b


Add Jenkins Repos and Compile Dependencies to Gradle

  1. Edit the build.gradle config file
  2. The following example will grab Jenkins Core Libraries, Cloudbees Amazon ECS Plugin hpi, plugin dependencies and Java Docs for all imported libraries:
    group 'jenkinsPluginAmazonEcsInit'
    version '1.0-SNAPSHOT'
    
    apply plugin: 'groovy'
    apply plugin: 'java'
    apply plugin: 'idea'
    
    idea {
        module {
            downloadJavadoc = true
            downloadSources = true
        }
    }
    
    sourceCompatibility = 1.8
    targetCompatibility = 1.8
    
    repositories {
        maven { url 'http://repo.jenkins-ci.org/releases/'}
        maven { url 'http://repo.jenkins-ci.org/releases/org/jenkins-ci/main/jenkins-core/'}
        maven { url 'http://repo.jenkins-ci.org/releases/com/cloudbees/jenkins/plugins/amazon-ecs/'}
        mavenCentral()
    }
    
    dependencies {
        compile 'org.codehaus.groovy:groovy-all:2.3.11'
        testCompile group: 'junit', name: 'junit', version: '4.11'
        compile 'com.cloudbees.jenkins.plugins:amazon-ecs:1.10'
        compile 'org.jenkins-ci.main:jenkins-core:2.45'
        compile fileTree(dir: 'lib', include: ['*.jar'])
    }
    


Sync Libraries

If the Auto Import was not selected when configuring Gradle run the Sync or Refresh all Gradle Projects operation.

  1. Select the Gradle side menu on right
  2. Select the Refresh icon (Blue arrows in circle)
    Jetbrains intellij idea new gradle groovy project05

You should see the libraries download if not already in your local cache or simple get added to your project if you do have the libraries cached.

Jetbrains intellij idea new gradle groovy project06


Groovy Init Script

For demonstration of the main issue this article attempts to solve, let's add our starter Jenkins Amazon ECS Groovy Init into the src/main/groovy directory.

  1. Create ecs-cluster.groovy script
  2. As we will see some classes and objects are not recognized by IntelliJ. This is because it is not diving into the nested jar files of the plugin we downloaded with Gradle from the Jenkins-ci Maven repo.
    Jetbrains intellij idea new gradle groovy project07
import java.util.logging.Logger
import jenkins.model.*
import com.cloudbees.jenkins.plugins.amazonecs.ECSCloud

Logger logger = Logger.getLogger("ecs-cluster")

logger.info("Loading Jenkins")
Jenkins instance = Jenkins.getInstance()

logger.info("Gettings clouds")
def clouds = instance.clouds

logger.info("Retrieving ecs cloud config by name")
def cloud = clouds.getByName("ecs-cluster")

if (cloud == null) {
    ecsCloud = new ECSCloud(
        name = "ecs-cluster",
        templates = [],
        credentialsId = null,
        cluster = "arn:aws:ecs:us-east-1:00000000000:cluster/cluster-name",
        regionName = "us-east-1",
        jenkinsUrl = "http://10.0.0.100:8080/",
        slaveTimoutInSeconds = 60
    )

    clouds.add(ecsCloud)
    logger.info("Added ECS cloud named: " + ecsCloud.name)

}
logger.info("Saving jenkins")
instance.save()

Gnome-sticky-notes-applet This is NOT solid code currently. Just something I found online. When I get a solid solution completed I'll update the code example and remove this.


Manually Add Nested Jars from Plugin

Copy Plugin Jars to Project Lib Folder

Someday I hope to find a better solution, but for now this is the workaround I came up with. The Jenkins Plugins aren't setup like regular JAR files so IntelliJ doesn't find the nested JAR files in the hpi/jpi. So, basically what worked for me was to extract the hpi/jpi file, drop the .jar files into a lib folder and set IntelliJ to import any .jar in that folder.

  1. We can see here
  2. Create lib folder of root of project
  3. Browse the External Libraries drop-down menu for the Jenkins Plugin
    1. In this example I'm looking for com.cloudbees.jenkins.plugins:amazon-ecs
  4. Expand the library Gradle: com.cloudbees.jenkins.plugins:amazon-ecs:hpi:1.10 | amazon-ecs-1.10.hpi | WEB-INF | lib
  5. Select all of the jar files
  6. Right-Click Copy
    Jetbrains intellij idea new gradle groovy project08
  7. Scroll up to our new lib folder
  8. Right-Click Paste
    Jetbrains intellij idea new gradle groovy project09

Add Lib Folder for Imports

Using Gradle (Option 1)

Now we need to instruct Gradle or IntelliJ that there are Libraries we want to import no matter if we call for them or not in our lib folder.

  1. Add the following to the Gradle build.gradle file dependencies section
    1. Which in the above example we already have this line. So just double check it's there.
  2. compile fileTree(dir: 'lib', include: ['*.jar'])
    
  3. Run Gradle refresh
Project Structure (Option 2)

Alternatively, we could add the folder in the Project Structure:

  1. Open Project Structure menu
  2. Select Project Settings | Modules | main module
  3. Select Dependencies Tab on right
  4. Select + at bottom
  5. Select 1 Jar or directories
    Jetbrains intellij idea new gradle groovy project010
  6. Drill down to lib folder in project
    Jetbrains intellij idea new gradle groovy project011
  7. Select Ok | Ok


Success!

Now when we look at our Groovy Init Script the classes can resolve! So we'll have actual code inspection plus can figure out what classes/methods and object types are in these mysterious plugins... that unfortunately tend to lack any Java Docs at all. Although Java Docs suck anyways but can help get us in the right direction.

Jetbrains intellij idea new gradle groovy project012


Icon-Tip-Square-Green.png Set static variable types on all variables will let IntelliJ know what things are supposed to be so it can look for errors and help with code completion. Look at the example below of that original Groovy init.

Jetbrains intellij idea new gradle groovy project013
import hudson.slaves.Cloud

import java.util.logging.Logger
import jenkins.model.*
import com.cloudbees.jenkins.plugins.amazonecs.ECSCloud

Logger logger = Logger.getLogger("ecs-cluster")

logger.info("Loading Jenkins")
Jenkins instance = Jenkins.getInstance()

logger.info("Gettings clouds")
Jenkins.CloudList clouds = instance.clouds

logger.info("Retrieving ecs cloud config by name")
Cloud cloud = clouds.getByName("ecs-cluster")

if (cloud == null) {
    ECSCloud ecsCloud = new ECSCloud(
        name = "ecs-cluster",
        templates = [],
        credentialsId = null,
        cluster = "arn:aws:ecs:us-east-1:00000000000:cluster/cluster-name",
        regionName = "us-east-1",
        jenkinsUrl = "http://10.0.0.100:8080/",
        slaveTimoutInSeconds = 60
    )

    clouds.add(ecsCloud)
    logger.info("Added ECS cloud named: " + ecsCloud.name)

}
logger.info("Saving jenkins")
instance.save()
Jetbrains intellij idea new gradle groovy project014


Related Articles