SlideShare une entreprise Scribd logo
1  sur  63
Getting to Your
Third Plugin

Justin Ryan
jryan@netflix.com
@quidryan
Disclaimer
         Jenkins has evolved
         There will be zombies




[http://www.squidoo.com/zombies-hq]
[http://www.evike.com/product_info.php?products_id=27951]
Disclaimer
         Jenkins has evolved
         There will be zombies




[http://www.squidoo.com/zombies-hq]
[http://www.evike.com/product_info.php?products_id=27951]
Disclaimer
         Jenkins has evolved
         There will be zombies




[http://www.squidoo.com/zombies-hq]
[http://www.evike.com/product_info.php?products_id=27951]
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]
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/]
Don’t write a plugin!
        Boilerplate
        Maintenance
        Overhead




[http://www.ufunk.net/en/photos/dead-of-the-class-lavantapres-des-zombies/]
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]
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/]
Groovy Plugin
def 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;
       }
     }
}
Display Object
def 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) }
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]
Groovy Postbuild Plugin
pattern = ~/.*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)
Groovy Postbuild Plugin




https://wiki.jenkins-ci.org/display/JENKINS/Groovy+Postbuild+Plugin
Groovy Postbuild Plugin
if("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
Job DSL Plugin
        Programmatic
        Editable
        Templates




[http://www.zombiedaily.com/2008/08/zombie-zoot-suit.html?m=1]
Job DSL Plugin
import groovy.json.JsonSlurper

def project = 'Netflix/asgard'
def 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
Getting Started
        Plugin Tutorial
        Stephen Connolly’s 7
        Part Tutorial
        hello-world Plugin




[http://www.myspace.com/theraychul/photos/736009]
Mental Model
        Categorize technologies
        Dig deeper into each
        Able to ask questions




[http://www.zombiesatemyblog.com/post/1277325743]
Describable
        Everything with a UI
             JDKs
             Build Step
        Actual Instance




[http://sylverblaque.wordpress.com/2011/10/24/zombie-love-song/]
Describable
Descriptor
        Needed for each
        Describable
        Hold Global Config
        Creates Describable




[http://www.sandovalnation.webs.com/]
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]
Extension Points
“Hooks into system”
@ExtensionPoint indicates
implementation
Most Common:
  BuildWrapper
  Trigger
  BuildStep
  Publisher
What is a HPI?
        Just a .jar
            META-INF/MANIFEST.MF
            WEB-INF
                 classes
                       META-INF
                 lib
        Isolated Classloader

[http://zombieapocalypseacademy.org/zombie-wallpapers/]
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]
Plugin Model
                   Plugin


                  HPI/JPI


    Extension    Extension     Extension


                 Descriptor


   Describable   Describable   Describable
UI Model
              Browser




               Stapler

       GET                 POST
                   Ajax

   Jelly     Describable     Descriptor
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/]
Descriptor Lifecycle
Startup   Descriptor()

Global
Config
          Descriptor.configure

 Job
Config
          Descriptor.newInstance
Descriptor Lifecycle
Startup   Descriptor()   Call load() on constructor

Global
Config
          Descriptor.configure

 Job
Config
          Descriptor.newInstance
Descriptor Lifecycle
Startup   Descriptor()   Call load() on constructor

Global
          Descriptor.configure       req.getParam
Config

 Job
Config
          Descriptor.newInstance
Descriptor Lifecycle
Startup   Descriptor()   Call load() on constructor

Global
          Descriptor.configure       req.getParam
Config

 Job
          Descriptor.newInstance     req.getParam
Config
Descriptor Lifecycle
Startup   Descriptor()   Call load() on constructor

Global
          Descriptor.configure       req.getParam
Config

 Job
          Descriptor.newInstance     req.getParam
Config

                         @DataBoundConstructor
Describable Lifecycle
        Configuration -> AJAX
            doCheckFoo
            doFillFooItems
            doAutocompleteFoo
        Saving -> Descriptor
        Loading -> XStream
            readResolve() for
            migrations
[http://www.mrpoesmorgue.com/boneyard/robzombie.html]
Stapler Example
@Override
public 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);
}
Break
        What have I not talked
        about?




[http://www.seattlepi.com/local/slideshow/Zombie-Walk-in-Fremont-45631.php]
Jelly
         JSP-like
         Placed in a package with
         name of Describable




[http://www.crawlofthedead.com/article/the_zombie_brain_jelly_mould/]
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/]
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/]
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]
Jelly Files Locations
Plugin Manager Listing
  src/main/resources/index.jelly

Global Config
  src/main/resources/${package}/${describable}/global.jelly

Job Config
  src/main/resources/${package}/${describable}/config.jelly

  src/main/resources/${package}/${describable}/help-$
  {field}.html

Viewing Job
  src/main/resources/${package}/${action}/summary.jelly
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]
Installations Per Plugin
Median
Jenkins Singleton
        Top-level access to
        Jenkins data model
        Made up of ItemGroup
        filled with Item




[http://zombiecombatcommand.com/]
Jenkins Singleton
        Top-level access to               Ignore
        Jenkins data model          Hudson.getInstance()
        Made up of ItemGroup
        filled with Item




[http://zombiecombatcommand.com/]
Jenkins Singleton
 Top-level access to
 Jenkins data model
 Made up of ItemGroup
 filled with Item
Jenkins Singleton
                            Ignore
                        StaplerRequest
 Top-level access to
 Jenkins data model        Methods

 Made up of ItemGroup
 filled with Item
Jenkins Singleton
                            Ignore
                        StaplerRequest
 Top-level access to
 Jenkins data model        Methods

 Made up of ItemGroup
 filled with Item          Ignore doCli/
                          doCreateView
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
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             doCreateView
when changing Upstream/
       Downstream
Jenkins Singleton
 getItem is useful if                 Ignore
you 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
Jenkins Singleton
 getItem is useful if                 Ignore
you 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
Jenkins Singleton
 getItem is useful if                 Ignore
you 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
getPlugin to get            onRename/
 other plugins              OnDeleted
Jenkins Model
               Jenkins

    Project/              Project/
      Job      Project/     Job
                 Job

     Build                 Build
                Build



     Action     Action     Action
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]
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]
FilePath
         Very likely that a “file” is remote
         AbstractBuild.getWorkspace()
         FileCallable




[http://www.cisionwire.com/livingsocial-uk/i/the-horde,c148133]
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();
   }
 });
Build Tool
        Maven
        Gradle




[http://zombieupdate2k12.tumblr.com/post/24677485908]
Thank You To Our Sponsors
Justin Ryan
     jryan@netflix.com
     @quidryan

     Netflix is hiring!
     techblog.netflix.com
     netflix.github.com

[http://calitreview.com/7933]

Contenu connexe

Tendances

Cucumber Ru09 Web
Cucumber Ru09 WebCucumber Ru09 Web
Cucumber Ru09 WebJoseph Wilk
 
Outside-in Development with Cucumber and Rspec
Outside-in Development with Cucumber and RspecOutside-in Development with Cucumber and Rspec
Outside-in Development with Cucumber and RspecJoseph Wilk
 
SproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFestSproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFesttomdale
 
Djangocon 2014 angular + django
Djangocon 2014 angular + djangoDjangocon 2014 angular + django
Djangocon 2014 angular + djangoNina Zakharenko
 
greach 2014 marco vermeulen bdd using cucumber jvm and groovy
greach 2014 marco vermeulen bdd using cucumber jvm and groovygreach 2014 marco vermeulen bdd using cucumber jvm and groovy
greach 2014 marco vermeulen bdd using cucumber jvm and groovyJessie Evangelista
 
Getting big without getting fat, in perl
Getting big without getting fat, in perlGetting big without getting fat, in perl
Getting big without getting fat, in perlDean Hamstead
 
jQuery For Developers Stack Overflow Dev Days Toronto
jQuery For Developers Stack Overflow Dev Days TorontojQuery For Developers Stack Overflow Dev Days Toronto
jQuery For Developers Stack Overflow Dev Days TorontoRalph Whitbeck
 
Beyond DOM Manipulations: Building Stateful Modules with Events and Promises
Beyond DOM Manipulations: Building Stateful Modules with Events and PromisesBeyond DOM Manipulations: Building Stateful Modules with Events and Promises
Beyond DOM Manipulations: Building Stateful Modules with Events and PromisesCrashlytics
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the FinishYehuda Katz
 
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other Tools
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other ToolsCool like a Frontend Developer: Grunt, RequireJS, Bower and other Tools
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other ToolsRyan Weaver
 
Symfony tips and tricks
Symfony tips and tricksSymfony tips and tricks
Symfony tips and tricksJavier Eguiluz
 
Continuous Deployment at Etsy
Continuous Deployment at EtsyContinuous Deployment at Etsy
Continuous Deployment at EtsyPremshree Pillai
 
jQuery Anti-Patterns for Performance & Compression
jQuery Anti-Patterns for Performance & CompressionjQuery Anti-Patterns for Performance & Compression
jQuery Anti-Patterns for Performance & CompressionPaul Irish
 
Hybrid Web Applications
Hybrid Web ApplicationsHybrid Web Applications
Hybrid Web ApplicationsJames Da Costa
 
jQuery from the very beginning
jQuery from the very beginningjQuery from the very beginning
jQuery from the very beginningAnis Ahmad
 
Behaviour Driven Development con Behat & Drupal
Behaviour Driven Development con Behat & DrupalBehaviour Driven Development con Behat & Drupal
Behaviour Driven Development con Behat & Drupalsparkfabrik
 
Beyond the WordPress 5 minute Install
Beyond the WordPress 5 minute InstallBeyond the WordPress 5 minute Install
Beyond the WordPress 5 minute InstallSteve Taylor
 

Tendances (20)

Cucumber Ru09 Web
Cucumber Ru09 WebCucumber Ru09 Web
Cucumber Ru09 Web
 
Mojolicious
MojoliciousMojolicious
Mojolicious
 
Outside-in Development with Cucumber and Rspec
Outside-in Development with Cucumber and RspecOutside-in Development with Cucumber and Rspec
Outside-in Development with Cucumber and Rspec
 
SproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFestSproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFest
 
Djangocon 2014 angular + django
Djangocon 2014 angular + djangoDjangocon 2014 angular + django
Djangocon 2014 angular + django
 
greach 2014 marco vermeulen bdd using cucumber jvm and groovy
greach 2014 marco vermeulen bdd using cucumber jvm and groovygreach 2014 marco vermeulen bdd using cucumber jvm and groovy
greach 2014 marco vermeulen bdd using cucumber jvm and groovy
 
Getting big without getting fat, in perl
Getting big without getting fat, in perlGetting big without getting fat, in perl
Getting big without getting fat, in perl
 
jQuery For Developers Stack Overflow Dev Days Toronto
jQuery For Developers Stack Overflow Dev Days TorontojQuery For Developers Stack Overflow Dev Days Toronto
jQuery For Developers Stack Overflow Dev Days Toronto
 
SocketStream
SocketStreamSocketStream
SocketStream
 
Beyond DOM Manipulations: Building Stateful Modules with Events and Promises
Beyond DOM Manipulations: Building Stateful Modules with Events and PromisesBeyond DOM Manipulations: Building Stateful Modules with Events and Promises
Beyond DOM Manipulations: Building Stateful Modules with Events and Promises
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
 
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other Tools
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other ToolsCool like a Frontend Developer: Grunt, RequireJS, Bower and other Tools
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other Tools
 
Symfony tips and tricks
Symfony tips and tricksSymfony tips and tricks
Symfony tips and tricks
 
Continuous Deployment at Etsy
Continuous Deployment at EtsyContinuous Deployment at Etsy
Continuous Deployment at Etsy
 
jQuery Anti-Patterns for Performance & Compression
jQuery Anti-Patterns for Performance & CompressionjQuery Anti-Patterns for Performance & Compression
jQuery Anti-Patterns for Performance & Compression
 
Hybrid Web Applications
Hybrid Web ApplicationsHybrid Web Applications
Hybrid Web Applications
 
jQuery from the very beginning
jQuery from the very beginningjQuery from the very beginning
jQuery from the very beginning
 
Behaviour Driven Development con Behat & Drupal
Behaviour Driven Development con Behat & DrupalBehaviour Driven Development con Behat & Drupal
Behaviour Driven Development con Behat & Drupal
 
Ant User Guide
Ant User GuideAnt User Guide
Ant User Guide
 
Beyond the WordPress 5 minute Install
Beyond the WordPress 5 minute InstallBeyond the WordPress 5 minute Install
Beyond the WordPress 5 minute Install
 

En vedette

Building an Eclipse plugin to recommend changes to developers
Building an Eclipse plugin to recommend changes to developersBuilding an Eclipse plugin to recommend changes to developers
Building an Eclipse plugin to recommend changes to developerskim.mens
 
The Open-source Eclipse Plugin for Force.com Development, Summer ‘14
The Open-source Eclipse Plugin for Force.com Development, Summer ‘14The Open-source Eclipse Plugin for Force.com Development, Summer ‘14
The Open-source Eclipse Plugin for Force.com Development, Summer ‘14Salesforce Developers
 
A Simple Plugin Architecture for Wicket
A Simple Plugin Architecture for WicketA Simple Plugin Architecture for Wicket
A Simple Plugin Architecture for Wicketnielsvk
 
Building GPE: What We Learned
Building GPE: What We LearnedBuilding GPE: What We Learned
Building GPE: What We Learnedrajeevdayal
 
Plugin jQuery, Design Patterns
Plugin jQuery, Design PatternsPlugin jQuery, Design Patterns
Plugin jQuery, Design PatternsRobert Casanova
 
Eclipse Overview
Eclipse Overview Eclipse Overview
Eclipse Overview Lars Vogel
 
jQuery Plugin Creation
jQuery Plugin CreationjQuery Plugin Creation
jQuery Plugin Creationbenalman
 
Configuration as Code: The Job DSL Plugin
Configuration as Code: The Job DSL PluginConfiguration as Code: The Job DSL Plugin
Configuration as Code: The Job DSL PluginDaniel Spilker
 

En vedette (8)

Building an Eclipse plugin to recommend changes to developers
Building an Eclipse plugin to recommend changes to developersBuilding an Eclipse plugin to recommend changes to developers
Building an Eclipse plugin to recommend changes to developers
 
The Open-source Eclipse Plugin for Force.com Development, Summer ‘14
The Open-source Eclipse Plugin for Force.com Development, Summer ‘14The Open-source Eclipse Plugin for Force.com Development, Summer ‘14
The Open-source Eclipse Plugin for Force.com Development, Summer ‘14
 
A Simple Plugin Architecture for Wicket
A Simple Plugin Architecture for WicketA Simple Plugin Architecture for Wicket
A Simple Plugin Architecture for Wicket
 
Building GPE: What We Learned
Building GPE: What We LearnedBuilding GPE: What We Learned
Building GPE: What We Learned
 
Plugin jQuery, Design Patterns
Plugin jQuery, Design PatternsPlugin jQuery, Design Patterns
Plugin jQuery, Design Patterns
 
Eclipse Overview
Eclipse Overview Eclipse Overview
Eclipse Overview
 
jQuery Plugin Creation
jQuery Plugin CreationjQuery Plugin Creation
jQuery Plugin Creation
 
Configuration as Code: The Job DSL Plugin
Configuration as Code: The Job DSL PluginConfiguration as Code: The Job DSL Plugin
Configuration as Code: The Job DSL Plugin
 

Similaire à Writing your Third Plugin

Build Your Own CMS with Apache Sling
Build Your Own CMS with Apache SlingBuild Your Own CMS with Apache Sling
Build Your Own CMS with Apache SlingBob Paulin
 
Java 6 [Mustang] - Features and Enchantments
Java 6 [Mustang] - Features and Enchantments Java 6 [Mustang] - Features and Enchantments
Java 6 [Mustang] - Features and Enchantments Pavel Kaminsky
 
HTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyHTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyDavid Padbury
 
Spring boot introduction
Spring boot introductionSpring boot introduction
Spring boot introductionRasheed Waraich
 
Jenkins and Groovy
Jenkins and GroovyJenkins and Groovy
Jenkins and GroovyKiyotaka Oku
 
Webpack: your final module bundler
Webpack: your final module bundlerWebpack: your final module bundler
Webpack: your final module bundlerAndrea Giannantonio
 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers StealBen Scofield
 
Meetup Performance
Meetup PerformanceMeetup Performance
Meetup PerformanceGreg Whalin
 
Psgi Plack Sfpm
Psgi Plack SfpmPsgi Plack Sfpm
Psgi Plack Sfpmsom_nangia
 
Psgi Plack Sfpm
Psgi Plack SfpmPsgi Plack Sfpm
Psgi Plack Sfpmwilburlo
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing UpDavid Padbury
 
Javascript unit testing, yes we can e big
Javascript unit testing, yes we can   e bigJavascript unit testing, yes we can   e big
Javascript unit testing, yes we can e bigAndy Peterson
 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleThierry Wasylczenko
 
Dropwizard and Friends
Dropwizard and FriendsDropwizard and Friends
Dropwizard and FriendsYun Zhi Lin
 
Introduction to Client Side Dev in SharePoint Workshop
Introduction to Client Side Dev in SharePoint WorkshopIntroduction to Client Side Dev in SharePoint Workshop
Introduction to Client Side Dev in SharePoint WorkshopMark Rackley
 
Single Page JavaScript WebApps... A Gradle Story
Single Page JavaScript WebApps... A Gradle StorySingle Page JavaScript WebApps... A Gradle Story
Single Page JavaScript WebApps... A Gradle StoryKon Soulianidis
 

Similaire à Writing your Third Plugin (20)

Build Your Own CMS with Apache Sling
Build Your Own CMS with Apache SlingBuild Your Own CMS with Apache Sling
Build Your Own CMS with Apache Sling
 
Java 6 [Mustang] - Features and Enchantments
Java 6 [Mustang] - Features and Enchantments Java 6 [Mustang] - Features and Enchantments
Java 6 [Mustang] - Features and Enchantments
 
Play framework
Play frameworkPlay framework
Play framework
 
HTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyHTML5 for the Silverlight Guy
HTML5 for the Silverlight Guy
 
Spring boot introduction
Spring boot introductionSpring boot introduction
Spring boot introduction
 
Jenkins and Groovy
Jenkins and GroovyJenkins and Groovy
Jenkins and Groovy
 
Webpack: your final module bundler
Webpack: your final module bundlerWebpack: your final module bundler
Webpack: your final module bundler
 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers Steal
 
Meetup Performance
Meetup PerformanceMeetup Performance
Meetup Performance
 
Meetup Performance
Meetup PerformanceMeetup Performance
Meetup Performance
 
Psgi Plack Sfpm
Psgi Plack SfpmPsgi Plack Sfpm
Psgi Plack Sfpm
 
Psgi Plack Sfpm
Psgi Plack SfpmPsgi Plack Sfpm
Psgi Plack Sfpm
 
Plack - LPW 2009
Plack - LPW 2009Plack - LPW 2009
Plack - LPW 2009
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing Up
 
Javascript unit testing, yes we can e big
Javascript unit testing, yes we can   e bigJavascript unit testing, yes we can   e big
Javascript unit testing, yes we can e big
 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradle
 
Dropwizard and Friends
Dropwizard and FriendsDropwizard and Friends
Dropwizard and Friends
 
Introduction to Client Side Dev in SharePoint Workshop
Introduction to Client Side Dev in SharePoint WorkshopIntroduction to Client Side Dev in SharePoint Workshop
Introduction to Client Side Dev in SharePoint Workshop
 
Rails 101
Rails 101Rails 101
Rails 101
 
Single Page JavaScript WebApps... A Gradle Story
Single Page JavaScript WebApps... A Gradle StorySingle Page JavaScript WebApps... A Gradle Story
Single Page JavaScript WebApps... A Gradle Story
 

Dernier

Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Principled Technologies
 

Dernier (20)

Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 

Writing your Third Plugin

  • 1. Getting to Your Third Plugin Justin Ryan jryan@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 Plugin def 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 Object def 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 Plugin pattern = ~/.*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)
  • 15. Groovy Postbuild Plugin if("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 Plugin import groovy.json.JsonSlurper def project = 'Netflix/asgard' def 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/]
  • 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 indicates implementation Most 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 Lifecycle Startup Descriptor() Global Config Descriptor.configure Job Config Descriptor.newInstance
  • 31. Descriptor Lifecycle Startup Descriptor() Call load() on constructor Global Config Descriptor.configure Job Config Descriptor.newInstance
  • 32. Descriptor Lifecycle Startup Descriptor() Call load() on constructor Global Descriptor.configure req.getParam Config Job Config Descriptor.newInstance
  • 33. Descriptor Lifecycle Startup Descriptor() Call load() on constructor Global Descriptor.configure req.getParam Config Job Descriptor.newInstance req.getParam Config
  • 34. Descriptor Lifecycle Startup Descriptor() Call load() on constructor Global Descriptor.configure req.getParam Config Job Descriptor.newInstance req.getParam Config @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 @Override public 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 Locations Plugin Manager Listing src/main/resources/index.jelly Global Config src/main/resources/${package}/${describable}/global.jelly Job Config src/main/resources/${package}/${describable}/config.jelly src/main/resources/${package}/${describable}/help-$ {field}.html Viewing 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]
  • 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 doCreateView when changing Upstream/ Downstream
  • 53. Jenkins Singleton getItem is useful if Ignore you 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 Ignore you 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 Ignore you 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 getPlugin 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]

Notes de l'éditeur

  1. Why are you here?\n\nEither you&amp;#x2019;ve written a plugin and had no idea what you&amp;#x2019;re doing. Or.... Or.... you&amp;#x2019;ve never written a plugin.\n\nI&amp;#x2019;m here to simplify things, make things clear which weren&amp;#x2019;t once before. I&amp;#x2019;m also trying to capture my experiences as a newbie, before I&amp;#x2019;m not one anymore.\n\nI know I&amp;#x2019;m going to have people come up to me afterwards to tell me how easy things are. Well, you all wouldn&apos;t be here if you thought the same thing. Maybe we can mob them afterwards.\n\nI&amp;#x2019;ll be making a lot of references to websites and plugins. There&amp;#x2019;s no need to write them all down in your notepad or go clickety-clack on your keyboard, I&amp;#x2019;ll put the slides up later, with nice hyperlinks. Follow @quidryan to see where post them.\n\nNo easy answer here. I don&apos;t have sage advice, I have war wounds.\n
  2. 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&amp;#x2019;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&amp;#x2019;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&amp;#x2019;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
  3. 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&amp;#x2019;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&amp;#x2019;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&amp;#x2019;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
  4. 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&amp;#x2019;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&amp;#x2019;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&amp;#x2019;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
  5. 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&amp;#x2019;ve heard how Jenkins is made up from Plugins, and there&amp;#x2019;s a friendly community behind them.\n\nSure, we all think if we write a Jenkins plugins we&apos;ll get famous. They&amp;#x2019;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
  6. Wrong!\n\nIn your head is one or two lines which truly represent when you want to accomplish. But you&amp;#x2019;ll realize that writing a plugin is work. There&amp;#x2019;s boilerplate code you have to write. You have to maintain it.\n\n
  7. One direction to go into is one of these three.\n\n
  8. 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&amp;#x2019;s not worth tracking them down. So after a period of time, we just disable the jobs. &amp;#x201C;If a builds get disabled in the Jenkins and no one notices, did really happen?&amp;#x201D; We also limit the number of builds to 20, unless they really want more\n
  9. I&amp;#x2019;ll show code examples, I don&amp;#x2019;t think it&amp;#x2019;s the best use of time to review them line by line.\n\nIn this sample, I&amp;#x2019;m going to each Job, aka Project, and looking at the log from the last build. \n
  10. Displays groovy objects, useful for exploration of Jenkins data model.\n
  11. 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&amp;#x2019;t be shared though. Needs scriptler integration.\n
  12. Examples looks for Sun priprietary APIs.\n
  13. You&amp;#x2019;ll have a hard time telling me this isn&amp;#x2019;t from a plugin.\n
  14. \n
  15. 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
  16. Sample loops through all the branches, creating a job for each one.\n
  17. OK, Fine, you want to write a plugin\n\nYou start with https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial but you&amp;#x2019;ll find nothing for how to code for it. It&amp;#x2019;ll talk just about setting up your environment\nIt&amp;#x2019;ll forward you to Stephen Connolly&apos;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&amp;#x2019;t know what is boilerplate and what should be changed.\nExisting tutorials show how to create a simple plugin. I&amp;#x2019;m taking a orthogonal approach today.\n\n
  18. There&amp;#x2019;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&amp;#x2019;ll be left dazed and confused.\n\nIn our field, you need to ask questions, but sometimes you&amp;#x2019;re so far removed from the problem, that you don&amp;#x2019;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&amp;#x2019;s a few way to slice and dice the models.\n\n
  19. Let&amp;#x2019;s start with what you know. Well, you don&amp;#x2019;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
  20. \n
  21. Think of them attached as your implementations of your plugin. We&amp;#x2019;ll come back to how it&amp;#x2019;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&amp;#x2019;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&amp;#x2019;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&amp;#x2019;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(&quot;useFrench&quot;);\n More complex: req.bindJSONToList(AnsiColorMap.class, req.getSubmittedForm().get(&quot;colorMap&quot;)\n Then always call save()\n\n
  22. Extension points provides answers to the question, &amp;#x201C;are there any implementations for this interface?&amp;#x201D; It then requires a consumer to call Jenkins.getInstance().getExtensionList(Class&lt;T&gt;);\n
  23. Up to consumer how it&amp;#x2019;ll collect the extension points. Each one has it&amp;#x2019;s own rules for how it&amp;#x2019;ll be used.\nStick with basics:\n BuildWrapper\n preCheckout\n setup, after checkout\n BuildStep\n Publisher\n&amp;#x201C;The save operation happens without any notice, and the restore operation happens without calling the constructor, just like Java serialization.&amp;#x201D; \n
  24. http://zombieapocalypseacademy.org/zombie-wallpapers/\n\nFirst, let&amp;#x2019;s talk about what is a HPI\nIt&amp;#x2019;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
  25. It&amp;#x2019;s an HPI. Really, it has no other meaning, there is no Plugin class that gets implemented.\n\n
  26. \n
  27. \n
  28. 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
  29. Let&amp;#x2019;s start talking about how they&amp;#x2019;re loaded, I&amp;#x2019;m going to skim over UI pieces\n\n* Startup - Loads HPI, Finds Extensions, Instantiates Descriptions\n* Global Config\nLoads &amp;#x201C;src/main/resources/${plugin-package}/${plugin-class-name}/global.jelly&amp;#x201D;\nsave calls configure(StaplerRequest req, JSONObject json)\n* Job Config\nLoads &amp;#x201C;src/main/resources/${plugin-package}/${plugin-class-name}/config.jelly&amp;#x201D;\n(Loading values via XSTREAM, then applying via Jelly)\n
  30. Let&amp;#x2019;s start talking about how they&amp;#x2019;re loaded, I&amp;#x2019;m going to skim over UI pieces\n\n* Startup - Loads HPI, Finds Extensions, Instantiates Descriptions\n* Global Config\nLoads &amp;#x201C;src/main/resources/${plugin-package}/${plugin-class-name}/global.jelly&amp;#x201D;\nsave calls configure(StaplerRequest req, JSONObject json)\n* Job Config\nLoads &amp;#x201C;src/main/resources/${plugin-package}/${plugin-class-name}/config.jelly&amp;#x201D;\n(Loading values via XSTREAM, then applying via Jelly)\n
  31. Let&amp;#x2019;s start talking about how they&amp;#x2019;re loaded, I&amp;#x2019;m going to skim over UI pieces\n\n* Startup - Loads HPI, Finds Extensions, Instantiates Descriptions\n* Global Config\nLoads &amp;#x201C;src/main/resources/${plugin-package}/${plugin-class-name}/global.jelly&amp;#x201D;\nsave calls configure(StaplerRequest req, JSONObject json)\n* Job Config\nLoads &amp;#x201C;src/main/resources/${plugin-package}/${plugin-class-name}/config.jelly&amp;#x201D;\n(Loading values via XSTREAM, then applying via Jelly)\n
  32. Let&amp;#x2019;s start talking about how they&amp;#x2019;re loaded, I&amp;#x2019;m going to skim over UI pieces\n\n* Startup - Loads HPI, Finds Extensions, Instantiates Descriptions\n* Global Config\nLoads &amp;#x201C;src/main/resources/${plugin-package}/${plugin-class-name}/global.jelly&amp;#x201D;\nsave calls configure(StaplerRequest req, JSONObject json)\n* Job Config\nLoads &amp;#x201C;src/main/resources/${plugin-package}/${plugin-class-name}/config.jelly&amp;#x201D;\n(Loading values via XSTREAM, then applying via Jelly)\n
  33. I don&amp;#x2019;t think it&amp;#x2019;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
  34. From hudson.scm.SubversionSCM\n\nCame from this:\n&lt;j:jelly xmlns:j=&quot;jelly:core&quot; xmlns:st=&quot;jelly:stapler&quot; xmlns:d=&quot;jelly:define&quot; xmlns:l=&quot;/lib/layout&quot; xmlns:t=&quot;/lib/hudson&quot; xmlns:f=&quot;/lib/form&quot;&gt;\n &lt;f:section title=&quot;${%Subversion}&quot;&gt;\n &lt;f:entry title=&quot;${%Subversion Workspace Version}&quot; help=&quot;/descriptor/hudson.scm.SubversionSCM/help/workspaceFormat&quot;&gt;\n &lt;select name=&quot;svn.workspaceFormat&quot;&gt;\n &lt;f:option value=&quot;8&quot; selected=&quot;${descriptor.workspaceFormat==8}&quot; &gt;1.4&lt;/f:option&gt;\n &lt;f:option value=&quot;9&quot; selected=&quot;${descriptor.workspaceFormat==9}&quot; &gt;1.5&lt;/f:option&gt;\n &lt;f:option value=&quot;10&quot; selected=&quot;${descriptor.workspaceFormat==10}&quot;&gt;1.6 (svn:externals to file)&lt;/f:option&gt;\n &lt;/select&gt;\n &lt;/f:entry&gt;\n &lt;f:entry title=&quot;${%Exclusion revprop name}&quot; help=&quot;/descriptor/hudson.scm.SubversionSCM/help/excludedRevprop&quot;&gt;\n &lt;f:textbox name=&quot;svn.global_excluded_revprop&quot; value=&quot;${descriptor.globalExcludedRevprop}&quot;/&gt;\n &lt;/f:entry&gt;\n &lt;f:optionalBlock\n name=&quot;svn.validateRemoteUpToVar&quot;\n checked=&quot;${descriptor.validateRemoteUpToVar}&quot;\n title=&quot;${%Validate repository URLs up to the first variable name}&quot;\n help=&quot;/descriptor/hudson.scm.SubversionSCM/help/validateRemoteUpToVar&quot;/&gt;\n &lt;f:optionalBlock\n name=&quot;svn.storeAuthToDisk&quot;\n checked=&quot;${descriptor.storeAuthToDisk}&quot;\n title=&quot;${%Update default Subversion credentials cache after successful authentication}&quot;/&gt;\n &lt;/f:section&gt;\n&lt;/j:jelly&gt;\n
  35. \n
  36. \nCan write in Groovy, which is a facade over jelly. But it&apos;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
  37. \nCan write in Groovy, which is a facade over jelly. But it&apos;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
  38. \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&lt;f:section title=&quot;Environment Selector Set-up&quot;&gt;\nEntry\nDoes magic with doCheck, and binding help-*.html foo, auto population, \nExcept for boolean/checkboxes\n&lt;f:entry title=&quot;${%Environment}&quot;&gt;\nTextbox\nShouldn&amp;#x2019;t need name and value, if wrapped in entry\n&lt;f:textbox name=&quot;env.envName&quot; value=&quot;${env.envName}&quot;/&gt;\nRuby doesn&amp;#x2019;t have it much better:\nhttps://github.com/rtyler/vagrant-plugin/blob/master/views/vagrant/sudo_builder/config.erb\n\n
  39. Simplified because anything Describable can have a view\n
  40. \nDocumentation is typically poor, so just install them. It&apos;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&amp;#x2019;t use static analysis plugins and Job Property Plugin\n\n
  41. 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&amp;#x2019;s hard to know what is new/old/modern.\n
  42. This graph represents just the middle. The bar isn&amp;#x2019;t that high though. SBT is a major build tool, and it&amp;#x2019;s at 310. Then again, there&amp;#x2019;s a emma plugin which mis-spells column and a plugin that just shows Bruce Scheneier is here. But at the same time there&amp;#x2019;s plugins which serve a small community, that doesn&amp;#x2019;t make it old or worthless.\n
  43. 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. &quot;Full Name&quot; is the join of &apos;/&apos;.\nKeep in mind that properties of Item as you work with objects, because it won&amp;#x2019;t be obvious. E.g. ItemListener for things like onLoad()\nSpecial type of item: TopLevelItem\n\n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. 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
  53. 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&amp;#x2019;s you ship code to slave to run.\n&amp;#x201C;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.&amp;#x201D;\nYou get one from something like boolean perform(AbstractBuild&lt;?,?&gt; build, Launcher launcher, BuildListener listener)\n\n
  54. \n
  55. There&apos;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&amp;#x2019;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
  56. I&amp;#x2019;d like to thank our sponsors. Having a conference like this is really important to the community.\n
  57. \n