Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Writing your Third Plugin

Jenkins User Conference 2012

Only by the third plugin do you get the hang of writing a plugin. I thought as a developer coming to the build side of things it'd be easy to jump in and write some plugins. I was wrong. Don't be fooled by the extremely friendly Jenkins community, writing a plugin from scratch is harder than they let on. This talk will explain the hurdles that I had to cross to make writing plugins easy.

  • Be the first to comment

Writing your Third Plugin

  1. 1. Getting to YourThird PluginJustin Ryanjryan@netflix.com@quidryan
  2. 2. Disclaimer Jenkins has evolved There will be zombies[http://www.squidoo.com/zombies-hq][http://www.evike.com/product_info.php?products_id=27951]
  3. 3. Disclaimer Jenkins has evolved There will be zombies[http://www.squidoo.com/zombies-hq][http://www.evike.com/product_info.php?products_id=27951]
  4. 4. Disclaimer Jenkins has evolved There will be zombies[http://www.squidoo.com/zombies-hq][http://www.evike.com/product_info.php?products_id=27951]
  5. 5. Disclaimer Jenkins has evolved There will be zombies Survival Tip: Use your instincts[http://www.squidoo.com/zombies-hq][http://www.evike.com/product_info.php?products_id=27951]
  6. 6. Why do we write plugins? “An extendable open source continuous integration server”[http://www.ufunk.net/en/photos/dead-of-the-class-lavantapres-des-zombies/]
  7. 7. Don’t write a plugin! Boilerplate Maintenance Overhead[http://www.ufunk.net/en/photos/dead-of-the-class-lavantapres-des-zombies/]
  8. 8. Avoiding writing of plugins Groovy Plugin Groovy Postbuild Plugin Job DSL Plugin[http://www.wired.co.uk/magazine/archive/2012/02/play/on-your-marks]
  9. 9. Groovy Plugin Access to complete system Sample: Disable failing jobs Scan for known errors Enforce plugin defaults[http://www.spencersonline.com/product/n-zombie-brains-poster/]
  10. 10. Groovy Plugindef buildable = Jenkins.instance.projects    .findAll { !it.getBuilds().isEmpty() && it.buildable }def bad = "Illegal attempt to republish existing"buildable.each { job ->  lastBuild = job.getLastBuild()  log = lastBuild.getLog(100)  logLength = log.size()  int lineNum = 0  for (; lineNum < logLength && !errorFound; lineNum++) {    if (log[lineNum].contains(bad)) {      print "Error in ${job.name} “ println “build ${lastBuild.number} on line ${lineNum}"      errorFound = true;    }  }}
  11. 11. Display Objectdef display(obj) { if (obj == null) { println "Null" return } println obj.class.name println " Properties:" obj.metaClass.properties.each { p -> if (p.getter) { println " ${p.name}:${p.type}:${p.getProperty(obj)}" } } println " Methods:" obj.class.getDeclaredMethods().each { m -> println " ${m.toString()}" }}Jenkins.instance.items.each { display(it) }
  12. 12. Groovy Postbuild Plugin Add Badges Add Summary Set Status Provides Context Searching[http://www.stickergiant.com/zombies-button_hpsb4036.html][http://www.cafepress.com/+keep_calm_and_kill_zombies_35_button,669439132][http://www.polyvore.com/zombies_buttons_pins_badges_cafepress/thing?id=17892027]
  13. 13. Groovy Postbuild Pluginpattern = ~/.*src/main/java/(.*).java:[^ ]* (.*)def map = [:]manager.build.logFile.eachLine { line -> matcher = pattern.matcher(line) if(matcher.matches()) { ownClass = matcher.group(1).replaceAll("/", ".") map[ownClass] = matcher.group(2) }}summary = manager.createSummary("warning.gif")summary.appendText("Classes using Sun proprietary API:<ul>", false)map.each { summary.appendText("<li><b>$it.key</b> - $it.value</li>", false)}summary.appendText("</ul>", false)
  14. 14. Groovy Postbuild Pluginhttps://wiki.jenkins-ci.org/display/JENKINS/Groovy+Postbuild+Plugin
  15. 15. Groovy Postbuild Pluginif("true".equals(manager.build.buildVariables.get("storeToDB"))) { manager.addBadge("db_in.gif", "Stored to DB")}https://wiki.jenkins-ci.org/display/JENKINS/Groovy+Postbuild+Plugin
  16. 16. Job DSL Plugin Programmatic Editable Templates[http://www.zombiedaily.com/2008/08/zombie-zoot-suit.html?m=1]
  17. 17. Job DSL Pluginimport groovy.json.JsonSlurperdef project = Netflix/asgarddef url = “https://api.github.com/repos/${project}/branches”def api = new URL(url)def branches = new JsonSlurper().parse(api.newReader())branches.each { def branchName = it.name job { name "${project}-${branchName}".replaceAll(/,-) scm { git("git://github.com/${project}.git", branchName) } steps { maven(clean build) } }}https://github.com/jenkinsci/job-dsl-plugin/wiki
  18. 18. Getting Started Plugin Tutorial Stephen Connolly’s 7 Part Tutorial hello-world Plugin[http://www.myspace.com/theraychul/photos/736009]
  19. 19. Mental Model Categorize technologies Dig deeper into each Able to ask questions[http://www.zombiesatemyblog.com/post/1277325743]
  20. 20. Describable Everything with a UI JDKs Build Step Actual Instance[http://sylverblaque.wordpress.com/2011/10/24/zombie-love-song/]
  21. 21. Describable
  22. 22. Descriptor Needed for each Describable Hold Global Config Creates Describable[http://www.sandovalnation.webs.com/]
  23. 23. Extension Points “Hooks into system” @ExtensionPoint indicates implementation Most Common: BuildWrapper Trigger BuildStep Publisher[http://s268.photobucket.com/albums/jj23/cooljay1622/?action=view&current=ZombieArms.png&newest=1]
  24. 24. Extension Points“Hooks into system”@ExtensionPoint indicatesimplementationMost Common: BuildWrapper Trigger BuildStep Publisher
  25. 25. What is a HPI? Just a .jar META-INF/MANIFEST.MF WEB-INF classes META-INF lib Isolated Classloader[http://zombieapocalypseacademy.org/zombie-wallpapers/]
  26. 26. What is a Plugin? HPI Published to Jenkins Maven Documented in Jenkins Wiki[http://ismashphone.com/2011/08/plug-in-zone-out-die-english-tabloid-warns-of-ipod-zombies.html]
  27. 27. Plugin Model Plugin HPI/JPI Extension Extension Extension Descriptor Describable Describable Describable
  28. 28. UI Model Browser Stapler GET POST Ajax Jelly Describable Descriptor
  29. 29. Stapler Technically a URL mapping system Responsible for Loading UI Form submissions View “Structured Form Submission” Wiki[http://www.bitrebels.com/geek/zombie-skull-pencil-holder-for-the-horrific-office-worker/]
  30. 30. Descriptor LifecycleStartup Descriptor()GlobalConfig Descriptor.configure JobConfig Descriptor.newInstance
  31. 31. Descriptor LifecycleStartup Descriptor() Call load() on constructorGlobalConfig Descriptor.configure JobConfig Descriptor.newInstance
  32. 32. Descriptor LifecycleStartup Descriptor() Call load() on constructorGlobal Descriptor.configure req.getParamConfig JobConfig Descriptor.newInstance
  33. 33. Descriptor LifecycleStartup Descriptor() Call load() on constructorGlobal Descriptor.configure req.getParamConfig Job Descriptor.newInstance req.getParamConfig
  34. 34. Descriptor LifecycleStartup Descriptor() Call load() on constructorGlobal Descriptor.configure req.getParamConfig Job Descriptor.newInstance req.getParamConfig @DataBoundConstructor
  35. 35. Describable Lifecycle Configuration -> AJAX doCheckFoo doFillFooItems doAutocompleteFoo Saving -> Descriptor Loading -> XStream readResolve() for migrations[http://www.mrpoesmorgue.com/boneyard/robzombie.html]
  36. 36. Stapler Example@Overridepublic boolean configure(StaplerRequest req, JSONObject formData)throws FormException { globalExcludedRevprop = fixEmptyAndTrim( req.getParameter("svn.global_excluded_revprop")); String workspaceFormatStr = req.getParameter("svn.workspaceFormat"); workspaceFormat = Integer.parseInt(workspaceFormatStr); validateRemoteUpToVar =formData.containsKey("validateRemoteUpToVar"); // Save configuration save(); return super.configure(req, formData);}
  37. 37. Break What have I not talked about?[http://www.seattlepi.com/local/slideshow/Zombie-Walk-in-Fremont-45631.php]
  38. 38. Jelly JSP-like Placed in a package with name of Describable[http://www.crawlofthedead.com/article/the_zombie_brain_jelly_mould/]
  39. 39. Jelly JSP-like Placed in a package with name of Describable Annoying to write in groovy[http://www.crawlofthedead.com/article/the_zombie_brain_jelly_mould/]
  40. 40. Jelly Eclipse will not like the JSP-like package name Placed in a package with name of Describable Annoying to write in groovy[http://www.crawlofthedead.com/article/the_zombie_brain_jelly_mould/]
  41. 41. Jelly Sample<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form"> <f:section title=”$%{My Plugin Setup}” <f:entry title="${%Server URL}" name=”server”> <f:textbox/> </f:entry> <f:advanced> <f:entry title="${%Workspace name}" field=”workspaceName”> <f:textbox/> </f:entry> </f:advanced> </f:section></j:jelly>[http://commons.apache.org/jelly/][http://jenkins-ci.org/maven-site/hudson-core/jelly-taglib-ref.html#form]
  42. 42. Jelly Files LocationsPlugin Manager Listing src/main/resources/index.jellyGlobal Config src/main/resources/${package}/${describable}/global.jellyJob Config src/main/resources/${package}/${describable}/config.jelly src/main/resources/${package}/${describable}/help-$ {field}.htmlViewing Job src/main/resources/${package}/${action}/summary.jelly
  43. 43. Plugin Ecosystem Recommendations: Associated File Plugin hello-world Plugin TEPCO Plugin Avoid for copying: Static Analysis Plugins Job Property Plugin[http://gregtodiffer.com/home/2011/4/21/a-bangkok-zombie-apocalypse.html]
  44. 44. Installations Per Plugin
  45. 45. Median
  46. 46. Jenkins Singleton Top-level access to Jenkins data model Made up of ItemGroup filled with Item[http://zombiecombatcommand.com/]
  47. 47. Jenkins Singleton Top-level access to Ignore Jenkins data model Hudson.getInstance() Made up of ItemGroup filled with Item[http://zombiecombatcommand.com/]
  48. 48. Jenkins Singleton Top-level access to Jenkins data model Made up of ItemGroup filled with Item
  49. 49. Jenkins Singleton Ignore StaplerRequest Top-level access to Jenkins data model Methods Made up of ItemGroup filled with Item
  50. 50. Jenkins Singleton Ignore StaplerRequest Top-level access to Jenkins data model Methods Made up of ItemGroup filled with Item Ignore doCli/ doCreateView
  51. 51. Jenkins Singleton Ignore StaplerRequest Top-level access to Jenkins data model Beware Methods synchronized Made up of ItemGroup filled with Item methods Ignore doCli/ doCreateView
  52. 52. Jenkins Singleton Ignore StaplerRequest Top-level access to Jenkins data model Beware Methods synchronized Made up of ItemGroup filled with Item methods Ignore doCli/rebuildDependencyGraph doCreateViewwhen changing Upstream/ Downstream
  53. 53. Jenkins Singleton getItem is useful if Ignoreyou know access to StaplerRequest Top-level the name Jenkins data model Beware Methods synchronized Made up of ItemGroup filled with Item methods Ignore doCli/ rebuildDependencyGraph doCreateView when changing Upstream/ Downstream
  54. 54. Jenkins Singleton getItem is useful if Ignoreyou know access to StaplerRequest Top-level the name Jenkins data model Beware Methods synchronized Made up of ItemGroup filled with Item methods Ignore doCli/ rebuildDependencyGraph doCreateView when changing Upstream/ Downstream Never call onRename/ OnDeleted
  55. 55. Jenkins Singleton getItem is useful if Ignoreyou know access to StaplerRequest Top-level the name Jenkins data model Beware Methods synchronized Made up of ItemGroup filled with Item methods Ignore doCli/ rebuildDependencyGraph doCreateView when changing Upstream/ Downstream Never callgetPlugin to get onRename/ other plugins OnDeleted
  56. 56. Jenkins Model Jenkins Project/ Project/ Job Project/ Job Job Build Build Build Action Action Action
  57. 57. Actions Badly Named Metadata tacked on Persisted when attached to Build[http://tnation.t-nation.com/free_online_forum/music_movies_girls_life/zombie_apocalypse_choose_your_weapon]
  58. 58. Actions Badly Named Metadata tacked on Persisted when attached to Build Keep Actions on Build[http://tnation.t-nation.com/free_online_forum/music_movies_girls_life/zombie_apocalypse_choose_your_weapon]
  59. 59. FilePath Very likely that a “file” is remote AbstractBuild.getWorkspace() FileCallable[http://www.cisionwire.com/livingsocial-uk/i/the-horde,c148133]
  60. 60. FilePath// make file a fresh empty directory.file.act(new FileCallable<Void>() {   // if file is on a different node, this FileCallable will   // be transfered to that node and executed there.   public Void invoke(File f,VirtualChannel channel) {     // f and file represents the same thing     f.deleteContents();     f.mkdirs();   } });
  61. 61. Build Tool Maven Gradle[http://zombieupdate2k12.tumblr.com/post/24677485908]
  62. 62. Thank You To Our Sponsors
  63. 63. Justin Ryan jryan@netflix.com @quidryan Netflix is hiring! techblog.netflix.com netflix.github.com[http://calitreview.com/7933]

    Be the first to comment

    Login to see the comments

  • quidryan

    Oct. 5, 2012
  • ctrabold

    Jan. 27, 2013
  • mubbashir

    Jun. 4, 2013
  • jmniesen

    Aug. 8, 2014
  • TaopaiC

    Sep. 28, 2014
  • chelusly

    Oct. 10, 2014
  • jacobdanner

    Nov. 26, 2014
  • alexis.tejeda

    Mar. 2, 2015
  • neofreko

    Jan. 27, 2016
  • illesm

    Jun. 8, 2020

Jenkins User Conference 2012 Only by the third plugin do you get the hang of writing a plugin. I thought as a developer coming to the build side of things it'd be easy to jump in and write some plugins. I was wrong. Don't be fooled by the extremely friendly Jenkins community, writing a plugin from scratch is harder than they let on. This talk will explain the hurdles that I had to cross to make writing plugins easy.

Views

Total views

31,273

On Slideshare

0

From embeds

0

Number of embeds

17,771

Actions

Downloads

79

Shares

0

Comments

0

Likes

10

×