jenkins-plugin-runtime 0.1.18 → 0.1.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/README.md +12 -0
  2. data/Rakefile +2 -1
  3. data/jenkins-plugin-runtime.gemspec +2 -1
  4. data/lib/core_ext/exception.rb +36 -0
  5. data/lib/jenkins/cli/command.rb +167 -0
  6. data/lib/jenkins/cli/command_proxy.rb +62 -0
  7. data/lib/jenkins/filepath.rb +1 -6
  8. data/lib/jenkins/launcher.rb +4 -14
  9. data/lib/jenkins/model.rb +8 -41
  10. data/lib/jenkins/model/action.rb +1 -9
  11. data/lib/jenkins/model/build.rb +4 -5
  12. data/lib/jenkins/model/describable.rb +16 -30
  13. data/lib/jenkins/model/root_action.rb +2 -2
  14. data/lib/jenkins/plugin.rb +61 -12
  15. data/lib/jenkins/plugin/behavior.rb +96 -0
  16. data/lib/jenkins/plugin/proxies.rb +4 -0
  17. data/lib/jenkins/plugin/proxies/action.rb +10 -6
  18. data/lib/jenkins/plugin/proxies/build_step.rb +1 -0
  19. data/lib/jenkins/plugin/proxies/build_wrapper.rb +2 -5
  20. data/lib/jenkins/plugin/proxies/builder.rb +1 -5
  21. data/lib/jenkins/plugin/proxies/describable.rb +6 -0
  22. data/lib/jenkins/plugin/proxies/publisher.rb +1 -5
  23. data/lib/jenkins/plugin/proxies/root_action.rb +2 -17
  24. data/lib/jenkins/plugin/proxy.rb +27 -6
  25. data/lib/jenkins/plugin/runtime.rb +3 -0
  26. data/lib/jenkins/plugin/runtime/version.rb +1 -1
  27. data/lib/jenkins/plugin/wrapper.rb +29 -0
  28. data/spec/jenkins/cli/command_proxy_spec.rb +5 -0
  29. data/spec/jenkins/cli/command_spec.rb +5 -0
  30. data/spec/jenkins/launcher_spec.rb +0 -4
  31. data/spec/jenkins/model/action_spec.rb +2 -1
  32. data/spec/jenkins/model/build_spec.rb +2 -3
  33. data/spec/jenkins/model/describable_spec.rb +22 -7
  34. data/spec/jenkins/model_spec.rb +0 -28
  35. data/spec/jenkins/plugin/behavior_spec.rb +109 -0
  36. data/spec/jenkins/plugin/proxy_spec.rb +14 -0
  37. data/spec/jenkins/plugin_spec.rb +20 -0
  38. data/spec/spec_helper.rb +11 -5
  39. metadata +34 -13
  40. data/spec/mockito-all-1.8.5.jar +0 -0
@@ -7,15 +7,14 @@ module Jenkins
7
7
  # all build steps, and can be used to configure, halt, message
8
8
  # the current running build.
9
9
  class Build
10
+ include Jenkins::Plugin::Wrapper
11
+
12
+ wrapper_for Java.hudson.model.AbstractBuild
10
13
 
11
14
  # Raised to indicate that a build wrapper halted a build.
12
15
  # Raising this does *not* set the build result to error.
13
16
  class Halt < Exception; end
14
17
 
15
-
16
- # the Hudson::Model::AbstractBuild represented by this build
17
- attr_reader :native
18
-
19
18
  # Hash of environment variables that will be added to each process
20
19
  # started as part of this build. E.g.
21
20
  #
@@ -30,7 +29,7 @@ module Jenkins
30
29
  attr_reader :env
31
30
 
32
31
  def initialize(native)
33
- @native = native
32
+ super(native)
34
33
  @variables = {}
35
34
  @env = {}
36
35
  @native.buildEnvironments.add(EnvironmentVariables.new(@env))
@@ -29,17 +29,29 @@ module Jenkins
29
29
  # This class should generally not be needed by plugin authors since it is part of the
30
30
  # glue layer and not the public runtime API.
31
31
  module Describable
32
+ extend Plugin::Behavior
32
33
  DescribableError = Class.new(StandardError)
33
34
 
35
+ implemented do |cls|
36
+ Jenkins.plugin.register_describable cls if Jenkins.plugin
37
+ end
38
+
34
39
  module DescribeAs
40
+
35
41
  # Java class that represents the extension point, which gets eventually set to Descriptor.clazz
36
42
  # :with will use this java class as the type of descriptor.
37
43
  def describe_as cls, options = {}
38
44
  @describe_as_type = verify_java_class(cls).java_class
39
45
  @descriptor_is = verify_java_class(options[:with]).java_class if options[:with]
40
46
  end
41
- attr_reader :describe_as_type
42
- attr_reader :descriptor_is
47
+
48
+ def describe_as_type
49
+ @describe_as_type ? @describe_as_type : (superclass.describe_as_type if superclass.respond_to?(:describe_as_type))
50
+ end
51
+
52
+ def descriptor_is
53
+ @descriptor_is ? @descriptor_is : (superclass.descriptor_is if superclass.respond_to?(:descriptor_is))
54
+ end
43
55
 
44
56
  private
45
57
 
@@ -51,35 +63,9 @@ module Jenkins
51
63
  end
52
64
  end
53
65
 
54
- # When a Describable class is subclassed, make it also Describable
55
- module Inherited
56
- def inherited(cls)
57
- super(cls)
58
- cls.extend Inherited
59
- describe_as_type = @describe_as_type
60
- descriptor_is = @descriptor_is
61
- cls.class_eval do
62
- @describe_as_type = describe_as_type
63
- @descriptor_is = descriptor_is
64
- end
65
- if Jenkins::Plugin.instance
66
- Jenkins::Plugin.instance.register_describable(cls, describe_as_type, descriptor_is)
67
- end
68
- end
69
- end
70
-
71
- module Included
72
- def included(mod)
73
- super
74
- if mod.is_a? Class
75
- mod.extend DescribeAs
76
- mod.extend Inherited
77
- else
78
- warn "tried to include Describable into a Module. Are you sure?"
79
- end
80
- end
66
+ module ClassMethods
67
+ include DescribeAs
81
68
  end
82
- self.extend Included
83
69
  end
84
70
  end
85
71
  end
@@ -2,8 +2,8 @@ require 'jenkins/model/action'
2
2
 
3
3
  module Jenkins
4
4
  module Model
5
- class RootAction < Action
6
- include Model
5
+ class RootAction
6
+ include Action
7
7
  end
8
8
  end
9
9
  end
@@ -28,6 +28,17 @@ module Jenkins
28
28
  # the instance of jenkins.ruby.RubyPlugin with which this Plugin is associated
29
29
  attr_reader :peer
30
30
 
31
+ # Add listeners for things that might happen to a plugin. E.g.
32
+ #
33
+ # plugin.on.start do |plugin|
34
+ # #do some setup
35
+ # end
36
+ # plugin.on.stop do |plugin|
37
+ # #do some teardown
38
+ # end
39
+ # @return [Lifecycle]
40
+ attr_reader :on
41
+
31
42
  # Initializes this plugin by reading the models.rb
32
43
  # file. This is a manual registration process
33
44
  # Where ruby objects register themselves with the plugin
@@ -40,6 +51,7 @@ module Jenkins
40
51
  @start = @stop = proc {}
41
52
  @descriptors = {}
42
53
  @proxies = Proxies.new(self)
54
+ @on = Lifecycle.new
43
55
  end
44
56
 
45
57
  # Initialize the singleton instance that will run for a
@@ -88,7 +100,7 @@ module Jenkins
88
100
  # @param [...] arguments to pass to
89
101
 
90
102
  def register_extension(class_or_instance, *args)
91
- extension = class_or_instance.is_a?(Class) ? class_or_instance.new : class_or_instance
103
+ extension = class_or_instance.is_a?(Class) ? class_or_instance.new(*args) : class_or_instance
92
104
  @peer.addExtension(export(extension))
93
105
  end
94
106
 
@@ -98,15 +110,18 @@ module Jenkins
98
110
  # This method is invoked automatically as part of the auto-registration
99
111
  # process, and should not need to be invoked by plugin code.
100
112
  #
101
- # @param [Class] ruby_class the class implementing the extension point
102
- # @param [java.lang.Class] describable_class that Jenkins will see this extention point as
103
- # @param [Class] descriptor_class that we use to instantiate Descriptor.
104
- # nil to use the plain-vanilla Descriptor class for those extension points that don't define its own Descriptor type
105
- def register_describable(ruby_class, describable_class, descriptor_class = nil)
106
- descriptor_class ||= Jenkins::Model::Descriptor
107
- descriptor = descriptor_class.new(ruby_class, self, describable_class)
108
- @descriptors[ruby_class] = descriptor
109
- register_extension(descriptor)
113
+ # Classes including `Describabble` will be autoregistered in this way.
114
+ #
115
+ # @param [Class] describable_class the class implementing the extension point
116
+ # @see [Model::Describable]
117
+ def register_describable(describable_class)
118
+ fail "#{describable_class} is not an instance of Describable" unless describable_class.is_a? Model::Describable
119
+ on.start do
120
+ descriptor_class = descriptor_class.descriptor_is || Jenkins::Model::Descriptor
121
+ descriptor = descriptor_class.new(ruby_class, self, describable_class.describe_as_type)
122
+ @descriptors[ruby_class] = descriptor
123
+ register_extension(descriptor)
124
+ end
110
125
  end
111
126
 
112
127
  # unique identifier for this plugin in the Jenkins server
@@ -118,14 +133,14 @@ module Jenkins
118
133
  # currently does nothing, but plugin startup hooks would
119
134
  # go here.
120
135
  def start
121
- @start.call()
136
+ @on.fire(:start, self)
122
137
  end
123
138
 
124
139
  # Called one by Jenkins (via RubyPlugin) when this plugin
125
140
  # is shut down. Currently this does nothing, but plugin
126
141
  # shutdown hooks would go here.
127
142
  def stop
128
- @stop.call()
143
+ @on.fire(:stop, self)
129
144
  end
130
145
 
131
146
  # Reflect an Java object coming from Jenkins into the context of this plugin
@@ -159,6 +174,12 @@ module Jenkins
159
174
  @proxies.linkout internal, external
160
175
  end
161
176
 
177
+ # Load all of the Ruby code associated with this plugin. For
178
+ # historical purposes this is called "models", but really
179
+ # it should be something like extensions ext/ or maybe it's
180
+ # just one file associated with the plugin itself. Who knows?
181
+ # The jury is definitely still out on the best way to discover
182
+ # and load extension points.
162
183
  def load_models
163
184
  path = @java.getModelsPath().getPath()
164
185
  # TODO: can we access to Jenkins console logger?
@@ -191,6 +212,34 @@ module Jenkins
191
212
  load_file_in_dir(dir)
192
213
  end
193
214
  end
215
+
216
+ class Lifecycle
217
+ def initialize
218
+ @start = []
219
+ @stop = []
220
+ end
221
+
222
+ def start(&block)
223
+ @start << block if block
224
+ end
225
+
226
+ def stop(&block)
227
+ @stop << block if block
228
+ end
229
+
230
+ def fire(event, *args)
231
+ if listeners = instance_variable_get("@#{event}")
232
+ listeners.each do |l|
233
+ callback(l, *args)
234
+ end
235
+ end
236
+ end
237
+ def callback(listener, *args)
238
+ listener.call(*args)
239
+ rescue Exception => e
240
+ $stderr.warn "#{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
241
+ end
242
+ end
194
243
  end
195
244
 
196
245
  # Make the singleton instance available from the top-level
@@ -0,0 +1,96 @@
1
+ require 'set'
2
+
3
+ module Jenkins
4
+ class Plugin
5
+ # A Behavior will receive a callback any time that it is
6
+ # included into a class or when a class that has been included
7
+ # is extended. This is needed for a couple reasons.
8
+ #
9
+ # One case is to enable Transient marking behavior. Every
10
+ # time a concrete model class is implemented, it needs the
11
+ # ability to define which of its attributes are transient,
12
+ # so that they will not be persisted with the Jenkins serialization.
13
+ # which attributes are tracked on a per-class basis, so we
14
+ # need a callback for each class in the inheritance hierachy.
15
+ #
16
+ # class Foo
17
+ # include Model
18
+ # transient :foo do
19
+ # @foo = 1 + 2
20
+ # end
21
+ # end
22
+ # class Bar < Foo
23
+ # transient :bar do # <- no need to include Model
24
+ # @bar = create_bar
25
+ # end
26
+ # end
27
+ #
28
+ # Another is the case of auto registration. We want to be able
29
+ # to find out when extension points are implemented, and register
30
+ # them with the Jenkins Runtime
31
+ #
32
+ # module Descriptor
33
+ # implemented do |cls|
34
+ # Jenkins.plugin.on.start do |plugin|
35
+ # plugin.register_extension new(Jenkins.plugin, cls.ruby_type, cls.java_type)
36
+ # end
37
+ # end
38
+ # end
39
+ # And of course, there is the case of proxies where we need to make sure that
40
+ # certain behaviors are always included into the proxy, and that if java classes
41
+ # need to be implemented, they are.
42
+ module Behavior
43
+ def included(mod)
44
+ if mod.is_a? Class
45
+ mod.extend Implementation unless mod.is_a? Implementation
46
+ else
47
+ mod.extend Behavior unless mod.is_a? Behavior
48
+ end
49
+ mod.behaves_as *@_behaviors
50
+ super(mod)
51
+ end
52
+
53
+ def implemented(cls = nil, &implemented_block)
54
+ if cls
55
+ @implemented_block.call cls if @implemented_block
56
+ else
57
+ @implemented_block = implemented_block
58
+ end
59
+ end
60
+
61
+ def self.extended(mod)
62
+ super(mod)
63
+ mod.instance_eval do
64
+ @_behaviors = Set.new([self])
65
+ end
66
+ end
67
+
68
+ module BehavesAs
69
+ def behaves_as(*behaviors)
70
+ @_behaviors ||= Set.new
71
+ behaviors.each do |b|
72
+ unless @_behaviors.include? b
73
+ b.implemented self if self.is_a? Class
74
+ self.extend b::ClassMethods if b.const_defined? :ClassMethods
75
+ self.send(:include, b::InstanceMethods) if b.const_defined? :InstanceMethods
76
+ @_behaviors << b
77
+ end
78
+ end
79
+ return @_behaviors
80
+ end
81
+ end
82
+ include BehavesAs
83
+
84
+ module Implementation
85
+ include BehavesAs
86
+
87
+ def inherited(cls)
88
+ super.tap do
89
+ cls.extend Implementation unless cls.is_a? Implementation
90
+ cls.behaves_as *@_behaviors
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -175,3 +175,7 @@ require 'jenkins/model/describable'
175
175
  ["action", "build_wrapper", "builder", "publisher", "root_action"].each do |proxy|
176
176
  require "jenkins/plugin/proxies/#{proxy}"
177
177
  end
178
+
179
+ ["cli/command"].each do |proxy|
180
+ require "jenkins/#{proxy}_proxy"
181
+ end
@@ -4,11 +4,17 @@ require 'jenkins/plugin/proxies/describable'
4
4
  module Jenkins
5
5
  class Plugin
6
6
  class Proxies
7
- class Action
8
- include Java.hudson.model.Action
9
- include Java.jenkins.ruby.Get
7
+ module Action
10
8
  include Jenkins::Plugin::Proxy
11
- include Jenkins::Plugin::Proxies::Describable
9
+ implemented do |cls|
10
+ cls.class_eval do
11
+ include Java.hudson.model.Action
12
+ end
13
+ end
14
+
15
+ def getDisplayName
16
+ @object.display_name
17
+ end
12
18
 
13
19
  def getIconFileName
14
20
  @object.icon
@@ -18,8 +24,6 @@ module Jenkins
18
24
  @object.url_path
19
25
  end
20
26
  end
21
-
22
- register Jenkins::Model::Action, Action
23
27
  end
24
28
  end
25
29
  end
@@ -2,6 +2,7 @@ module Jenkins
2
2
  class Plugin
3
3
  class Proxies
4
4
  module BuildStep
5
+ include Describable
5
6
  def prebuild(build, listener)
6
7
  boolean_result(listener) do
7
8
  @object.prebuild(import(build), import(listener))
@@ -11,9 +11,8 @@ module Jenkins
11
11
  # Ruby API Jenkins::Tasks::BuildWrapper
12
12
 
13
13
  class BuildWrapper < Java.hudson.tasks.BuildWrapper
14
- include Jenkins::Plugin::Proxies::Describable
15
- include Java.jenkins.ruby.Get
16
- include Jenkins::Plugin::Proxy
14
+ include Describable
15
+ proxy_for Jenkins::Tasks::BuildWrapper
17
16
 
18
17
  def setUp(build, launcher, listener)
19
18
  @object.setup(import(build), import(launcher), import(listener))
@@ -45,8 +44,6 @@ module Jenkins
45
44
  false
46
45
  end
47
46
  end
48
-
49
- register Jenkins::Tasks::BuildWrapper, BuildWrapper
50
47
  end
51
48
  end
52
49
  end
@@ -5,13 +5,9 @@ module Jenkins
5
5
  class Plugin
6
6
  class Proxies
7
7
  class Builder < Java.hudson.tasks.Builder
8
- include Jenkins::Plugin::Proxies::Describable
9
- include Java.jenkins.ruby.Get
10
- include Jenkins::Plugin::Proxy
11
8
  include BuildStep
9
+ proxy_for Jenkins::Tasks::Builder
12
10
  end
13
-
14
- register Jenkins::Tasks::Builder, Builder
15
11
  end
16
12
  end
17
13
  end
@@ -4,6 +4,12 @@ module Jenkins
4
4
  # mix-in on top of the subtypes of the Describable Java class
5
5
  # to add standard behaviour as a proxy to Ruby object
6
6
  module Describable
7
+ include Jenkins::Plugin::Proxy
8
+ implemented do |cls|
9
+ cls.class_eval do
10
+ include Java.jenkins.ruby.Get
11
+ end
12
+ end
7
13
  def getDescriptor
8
14
  @plugin.descriptors[@object.class]
9
15
  end
@@ -5,13 +5,9 @@ module Jenkins
5
5
  class Plugin
6
6
  class Proxies
7
7
  class Publisher < Java.hudson.tasks.Publisher
8
- include Jenkins::Plugin::Proxies::Describable
9
- include Java.jenkins.ruby.Get
10
- include Jenkins::Plugin::Proxy
11
8
  include BuildStep
9
+ proxy_for Jenkins::Tasks::Publisher
12
10
  end
13
-
14
- register Jenkins::Tasks::Publisher, Publisher
15
11
  end
16
12
  end
17
13
  end
@@ -4,25 +4,10 @@ module Jenkins
4
4
  class Plugin
5
5
  class Proxies
6
6
  class RootAction
7
+ include Action
7
8
  include Java.hudson.model.RootAction
8
- include Java.jenkins.ruby.Get
9
- include Jenkins::Plugin::Proxy
10
- include Jenkins::Plugin::Proxies::Describable
11
-
12
- def getDisplayName
13
- @object.display_name
14
- end
15
-
16
- def getIconFileName
17
- @object.icon
18
- end
19
-
20
- def getUrlName
21
- @object.url_path
22
- end
9
+ proxy_for Jenkins::Model::RootAction
23
10
  end
24
-
25
- register Jenkins::Model::RootAction, RootAction
26
11
  end
27
12
  end
28
13
  end