jenkins-plugin-runtime 0.1.0
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.
- data/.gitignore +7 -0
- data/.travis.yml +2 -0
- data/Gemfile +4 -0
- data/Rakefile +21 -0
- data/jenkins-plugin-runtime.gemspec +30 -0
- data/lib/jenkins/launcher.rb +15 -0
- data/lib/jenkins/model.rb +91 -0
- data/lib/jenkins/model/action.rb +37 -0
- data/lib/jenkins/model/build.rb +21 -0
- data/lib/jenkins/model/describable.rb +75 -0
- data/lib/jenkins/model/descriptor.rb +40 -0
- data/lib/jenkins/model/listener.rb +47 -0
- data/lib/jenkins/plugin.rb +141 -0
- data/lib/jenkins/plugin/cli.rb +20 -0
- data/lib/jenkins/plugin/proxies.rb +131 -0
- data/lib/jenkins/plugin/proxies/build_wrapper.rb +50 -0
- data/lib/jenkins/plugin/proxies/builder.rb +22 -0
- data/lib/jenkins/plugin/proxy.rb +76 -0
- data/lib/jenkins/plugin/runtime.rb +13 -0
- data/lib/jenkins/plugin/runtime/version.rb +7 -0
- data/lib/jenkins/slaves/cloud.rb +9 -0
- data/lib/jenkins/tasks/build_wrapper.rb +39 -0
- data/lib/jenkins/tasks/builder.rb +33 -0
- data/spec/jenkins/launcher_spec.rb +8 -0
- data/spec/jenkins/model/action_spec.rb +36 -0
- data/spec/jenkins/model/build_spec.rb +8 -0
- data/spec/jenkins/model/describable_spec.rb +51 -0
- data/spec/jenkins/model/listener_spec.rb +31 -0
- data/spec/jenkins/model_spec.rb +100 -0
- data/spec/jenkins/plugin/proxies/build_wrapper_spec.rb +25 -0
- data/spec/jenkins/plugin/proxies/builder_spec.rb +24 -0
- data/spec/jenkins/plugin/proxies/proxy_helper.rb +24 -0
- data/spec/jenkins/plugin/proxies_spec.rb +148 -0
- data/spec/jenkins/plugin/proxy_spec.rb +43 -0
- data/spec/jenkins/plugin_spec.rb +7 -0
- data/spec/jenkins/tasks/build_wrapper_spec.rb +7 -0
- data/spec/jenkins/tasks/builder_spec.rb +8 -0
- data/spec/spec_helper.rb +11 -0
- data/src/jenkins/ruby/DoDynamic.java +18 -0
- data/src/jenkins/ruby/Get.java +18 -0
- metadata +175 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rspec-spies'
|
3
|
+
describe Jenkins::Model::Describable do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@plugin = mock(Jenkins::Plugin)
|
7
|
+
Jenkins::Plugin.stub(:instance).and_return(@plugin)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "when mixed into a class" do
|
11
|
+
before do
|
12
|
+
@class = Class.new
|
13
|
+
@class.send(:include, Jenkins::Model::Describable)
|
14
|
+
@plugin.stub(:register_describable)
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
it "can't be described as plain old object" do
|
19
|
+
lambda {@class.describe_as Object}.should raise_error(Jenkins::Model::Describable::DescribableError)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "can't be described as plain old java object" do
|
23
|
+
lambda {@class.describe_as java.lang.Object.new}.should raise_error(Jenkins::Model::Describable::DescribableError)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "must be described as a java.lang.Class" do
|
27
|
+
lambda {@class.describe_as java.lang.Object}.should_not raise_error
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "a subclass of that class" do
|
31
|
+
before do
|
32
|
+
@class.describe_as java.lang.Object
|
33
|
+
@subclass = Class.new(@class)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "is registered as an extension of the java type" do
|
37
|
+
@plugin.should have_received(:register_describable).with(@subclass, java.lang.Object.java_class)
|
38
|
+
end
|
39
|
+
|
40
|
+
describe ". a sub-subclass" do
|
41
|
+
before do
|
42
|
+
@subsubclass = Class.new(@subclass)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "is also registered as an extension of the original java type" do
|
46
|
+
@plugin.should have_received(:register_describable).with(@subsubclass, java.lang.Object.java_class)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Jenkins::Model::Listener do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@output = java.io.ByteArrayOutputStream.new
|
7
|
+
@java = Java.hudson.util.StreamTaskListener.new(@output)
|
8
|
+
@listener = Jenkins::Model::Listener.new(@java)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "logs messages" do
|
12
|
+
@listener.log('Hi')
|
13
|
+
@output.toString.should eql "Hi"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "logs errors" do
|
17
|
+
@listener.error('Oh no!')
|
18
|
+
@output.toString.should match /^ERROR: Oh no!/
|
19
|
+
end
|
20
|
+
|
21
|
+
it "logs fatal errors" do
|
22
|
+
@listener.fatal('boom!')
|
23
|
+
@output.toString.should match /^FATAL: boom!/
|
24
|
+
end
|
25
|
+
|
26
|
+
it "logs hyperlinks" do
|
27
|
+
@java.should_receive(:hyperlink).with("/foo/bar", "click here")
|
28
|
+
@listener.hyperlink("/foo/bar", "click here")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Jenkins::Model do
|
4
|
+
Model = Jenkins::Model
|
5
|
+
|
6
|
+
it "has a display name which is settable via the class, and accessable via the class and instance" do
|
7
|
+
cls = new_model do
|
8
|
+
display_name "One-Off Class"
|
9
|
+
end
|
10
|
+
cls.display_name.should eql "One-Off Class"
|
11
|
+
cls.new.display_name.should eql "One-Off Class"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "passes down display_name capabilities to subclasses" do
|
15
|
+
parent = new_model
|
16
|
+
child = Class.new(parent)
|
17
|
+
child.class_eval do
|
18
|
+
display_name "Child"
|
19
|
+
end
|
20
|
+
child.display_name.should eql "Child"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "passes down display_name capabilities to submodules" do
|
24
|
+
submodule = Module.new
|
25
|
+
submodule.send(:include, Jenkins::Model)
|
26
|
+
cls = Class.new
|
27
|
+
cls.send(:include, submodule)
|
28
|
+
cls.display_name "SubAwesome"
|
29
|
+
cls.display_name.should eql "SubAwesome"
|
30
|
+
cls.new.display_name.should eql "SubAwesome"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "has a default display name of the class name" do
|
34
|
+
cls = new_model do
|
35
|
+
def self.name
|
36
|
+
"AwesomeClass"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
cls.display_name.should eql "AwesomeClass"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "keeps a list of which of its properties are transient" do
|
43
|
+
cls = new_model do
|
44
|
+
transient :foo, :bar
|
45
|
+
end
|
46
|
+
cls.should be_transient(:foo)
|
47
|
+
cls.should be_transient(:bar)
|
48
|
+
cls.should_not be_transient(:baz)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "includes parent classes's transient properties, but doesn't affect the parent property list" do
|
52
|
+
parent = new_model do
|
53
|
+
transient :foo
|
54
|
+
end
|
55
|
+
child = Class.new(parent)
|
56
|
+
child.class_eval do
|
57
|
+
transient :bar
|
58
|
+
end
|
59
|
+
parent.should_not be_transient(:bar)
|
60
|
+
child.should be_transient(:foo)
|
61
|
+
child.should be_transient(:bar)
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "tracking descendants" do
|
65
|
+
before do
|
66
|
+
Model.clear
|
67
|
+
end
|
68
|
+
|
69
|
+
it "captures including classes" do
|
70
|
+
cls = Class.new
|
71
|
+
cls.send(:include, Model)
|
72
|
+
Model.should be_descendant cls
|
73
|
+
end
|
74
|
+
|
75
|
+
it "captures classes that extend including classes" do
|
76
|
+
cls = Class.new
|
77
|
+
cls.send(:include, Model)
|
78
|
+
Model.should be_descendant(Class.new(cls))
|
79
|
+
end
|
80
|
+
|
81
|
+
it "captures classes that include including modules" do
|
82
|
+
m1 = Module.new
|
83
|
+
m1.send(:include, Model)
|
84
|
+
m2 = Module.new
|
85
|
+
m2.send(:include, m1)
|
86
|
+
cls = Class.new
|
87
|
+
cls.send(:include, m2)
|
88
|
+
Model.should be_descendant(Class.new(cls))
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def new_model(&block)
|
95
|
+
cls = Class.new
|
96
|
+
cls.send(:include, Jenkins::Model)
|
97
|
+
cls.class_eval(&block) if block_given?
|
98
|
+
return cls
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Jenkins::Plugin::Proxies::BuildWrapper do
|
5
|
+
include ProxyHelper
|
6
|
+
|
7
|
+
subject {Jenkins::Plugin::Proxies::BuildWrapper}
|
8
|
+
it {should be_transient(:plugin)}
|
9
|
+
|
10
|
+
before do
|
11
|
+
@object = mock(Jenkins::Tasks::BuildWrapper)
|
12
|
+
@wrapper = Jenkins::Plugin::Proxies::BuildWrapper.new(@plugin, @object)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "passes in an env file which will be called to " do
|
16
|
+
env = nil
|
17
|
+
@object.should_receive(:setup).with(@build, @launcher, @listener, an_instance_of(Hash)) do |*args|
|
18
|
+
env = args.last
|
19
|
+
end
|
20
|
+
environment = @wrapper.setUp(@jBuild, @jLauncher, @jListener)
|
21
|
+
|
22
|
+
@object.should_receive(:teardown).with(@build, @listener, env)
|
23
|
+
environment.tearDown(@jBuild, @jListener)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Jenkins::Plugin::Proxies::Builder do
|
4
|
+
include ProxyHelper
|
5
|
+
|
6
|
+
before do
|
7
|
+
@object = mock(Jenkins::Tasks::Builder)
|
8
|
+
@builder = Jenkins::Plugin::Proxies::Builder.new(@plugin, @object)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "prebuild" do
|
12
|
+
it "calls through to its implementation" do
|
13
|
+
@object.should_receive(:prebuild).with(@build, @launcher, @listener)
|
14
|
+
@builder.prebuild(@jBuild, @jLauncher, @jListener)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "perform" do
|
19
|
+
it "calls through to its implementation" do
|
20
|
+
@object.should_receive(:perform).with(@build, @launcher, @listener)
|
21
|
+
@builder.perform(@jBuild, @jLauncher, @jListener)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
module ProxyHelper
|
3
|
+
|
4
|
+
def self.included(mod)
|
5
|
+
super
|
6
|
+
mod.class_eval do
|
7
|
+
before do
|
8
|
+
@plugin = mock(Jenkins::Plugin, :name => "test-plugin")
|
9
|
+
|
10
|
+
@jBuild = mock(Java.hudson.model.AbstractBuild)
|
11
|
+
@jLauncher = mock(Java.hudson.Launcher)
|
12
|
+
@jListener = mock(Java.hudson.model.BuildListener)
|
13
|
+
|
14
|
+
@build = mock(Jenkins::Model::Build)
|
15
|
+
@launcher = mock(Jenkins::Launcher)
|
16
|
+
@listener = mock(Jenkins::Model::Listener)
|
17
|
+
|
18
|
+
@plugin.stub(:import).with(@jBuild).and_return(@build)
|
19
|
+
@plugin.stub(:import).with(@jLauncher).and_return(@launcher)
|
20
|
+
@plugin.stub(:import).with(@jListener).and_return(@listener)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Jenkins::Plugin::Proxies do
|
4
|
+
Proxies = Jenkins::Plugin::Proxies
|
5
|
+
before do
|
6
|
+
Proxies.clear
|
7
|
+
@plugin = mock(Jenkins::Plugin)
|
8
|
+
@proxies = Jenkins::Plugin::Proxies.new(@plugin)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "exporting a native ruby object" do
|
12
|
+
|
13
|
+
before do
|
14
|
+
@class = Class.new
|
15
|
+
@object = @class.new
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "when no wrapper exists for it" do
|
19
|
+
|
20
|
+
describe "and there is a matching proxy class registered" do
|
21
|
+
before do
|
22
|
+
@proxy_class = Class.new
|
23
|
+
@proxy_class.class_eval do
|
24
|
+
attr_reader :plugin, :object
|
25
|
+
def initialize(plugin, object)
|
26
|
+
@plugin, @object = plugin, object
|
27
|
+
end
|
28
|
+
end
|
29
|
+
Jenkins::Plugin::Proxies.register @class, @proxy_class
|
30
|
+
@export = @proxies.export(@object)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "instantiates the proxy" do
|
34
|
+
@export.should be_kind_of(@proxy_class)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "passes in the plugin and the wrapped object" do
|
38
|
+
@export.plugin.should be(@plugin)
|
39
|
+
@export.object.should be(@object)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "and there is not an appropriate proxy class registered for it" do
|
44
|
+
it "raises an exception on import" do
|
45
|
+
expect {@proxies.export(@object)}.should raise_error
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "when a wrapper has already existed" do
|
51
|
+
before do
|
52
|
+
@proxy = Object.new
|
53
|
+
@proxies.link @object, @proxy
|
54
|
+
end
|
55
|
+
|
56
|
+
it "finds the same proxy on export" do
|
57
|
+
@proxies.export(@object).should be(@proxy)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "finds associated Ruby object on import" do
|
61
|
+
@proxies.import(@proxy).should be(@object)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "proxy matching" do
|
66
|
+
describe "when there are two related classes" do
|
67
|
+
before do
|
68
|
+
@A = Class.new
|
69
|
+
@B = Class.new(@A)
|
70
|
+
@A.class_eval do
|
71
|
+
attr_reader :native
|
72
|
+
def initialize(native = nil)
|
73
|
+
@native = native
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "and there is a proxy registered for the subclass but not the superclass" do
|
79
|
+
before do
|
80
|
+
@p = proxy_class
|
81
|
+
Proxies.register @B, @p
|
82
|
+
end
|
83
|
+
|
84
|
+
it "will create a proxy for the subclass" do
|
85
|
+
@proxies.export(@B.new).should be_kind_of(@p)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "will create a native for the external class" do
|
89
|
+
internal = @proxies.import(@p.new)
|
90
|
+
internal.should be_kind_of(@B)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "will fail to create a proxy for the superclass" do
|
94
|
+
expect {@proxies.export @A.new}.should raise_error(Jenkins::Plugin::ExportError)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "and there is a proxy registered for the superclass but not the superclass" do
|
99
|
+
before do
|
100
|
+
@p = proxy_class
|
101
|
+
Proxies.register @A, @p
|
102
|
+
end
|
103
|
+
it "will create a proxy for the superclass" do
|
104
|
+
@proxies.export(@A.new).should be_kind_of(@p)
|
105
|
+
@proxies.import(@p.new).should be_kind_of(@A)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "will create a proxy for the subclass" do
|
109
|
+
@proxies.export(@B.new).should be_kind_of(@p)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "and there is proxy registered for both classes" do
|
114
|
+
|
115
|
+
before do
|
116
|
+
@pA = proxy_class
|
117
|
+
@pB = proxy_class
|
118
|
+
Proxies.register @A, @pA
|
119
|
+
Proxies.register @B, @pB
|
120
|
+
end
|
121
|
+
it "will create a proxy for the subclass with its registered proxy class" do
|
122
|
+
@proxies.export(@A.new).should be_kind_of(@pA)
|
123
|
+
@proxies.import(@pA.new).should be_kind_of(@A)
|
124
|
+
end
|
125
|
+
|
126
|
+
it "will create a proxy for the superclass with its registered proxy class" do
|
127
|
+
@proxies.export(@B.new).should be_kind_of(@pB)
|
128
|
+
@proxies.import(@pB.new).should be_kind_of(@B)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def proxy_class
|
139
|
+
cls = Class.new
|
140
|
+
cls.class_eval do
|
141
|
+
attr_reader :plugin, :object
|
142
|
+
def initialize(plugin = nil, object = nil)
|
143
|
+
@plugin, @object = plugin, object
|
144
|
+
end
|
145
|
+
end
|
146
|
+
return cls
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "a class with #{Jenkins::Plugin::Proxy} mixed in" do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@class = Class.new
|
7
|
+
@class.send(:include, Jenkins::Plugin::Proxy)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "treats the plugin as transient" do
|
11
|
+
@class.transient?(:plugin).should be_true
|
12
|
+
end
|
13
|
+
|
14
|
+
it "leaves other fields alone" do
|
15
|
+
@class.transient?(:object).should be_false
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "unmarshalling" do
|
19
|
+
before do
|
20
|
+
@class.class_eval do
|
21
|
+
attr_reader :plugin
|
22
|
+
end
|
23
|
+
@plugin = mock(Jenkins::Plugin)
|
24
|
+
@impl = impl = Object.new
|
25
|
+
@proxy = @class.allocate
|
26
|
+
@proxy.instance_eval do
|
27
|
+
@pluginid = "test-plugin"
|
28
|
+
@object = impl
|
29
|
+
end
|
30
|
+
@jenkins = mock(Java.jenkins.model.Jenkins)
|
31
|
+
@java_plugin = mock(:RubyPlugin, :getNativeRubyPlugin => @plugin)
|
32
|
+
@jenkins.stub(:getPlugin).with("test-plugin").and_return(@java_plugin)
|
33
|
+
Java.jenkins.model.Jenkins.stub(:getInstance).and_return(@jenkins)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "reconstructs the @plugin field" do
|
37
|
+
@plugin.should_receive(:link).with(@impl, @proxy)
|
38
|
+
@proxy.read_completed
|
39
|
+
@proxy.plugin.should be(@plugin)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|