Setting up Groovy completion for Jenkins Pipelines consumers

I'm building a library for Jenkins Global Pipeline Libraries (https://github.com/jenkinsci/workflow-cps-global-lib-plugin) for consumers of Jenkins Pipelines.

The way that users in our organization generally consume Jenkins Pipelines is:

  1. Each repository has a file in the root named Jenkinsfile - this is a Groovy file with a special DSL that is used by Jenkins
  2. They import each repository as a module or as a project into IntelliJ, where they may or may not use the module per source set functionality because most of them use Gradle
  3. Very few people are using Gradle's Groovy plugin
  4. IntelliJ gives them no auto-complete or validation when they consume our library

From my standpoint, there are a few things to consider:

  • I don't want all of our users to have to install another plugin (like https://github.com/oliverlockwood/jenkinsfile-idea-plugin)
  • If I can setup something easy for the classpath or autocompletion using their existing Gradle tooling (like another sourceSet or something just for that Jenkinsfile) that would be most ideal
  • Jenkins Pipelines consumes Groovy source code, not compiled artifacts

I'm wondering what my best options is for getting my users at least auto-completion of our library using the tools we already use?

I found GDSL (like https://confluence.jetbrains.com/display/GRVY/Scripting+IDE+for+DSL+awareness), but the IntelliJ tooling seems to be failing to provide the documentation for the methods and other pieces (see below image). GDSL doesn't seem like the easiest option for consumers, so I'm interested in hearing what other options I have or the best path.

 

Consumers will have a Groovy `Jenkinsfile` in the root of their repository, and I would like to give them something to give them IDE assistance when they consume our library without having to have them install a plugin (like this one https://github.com/oliverlockwood/jenkinsfile-idea-plugin). Most of our users use IntelliJ and Gradle, so I was trying to figure out some of solution around that.

 

What I thought I could do, (stemming from my question above) was to write what I believe are called GDSL scripts (looking at https://confluence.jetbrains.com/display/GRVY/Scripting+IDE+for+DSL+awareness) for consumers of my library, but im definitely open to other suggestions.

7
7 comments
  • "...get something working is to create a 'sourceSet' and then..." - this was to get IntelliJ to auto-recognize those files as Groovy and provide code completion for a Jenkinsfile
  • consumer in my case are the development teams who are writing Jenkinsfiles and want to get source code completion when writing/developing them. When I said consumer above, I meant consumer of my plugin who is targeted at those writing Jenkinsfiles.
  • When I was talking about the sourceSet terminology above, I was speaking specifically about Gradle's SourceSet terminology

My use case before was for developers that:

  • Already using Gradle
  • Use IntelliJ's feature to import Gradle projects which recognizes Java, Groovy, Kotlin, and other project types
  • Don't want to install additional IntelliJ plugins

My example was that given a build.gradle file, and a file jenkinsfileAutocompletion/Jenkinsfile.groovy, the project could be imported into IntelliJ with Groovy source code completion. In order to get all of the Jenkins steps (like nodestage, whatever) you need to get that from elsewhere (like the idea.gdsl that a hosted Jenkins instance generates). Here is an example of the build.gradle

group 'mkobit.test'
version '1.0-SNAPSHOT'

apply plugin: 'groovy'
apply plugin: 'java'

sourceCompatibility = 1.8

repositories {
mavenCentral()
}

sourceSets {
autocompletion {
groovy {
srcDirs = ['jenkinsfileAutocompletion']
}
}
}

dependencies {
compile 'org.codehaus.groovy:groovy-all:2.4.10'
myOtherSourceSetCompile 'com.mypipeline:mkobit-lib:1.0.0'
myOtherSourceSetCompile 'org.codehaus.groovy:groovy-all:2.4.10'
testCompile group: 'junit', name: 'junit', version: '4.12'
}

Does that make sense?

1

So, I did find a way to get this to work when not using the Separate Module per Source Set feature, but that is not ideal. The separate module is what every developer at our company uses right now, so this isn't a great solution in general but does seem like a step in the right direction.

This is what the build.gradle looks like for this example:

group 'mkobit.test'
version '1.0-SNAPSHOT'

apply plugin: 'groovy'
apply plugin: 'java'

sourceCompatibility = 1.8

repositories {
mavenCentral()
mavenLocal()
}

sourceSets {
myOtherSourceSet {
groovy {
srcDirs = [project.rootDir.toString()]
include('Jenkinsfile')
}
java {
srcDirs = []
}
resources {
srcDirs = []
}
}
}
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.4.10'
myOtherSourceSetCompile 'com.mypipeline:mkobit-lib:1.0.0'
myOtherSourceSetCompile 'org.codehaus.groovy:groovy-all:2.4.10'
testCompile group: 'junit', name: 'junit', version: '4.12'
}

This however does not work when using the Separate Module per Source Set

0

Maybe there is some way to do symlinks from a folder so that IntelliJ maps it as a module, and then put the Jenkinsfile in that directory? I will probably try that this weekend, but doesn't seems like more complexity for users

0

It could also be better to wait for something like https://issues.jenkins-ci.org/browse/JENKINS-34561 to be merged in with https://github.com/jenkinsci/workflow-multibranch-plugin/pull/59 which would make this a little bit easier to deal with

0

One way I found out to at least get something working is to create a `sourceSet` and then symlink the `Jenkinsfile` to that directory.

sourceSets {
autocompletion {
groovy {
srcDirs = ['jenkinsfileAutocompletion']
}
}
all {
java {
srcDirs = []
}
resources {
srcDirs = []
}
}
}


 

And then the `Jenkinsfile` can be symlinked into that directory from inside of it. `cd

cd jenkinsfileAutocompletion && ln -s ../Jenkinsfile Jenkinsfile.groovy

This is hacky but seems to work for now.

0

"...get something working is to create a 'sourceSet' and then..."

Would you mind being more explicit? This looks it is contents of a file (or inserted into an existing file). What file, exactly?

Also would like further clarification of the phrase "consume Jenkins Pipelines".

Here's my problem: I'm not in Development. I'm in TechSupport, and thereby more a DevOps victim than practitioner.

The Developers mostly don't use IDEs at all. They prefer to write java in notepad++ or some such. They're hardcore. They don't use Jenkins, and have no interest in helping those of us who have to build and deploy their code for actual customers with the Jenkins side of things. So Development has never ever created a Jenkinsfile.

So we have nearly a dozen Java projects in GitHub (private, Enterprise) repos, and none of them know anything about Jenkins or Jenkinsfile or Groovy. My overarching task (amidst dozens of others) is to make these Java Projects do their things more efficiently and repeatably and track-ably in Jenkins at Build Day and beyond. To do that, common wisdom says "Oh, of course your pipelines should be code, tracked like everything else." Yes. Agree wholeheartedly.

Now - IntelliJ IDEA comes bundled with Groovy support (but it doesn't help at all with syntax highlighting out of the box). I have no intention of consuming a Jenkinsfile. I intend to write and edit Jenkinsfiles for Jenkins to consume.

Are you saying that if my expectation and desire is to have context-highlighting and assistance with writing and editing a Jenkinsfile, that makes me a consumer of it? I'm just trying to follow the semantics.

0

Yes, it does make sense. Sadly, it also means it won't work for me/us (at least not directly). We have only java. We have no build.whatever files, just pom.xml (and we have dozens and dozens of those).

Maybe we'll have projects where Developers are dealing with them as Java Projects, but in TechSupport we open them as something else.

Follow-up question: Would all of this have been a ton easier if the powers-that-be at Jenkins had declared that a Jenkinsfile must always be named "Jenkinsfile.groovy"? Or would that not help?

0

Please sign in to leave a comment.