In this session I will talk about advanced aspects of plugin development, such as working with remote agents, working in multiple operation systems, creating UI using Groovy, extending Jelly components, etc.
3. JFrog & Jenkins
With Jenkins from day 1
Jenkins Artifactory Plugin
Hosted JUC Israel
repo.jenkins-ci.org
JavaOne DEMOzone
4. Agenda
Vote and guessing
Working with remote agents
Working in multiple operation systems
Creating UI using Groovy
Writing custom Jelly(?) tags
Maintaining backwards compatibility
5. Agenda
Vote and guessing
Working with remote agents
Working in multiple operation systems
Creating UI using Groovy
Writing custom Jelly(?) tags
Maintaining backwards compatibility
6. First, let’s vote
Who saw “Take Control. Write a Plugin” session
on YouTube?
Let me guess…
one or two hands…
7. “Hello, my name is Noam Tenne”
PREVIOUSLY IN “TAKE CONTROL.
WRITE A PLUGIN”…
8. Overview – Why plugins
What you can do with plugins
What you can’t do with plugins
Plugins statistics
9. What can I extend?
UI
SCM
Build Processes
Slave management
Tooling
... Many, many, more
You can even create new extension points!
10. Environment
IDE
All majors have good support
We love IntelliJ IDEA
Build tool
Can be Maven or Gradle
11. The “Motivation” Plugin
Target: Rewarding failing builds with insulting
mockery
Global configuration: Motivation phrase
Project configuration: Is motivator enabled
Outcome: Message appears in log after failure
13. Agenda
Vote and guessing
Working with remote agents
Working in multiple operation systems
Creating UI using Groovy
Writing custom Jelly(?) tags
Maintaining backwards compatibility
22. Distribution Abstractions – Launcher
hudson.Launcher
Much like java.lang.ProcessBuilder
Pick your environment variables wisely!
23. Agenda
Vote and guessing
Working with remote agents
Working in multiple operation systems
Creating UI using Groovy
Writing custom Jelly(?) tags
Maintaining backwards compatibility
24. Working in multiple OSs
WORA. You know. But.
/ vs
.sh vs .bat
Quotes around commands
Permissions
(wait for it…)
27. Going Remote with File
Use FilePath – it will take care of all the details!
Execute FilePath.act(FileCallable)
If you need the File API, invoke() method
has it, converted to remote file properly
29. Agenda
Vote and guessing
Working with remote agents
Working in multiple operation systems
Creating UI using Groovy
Writing custom Jelly(?) tags
Maintaining backwards compatibility
31. Creating UI using Groovy
Analogous to Jelly
Can use Jelly tags and libraries
Kohsuke:
When What
Lots of program logic Groovy
Lots of HTML layout markup Jelly
32. Creating UI using Groovy
Analogous to Jelly
Can use Jelly tags and libraries
me:
When What
Always! Groovy
33. Creating UI using Groovy
Jelly:
1 <j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
2 <f:section title="Motivation Plugin">
3 <f:entry title=" Motivating Message" field="motivatingMessage"
4 description="The motivational message to display when a build fails">
5 <f:textbox/>
6 </f:entry>
7 </f:section>
8 </j:jelly>
Groovy:
1 f=namespace('lib/form')
2
3 f.section(title:'Motivation Plugin') {
4 f.entry(title:'Motivating Message', field:'motivatingMessage',
5 description:'The motivational message to display when a build fails'){
6 f.textbox()
7 }
8 }
34. Creating UI using Groovy
Real code
Debuggable, etc.
(stay tuned…)
1 f=namespace('lib/form')
2
3 f.section(title:'Motivation Plugin') {
4 f.entry(title:'Motivating Message', field:'motivatingMessage',
5 description:'The motivational message to display when a build fails'){
6 f.textbox()
7 }
8 }
35. Agenda
Vote and guessing
Working with remote agents
Working in multiple operation systems
Creating UI using Groovy
Writing custom Jelly(?) tags
Maintaining backwards compatibility
41. 2. Use!
1 import org._10ne.jenkins.MotivationTagLib
2
3 f = namespace('lib/form')
4 m = new MotivationTagLib(builder);
5
6 f.entry(title: '') {
7 m.evilLaugh()
8 f.checkbox(…)
11 }
42. Agenda
Vote and guessing
Working with remote agents
Working in multiple operation systems
Creating UI using Groovy
Writing custom Jelly(?) tags
Maintaining backwards compatibility
45. XStream Aliasing To The Rescue
1 @Initializer(before = PLUGINS_STARTED)
2 public static void addAliases() {
3 Items.XSTREAM2.aliasField("defaultMotivatingMessage",
4 DescriptorImpl.class, "motivatingMessage");
5 }
Register field (or class) alias
In Initializer that runs before plugins started
More complex cases might reqiure XStream
converter
Let it runOverall structureGlobal.jellyConfig.jellyCode:Extends NotifierDatabound constructorPerform Descriptor:ExtensionSerializationXML
MD5 digest
Represents file path, but may be local or remoteisRemote()moveAllChilderenTo()Etc.Push – MD5
MD5 digest
Starts a process, but may be local or remoteCall to launch() returns builderjoin() on builder actually starts the processDon’t include machine specific ones, like PATH, TIMEZONE, etc.