take control. write a plugin. part ii
DESCRIPTION
Take Control. Write a Plugin. Part II. Baruch Sadogursky JFrog www.jfrog.com. About me. Developer Advocate @JFrog Job definition: Write code Talk about it github.com/ jbaruch @ jbaruch. JFrog & Jenkins. With Jenkins from day 1 Jenkins Artifactory Plugin Hosted JUC Israel - PowerPoint PPT PresentationTRANSCRIPT
![Page 1: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/1.jpg)
Jenkins User Conference San Francisco, Sept 30 2012 #jenkinsconf
Take Control. Write a Plugin.Part II
Baruch SadogurskyJFrog
www.jfrog.com
![Page 2: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/2.jpg)
About me
Developer Advocate @JFrogJob definition:
Write code Talk about it
github.com/jbaruch@jbaruch
![Page 3: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/3.jpg)
With Jenkins from day 1Jenkins Artifactory PluginHosted JUC Israelrepo.jenkins-ci.orgJavaOne DEMOzone
JFrog & Jenkins
![Page 4: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/4.jpg)
Vote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility
Agenda
![Page 5: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/5.jpg)
Vote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility
Agenda
![Page 6: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/6.jpg)
Who saw “Take Control. Write a Plugin” session on YouTube?Let me guess…
one or two hands…
First, let’s vote
![Page 7: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/7.jpg)
PREVIOUSLY IN “TAKE CONTROL. WRITE A PLUGIN”…
“Hello, my name is Noam Tenne”
![Page 8: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/8.jpg)
What you can do with pluginsWhat you can’t do with pluginsPlugins statistics
Overview – Why plugins
![Page 9: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/9.jpg)
UISCMBuild ProcessesSlave managementTooling ... Many, many, more
You can even create new extension points!
What can I extend?
![Page 10: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/10.jpg)
IDEAll majors have good supportWe love IntelliJ IDEA
Build toolCan be Maven or Gradle
Environment
![Page 11: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/11.jpg)
Target: Rewarding failing builds with insulting mockeryGlobal configuration: Motivation phraseProject configuration: Is motivator enabledOutcome: Message appears in log after failure
The “Motivation” Plugin
![Page 12: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/12.jpg)
BACK TO OUR AGENDANowdays…
![Page 13: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/13.jpg)
Vote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility
Agenda
![Page 14: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/14.jpg)
Jenkins has remote agents!
Working with remote agents
![Page 15: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/15.jpg)
Send closures to remote agentshudson.remoting.Callable
Working with remote agents
Java Serialization
![Page 16: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/16.jpg)
Poor guy’s Java closureUsually anonymous inner class (not always)
Closure
1 private static class GetSystemProperties implements Callable<Properties,RuntimeException> { 2 public Properties call() { 3 return System.getProperties(); 4 } 5 private static final long serialVersionUID = 1L; 6 }
![Page 17: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/17.jpg)
Channel?
Cast your bread on the waters
1 this.systemProperties = channel.call(new GetSystemProperties());
![Page 18: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/18.jpg)
Represents a communication channel to the remote peer
Obtain from:
Channel
![Page 19: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/19.jpg)
Where is the file?
Distribution Abstractions – FilePath
![Page 20: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/20.jpg)
hudson.FilePathMuch like java.util.File
Consider pushing logic to the fileUse FilePath.act(FileCallable)
Distribution Abstractions – FilePath
![Page 21: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/21.jpg)
Launch stuff remotely!
Distribution Abstractions – Launcher
![Page 22: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/22.jpg)
hudson.LauncherMuch like java.lang.ProcessBuilder
Pick your environment variables wisely!
Distribution Abstractions – Launcher
![Page 23: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/23.jpg)
Vote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility
Agenda
![Page 24: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/24.jpg)
WORA. You know. But.
/ vs \.sh vs .batQuotes around commandsPermissions
(wait for it…)
Working in multiple OSs
![Page 25: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/25.jpg)
Executing file…
remotely… platform independent…
Running script…
![Page 26: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/26.jpg)
Can You Spot The Error?
1 String workspaceDir = build.getWorkspace().getRemote(); 2 String scriptName = launcher.isUnix() ? "proc.sh" : "proc.bat"; 3 Launcher.ProcStarter procStarter = launcher.launch().stdout(System.out); 4 procStarter.cmds(new File(workspaceDir, scriptName)).join();
Executedlocally!
![Page 27: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/27.jpg)
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
Going Remote with File
![Page 28: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/28.jpg)
Permissions Dance
1 public boolean isDirectoryReadOnly(final FilePath filePath) throws IOException, 2 InterruptedException { 3 return filePath.getChannel().call(new Callable<Boolean, IOException>() { 4 public Boolean call() throws IOException { 5 Path path = FileSystems.getDefault().getPath(filePath.getRemote()); 6 Set<String> systems = FileSystems.getDefault().supportedFileAttributeViews(); 7 if (systems.contains("dos")) { 8 DosFileAttributeView dosView = 9 Files.getFileAttributeView(path, DosFileAttributeView.class); 10 DosFileAttributes dosAttributes = dosView.readAttributes(); 11 return dosAttributes.isReadOnly(); 12 } 13 if (systems.contains("posix")) { 14 PosixFileAttributeView posixView = 15 Files.getFileAttributeView(path, PosixFileAttributeView.class); 16 PosixFileAttributes posixAttributes = posixView.readAttributes(); 17 Set<PosixFilePermission> permissions = posixAttributes.permissions(); 18 return !permissions.contains(PosixFilePermission.OTHERS_WRITE) 19 } 20 throw new IOException("Unknown filesystem"); 21 } 22 }); 23 }
![Page 29: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/29.jpg)
Vote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility
Agenda
![Page 30: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/30.jpg)
First, let’s look at the docs:
Creating UI using Groovy
![Page 31: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/31.jpg)
Analogous to JellyCan use Jelly tags and libraries
Kohsuke:
Creating UI using Groovy
When What
Lots of program logic Groovy
Lots of HTML layout markup Jelly
![Page 32: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/32.jpg)
Analogous to JellyCan use Jelly tags and libraries
me:
Creating UI using Groovy
When What
Always! Groovy
![Page 33: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/33.jpg)
Jelly:
Groovy:
Creating UI using Groovy
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>
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 }
![Page 34: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/34.jpg)
Creating UI using 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 }
Real codeDebuggable, etc.
(stay tuned…)
![Page 35: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/35.jpg)
Vote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility
Agenda
![Page 36: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/36.jpg)
Documentation:
Writing custom Jelly(?) tags
![Page 37: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/37.jpg)
![Page 38: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/38.jpg)
Writing custom Jelly(?) tags
![Page 39: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/39.jpg)
Simple as 1,2…that’s it.
Writing custom Jelly Groovy tags
![Page 40: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/40.jpg)
1. Implement
1 class MotivationTagLib extends 2 AbstractGroovyViewModule { 3 def tools = .namespace( builder ) 'hudson/tools' 4 5 MotivationTagLib(JellyBuilder b) { 6 (b) super 7 } 8 9 def evilLaugh() { 10 .label(tools ) 'mu-ha-ha!'11 } 12 }
![Page 41: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/41.jpg)
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 }
![Page 42: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/42.jpg)
Vote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility
Agenda
![Page 43: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/43.jpg)
Back to Motivation plugin…
Maintaining backwards compatibility
![Page 44: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/44.jpg)
Rename defaultMotivatingMessageto
motivatingMessage
What happens to existing configuration on users machines?
Refactoring!
![Page 45: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/45.jpg)
Register field (or class) aliasIn Initializer that runs before plugins started
More complex cases might reqiure XStream converter
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 }
![Page 46: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/46.jpg)
See you at our DEMOzone!
Thank you!
![Page 47: Take Control. Write a Plugin. Part II](https://reader031.vdocument.in/reader031/viewer/2022032708/56812ac3550346895d8e9033/html5/thumbnails/47.jpg)
Thank You To Our Sponsors