├── .gitignore ├── Gemfile ├── README.md ├── Rakefile ├── models ├── directory_listing_root_action.rb ├── logging_wrapper.rb ├── model_reload_root_action.rb ├── test_builder.rb ├── test_notifier_recorder.rb ├── test_publisher.rb ├── test_root_action.rb ├── travis_script_builder.rb ├── ui_samples.rb └── ui_samples │ ├── auto_complete_text_box.rb │ ├── dropdown_list.rb │ ├── java_script_proxy.rb │ ├── progress_bar.rb │ └── syntax_highlighted_text_area.rb ├── ruby-prototype.pluginspec └── views ├── lib ├── README.txt └── samples │ ├── sample.jelly │ └── taglib ├── logging_wrapper └── config.erb ├── test_builder └── config.erb ├── test_root_action └── index.erb └── ui_samples ├── README.txt ├── auto_complete_text_box └── index.erb ├── dropdown_list ├── apple │ └── config.erb ├── banana │ └── config.erb └── index.erb ├── java_script_proxy └── index.erb ├── progress_bar └── index.erb ├── root └── index.erb └── syntax_highlighted_text_area └── index.erb /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | .rake 3 | .bundle 4 | .rvmrc 5 | .rspec 6 | .idea 7 | pkg 8 | work 9 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source :rubygems 2 | 3 | # Use this line instead if you want to bundle from a local copy. 4 | # gem "jenkins-plugin-runtime", :path => "#{File.dirname(__FILE__)}/../jenkins-plugin-runtime" 5 | gem "jenkins-plugin-runtime", "~> 0.1.6" 6 | 7 | gem "sinatra" 8 | 9 | group :development do 10 | # we need this patched version of bundler in order to generate valide .hpi file 11 | gem "jenkins-plugin", "~> 0.1.8" 12 | end 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A prototype Ruby plugin 2 | 3 | There is no Java, only Ruby. 4 | 5 | This is a sample ground for what a *pure* ruby Jenkins plugin would look like on its own. It is different 6 | than the jenkins-ruby-plugins-playground in that it is not "embedded" inside a vanilla Java plugin. It has 7 | its own structure that is completely independent. 8 | 9 | Inside this plugin are several extension points. 10 | 11 | # Running 12 | 13 | 1. use JRuby 14 | 1. `bundle` 15 | 1. `rake server` 16 | 17 | # Extensions 18 | 19 | ## Logging Wrapper 20 | [`LoggingWrapper`](https://github.com/cowboyd/jenkins-prototype-ruby-plugin/blob/master/models/logging_wrapper.rb). 21 | 22 | This is a trivial `BuildWrapper` that outputs a message to the console whenever a build starts and when it finishes. 23 | 24 | ## TestRootAction 25 | 26 | [`TestRootAction`](https://github.com/cowboyd/jenkins-prototype-ruby-plugin/blob/master/models/root_action.rb) demonstrates adding links to the main sidebar. 27 | 28 | ## ModelReloadAction 29 | 30 | ['ModelReloadAction'](https://github.com/cowboyd/jenkins-prototype-ruby-plugin/blob/master/models/root_action.rb#L50) 31 | 32 | reloads all of the Ruby classes in the plugin. Very useful for development! 33 | 34 | ## DirectoryListingAction 35 | 36 | https://github.com/cowboyd/jenkins-prototype-ruby-plugin/blob/master/models/root_action.rb#L72 37 | 38 | list the contents of the ruby plugin 39 | 40 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | 2 | load "#{File.dirname(__FILE__)}/.rake" if File.exists? '.rake' 3 | 4 | require 'jenkins/rake' 5 | Jenkins::Rake.install_tasks 6 | 7 | 8 | task :foo,:x do |t,args| 9 | puts "ARGS: #{args.inspect}" 10 | end 11 | 12 | 13 | desc "create a sample .rake file that allows you to provide environment overrides" 14 | task :rakedev do 15 | fail ".rake already exists" if File.exists?(".rake") 16 | File.open(".rake", "w") do |f| 17 | f.write<<-RAKE 18 | puts "Using devmods in #{__FILE__}" 19 | #override paths, environment, etc.... 20 | #require 'pathname' 21 | #$:.unshift Pathname(__FILE__).dirname.join('../jenkins-plugin-tools/lib').expand_path 22 | RAKE 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /models/directory_listing_root_action.rb: -------------------------------------------------------------------------------- 1 | require 'webrick' 2 | require 'logger' 3 | 4 | class DirectoryListingRootAction < Jenkins::Model::RootAction 5 | display_name 'Directory Listing' 6 | icon 'folder.png' 7 | url_path 'dir' 8 | 9 | def initialize(root = File.dirname(__FILE__)) 10 | @logger = Logger.new(STDERR) 11 | @config = { 12 | :HTTPVersion => '1.1', 13 | :Logger => @logger, 14 | :DirectoryIndex => ['index.html'], 15 | :MimeTypes => WEBrick::HTTPUtils::DefaultMimeTypes, 16 | } 17 | server = Struct.new(:config).new 18 | server.config = @config 19 | @servlet = WEBrick::HTTPServlet::FileHandler.new(server, root, :FancyIndexing => true) 20 | end 21 | 22 | include Java.jenkins.ruby.DoDynamic 23 | def doDynamic(request, response) 24 | begin 25 | req = WEBrick::HTTPRequest.new(@config) 26 | req.path_info = request.getRestOfPath() + "/" 27 | req.script_name = "" 28 | req.instance_variable_set("@path", request.getRestOfPath() + "/") 29 | req.instance_variable_set("@request_method", 'GET') 30 | res = WEBrick::HTTPResponse.new(@config) 31 | @servlet.do_GET(req, res) 32 | res.send_body(str = '') 33 | response.getWriter().print(str) 34 | rescue Exception => e 35 | @logger.error(e) 36 | end 37 | end 38 | end 39 | 40 | dir = DirectoryListingRootAction.new(File.expand_path('..', File.dirname(__FILE__))) 41 | Jenkins::Plugin.instance.register_extension(dir) 42 | -------------------------------------------------------------------------------- /models/logging_wrapper.rb: -------------------------------------------------------------------------------- 1 | 2 | ## 3 | # Output a message to the console when the build is to start 4 | # and when it has ended. 5 | class LoggingWrapper < Jenkins::Tasks::BuildWrapper 6 | 7 | display_name "Logging Build Wrapper" 8 | 9 | # Called some time before the build is to start. 10 | def setup(build, launcher, listener) 11 | listener.info "build will start" 12 | 13 | return {} # return an 'environment' object that gets passed to the tear down method 14 | end 15 | 16 | # Called some time when the build is finished. 17 | def teardown(build, listener, env) 18 | listener.info "build finished" 19 | end 20 | 21 | end 22 | -------------------------------------------------------------------------------- /models/model_reload_root_action.rb: -------------------------------------------------------------------------------- 1 | require 'jenkins/rack' 2 | 3 | class ModelReloadRootAction < Jenkins::Model::RootAction 4 | display_name 'Reload Ruby plugins' 5 | icon 'refresh.png' 6 | url_path 'reload_ruby_plugins' 7 | 8 | # TODO: no need to be a RackApp 9 | include Jenkins::RackSupport 10 | def call(env) 11 | # TODO: add to Jenkins::Plugin 12 | Jenkins::Plugin.instance.instance_eval do 13 | @peer.getExtensions().clear 14 | end 15 | Jenkins::Plugin.instance.load_models 16 | # TODO: is it enough for Jenkins/JRuby plugin for reloading? 17 | Sinatra.new(Sinatra::Base) { 18 | get('/') { redirect '/' } 19 | }.call(env) 20 | end 21 | end 22 | 23 | reload = ModelReloadRootAction.new 24 | Jenkins::Plugin.instance.register_extension(reload) 25 | -------------------------------------------------------------------------------- /models/test_builder.rb: -------------------------------------------------------------------------------- 1 | class TestBuilder < Jenkins::Tasks::Builder 2 | 3 | display_name "Test Builder" 4 | 5 | def initialize(attrs) 6 | p attrs 7 | end 8 | 9 | def prebuild(build, listener) 10 | listener.info "= build_var" 11 | log_hash(listener, build.build_var) 12 | listener.info "= env" 13 | log_hash(listener, build.env) 14 | end 15 | 16 | def log_hash(listener, hash) 17 | hash.each do |k, v| 18 | listener.info [k, ": ", v].join 19 | end 20 | end 21 | 22 | def perform(build, launcher, listener) 23 | listener.info "perform" 24 | launcher.execute("ls -l", :chdir => "/", :out => listener) 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /models/test_notifier_recorder.rb: -------------------------------------------------------------------------------- 1 | require 'jenkins/tasks/build_step' 2 | 3 | module Jenkins 4 | module Tasks 5 | class Notifier 6 | include Jenkins::Model 7 | include Jenkins::Model::Describable 8 | 9 | include BuildStep 10 | 11 | describe_as Java.hudson.tasks.Notifier 12 | end 13 | 14 | class Recorder 15 | include Jenkins::Model 16 | include Jenkins::Model::Describable 17 | 18 | include BuildStep 19 | 20 | describe_as Java.hudson.tasks.Recorder 21 | end 22 | end 23 | end 24 | 25 | require 'jenkins/plugin/proxies/build_step' 26 | 27 | module Jenkins 28 | class Plugin 29 | class Proxies 30 | class Notifier < Java.hudson.tasks.Notifier 31 | include Java.jenkins.ruby.Get 32 | include Jenkins::Plugin::Proxy 33 | 34 | include BuildStep 35 | 36 | def getDescriptor 37 | @plugin.descriptors[@object.class] 38 | end 39 | 40 | def get(name) 41 | @object.respond_to?(name) ? @object.send(name) : nil 42 | end 43 | end 44 | 45 | register Jenkins::Tasks::Notifier, Notifier 46 | 47 | class Recorder < Java.hudson.tasks.Recorder 48 | include Java.jenkins.ruby.Get 49 | include Jenkins::Plugin::Proxy 50 | 51 | include BuildStep 52 | 53 | def getDescriptor 54 | @plugin.descriptors[@object.class] 55 | end 56 | 57 | def get(name) 58 | @object.respond_to?(name) ? @object.send(name) : nil 59 | end 60 | end 61 | 62 | register Jenkins::Tasks::Recorder, Recorder 63 | end 64 | end 65 | end 66 | 67 | class TestNotifier < Jenkins::Tasks::Notifier 68 | display_name "Test Notifier" 69 | 70 | def prebuild(build, listener) 71 | listener.info "Notifier#prebuild" 72 | end 73 | 74 | def perform(build, launcher, listener) 75 | listener.info "Notifier#perform" 76 | end 77 | end 78 | 79 | class TestRecorder < Jenkins::Tasks::Recorder 80 | display_name "Test Recorder" 81 | 82 | def prebuild(build, listener) 83 | listener.info "Recorder#prebuild" 84 | end 85 | 86 | def perform(build, launcher, listener) 87 | listener.info "Recorder#perform" 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /models/test_publisher.rb: -------------------------------------------------------------------------------- 1 | class TestPublisher < Jenkins::Tasks::Publisher 2 | display_name "Test Publisher" 3 | 4 | def initialize(attrs) 5 | p attrs 6 | end 7 | 8 | def prebuild(build, listener) 9 | listener.info { 10 | "Test Publisher#prebuild" 11 | } 12 | end 13 | 14 | def perform(build, launcher, listener) 15 | listener.error { 16 | "Test Publisher#perform" 17 | } 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /models/test_root_action.rb: -------------------------------------------------------------------------------- 1 | require 'sinatra/base' 2 | require 'jenkins/rack' 3 | class SomeSinatraApp < Sinatra::Base 4 | get '/hi' do 5 | 'Hello world from Sinatra!' 6 | end 7 | end 8 | 9 | class TestRootAction < Jenkins::Model::RootAction 10 | display_name 'Test Root Action' 11 | icon 'gear.png' 12 | url_path 'root_action' 13 | 14 | # this part shows how to mount Rack app to take over the request handling entirely 15 | # to see this in action request "/root_action/hi" in your browser 16 | include Jenkins::RackSupport 17 | def call(env) 18 | SomeSinatraApp.new.call(env) 19 | end 20 | end 21 | 22 | Jenkins::Plugin.instance.register_extension(TestRootAction) 23 | -------------------------------------------------------------------------------- /models/travis_script_builder.rb: -------------------------------------------------------------------------------- 1 | require 'yaml' 2 | 3 | class TravisScriptBuilder < Jenkins::Tasks::Builder 4 | 5 | display_name "Travis Builder" 6 | 7 | # TODO: better to use travis-worker instead of re-implementing it? 8 | def prebuild(build, listener) 9 | init(build, nil, listener) 10 | listener.info "Prebuild" 11 | 12 | travis_file = workspace + '.travis.yml' 13 | unless travis_file.exist? 14 | listener.error"Travis config `#{travis_file}' not found" 15 | raise "Travis config file not found" 16 | end 17 | listener.info "Found travis file: #{travis_file}" 18 | @config = YAML.load(travis_file.read) 19 | 20 | @gemfile = @config['gemfile'] || 'Gemfile' 21 | @gemfile = nil unless (workspace + @gemfile).exist? 22 | @config['script'] ||= @gemfile ? "bundle exec rake" : 'rake' 23 | 24 | listener.info "Prebuild finished" 25 | end 26 | 27 | def perform(build, launcher, listener) 28 | init(build, launcher, listener) 29 | listener.info "Build" 30 | 31 | env = setup_env 32 | install_dependencies 33 | run_scripts(env) 34 | 35 | listener.info "Build finished" 36 | end 37 | 38 | private 39 | 40 | def init(build, launcher, listener) 41 | @build, @launcher, @listener = build, launcher, listener 42 | end 43 | 44 | def launcher 45 | @launcher 46 | end 47 | 48 | def listener 49 | @listener 50 | end 51 | 52 | def workspace 53 | @build.workspace 54 | end 55 | 56 | # TODO: we should have common gem repository 57 | def default_env 58 | {'BUNDLE_PATH' => '.'} 59 | end 60 | 61 | def setup_env 62 | env = default_env 63 | if @gemfile 64 | env['BUNDLE_GEMFILE'] = @gemfile 65 | end 66 | Array(@config['env']).each do |line| 67 | key, value = line.split(/\s*=\s*/, 2) 68 | env[key] = value 69 | end 70 | listener.info "Additional environment variable(s): #{env.inspect}" 71 | env 72 | end 73 | 74 | def install_dependencies 75 | if @gemfile 76 | env = default_env 77 | script = "bundle install" 78 | script += " #{@config['bundler_args']}" if @config['bundler_args'] 79 | exec(env, script) 80 | end 81 | end 82 | 83 | def run_scripts(env) 84 | %w{before_script script after_script}.each do |type| 85 | next unless @config.key?(type) 86 | listener.info "Start #{type}: " + @config[type] 87 | scan_multiline_scripts(@config[type]).each do |script| 88 | exec(env, script) 89 | end 90 | end 91 | end 92 | 93 | def scan_multiline_scripts(script) 94 | case script 95 | when Array 96 | script 97 | else 98 | script.to_s.split("\n") 99 | end 100 | end 101 | 102 | def exec(env, command) 103 | listener.info "Launching command: #{command}, with environment: #{env.inspect}" 104 | result = launcher.execute(env, command, :chdir => workspace, :out => listener) 105 | listener.info "Command execution finished with #{result}" 106 | raise "command execution failed" if result != 0 107 | end 108 | end 109 | -------------------------------------------------------------------------------- /models/ui_samples.rb: -------------------------------------------------------------------------------- 1 | module UISamples 2 | 3 | class Root < Jenkins::Model::RootAction 4 | icon 'gear.gif' 5 | display_name 'UI Samples (Ruby)' 6 | url_path 'ui-samples-ruby' 7 | 8 | include Java.jenkins.ruby.Get 9 | def get(name) 10 | all.find { |action| action.url_path == name } 11 | end 12 | 13 | def all 14 | BaseAction.all 15 | end 16 | end 17 | 18 | class BaseAction < Jenkins::Model::Action 19 | icon 'gear.gif' 20 | 21 | module Inherited 22 | def inherited(cls) 23 | cls.extend(ClassMethods) 24 | cls.send(:include, InstanceMethods) 25 | cls.class_eval do 26 | display_name simple_name 27 | url_path path_name 28 | end 29 | end 30 | end 31 | extend Inherited 32 | 33 | module ClassMethods 34 | def new(*arg) 35 | obj = allocate 36 | obj.send(:initialize, *arg) 37 | BaseAction.all << obj 38 | obj 39 | end 40 | 41 | def display_name(name = nil) 42 | @display_name = name if name 43 | @display_name 44 | end 45 | 46 | def description(desc = nil) 47 | @description = desc if desc 48 | @description 49 | end 50 | end 51 | 52 | module InstanceMethods 53 | def display_name 54 | self.class.display_name 55 | end 56 | 57 | def description 58 | self.class.description 59 | end 60 | end 61 | 62 | class << self 63 | def all 64 | @all ||= [] 65 | end 66 | 67 | def simple_name 68 | self.name.sub(/\A.*::/, '') 69 | end 70 | 71 | def path_name 72 | underscore(simple_name) 73 | end 74 | 75 | private 76 | 77 | def underscore(word) 78 | word = word.to_s.dup 79 | word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2') 80 | word.gsub!(/([a-z\d])([A-Z])/,'\1_\2') 81 | word.tr!("-", "_") 82 | word.downcase! 83 | word 84 | end 85 | end 86 | # TODO: for reloading. Caching instances is a memory leak. We should find another way. 87 | all.clear 88 | 89 | # TODO: sample.jelly does not pick up 'it' correctly now. 90 | def sourceFiles 91 | [SourceFile.new(path_name + '.rb'), SourceFile.new(path_name + "/index.erb")] 92 | end 93 | end 94 | 95 | class SourceFile 96 | attr_reader :name 97 | 98 | def initialize(name) 99 | @name = name 100 | end 101 | 102 | def resolve 103 | @name # TODO: need URL 104 | end 105 | 106 | def content 107 | # TODO 108 | end 109 | end 110 | end 111 | 112 | Jenkins::Plugin.instance.register_extension(UISamples::Root) 113 | -------------------------------------------------------------------------------- /models/ui_samples/auto_complete_text_box.rb: -------------------------------------------------------------------------------- 1 | module UISamples 2 | 3 | # WARNING: This port is incomplete. 4 | class AutoCompleteTextBox < BaseAction 5 | description "[NOT YET] Provide auto-completion to the text box" 6 | 7 | # TODO: how do we implement AutoCompletionCandidates? 8 | 9 | STATES = [ 10 | "Alabama", 11 | "Alaska", 12 | "Arizona", 13 | "Arkansas", 14 | "California", 15 | "Colorado", 16 | "Connecticut", 17 | "Delaware", 18 | "Florida", 19 | "Georgia", 20 | "Hawaii", 21 | "Idaho", 22 | "Illinois", 23 | "Indiana", 24 | "Iowa", 25 | "Kansas", 26 | "Kentucky", 27 | "Louisiana", 28 | "Maine", 29 | "Maryland", 30 | "Massachusetts", 31 | "Michigan", 32 | "Minnesota", 33 | "Mississippi", 34 | "Missouri", 35 | "Montana", 36 | "Nebraska", 37 | "Nevada", 38 | "New Hampshire", 39 | "New Jersey", 40 | "New Mexico", 41 | "New York", 42 | "North Carolina", 43 | "North Dakota", 44 | "Ohio", 45 | "Oklahoma", 46 | "Oregon", 47 | "Pennsylvania", 48 | "Rhode Island", 49 | "South Carolina", 50 | "South Dakota", 51 | "Tennessee", 52 | "Texas", 53 | "Utah", 54 | "Vermont", 55 | "Virginia", 56 | "Washington", 57 | "West Virginia", 58 | "Wisconsin", 59 | "Wyoming" 60 | ] 61 | end 62 | end 63 | 64 | Jenkins::Plugin.instance.register_extension(UISamples::AutoCompleteTextBox) 65 | -------------------------------------------------------------------------------- /models/ui_samples/dropdown_list.rb: -------------------------------------------------------------------------------- 1 | module UISamples 2 | 3 | # WARNING: This port is incomplete you'll see empty dropdown list now. 4 | # See TODO's below. 5 | class DropdownList < BaseAction 6 | description "[NOT YET] Show different form elements based on choice in a <select> control" 7 | 8 | def fruit 9 | nil 10 | end 11 | 12 | # TODO: It doesn't work. We need to handle right descriptors here for (st:include page) in view. 13 | def fruit_descriptors 14 | [Apple.new, Banana.new] 15 | end 16 | 17 | class Fruit < Action 18 | # include Jenkins::Model 19 | # include Jenkins::Model::Describable 20 | 21 | # TODO: Should create Java side Descriptor class and use Descriptor#getConfigPage. Is it worth trying? 22 | def config_page 23 | "/#{name_to_path}/config" 24 | end 25 | 26 | def self.display_name(name = nil) 27 | @display_name = name if name 28 | @display_name 29 | end 30 | 31 | def display_name 32 | self.class.display_name 33 | end 34 | 35 | def name_to_path 36 | self.class.name.split('::').join('/') 37 | end 38 | end 39 | 40 | class Apple < Fruit 41 | display_name "Apple" 42 | end 43 | 44 | class Banana < Fruit 45 | display_name "Banana" 46 | end 47 | end 48 | end 49 | 50 | Jenkins::Plugin.instance.register_extension(UISamples::DropdownList) 51 | -------------------------------------------------------------------------------- /models/ui_samples/java_script_proxy.rb: -------------------------------------------------------------------------------- 1 | module UISamples 2 | 3 | # WARNING: This port is incomplete now. 4 | class JavaScriptProxy < BaseAction 5 | description "[NOT YET] Use JavaScript proxy objects to access server-side Java objects from inside the browser." 6 | 7 | def initialize 8 | @i = 0 9 | end 10 | 11 | # TODO: let stapler recognize it. 12 | def increment(n) 13 | @i += n 14 | end 15 | end 16 | end 17 | 18 | Jenkins::Plugin.instance.register_extension(UISamples::JavaScriptProxy) 19 | -------------------------------------------------------------------------------- /models/ui_samples/progress_bar.rb: -------------------------------------------------------------------------------- 1 | module UISamples 2 | 3 | class ProgressBar < BaseAction 4 | description "Shows you how to use the progress bar widget that's used in the executor view and other places" 5 | end 6 | end 7 | 8 | Jenkins::Plugin.instance.register_extension(UISamples::ProgressBar) 9 | -------------------------------------------------------------------------------- /models/ui_samples/syntax_highlighted_text_area.rb: -------------------------------------------------------------------------------- 1 | module UISamples 2 | 3 | class SyntaxHighlightedTextArea < BaseAction 4 | description "Syntax-highlighted text area powered by CodeMirror" 5 | end 6 | end 7 | 8 | Jenkins::Plugin.instance.register_extension(UISamples::SyntaxHighlightedTextArea) 9 | -------------------------------------------------------------------------------- /ruby-prototype.pluginspec: -------------------------------------------------------------------------------- 1 | 2 | Jenkins::Plugin::Specification.new do |plugin| 3 | plugin.name = 'ruby-prototype' 4 | plugin.version = '0.1.0' 5 | plugin.description = 'a pure ruby playground for Jenkins plugins' 6 | plugin.url = 'https://github.com/cowboyd/jenkins-prototype-ruby-plugin' 7 | 8 | plugin.depends_on 'ruby-runtime', '0.3' 9 | end 10 | -------------------------------------------------------------------------------- /views/lib/README.txt: -------------------------------------------------------------------------------- 1 | Files under this directory is copied from Jenkins source repository. 2 | $JENKINS_SRC/ui-samples-plugin/src/main/resources/lib 3 | -------------------------------------------------------------------------------- /views/lib/samples/sample.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | Page layout for UI samples and variable bindings that emulate the form environment. 28 | 29 | Page title 30 | 31 | 32 | 33 | 34 | 35 | 36 |

${title}

37 |

38 | 39 |

40 |

Source Files

41 | 46 |

Sample

47 | 48 |
49 |
50 |
51 | -------------------------------------------------------------------------------- /views/lib/samples/taglib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cowboyd/jenkins-prototype-ruby-plugin/6b337bd4e44d6d1098d013a5a6845ec06de1a35e/views/lib/samples/taglib -------------------------------------------------------------------------------- /views/logging_wrapper/config.erb: -------------------------------------------------------------------------------- 1 | <% f = taglib("/lib/form") %> 2 | <% f.entry do %> 3 |

4 | There's no configuration at this moment! Now: <%= Time.now.to_s %> 5 |

6 | <% end %> -------------------------------------------------------------------------------- /views/test_builder/config.erb: -------------------------------------------------------------------------------- 1 | <% f = taglib("/lib/form") %> 2 | <% f.entry do %> 3 |

4 | There's no configuration at this moment. Now: <%= Time.now.to_s %> 5 |

6 | <% end %> -------------------------------------------------------------------------------- /views/test_root_action/index.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | I am <%= it.class %>!! 5 |

6 |

7 | 1+1 = <%= 1+1 %> 8 |

9 |

10 | take me to a page rendered by Sinatra 11 |

12 | 13 | 14 | -------------------------------------------------------------------------------- /views/ui_samples/README.txt: -------------------------------------------------------------------------------- 1 | Files under this directory is based on Jenkins source repository. 2 | $JENKINS_SRC/ui-samples-plugin/src/main/resources/jenkins/plugins/ui_samples 3 | 4 | NaHi ported Jelly scripts to ERb. 5 | -------------------------------------------------------------------------------- /views/ui_samples/auto_complete_text_box/index.erb: -------------------------------------------------------------------------------- 1 | <% 2 | =begin 3 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 |
35 |
36 |
37 |
38 | =end 39 | %> 40 | <% f = taglib("/lib/form") %> 41 | <% s = taglib("/lib/samples") %> 42 | <% s.sample(:title => "Dynamic ComboBox Sample") do %> 43 |
44 | 45 | <% f.entry(:title => "U.S. State", :field => "state") do %> 46 | <% f.textbox %> 47 | <% end %> 48 |
49 |
50 | <% end %> 51 | -------------------------------------------------------------------------------- /views/ui_samples/dropdown_list/apple/config.erb: -------------------------------------------------------------------------------- 1 | <% 2 | =begin 3 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | =end 33 | %> 34 | <% 35 | f = taglib("/lib/form") 36 | f.entry(:title => "Seeds") do 37 | f.textbox(:class => "number", name => "seeds", :value => fruit.seeds) 38 | end 39 | %> 40 | -------------------------------------------------------------------------------- /views/ui_samples/dropdown_list/banana/config.erb: -------------------------------------------------------------------------------- 1 | <% 2 | =begin 3 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | =end 33 | %> 34 | <% 35 | f = taglib("/lib/form") 36 | f.entry(:title => "") do 37 | f.checkbox(:name => "yellow", checked => fruit.yellow, :title => "Yellow?") 38 | end 39 | %> 40 | -------------------------------------------------------------------------------- /views/ui_samples/dropdown_list/index.erb: -------------------------------------------------------------------------------- 1 | <% 2 | =begin 3 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
50 |
51 |
52 |
53 | =end 54 | %> 55 | <% 56 | s = taglib("/lib/samples") 57 | f = taglib("/lib/form") 58 | st = taglib("jelly:stapler") 59 | 60 | s.sample(:title => "Dropdown List Sample") do 61 | %> 62 |
63 | 64 | <% 65 | f.dropdownList(:name => "fruit", :title => "Fruits") do 66 | it.fruit_descriptors.each_with_index do |descriptor, idx| 67 | selected = true if it.fruit && descriptor == it.fruit.descriptor 68 | f.dropdownListBlock(:title => descriptor.display_name, :value => idx, :selected => selected, :staplerClass => descriptor.class.name) do 69 | st.include(:page => descriptor.config_page, :from => descriptor) 70 | end 71 | end 72 | end 73 | f.entry(:title => "") do 74 | f.submit(:value => "Submit") 75 | end 76 | %> 77 |
78 |
79 | <% 80 | end 81 | %> 82 | -------------------------------------------------------------------------------- /views/ui_samples/java_script_proxy/index.erb: -------------------------------------------------------------------------------- 1 | <% 2 | =begin 3 | 26 | 27 | 28 | 29 |

30 | In Jenkins, you can export arbitrary server-side Java object to JavaScript via a proxy, 31 | then invoke their methods from JavaScript. See the Wiki for more details. 32 | In this sample, we call a method on the server to increment a counter. This object is a singleton, 33 | so you'll see the same counter value across all the browsers. 34 |

35 | 36 | 37 | 38 |
39 | 46 | 47 | 48 | =end 49 | %> 50 | <% s = taglib("/lib/samples") %> 51 | <% st = taglib("jelly:stapler") %> 52 | <% s.sample(:tile => "AJAX with JavaScript Proxy") do %> 53 |

54 | In Jenkins, you can export arbitrary server-side Java object to JavaScript via a proxy, 55 | then invoke their methods from JavaScript. See the Wiki for more details. 56 | In this sample, we call a method on the server to increment a counter. This object is a singleton, 57 | so you'll see the same counter value across all the browsers. 58 |

59 | 60 | <% st.bind(:var => "a", :value => it) %> 61 | 62 |
63 | 70 | <% end %> 71 | -------------------------------------------------------------------------------- /views/ui_samples/progress_bar/index.erb: -------------------------------------------------------------------------------- 1 | <% 2 | =begin 3 | package jenkins.plugins.ui_samples.ProgressBar; 4 | 5 | import lib.JenkinsTagLib 6 | 7 | def st=namespace("jelly:stapler") 8 | 9 | t=namespace(JenkinsTagLib.class) 10 | 11 | namespace("/lib/samples").sample(title:_("Progress Bar")) { 12 | // in this sample, we add extra margin around them 13 | style(".progress-bar {margin:1em;}") 14 | p("This page shows you how to use the progress bar widget") 15 | 16 | p("The 'pos' parameter controls the degree of progress, 0-100") 17 | t.progressBar(pos:30) 18 | t.progressBar(pos:60) 19 | t.progressBar(pos:90) 20 | p("-1 will draw the progress bar in the 'indeterminate' state"); 21 | t.progressBar(pos:-1) 22 | 23 | p("The 'red' parameter turns the progress bar to red. Used to indicate that it's overdue") 24 | t.progressBar(pos:99, red:true) 25 | t.progressBar(pos:-1, red:true) 26 | 27 | p("Tooltip can be added with the 'tooltip' parameter. It can contain arbitrary HTML. Hover your mouse below to see.") 28 | t.progressBar(pos:70, tooltip:"Allows arbitrary html") 29 | 30 | p("Hyperlink can be added with the 'href' pointer. Click the progress bar below") 31 | t.progressBar(pos:70, href:"http://jenkins-ci.org/") 32 | } 33 | =end 34 | %> 35 | <% s = taglib("/lib/samples") %> 36 | <% t = taglib("/lib/hudson") %> 37 | <% st = taglib("jelly:stapler") %> 38 | <% s.sample(:title => "Progress Bar") do %> 39 | 40 |

This page shows you how to use the progress bar widget

41 | 42 |

The 'pos' parameter controls the degree of progress, 0-100

43 | <%= t.progressBar(:pos => 30) %> 44 | <%= t.progressBar(:pos => 60) %> 45 | <%= t.progressBar(:pos => 90) %> 46 | 47 |

-1 will draw the progress bar in the 'indeterminate' state

48 | <%= t.progressBar(:pos => -1) %> 49 | 50 |

The 'red' parameter turns the progress bar to red. Used to indicate that it's overdue

51 | <%= t.progressBar(:pos => 99, :red => true) %> 52 | <%= t.progressBar(:pos => -1, :red => true) %> 53 | 54 |

Tooltip can be added with the 'tooltip' parameter. It can contain arbitrary HTML. Hover your mouse below to see.

55 | <%= t.progressBar(:pos => 70, :tooltip => "Allows arbitrary html") %> 56 | 57 |

Hyperlink can be added with the 'href' pointer. Click the progress bar below

58 | <%= t.progressBar(:pos => 70, :href => "http://jenkins-ci.org/") %> 59 | <% end %> 60 | -------------------------------------------------------------------------------- /views/ui_samples/root/index.erb: -------------------------------------------------------------------------------- 1 | <% 2 | =begin 3 | 26 | 27 | 28 | 29 | 30 |

UI Samples

31 | 32 | 33 | 34 | 36 | 37 |
38 | 39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | =end 47 | %> 48 | <% l = taglib("/lib/layout") %> 49 | <% t = taglib("/lib/hudson") %> 50 | <% l.layout(:title => "UI Samples") do %> 51 | <% l.main_panel do %> 52 |

UI Samples

53 | 54 | <% it.all.each do |s| %> 55 | <% t.summary(:icon => "document.gif", :iconOnly => true) do %> 56 | 57 |
<%= s.description %>
58 | <% end %> 59 | <% end %> 60 |
61 | <% end %> 62 | <% end %> 63 | -------------------------------------------------------------------------------- /views/ui_samples/syntax_highlighted_text_area/index.erb: -------------------------------------------------------------------------------- 1 | <% 2 | =begin 3 | def st=namespace("jelly:stapler") 4 | 5 | namespace("/lib/samples").sample(title:_("Syntax Highlighted Text Area")) { 6 | p("CodeMirror can be used to turn ordinary text area into syntax-highlighted content-assistable text area") 7 | 8 | // this loads the necessary JavaScripts, if it hasn't loaded already 9 | // the first we load is the mode definition file (mode as in Emacs mode) 10 | // the second is the theme. 11 | // 12 | // for other modes, look for "clike.js" in your IDE and see adjacent folders. 13 | st.adjunct(includes:"org.kohsuke.stapler.codemirror.mode.clike.clike") 14 | st.adjunct(includes:"org.kohsuke.stapler.codemirror.theme.default") 15 | 16 | // TODO: adjunct tag doesn't work because 'wroteHEAD' is not set correctly 17 | // TODO: provide abstraction that hides CSS hookup 18 | 19 | // this text area is what we convert to the super text area 20 | // we use CSS class to hook up the initialization script. In this particular demo, 21 | // the ID attribute can be used, but in more general case (such as when you use this in your Builder, etc., 22 | // a single web page may end up containing multiple instances of such text area, so the CSS class works better. 23 | textarea("class":"my-groovy-textbox", style:"width:100%; height:10em") 24 | 25 | // see CodeMirror web site for more about how to control the newly instantiated text area. 26 | script(""" 27 | hudsonRules["TEXTAREA.my-groovy-textbox"] = function(e) { 28 | var w = CodeMirror.fromTextArea(e,{ 29 | mode:"text/x-groovy", 30 | lineNumbers: true 31 | }).getWrapperElement(); 32 | w.setAttribute("style","border:1px solid black; margin-top: 1em; margin-bottom: 1em") 33 | } 34 | """) 35 | } 36 | =end 37 | %> 38 | <% st = taglib("jelly:stapler") %> 39 | <% taglib("/lib/samples").sample(:title => "Syntax Highlighted Text Area") do %> 40 |

41 | CodeMirror can be used to turn ordinary text area into syntax-highlighted content-assistable text area. 42 |

43 | 44 | <% st.adjunct(:includes => "org.kohsuke.stapler.codemirror.mode.clike.clike") %> 45 | <% st.adjunct(:includes => "org.kohsuke.stapler.codemirror.theme.default") %> 46 | 47 | 48 | 49 | 58 | <% end %> 59 | --------------------------------------------------------------------------------