jenkins-plugin-runtime 0.1.18 → 0.1.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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