Your SlideShare is downloading. ×
0
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Writing your Third Plugin
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Writing your Third Plugin

10,113

Published on

Jenkins User Conference 2012 …

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.

Published in: Technology
0 Comments
8 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
10,113
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
59
Comments
0
Likes
8
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
  • Why are you here?\n\nEither you’ve written a plugin and had no idea what you’re doing. Or.... Or.... you’ve never written a plugin.\n\nI’m here to simplify things, make things clear which weren’t once before. I’m also trying to capture my experiences as a newbie, before I’m not one anymore.\n\nI know I’m going to have people come up to me afterwards to tell me how easy things are. Well, you all wouldn't be here if you thought the same thing. Maybe we can mob them afterwards.\n\nI’ll be making a lot of references to websites and plugins. There’s no need to write them all down in your notepad or go clickety-clack on your keyboard, I’ll put the slides up later, with nice hyperlinks. Follow @quidryan to see where post them.\n\nNo easy answer here. I don't have sage advice, I have war wounds.\n
  • http://www.squidoo.com/zombies-hq\nhttp://www.evike.com/product_info.php?products_id=27951\n\nI believe what Jenkins has accomplished is nothing short of amazing. One particular miracle they’ve pulled off is being backwards compatible for so many versions. This has the side effect of certain core objects showing their age. Which means as you traverse the documentation, you will have to waste precious cycles of your brain. Don’t let Jenkins eat your brains.\n\nI should add that during the presentation, I might make disparaging remarks concerning the documentation. I fully understand that as an open source project the onus is on us to be fixing it as we see it. But I didn’t realize my qualms until I worked through this presentation. It just proves that we have selective memories, while working my plugns I just pushed through until it worked and forgot all the bad parts.\n
  • http://www.squidoo.com/zombies-hq\nhttp://www.evike.com/product_info.php?products_id=27951\n\nI believe what Jenkins has accomplished is nothing short of amazing. One particular miracle they’ve pulled off is being backwards compatible for so many versions. This has the side effect of certain core objects showing their age. Which means as you traverse the documentation, you will have to waste precious cycles of your brain. Don’t let Jenkins eat your brains.\n\nI should add that during the presentation, I might make disparaging remarks concerning the documentation. I fully understand that as an open source project the onus is on us to be fixing it as we see it. But I didn’t realize my qualms until I worked through this presentation. It just proves that we have selective memories, while working my plugns I just pushed through until it worked and forgot all the bad parts.\n
  • http://www.squidoo.com/zombies-hq\nhttp://www.evike.com/product_info.php?products_id=27951\n\nI believe what Jenkins has accomplished is nothing short of amazing. One particular miracle they’ve pulled off is being backwards compatible for so many versions. This has the side effect of certain core objects showing their age. Which means as you traverse the documentation, you will have to waste precious cycles of your brain. Don’t let Jenkins eat your brains.\n\nI should add that during the presentation, I might make disparaging remarks concerning the documentation. I fully understand that as an open source project the onus is on us to be fixing it as we see it. But I didn’t realize my qualms until I worked through this presentation. It just proves that we have selective memories, while working my plugns I just pushed through until it worked and forgot all the bad parts.\n
  • Then one day you get one little use case you think needs some tweaking, so you decide it time to write a plugin. Right? You’ve heard how Jenkins is made up from Plugins, and there’s a friendly community behind them.\n\nSure, we all think if we write a Jenkins plugins we'll get famous. They’ll put out the red carpet at Devoxx, you get interviewed on the The Ship Show Podcast, the Java Posse will give you a mention.\n
  • Wrong!\n\nIn your head is one or two lines which truly represent when you want to accomplish. But you’ll realize that writing a plugin is work. There’s boilerplate code you have to write. You have to maintain it.\n\n
  • One direction to go into is one of these three.\n\n
  • Available at the system level or in a job. Use system groovy when possible. It can go back and clean up jobs, enforce plugins. It has the advantage of being easy to code. Can be scheduled at regular intervals, when put into a Job. Plugins typically have to be enabled on a Job, which is hard when you have hundreds of jobs.\n\nExample: Disable failing jobs - People are going to be move on a project, or forget job. it’s not worth tracking them down. So after a period of time, we just disable the jobs. “If a builds get disabled in the Jenkins and no one notices, did really happen?” We also limit the number of builds to 20, unless they really want more\n
  • I’ll show code examples, I don’t think it’s the best use of time to review them line by line.\n\nIn this sample, I’m going to each Job, aka Project, and looking at the log from the last build. \n
  • Displays groovy objects, useful for exploration of Jenkins data model.\n
  • Badges - addInfoBadge, addWarningBadge, addErrorBadge\nSummary - createSummary\nStatus - buildUnstable, buildFailure, buildSuccess\nAccess to Jenkins instance, Build and Listener\nSearching - logContains, contains to search file, getMatch, getLogMatcher\n\nCan’t be shared though. Needs scriptler integration.\n
  • Examples looks for Sun priprietary APIs.\n
  • You’ll have a hard time telling me this isn’t from a plugin.\n
  • \n
  • Allows programmatic approach to creating jobs\nCan come from source control. Can be accompanied with a job.\nWhich also gives you a lot of power to share common functionality.\nScales real nicely to build a few similar projects, instead of being tempted to parameterize them\n\n
  • Sample loops through all the branches, creating a job for each one.\n
  • OK, Fine, you want to write a plugin\n\nYou start with https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial but you’ll find nothing for how to code for it. It’ll talk just about setting up your environment\nIt’ll forward you to Stephen Connolly's 7 part tutorial, while thorough, it is bogged down maven mentuia and 5 years old\nMaybe you look at the hello-world plugin. But you still don’t know what is boilerplate and what should be changed.\nExisting tutorials show how to create a simple plugin. I’m taking a orthogonal approach today.\n\n
  • There’s a lot of independent projects being used here, e.g. Java, Stapler, Jelly, HTML\n\nThe most important thing for me to build a mental model.\n\nAlong the lines of learning Hibernate and not learning how Sessions work. You’ll be left dazed and confused.\n\nIn our field, you need to ask questions, but sometimes you’re so far removed from the problem, that you don’t even know what questions to ask.\nThe rest of the talk is about diving a little deeper into each of these technologies so that you know what do look into when you come across them. \n\nThere’s a few way to slice and dice the models.\n\n
  • Let’s start with what you know. Well, you don’t know that you know it.\n\nMaking a Describable allows you to define help files, form validation check methods, and so on correctly. \n\n https://github.com/jenkinsci/git-plugin/blob/master/src/main/java/hudson/plugins/git/GitSCM.java\n
  • \n
  • Think of them attached as your implementations of your plugin. We’ll come back to how it’s viewed later, but here are some examples.\n\nCan always look it up:\n DescriptorImpl descriptor = Jenkins.getInstance().getDescriptorByType(DescriptorImpl.class);\nDescriptors are funny. Descriptor.load() in constructor, you’re responsibility to save(). \nnewInstance used to constantly create per-Project instances. Interestingly this calls stapler to do DataBoundConstructor for you, which is why you can ignore it, until you can’t.\nNothing stopping you from having multiple Descriptors in your plugin, where each \nBest done with a @Extension static class, will get created by Jenkins\nData can live on descriptor, because that’s global \nForced to use configure to get values, everyone should read:\n https://wiki.jenkins-ci.org/display/JENKINS/Structured+Form+Submission\n Most basic level: useFrench = json.getBoolean("useFrench");\n More complex: req.bindJSONToList(AnsiColorMap.class, req.getSubmittedForm().get("colorMap")\n Then always call save()\n\n
  • Extension points provides answers to the question, “are there any implementations for this interface?” It then requires a consumer to call Jenkins.getInstance().getExtensionList(Class<T>);\n
  • Up to consumer how it’ll collect the extension points. Each one has it’s own rules for how it’ll be used.\nStick with basics:\n BuildWrapper\n preCheckout\n setup, after checkout\n BuildStep\n Publisher\n“The save operation happens without any notice, and the restore operation happens without calling the constructor, just like Java serialization.” \n
  • http://zombieapocalypseacademy.org/zombie-wallpapers/\n\nFirst, let’s talk about what is a HPI\nIt’ll build to real binaries, one jar and one hpi.\nJust unzip look around\nMETA-INF/MANIFEST.MF - Manifest, tells you about version numbers\nWEB-INF/classes - .class files and jelly files\nWEB-INF/classes/META-INF - Output from annotation scanning\nWEB-INF/lib just has the jars\nBinary. Wrapped with all dependencies, relying on Classloaders to isolate, like OSGI\n\n\nMANIFEST.MF\nManifest-Version: 1.0\nv: 1.0-beta\nUrl: https://wiki.jenkins-ci.org/display/JENKINS/Job+DSL+Plugin\nGroup-Id: org.jenkinsci.plugins\nJenkins-Version: 1.456\nPlugin-Version: 1.0-beta\nLong-Name: Job DSL\nShort-Name: job-dsl\n
  • It’s an HPI. Really, it has no other meaning, there is no Plugin class that gets implemented.\n\n
  • \n
  • \n
  • It is not a modern web framework. It is what it is.\nMost commonly needed to map HTML forms and bind the request to objects.\nRequired for Descriptor.configure.\nBest possible source is Structured Form Submission (https://wiki.jenkins-ci.org/display/JENKINS/Structured+Form+Submission) and http://stapler.kohsuke.org/\nThe lesson is to use good consistent names and everything will be easy.\n\n
  • Let’s start talking about how they’re loaded, I’m going to skim over UI pieces\n\n* Startup - Loads HPI, Finds Extensions, Instantiates Descriptions\n* Global Config\nLoads “src/main/resources/${plugin-package}/${plugin-class-name}/global.jelly”\nsave calls configure(StaplerRequest req, JSONObject json)\n* Job Config\nLoads “src/main/resources/${plugin-package}/${plugin-class-name}/config.jelly”\n(Loading values via XSTREAM, then applying via Jelly)\n
  • Let’s start talking about how they’re loaded, I’m going to skim over UI pieces\n\n* Startup - Loads HPI, Finds Extensions, Instantiates Descriptions\n* Global Config\nLoads “src/main/resources/${plugin-package}/${plugin-class-name}/global.jelly”\nsave calls configure(StaplerRequest req, JSONObject json)\n* Job Config\nLoads “src/main/resources/${plugin-package}/${plugin-class-name}/config.jelly”\n(Loading values via XSTREAM, then applying via Jelly)\n
  • Let’s start talking about how they’re loaded, I’m going to skim over UI pieces\n\n* Startup - Loads HPI, Finds Extensions, Instantiates Descriptions\n* Global Config\nLoads “src/main/resources/${plugin-package}/${plugin-class-name}/global.jelly”\nsave calls configure(StaplerRequest req, JSONObject json)\n* Job Config\nLoads “src/main/resources/${plugin-package}/${plugin-class-name}/config.jelly”\n(Loading values via XSTREAM, then applying via Jelly)\n
  • Let’s start talking about how they’re loaded, I’m going to skim over UI pieces\n\n* Startup - Loads HPI, Finds Extensions, Instantiates Descriptions\n* Global Config\nLoads “src/main/resources/${plugin-package}/${plugin-class-name}/global.jelly”\nsave calls configure(StaplerRequest req, JSONObject json)\n* Job Config\nLoads “src/main/resources/${plugin-package}/${plugin-class-name}/config.jelly”\n(Loading values via XSTREAM, then applying via Jelly)\n
  • I don’t think it’s relevant, but it creates URL for your classes, which have backend values for ajax calls and pages for your plugins.\ndoCheckFoo - Validation\ndoFillFooItems - Auto-populate field, used by jclouds plugin to fill in hardware types\ndoAutocompleteFoo - Contributes to auto complete values\n\n
  • From hudson.scm.SubversionSCM\n\nCame from this:\n<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">\n <f:section title="${%Subversion}">\n <f:entry title="${%Subversion Workspace Version}" help="/descriptor/hudson.scm.SubversionSCM/help/workspaceFormat">\n <select name="svn.workspaceFormat">\n <f:option value="8" selected="${descriptor.workspaceFormat==8}" >1.4</f:option>\n <f:option value="9" selected="${descriptor.workspaceFormat==9}" >1.5</f:option>\n <f:option value="10" selected="${descriptor.workspaceFormat==10}">1.6 (svn:externals to file)</f:option>\n </select>\n </f:entry>\n <f:entry title="${%Exclusion revprop name}" help="/descriptor/hudson.scm.SubversionSCM/help/excludedRevprop">\n <f:textbox name="svn.global_excluded_revprop" value="${descriptor.globalExcludedRevprop}"/>\n </f:entry>\n <f:optionalBlock\n name="svn.validateRemoteUpToVar"\n checked="${descriptor.validateRemoteUpToVar}"\n title="${%Validate repository URLs up to the first variable name}"\n help="/descriptor/hudson.scm.SubversionSCM/help/validateRemoteUpToVar"/>\n <f:optionalBlock\n name="svn.storeAuthToDisk"\n checked="${descriptor.storeAuthToDisk}"\n title="${%Update default Subversion credentials cache after successful authentication}"/>\n </f:section>\n</j:jelly>\n
  • \n
  • \nCan write in Groovy, which is a facade over jelly. But it's even worse documented\nui-samples plugin is the best reference for groovy examples. Though I was tripped up by s:sample notation.\nStapler identifies appropriate file to render\nTags are run. Everything is executed on the server. Though some will output HTML that could come with javascript to run.\nPage renders\nCallbacks to fillFooItems, prototype.js behind the scenes.\n\n
  • \nCan write in Groovy, which is a facade over jelly. But it's even worse documented\nui-samples plugin is the best reference for groovy examples. Though I was tripped up by s:sample notation.\nStapler identifies appropriate file to render\nTags are run. Everything is executed on the server. Though some will output HTML that could come with javascript to run.\nPage renders\nCallbacks to fillFooItems, prototype.js behind the scenes.\n\n
  • \n/jenkins/tree/master/core/src/main/resources/lib/[hudson,layout,form]\njelly:core\nwhile, choose/when/otherwise, \nPointless: core:scope, core:thread, core:parse, core:mute\n/lib/hudson\n/lib/form\nSection, almost necessary div identifying your plugin verses others\n<f:section title="Environment Selector Set-up">\nEntry\nDoes magic with doCheck, and binding help-*.html foo, auto population, \nExcept for boolean/checkboxes\n<f:entry title="${%Environment}">\nTextbox\nShouldn’t need name and value, if wrapped in entry\n<f:textbox name="env.envName" value="${env.envName}"/>\nRuby doesn’t have it much better:\nhttps://github.com/rtyler/vagrant-plugin/blob/master/views/vagrant/sudo_builder/config.erb\n\n
  • Simplified because anything Describable can have a view\n
  • \nDocumentation is typically poor, so just install them. It's so crazy easy to run Jenkins locally.\nThere will be no end to people telling you to look at existing plugins.\nWork with modern plugins, with @Extensions, like\n Associated File Plugin - For Gradle Example\n https://github.com/jenkinsci/hello-world-plugin\n https://wiki.jenkins-ci.org/display/JENKINS/TEPCO+Plugin For Widget, Recurring work\n Don’t use static analysis plugins and Job Property Plugin\n\n
  • Number of installations per plugin follows a steep hockey curve. If you ignore the core, all plugins have a real limited install base. There is a daunting number of plugins out there. It’s hard to know what is new/old/modern.\n
  • This graph represents just the middle. The bar isn’t that high though. SBT is a major build tool, and it’s at 310. Then again, there’s a emma plugin which mis-spells column and a plugin that just shows Bruce Scheneier is here. But at the same time there’s plugins which serve a small community, that doesn’t make it old or worthless.\n
  • http://javadoc.jenkins-ci.org/jenkins/model/Jenkins.html\n\nSpeaking of Jenkins the class, this is a place to start exploring. Starts with ItemGroup, containing a specific type of Item. "Full Name" is the join of '/'.\nKeep in mind that properties of Item as you work with objects, because it won’t be obvious. E.g. ItemListener for things like onLoad()\nSpecial type of item: TopLevelItem\n\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Pretty much any meta-data added to an object\nThe only real way to contribute actions to a Project is getProjectActions()\nI tried to save post-build data directly onto an project action, but it kept getting creamed. Best solution was to do with most other plugins do, which is store action on the build, then at the project level aggregate them.\n\n\n\n
  • You can no longer assume files are local. Welcome to the world of distributed computing.\nJenkins will let you fake a synchronous call, via FileCallable. Let’s you ship code to slave to run.\n“On a slave, usually only a part of the Jenkins object graph is available. This means that, for instance, Hudson.getInstance() can return null. To work around this, grab all the information you need on the master side, assign them to final variables, then access them from the closure so that only those bits get sent to the slave.”\nYou get one from something like boolean perform(AbstractBuild<?,?> build, Launcher launcher, BuildListener listener)\n\n
  • \n
  • There's a long history of tight maven integration. Maven is not as bad as long as you have someone else writing the plugins, luckily that’s already done for Jenkins. Gradle is new enough that could cause confusion for new developers, especially without a Java background.\nThe only reason I used it was that I had Hans Dockter and Andrew Bayer around.\nI ran into issues around requiring maven plugin support, testCompile needing exclusions.\n\n
  • I’d like to thank our sponsors. Having a conference like this is really important to the community.\n
  • \n
  • Transcript

    • 1. Getting to YourThird PluginJustin Ryanjryan@netflix.com@quidryan
    • 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. 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. 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. 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. 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. Don’t write a plugin! Boilerplate Maintenance Overhead[http://www.ufunk.net/en/photos/dead-of-the-class-lavantapres-des-zombies/]
    • 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. 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. 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. 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. 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. 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. Groovy Postbuild Pluginhttps://wiki.jenkins-ci.org/display/JENKINS/Groovy+Postbuild+Plugin
    • 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. Job DSL Plugin Programmatic Editable Templates[http://www.zombiedaily.com/2008/08/zombie-zoot-suit.html?m=1]
    • 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. Getting Started Plugin Tutorial Stephen Connolly’s 7 Part Tutorial hello-world Plugin[http://www.myspace.com/theraychul/photos/736009]
    • 19. Mental Model Categorize technologies Dig deeper into each Able to ask questions[http://www.zombiesatemyblog.com/post/1277325743]
    • 20. Describable Everything with a UI JDKs Build Step Actual Instance[http://sylverblaque.wordpress.com/2011/10/24/zombie-love-song/]
    • 21. Describable
    • 22. Descriptor Needed for each Describable Hold Global Config Creates Describable[http://www.sandovalnation.webs.com/]
    • 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. Extension Points“Hooks into system”@ExtensionPoint indicatesimplementationMost Common: BuildWrapper Trigger BuildStep Publisher
    • 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. 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. Plugin Model Plugin HPI/JPI Extension Extension Extension Descriptor Describable Describable Describable
    • 28. UI Model Browser Stapler GET POST Ajax Jelly Describable Descriptor
    • 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. Descriptor LifecycleStartup Descriptor()GlobalConfig Descriptor.configure JobConfig Descriptor.newInstance
    • 31. Descriptor LifecycleStartup Descriptor() Call load() on constructorGlobalConfig Descriptor.configure JobConfig Descriptor.newInstance
    • 32. Descriptor LifecycleStartup Descriptor() Call load() on constructorGlobal Descriptor.configure req.getParamConfig JobConfig Descriptor.newInstance
    • 33. Descriptor LifecycleStartup Descriptor() Call load() on constructorGlobal Descriptor.configure req.getParamConfig Job Descriptor.newInstance req.getParamConfig
    • 34. Descriptor LifecycleStartup Descriptor() Call load() on constructorGlobal Descriptor.configure req.getParamConfig Job Descriptor.newInstance req.getParamConfig @DataBoundConstructor
    • 35. Describable Lifecycle Configuration -> AJAX doCheckFoo doFillFooItems doAutocompleteFoo Saving -> Descriptor Loading -> XStream readResolve() for migrations[http://www.mrpoesmorgue.com/boneyard/robzombie.html]
    • 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. Break What have I not talked about?[http://www.seattlepi.com/local/slideshow/Zombie-Walk-in-Fremont-45631.php]
    • 38. Jelly JSP-like Placed in a package with name of Describable[http://www.crawlofthedead.com/article/the_zombie_brain_jelly_mould/]
    • 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. 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. 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. 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. 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. Installations Per Plugin
    • 45. Median
    • 46. Jenkins Singleton Top-level access to Jenkins data model Made up of ItemGroup filled with Item[http://zombiecombatcommand.com/]
    • 47. Jenkins Singleton Top-level access to Ignore Jenkins data model Hudson.getInstance() Made up of ItemGroup filled with Item[http://zombiecombatcommand.com/]
    • 48. Jenkins Singleton Top-level access to Jenkins data model Made up of ItemGroup filled with Item
    • 49. Jenkins Singleton Ignore StaplerRequest Top-level access to Jenkins data model Methods Made up of ItemGroup filled with Item
    • 50. Jenkins Singleton Ignore StaplerRequest Top-level access to Jenkins data model Methods Made up of ItemGroup filled with Item Ignore doCli/ doCreateView
    • 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. 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. 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. 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. 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. Jenkins Model Jenkins Project/ Project/ Job Project/ Job Job Build Build Build Action Action Action
    • 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. 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. FilePath Very likely that a “file” is remote AbstractBuild.getWorkspace() FileCallable[http://www.cisionwire.com/livingsocial-uk/i/the-horde,c148133]
    • 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. Build Tool Maven Gradle[http://zombieupdate2k12.tumblr.com/post/24677485908]
    • 62. Thank You To Our Sponsors
    • 63. Justin Ryan jryan@netflix.com @quidryan Netflix is hiring! techblog.netflix.com netflix.github.com[http://calitreview.com/7933]

    ×