jpi 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Gemfile +4 -0
- data/README.md +76 -0
- data/Rakefile +6 -0
- data/bin/jpi +5 -0
- data/features/create-new-plugin.feature +18 -0
- data/features/support/create_new_plugin_steps.rb +7 -0
- data/features/support/directory_structure.rb +49 -0
- data/features/support/work.rb +20 -0
- data/jpi.gemspec +28 -0
- data/lib/jenkins/jenkins-ci.org/credential.rb +39 -0
- data/lib/jenkins/plugin/cli.rb +66 -0
- data/lib/jenkins/plugin/cli/formatting.rb +54 -0
- data/lib/jenkins/plugin/cli/generate.rb +27 -0
- data/lib/jenkins/plugin/cli/new.rb +39 -0
- data/lib/jenkins/plugin/cli/templates/Gemfile.tt +4 -0
- data/lib/jenkins/plugin/cli/templates/build_step.tt +25 -0
- data/lib/jenkins/plugin/cli/templates/pluginspec.tt +28 -0
- data/lib/jenkins/plugin/tools/bundle.rb +30 -0
- data/lib/jenkins/plugin/tools/hpi.rb +107 -0
- data/lib/jenkins/plugin/tools/loadpath.rb +29 -0
- data/lib/jenkins/plugin/tools/manifest.rb +80 -0
- data/lib/jenkins/plugin/tools/package.rb +60 -0
- data/lib/jenkins/plugin/tools/release.rb +70 -0
- data/lib/jenkins/plugin/tools/resolver.rb +61 -0
- data/lib/jenkins/plugin/tools/server.rb +49 -0
- data/lib/jenkins/plugin/tools/templates/release-pom.xml.erb +54 -0
- data/lib/jenkins/plugin/version.rb +5 -0
- data/lib/jenkins/rake.rb +52 -0
- metadata +164 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# Jenkins plugins
|
2
|
+
|
3
|
+
Provide the facility to create, develop and release extensions for [Jenkins](http://jenkins-ci.org) with nothing but knowledge of the language, tools and best practices of the Ruby community.
|
4
|
+
|
5
|
+
[read more](http://blog.thefrontside.net/2011/05/12/what-it-take-to-bring-ruby-to-jenkins)...
|
6
|
+
|
7
|
+
# Get started
|
8
|
+
|
9
|
+
Using JRuby, install the plugin tools
|
10
|
+
|
11
|
+
$ gem install jpi
|
12
|
+
|
13
|
+
The gem provides the `jpi` executeable
|
14
|
+
|
15
|
+
$ jpi -h
|
16
|
+
|
17
|
+
jpi- tools to create, build, develop and release Jenkins plugins
|
18
|
+
|
19
|
+
Usage: jpi command [arguments] [options]
|
20
|
+
|
21
|
+
Commands:
|
22
|
+
jpi help [COMMAND] # get help for COMMAND, or for jpi itself
|
23
|
+
jpi new NAME # create a new plugin called NAME
|
24
|
+
jpi generate # generate code for extensions points
|
25
|
+
jpi build # build plugin into .hpi file suitable for distribution
|
26
|
+
jpi server # run a test server with plugin
|
27
|
+
jpi version # show jpi version information
|
28
|
+
|
29
|
+
The first thing you'll probably want to do is create a new ruby plugin.
|
30
|
+
|
31
|
+
$ jpi new one-great-plugin
|
32
|
+
create one-great-plugin/Gemfile
|
33
|
+
create one-great-plugin/one-great-plugin.pluginspec
|
34
|
+
|
35
|
+
This will create a minimal plugin project structure, to which you can add later.
|
36
|
+
Once you have your plugin created, you can run a server with it loaded
|
37
|
+
|
38
|
+
$ cd one-great-plugin
|
39
|
+
$ jpi server
|
40
|
+
|
41
|
+
Listening for transport dt_socket at address: 8000
|
42
|
+
webroot: System.getProperty("JENKINS_HOME")
|
43
|
+
[Winstone 2011/09/19 12:01:36] - Beginning extraction from war file
|
44
|
+
[Winstone 2011/09/19 12:01:37] - HTTP Listener started: port=8080
|
45
|
+
[Winstone 2011/09/19 12:01:37] - AJP13 Listener started: port=8009
|
46
|
+
[Winstone 2011/09/19 12:01:37] - Winstone Servlet Engine v0.9.10 running: controlPort=disabled
|
47
|
+
Sep 19, 2011 12:01:37 PM jenkins.model.Jenkins$6 onAttained
|
48
|
+
INFO: Started initialization
|
49
|
+
Sep 19, 2011 12:01:38 PM hudson.PluginManager$1$3$1 isDuplicate
|
50
|
+
Sep 19, 2011 12:01:39 PM jenkins.model.Jenkins$6 onAttained
|
51
|
+
INFO: Listed all plugins
|
52
|
+
Sep 19, 2011 12:01:39 PM ruby.RubyRuntimePlugin start
|
53
|
+
INFO: Injecting JRuby into XStream
|
54
|
+
Sep 19, 2011 12:01:49 PM jenkins.model.Jenkins$6 onAttained
|
55
|
+
INFO: Prepared all plugins
|
56
|
+
Sep 19, 2011 12:01:49 PM jenkins.model.Jenkins$6 onAttained
|
57
|
+
INFO: Started all plugins
|
58
|
+
Sep 19, 2011 12:01:49 PM jenkins.model.Jenkins$6 onAttained
|
59
|
+
INFO: Augmented all extensions
|
60
|
+
Sep 19, 2011 12:01:49 PM jenkins.model.Jenkins$6 onAttained
|
61
|
+
INFO: Loaded all jobs
|
62
|
+
Sep 19, 2011 12:01:51 PM jenkins.model.Jenkins$6 onAttained
|
63
|
+
INFO: Completed initialization
|
64
|
+
Sep 19, 2011 12:01:51 PM hudson.TcpSlaveAgentListener <init>
|
65
|
+
INFO: JNLP slave agent listener started on TCP port 52262
|
66
|
+
Sep 19, 2011 12:02:01 PM hudson.WebAppMain$2 run
|
67
|
+
INFO: Jenkins is fully up and running
|
68
|
+
|
69
|
+
Of course, this plugin isn't actually doing anything because we haven't defined any extension
|
70
|
+
points. Let's go ahead and create one of the most common extension points: a `Builder`
|
71
|
+
|
72
|
+
$ jpi generate builder logging
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
|
data/Rakefile
ADDED
data/bin/jpi
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
Feature: Generating a new Jenkins Ruby Plugin
|
3
|
+
|
4
|
+
Creating a new Ruby plugin for Jenkins needs to be as simple as running a single command
|
5
|
+
that will generate a project skeleton. This skeleton will come complete with git repository and all
|
6
|
+
the goodies that you need to do your plugin develompent.
|
7
|
+
|
8
|
+
Scenario: The directory skeleton is generated
|
9
|
+
When I run "jpi new newplugin"
|
10
|
+
# Then I should see this structure
|
11
|
+
# """
|
12
|
+
# [-] newplugin
|
13
|
+
# | [+] .git
|
14
|
+
# | .gitignore
|
15
|
+
# | Gemfile
|
16
|
+
# | Rakefile
|
17
|
+
# | newplugin.pluginspec
|
18
|
+
# """
|
@@ -0,0 +1,49 @@
|
|
1
|
+
|
2
|
+
class DirectoryStructure
|
3
|
+
def initialize(structure)
|
4
|
+
|
5
|
+
@root = context = DirChild.new('.')
|
6
|
+
|
7
|
+
structure.each_line do |line|
|
8
|
+
if line =~ /(\[[-+]\]|\|)?\s+(\.?\w+)$/
|
9
|
+
op, name = $1, $2
|
10
|
+
case op
|
11
|
+
when "[+]"
|
12
|
+
context.add(DirChild.new name)
|
13
|
+
when "[-]"
|
14
|
+
new_context = DirChild.new name
|
15
|
+
context.add(new_context)
|
16
|
+
context = new_context
|
17
|
+
when "|"
|
18
|
+
context.add(FileChild.new name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def matches?(dir)
|
25
|
+
@root.matches?(dir)
|
26
|
+
end
|
27
|
+
|
28
|
+
Entry = Struct.new(:name)
|
29
|
+
|
30
|
+
class DirChild < Entry
|
31
|
+
def initialize(name)
|
32
|
+
super(name)
|
33
|
+
@entries = []
|
34
|
+
end
|
35
|
+
|
36
|
+
def add(entry)
|
37
|
+
@entries << entries
|
38
|
+
end
|
39
|
+
|
40
|
+
def matches?(realdir)
|
41
|
+
entries = Dir.new(realdir).entries
|
42
|
+
!@entries.detect {|e| !entries.map{|e| File.basename(e)}.member?(e)}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class FileChild < Entry
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Work
|
2
|
+
def run cmd
|
3
|
+
Dir.chdir(work_dir) do
|
4
|
+
root = Pathname(__FILE__).join('..', '..', '..')
|
5
|
+
full_cmd = "ruby -rubygems -I #{root.join('lib')} -S #{root.join('bin',cmd)}"
|
6
|
+
system(full_cmd) or fail "failed to run command #{cmd}"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def work_dir
|
11
|
+
@work_dir ||= File.expand_path("tmp/work")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Before do
|
16
|
+
FileUtils.rm_rf work_dir
|
17
|
+
FileUtils.mkdir_p work_dir
|
18
|
+
end
|
19
|
+
|
20
|
+
World(Work)
|
data/jpi.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "jenkins/plugin/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "jpi"
|
7
|
+
s.version = Jenkins::Plugin::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Charles Lowell", "Jørgen P. Tjernø", "Kohsuke Kawaguchi"]
|
10
|
+
s.email = ["cowboyd@thefrontside.net"]
|
11
|
+
s.homepage = "https://github.com/jenkinsci/jpi.rb"
|
12
|
+
s.summary = %q{Tools for creating and building Jenkins Ruby plugins}
|
13
|
+
s.description = %q{Allows you to generate a new Ruby plugin project, build it, test it in Jenkins and release it to the Jenkins Update Center.}
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.add_dependency "rubyzip"
|
21
|
+
s.add_dependency "thor"
|
22
|
+
s.add_dependency "jenkins-war", ">= 1.427"
|
23
|
+
s.add_dependency "bundler", "~> 1.1.rc2"
|
24
|
+
s.add_dependency "jenkins-plugin-runtime", "~> 0.1.13"
|
25
|
+
|
26
|
+
s.add_development_dependency "rspec", "~> 2.0"
|
27
|
+
s.add_development_dependency "cucumber", "~> 1.0"
|
28
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Jenkins
|
2
|
+
class CiOrg
|
3
|
+
# credential to access jenkins-ci.org
|
4
|
+
# TODO: move it elsewhere
|
5
|
+
class Credential
|
6
|
+
CREDENTIAL = File.expand_path("~/.jenkins-ci.org")
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@props = {}
|
10
|
+
|
11
|
+
if File.exists?(CREDENTIAL) then
|
12
|
+
File.open(CREDENTIAL,'r') do |f|
|
13
|
+
f.each_line do |l|
|
14
|
+
if l[0]=='#' then
|
15
|
+
return # comment
|
16
|
+
end
|
17
|
+
|
18
|
+
k,v = l.split("=",2)
|
19
|
+
@props[k]=v.strip
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# do we already have the credential?
|
26
|
+
def has_credential?
|
27
|
+
@props["userName"] && @props["password"]
|
28
|
+
end
|
29
|
+
|
30
|
+
def user_name
|
31
|
+
@props["userName"]
|
32
|
+
end
|
33
|
+
|
34
|
+
def password
|
35
|
+
@props["password"]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
|
2
|
+
require 'thor'
|
3
|
+
require 'jenkins/plugin/specification'
|
4
|
+
require 'jenkins/plugin/cli/formatting'
|
5
|
+
require 'jenkins/plugin/cli/new'
|
6
|
+
require 'jenkins/plugin/cli/generate'
|
7
|
+
|
8
|
+
|
9
|
+
module Jenkins
|
10
|
+
class Plugin
|
11
|
+
class CLI < Thor
|
12
|
+
extend Formatting
|
13
|
+
|
14
|
+
register New, "new", "new NAME", "create a new plugin called NAME"
|
15
|
+
register Generate, "generate", "generate [options] [arguments]", "add new classes/templates and views to your project"
|
16
|
+
map "g" => "generate"
|
17
|
+
|
18
|
+
|
19
|
+
desc "build", "build plugin into .hpi file suitable for distribution"
|
20
|
+
def build
|
21
|
+
require 'jenkins/plugin/tools/package'
|
22
|
+
pkg = Tools::Package.new(spec, "pkg")
|
23
|
+
pkg.build
|
24
|
+
pkg
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "server", "run a test server with plugin"
|
28
|
+
method_option :home, :desc => "set server work directory", :default => 'work'
|
29
|
+
method_option :port, :desc => "server http port (currently ignored)", :default => 8080
|
30
|
+
method_option :war, :desc => "specify a custom jenkins.war to run the plugin with"
|
31
|
+
def server
|
32
|
+
require 'jenkins/plugin/tools/server'
|
33
|
+
server = Tools::Server.new(spec, options[:home], options[:war])
|
34
|
+
server.run!
|
35
|
+
end
|
36
|
+
map "s" => "server"
|
37
|
+
|
38
|
+
desc "release", "release to jenkins-ci.org"
|
39
|
+
method_option :release, :desc => "deploy as a release (as opposed to a snapshot)", :type => :boolean
|
40
|
+
def release
|
41
|
+
require 'jenkins/plugin/tools/release'
|
42
|
+
|
43
|
+
Tools::Release.new(spec,build().file_name, !options[:release]).run
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "version", "show jpi version information"
|
47
|
+
def version
|
48
|
+
require 'jenkins/plugin/version'
|
49
|
+
shell.say Jenkins::Plugin::VERSION
|
50
|
+
end
|
51
|
+
map ["-v","--version"] => "version"
|
52
|
+
|
53
|
+
desc "help [COMMAND]", "get help for COMMAND, or for jpi itself"
|
54
|
+
def help(command = nil)
|
55
|
+
super
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def spec
|
61
|
+
Specification.find!
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
|
2
|
+
module Jenkins
|
3
|
+
class Plugin
|
4
|
+
class CLI < Thor
|
5
|
+
module Formatting
|
6
|
+
def task_help(shell, task_name)
|
7
|
+
meth = normalize_task_name(task_name)
|
8
|
+
task = all_tasks[meth]
|
9
|
+
handle_no_task_error(meth) unless task
|
10
|
+
|
11
|
+
shell.say "usage: #{banner(task)}"
|
12
|
+
shell.say
|
13
|
+
class_options_help(shell, nil => task.options.map { |_, o| o })
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def print_options(shell, options, grp = nil)
|
18
|
+
return if options.empty?
|
19
|
+
table = options.map do |option|
|
20
|
+
prototype = if option.default
|
21
|
+
" [#{option.default}]"
|
22
|
+
elsif option.type == :boolean
|
23
|
+
""
|
24
|
+
elsif option.required?
|
25
|
+
" #{option.banner}"
|
26
|
+
else
|
27
|
+
" [#{option.banner}]"
|
28
|
+
end
|
29
|
+
aliases = option.aliases.empty? ? "" : option.aliases.join(" ") + ","
|
30
|
+
[aliases, "--#{option.name}#{prototype}", "\t",option.description]
|
31
|
+
end
|
32
|
+
shell.print_table(table, :ident => 2)
|
33
|
+
shell.say
|
34
|
+
end
|
35
|
+
|
36
|
+
def help(shell, task)
|
37
|
+
list = printable_tasks
|
38
|
+
print shell.set_color("jpi", :black, true)
|
39
|
+
shell.say <<-USEAGE
|
40
|
+
- tools to create, build, develop and release Jenkins plugins
|
41
|
+
|
42
|
+
Usage: jpi command [arguments] [options]
|
43
|
+
|
44
|
+
USEAGE
|
45
|
+
|
46
|
+
shell.say "Commands:"
|
47
|
+
shell.print_table(list, :ident => 2, :truncate => true)
|
48
|
+
shell.say
|
49
|
+
class_options_help(shell)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
module Jenkins
|
3
|
+
class Plugin
|
4
|
+
class CLI
|
5
|
+
class Generate < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
source_root File.dirname(__FILE__)
|
9
|
+
|
10
|
+
argument :name
|
11
|
+
|
12
|
+
desc "publisher", "publisher NAME", :desc => "generate a publish step definition"
|
13
|
+
def publisher
|
14
|
+
@step_class = "Publisher"
|
15
|
+
template('templates/build_step.tt', "models/#{name.downcase}_publisher.rb")
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "builder", "builder NAME", :desc => "generate a build step definition"
|
19
|
+
def builder
|
20
|
+
@step_class = "Builder"
|
21
|
+
template('templates/build_step.tt', "models/#{name.downcase}_builder.rb")
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
require 'thor/group'
|
3
|
+
|
4
|
+
module Jenkins
|
5
|
+
class Plugin
|
6
|
+
class CLI
|
7
|
+
class New < Thor::Group
|
8
|
+
include Thor::Actions
|
9
|
+
|
10
|
+
source_root File.dirname(__FILE__)
|
11
|
+
|
12
|
+
argument :name
|
13
|
+
|
14
|
+
def create_gemfile
|
15
|
+
template('templates/Gemfile.tt', "#{name}/Gemfile")
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_pluginspec
|
19
|
+
git_name = %x[git config user.name].chomp
|
20
|
+
git_email = %x[git config user.email].chomp
|
21
|
+
|
22
|
+
developer_id = git_email.split('@', 2).first || ''
|
23
|
+
|
24
|
+
# Fallback values.
|
25
|
+
git_name = 'TODO: Put your realname here' if git_name.empty?
|
26
|
+
git_email = 'email@example.com' if git_email.empty?
|
27
|
+
|
28
|
+
opts = {
|
29
|
+
:developer_id => developer_id.empty? ? 'TODO: Put your jenkins-ci.org username here.' : developer_id,
|
30
|
+
:developer_name => "#{git_name} <#{git_email}>"
|
31
|
+
}
|
32
|
+
|
33
|
+
template('templates/pluginspec.tt', "#{name}/#{name}.pluginspec", opts)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
class <%= name.capitalize %><%= @step_class %> < Jenkins::Tasks::<%= @step_class %>
|
3
|
+
|
4
|
+
display_name "<%= name.capitalize %> <%= @step_class.downcase %>"
|
5
|
+
|
6
|
+
##
|
7
|
+
# Runs before the build begins
|
8
|
+
#
|
9
|
+
# @param [Jenkins::Model::Build] build the build which will begin
|
10
|
+
# @param [Jenkins::Model::Listener] listener the listener for this build.
|
11
|
+
def prebuild(build, listener)
|
12
|
+
# do any setup that needs to be done before this build runs.
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Runs the step over the given build and reports the progress to the listener.
|
17
|
+
#
|
18
|
+
# @param [Jenkins::Model::Build] build on which to run this step
|
19
|
+
# @param [Jenkins::Launcher] launcher the launcher that can run code on the node running this build
|
20
|
+
# @param [Jenkins::Model::Listener] listener the listener for this build.
|
21
|
+
def perform(build, launcher, listener)
|
22
|
+
# actually perform the build step
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
Jenkins::Plugin::Specification.new do |plugin|
|
3
|
+
plugin.name = <%= name.inspect %>
|
4
|
+
plugin.display_name = <%= (name.capitalize + " Plugin").inspect %>
|
5
|
+
plugin.version = '0.0.1'
|
6
|
+
plugin.description = 'enter description here'
|
7
|
+
|
8
|
+
# You should create a wiki-page for your plugin when you publish it, see
|
9
|
+
# https://wiki.jenkins-ci.org/display/JENKINS/Hosting+Plugins#HostingPlugins-AddingaWikipage
|
10
|
+
# This line makes sure it's listed in your POM.
|
11
|
+
plugin.url = 'https://wiki.jenkins-ci.org/display/JENKINS/My+Plugin'
|
12
|
+
|
13
|
+
# The first argument is your user name for jenkins-ci.org.
|
14
|
+
plugin.developed_by <%= config[:developer_id].inspect %>, <%= config[:developer_name].inspect %>
|
15
|
+
|
16
|
+
# This specifies where your code is hosted.
|
17
|
+
# Alternatives include:
|
18
|
+
# :github => 'myuser/my-plugin' (without myuser it defaults to jenkinsci)
|
19
|
+
# :git => 'git://repo.or.cz/my-plugin.git'
|
20
|
+
# :svn => 'https://svn.jenkins-ci.org/trunk/hudson/plugins/my-plugin'
|
21
|
+
plugin.uses_repository :github => 'my-plugin'
|
22
|
+
|
23
|
+
# This is a required dependency for every ruby plugin.
|
24
|
+
plugin.depends_on 'ruby-runtime', '0.4'
|
25
|
+
|
26
|
+
# This is a sample dependency for a Jenkins plugin, 'git'.
|
27
|
+
plugin.depends_on 'git', '1.1.11'
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
module Jenkins
|
3
|
+
class Plugin
|
4
|
+
module Tools
|
5
|
+
class Bundle
|
6
|
+
|
7
|
+
def initialize(target)
|
8
|
+
@target = target
|
9
|
+
end
|
10
|
+
|
11
|
+
def install
|
12
|
+
require 'java'
|
13
|
+
require 'bundler'
|
14
|
+
puts "bundling..."
|
15
|
+
|
16
|
+
# We set these in ENV instead of passing the --without and --path
|
17
|
+
# options because the CLI options are remembered in .bundle/config and
|
18
|
+
# will interfere with regular usage of bundle exec / install.
|
19
|
+
Bundler.with_clean_env {
|
20
|
+
ENV['BUNDLE_APP_CONFIG'] = "#{@target}/vendor/bundle"
|
21
|
+
ENV['BUNDLE_WITHOUT'] = "development"
|
22
|
+
ENV['BUNDLE_PATH'] = "#{@target}/vendor/gems"
|
23
|
+
ENV.delete 'RUBYOPT'
|
24
|
+
system('bundle --standalone')
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'zip/zip'
|
2
|
+
require 'net/http'
|
3
|
+
require 'uri'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
module Jenkins
|
7
|
+
class Plugin
|
8
|
+
module Tools
|
9
|
+
# class for parsing hpi file and its manifests
|
10
|
+
class Hpi
|
11
|
+
attr_reader :file, :manifest
|
12
|
+
|
13
|
+
# take the path name to the plugin file
|
14
|
+
def initialize(file)
|
15
|
+
@file = file
|
16
|
+
|
17
|
+
# load and parse manifests
|
18
|
+
Zip::ZipFile.open(@file) do |zip|
|
19
|
+
zip.get_input_stream("META-INF/MANIFEST.MF") do |m|
|
20
|
+
# main section of the manifest
|
21
|
+
@manifest = parse_manifest(m.read)[0]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# parse dependencies into hash
|
26
|
+
@dependencies = {}
|
27
|
+
deps = @manifest["Plugin-Dependencies"]
|
28
|
+
if deps
|
29
|
+
deps.split(",").each do |token|
|
30
|
+
token = token.gsub(/;.+/,"") # trim off the optional portions
|
31
|
+
name,ver = token.split(":")
|
32
|
+
@dependencies[name] = ver
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# given the plugin short name and the version number,
|
38
|
+
# return the path name of the .hpi file by either locating the plugin locally or downloading it.
|
39
|
+
def self.resolve(short_name,version)
|
40
|
+
# this is where we expect the retrieved file to be
|
41
|
+
cache = File.expand_path "~/.jenkins/cache/plugins/#{short_name}/#{version}/#{short_name}.hpi"
|
42
|
+
|
43
|
+
return cache if File.exists?(cache)
|
44
|
+
|
45
|
+
# now we start looking for places to find them
|
46
|
+
|
47
|
+
# is it in the local maven2 repository?
|
48
|
+
maven = File.expand_path "~/.m2/repository/org/jenkins-ci/plugins/#{short_name}/#{version}/#{short_name}-#{version}.hpi"
|
49
|
+
return maven if File.exists?(maven)
|
50
|
+
|
51
|
+
# download from the community update center
|
52
|
+
FileUtils.mkdir_p(File.dirname(cache))
|
53
|
+
open(cache+".tmp","wb") do |f|
|
54
|
+
puts "Downloading #{short_name} #{version}"
|
55
|
+
url = "http://updates.jenkins-ci.org/download/plugins/#{short_name}/#{version}/#{short_name}.hpi?for=ruby-plugin"
|
56
|
+
puts " from #{url}"
|
57
|
+
f.write fetch(url).body
|
58
|
+
end
|
59
|
+
FileUtils.mv cache+".tmp", cache
|
60
|
+
|
61
|
+
return cache
|
62
|
+
end
|
63
|
+
|
64
|
+
# download with redirect support
|
65
|
+
def self.fetch(uri, limit = 10)
|
66
|
+
# You should choose better exception.
|
67
|
+
raise ArgumentError, 'HTTP redirect too deep' if limit == 0
|
68
|
+
|
69
|
+
response = Net::HTTP.get_response(URI.parse(uri))
|
70
|
+
case response
|
71
|
+
when Net::HTTPSuccess then response
|
72
|
+
when Net::HTTPRedirection then fetch(response['location'], limit - 1)
|
73
|
+
else
|
74
|
+
response.error!
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# parse manifest file text into a hash
|
79
|
+
def parse_manifest(txt)
|
80
|
+
# separators
|
81
|
+
nl = /\r\n|\n|\r[^\n]/
|
82
|
+
secsep = /(#{nl}){2}/
|
83
|
+
|
84
|
+
txt.split(secsep).reject { |s| s.chomp.length==0 }.map do |section|
|
85
|
+
lines = []
|
86
|
+
section.split(nl).each do |line|
|
87
|
+
if line[0]==0x20
|
88
|
+
lines.last << line[1..-1] # continuation of the previous line
|
89
|
+
else
|
90
|
+
lines << line
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# convert to hash
|
95
|
+
hash = {}
|
96
|
+
lines.each do |l|
|
97
|
+
(k,v) = l.split(/: /,2)
|
98
|
+
hash[k] = v
|
99
|
+
end
|
100
|
+
|
101
|
+
hash
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Jenkins
|
2
|
+
class Plugin
|
3
|
+
module Tools
|
4
|
+
class Loadpath
|
5
|
+
def initialize(*groups)
|
6
|
+
require 'bundler'
|
7
|
+
@groups = groups.empty? ? [:default] : groups
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_path
|
11
|
+
to_a.join(File::PATH_SEPARATOR)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_a
|
15
|
+
[].tap do |paths|
|
16
|
+
specs = Bundler.definition.specs_for @groups.map {|g| g.to_sym}
|
17
|
+
for spec in specs
|
18
|
+
next if spec.name == "bundler"
|
19
|
+
for path in spec.require_paths
|
20
|
+
paths << File.join(spec.full_gem_path, path)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
|
2
|
+
#require 'jenkins/plugin/version'
|
3
|
+
|
4
|
+
require 'jenkins/plugin/version'
|
5
|
+
require 'etc'
|
6
|
+
|
7
|
+
module Jenkins
|
8
|
+
class Plugin
|
9
|
+
module Tools
|
10
|
+
class Manifest
|
11
|
+
|
12
|
+
def initialize(spec)
|
13
|
+
@spec = spec
|
14
|
+
end
|
15
|
+
|
16
|
+
def write_hpi(io)
|
17
|
+
w = Writer.new(io)
|
18
|
+
w.put "Manifest-Version", "1.0"
|
19
|
+
w.put "Created-By", Jenkins::Plugin::VERSION
|
20
|
+
w.put "Build-Ruby-Platform", RUBY_PLATFORM
|
21
|
+
w.put "Build-Ruby-Version", RUBY_VERSION
|
22
|
+
w.put "Built-By", Etc.getlogin()
|
23
|
+
|
24
|
+
w.put "Group-Id", "org.jenkins-ci.plugins"
|
25
|
+
w.put "Short-Name", @spec.name
|
26
|
+
w.put "Long-Name", @spec.display_name
|
27
|
+
w.put "Url", @spec.url if @spec.url
|
28
|
+
|
29
|
+
w.put "Plugin-Class", "ruby.RubyPlugin"
|
30
|
+
w.put "Plugin-Version", @spec.version
|
31
|
+
w.put "Jenkins-Version", "1.432"
|
32
|
+
|
33
|
+
w.put "Plugin-Dependencies", @spec.dependencies.map{|k,v| "#{k}:#{v}"}.join(",")
|
34
|
+
end
|
35
|
+
|
36
|
+
def write_hpl(io, loadpath)
|
37
|
+
write_hpi(io)
|
38
|
+
|
39
|
+
w = Writer.new(io)
|
40
|
+
w.put "Load-Path", loadpath.to_a.join(':')
|
41
|
+
w.put "Lib-Path", "#{Dir.pwd}/lib/"
|
42
|
+
w.put "Models-Path", "#{Dir.pwd}/models"
|
43
|
+
# Stapler expects view erb/haml scripts to be in the JVM ClassPath
|
44
|
+
w.put "Class-Path", "#{Dir.pwd}/views" if File.exists?("#{Dir.pwd}/views")
|
45
|
+
# Directory for static images, javascript, css, etc. of this plugin.
|
46
|
+
# The static resources are mapped under #CONTEXTPATH/plugin/SHORTNAME/
|
47
|
+
w.put "Resource-Path", "#{Dir.pwd}/static"
|
48
|
+
end
|
49
|
+
|
50
|
+
class Writer
|
51
|
+
|
52
|
+
MAX_LENGTH = 72.to_i
|
53
|
+
|
54
|
+
def initialize(io)
|
55
|
+
@io = io
|
56
|
+
end
|
57
|
+
|
58
|
+
def put(key, value)
|
59
|
+
@io.puts "#{key}: #{manifest_truncate(value)}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def manifest_truncate(message)
|
63
|
+
if message.length < MAX_LENGTH
|
64
|
+
return message
|
65
|
+
end
|
66
|
+
|
67
|
+
line = message[0 ... MAX_LENGTH] + "\n"
|
68
|
+
offset = MAX_LENGTH
|
69
|
+
|
70
|
+
while offset < message.length
|
71
|
+
line += " #{message[offset ... (offset + MAX_LENGTH - 1)]}\n"
|
72
|
+
offset += (MAX_LENGTH - 1)
|
73
|
+
end
|
74
|
+
return line
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'jenkins/plugin/tools/bundle'
|
2
|
+
require 'jenkins/plugin/tools/manifest'
|
3
|
+
require 'zip/zip'
|
4
|
+
|
5
|
+
module Jenkins
|
6
|
+
class Plugin
|
7
|
+
module Tools
|
8
|
+
class Package
|
9
|
+
|
10
|
+
def initialize(spec,target)
|
11
|
+
@target = target
|
12
|
+
@spec = spec
|
13
|
+
end
|
14
|
+
|
15
|
+
# where to generate the package?
|
16
|
+
def file_name
|
17
|
+
file_name = "#{@target}/#{@spec.name}.hpi"
|
18
|
+
end
|
19
|
+
|
20
|
+
def build
|
21
|
+
FileUtils.mkdir_p @target
|
22
|
+
|
23
|
+
Bundle.new(@target).install
|
24
|
+
|
25
|
+
manifest = Manifest.new(@spec)
|
26
|
+
|
27
|
+
File.delete file_name if File.exists?(file_name)
|
28
|
+
|
29
|
+
Zip::ZipFile.open(file_name, Zip::ZipFile::CREATE) do |zipfile|
|
30
|
+
zipfile.get_output_stream("META-INF/MANIFEST.MF") do |f|
|
31
|
+
manifest.write_hpi(f)
|
32
|
+
f.puts "Bundle-Path: vendor/gems"
|
33
|
+
end
|
34
|
+
zipfile.mkdir("WEB-INF/classes")
|
35
|
+
|
36
|
+
["lib","models","#{@target}/vendor"].each do |d|
|
37
|
+
Dir.glob("#{d}/**/*") do |f|
|
38
|
+
if !File.directory? f
|
39
|
+
p = f.gsub("#{@target}/",'')
|
40
|
+
if p !~ %r{/cache/}
|
41
|
+
zipfile.add("WEB-INF/classes/#{p}",f)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# stapler expects views to be directly in the classpath without any prefix
|
48
|
+
Dir.glob("views/**/*") do |f|
|
49
|
+
if !File.directory? f
|
50
|
+
zipfile.add("WEB-INF/classes/#{f[6..-1]}",f)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
puts "#{@spec.name} plugin #{@spec.version} built to #{file_name}"
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'jenkins/plugin/tools/bundle'
|
2
|
+
require 'jenkins/plugin/tools/manifest'
|
3
|
+
require 'jenkins/jenkins-ci.org/credential'
|
4
|
+
require 'net/http'
|
5
|
+
require 'erb'
|
6
|
+
|
7
|
+
module Jenkins
|
8
|
+
class Plugin
|
9
|
+
module Tools
|
10
|
+
# task for deploying a plugin
|
11
|
+
class Release
|
12
|
+
|
13
|
+
def initialize(spec,hpi,snapshot)
|
14
|
+
@spec = spec
|
15
|
+
@hpi = hpi # hpi file to release
|
16
|
+
@snapshot = snapshot # if true, deploy as a snapshot, otherwise as release
|
17
|
+
end
|
18
|
+
|
19
|
+
def check_error(rsp)
|
20
|
+
# in case of 401 Unauthorized, the server just resets the connection and Net::HTTP fails to parse the response,
|
21
|
+
# so we don't really get any meaningful error message.
|
22
|
+
rsp.value # TODO: is this how we check for the error?
|
23
|
+
end
|
24
|
+
|
25
|
+
def each_developer
|
26
|
+
@spec.developers.each do |id, name|
|
27
|
+
email = ''
|
28
|
+
if name =~ /^(.*)<([^>]+)>$/
|
29
|
+
name = $1
|
30
|
+
email = $2.strip
|
31
|
+
end
|
32
|
+
|
33
|
+
yield id, name.strip, email
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def run
|
38
|
+
cred = Jenkins::CiOrg::Credential.new
|
39
|
+
if !cred.has_credential? then
|
40
|
+
raise Exception.new("no credential available to connect to jenkins-ci.org. Please create ~/.jenkins-ci.org. See https://wiki.jenkins-ci.org/display/JENKINS/Dot+Jenkins+Ci+Dot+Org")
|
41
|
+
end
|
42
|
+
|
43
|
+
http = Net::HTTP.new("maven.jenkins-ci.org",8081)
|
44
|
+
|
45
|
+
puts @snapshot ? "deploying as a snapshot" : "deploying as a release"
|
46
|
+
puts "Generating POM"
|
47
|
+
version = @snapshot ? @spec.version+"-SNAPSHOT" : @spec.version
|
48
|
+
pom = ERB.new(File.read(File.dirname(__FILE__)+"/templates/release-pom.xml.erb")).result(binding)
|
49
|
+
|
50
|
+
path = "/content/repositories/#{@snapshot?'snapshots':'releases'}/org/jenkins-ci/ruby-plugins/#{@spec.name}/#{version}/#{@spec.name}-#{version}"
|
51
|
+
req = Net::HTTP::Put.new("#{path}.pom")
|
52
|
+
req.body = pom
|
53
|
+
req.basic_auth(cred.user_name,cred.password)
|
54
|
+
check_error(http.request(req))
|
55
|
+
|
56
|
+
puts "Uploading #{@hpi}"
|
57
|
+
File.open(@hpi,'r') do |f|
|
58
|
+
req = Net::HTTP::Put.new("#{path}.hpi")
|
59
|
+
req.body_stream = f
|
60
|
+
req.basic_auth(cred.user_name,cred.password)
|
61
|
+
req.content_length = File.size(@hpi)
|
62
|
+
check_error(http.request(req))
|
63
|
+
end
|
64
|
+
|
65
|
+
puts "See http://maven.jenkins-ci.org"+File.dirname(path)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Jenkins
|
4
|
+
class Plugin
|
5
|
+
module Tools
|
6
|
+
class Resolver
|
7
|
+
|
8
|
+
def initialize(spec, dir)
|
9
|
+
@spec = spec
|
10
|
+
@dir = dir
|
11
|
+
FileUtils.mkdir_p(dir) unless File.directory? @dir
|
12
|
+
end
|
13
|
+
|
14
|
+
def resolve!
|
15
|
+
@spec.dependencies.each do |name, version|
|
16
|
+
FileUtils.cp resolve(name, version), @dir
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def resolve(short_name,version)
|
21
|
+
# this is where we expect the retrieved file to be
|
22
|
+
cache = File.expand_path "~/.jenkins/cache/plugins/#{short_name}/#{version}/#{short_name}.hpi"
|
23
|
+
|
24
|
+
return cache if File.exists?(cache)
|
25
|
+
|
26
|
+
# now we start looking for places to find them
|
27
|
+
|
28
|
+
# is it in the local maven2 repository?
|
29
|
+
maven = File.expand_path "~/.m2/repository/org/jenkins-ci/plugins/#{short_name}/#{version}/#{short_name}-#{version}.hpi"
|
30
|
+
return maven if File.exists?(maven)
|
31
|
+
|
32
|
+
# download from the community update center
|
33
|
+
FileUtils.mkdir_p(File.dirname(cache))
|
34
|
+
open(cache+".tmp","wb") do |f|
|
35
|
+
puts "Downloading #{short_name} #{version}"
|
36
|
+
url = "http://updates.jenkins-ci.org/download/plugins/#{short_name}/#{version}/#{short_name}.hpi?for=ruby-plugin"
|
37
|
+
puts " from #{url}"
|
38
|
+
f.write fetch(url).body
|
39
|
+
end
|
40
|
+
FileUtils.mv cache+".tmp", cache
|
41
|
+
|
42
|
+
return cache
|
43
|
+
end
|
44
|
+
|
45
|
+
# download with redirect support
|
46
|
+
def fetch(uri, limit = 10)
|
47
|
+
# You should choose better exception.
|
48
|
+
raise ArgumentError, 'HTTP redirect too deep' if limit == 0
|
49
|
+
|
50
|
+
response = Net::HTTP.get_response(URI.parse(uri))
|
51
|
+
case response
|
52
|
+
when Net::HTTPSuccess then response
|
53
|
+
when Net::HTTPRedirection then fetch(response['location'], limit - 1)
|
54
|
+
else
|
55
|
+
response.error!
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'jenkins/plugin/tools/loadpath'
|
2
|
+
require 'jenkins/plugin/tools/resolver'
|
3
|
+
require 'jenkins/plugin/tools/manifest'
|
4
|
+
require 'jenkins/war'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
module Jenkins
|
8
|
+
class Plugin
|
9
|
+
module Tools
|
10
|
+
class Server
|
11
|
+
|
12
|
+
def initialize(spec, workdir, war)
|
13
|
+
@spec = spec
|
14
|
+
@workdir = workdir
|
15
|
+
@plugindir = "#{workdir}/plugins"
|
16
|
+
@war = war || Jenkins::War::LOCATION
|
17
|
+
end
|
18
|
+
|
19
|
+
def run!
|
20
|
+
FileUtils.mkdir_p(@plugindir)
|
21
|
+
loadpath = Jenkins::Plugin::Tools::Loadpath.new
|
22
|
+
manifest = Jenkins::Plugin::Tools::Manifest.new(@spec)
|
23
|
+
resolver = Jenkins::Plugin::Tools::Resolver.new(@spec, @plugindir)
|
24
|
+
|
25
|
+
resolver.resolve!
|
26
|
+
# generate the plugin manifest
|
27
|
+
|
28
|
+
File.open("#{@plugindir}/#{@spec.name}.hpl",mode="w+") do |f|
|
29
|
+
manifest.write_hpl(f, loadpath)
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
# execute Jenkins
|
34
|
+
args = []
|
35
|
+
args << "java"
|
36
|
+
args << "-Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n"
|
37
|
+
args << "-DJENKINS_HOME=#{@workdir}"
|
38
|
+
args << "-Dstapler.trace=true"
|
39
|
+
args << "-Ddebug.YUI=true"
|
40
|
+
# args << "-Djruby.debug.loadService=true"
|
41
|
+
# args << "-Djruby.debug.loadService.timing=true"
|
42
|
+
args << "-jar"
|
43
|
+
args << @war
|
44
|
+
exec *args
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
2
|
+
<modelVersion>4.0.0</modelVersion>
|
3
|
+
<parent>
|
4
|
+
<groupId>org.jenkins-ci.plugins</groupId>
|
5
|
+
<artifactId>plugin</artifactId>
|
6
|
+
<version>1.420</version>
|
7
|
+
</parent>
|
8
|
+
|
9
|
+
<groupId>org.jenkins-ci.ruby-plugins</groupId>
|
10
|
+
<artifactId><%= @spec.name %></artifactId>
|
11
|
+
<version><%= version %></version>
|
12
|
+
<name><%= @spec.display_name %></name>
|
13
|
+
<description><%= @spec.description %></description>
|
14
|
+
<packaging>hpi</packaging>
|
15
|
+
|
16
|
+
<% if @spec.url %>
|
17
|
+
<url><%= @spec.url %></url>
|
18
|
+
<% end %>
|
19
|
+
|
20
|
+
<repositories>
|
21
|
+
<repository>
|
22
|
+
<id>m.g.o-public</id>
|
23
|
+
<url>http://maven.glassfish.org/content/groups/public/</url>
|
24
|
+
</repository>
|
25
|
+
</repositories>
|
26
|
+
|
27
|
+
<developers>
|
28
|
+
<% each_developer do |id, name, email| %>
|
29
|
+
<developer>
|
30
|
+
<id><%= id %></id>
|
31
|
+
<name><%= name %></name>
|
32
|
+
<% if not email.empty? %>
|
33
|
+
<email><%= email %></email>
|
34
|
+
<% end %>
|
35
|
+
</developer>
|
36
|
+
<% end %>
|
37
|
+
</developers>
|
38
|
+
|
39
|
+
<dependencies>
|
40
|
+
<% @spec.dependencies.each do |k,v| %>
|
41
|
+
<dependency>
|
42
|
+
<groupId>org.jenkins-ci.plugins</groupId><!-- TODO: needs to figure out correct groupId -->
|
43
|
+
<artifactId><%= k %></artifactId>
|
44
|
+
<version><%= v %></version>
|
45
|
+
</dependency>
|
46
|
+
<% end %>
|
47
|
+
</dependencies>
|
48
|
+
|
49
|
+
<% if @spec.repository %>
|
50
|
+
<scm>
|
51
|
+
<connection>scm:<%= @spec.repository[:type] %>:<%= @spec.repository[:url] %></connection>
|
52
|
+
</scm>
|
53
|
+
<% end %>
|
54
|
+
</project>
|
data/lib/jenkins/rake.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'jenkins/plugin/version'
|
2
|
+
require 'jenkins/plugin/specification'
|
3
|
+
require 'jenkins/plugin/tools/hpi'
|
4
|
+
require 'jenkins/plugin/tools/loadpath'
|
5
|
+
require 'zip/zip'
|
6
|
+
|
7
|
+
module Jenkins
|
8
|
+
# given the IO handle, produce the basic manifest entries that are common between hpi and hpl formats
|
9
|
+
|
10
|
+
def self.spec
|
11
|
+
@spec ||= Jenkins::Plugin::Specification.load(Dir['*.pluginspec'].first)
|
12
|
+
end
|
13
|
+
|
14
|
+
class Rake
|
15
|
+
def self.install_tasks
|
16
|
+
self.new.install
|
17
|
+
end
|
18
|
+
|
19
|
+
include ::Rake::DSL if defined? ::Rake::DSL
|
20
|
+
|
21
|
+
def install
|
22
|
+
desc "Directory used as JENKINS_HOME during 'rake server'"
|
23
|
+
directory work = "work"
|
24
|
+
|
25
|
+
desc "remove built artifacts"
|
26
|
+
task :clean do
|
27
|
+
sh "rm -rf pkg"
|
28
|
+
sh "rm -rf vendor"
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "output the development servers loadpath"
|
32
|
+
task :loadpath do
|
33
|
+
loadpath = Jenkins::Plugin::Tools::Loadpath.new(:default)
|
34
|
+
puts loadpath.to_path
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "package up stuff into HPI file"
|
38
|
+
task :package do
|
39
|
+
require 'jenkins/plugin/tools/package'
|
40
|
+
Jenkins::Plugin::Tools::Package.new(Jenkins.spec,"pkg").build
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "run a Jenkins server with this plugin"
|
44
|
+
task :server do
|
45
|
+
require 'jenkins/plugin/tools/server'
|
46
|
+
|
47
|
+
server = Jenkins::Plugin::Tools::Server.new(Jenkins.spec, "work")
|
48
|
+
server.run!
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
metadata
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jpi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.3.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Charles Lowell
|
9
|
+
- "J\xC3\xB8rgen P. Tjern\xC3\xB8"
|
10
|
+
- Kohsuke Kawaguchi
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
|
15
|
+
date: 2011-12-19 00:00:00 Z
|
16
|
+
dependencies:
|
17
|
+
- !ruby/object:Gem::Dependency
|
18
|
+
name: rubyzip
|
19
|
+
prerelease: false
|
20
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
21
|
+
none: false
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: "0"
|
26
|
+
type: :runtime
|
27
|
+
version_requirements: *id001
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: thor
|
30
|
+
prerelease: false
|
31
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
32
|
+
none: false
|
33
|
+
requirements:
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: "0"
|
37
|
+
type: :runtime
|
38
|
+
version_requirements: *id002
|
39
|
+
- !ruby/object:Gem::Dependency
|
40
|
+
name: jenkins-war
|
41
|
+
prerelease: false
|
42
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: "1.427"
|
48
|
+
type: :runtime
|
49
|
+
version_requirements: *id003
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: bundler
|
52
|
+
prerelease: false
|
53
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ~>
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: 1.1.rc2
|
59
|
+
type: :runtime
|
60
|
+
version_requirements: *id004
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: jenkins-plugin-runtime
|
63
|
+
prerelease: false
|
64
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 0.1.13
|
70
|
+
type: :runtime
|
71
|
+
version_requirements: *id005
|
72
|
+
- !ruby/object:Gem::Dependency
|
73
|
+
name: rspec
|
74
|
+
prerelease: false
|
75
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ~>
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: "2.0"
|
81
|
+
type: :development
|
82
|
+
version_requirements: *id006
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: cucumber
|
85
|
+
prerelease: false
|
86
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ~>
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: "1.0"
|
92
|
+
type: :development
|
93
|
+
version_requirements: *id007
|
94
|
+
description: Allows you to generate a new Ruby plugin project, build it, test it in Jenkins and release it to the Jenkins Update Center.
|
95
|
+
email:
|
96
|
+
- cowboyd@thefrontside.net
|
97
|
+
executables:
|
98
|
+
- jpi
|
99
|
+
extensions: []
|
100
|
+
|
101
|
+
extra_rdoc_files: []
|
102
|
+
|
103
|
+
files:
|
104
|
+
- .gitignore
|
105
|
+
- Gemfile
|
106
|
+
- README.md
|
107
|
+
- Rakefile
|
108
|
+
- bin/jpi
|
109
|
+
- features/create-new-plugin.feature
|
110
|
+
- features/support/create_new_plugin_steps.rb
|
111
|
+
- features/support/directory_structure.rb
|
112
|
+
- features/support/work.rb
|
113
|
+
- jpi.gemspec
|
114
|
+
- lib/jenkins/jenkins-ci.org/credential.rb
|
115
|
+
- lib/jenkins/plugin/cli.rb
|
116
|
+
- lib/jenkins/plugin/cli/formatting.rb
|
117
|
+
- lib/jenkins/plugin/cli/generate.rb
|
118
|
+
- lib/jenkins/plugin/cli/new.rb
|
119
|
+
- lib/jenkins/plugin/cli/templates/Gemfile.tt
|
120
|
+
- lib/jenkins/plugin/cli/templates/build_step.tt
|
121
|
+
- lib/jenkins/plugin/cli/templates/pluginspec.tt
|
122
|
+
- lib/jenkins/plugin/tools/bundle.rb
|
123
|
+
- lib/jenkins/plugin/tools/hpi.rb
|
124
|
+
- lib/jenkins/plugin/tools/loadpath.rb
|
125
|
+
- lib/jenkins/plugin/tools/manifest.rb
|
126
|
+
- lib/jenkins/plugin/tools/package.rb
|
127
|
+
- lib/jenkins/plugin/tools/release.rb
|
128
|
+
- lib/jenkins/plugin/tools/resolver.rb
|
129
|
+
- lib/jenkins/plugin/tools/server.rb
|
130
|
+
- lib/jenkins/plugin/tools/templates/release-pom.xml.erb
|
131
|
+
- lib/jenkins/plugin/version.rb
|
132
|
+
- lib/jenkins/rake.rb
|
133
|
+
homepage: https://github.com/jenkinsci/jpi.rb
|
134
|
+
licenses: []
|
135
|
+
|
136
|
+
post_install_message:
|
137
|
+
rdoc_options: []
|
138
|
+
|
139
|
+
require_paths:
|
140
|
+
- lib
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
+
none: false
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: "0"
|
147
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
148
|
+
none: false
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: "0"
|
153
|
+
requirements: []
|
154
|
+
|
155
|
+
rubyforge_project:
|
156
|
+
rubygems_version: 1.8.9
|
157
|
+
signing_key:
|
158
|
+
specification_version: 3
|
159
|
+
summary: Tools for creating and building Jenkins Ruby plugins
|
160
|
+
test_files:
|
161
|
+
- features/create-new-plugin.feature
|
162
|
+
- features/support/create_new_plugin_steps.rb
|
163
|
+
- features/support/directory_structure.rb
|
164
|
+
- features/support/work.rb
|