IDE Support

162 views
Skip to first unread message

Daniel Spilker

unread,
Oct 13, 2014, 4:35:23 AM10/13/14
to job-dsl...@googlegroups.com
Hi everyone!

IDE support is on my wishlist for the Job DSL plugin since early on. Last week I found some time to work on the topic.

tl;dr

IDE support is coming and the parts of the DSL documented in the wiki are not going to change, but undocumented behavior is going to change.

The Good

The following features are working in IDEA 13.1.5:
This works by adding the job-dsl-core library to the project containing the DSL scripts. The library contains a GroovyDSL script that tells the IDE (IDEA only) which methods are available in scripts.

The Bad

Code completion does not work in IDEA 13.1.5. I tried the latest IDEA 14 EAP release, but also without luck.

There will be no IDE support for configure blocks. I have no idea how to get that done and I'm not sure if it's possible to implement.

The IDE can not guess the methods available in closures because the signature of methods taking a closure does not contain that information. The IDEA way to add IDE integration for closure parameters this is to extend the GroovyDSL script and the Groovy way is to use the DelegatesTo annotation. I favor the Groovy way since it will enable support for those IDEs in the future. But the DelegatesTo annotation is only available in Groovy 2.1 or later and Jenkins uses Groovy 1.8. Updating the Groovy version in Jenkins will take some more time (JENKINS-21249). So I had to copy the annotation to the Job DSL plugin. I started to annotate some closure parameters with DelegatesTo, but there is still work left.

Only very few methods have useful Groovydoc. It will be a lot of work to add useful texts to all methods.

The Ugly

The Job class uses the Delegate annotation to move functionality to other classes. The classes are called helpers in the Job DSL plugin, like PublisherContextHelper. Unfortunately there is a bug in IDEA so that DelegateTo annotations in method signatures blended in via Delegate fields are not evaluated. I tried the latest IDEA 14 EAP release, but again without luck. For some reason the helper classes only exist on the first level below the job context (the exception to the rule is StaticAnalysisPublisherContext) but deeper levels don't use that pattern. I always thought it was strange the have the helper classes on the first level, so I decided to remove them and move the functionality to the Job class. The benefit is that we don't have to wait for a fix in IDEA and that the DSL implementation is now cleaner, since the same pattern is used for contexts on all levels. On the downside the Job class will get bigger, but not as big as PublisherContext for instance.

The Job class contains the methods for all job types. But views and config files are implemented in a different way. There are subclasses for each type. The good part is that those classes do not use the @Delegate annotation to keep the classes small since each class only contains the methods needed for the concrete type and it's not necessary to move the methods back as for the Job class. But the bad part is that there only one view and one configFiles method which select the view or config file type with a named parameter (e.g view(type: NestedView)). The DelegatesTo annotation on those methods can not dynamically point the class implementing the view or configFile type. So it has to point to the super type which contains only a few common methods. Meaning that there will be no IDE support for specific view or config file types without further changes. The named parameter pattern is only used for the top-level DSL methods (with a few exceptions like the trigger method in extendedEmail) and the DSL design will get cleaner if the same rules are used on all levels. So I will deprecate the top-level methods and add new ones for each type of job, view or configFile (e.g. mavenJob or deliveryPipelineView) which will have the @DelegatesTo annotation pointing to the implementing class. I will also split-up the Job class into subclasses for each job type to cut down the size and to use the same pattern as for views and config files.

Allmost all DSL methods specify "def" as return type, meaning that we don't care for the return type. The exception to the rule are the top-level methods which return Job, View or ConfigFile objects for further manipulation. In Groovydoc, def shows up as Object. The value actually returned by a DSL methods depends on the last statement in the implementing method block and since we do not care it can be anything. And when it shows up in the documentation, users may start to rely on the existing behavior. So we should start to care about the return value. To fix this I will change all return types to void, since there are no reasonable values to return.


Daniel

Daniel Spilker

unread,
Oct 13, 2014, 4:35:28 PM10/13/14
to job-dsl...@googlegroups.com
It turned out that my assumption about the @Delegate/@DelegatesTo problem being an IDEA bug was wrong. In Groovy 2.1 a parameterAnnotations flag has been added to @Delegate. Setting that flag to true causes the @DelegatesTo annotation to be carried over to the delegating class. That would fix the issue for us, but Jenkins does not support Groovy 2.1 and copying over the class to job-dsl-core does not work because it's already present in Groovy 1.8 (unlike @DelegatesTo).

So I would still like to get rid of the @Delegate annotations for now and add them back after JENKINS-21249 got solved and the job-dsl-plugin has been updated to a version of Jenkins core support Groovy 2.1 or later.

Matt Sheehan

unread,
Oct 13, 2014, 11:40:47 PM10/13/14
to job-dsl...@googlegroups.com
That's very cool! These updates sounds good to me.

On a somewhat similar note, I've been playing around with a way to auto-generate API docs from the source code. It uses the @DelegatesTo along with another annotation, @DslMethod. 

I created a demo here with a handful of methods annotated: http://sheehan.github.io/job-dsl-plugin/#job-scm-git
and was hoping to get some feedback on this approach before I proceed any further. 

The short of it is that running 'gradle generateApiDoc' creates a json file describing the API, which is then used by the web page in the gh-pages branch.


Other than adding the @DelegatesTo annotations, the tedious work involved would mainly be:

1. Add @DslMethod annotations to each exposed method
2. Add the relevant plugin id as an attribute to @DslMethod
3. Copy any markdown from the wiki to that method's javadoc section.

Any thoughts?


On Mon, Oct 13, 2014 at 3:35 PM, Daniel Spilker <ma...@daniel-spilker.com> wrote:
It turned out that my assumption about the @Delegate/@DelegatesTo problem being an IDEA bug was wrong. In Groovy 2.1 a parameterAnnotations flag has been added to @Delegate. Setting that flag to true causes the @DelegatesTo annotation to be carried over to the delegating class. That would fix the issue for us, but Jenkins does not support Groovy 2.1 and copying over the class to job-dsl-core does not work because it's already present in Groovy 1.8 (unlike @DelegatesTo).

So I would still like to get rid of the @Delegate annotations for now and add them back after JENKINS-21249 got solved and the job-dsl-plugin has been updated to a version of Jenkins core support Groovy 2.1 or later.

--
You received this message because you are subscribed to the Google Groups "job-dsl-plugin" group.
To unsubscribe from this group and stop receiving emails from it, send an email to job-dsl-plugi...@googlegroups.com.
To post to this group, send email to job-dsl...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/job-dsl-plugin/64f93fb4-f205-4545-bbda-ec4867f91182%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Daniel Spilker

unread,
Oct 14, 2014, 3:29:18 AM10/14/14
to job-dsl...@googlegroups.com
Great! That's exactly what I had in mind for the docs. We already exceeded the limits of the GitHub wiki too far.

I would like to get the changes for the IDE support done first since that's also the foundation for the doc update. After that we can focus on the new documentation.

Daniel

Matt Sheehan

unread,
Mar 23, 2015, 11:22:33 PM3/23/15
to job-dsl...@googlegroups.com
I've spent some more time on the auto-generated documentation now that the changes for IDE support have been addressed. I'll outline the proposal here.

There are two separate components, the API generator and the API viewer. The API generator extracts details from the source code and creates a json file like this one:


The API viewer is a web app for displaying the json files. Like so:


(Note that this demo only includes a small subset of the DSL methods and hardly any method descriptions.)

The API generator requires some additional info to be added to the source. The process for documenting API methods would be as follows:

1. Add @DslMethodDoc to exposed methods

This annotation must be added to all methods that should show up in the DSL doc. The API generator will start at JobParent and automatically walk the tree of methods that are annotated with @DslMethodDoc and Closure arguments annotated with @DslContext.

@DslMethodDoc
void batchTask(String name, String script) {}

2. Add method descriptions

If the method has javadoc, the API generator will use that as the description. The text will be parsed as markdown.

For methods with long descriptions, I've added another option to store the text in a separate file. For example, for the JobParent#job method, the API generator will first look for the file "/job-dsl-core/api-docs/javaposse/jobdsl/dsl/JobParent/job.md". If not found, it will use the javadoc.


3. Add related plugin ID

The @DslMethodDoc annotation has a plugin attribute that can be used to specify the ID of the relevant plugin. The ID of a plugin can be found in the Plugin Information section of the Jenkins plugin page like:


Adding the plugin ID will display plugin information along side DSL methods and allow the user to filter methods by plugin.

@DslMethodDoc(plugin = 'batch-task')
void batchTask(String name, String script) {}

4. Add availableSince, deprecatedSince

These attributes can be added to indicate the version that the method was added or deprecated. The info is displayed above the method signature in the doc.

@DslMethodDoc(plugin = 'batch-task', availableSince = '1.24')
void batchTask(String name, String script) {}

5. Add example XML

Currently the example XML is usually added to the JavaDoc. I propose moving this to an annotation attribute so that it won't show up in the method description, but is still added to the json file. It's not currently displayed in the API viewer, but could be added at some point.

@DslMethodDoc(
    plugin = 'batch-task',
    availableSince = '1.24',
    exampleXml = '''
        <properties>
            <hudson.plugins.batch__task.BatchTaskProperty>
                <tasks>
                    <hudson.plugins.batch__task.BatchTask>
                        <name>Hello World</name>
                        <script>echo Hello World</script>
                    </hudson.plugins.batch__task.BatchTask>
                </tasks>
            </hudson.plugins.batch__task.BatchTaskProperty>
        </properties>
)
void batchTask(String name, String script) {}

Let me know if you have feedback on this. If it sounds like a good plan, I can start moving the existing documentation over and create a PR.


Daniel Spilker

unread,
Mar 28, 2015, 6:04:33 PM3/28/15
to job-dsl...@googlegroups.com
Nice one! See my comments inline.

On Tue, Mar 24, 2015 at 4:22 AM, Matt Sheehan <mr.sh...@gmail.com> wrote:

The API viewer is a web app for displaying the json files. Like so:



Cool! I really like your API viewer!
 

1. Add @DslMethodDoc to exposed methods


Hm, is this really necessary? I was hoping that all public methods (except for getter/setters and everything inherited from GroovyObject) are DSL methods. Or are there too many exceptions?
 
2. Add method descriptions

If the method has javadoc, the API generator will use that as the description. The text will be parsed as markdown.


Wouldn't it be more standard compliant to use the HTML like Java/GroovyDoc? IDE support would also benefit from that since IDEs will try to parse the docs as HTML-like.
 
3. Add related plugin ID


I have been thinking about something like that. I have been using JobManagement.requireMinimumPluginVersion to ensure hat a plugin is installed and has the correct version. I would like to replace that by a separate annotation which can be used by an AST to check at runtime that the plugin is installed and if a version is given that at least that version is installed. That annotation could then also be used for the API docs.


4. Add availableSince, deprecatedSince

 
Wouldn't to be possible to use the standard @since JavaDoc tag the @Deprecated annotation for this? Again, the IDE support would benefit from that. We would not be able specify the version that deprecated a method but I would rather loose that info in favour of using a standard mechanism.

http://www.oracle.com/technetwork/java/javase/documentation/index-137868.html#@since
http://docs.oracle.com/javase/7/docs/api/java/lang/Deprecated.html


5. Add example XML

 
Actually, I would like to get rid of the XML examples. I do not need them for my pull request review process any more and they should make room for more relevant docs. Does anyone else need the XML examples?

I will start with removing the XML examples until we agree on the other points.

Daniel

Daniel Spilker

unread,
Mar 30, 2015, 4:40:38 AM3/30/15
to job-dsl...@googlegroups.com
btw, here is the pull request to remove the XML examples:
https://github.com/jenkinsci/job-dsl-plugin/pull/428

Daniel

Daniel Spilker

unread,
Mar 30, 2015, 8:49:25 AM3/30/15
to job-dsl...@googlegroups.com
And here is a pull request which adds an annotation to specify the required plugin and optionally a minimum version of the required plugin:
https://github.com/jenkinsci/job-dsl-plugin/pull/430

I converted the existing jobManagement.requireMinimumPlugin calls as part of the pull request. If there is no objection, I will merge the PR and add more @RequiresPlugin annotations in an additional pull request.

Daniel

Matt Sheehan

unread,
Mar 31, 2015, 6:50:15 PM3/31/15
to job-dsl...@googlegroups.com
Your suggestions sound good to me. As far as the DslMethodDoc annotation, I'll take another look and see if we can do without it.

--
You received this message because you are subscribed to the Google Groups "job-dsl-plugin" group.
To unsubscribe from this group and stop receiving emails from it, send an email to job-dsl-plugi...@googlegroups.com.
To post to this group, send email to job-dsl...@googlegroups.com.

Daniel Spilker

unread,
Apr 13, 2015, 1:59:09 PM4/13/15
to job-dsl...@googlegroups.com
Hi!

I've (hopefully) added all @RequiresPlugin annotations and @since tags back to 1.15. The Git tags for earlier releases are missing, so it's not possible to reverse engineer anything before 1.15, but that's probably OK. Please open a pull request if anything is missing.

Unfortunately we have broken compatibility by moving methods to the new Job subclasses and new job-type specific Context subclasses, see JENKINS-27921 for an example. I'm thinking about moving the methods back to restore compatibility until the deprecated job methods in DslFactory/JobParent have been removed.

Daniel

Daniel Spilker

unread,
Apr 13, 2015, 2:37:25 PM4/13/15
to job-dsl...@googlegroups.com
Scratch my last paragraph, JENKINS-27921 is caused by another problem.

Daniel

Matt Sheehan

unread,
Apr 13, 2015, 11:01:28 PM4/13/15
to job-dsl...@googlegroups.com
Glad that's not the issue.

Regarding the api docs, I've updated my demo with the discussed changes. See http://sheehan.github.io/job-dsl-plugin for the latest. All methods should be included now.

I'm planning on adding a search control for methods/plugins and then I should be done.

Reply all
Reply to author
Forward
0 new messages