jenkins-plugin-runtime 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/.gitignore +7 -0
  2. data/.travis.yml +2 -0
  3. data/Gemfile +4 -0
  4. data/Rakefile +21 -0
  5. data/jenkins-plugin-runtime.gemspec +30 -0
  6. data/lib/jenkins/launcher.rb +15 -0
  7. data/lib/jenkins/model.rb +91 -0
  8. data/lib/jenkins/model/action.rb +37 -0
  9. data/lib/jenkins/model/build.rb +21 -0
  10. data/lib/jenkins/model/describable.rb +75 -0
  11. data/lib/jenkins/model/descriptor.rb +40 -0
  12. data/lib/jenkins/model/listener.rb +47 -0
  13. data/lib/jenkins/plugin.rb +141 -0
  14. data/lib/jenkins/plugin/cli.rb +20 -0
  15. data/lib/jenkins/plugin/proxies.rb +131 -0
  16. data/lib/jenkins/plugin/proxies/build_wrapper.rb +50 -0
  17. data/lib/jenkins/plugin/proxies/builder.rb +22 -0
  18. data/lib/jenkins/plugin/proxy.rb +76 -0
  19. data/lib/jenkins/plugin/runtime.rb +13 -0
  20. data/lib/jenkins/plugin/runtime/version.rb +7 -0
  21. data/lib/jenkins/slaves/cloud.rb +9 -0
  22. data/lib/jenkins/tasks/build_wrapper.rb +39 -0
  23. data/lib/jenkins/tasks/builder.rb +33 -0
  24. data/spec/jenkins/launcher_spec.rb +8 -0
  25. data/spec/jenkins/model/action_spec.rb +36 -0
  26. data/spec/jenkins/model/build_spec.rb +8 -0
  27. data/spec/jenkins/model/describable_spec.rb +51 -0
  28. data/spec/jenkins/model/listener_spec.rb +31 -0
  29. data/spec/jenkins/model_spec.rb +100 -0
  30. data/spec/jenkins/plugin/proxies/build_wrapper_spec.rb +25 -0
  31. data/spec/jenkins/plugin/proxies/builder_spec.rb +24 -0
  32. data/spec/jenkins/plugin/proxies/proxy_helper.rb +24 -0
  33. data/spec/jenkins/plugin/proxies_spec.rb +148 -0
  34. data/spec/jenkins/plugin/proxy_spec.rb +43 -0
  35. data/spec/jenkins/plugin_spec.rb +7 -0
  36. data/spec/jenkins/tasks/build_wrapper_spec.rb +7 -0
  37. data/spec/jenkins/tasks/builder_spec.rb +8 -0
  38. data/spec/spec_helper.rb +11 -0
  39. data/src/jenkins/ruby/DoDynamic.java +18 -0
  40. data/src/jenkins/ruby/Get.java +18 -0
  41. metadata +175 -0
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ .rvmrc
2
+ *.gem
3
+ .bundle
4
+ .idea
5
+ Gemfile.lock
6
+ pkg/*
7
+ target/
data/.travis.yml ADDED
@@ -0,0 +1,2 @@
1
+ rvm:
2
+ - jruby
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in jenkins-plugins.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ require 'jenkins/war'
8
+ Jenkins::War.classpath
9
+ ClassPath = FileList[File.join(ENV['HOME'], '.jenkins', 'wars', Jenkins::War::VERSION, "**/*.jar")].to_a.join(':')
10
+
11
+ desc "compile java source code"
12
+ task "compile" => "target" do
13
+ puts command = "javac -classpath #{ClassPath} #{FileList['src/**/*.java']} -d target"
14
+ system(command)
15
+ end
16
+
17
+ require 'rake/clean'
18
+ directory "target"
19
+ CLEAN.include("target")
20
+
21
+ task :default => [:compile, :spec]
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "jenkins/plugin/runtime/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "jenkins-plugin-runtime"
7
+ s.version = Jenkins::Plugin::Runtime::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Charles Lowell"]
10
+ s.email = ["cowboyd@thefrontside.net"]
11
+ s.homepage = "http://github.com/cowboyd/jenkins-plugins.rb"
12
+ s.summary = %q{Runtime support libraries for Jenkins Ruby plugins}
13
+ s.description = %q{I'll think of a better description later, but if you're reading this, then I haven't}
14
+
15
+ s.rubyforge_project = "jenkins-plugin-runtime"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency "json"
23
+
24
+ s.add_development_dependency "rake"
25
+ s.add_development_dependency "rspec", "~> 2.0"
26
+ s.add_development_dependency "rspec-spies"
27
+ s.add_development_dependency "cucumber", "~> 1.0"
28
+ s.add_development_dependency "jenkins-war"
29
+
30
+ end
@@ -0,0 +1,15 @@
1
+
2
+ module Jenkins
3
+
4
+ # Launch processes on build slaves. No functionality is currently exposed
5
+ class Launcher
6
+ # the nantive hudson.Launcher object
7
+ attr_reader :native
8
+
9
+ def initialize(native = nil)
10
+ @native = native
11
+ end
12
+
13
+ Plugin::Proxies.register self, Java.hudson.Launcher
14
+ end
15
+ end
@@ -0,0 +1,91 @@
1
+
2
+ module Jenkins
3
+ module Model
4
+
5
+ module Included
6
+ def included(cls)
7
+ super(cls)
8
+ if cls.class == Module
9
+ cls.extend(Included)
10
+ else
11
+ cls.extend(Inherited)
12
+ cls.extend(ClassDisplayName)
13
+ cls.extend(Transience)
14
+ cls.send(:include, InstanceDisplayName)
15
+ end
16
+ Model.descendant(cls)
17
+ end
18
+ end
19
+ extend Included
20
+
21
+ module Inherited
22
+ def inherited(cls)
23
+ super(cls)
24
+ Model.descendant(cls)
25
+ cls.extend(Inherited)
26
+ end
27
+ end
28
+
29
+ module InstanceDisplayName
30
+ # Get the display name of this Model. This value will be used as a default
31
+ # whenever this model needs to be shown in the UI. If no display name has
32
+ # been set, then it will use the Model's class name.
33
+ #
34
+ # @return [String] the display name
35
+ def display_name
36
+ self.class.display_name
37
+ end
38
+ end
39
+
40
+ module ClassDisplayName
41
+
42
+ # Set or get the display name of this Model Class.
43
+ #
44
+ # If `name` is not nil, then sets the display name.
45
+ # @return [String] the display name
46
+ def display_name(name = nil)
47
+ name.nil? ? @display_name || self.name : @display_name = name.to_s
48
+ end
49
+ end
50
+
51
+ module Transience
52
+
53
+ # Mark a set of properties that should not be persisted as part of this Model's lifecycle.
54
+ #
55
+ # Jenkins supports transparent persistent
56
+ def transient(*properties)
57
+ properties.each do |p|
58
+ transients[p.to_sym] = true
59
+ end
60
+ end
61
+
62
+ def transient?(property)
63
+ transients.keys.member?(property.to_sym) || (superclass < Model && superclass.transient?(property))
64
+ end
65
+
66
+ def transients
67
+ @transients ||= {}
68
+ end
69
+ end
70
+
71
+ module Descendants
72
+ def descendant(mod)
73
+ @descendants ||= clear
74
+ @descendants[mod] = true
75
+ end
76
+
77
+ def descendants
78
+ @descendants.keys
79
+ end
80
+
81
+ def clear
82
+ @descendants = {}
83
+ end
84
+
85
+ def descendant?(cls)
86
+ @descendants[cls]
87
+ end
88
+ end
89
+ extend Descendants
90
+ end
91
+ end
@@ -0,0 +1,37 @@
1
+
2
+ module Jenkins
3
+ module Model
4
+ module Action
5
+ include Model
6
+
7
+ module Included
8
+ def included(cls)
9
+ super(cls)
10
+ if cls.class == Module
11
+ cls.extend(Included)
12
+ else
13
+ cls.extend(ClassMethods)
14
+ cls.send(:include, InstanceMethods)
15
+ end
16
+ end
17
+ end
18
+ extend Included
19
+
20
+ # def included(cls)
21
+ # super(cls)
22
+ # cls.send(:include)
23
+ # end
24
+ module InstanceMethods
25
+ def icon
26
+ self.class.icon
27
+ end
28
+ end
29
+ #
30
+ module ClassMethods
31
+ def icon(path = nil)
32
+ path.nil? ? @path : @path = path.to_s
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,21 @@
1
+
2
+ module Jenkins
3
+ module Model
4
+ ##
5
+ # Represents a single build. In general, you won't need this
6
+ #
7
+ class Build
8
+
9
+ ##
10
+ # the Hudson::Model::AbstractBuild represented by this build
11
+ attr_reader :native
12
+
13
+ def initialize(native = nil)
14
+ @native = native
15
+ end
16
+
17
+ Jenkins::Plugin::Proxies.register self, Java.hudson.model.AbstractBuild
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,75 @@
1
+
2
+ module Jenkins
3
+ module Model
4
+
5
+ # Register a Ruby class as a Jenkins extension point
6
+
7
+ # When Jenkins is searching for all the extension points of a particular
8
+ # type... let's say `Builder` for example. It first asks for all the `Descriptor`s
9
+ # registered to describe the `Builder` type. It will then use the descriptors
10
+ # it finds to do things like construct and validate the extension objects.
11
+ #
12
+ # It helps me to think about the Jenkins `Descriptor` as a Ruby class. It is a
13
+ # factory for instances, and contains data about what those instances can do.
14
+ #
15
+ # This module, when included, provides a single class method `describe_as`
16
+ # which tell Jenkins in effect "when you are looking for Java Classes of this type"
17
+ # you can use this ruby class too. e.g.
18
+ #
19
+ # class Builder
20
+ # include Jenkins::Model::Describeable
21
+ # describe_as Java.hudson.tasks.Builder
22
+ # end
23
+ #
24
+ # behind the scenes, this creates a `Descriptor` instance registered against the java type
25
+ # `Java.hudson.tasks.Builder`. Now, any time Jenkins asks about what kind of `hudson.tasks.Builder`s there
26
+ # are in the system, this class will come up.
27
+ #
28
+ # This class should generally not be needed by plugin authors since it is part of the
29
+ # glue layer and not the public runtime API.
30
+ module Describable
31
+ DescribableError = Class.new(StandardError)
32
+
33
+ module DescribeAs
34
+ def describe_as cls
35
+ if defined?(cls.java_class) && cls.is_a?(Class)
36
+ @describe_as_type = cls.java_class
37
+ else
38
+ fail DescribableError, "#{cls.class.inspect} is not an instance of java.lang.Class"
39
+ end
40
+ end
41
+ def describe_as_type
42
+ @describe_as_type
43
+ end
44
+ end
45
+
46
+ # When a Describable class is subclassed, make it also Describable
47
+ module Inherited
48
+ def inherited(cls)
49
+ super(cls)
50
+ cls.extend Inherited
51
+ describe_as_type = @describe_as_type
52
+ cls.class_eval do
53
+ @describe_as_type = describe_as_type
54
+ end
55
+ if Jenkins::Plugin.instance
56
+ Jenkins::Plugin.instance.register_describable(cls, describe_as_type)
57
+ end
58
+ end
59
+ end
60
+
61
+ module Included
62
+ def included(mod)
63
+ super
64
+ if mod.is_a? Class
65
+ mod.extend DescribeAs
66
+ mod.extend Inherited
67
+ else
68
+ warn "tried to include Describable into a Module. Are you sure?"
69
+ end
70
+ end
71
+ end
72
+ self.extend Included
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,40 @@
1
+
2
+ require 'json'
3
+
4
+ module Jenkins
5
+ module Model
6
+ class Descriptor < Java.hudson.model.Descriptor
7
+
8
+ def initialize(impl, plugin, java_type)
9
+ super(Java.org.jruby.RubyObject.java_class)
10
+ @impl, @plugin, @java_type = impl, plugin, java_type
11
+ end
12
+
13
+ def getDisplayName
14
+ @impl.display_name
15
+ end
16
+
17
+ def getT()
18
+ @java_type
19
+ end
20
+
21
+ def newInstance(request, form)
22
+ properties = JSON.parse(form.toString(2))
23
+ properties.delete("kind")
24
+ properties.delete("stapler-class")
25
+ instance = @plugin.export(construct(properties))
26
+ puts "instance created: #{instance}"
27
+ return instance
28
+ end
29
+
30
+ private
31
+
32
+ def construct(attrs)
33
+ @impl.new(attrs)
34
+ rescue ArgumentError
35
+ @impl.new
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,47 @@
1
+
2
+ module Jenkins
3
+ module Model
4
+
5
+ # Receive/Send events about a running task
6
+ class Listener
7
+
8
+ # the underlying hudson.model.TaskListener object
9
+ attr_reader :native
10
+
11
+ def initialize(native = nil)
12
+ @native = native
13
+ end
14
+
15
+ ##
16
+ # Insert a clickable hyperlink into this tasks's output
17
+ # @param [String] url the link target
18
+ # @param [String] text the link content
19
+ def hyperlink(url, text)
20
+ @native.hyperlink(url, text)
21
+ end
22
+
23
+ ##
24
+ # Append a message to the task output.
25
+ # @param [String] msg the message
26
+ def log(msg)
27
+ @native.getLogger().write(msg.to_s)
28
+ end
29
+
30
+ ##
31
+ # Append an error message to the task output.
32
+ # @param [String] msg the error message
33
+ def error(msg)
34
+ @native.error(msg.to_s)
35
+ end
36
+
37
+ ##
38
+ # Append a fatal error message to the task output
39
+ # @param [String] msg the fatal error message
40
+ def fatal(msg)
41
+ @native.fatalError(msg.to_s)
42
+ end
43
+
44
+ Jenkins::Plugin::Proxies.register self, Java.hudson.util.AbstractTaskListener
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,141 @@
1
+
2
+ require 'pathname'
3
+
4
+ module Jenkins
5
+ # Acts as the primary gateway between Ruby and Jenkins
6
+ # There is one instance of this object for the entire
7
+ # plugin
8
+ #
9
+ # On the Java side, it contains a reference to an instance
10
+ # of RubyPlugin. These two objects talk to each other to
11
+ # get things done.
12
+ #
13
+ # Each running ruby plugin has exactly one instance of
14
+ # `Jenkins::Plugin`
15
+ class Plugin
16
+
17
+ # A list of all the hudson.model.Descriptor objects
18
+ # of which this plugin is aware *indexed by Wrapper class*
19
+ #
20
+ # This is used so that wrappers can always have a single place
21
+ # to go when they are asked for a descriptor. That way, wrapper
22
+ # instances can always return the descriptor associated with
23
+ # their class.
24
+ #
25
+ # This may go away.
26
+ attr_reader :descriptors
27
+
28
+ # the instance of jenkins.ruby.RubyPlugin with which this Plugin is associated
29
+ attr_reader :peer
30
+
31
+ # Initializes this plugin by reading the models.rb
32
+ # file. This is a manual registration process
33
+ # Where ruby objects register themselves with the plugin
34
+ # In the future, this process will be automatic, but
35
+ # I haven't decided the best way to do this yet.
36
+ #
37
+ # @param [org.jenkinsci.ruby.RubyPlugin] java a native java RubyPlugin
38
+ def initialize(java)
39
+ @java = @peer = java
40
+ @start = @stop = proc {}
41
+ @descriptors = {}
42
+ @proxies = Proxies.new(self)
43
+ end
44
+
45
+ # Initialize the singleton instance that will run for a
46
+ # ruby plugin. This method is designed to be called by the
47
+ # Java side when setting up the ruby plugin
48
+ # @return [Jenkins::Plugin] the singleton instance
49
+ def self.initialize(java)
50
+ #TODO: check for double initialization?!?
51
+ @instance = new(java)
52
+ @instance.load_models
53
+ return @instance
54
+ end
55
+
56
+ # Get the singleton instance associated with this plugin
57
+ #
58
+ # This is useful when code in the plugin needs to get a
59
+ # reference to the plugin in which it is running e.g.
60
+ #
61
+ # Jenkins::Plugin.instance #=> the running plugin
62
+ #
63
+ # @return [Jenkins::Plugin] the singleton instance
64
+ def self.instance
65
+ @instance
66
+ end
67
+
68
+ # Register a ruby class as a Jenkins extension point of
69
+ # a particular java type
70
+ #
71
+ # This method is invoked automatically as part of the auto-registration
72
+ # process, and should not need to be invoked by plugin code.
73
+ #
74
+ # @param [Class] ruby_class the class implementing the extension point
75
+ # @param [java.lang.Class] java_class that Jenkins will see this extention point as
76
+ def register_describable(ruby_class, java_class)
77
+ descriptor = Jenkins::Model::Descriptor.new(ruby_class, self, java_class)
78
+ @peer.addExtension(descriptor)
79
+ @descriptors[ruby_class] = descriptor
80
+ end
81
+
82
+ # unique identifier for this plugin in the Jenkins server
83
+ def name
84
+ @peer.getWrapper().getShortName()
85
+ end
86
+
87
+ # Called once when Jenkins first initializes this plugin
88
+ # currently does nothing, but plugin startup hooks would
89
+ # go here.
90
+ def start
91
+ @start.call()
92
+ end
93
+
94
+ # Called one by Jenkins (via RubyPlugin) when this plugin
95
+ # is shut down. Currently this does nothing, but plugin
96
+ # shutdown hooks would go here.
97
+ def stop
98
+ @stop.call()
99
+ end
100
+
101
+ # Reflect an Java object coming from Jenkins into the context of this plugin
102
+ # If the object is originally from the ruby plugin, and it was previously
103
+ # exported, then it will unwrap it. Otherwise, it will just use the object
104
+ # as a normal Java object.
105
+ #
106
+ # @param [Object] object the object to bring in from the outside
107
+ # @return the best representation of that object for this plugin
108
+ def import(object)
109
+ @proxies.import object
110
+ end
111
+
112
+ # Reflect a native Ruby object into its External Java form.
113
+ #
114
+ # Delegates to `Proxies` for the heavy lifting.
115
+ #
116
+ # @param [Object] object the object
117
+ # @returns [java.lang.Object] the Java proxy
118
+ def export(object)
119
+ @proxies.export object
120
+ end
121
+
122
+ # Link a plugin-local Ruby object to an external Java object.
123
+ #
124
+ # see 'Proxies#link`
125
+ #
126
+ # @param [Object] internal the object on the Ruby side of the link
127
+ # @param [java.lang.Object] external the object on the Java side of the link
128
+ def link(internal, external)
129
+ @proxies.link internal, external
130
+ end
131
+
132
+ def load_models
133
+ p = @java.getModelsPath().getPath()
134
+ puts "Trying to load models from #{p}"
135
+ for filename in Dir["#{p}/**/*.rb"]
136
+ puts "Loading "+filename
137
+ load filename
138
+ end
139
+ end
140
+ end
141
+ end