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.
- data/README.md +12 -0
- data/Rakefile +2 -1
- data/jenkins-plugin-runtime.gemspec +2 -1
- data/lib/core_ext/exception.rb +36 -0
- data/lib/jenkins/cli/command.rb +167 -0
- data/lib/jenkins/cli/command_proxy.rb +62 -0
- data/lib/jenkins/filepath.rb +1 -6
- data/lib/jenkins/launcher.rb +4 -14
- data/lib/jenkins/model.rb +8 -41
- data/lib/jenkins/model/action.rb +1 -9
- data/lib/jenkins/model/build.rb +4 -5
- data/lib/jenkins/model/describable.rb +16 -30
- data/lib/jenkins/model/root_action.rb +2 -2
- data/lib/jenkins/plugin.rb +61 -12
- data/lib/jenkins/plugin/behavior.rb +96 -0
- data/lib/jenkins/plugin/proxies.rb +4 -0
- data/lib/jenkins/plugin/proxies/action.rb +10 -6
- data/lib/jenkins/plugin/proxies/build_step.rb +1 -0
- data/lib/jenkins/plugin/proxies/build_wrapper.rb +2 -5
- data/lib/jenkins/plugin/proxies/builder.rb +1 -5
- data/lib/jenkins/plugin/proxies/describable.rb +6 -0
- data/lib/jenkins/plugin/proxies/publisher.rb +1 -5
- data/lib/jenkins/plugin/proxies/root_action.rb +2 -17
- data/lib/jenkins/plugin/proxy.rb +27 -6
- data/lib/jenkins/plugin/runtime.rb +3 -0
- data/lib/jenkins/plugin/runtime/version.rb +1 -1
- data/lib/jenkins/plugin/wrapper.rb +29 -0
- data/spec/jenkins/cli/command_proxy_spec.rb +5 -0
- data/spec/jenkins/cli/command_spec.rb +5 -0
- data/spec/jenkins/launcher_spec.rb +0 -4
- data/spec/jenkins/model/action_spec.rb +2 -1
- data/spec/jenkins/model/build_spec.rb +2 -3
- data/spec/jenkins/model/describable_spec.rb +22 -7
- data/spec/jenkins/model_spec.rb +0 -28
- data/spec/jenkins/plugin/behavior_spec.rb +109 -0
- data/spec/jenkins/plugin/proxy_spec.rb +14 -0
- data/spec/jenkins/plugin_spec.rb +20 -0
- data/spec/spec_helper.rb +11 -5
- metadata +34 -13
- data/spec/mockito-all-1.8.5.jar +0 -0
data/README.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
# Jenkins Plugin Runtime
|
3
|
+
|
4
|
+
This gem provides the glue between the native Jenkins runtime
|
5
|
+
which is implemented in Java, and an idiomatic API that allows
|
6
|
+
for development with a Ruby 'feel'
|
7
|
+
|
8
|
+
If you're interested in developing actual plugin, see the
|
9
|
+
[plugin development tools][1]
|
10
|
+
|
11
|
+
[1]:https://github.com/jenkinsci/jpi.rb
|
12
|
+
|
data/Rakefile
CHANGED
@@ -3,6 +3,7 @@ Bundler::GemHelper.install_tasks
|
|
3
3
|
|
4
4
|
require 'rspec/core/rake_task'
|
5
5
|
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
task :spec => :compile
|
6
7
|
|
7
8
|
require 'jenkins/war'
|
8
9
|
Jenkins::War.classpath
|
@@ -18,4 +19,4 @@ require 'rake/clean'
|
|
18
19
|
directory "target"
|
19
20
|
CLEAN.include("target")
|
20
21
|
|
21
|
-
task :default => [:compile, :spec]
|
22
|
+
task :default => [:compile, :spec]
|
@@ -20,9 +20,10 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.require_paths = ["lib"]
|
21
21
|
|
22
22
|
s.add_dependency "json"
|
23
|
+
s.add_dependency "slop", "~> 3.0.2"
|
23
24
|
|
24
25
|
s.add_development_dependency "rake", "0.8.7"
|
25
|
-
s.add_development_dependency "rspec", "~> 2.0"
|
26
|
+
s.add_development_dependency "rspec", "~> 2.7.0" # something in rspec 2.8 breaks rspec-spies
|
26
27
|
s.add_development_dependency "rspec-spies"
|
27
28
|
s.add_development_dependency "jenkins-war", "~> 1.445"
|
28
29
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# From utilrb's full_message.rb, http://utilrb.rubyforge.org/
|
2
|
+
# http://gitorious.org/+rock-core-maintainers/orocos-toolchain/rock-utilrb
|
3
|
+
#
|
4
|
+
# Copyright (c) 2006-2008
|
5
|
+
# Sylvain Joyeux <sylvain.joyeux@m4x.org>
|
6
|
+
# LAAS/CNRS <openrobots@laas.fr>
|
7
|
+
#
|
8
|
+
# Released under the BSD license,
|
9
|
+
# http://gitorious.org/+rock-core-maintainers/orocos-toolchain/rock-utilrb/blobs/master/License.txt
|
10
|
+
|
11
|
+
class Exception
|
12
|
+
def full_message(options = {}, &block)
|
13
|
+
since_matches, until_matches = options[:since], options[:until]
|
14
|
+
|
15
|
+
trace = backtrace
|
16
|
+
if since_matches || until_matches
|
17
|
+
found_beginning, found_end = !since_matches, false
|
18
|
+
trace = trace.find_all do |line|
|
19
|
+
found_beginning ||= (line =~ since_matches)
|
20
|
+
found_end ||= (line =~ until_matches) if until_matches
|
21
|
+
found_beginning && !found_end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
first, *remaining = if block_given? then trace.find_all(&block)
|
26
|
+
else trace
|
27
|
+
end
|
28
|
+
|
29
|
+
msg = "#{first}: #{message} (#{self.class})"
|
30
|
+
unless remaining.empty?
|
31
|
+
msg << "\n\tfrom " + remaining.join("\n\tfrom ")
|
32
|
+
end
|
33
|
+
|
34
|
+
msg
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'slop'
|
2
|
+
|
3
|
+
module Jenkins::CLI
|
4
|
+
# Extend the Jenkins CLI
|
5
|
+
#
|
6
|
+
# Jenkins ships with a CLI which can be used to iteract with it
|
7
|
+
# from a terminal, or from a program. It also exposes an API with
|
8
|
+
# which developers can extend the CLI with their own commands.
|
9
|
+
#
|
10
|
+
# The Ruby API allows you define a command as a Ruby class, which
|
11
|
+
# is then instantiated once for each invocation of the command via
|
12
|
+
# the CLI.
|
13
|
+
#
|
14
|
+
# Argument parsing is flexible, and a parsing scheme (Slop) is
|
15
|
+
# provided by default, but this is optional behavior which can
|
16
|
+
# be overridden.
|
17
|
+
#
|
18
|
+
# Include this to define a new CLI / SSHD command. Example:
|
19
|
+
#
|
20
|
+
# class HelloWorldCommand
|
21
|
+
# include Jenkins::CLI::Command
|
22
|
+
#
|
23
|
+
# description "Hello world sample command"
|
24
|
+
#
|
25
|
+
# arguments do
|
26
|
+
# on :v, :verbose, 'Print verbosely'
|
27
|
+
# on :n, :name=, 'Set your name, if not Joe', :default => 'Joe'
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# run do
|
31
|
+
# puts "Hello #{options[:name]}!"
|
32
|
+
# if options.verbose?
|
33
|
+
# puts "It's currently #{Time.now}"
|
34
|
+
# puts "Very glad to see you! How are you doing today?"
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# This will create a Jenkins CLI command called `hello-world`
|
40
|
+
# Which can be used as
|
41
|
+
# jenkins-cli hello-world --n cowboyd -v
|
42
|
+
#
|
43
|
+
# @see {https://github.com/injekt/slop Slop}
|
44
|
+
# @see {https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+CLI Running Jenkins CLI}
|
45
|
+
module Command
|
46
|
+
extend Jenkins::Plugin::Behavior
|
47
|
+
|
48
|
+
implemented do |cls|
|
49
|
+
cls.instance_eval do
|
50
|
+
@slop_block = Proc.new {}
|
51
|
+
@run_block = Proc.new {}
|
52
|
+
@description = 'No description'
|
53
|
+
command_name default_command_name
|
54
|
+
end
|
55
|
+
Jenkins.plugin.register_extension CommandProxy.new(Jenkins.plugin, cls.new)
|
56
|
+
end
|
57
|
+
|
58
|
+
module ClassMethods
|
59
|
+
attr_reader :slop_block, :run_block
|
60
|
+
|
61
|
+
# Set (or get) the description shown by this command in the 'help' CLI
|
62
|
+
# command. Also used in the default implementation of Slop's banner -
|
63
|
+
# meaning the my-command --help output.
|
64
|
+
#
|
65
|
+
# Example: description "Cool command that'll rock your world!"
|
66
|
+
# @param [String] description the description of the command
|
67
|
+
# @return [String] the description of the command
|
68
|
+
def description(desc = nil)
|
69
|
+
desc ? @description = desc : @description
|
70
|
+
end
|
71
|
+
|
72
|
+
# Set up the block passed to Slop.parse. See the Slop README for
|
73
|
+
# information on the way this block works:
|
74
|
+
# https://github.com/injekt/slop/blob/master/README.md
|
75
|
+
#
|
76
|
+
# Example: arguments { on :v, :verbose, "Be verbose" }
|
77
|
+
#
|
78
|
+
# @yield a declaration of arguments and options of this command
|
79
|
+
def arguments(&slop_block)
|
80
|
+
@slop_block = slop_block
|
81
|
+
end
|
82
|
+
|
83
|
+
# Define the actual implementation of the command
|
84
|
+
#
|
85
|
+
# This block specified with {#run} will be invoked in the
|
86
|
+
# scope of a fresh instance for each command invocation.
|
87
|
+
#
|
88
|
+
# Example: run { puts "Hello world" }
|
89
|
+
#
|
90
|
+
# @yield the command body
|
91
|
+
def run(&run_block)
|
92
|
+
@run_block = run_block
|
93
|
+
end
|
94
|
+
|
95
|
+
# Get/set the name by which the command will be invoked.
|
96
|
+
#
|
97
|
+
# This is what the user has to call the command as. The default value is
|
98
|
+
# the class name, with any 'Command' suffix removed, and the 'CamelCase'
|
99
|
+
# words separated using hypen, into 'camel-case'. For example this turns
|
100
|
+
# `HelloWorldCommand` into `hello-world`.
|
101
|
+
#
|
102
|
+
# To use a custom name, just invoke it with that name. E.g.
|
103
|
+
#
|
104
|
+
# command_name "my-cooler-name"
|
105
|
+
#
|
106
|
+
# @param [String] the name with which the command will be invoked
|
107
|
+
# @return [String] the command name
|
108
|
+
def command_name(command_name = nil)
|
109
|
+
command_name ? @command_name = command_name : @command_name
|
110
|
+
end
|
111
|
+
|
112
|
+
# We use this to initialize the default value of @command_name. You can
|
113
|
+
# override this using the above `command_name`.
|
114
|
+
def default_command_name
|
115
|
+
command = name
|
116
|
+
|
117
|
+
# Replace any 'CLICommand' or 'Command' suffix on class name.
|
118
|
+
command = command.sub(/(CLI)?Command$/, '')
|
119
|
+
|
120
|
+
# Then convert "FooBarZot" into "Foo-Bar-Zot"
|
121
|
+
command = command.gsub(/([a-z0-9])([A-Z])/, '\1-\2')
|
122
|
+
|
123
|
+
# Then lower-case it.
|
124
|
+
command.downcase
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
module InstanceMethods
|
129
|
+
attr_reader :options
|
130
|
+
|
131
|
+
# Set up the instance with command-line arguments.
|
132
|
+
#
|
133
|
+
# Any arguments from the terminal will be passed to {#parse} as
|
134
|
+
# a whitespace separated list. The default implementation uses
|
135
|
+
# Slop to parse this list with the block passed to {.arguments}
|
136
|
+
#
|
137
|
+
# Note: If this method returns a falsy value, then the command will
|
138
|
+
# *not* be run.
|
139
|
+
#
|
140
|
+
# You can override this instance method if you don't want to use Slop, or
|
141
|
+
# if you want to do some preprocessing before Slop is called.
|
142
|
+
# param [Array] args the list of whitespace separated command line arguments
|
143
|
+
# return [Object] a truthy value if the parse succeeded and the command can be run.
|
144
|
+
def parse(args)
|
145
|
+
default_banner = "#{self.class.command_name} [options] - #{self.class.description}"
|
146
|
+
@options = Slop.new(:help => true, :strict => true,
|
147
|
+
:banner => default_banner, &self.class.slop_block)
|
148
|
+
@options.parse(args)
|
149
|
+
rescue Slop::Error => e
|
150
|
+
$stderr.puts e.message
|
151
|
+
$stderr.puts @options.help
|
152
|
+
end
|
153
|
+
|
154
|
+
# Run the command.
|
155
|
+
#
|
156
|
+
# This method is invoked immediately after {#parse} and
|
157
|
+
# implements the "meat" of the command. By default, it invokes
|
158
|
+
# body specified with {.run}.
|
159
|
+
#
|
160
|
+
# There should generally be no reason to override this, but hey
|
161
|
+
# it's your world! :-)
|
162
|
+
def run
|
163
|
+
self.instance_eval(&self.class.run_block)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'core_ext/exception'
|
2
|
+
|
3
|
+
module Jenkins::CLI
|
4
|
+
# The native Java CLICommand class has a static initializer
|
5
|
+
# that prevents the class from being loaded without a running
|
6
|
+
# Jenkins instance. This disgusting hack detects if we're in
|
7
|
+
# RSpec mode and just creates the proxy class without descending
|
8
|
+
# from the Java class.
|
9
|
+
if Jenkins.rspec_ewwww_gross_hack?
|
10
|
+
class CommandProxy; end
|
11
|
+
else
|
12
|
+
class CommandProxy < Java.hudson.cli.CLICommand; end
|
13
|
+
end
|
14
|
+
|
15
|
+
class CommandProxy
|
16
|
+
include Jenkins::Plugin::Proxy
|
17
|
+
|
18
|
+
AbortException = Java.hudson.AbortException
|
19
|
+
|
20
|
+
def getShortDescription
|
21
|
+
@object.class.description
|
22
|
+
end
|
23
|
+
|
24
|
+
def createClone
|
25
|
+
self.dup.tap do |dup|
|
26
|
+
dup.instance_variable_set(:@object, @object.dup)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# This mirrors what Java.hudson.cli.CLICommand#getName does, but with the
|
31
|
+
# @object's class instead.
|
32
|
+
def getName
|
33
|
+
@object.class.command_name
|
34
|
+
end
|
35
|
+
|
36
|
+
def run
|
37
|
+
# We don't call run from within our main, but needs to be here to satisfy the Java Interface
|
38
|
+
raise RuntimeError, "This method should never be called."
|
39
|
+
end
|
40
|
+
|
41
|
+
# main(List<String> args, Locale locale, InputStream stdin, PrintStream stdout, PrintStream stderr)
|
42
|
+
def main(args, locale, stdin, stdout, stderr)
|
43
|
+
old_in, old_out, old_err = $stdin, $stdout, $stderr
|
44
|
+
begin
|
45
|
+
$stdin, $stdout, $stderr = stdin.to_io, stdout.to_io, stderr.to_io
|
46
|
+
if @object.parse(args.to_a)
|
47
|
+
@object.run
|
48
|
+
return 0
|
49
|
+
else
|
50
|
+
return -1
|
51
|
+
end
|
52
|
+
rescue AbortException
|
53
|
+
return -1
|
54
|
+
rescue => e
|
55
|
+
$stderr.puts e.full_message
|
56
|
+
return -1
|
57
|
+
ensure
|
58
|
+
$stdin, $stdout, $stderr = old_in, old_out, old_err
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/jenkins/filepath.rb
CHANGED
@@ -2,14 +2,9 @@ require 'pathname'
|
|
2
2
|
|
3
3
|
module Jenkins
|
4
4
|
class FilePath
|
5
|
+
include Jenkins::Plugin::Wrapper
|
5
6
|
Stat = Struct.new(:size, :mode, :mtime)
|
6
7
|
|
7
|
-
attr_reader :native
|
8
|
-
|
9
|
-
def initialize(native)
|
10
|
-
@native = native
|
11
|
-
end
|
12
|
-
|
13
8
|
# Ruby's Pathname internace
|
14
9
|
|
15
10
|
def +(name)
|
data/lib/jenkins/launcher.rb
CHANGED
@@ -2,12 +2,11 @@ module Jenkins
|
|
2
2
|
|
3
3
|
# Launch processes on build slaves. No functionality is currently exposed
|
4
4
|
class Launcher
|
5
|
-
|
6
|
-
|
5
|
+
include Jenkins::Plugin::Wrapper
|
6
|
+
wrapper_for Java.hudson.Launcher
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
end
|
8
|
+
class Proc
|
9
|
+
include Jenkins::Plugin::Wrapper
|
11
10
|
|
12
11
|
def alive?
|
13
12
|
@native.isAlive()
|
@@ -35,13 +34,6 @@ module Jenkins
|
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
38
|
-
# the native hudson.Launcher object
|
39
|
-
attr_reader :native
|
40
|
-
|
41
|
-
def initialize(native = nil)
|
42
|
-
@native = native
|
43
|
-
end
|
44
|
-
|
45
37
|
# execute([env,] command... [,options]) -> fixnum
|
46
38
|
def execute(*args)
|
47
39
|
spawn(*args).join
|
@@ -113,7 +105,5 @@ module Jenkins
|
|
113
105
|
end
|
114
106
|
[env || {}, cmd, opt || {}]
|
115
107
|
end
|
116
|
-
|
117
|
-
Plugin::Proxies.register self, Java.hudson.Launcher
|
118
108
|
end
|
119
109
|
end
|
data/lib/jenkins/model.rb
CHANGED
@@ -1,30 +1,7 @@
|
|
1
1
|
|
2
2
|
module Jenkins
|
3
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
|
4
|
+
extend Plugin::Behavior
|
28
5
|
|
29
6
|
module InstanceDisplayName
|
30
7
|
# Get the display name of this Model. This value will be used as a default
|
@@ -66,26 +43,16 @@ module Jenkins
|
|
66
43
|
def transients
|
67
44
|
@transients ||= {}
|
68
45
|
end
|
69
|
-
end
|
70
46
|
|
71
|
-
|
72
|
-
def descendant(mod)
|
73
|
-
@descendants ||= clear
|
74
|
-
@descendants[mod] = true
|
75
|
-
end
|
76
|
-
|
77
|
-
def descendants
|
78
|
-
@descendants.keys
|
79
|
-
end
|
47
|
+
end
|
80
48
|
|
81
|
-
|
82
|
-
|
83
|
-
|
49
|
+
module ClassMethods
|
50
|
+
include ClassDisplayName
|
51
|
+
include Transience
|
52
|
+
end
|
84
53
|
|
85
|
-
|
86
|
-
|
87
|
-
end
|
54
|
+
module InstanceMethods
|
55
|
+
include InstanceDisplayName
|
88
56
|
end
|
89
|
-
extend Descendants
|
90
57
|
end
|
91
58
|
end
|
data/lib/jenkins/model/action.rb
CHANGED
@@ -1,13 +1,8 @@
|
|
1
|
-
|
2
1
|
require 'jenkins/model'
|
3
2
|
|
4
3
|
module Jenkins
|
5
4
|
module Model
|
6
|
-
|
7
|
-
# TODO: I turned Action into Class from Module but it should be a bad idea.
|
8
|
-
# The change may be reverted. I used class Action for implementing a model
|
9
|
-
# as a describable but I really should do is implementing describable.
|
10
|
-
class Action
|
5
|
+
module Action
|
11
6
|
include Model
|
12
7
|
|
13
8
|
module InstanceMethods
|
@@ -29,9 +24,6 @@ module Jenkins
|
|
29
24
|
path.nil? ? @url_path : @url_path = path.to_s
|
30
25
|
end
|
31
26
|
end
|
32
|
-
|
33
|
-
include InstanceMethods
|
34
|
-
extend ClassMethods
|
35
27
|
end
|
36
28
|
end
|
37
29
|
end
|