├── .gitignore ├── README.md ├── img └── how-it-works.png ├── pom.xml ├── step-01-basic ├── HOW-IT-WORKS.md ├── README.md ├── img │ ├── root-action-page.png │ └── root-action.png ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── jenkinsci │ │ └── ui │ │ └── samples │ │ └── JSLibSample.java │ └── resources │ ├── index.jelly │ └── org │ └── jenkinsci │ └── ui │ └── samples │ └── JSLibSample │ └── index.jelly ├── step-02-nodeify ├── HOW-IT-WORKS.md ├── README.md ├── gulpfile.js ├── img │ └── root-action-page.png ├── package.json ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── jenkinsci │ │ └── ui │ │ └── samples │ │ └── JSLibSample.java │ ├── js │ └── jslib-samples.js │ └── resources │ ├── index.jelly │ └── org │ └── jenkinsci │ └── ui │ └── samples │ └── JSLibSample │ └── index.jelly ├── step-03-more-npm-packs ├── .gitignore ├── HOW-IT-WORKS.md ├── README.md ├── gulpfile.js ├── img │ └── root-action-page.png ├── package.json ├── pom.xml └── src │ └── main │ ├── css │ └── bootstrap336 │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap-theme.min.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ └── bootstrap.min.css.map │ ├── java │ └── org │ │ └── jenkinsci │ │ └── ui │ │ └── samples │ │ └── JSLibSample.java │ ├── js │ └── jslib-samples.js │ └── resources │ ├── index.jelly │ └── org │ └── jenkinsci │ └── ui │ └── samples │ └── JSLibSample │ └── index.jelly ├── step-04-externalize-libs ├── HOW-IT-WORKS.md ├── README.md ├── gulpfile.js ├── img │ └── browser-loading.png ├── package.json ├── pom.xml └── src │ └── main │ ├── css │ └── bootstrap336 │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap-theme.min.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ └── bootstrap.min.css.map │ ├── java │ └── org │ │ └── jenkinsci │ │ └── ui │ │ └── samples │ │ └── JSLibSample.java │ ├── js │ └── jslib-samples.js │ └── resources │ ├── index.jelly │ └── org │ └── jenkinsci │ └── ui │ └── samples │ └── JSLibSample │ └── index.jelly ├── step-05-namespaced-css ├── HOW-IT-WORKS.md ├── README.md ├── gulpfile.js ├── package.json ├── pom.xml └── src │ └── main │ ├── css │ └── bootstrap336 │ │ ├── bootstrap-ns3.less │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap-theme.min.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ └── bootstrap.min.css.map │ ├── java │ └── org │ │ └── jenkinsci │ │ └── ui │ │ └── samples │ │ └── JSLibSample.java │ ├── js │ └── jslib-samples.js │ └── resources │ ├── index.jelly │ └── org │ └── jenkinsci │ └── ui │ └── samples │ └── JSLibSample │ └── index.jelly ├── step-06-handlebars-templates ├── HOW-IT-WORKS.md ├── README.md ├── gulpfile.js ├── package.json ├── pom.xml └── src │ └── main │ ├── css │ └── bootstrap336 │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap-theme.min.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ └── bootstrap.min.css.map │ ├── java │ └── org │ │ └── jenkinsci │ │ └── ui │ │ └── samples │ │ └── JSLibSample.java │ ├── js │ ├── jslib-samples.js │ └── templates │ │ └── form.hbs │ └── resources │ ├── index.jelly │ └── org │ └── jenkinsci │ └── ui │ └── samples │ └── JSLibSample │ └── index.jelly ├── step-07-jsdom-tests ├── README.md ├── gulpfile.js ├── img │ └── root-action-page.png ├── package.json ├── pom.xml └── src │ ├── main │ ├── css │ │ └── bootstrap336 │ │ │ ├── bootstrap-theme.css │ │ │ ├── bootstrap-theme.css.map │ │ │ ├── bootstrap-theme.min.css │ │ │ ├── bootstrap-theme.min.css.map │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ └── bootstrap.min.css.map │ ├── java │ │ └── org │ │ │ └── jenkinsci │ │ │ └── ui │ │ │ └── samples │ │ │ └── JSLibSample.java │ ├── js │ │ ├── jslib-samples.js │ │ └── templates │ │ │ └── form.hbs │ └── resources │ │ ├── index.jelly │ │ └── org │ │ └── jenkinsci │ │ └── ui │ │ └── samples │ │ └── JSLibSample │ │ └── index.jelly │ └── test │ └── js │ └── jslib-samples-spec.js └── step-08-zombie-tests ├── README.md ├── gulpfile.js ├── img └── root-action-page.png ├── package.json ├── pom.xml └── src ├── main ├── css │ └── bootstrap336 │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap-theme.min.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ ├── bootstrap.min.css.map │ │ └── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 ├── java │ └── org │ │ └── jenkinsci │ │ └── ui │ │ └── samples │ │ └── JSLibSample.java ├── js │ ├── jslib-samples.js │ └── templates │ │ └── form.hbs └── resources │ ├── index.jelly │ └── org │ └── jenkinsci │ └── ui │ └── samples │ └── JSLibSample │ └── index.jelly └── test └── js ├── jslib-samples-spec.js └── testpage.html /.gitignore: -------------------------------------------------------------------------------- 1 | # IntelliJ project files 2 | *.iml 3 | *.ipr 4 | *.iws 5 | .idea/ 6 | 7 | # Jenkins 8 | work/ 9 | 10 | # Node 11 | node/ 12 | node_modules/ 13 | npm-debug.log 14 | 15 | # Ignore generated bundles 16 | **/webapp/jsbundles/* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ❗ This repository is unmaintained and end of life! 2 |

3 | The samples do no longer comply with the standards and requirements in Jenkins.
4 | If you are looking for up-to-date samples and documentation how to use JS in plugins, please consult the Jenkins documentation. 5 |

6 | 7 | # jenkins-js Sample Plugins 8 | 9 | This repository provides some sample Jenkins Plugins, showing how to use [jenkins-js-builder] to build 10 | Jenkins plugins that support a richer UI through the use of Modularized JavaScript. 11 | 12 | 13 | ## Step-by-step Plugins 14 | 15 | The repository contains step-by-step example plugins, starting with step-01-basic, 16 | which is just a simple Jenkins plugin that contains no JavaScript at all, working up through steps 02 and 03 etc, 17 | incrementally adding more JavaScript "features". 18 | 19 | | Name | Description | 20 | | :-----| :------------| 21 | | step-01-basic | A very basic Jenkins plugin with no JavaScript. 22 | | step-02-nodeify | Update step-01-basic to add a very simple jQuery based JavaScript App bundle (jQuery bundled).| 23 | | step-03-more-npm-packs | Update step-02-nodeify to use Twitter Bootstrap instead of jQuery and to also use Moment.js (Bootstrap and Moment.js bundled). | 24 | | step-04-externalize-libs | Update step-03-more-npm-packs to slim down the the App bundle by externalizing Bootstrap and Moment.js (Bootstrap and Moment.js NOT bundled). | 25 | | step-05-namespaced-css | Update step-04-externalize-libs to use bootstrap's default namespaced CSS. | 26 | | step-06-handlebars-templates | Update step-04-externalize-libs to use Handlebars Templates. | 27 | | step-07-jsdom-tests | How to add unit tests using [jsdom] and [Jasmine]. | 28 | | step-08-zombie-tests | How to add integration tests using [Zombie] and [Jasmine]. | 29 | 30 | [jenkins-js-modules]: https://github.com/jenkinsci/js-modules 31 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder 32 | [jenkins-js-libs]: https://github.com/jenkinsci/js-libs 33 | [jenkins-js-test]: https://github.com/jenkinsci/js-test 34 | [Jasmine]: http://jasmine.github.io/ 35 | [jsdom]: https://github.com/tmpvar/jsdom 36 | [Zombie]: http://zombie.js.org/ 37 | -------------------------------------------------------------------------------- /img/how-it-works.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/js-samples/a641067df2da59ff3f210c266d1a0c3c1127bdc1/img/how-it-works.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.jenkins-ci.plugins 8 | plugin 9 | 2.6 10 | 11 | 12 | 13 | org.jenkins-ci.ui.samples 14 | jenkins-js-samples 15 | 1.0-SNAPSHOT 16 | pom 17 | 18 | JS Lib Samples: Parent POM 19 | 20 | 21 | 1.639 22 | 1.106 23 | 27 | 6.8.1 28 | 3.10.9 29 | 30 | 31 | 32 | step-01-basic 33 | step-02-nodeify 34 | step-03-more-npm-packs 35 | step-04-externalize-libs 36 | step-05-namespaced-css 37 | step-06-handlebars-templates 38 | step-07-jsdom-tests 39 | step-08-zombie-tests 40 | 41 | 42 | 43 | 44 | MIT License 45 | http://opensource.org/licenses/MIT 46 | 47 | 48 | 49 | 50 | 51 | repo.jenkins-ci.org 52 | http://repo.jenkins-ci.org/public/ 53 | 54 | 55 | 56 | 57 | repo.jenkins-ci.org 58 | http://repo.jenkins-ci.org/public/ 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /step-01-basic/HOW-IT-WORKS.md: -------------------------------------------------------------------------------- 1 | # Step 01 - A "basic" Plugin - How it Works 2 | Creating a basic Jenkins plugin is already well covered in the [Plugin Tutorial] on the wiki. 3 | 4 | There's really nothing much to this first Jenkins plugin in this repo. It's just a standard Jenkins plugin with 5 | nothing extra. It acts as the foundation for the other sample plugins in this repository. 6 | 7 | This plugin ("step-01-basic") just adds a standard Jenkins "root action" page that contains 8 | a simple form. 9 | 10 | On running the plugin (`mvn hpi:run`), you will see the following screens. 11 | 12 | ![root action](img/root-action.png) 13 | ![root action page](img/root-action-page.png) 14 | 15 | At this point, we are ready to "nodeify" the plugin by adding some [CommonJS] JavaScript modules. 16 | 17 |
18 |

19 | >> NEXT (step-02-nodeify) >> 20 |

21 | 22 | [Plugin Tutorial]: https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial 23 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder 24 | [CommonJS]: http://www.commonjs.org/ 25 | -------------------------------------------------------------------------------- /step-01-basic/README.md: -------------------------------------------------------------------------------- 1 | # Step 01 - A "basic" Plugin 2 | A basic Jenkins plugin with just a standard Jenkins "root action" page that contains 3 | a simple form. This plugin is the foundation for all other sample plugins in this repo. 4 | 5 |

6 |

    7 |
  1. How to run
    8 |
  2. How it works
    9 |
10 |

11 | 12 | ## How to run 13 | The easiest way to run this Jenkins plugin is to [use the standard Maven HPI plugin for Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin). 14 | 15 | ```sh 16 | $ mvn hpi:run 17 | ``` 18 | 19 | On running the plugin, you will see the following screens. 20 | 21 | ![root action](img/root-action.png) 22 | ![root action page](img/root-action-page.png) 23 | 24 | ## How it works 25 | 26 | 27 | 28 |
29 |

30 | >> NEXT (step-02-nodeify) >> 31 |

32 | 33 | [Plugin Tutorial]: https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial 34 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder 35 | [CommonJS]: http://www.commonjs.org/ 36 | -------------------------------------------------------------------------------- /step-01-basic/img/root-action-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/js-samples/a641067df2da59ff3f210c266d1a0c3c1127bdc1/step-01-basic/img/root-action-page.png -------------------------------------------------------------------------------- /step-01-basic/img/root-action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/js-samples/a641067df2da59ff3f210c266d1a0c3c1127bdc1/step-01-basic/img/root-action.png -------------------------------------------------------------------------------- /step-01-basic/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.jenkins-ci.ui.samples 8 | jenkins-js-samples 9 | 1.0-SNAPSHOT 10 | ../ 11 | 12 | step-01-basic 13 | 1.0 14 | hpi 15 | 16 | JS Lib Samples: Step 1 - Basic 17 | 18 | 19 | -------------------------------------------------------------------------------- /step-01-basic/src/main/java/org/jenkinsci/ui/samples/JSLibSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2015, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.ui.samples; 25 | 26 | import hudson.Extension; 27 | import hudson.model.RootAction; 28 | 29 | /** 30 | * @author tom.fennelly@gmail.com 31 | */ 32 | @Extension 33 | public class JSLibSample implements RootAction { 34 | 35 | public String getIconFileName() { 36 | return "green.png"; 37 | } 38 | 39 | public String getDisplayName() { 40 | return "JSLib Sample"; 41 | } 42 | 43 | public String getUrlName() { 44 | return "/js-sample"; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /step-01-basic/src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | JavaScript GUI Lib Sample. 4 |
5 | -------------------------------------------------------------------------------- /step-01-basic/src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 |

Jenkins JS Samples

30 |
31 |
32 | 33 | 34 |
35 |
36 | 37 | 38 |
39 |
40 | 43 |
44 | 45 |
46 |
47 |
48 |
49 | -------------------------------------------------------------------------------- /step-02-nodeify/HOW-IT-WORKS.md: -------------------------------------------------------------------------------- 1 | # Step 02 - Add CommonJS modules ("nodeify") - How it works 2 | The plugin in this step (`step-02-nodeify`) builds on top of step-01-basic, 3 | adding some [CommonJS] modules. We use [jenkins-js-builder] and some other [Node.js] 4 | tools to build a self contained browser-ready JavaScript "[bundle]" that can be loaded through your Jenkins `.jelly` files 5 | (or whatever mechanism works for your plugin). 6 | 7 | There are a few simple steps to adding [CommonJS] modules to your plugin. 8 | 9 |

10 |

    11 |
  1. Install Node.js and Gulp
    12 |
  2. Add `package.json`
    13 |
  3. Add initial NPM packages
    14 |
  4. Add first CommonJS module
    15 |
  5. Add `gulpfile.js`
    16 |
  6. Build the JavaScript bundle for the Browser
    17 |
  7. Add the JavaScript bundle to the .jelly page
    18 |
  8. Test run
    19 |
  9. Integrate Gulp and Maven builds
    20 |
21 |

22 | 23 | ## Install Node.js and Gulp 24 | On your dev machine, install [Node.js] v4.0.0+. 25 | 26 | You'll also need to globally install [Gulp]. 27 | 28 | ```sh 29 | $ npm install --global gulp 30 | ``` 31 | 32 | > __NOTE__ that [Node.js] and [Gulp] only needs to be installed on Dev machines so as to allow the running of node/npm/gulp etc commands while developing the plugin. A simple check out and build of your plugin (using maven) will NOT require [Node.js] to be installed on the build machine. The maven build will take care of everything. 33 | 34 | ## Add `package.json` 35 | Add a `package.json` file to the root of your plugin using the [`npm init`](https://docs.npmjs.com/cli/init) command. 36 | 37 | ```sh 38 | $ npm init 39 | This utility will walk you through creating a package.json file. 40 | It only covers the most common items, and tries to guess sensible defaults. 41 | 42 | See 'npm help json' for definitive documentation on these fields 43 | and exactly what they do. 44 | 45 | Use 'npm install --save' afterwards to install a package and 46 | save it as a dependency in the package.json file. 47 | 48 | Press ^C at any time to quit. 49 | name: (step-02-nodeify) 50 | ``` 51 | 52 | ## Add initial NPM packages 53 | Install the minimum set of NPM packages required for your plugin to build ([gulp](https://github.com/gulpjs/gulp), [jenkins-js-builder] and [jenkins-js-modules]). 54 | 55 | ```sh 56 | $ npm install --save-dev gulp @jenkins-cd/js-builder 57 | $ npm install --save @jenkins-cd/js-modules 58 | ``` 59 | 60 | Let's also install the jquery package. 61 | 62 | ```sh 63 | $ npm install --save jquery 64 | ``` 65 | 66 | ## Add first CommonJS module 67 | Create `src/main/js/jslib-samples.js` and add the following JavaScript code: 68 | 69 | ```javascript 70 | var $ = require('jquery'); 71 | 72 | $(document).ready(function () { 73 | $('#side-panel').remove(); 74 | $('#main-panel').css('margin-left', '0px'); 75 | }); 76 | ``` 77 | 78 | This silly little [CommonJS] module will just use jQuery to remove the left side-panel. Of 79 | course we could add more [CommonJS] modules in `src/main/js` and use them in our App. 80 | 81 | ## Add `gulpfile.js` 82 | Add a `gulpfile.js` file to the root of your plugin. 83 | 84 | `gulpfile.js` will not contain a lot of code. Most of the work is done by [jenkins-js-builder]. 85 | 86 | ```javascript 87 | var builder = require('@jenkins-cd/js-builder'); 88 | 89 | // 90 | // Bundle the modules. 91 | // See https://github.com/jenkinsci/js-builder 92 | // 93 | builder.bundle('src/main/js/jslib-samples.js'); 94 | ``` 95 | 96 | The `builder.bundle` command is asking [jenkins-js-builder] to create a [bundle] (using [Browserify]) starting from 97 | `src/main/js/jslib-samples.js`, and to output the generated [bundle] file to the `target/classes` folder, allowing the 98 | `.js` bundle to be loaded as an adjunct. The generated [bundle] file will be totally self contained (containing a private 99 | copy of jQuery and anything else used by the App) and loadable in a browser. 100 | 101 | ## Build the JavaScript bundle for the Browser 102 | To build the [bundle], simple run: 103 | 104 | ```sh 105 | $ gulp 106 | ``` 107 | 108 | You should see output like the following: 109 | 110 | ```sh 111 | $ gulp 112 | [11:07:27] ********************************************************************** 113 | [11:07:27] This build is using Jenkins JS Builder. 114 | [11:07:27] For command line options and other help, go to 115 | [11:07:27] https://www.npmjs.com/package/@jenkins-cd/js-builder 116 | [11:07:27] ********************************************************************** 117 | [11:07:27] Maven project. 118 | [11:07:27] - Jenkins plugin (HPI): step-02-nodeify 119 | [11:07:27] Language level set to ECMA v5. Call builder.lang([number]) to change. 120 | [11:07:27] Defining default tasks... 121 | [11:07:27] Using gulpfile ~/projects/jenkins-plugins/jenkins-js-samples/step-02-nodeify/gulpfile.js 122 | [11:07:27] Starting 'lint'... 123 | [11:07:28] - Using the "es5" eslint configuration from eslint-config-jenkins. Override by defining a .eslintrc in this folder (if you really must). 124 | [11:07:28] Finished 'lint' after 549 ms 125 | [11:07:28] Starting 'log-env'... 126 | [11:07:28] Source Dirs: 127 | [11:07:28] - src: src/main/js,src/main/less 128 | [11:07:28] - test: src/test/js 129 | [11:07:28] Finished 'log-env' after 599 μs 130 | [11:07:28] Starting 'bundle_jslib-samples'... 131 | [11:07:28] Javascript bundle "jslib-samples" will be available in Jenkins as adjunct "org.jenkins.ui.jsmodules.step_02_nodeify.jslib-samples". 132 | [11:07:29] Finished 'bundle_jslib-samples' after 1.53 s 133 | [11:07:29] Starting 'bundle'... 134 | [11:07:29] bundling: done 135 | [11:07:29] Finished 'bundle' after 207 μs 136 | [11:07:29] Starting 'test'... 137 | [11:07:29] Test specs: src/test/js/**/*-spec.js 138 | [11:07:29] Testing web server started on port 18999 (http://localhost:18999). Content root: /Users/tfennelly/projects/jenkins-plugins/jenkins-js-samples/step-02-nodeify 139 | [11:07:29] Finished 'test' after 54 ms 140 | [11:07:29] Starting 'default'... 141 | [11:07:29] Finished 'default' after 3.77 μs 142 | SUCCESS: 0 specs, 0 failures, 0 skipped, 0 disabled in 0.001s. 143 | [11:07:30] Testing web server stopped. 144 | ``` 145 | 146 | The part of the build output that's of most interest to us here is: 147 | 148 | ```sh 149 | [11:07:28] Javascript bundle "jslib-samples" will be available 150 | in Jenkins as adjunct "org.jenkins.ui.jsmodules.step_02_nodeify.jslib-samples". 151 | ``` 152 | 153 | This tells us where the generated `.js` [bundle] can be loaded from as a Jenkins adjunct i.e. `org.jenkins.ui.jsmodules.step_02_nodeify.jslib-samples`. 154 | We will use this information in the next section. 155 | 156 | ## Add the JavaScript bundle to the .jelly page 157 | Using the information from the previous section, it's easy to determine how to load the [bundle] in Jenkins via the 158 | `.jelly` file. In this example we will use a Jenkins adjunt, adding it to 159 | [JSLibSample/index.jelly](src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly). 160 | 161 | ```html 162 | 163 | ``` 164 | 165 | > Note: The `org.jenkins.ui.jsmodules.step_02_nodeify.jslib-samples` adjunct identifier translates to an adjunct URL of the form `http://localhost:8080//org/jenkins/ui/jsmodules/step_02_nodeify/jslib-samples.js`. 166 | > The `` prefix is typically something like `jenkins/adjuncts/1cc49125`. In JavaScript code, it can typically be accessed using the `getAdjunctURL()` method of the `@jenkins-cd/js-modules` package. 167 | 168 | ## Test run 169 | At this stage, you should be able to take `step-02-nodeify` for a test run and see how the Modularized JavaScript 170 | behaves. You can do this by simply [running the plugin using the HPI plugin](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin). 171 | 172 | ![root action page](img/root-action-page.png) 173 | 174 | As you can see, the [bundle] ran fine and used jQuery (contained in the [bundle]) to remove the left side-panel. 175 | 176 | ## Integrate Gulp and Maven builds 177 | You will want to run the `gulp` build (to generate the [bundle]) as part of your plugin's Maven build. For that reason, 178 | the `gulp` build needs to be integrated into the `mvn` build lifecycle. 179 | 180 | If your plugin's parent POM is `org.jenkins-ci.plugins:plugins:1.639` or newer, no action is required. If your 181 | plugin depends on an older parent POM, then you will need to add the maven ``s referred to in the 182 | [sample_extract_pom.xml](https://github.com/jenkinsci/js-builder/blob/master/res/sample_extract_pom.xml) in 183 | [Maven Integration](https://github.com/jenkinsci/js-builder#maven-integration) section of the [jenkins-js-builder] docs. 184 | 185 |
186 |

187 | << PREV (step-01-basic) <<             >> NEXT (step-03-more-npm-packs) >> 188 |

189 | 190 | [Node.js]: https://nodejs.org 191 | [Gulp]: https://github.com/gulpjs/gulp 192 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder 193 | [jenkins-js-modules]: https://github.com/jenkinsci/js-modules 194 | [CommonJS]: http://www.commonjs.org/ 195 | [jquery-detached]: https://github.com/tfennelly/jquery-detached 196 | [Browserify]: http://browserify.org/ 197 | [bundle]: https://github.com/jenkinsci/js-modules/blob/master/FAQs.md#what-is-the-difference-between-a-module-and-a-bundle 198 | -------------------------------------------------------------------------------- /step-02-nodeify/README.md: -------------------------------------------------------------------------------- 1 | # Step 02 - Add CommonJS modules ("nodeify") 2 | The plugin in this step (`step-02-nodeify`) builds on top of step-01-basic, 3 | adding some [CommonJS] modules. 4 | 5 |

6 |

    7 |
  1. How to run
    8 |
  2. How it works
    9 |
10 |

11 | 12 | ## How to run 13 | The easiest way to run this Jenkins plugin is to [use the standard Maven HPI plugin for Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin). 14 | 15 | ```sh 16 | $ mvn hpi:run 17 | ``` 18 | 19 | On running the plugin, you will see the following screen. Nothing much has visually changed from 20 | step-01-basic, apart from the fact that some Modularized 21 | JavaScript has run (see how it works) which removed the left side-panel. 22 | 23 | ![root action page](img/root-action-page.png) 24 | 25 | ## How it works 26 | 27 | 28 | 29 |
30 |

31 | << PREV (step-01-basic) <<             >> NEXT (step-03-more-npm-packs) >> 32 |

33 | 34 | [Node.js]: https://nodejs.org 35 | [Gulp]: https://github.com/gulpjs/gulp 36 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder 37 | [jenkins-js-modules]: https://github.com/jenkinsci/js-modules 38 | [CommonJS]: http://www.commonjs.org/ 39 | [jquery-detached]: https://github.com/tfennelly/jquery-detached 40 | [Browserify]: http://browserify.org/ 41 | [bundle]: https://github.com/jenkinsci/js-modules/blob/master/FAQs.md#what-is-the-difference-between-a-module-and-a-bundle 42 | -------------------------------------------------------------------------------- /step-02-nodeify/gulpfile.js: -------------------------------------------------------------------------------- 1 | var builder = require('@jenkins-cd/js-builder'); 2 | 3 | // 4 | // Bundle the modules. 5 | // See https://github.com/jenkinsci/js-builder 6 | // 7 | builder.bundle('src/main/js/jslib-samples.js'); 8 | -------------------------------------------------------------------------------- /step-02-nodeify/img/root-action-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/js-samples/a641067df2da59ff3f210c266d1a0c3c1127bdc1/step-02-nodeify/img/root-action-page.png -------------------------------------------------------------------------------- /step-02-nodeify/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "step-02-nodeify", 3 | "version": "1.0.0", 4 | "description": "step-02-nodeify", 5 | "license": "MIT", 6 | "devDependencies": { 7 | "gulp": "^3.9.0", 8 | "@jenkins-cd/js-builder": "latest" 9 | }, 10 | "dependencies": { 11 | "@jenkins-cd/js-modules": "latest", 12 | "jquery": "^2.2.3", 13 | "jquery-detached": "^2.1.4-v2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /step-02-nodeify/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.jenkins-ci.ui.samples 8 | jenkins-js-samples 9 | 1.0-SNAPSHOT 10 | ../ 11 | 12 | step-02-nodeify 13 | 1.0 14 | hpi 15 | 16 | JS Lib Samples: Step 2 - Nodeify 17 | A sample that adds the basic node/npm hooks 18 | 19 | 20 | -------------------------------------------------------------------------------- /step-02-nodeify/src/main/java/org/jenkinsci/ui/samples/JSLibSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2015, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.ui.samples; 25 | 26 | import hudson.Extension; 27 | import hudson.model.RootAction; 28 | 29 | /** 30 | * @author tom.fennelly@gmail.com 31 | */ 32 | @Extension 33 | public class JSLibSample implements RootAction { 34 | 35 | public String getIconFileName() { 36 | return "green.png"; 37 | } 38 | 39 | public String getDisplayName() { 40 | return "JSLib Sample"; 41 | } 42 | 43 | public String getUrlName() { 44 | return "/js-sample"; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /step-02-nodeify/src/main/js/jslib-samples.js: -------------------------------------------------------------------------------- 1 | var $ = require('jquery'); 2 | 3 | $(document).ready(function start() { 4 | $('#side-panel').remove(); 5 | $('#main-panel').css('margin-left', '0px'); 6 | }); 7 | -------------------------------------------------------------------------------- /step-02-nodeify/src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | JavaScript GUI Lib Sample. 4 |
5 | -------------------------------------------------------------------------------- /step-02-nodeify/src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 |

Jenkins JS Samples

30 |
31 |
32 | 33 | 34 |
35 |
36 | 37 | 38 |
39 |
40 | 43 |
44 | 45 |
46 |
47 |
48 | 49 | 53 | 54 |
55 | -------------------------------------------------------------------------------- /step-03-more-npm-packs/.gitignore: -------------------------------------------------------------------------------- 1 | target -------------------------------------------------------------------------------- /step-03-more-npm-packs/HOW-IT-WORKS.md: -------------------------------------------------------------------------------- 1 | # Step 03 - Use more NPM packages i.e. Twitter Bootstrap and Moment.js - How it works 2 | `step-03-more-npm-packs` builds on step-02-nodeify, adding a few more 3 | NPM packages to the mix, namely Twitter Bootstrap (via [bootstrap-detached]) 4 | and Moment.js. This is one of the major benefits of using [CommonJS] style packages; it means we can easily utilise 5 | the huge number of JavaScript packages available in the NPM registry. 6 | 7 | ## Install/Uninstall NPM packages 8 | Install [bootstrap-detached] and Moment.js: 9 | 10 | ```sh 11 | $ npm install --save bootstrap-detached moment 12 | ``` 13 | 14 | Since we are using [bootstrap-detached], we can uninstall jquery because [bootstrap-detached] 15 | is `jquery + bootstrap`: 16 | 17 | ```sh 18 | $ npm uninstall --save jquery 19 | ``` 20 | 21 | > Note: [bootstrap-detached] is easier to use because it contains it's own "detached" instance of jquery ([jquery-detached]). 22 | 23 | ## Update `.js` 24 | The changes to the `src/main/js/jslib-samples.js` are very trivial. 25 | 26 | ```diff 27 | -var $ = require('jquery'); 28 | +// Change from 'jquery' to 'bootstrap-detached' 29 | +var $ = require('bootstrap-detached').getBootstrap(); 30 | 31 | $(document).ready(function () { 32 | $('#side-panel').remove(); 33 | $('#main-panel').css('margin-left', '0px'); 34 | + 35 | + // Add some code to use momentjs, adding formatted time text to the page. 36 | + // See src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly. 37 | + var moment = require('moment'); 38 | + $('#main-panel .time').text(moment().format("MMM Do YY")); 39 | }); 40 | ``` 41 | 42 | ## Bundle Bootstrap CSS 43 | 44 | The fact that we're using Bootstrap means that we need to add bootstrap's CSS to the plugin. After [downloading the 45 | bootstrap distro](http://getbootstrap.com/getting-started/), the CSS was added in 46 | [src/main/css/bootstrap336](src/main/css/bootstrap336). We want to bundle this CSS (and all related 47 | resources - fonts etc) in our plugin and to do that, we simply add another `bundle` 48 | command to the [gulpfile.js](gulpfile.js) as follows: 49 | 50 | ```javascript 51 | builder.bundle('src/main/css/bootstrap336/bootstrap.css'); 52 | ``` 53 | 54 | This bundling command will bundle everything under `src/main/css/bootstrap336` into the plugin as adjuncts. The 55 | adjunct identifier is output to the console by the build (just as described with the `.js` bundle adjunct 56 | in step-02-nodeify). 57 | 58 | ```sh 59 | [12:33:57] CSS resource "src/main/css/bootstrap336/bootstrap.css" will be available 60 | in Jenkins as adjunct "org.jenkins.ui.jsmodules.bootstrap336.bootstrap". 61 | ``` 62 | 63 | > Note: You can also specify a [LESS](http://lesscss.org/) file here and it will be pre-processed and bundled into the Jenkins plugin. 64 | 65 | The changes to [JSLibSample/index.jelly](src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly) were trivial 66 | i.e. just add the adjunct: 67 | 68 | ```html 69 | 70 | ``` 71 | 72 | > Note: Of course you can also just place the CSS resources somewhere in `src/main/resources` and they will get bundled 73 | > in the plugin classpath. The benefit of doing it as outlined above is that it makes dealing with [LESS](http://lesscss.org/) a bit easier. 74 | > It also auto-adds `.adjunct` marker files to all the resource sub-directories, making it possible to load fonts etc as adjuncts. 75 | 76 | ## Test run 77 | Now take `step-03-more-npm-packs` for a test run and see the effect of these changes. 78 | Again, you can do this by simply [running the plugin using the HPI plugin](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin). 79 | 80 | ![root action page](img/root-action-page.png) 81 | 82 |
83 |

84 | << PREV (step-02-nodeify) <<             >> NEXT (04-externalize-libs) >> 85 |

86 | 87 | [Node.js]: https://nodejs.org 88 | [Gulp]: https://github.com/gulpjs/gulp 89 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder 90 | [jenkins-js-modules]: https://github.com/jenkinsci/js-modules 91 | [CommonJS]: http://www.commonjs.org/ 92 | [jquery-detached]: https://github.com/tfennelly/jquery-detached 93 | [bootstrap-detached]: https://github.com/tfennelly/bootstrap-detached 94 | [Browserify]: http://browserify.org/ 95 | [bundle]: https://github.com/jenkinsci/js-modules/blob/master/FAQs.md#what-is-the-difference-between-a-module-and-a-bundle 96 | 97 | -------------------------------------------------------------------------------- /step-03-more-npm-packs/README.md: -------------------------------------------------------------------------------- 1 | # Step 03 - Use more NPM packages i.e. Twitter Bootstrap and Moment.js 2 | `step-03-more-npm-packs` builds on step-02-nodeify, adding a few more 3 | NPM packages to the mix, namely Twitter Bootstrap (via [bootstrap-detached]) 4 | and Moment.js. This is one of the major benefits of using [CommonJS] style packages; it means we can easily utilise 5 | the huge number of JavaScript packages available in the NPM registry. 6 | 7 |

8 |

    9 |
  1. How to run
    10 |
  2. How it works
    11 |
12 |

13 | 14 | ## How to run 15 | The easiest way to run this Jenkins plugin is to [use the standard Maven HPI plugin for Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin). 16 | 17 | ```sh 18 | $ mvn hpi:run 19 | ``` 20 | 21 | On running the plugin, you will see the following screen. The main change from 22 | step-02-nodeify is the fact that the sample is utilizing 23 | bootstrap and moment.js (see how it works). 24 | 25 | ![root action page](img/root-action-page.png) 26 | 27 | ## How it works 28 | 29 | 30 | 31 |
32 |

33 | << PREV (step-02-nodeify) <<             >> NEXT (04-externalize-libs) >> 34 |

35 | 36 | [Node.js]: https://nodejs.org 37 | [Gulp]: https://github.com/gulpjs/gulp 38 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder 39 | [jenkins-js-modules]: https://github.com/jenkinsci/js-modules 40 | [CommonJS]: http://www.commonjs.org/ 41 | [jquery-detached]: https://github.com/tfennelly/jquery-detached 42 | [bootstrap-detached]: https://github.com/tfennelly/bootstrap-detached 43 | [Browserify]: http://browserify.org/ 44 | [bundle]: https://github.com/jenkinsci/js-modules/blob/master/FAQs.md#what-is-the-difference-between-a-module-and-a-bundle 45 | 46 | -------------------------------------------------------------------------------- /step-03-more-npm-packs/gulpfile.js: -------------------------------------------------------------------------------- 1 | var builder = require('@jenkins-cd/js-builder'); 2 | 3 | // 4 | // Bundle the modules. 5 | // See https://github.com/jenkinsci/js-builder 6 | // 7 | builder.bundle('src/main/js/jslib-samples.js'); 8 | 9 | // 10 | // Bundle the bootstrap CSS (and associated files). 11 | // Will be made available as a Jenkins adjunct - check build output message. 12 | // 13 | builder.bundle('src/main/css/bootstrap336/bootstrap.css'); 14 | -------------------------------------------------------------------------------- /step-03-more-npm-packs/img/root-action-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/js-samples/a641067df2da59ff3f210c266d1a0c3c1127bdc1/step-03-more-npm-packs/img/root-action-page.png -------------------------------------------------------------------------------- /step-03-more-npm-packs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "step-03-more-npm-packs", 3 | "version": "1.0.0", 4 | "description": "step-03-more-npm-packs", 5 | "license": "MIT", 6 | "devDependencies": { 7 | "gulp": "^3.9.0", 8 | "@jenkins-cd/js-builder": "latest" 9 | }, 10 | "dependencies": { 11 | "@jenkins-cd/js-modules": "latest", 12 | "bootstrap-detached": "^3.3.4-v6", 13 | "moment": "^2.10.6" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /step-03-more-npm-packs/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.jenkins-ci.ui.samples 8 | jenkins-js-samples 9 | 1.0-SNAPSHOT 10 | ../ 11 | 12 | step-03-more-npm-packs 13 | 1.0 14 | hpi 15 | 16 | JS Lib Samples: Step 3 - Adding More NPMs 17 | A sample that adds more npm packages 18 | 19 | 20 | -------------------------------------------------------------------------------- /step-03-more-npm-packs/src/main/css/bootstrap336/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.6 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} 6 | /*# sourceMappingURL=bootstrap-theme.min.css.map */ -------------------------------------------------------------------------------- /step-03-more-npm-packs/src/main/css/bootstrap336/bootstrap-theme.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /step-03-more-npm-packs/src/main/java/org/jenkinsci/ui/samples/JSLibSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2015, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.ui.samples; 25 | 26 | import hudson.Extension; 27 | import hudson.model.RootAction; 28 | 29 | /** 30 | * @author tom.fennelly@gmail.com 31 | */ 32 | @Extension 33 | public class JSLibSample implements RootAction { 34 | 35 | public String getIconFileName() { 36 | return "green.png"; 37 | } 38 | 39 | public String getDisplayName() { 40 | return "JSLib Sample"; 41 | } 42 | 43 | public String getUrlName() { 44 | return "/js-sample"; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /step-03-more-npm-packs/src/main/js/jslib-samples.js: -------------------------------------------------------------------------------- 1 | // Change from 'jquery' to 'bootstrap-detached' 2 | var $ = require('bootstrap-detached').getBootstrap(); 3 | 4 | $(document).ready(function start() { 5 | var moment = require('moment'); 6 | 7 | $('#side-panel').remove(); 8 | $('#main-panel').css('margin-left', '0px'); 9 | 10 | // Add some code to use momentjs, adding formatted time text to the page. 11 | // See src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly. 12 | $('#main-panel .time').text(moment().format('MMM Do YY')); 13 | }); 14 | -------------------------------------------------------------------------------- /step-03-more-npm-packs/src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | JavaScript GUI Lib Sample. 4 |
5 | -------------------------------------------------------------------------------- /step-03-more-npm-packs/src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 |

Jenkins JS Samples

30 |

31 |
32 |
33 | 34 | 35 |
36 |
37 | 38 | 39 |
40 |
41 | 44 |
45 | 46 |
47 |
48 |
49 | 50 | 54 | 55 | 59 | 60 |
61 | -------------------------------------------------------------------------------- /step-04-externalize-libs/HOW-IT-WORKS.md: -------------------------------------------------------------------------------- 1 | # Step 04 - Externalize Dependency Libraries (slim down) - How it Works 2 | With `step-03-more-npm-packs`, we have a plugin using Modularized [CommonJS] style JavaScript, which is good. Using 3 | [CommonJS] means we can easily use any of the huge number of JavaScript packages available in the NPM registry. 4 | 5 | This is great, but one of the issues with `step-03-more-npm-packs` is that its [bundle] contains everything it needs, 6 | including jQuery, Bootstrap, Moment.js and anything else we might add. This results in a quite bloated `.js` [bundle] 7 | for `step-03-more-npm-packs` - roughly 100Kb. If a given Jenkins page loads multiple `.js` bundles like this, it will 8 | potentially result in multiple jQuery instances (and Bootstrap, Moment.js etc) being loaded. What we really want in 9 | this kind of situations is to have slimmer/lighter "App" bundles, all sharing the same jQuery etc. 10 | 11 | In `step-04-externalize-libs`, we build on top of step-03-more-npm-packs, 12 | changing the bundling process by telling [jenkins-js-builder] to "externalize" some of the NPM dependencies. This means 13 | that `step-04-externalize-libs`s `.js` [bundle] will no longer include these dependencies and it's size will reduce to 14 | ~10Kb gzipped (as opposed to ~100Kb). Note that this change should not require app `.js` 15 | code changes. The only change is in the `package.json`. 16 | 17 | ## Configure Node build to externalize dependencies 18 | Externalizing NPM dependencies is a simple process. Just add an `import` entry in the `package.json`. 19 | In the case of this plugin externalizing [bootstrap-detached] and Moment.js: 20 | 21 | ```javascript 22 | "jenkinscd" : { 23 | "import": ["bootstrap-detached", "moment"] 24 | } 25 | ``` 26 | 27 | The above instruction tells [jenkins-js-builder] to create seperate adjunct based bundles for these dependencies 28 | and to add them to the plugin archive. [jenkins-js-builder] does some magic (with [jenkins-js-modules]) that results in 29 | these dependency bundles being created in a way that if (e.g.) another plugin has also externalized the same dependency 30 | (version compatibility info below) then it will only be loaded once at runtime e.g. if a "compatible" version of the 31 | same NPM dependency was already loaded by [jenkins-js-modules] then it will not be loaded again. 32 | 33 | An important aspect of this externalization of NPM dependencies is the rules around how version compatibility works. 34 | In this regard, the above mentioned [jenkins-js-builder]/[jenkins-js-modules] magic honours the semantic versioning 35 | rules i.e. if a dependency bundle for Moment.js version `2.12.0` is already loaded, [jenkins-js-modules] will 36 | serve that version to anything that has a `moment` NPM dependency specification of version `^2.12.x` or `^2.x` i.e. 37 | they are considered as being compatible. If a compatible version of `moment` has not yet been loaded, 38 | [jenkins-js-modules] will trigger the async loading of that adjunct bundle. 39 | 40 | So putting it another way, every plugin will have `.js` bundle adjuncts for all of their external dependencies. 41 | If JavaScript for plugin "A" requires an externalized dependency to be loaded (e.g. `moment` v2.12.0), 42 | [jenkins-js-modules] will load that dependency for plugin "A". If plugin "B" then (some time later) also needs `moment` 43 | and it's version dependency is compatible with the already loaded version (e.g. `^2.x`), then [jenkins-js-modules] 44 | will not trigger another loading of `moment` i.e. it will provide the already loaded `moment` to plugin "B". 45 | 46 | ## Test run 47 | Now take `step-04-externalize-libs` for a test run and see the effect of these changes. What you'll see is that 48 | nothing has changed visually i.e. still works the same from a user perspective. The difference is in HOW it works. 49 | 50 | The `jslib-samples.js` [bundle] no longer contains [bootstrap-detached] or Moment.js. 51 | 52 | The easiest way to see this is through the Browsers Developer Tools. 53 | 54 | ![browser loading](img/browser-loading.png) 55 | 56 |
57 |

58 | << PREV (step-03-more-npm-packs) <<             >> NEXT (step-05-namespaced-css) >> 59 |

60 | 61 | [Node.js]: https://nodejs.org 62 | [Gulp]: https://github.com/gulpjs/gulp 63 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder 64 | [jenkins-js-modules]: https://github.com/jenkinsci/js-modules 65 | [jenkins-js-libs]: https://github.com/jenkinsci/js-libs 66 | [CommonJS]: http://www.commonjs.org/ 67 | [jquery-detached]: https://github.com/tfennelly/jquery-detached 68 | [bootstrap-detached]: https://github.com/tfennelly/bootstrap-detached 69 | [Browserify]: http://browserify.org/ 70 | [bundle]: https://github.com/jenkinsci/js-modules/blob/master/FAQs.md#what-is-the-difference-between-a-module-and-a-bundle 71 | 72 | -------------------------------------------------------------------------------- /step-04-externalize-libs/README.md: -------------------------------------------------------------------------------- 1 | # Step 04 - Externalize Dependency Libraries (slim down) 2 | In this plugin (`step-04-externalize-libs`), we build on top of step-03-more-npm-packs, 3 | changing it to "externalize" it's bulky dependencies i.e. [bootstrap-detached] and Moment.js. This means that `step-04-externalize-libs`s `.js` 4 | [bundle] will no longer include these dependencies and it's size will reduce to ~10Kb (as opposed to ~100Kb). 5 | 6 | This is important if you have multiple bundles loaded in Jenkins at once (e.g. from different plugins). You don't want each 7 | bundle to have their own copies of [bootstrap-detached], Moment.js etc, making them heavier to load etc. Instead, you want 8 | those common dependencies to be loaded separately and only once i.e. shared between all "app" bundles. 9 | 10 |

11 |

    12 |
  1. How to run
    13 |
  2. How it works
    14 |
15 |

16 | 17 | ## How to run 18 | The easiest way to run this Jenkins plugin is to [use the standard Maven HPI plugin for Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin). 19 | 20 | ```sh 21 | $ mvn hpi:run 22 | ``` 23 | 24 | Nothing visual changes from step-03-more-npm-packs to this plugin. 25 | The only difference is in how it works, specifically in how it loads JavaScript dependency 26 | libraries. 27 | 28 | The easiest way to see this is through the Browsers Developer Tools. 29 | 30 | ![browser loading](img/browser-loading.png) 31 | 32 | `jslib-samples.js` triggers the loading of `bootstrap3.js` and `momentjs2.js`. 33 | 34 | The main point here is that if you have a Jenkins page that loads multiple [bundle]s, many of which are loading common 35 | dependencies such as jQuery, Bootstrap etc, then you only need to load those dependencies once and share then between the 36 | different [bundle]s. And of course, the [bundle]s themselves are considerably lighter because they no longer contain 37 | these dependencies. 38 | 39 | ## How it works 40 | 41 | 42 | 43 |
44 |

45 | << PREV (step-03-more-npm-packs) <<             >> NEXT (step-05-namespaced-css) >> 46 |

47 | 48 | [Node.js]: https://nodejs.org 49 | [Gulp]: https://github.com/gulpjs/gulp 50 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder 51 | [jenkins-js-modules]: https://github.com/jenkinsci/js-modules 52 | [jenkins-js-libs]: https://github.com/jenkinsci/js-libs 53 | [CommonJS]: http://www.commonjs.org/ 54 | [jquery-detached]: https://github.com/tfennelly/jquery-detached 55 | [bootstrap-detached]: https://github.com/tfennelly/bootstrap-detached 56 | [Browserify]: http://browserify.org/ 57 | [bundle]: https://github.com/jenkinsci/js-modules/blob/master/FAQs.md#what-is-the-difference-between-a-module-and-a-bundle 58 | 59 | -------------------------------------------------------------------------------- /step-04-externalize-libs/gulpfile.js: -------------------------------------------------------------------------------- 1 | var builder = require('@jenkins-cd/js-builder'); 2 | 3 | // 4 | // Bundle the modules. 5 | // See https://github.com/jenkinsci/js-builder 6 | // 7 | builder.bundle('src/main/js/jslib-samples.js'); 8 | 9 | // 10 | // Bundle the bootstrap CSS (and associated files). 11 | // Will be made available as a Jenkins adjunct - check build output message. 12 | // 13 | builder.bundle('src/main/css/bootstrap336/bootstrap.css'); -------------------------------------------------------------------------------- /step-04-externalize-libs/img/browser-loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/js-samples/a641067df2da59ff3f210c266d1a0c3c1127bdc1/step-04-externalize-libs/img/browser-loading.png -------------------------------------------------------------------------------- /step-04-externalize-libs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "step-04-externalize-libs", 3 | "version": "1.0.0", 4 | "description": "step-04-externalize-libs", 5 | "license": "MIT", 6 | "devDependencies": { 7 | "gulp": "^3.9.0", 8 | "@jenkins-cd/js-builder": "latest" 9 | }, 10 | "dependencies": { 11 | "bootstrap-detached": "^3.3.4-v6", 12 | "@jenkins-cd/js-modules": "latest", 13 | "moment": "^2.10.6" 14 | }, 15 | "jenkinscd" : { 16 | "import": ["bootstrap-detached", "moment"] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /step-04-externalize-libs/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.jenkins-ci.ui.samples 8 | jenkins-js-samples 9 | 1.0-SNAPSHOT 10 | ../ 11 | 12 | step-04-externalize-libs 13 | 1.0 14 | hpi 15 | 16 | JS Lib Samples: Step 4 - Externalize JS Libs 17 | A sample that externalizes the framework libs Vs bundling them all 18 | 19 | 20 | -------------------------------------------------------------------------------- /step-04-externalize-libs/src/main/css/bootstrap336/bootstrap-theme.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /step-04-externalize-libs/src/main/java/org/jenkinsci/ui/samples/JSLibSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2015, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.ui.samples; 25 | 26 | import hudson.Extension; 27 | import hudson.model.RootAction; 28 | 29 | /** 30 | * @author tom.fennelly@gmail.com 31 | */ 32 | @Extension 33 | public class JSLibSample implements RootAction { 34 | 35 | public String getIconFileName() { 36 | return "green.png"; 37 | } 38 | 39 | public String getDisplayName() { 40 | return "JSLib Sample"; 41 | } 42 | 43 | public String getUrlName() { 44 | return "/js-sample"; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /step-04-externalize-libs/src/main/js/jslib-samples.js: -------------------------------------------------------------------------------- 1 | // Change from 'jquery' to 'bootstrap-detached' 2 | var $ = require('bootstrap-detached').getBootstrap(); 3 | 4 | $(document).ready(function start() { 5 | var moment = require('moment'); 6 | 7 | $('#side-panel').remove(); 8 | $('#main-panel').css('margin-left', '0px'); 9 | 10 | // Add some code to use momentjs, adding formatted time text to the page. 11 | // See src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly. 12 | $('#main-panel .time').text(moment().format('MMM Do YY')); 13 | }); 14 | -------------------------------------------------------------------------------- /step-04-externalize-libs/src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | JavaScript GUI Lib Sample. 4 |
5 | -------------------------------------------------------------------------------- /step-04-externalize-libs/src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 |

Jenkins JS Samples

30 |

31 |
32 |
33 | 34 | 35 |
36 |
37 | 38 | 39 |
40 |
41 | 44 |
45 | 46 |
47 |
48 |
49 | 50 | 54 | 55 | 59 | 60 |
61 | -------------------------------------------------------------------------------- /step-05-namespaced-css/HOW-IT-WORKS.md: -------------------------------------------------------------------------------- 1 | # Step 05 - "Namespaced" CSS - How it works 2 | In this plugin (`step-05-namespaced-css`), we modify step-04-externalize-libs 3 | a little so as to demonstrate how to "namespace" a set of CSS rules. 4 | 5 | Namespacing the CSS rules makes it safer to use multiple versions of the same CSS lib on the same page. So if, for example, you are 6 | using bootstrap on a widget that gets added to a page on which other plugins are contributing content (e.g. the Job index page), 7 | then it makes sense to use a namespaced CSS for bootstrap in case another widget also uses bootstrap, but is using a different version. 8 | 9 | ## CSS/LESS and `index.jelly` changes 10 | The easiest way to namespace the CSS rules is to pre-process the ruleset using [LESS]. In this sample, we will namespace the 11 | bootstrap rules by introducing a `bootstrap-3` namespace. To do this, we added a [bootstrap-ns3.less](src/main/css/bootstrap336/bootstrap-ns3.less) 12 | in `src/main/css/bootstrap336`. It simply does a [LESS] `@import` of the [bootstrap.css](src/main/css/bootstrap336/bootstrap.css) rules, 13 | adding the `.bootstrap-3` class on all of them. 14 | 15 | ```less 16 | .bootstrap-3 { 17 | @import (less) "bootstrap.css"; 18 | } 19 | ``` 20 | 21 | Of course we also had to modify the `gulpfile.js`, telling it to bundle the new [LESS] file: 22 | 23 | ```javascript 24 | builder.bundle('src/main/css/bootstrap336/bootstrap-ns3.less'); 25 | ``` 26 | 27 | We also had to modify [JSLibSample/index.jelly](src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly) to "namespace" the content 28 | using `
`, as well as updating the CSS adjunct in accordance with the name of the adjunct specified in the build output 29 | i.e. `org.jenkins.ui.jsmodules.bootstrap336.bootstrap-ns3`: 30 | 31 | ```diff 32 | 33 | 34 | 35 | +
36 |

Jenkins JS Samples

37 |

38 |
39 |
40 | 41 | 42 |
43 |
44 | 45 | 46 |
47 |
48 | 51 |
52 | 53 |
54 | +
55 |
56 |
57 | 58 | 62 | 63 | - 64 | + 65 |
66 | ``` 67 | 68 |
69 |

70 | << PREV (step-04-externalize-libs) <<             >> NEXT (step-06-handlebars-templates) >> 71 |

72 | 73 | [Node.js]: https://nodejs.org 74 | [Gulp]: https://github.com/gulpjs/gulp 75 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder 76 | [jenkins-js-modules]: https://github.com/jenkinsci/js-modules 77 | [jenkins-js-libs]: https://github.com/jenkinsci/js-libs 78 | [CommonJS]: http://www.commonjs.org/ 79 | [jquery-detached]: https://github.com/tfennelly/jquery-detached 80 | [bootstrap-detached]: https://github.com/tfennelly/bootstrap-detached 81 | [Browserify]: http://browserify.org/ 82 | [bundle]: https://github.com/jenkinsci/js-modules/blob/master/FAQs.md#what-is-the-difference-between-a-module-and-a-bundle 83 | [LESS]: http://lesscss.org/ 84 | 85 | -------------------------------------------------------------------------------- /step-05-namespaced-css/README.md: -------------------------------------------------------------------------------- 1 | # Step 05 - "Namespaced" CSS 2 | In this plugin (`step-05-namespaced-css`), we modify step-04-externalize-libs 3 | a little so as to demonstrate how to "namespace" a set of CSS rules. 4 | 5 | Namespacing the CSS rules makes it safer to use multiple versions of the same CSS lib on the same page. So if, for example, you are 6 | using bootstrap on a widget that gets added to a page on which other plugins are contributing content (e.g. the Job index page), 7 | then it makes sense to use a namespaced CSS for bootstrap in case another widget also uses bootstrap, but is using a different version. 8 | 9 |

10 |

    11 |
  1. How to run
    12 |
  2. How it works
    13 |
14 |

15 | 16 | ## How to run 17 | The easiest way to run this Jenkins plugin is to [use the standard Maven HPI plugin for Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin). 18 | 19 | ```sh 20 | $ mvn hpi:run 21 | ``` 22 | 23 | Again, nothing visual changes from step-04-externalize-libs to this plugin. 24 | The only difference is in how it works, specifically in how the default namespaced CSS is auto-loaded and used. 25 | 26 | ## How it works 27 | 28 | 29 | 30 |
31 |

32 | << PREV (step-04-externalize-libs) <<             >> NEXT (step-06-handlebars-templates) >> 33 |

34 | 35 | [Node.js]: https://nodejs.org 36 | [Gulp]: https://github.com/gulpjs/gulp 37 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder 38 | [jenkins-js-modules]: https://github.com/jenkinsci/js-modules 39 | [jenkins-js-libs]: https://github.com/jenkinsci/js-libs 40 | [CommonJS]: http://www.commonjs.org/ 41 | [jquery-detached]: https://github.com/tfennelly/jquery-detached 42 | [bootstrap-detached]: https://github.com/tfennelly/bootstrap-detached 43 | [Browserify]: http://browserify.org/ 44 | [bundle]: https://github.com/jenkinsci/js-modules/blob/master/FAQs.md#what-is-the-difference-between-a-module-and-a-bundle 45 | 46 | -------------------------------------------------------------------------------- /step-05-namespaced-css/gulpfile.js: -------------------------------------------------------------------------------- 1 | var builder = require('@jenkins-cd/js-builder'); 2 | 3 | // 4 | // Bundle the modules. 5 | // See https://github.com/jenkinsci/js-builder 6 | // 7 | builder.bundle('src/main/js/jslib-samples.js'); 8 | 9 | // 10 | // Bundle the namespaced bootstrap CSS (and associated files). 11 | // Will be made available as a Jenkins adjunct - check build output message. 12 | // 13 | builder.bundle('src/main/css/bootstrap336/bootstrap-ns3.less'); -------------------------------------------------------------------------------- /step-05-namespaced-css/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "step-05-namespaced-css", 3 | "version": "1.0.0", 4 | "description": "step-05-namespaced-css", 5 | "license": "MIT", 6 | "devDependencies": { 7 | "gulp": "^3.9.0", 8 | "@jenkins-cd/js-builder": "latest" 9 | }, 10 | "dependencies": { 11 | "bootstrap-detached": "^3.3.4-v6", 12 | "@jenkins-cd/js-modules": "latest", 13 | "moment": "^2.10.6" 14 | }, 15 | "jenkinscd" : { 16 | "import": ["bootstrap-detached", "moment"] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /step-05-namespaced-css/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.jenkins-ci.ui.samples 8 | jenkins-js-samples 9 | 1.0-SNAPSHOT 10 | ../ 11 | 12 | step-05-namespaced-css 13 | 1.0 14 | hpi 15 | 16 | JS Lib Samples: Step 5 - Namespaced CSS 17 | A sample that uses a namespaced CSS for Bootstrap 18 | 19 | 20 | -------------------------------------------------------------------------------- /step-05-namespaced-css/src/main/css/bootstrap336/bootstrap-ns3.less: -------------------------------------------------------------------------------- 1 | // 2 | // Use LESS to namespace the published bootstrap CSS i.e. no need to hand modify etc. 3 | // 4 | .bootstrap-3 { 5 | @import (less) "bootstrap.css"; 6 | } 7 | -------------------------------------------------------------------------------- /step-05-namespaced-css/src/main/css/bootstrap336/bootstrap-theme.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /step-05-namespaced-css/src/main/java/org/jenkinsci/ui/samples/JSLibSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2015, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.ui.samples; 25 | 26 | import hudson.Extension; 27 | import hudson.model.RootAction; 28 | 29 | /** 30 | * @author tom.fennelly@gmail.com 31 | */ 32 | @Extension 33 | public class JSLibSample implements RootAction { 34 | 35 | public String getIconFileName() { 36 | return "green.png"; 37 | } 38 | 39 | public String getDisplayName() { 40 | return "JSLib Sample"; 41 | } 42 | 43 | public String getUrlName() { 44 | return "/js-sample"; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /step-05-namespaced-css/src/main/js/jslib-samples.js: -------------------------------------------------------------------------------- 1 | // Change from 'jquery-detached' to 'bootstrap-detached' 2 | var $ = require('bootstrap-detached').getBootstrap(); 3 | 4 | $(document).ready(function start() { 5 | var moment = require('moment'); 6 | 7 | $('#side-panel').remove(); 8 | $('#main-panel').css('margin-left', '0px'); 9 | 10 | // Add some code to use momentjs, adding formatted time text to the page. 11 | // See src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly. 12 | $('#main-panel .time').text(moment().format('MMM Do YY')); 13 | }); 14 | -------------------------------------------------------------------------------- /step-05-namespaced-css/src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | JavaScript GUI Lib Sample. 4 |
5 | -------------------------------------------------------------------------------- /step-05-namespaced-css/src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |

Jenkins JS Samples

31 |

32 |
33 |
34 | 35 | 36 |
37 |
38 | 39 | 40 |
41 |
42 | 45 |
46 | 47 |
48 |
49 |
50 |
51 | 52 | 56 | 57 | 61 | 62 |
63 | -------------------------------------------------------------------------------- /step-06-handlebars-templates/HOW-IT-WORKS.md: -------------------------------------------------------------------------------- 1 | # Step 06 - Handlebars Templates - How it works 2 | In this plugin (`step-06-handlebars-templates`), we build on step-04-externalize-libs, 3 | changing it to apply client-side templates using the [Handlebars] templating engine. 4 | 5 | With this model, we change from the "traditional" pure server-side content rendering approach of Jenkins (in `.jelly` files), 6 | to an approach where just the bare minimum content is rendered server-side, and the reset of the content is rendered on 7 | the client-side e.g. the client-side makes a REST API call to get some data from the server and then applies a template 8 | to that data to produce the view content. This approach is fundamental to creating a more dynamic/slick user experience 9 | (Vs full page reloading etc). 10 | 11 | [Handlebars] is actually quite a tricky package to use with Browserify, especially if registering [Handlebars] helpers 12 | (which most apps need to do). The following sections outline the changes that were made to 13 | step-04-externalize-libs in order for it to use [Handlebars] templates. 14 | 15 | ## Install Handlebars NPM package 16 | 17 | ```sh 18 | $ npm install --save handlebars@3 19 | ``` 20 | 21 | Note that we are not goig to be pre-compiling the [Handlebars] templates (see [Handlebarsify]) as doing so would 22 | mean that we would not be able to externalize the [Handlebars] NPM package (due to how [Handlebarsify] references 23 | the [Handlebars] runtime, as well as how helpers work etc). 24 | 25 | ## Externalize the [Handlebars] NPM package 26 | Simply add `handlebars` to the `extDependencies` list in the `package.json` file: 27 | 28 | ```diff 29 | "jenkinscd" : { 30 | - "extDependencies": ["bootstrap-detached", "moment"] 31 | + "extDependencies": ["bootstrap-detached", "handlebars", "moment"] 32 | } 33 | ``` 34 | 35 | See step-04-externalize-libs for more on externalizing 36 | NPM dependencies. 37 | 38 | ## Move the form to `form.hbs` (from `JSLibSample/index.jelly`) 39 | Add the [Handlebars] template in [src/main/js/templates/form.hbs](src/main/js/templates/form.hbs). Note the `{{time}}` 40 | token; this will make more sense when we get to the `.js` changes below. 41 | 42 | ```html 43 |

{{time}}

44 |
45 |
46 | 47 | 48 |
49 |
50 | 51 | 52 |
53 |
54 | 57 |
58 | 59 |
60 | ``` 61 | 62 | Delete the same form content from [JSLibSample/index.jelly](src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly) 63 | and replace with a simple `
` holder element; again, this will make more sense when we get to the 64 | `.js` changes below. 65 | 66 | ```diff 67 | 68 | 69 |

Jenkins JS Samples

70 | -

71 | -
72 | -
73 | - 74 | - 75 | -
76 | -
77 | - 78 | - 79 | -
80 | -
81 | - 84 | -
85 | - 86 | -
87 | +
88 |
89 |
90 | ``` 91 | 92 | ## Modify `jslib-samples.js` to use Handlerbars 93 | We modified [jslib-samples.js](src/main/js/jslib-samples.js) to use the `form.hbs` [Handlebars] template, injecting the 94 | Moment.js generated `time` value into the template (remember the `{{time}}` tokens in `form.hbs`). 95 | 96 | ```diff 97 | $('#side-panel').remove(); 98 | $('#main-panel').css('margin-left', '0px'); 99 | 100 | - // Add some code to use momentjs, adding formatted time text to the page. 101 | - // See src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly. 102 | var moment = require('moment'); 103 | - $('#main-panel .time').text(moment().format("MMM Do YY")); 104 | + var handlebars = require('handlebars'); 105 | + var formTemplate = handlebars.compile(require('fs') 106 | + .readFileSync(__dirname + '/./templates/form.hbs', 'utf8')); 107 | + 108 | + // Apply the 'form' template, appending the resulting content to 109 | + // the 'form-container' element. We could also define a Handlers helper 110 | + // to handle the formatted time. 111 | + $('#form-container').append(formTemplate({ 112 | + time: moment().format("MMM Do YY") 113 | + })); 114 | }); 115 | ``` 116 | 117 | Note how we use the `fs` (filesystem) package to load the `form.hbs` template. [jenkins-js-builder] handles 118 | this at build time. 119 | 120 |
121 |

122 | << PREV (step-05-namespaced-css) <<             >> NEXT (step-07-jsdom-tests) >> 123 |

124 | 125 | [Handlebars]: http://handlebarsjs.com/ 126 | [Handlebarsify]: https://www.npmjs.com/package/handlebarsify 127 | [Node.js]: https://nodejs.org 128 | [Gulp]: https://github.com/gulpjs/gulp 129 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder 130 | [jenkins-js-modules]: https://github.com/jenkinsci/js-modules 131 | [jenkins-js-libs]: https://github.com/jenkinsci/js-libs 132 | [CommonJS]: http://www.commonjs.org/ 133 | [jquery-detached]: https://github.com/tfennelly/jquery-detached 134 | [bootstrap-detached]: https://github.com/tfennelly/bootstrap-detached 135 | [Browserify]: http://browserify.org/ 136 | [bundle]: https://github.com/jenkinsci/js-modules/blob/master/FAQs.md#what-is-the-difference-between-a-module-and-a-bundle 137 | 138 | -------------------------------------------------------------------------------- /step-06-handlebars-templates/README.md: -------------------------------------------------------------------------------- 1 | # Step 06 - Handlebars Templates 2 | In this plugin (`step-06-handlebars-templates`), we build on step-04-externalize-libs, 3 | changing it to apply client-side templates using the [Handlebars] templating engine. 4 | 5 | With this model, we change from the "traditional" pure server-side content rendering approach of Jenkins (in `.jelly` files), 6 | to an approach where just the bare minimum content is rendered server-side, and the reset of the content is rendered on 7 | the client-side e.g. the client-side makes a REST API call to get some data from the server and then applies a template 8 | to that data to produce the view content. This approach is fundamental to creating a more dynamic/slick user experience 9 | (Vs full page reloading etc). 10 | 11 |

12 |

    13 |
  1. How to run
    14 |
  2. How it works
    15 |
16 |

17 | 18 | ## How to run 19 | The easiest way to run this Jenkins plugin is to [use the standard Maven HPI plugin for Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin). 20 | 21 | ```sh 22 | $ mvn hpi:run 23 | ``` 24 | 25 | Again, nothing visual changes from step-04-externalize-libs to this plugin. 26 | The only difference is in how it works, specifically in how the form content is rendered on the client-side 27 | using [Handlebars] templates. 28 | 29 | ## How it works 30 | 31 | 32 | 33 |
34 |

35 | << PREV (step-05-namespaced-css) <<             >> NEXT (step-07-jsdom-tests) >> 36 |

37 | 38 | [Handlebars]: http://handlebarsjs.com/ 39 | [Node.js]: https://nodejs.org 40 | [Gulp]: https://github.com/gulpjs/gulp 41 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder 42 | [jenkins-js-modules]: https://github.com/jenkinsci/js-modules 43 | [jenkins-js-libs]: https://github.com/jenkinsci/js-libs 44 | [CommonJS]: http://www.commonjs.org/ 45 | [jquery-detached]: https://github.com/tfennelly/jquery-detached 46 | [bootstrap-detached]: https://github.com/tfennelly/bootstrap-detached 47 | [Browserify]: http://browserify.org/ 48 | [bundle]: https://github.com/jenkinsci/js-modules/blob/master/FAQs.md#what-is-the-difference-between-a-module-and-a-bundle 49 | 50 | -------------------------------------------------------------------------------- /step-06-handlebars-templates/gulpfile.js: -------------------------------------------------------------------------------- 1 | var builder = require('@jenkins-cd/js-builder'); 2 | 3 | // 4 | // Bundle the modules. 5 | // See https://github.com/jenkinsci/js-builder 6 | // 7 | builder.bundle('src/main/js/jslib-samples.js'); 8 | 9 | // 10 | // Bundle the bootstrap CSS (and associated files). 11 | // Will be made available as a Jenkins adjunct - check build output message. 12 | // 13 | builder.bundle('src/main/css/bootstrap336/bootstrap.css'); -------------------------------------------------------------------------------- /step-06-handlebars-templates/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "step-06-handlebars-templates", 3 | "version": "1.0.0", 4 | "description": "step-06-handlebars-templates", 5 | "license": "MIT", 6 | "devDependencies": { 7 | "gulp": "^3.9.0", 8 | "@jenkins-cd/js-builder": "latest" 9 | }, 10 | "dependencies": { 11 | "bootstrap-detached": "^3.3.4-v6", 12 | "@jenkins-cd/js-modules": "latest", 13 | "handlebars": "^4.0.5", 14 | "moment": "^2.10.6" 15 | }, 16 | "jenkinscd" : { 17 | "import": ["bootstrap-detached", "handlebars", "moment"] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /step-06-handlebars-templates/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.jenkins-ci.ui.samples 8 | jenkins-js-samples 9 | 1.0-SNAPSHOT 10 | ../ 11 | 12 | step-06-handlebars-templates 13 | 1.0 14 | hpi 15 | 16 | JS Lib Samples: Step 6 - Handlebars Templates 17 | A sample that uses Handlebars Templates 18 | 19 | 20 | -------------------------------------------------------------------------------- /step-06-handlebars-templates/src/main/css/bootstrap336/bootstrap-theme.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /step-06-handlebars-templates/src/main/java/org/jenkinsci/ui/samples/JSLibSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2015, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.ui.samples; 25 | 26 | import hudson.Extension; 27 | import hudson.model.RootAction; 28 | 29 | /** 30 | * @author tom.fennelly@gmail.com 31 | */ 32 | @Extension 33 | public class JSLibSample implements RootAction { 34 | 35 | public String getIconFileName() { 36 | return "green.png"; 37 | } 38 | 39 | public String getDisplayName() { 40 | return "JSLib Sample"; 41 | } 42 | 43 | public String getUrlName() { 44 | return "/js-sample"; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /step-06-handlebars-templates/src/main/js/jslib-samples.js: -------------------------------------------------------------------------------- 1 | // Change from 'jquery-detached' to 'bootstrap-detached' 2 | var $ = require('bootstrap-detached').getBootstrap(); 3 | var handlebars = require('handlebars'); 4 | var formTemplate = handlebars.compile(require('fs') 5 | .readFileSync(__dirname + '/./templates/form.hbs', 'utf8')); 6 | 7 | $(document).ready(function start() { 8 | var moment = require('moment'); 9 | 10 | $('#side-panel').remove(); 11 | 12 | $('#main-panel').css('margin-left', '0px'); 13 | // Apply the 'form' template, appending the resulting content to 14 | // the 'form-container' element. We could also define a Handlers helper 15 | // to handle the formatted time. 16 | $('#form-container').append(formTemplate({ 17 | time: moment().format('MMM Do YY') 18 | })); 19 | }); 20 | -------------------------------------------------------------------------------- /step-06-handlebars-templates/src/main/js/templates/form.hbs: -------------------------------------------------------------------------------- 1 |

{{time}}

2 |
3 |
4 | 5 | 6 |
7 |
8 | 9 | 10 |
11 |
12 | 15 |
16 | 17 |
18 | -------------------------------------------------------------------------------- /step-06-handlebars-templates/src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | JavaScript GUI Lib Sample. 4 |
5 | -------------------------------------------------------------------------------- /step-06-handlebars-templates/src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 |

Jenkins JS Samples

30 |
31 |
32 |
33 | 34 | 38 | 39 | 43 | 44 |
45 | -------------------------------------------------------------------------------- /step-07-jsdom-tests/README.md: -------------------------------------------------------------------------------- 1 | # Step 07 - jsdom tests 2 | [jsdom] is a JavaScript implementation of the [WHATWG](https://whatwg.org/), DOM and HTML standards. It's quite 3 | useful for writing unit tests. 4 | 5 | In this sample plugin, we modified step-06-handlebars-templates 6 | a little so as the make it a small bit more interactive. We then added a simple unit test that used [jsdom] via [jenkins-js-test]. 7 | 8 | > Also see step-08-zombie-tests as an example of how to do Integration Testing. 9 | 10 | ## How to run 11 | The easiest way to run this Jenkins plugin is to [use the standard Maven HPI plugin for Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin). 12 | 13 | ```sh 14 | $ mvn hpi:run 15 | ``` 16 | 17 | After running the plugin you'll see that the form (that was in step-06-handlebars-templates) 18 | has now moved into a Twitter Bootstrap popover. 19 | 20 | ![root action page](img/root-action-page.png) 21 | 22 | ## The test 23 | In this plugin, we want to add a JavaScript unit test to test this page i.e.: 24 | 25 | 1. That the big red button is displayed 26 | 1. That the popover form appears when we click on that button 27 | 1. That the popover form disappears when we click the form "Submit" button 28 | 29 | To install `jenkins-js-test`: 30 | 31 | ```sh 32 | $ npm install --save-dev @jenkins-cd/js-test 33 | ``` 34 | 35 | Since this is a maven project, [jenkins-js-builder] looks for the tests in `src/test/js` so that is where we 36 | added the test "spec" file i.e. `src/test/js/jslib-samples-spec.js`. [jenkins-js-builder] uses [Jasmine] to 37 | run all tests ("**/*-spec.js") it finds under the `src/test/js` sub directory. 38 | 39 | [See the test code in jslib-samples-spec.js and read the comments therein](src/test/js/jslib-samples-spec.js). 40 | 41 | ## Running the test 42 | Running the tests from the commandline is easy. Just run `gulp` and that will run the tests too: 43 | 44 | ```sh 45 | $ gulp 46 | ``` 47 | 48 | > The `gulp` process also runs as part of the `mvn` build, generating the JavaScript bundle(s) into the generated HPI artifact. 49 | 50 | Running `gulp` should produce an output something like the following: 51 | 52 | ```sh 53 | $ gulp 54 | [16:19:09] Maven project 55 | [16:19:09] - src: src/main/js,src/main/less 56 | [16:19:09] - test: src/test/js 57 | [16:19:09] Setting defaults 58 | [16:19:09] Bundle will be generated in directory 'src/main/webapp/jsbundles' as 'jslib-samples.js'. 59 | [16:19:09] Using gulpfile ~/projects/jenkins-plugins/jenkins-js-samples/step-07-jsdom-tests/gulpfile.js 60 | [16:19:09] Starting 'jshint'... 61 | [16:19:09] - Using default JSHint configuration (in jenkins-js-builder). Override by defining a .jshintrc in this folder. 62 | [16:19:09] Finished 'jshint' after 155 ms 63 | [16:19:09] Starting 'bundle_jslib-samples'... 64 | [16:19:09] Finished 'bundle_jslib-samples' after 391 ms 65 | [16:19:09] Starting 'bundle'... 66 | [16:19:09] Finished 'bundle' after 8.02 μs 67 | [16:19:09] Starting 'test'... 68 | [16:19:09] Testing web server started on port 18999 (http://localhost:18999). Content root: /Users/tfennelly/projects/jenkins-plugins/jenkins-js-samples/step-07-jsdom-tests 69 | [16:19:09] Test execution completed. 70 | [16:19:09] Finished 'test' after 26 ms 71 | [16:19:09] Starting 'default'... 72 | [16:19:09] Finished 'default' after 17 μs 73 | jslib-samples.js 74 | - test ... 75 | Passed 76 | 1 of 1 passed (0 skipped, 0 disabled). 77 | SUCCESS: 1 spec, 0 failures, 0 skipped, 0 disabled in 0.256s. 78 | [16:19:10] Testing web server stopped. 79 | ``` 80 | 81 |
82 |

83 | << PREV (step-06-handlebars-templates) <<             >> NEXT (step-08-zombie-tests) >> 84 |

85 | 86 | [jsdom]: https://github.com/tmpvar/jsdom 87 | [jenkins-js-test]: https://github.com/jenkinsci/js-test 88 | [jenkins-js-builder]: https://github.com/jenkinsci/js-builder 89 | [Jasmine]: http://jasmine.github.io/ 90 | 91 | -------------------------------------------------------------------------------- /step-07-jsdom-tests/gulpfile.js: -------------------------------------------------------------------------------- 1 | var builder = require('@jenkins-cd/js-builder'); 2 | 3 | // 4 | // Bundle the modules. 5 | // See https://github.com/jenkinsci/js-builder 6 | // 7 | builder.bundle('src/main/js/jslib-samples.js'); 8 | 9 | // 10 | // Bundle the bootstrap CSS (and associated files). 11 | // Will be made available as a Jenkins adjunct - check build output message. 12 | // 13 | builder.bundle('src/main/css/bootstrap336/bootstrap.css'); -------------------------------------------------------------------------------- /step-07-jsdom-tests/img/root-action-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/js-samples/a641067df2da59ff3f210c266d1a0c3c1127bdc1/step-07-jsdom-tests/img/root-action-page.png -------------------------------------------------------------------------------- /step-07-jsdom-tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "step-07-jsdom-tests", 3 | "version": "1.0.0", 4 | "description": "step-07-jsdom-tests", 5 | "license": "MIT", 6 | "devDependencies": { 7 | "gulp": "^3.9.0", 8 | "@jenkins-cd/js-builder": "latest", 9 | "@jenkins-cd/js-test": "latest" 10 | }, 11 | "dependencies": { 12 | "bootstrap-detached": "^3.3.4-v6", 13 | "@jenkins-cd/js-modules": "latest", 14 | "handlebars": "^4.0.5", 15 | "moment": "^2.10.6" 16 | }, 17 | "jenkinscd" : { 18 | "import": ["bootstrap-detached", "handlebars", "moment"] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /step-07-jsdom-tests/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.jenkins-ci.ui.samples 8 | jenkins-js-samples 9 | 1.0-SNAPSHOT 10 | ../ 11 | 12 | step-07-jsdom-tests 13 | 1.0 14 | hpi 15 | 16 | JS Lib Samples: Step 7 - jsdom Tests 17 | A sample that uses jsdom for unit testing 18 | 19 | 20 | -------------------------------------------------------------------------------- /step-07-jsdom-tests/src/main/css/bootstrap336/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.6 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} 6 | /*# sourceMappingURL=bootstrap-theme.min.css.map */ -------------------------------------------------------------------------------- /step-07-jsdom-tests/src/main/css/bootstrap336/bootstrap-theme.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /step-07-jsdom-tests/src/main/java/org/jenkinsci/ui/samples/JSLibSample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2015, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package org.jenkinsci.ui.samples; 25 | 26 | import hudson.Extension; 27 | import hudson.model.RootAction; 28 | 29 | /** 30 | * @author tom.fennelly@gmail.com 31 | */ 32 | @Extension 33 | public class JSLibSample implements RootAction { 34 | 35 | public String getIconFileName() { 36 | return "green.png"; 37 | } 38 | 39 | public String getDisplayName() { 40 | return "JSLib Sample"; 41 | } 42 | 43 | public String getUrlName() { 44 | return "/js-sample"; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /step-07-jsdom-tests/src/main/js/jslib-samples.js: -------------------------------------------------------------------------------- 1 | // Change from 'jquery-detached' to 'bootstrap-detached' 2 | var $ = require('bootstrap-detached').getBootstrap(); 3 | var handlebars = require('handlebars'); 4 | var formTemplate = handlebars.compile(require('fs') 5 | .readFileSync(__dirname + '/./templates/form.hbs', 'utf8')); 6 | 7 | $(document).ready(function () { 8 | var moment = require('moment'); 9 | 10 | $('#side-panel').remove(); 11 | $('#main-panel').css('margin-left', '0px'); 12 | // Apply the 'form' template, appending the resulting content to 13 | // the 'form-container' element. We could also define a Handlers helper 14 | // to handle the formatted time. 15 | $('#submit-details').click(function () { 16 | var popoverContent = formTemplate({ 17 | time: moment().format('MMM Do YY') 18 | }); 19 | $('#submit-details').popover({ 20 | title: 'Please submit your details', 21 | content: popoverContent, 22 | html: true, 23 | trigger: 'manual' 24 | }); 25 | $('#submit-details').on('shown.bs.popover', function () { 26 | $('#submit-details-go').click(function () { 27 | $('#submit-details').popover('destroy'); 28 | }); 29 | }); 30 | $('#submit-details').popover('show'); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /step-07-jsdom-tests/src/main/js/templates/form.hbs: -------------------------------------------------------------------------------- 1 |

{{time}}

2 |
3 |
4 | 5 | 6 |
7 |
8 | 9 | 10 |
11 |
12 | 15 |
16 | 17 |
18 | -------------------------------------------------------------------------------- /step-07-jsdom-tests/src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | JavaScript GUI Lib Sample. 4 |
5 | -------------------------------------------------------------------------------- /step-07-jsdom-tests/src/main/resources/org/jenkinsci/ui/samples/JSLibSample/index.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 |

Jenkins JS Samples

30 | 31 |
32 |
33 | 34 | 38 | 39 | 43 | 44 |
45 | -------------------------------------------------------------------------------- /step-07-jsdom-tests/src/test/js/jslib-samples-spec.js: -------------------------------------------------------------------------------- 1 | var jsTest = require("@jenkins-cd/js-test"); 2 | 3 | // This is a Jasmine test that uses the jsdom lib via @jenkins-cd/js-test. @jenkins-cd/js-test 4 | // just wraps up some things and makes jsdom a bit easier to use. 5 | 6 | describe("jslib-samples.js", function () { 7 | 8 | it("- test", function (done) { 9 | 10 | // Create a "fake" page with the same button as is on the real page when the plugin 11 | // is run in Jenkins. 12 | var PAGE = ''; 13 | 14 | // "Load" the fake page using @jenkins-cd/js-test. @jenkins-cd/js-test wraps jsdom, but also makes sure 15 | // the environment is reset properly for this test. 16 | jsTest.onPage(function() { 17 | // Load the CommonJS module under test 18 | jsTest.requireSrcModule('jslib-samples.js'); 19 | 20 | // Get bootstrap and manually fire events, mimicing user interactions 21 | var bootstrap = require("bootstrap-detached"); 22 | var $ = bootstrap.getBootstrap(); 23 | 24 | // Make sure the submit-details-go button is not visible 25 | expect($('#submit-details-go').length).toBe(0); 26 | 27 | // Click the submit 28 | $('#submit-details').click(); 29 | 30 | // Make sure that the popover with the submit-details-go button 31 | // is visible now 32 | expect($('#submit-details-go').length).toBe(1); 33 | 34 | // Click the submit go button on the popover. It should disappear then. 35 | $('#submit-details-go').click(); 36 | 37 | // Make sure the submit-details-go button is no longer visible 38 | expect($('#submit-details-go').length).toBe(0); 39 | 40 | // Calling done tells Jasmine that the test is complete. 41 | done(); 42 | }, PAGE); 43 | }); 44 | }); -------------------------------------------------------------------------------- /step-08-zombie-tests/README.md: -------------------------------------------------------------------------------- 1 | # Step 08 - Zombie tests 2 | [Zombie] is an "Insanely fast, full-stack, headless browser testing using node.js", making it useful 3 | for integration testing. 4 | 5 | In this sample plugin, we modified step-06-handlebars-templates 6 | a little so as the make it a small bit more interactive. We then added a simple integration test using [Zombie]. 7 | 8 | > Also see step-07-jsdom-tests as an example of how to do Unit Testing. 9 | 10 | ## How to run 11 | The easiest way to run this Jenkins plugin is to [use the standard Maven HPI plugin for Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Plugin+tutorial#Plugintutorial-DebuggingaPlugin). 12 | 13 | ```sh 14 | $ mvn hpi:run 15 | ``` 16 | 17 | After running the plugin you'll see that the form (that was in step-06-handlebars-templates) 18 | has now moved into a Twitter Bootstrap popover. 19 | 20 | ![root action page](img/root-action-page.png) 21 | 22 | ## The test 23 | In this plugin, we want to add a JavaScript unit test to test this page i.e.: 24 | 25 | 1. That the big red button is displayed 26 | 1. That the popover form appears when we click on that button 27 | 1. That the popover form disappears when we click the form "Submit" button 28 | 29 | To install `zombie`: 30 | 31 | ```sh 32 | $ npm install --save-dev zombie 33 | ``` 34 | 35 | Since this is a maven project, [jenkins-js-builder] looks for the tests in `src/test/js` so that is where we 36 | added the test "spec" file i.e. `src/test/js/jslib-samples-spec.js`. [jenkins-js-builder] uses [Jasmine] to 37 | run all tests ("**/*-spec.js") it finds under the `src/test/js` sub directory. 38 | 39 | [See the test code in jslib-samples-spec.js and read the comments therein](src/test/js/jslib-samples-spec.js). 40 | 41 | ## Running the test 42 | Running the tests from the commandline is easy. Just run `gulp` and that will run the tests too: 43 | 44 | ```sh 45 | $ gulp 46 | ``` 47 | 48 | > The `gulp` process also runs as part of the `mvn` build, generating the JavaScript bundle(s) into the generated HPI artifact. 49 | 50 | Running `gulp` should produce an output something like the following: 51 | 52 | ```sh 53 | $ gulp 54 | [13:57:00] Maven project 55 | [13:57:00] - src: src/main/js,src/main/less 56 | [13:57:00] - test: src/test/js 57 | [13:57:00] Setting defaults 58 | [13:57:00] Bundle will be generated in directory 'src/main/webapp/jsbundles' as 'jslib-samples.js'. 59 | [13:57:00] Using gulpfile ~/projects/jenkins-plugins/jenkins-js-samples/step-08-zombie-tests/gulpfile.js 60 | [13:57:00] Starting 'jshint'... 61 | [13:57:00] - Using default JSHint configuration (in jenkins-js-builder). Override by defining a .jshintrc in this folder. 62 | [13:57:00] Finished 'jshint' after 169 ms 63 | [13:57:00] Starting 'bundle_jslib-samples'... 64 | [13:57:00] Starting 'bundle_jslib-samples_no_imports'... 65 | [13:57:01] Finished 'bundle_jslib-samples' after 1.19 s 66 | [13:57:01] Finished 'bundle_jslib-samples_no_imports' after 1.11 s 67 | [13:57:01] Starting 'bundle'... 68 | [13:57:01] Finished 'bundle' after 7.94 μs 69 | [13:57:01] Starting 'test'... 70 | [13:57:01] Testing web server started on port 18999 (http://localhost:18999). Content root: /Users/tfennelly/projects/jenkins-plugins/jenkins-js-samples/step-08-zombie-tests 71 | [13:57:01] Test execution completed. 72 | [13:57:01] Finished 'test' after 61 ms 73 | [13:57:01] Starting 'default'... 74 | [13:57:01] Finished 'default' after 7.36 μs 75 | step 08 - zombie headless browser test 76 | - basic test ... 77 | zombie Opened window http://localhost:18999/src/test/js/testpage.html +0ms 78 | zombie GET http://localhost:18999/src/test/js/testpage.html => 200 +34ms 79 | zombie Loaded document http://localhost:18999/src/test/js/testpage.html +24ms 80 | zombie GET http://localhost:18999/src/main/webapp/jsbundles/no_imports/jslib-samples.js => 200 +11ms 81 | zombie Event loop is empty +100ms 82 | zombie Event loop is empty +33ms 83 | zombie Event loop is empty +6ms 84 | Passed 85 | 1 of 1 passed (0 skipped, 0 disabled). 86 | SUCCESS: 1 spec, 0 failures, 0 skipped, 0 disabled in 0.25s. 87 | [13:57:02] Testing web server stopped. 88 | ``` 89 | 90 | ## So what happened? 91 | The test relies on the fact that [jenkins-js-builder] automatically runs a test web server on port `18999`, with its 92 | content root being the `cwd` of the build run i.e. the root of the maven project. See the console output above i.e. 93 | 94 | ```sh 95 | [13:57:01] Testing web server started on port 18999 (http://localhost:18999). Content root: /Users/tfennelly/projects/jenkins-plugins/jenkins-js-samples/step-08-zombie-tests 96 | ``` 97 | 98 | The test spec file ([jslib-samples-spec.js](src/test/js/jslib-samples-spec.js)) uses this and [Zombie] to load a test HTML 99 | page ([testpage.html](src/test/js/testpage.html)). This test page contains the same ` 12 | 13 | --------------------------------------------------------------------------------