jenkins-plugin-runtime 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|