Take control. write a plugin. part II

  • 601 views
Uploaded on

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 …

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.

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
601
On Slideshare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
7
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide
  • 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.
  • Show defaultMotivating method refactoring

Transcript

  • 1. Jenkins User Conference San Francisco, Sept 30 2012 #jenkinsconf Take Control. Write a Plugin. Part II Baruch Sadogursky JFrog www.jfrog.com
  • 2. About meDeveloper Advocate @JFrogJob definition: Write code Talk about itgithub.com/jbaruch@jbaruch
  • 3. JFrog & JenkinsWith Jenkins from day 1Jenkins Artifactory PluginHosted JUC Israelrepo.jenkins-ci.orgJavaOne DEMOzone
  • 4. AgendaVote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility
  • 5. AgendaVote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility
  • 6. First, let’s voteWho saw “Take Control. Write a Plugin” sessionon 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 pluginsWhat you can do with pluginsWhat you can’t do with pluginsPlugins statistics
  • 9. What can I extend?UISCMBuild ProcessesSlave managementTooling... Many, many, moreYou can even create new extension points!
  • 10. EnvironmentIDE All majors have good support We love IntelliJ IDEABuild tool Can be Maven or Gradle
  • 11. The “Motivation” PluginTarget: Rewarding failing builds with insultingmockeryGlobal configuration: Motivation phraseProject configuration: Is motivator enabledOutcome: Message appears in log after failure
  • 12. Nowdays…BACK TO OUR AGENDA
  • 13. AgendaVote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility
  • 14. Working with remote agentsJenkins has remote agents!
  • 15. Working with remote agentsSend closures to remote agentshudson.remoting.Callable Java Serialization
  • 16. Closure Poor guy’s Java closure Usually anonymous inner class (not always)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 }
  • 17. Cast your bread on the waters1 this.systemProperties = channel.call(new GetSystemProperties()); Channel?
  • 18. ChannelRepresents a communication channel to theremote peerObtain from:
  • 19. Distribution Abstractions – FilePathWhere is the file?
  • 20. Distribution Abstractions – FilePathhudson.FilePath Much like java.util.FileConsider pushing logic to the file Use FilePath.act(FileCallable)
  • 21. Distribution Abstractions – LauncherLaunch stuff remotely!
  • 22. Distribution Abstractions – Launcherhudson.Launcher Much like java.lang.ProcessBuilderPick your environment variables wisely!
  • 23. AgendaVote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility
  • 24. Working in multiple OSsWORA. You know. But./ vs .sh vs .batQuotes around commandsPermissions (wait for it…)
  • 25. Running script…Executing file… remotely… platform independent…
  • 26. 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(); Executed locally!
  • 27. Going Remote with FileUse 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
  • 28. 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 }
  • 29. AgendaVote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility
  • 30. Creating UI using GroovyFirst, let’s look at the docs:
  • 31. Creating UI using GroovyAnalogous to JellyCan use Jelly tags and libraries Kohsuke: When What Lots of program logic Groovy Lots of HTML layout markup Jelly
  • 32. Creating UI using GroovyAnalogous to JellyCan 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)23 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)23 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. AgendaVote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility
  • 36. Writing custom Jelly(?) tagsDocumentation:
  • 37. Writing custom Jelly(?) tags
  • 38. Writing custom Jelly Groovy tagsSimple as 1,2… that’s it.
  • 39. 1. Implement 1 class MotivationTagLib extends 2 AbstractGroovyViewModule { 3 def tools = builder.namespace(hudson/tools) 4 5 MotivationTagLib(JellyBuilder b) { 6 super(b) 7 } 8 9 def evilLaugh() {10 tools.label(mu-ha-ha!)11 }12 }
  • 40. 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 }
  • 41. AgendaVote and guessingWorking with remote agentsWorking in multiple operation systemsCreating UI using GroovyWriting custom Jelly(?) tagsMaintaining backwards compatibility
  • 42. Maintaining backwards compatibilityBack to Motivation plugin…
  • 43. Refactoring!Rename defaultMotivatingMessage to motivatingMessageWhat happens to existing configuration onusers machines?
  • 44. XStream Aliasing To The Rescue1 @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
  • 45. Thank you!See you at our DEMOzone!
  • 46. Thank You To Our Sponsors