jenkins-plugin 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 ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ .idea
4
+ Gemfile.lock
5
+ pkg/*
6
+ target/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in jenkins-plugins.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,16 @@
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
+ > This is all very theoretical. Don't try this at home.
10
+
11
+ $ gem install jenkins-plugins
12
+ $ jpi create my-awesome-jenkins-plugin
13
+ $ cd my-awesome-jenkins-plugin
14
+ $ jpi gen build_wrapper MyBuildWrapper
15
+ $ rake server
16
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
data/bin/jpi ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'jpi/cli'
4
+
5
+ JPI::CLI.start
@@ -0,0 +1,90 @@
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
+ Background: Creating a brand new Jenkins Ruby Plugin
9
+ Given I've run "jenkins-plugin create newplugin"
10
+
11
+ Scenario: The directory skeleton is generated
12
+ Then I should see this structure
13
+ """
14
+ [-] newplugin
15
+ | [+] .git
16
+ | .gitignore
17
+ | Gemfile
18
+ | Rakefile
19
+ | [-] lib
20
+ | [-] newplugin
21
+ | | | version.rb
22
+ | | newplugin.rb
23
+ | [-] spec
24
+ | | spec_helper.rb
25
+ | [-] plugin
26
+ | | [+] models
27
+ | | [+] views
28
+ """
29
+
30
+ Scenario: The .gitignore contents
31
+ When I open ".gitignore"
32
+ Then I should see
33
+ """
34
+ .bundle
35
+ .rvmrc
36
+ .rspec
37
+ """
38
+
39
+ Scenario: The Gemfile contents
40
+ When I open "Gemfile"
41
+ Then I should see
42
+ """
43
+ source :rubygems
44
+
45
+ gem "jenkins-war"
46
+ gem "jenkins-plugins"
47
+ """
48
+
49
+ Scenario: The Rakefile contents
50
+ When I open "Rakefile"
51
+ Then I should see
52
+ """
53
+ require 'jenkins/rake'
54
+ Jenkins::Rake.install_tasks
55
+ """
56
+
57
+ Scenario: The plugin module contents
58
+ When I open "lib/newplugin.rb"
59
+ Then I should see
60
+ """
61
+ module Newplugin
62
+
63
+ def self.start
64
+ #do any startup when this plugin initializes
65
+ end
66
+
67
+ def self.stop
68
+ #perform any necessary cleanup when this plugin is shut down.
69
+ end
70
+ end
71
+ """
72
+
73
+ Scenario: The version file is generated
74
+ When I open "lib/newplugin/version.rb"
75
+ Then I should see
76
+ """
77
+
78
+ module Newplugin
79
+ VERSION = 0.0.1
80
+ end
81
+ """
82
+
83
+ Scenario: The spec_helper is created
84
+ When I open "spec/spec_helper.rb"
85
+ Then I should see
86
+ """
87
+ $:.unshift(Pathname(__FILE__).dirname.join('../lib'))
88
+ require 'newplugin'
89
+ """
90
+
@@ -0,0 +1,29 @@
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 = "jenkins-plugin"
7
+ s.version = Jenkins::Plugin::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Charles Lowell"]
10
+ s.email = ["cowboyd@thefrontside.net"]
11
+ s.homepage = "http://github.com/cowboyd/jenkins-plugin"
12
+ s.summary = %q{Tools for creating and building Jenkins Ruby plugins}
13
+ s.description = %q{I'll think of a better description later, but if you're reading this, then I haven't}
14
+
15
+ s.rubyforge_project = "jenkins-plugin"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency "rubyzip"
23
+ s.add_dependency "thor"
24
+ s.add_dependency "jenkins-war", ">= 1.427"
25
+ s.add_dependency "bundler", ">= 1.1.pre.8"
26
+
27
+ s.add_development_dependency "rspec", "~> 2.0"
28
+ s.add_development_dependency "cucumber", "~> 1.0"
29
+ end
@@ -0,0 +1,106 @@
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 = "https://updates.jenkins-ci.org/download/plugins/#{short_name}/#{version}/#{short_name}.hpi?for=ruby-plugin"
56
+ f.write fetch(url).body
57
+ end
58
+ FileUtils.mv cache+".tmp", cache
59
+
60
+ return cache
61
+ end
62
+
63
+ # download with redirect support
64
+ def fetch(uri, limit = 10)
65
+ # You should choose better exception.
66
+ raise ArgumentError, 'HTTP redirect too deep' if limit == 0
67
+
68
+ response = Net::HTTP.get_response(URI.parse(uri))
69
+ case response
70
+ when Net::HTTPSuccess then response
71
+ when Net::HTTPRedirection then fetch(response['location'], limit - 1)
72
+ else
73
+ response.error!
74
+ end
75
+ end
76
+
77
+ # parse manifest file text into a hash
78
+ def parse_manifest(txt)
79
+ # separators
80
+ nl = /\r\n|\n|\r[^\n]/
81
+ secsep = /(#{nl}){2}/
82
+
83
+ txt.split(secsep).reject { |s| s.chomp.length==0 }.map do |section|
84
+ lines = []
85
+ section.split(nl).each do |line|
86
+ if line[0]==0x20
87
+ lines.last << line[1..-1] # continuation of the previous line
88
+ else
89
+ lines << line
90
+ end
91
+ end
92
+
93
+ # convert to hash
94
+ hash = {}
95
+ lines.each do |l|
96
+ (k,v) = l.split(/: /,2)
97
+ hash[k] = v
98
+ end
99
+
100
+ hash
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ 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,5 @@
1
+ module Jenkins
2
+ class Plugin
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,140 @@
1
+ require 'jenkins/plugin/version'
2
+ require 'jenkins/plugin/tools/hpi'
3
+ require 'jenkins/plugin/tools/loadpath'
4
+ require 'zip/zip'
5
+
6
+ module Jenkins
7
+ # given the IO handle, produce the basic manifest entries that are common between hpi and hpl formats
8
+ def self.generate_manifest(f)
9
+ f.puts "Manifest-Version: 1.0"
10
+ f.puts "Created-By: #{Jenkins::Plugin::VERSION}"
11
+ f.puts "Build-Ruby-Platform: #{RUBY_PLATFORM}"
12
+ f.puts "Build-Ruby-Version: #{RUBY_VERSION}"
13
+
14
+ f.puts "Group-Id: org.jenkins-ci.plugins"
15
+ f.puts "Short-Name: #{::PluginName}"
16
+ f.puts "Long-Name: #{::PluginName}" # TODO: better name
17
+ f.puts "Url: http://jenkins-ci.org/" # TODO: better value
18
+ # f.puts "Compatible-Since-Version:"
19
+ f.puts "Plugin-Class: ruby.RubyPlugin"
20
+ f.puts "Plugin-Version: #{::PluginVersion}"
21
+ f.puts "Jenkins-Version: 1.426"
22
+
23
+ f.puts "Plugin-Dependencies: " + ::PluginDeps.map{|k,v| "#{k}:#{v}"}.join(",")
24
+ # f.puts "Plugin-Developers:"
25
+ end
26
+
27
+
28
+ class Rake
29
+ def self.install_tasks
30
+ self.new.install
31
+ end
32
+
33
+ include ::Rake::DSL if defined? ::Rake::DSL
34
+
35
+ def install
36
+ desc "Directory used as JENKINS_HOME during 'rake server'"
37
+ directory work = "work"
38
+
39
+ desc "remove built artifacts"
40
+ task :clean do
41
+ sh "rm -rf pkg"
42
+ sh "rm -rf vendor"
43
+ end
44
+
45
+ # verify that necessary metadata constants are defined
46
+ task :verify_constants do
47
+ ["PluginName","PluginVersion"].each do |n|
48
+ fail("Constant #{n} is not defined") unless Object.const_defined?(n)
49
+ end
50
+ end
51
+
52
+ desc "output the development servers loadpath"
53
+ task :loadpath do
54
+ loadpath = Jenkins::Plugin::Tools::Loadpath.new(:default)
55
+ puts loadpath.to_path
56
+ end
57
+
58
+ directory target = "pkg"
59
+ desc "bundle gems"
60
+ task :bundle => [target] do
61
+ require 'java'
62
+ require 'bundler'
63
+ require 'bundler/cli'
64
+
65
+ puts "bundling..."
66
+ ENV['BUNDLE_APP_CONFIG'] = "#{target}/vendor/bundle"
67
+ Bundler::CLI.start ["--standalone", "--path", "#{target}/vendor/gems", "--without", "development"]
68
+ end
69
+
70
+ desc "package up stuff into HPI file"
71
+ task :package => [:verify_constants, target, :bundle] do
72
+
73
+ file_name = "#{target}/#{::PluginName}.hpi"
74
+ File.delete file_name if File.exists?(file_name)
75
+
76
+ Zip::ZipFile.open(file_name, Zip::ZipFile::CREATE) do |zipfile|
77
+ zipfile.get_output_stream("META-INF/MANIFEST.MF") do |f|
78
+ Jenkins.generate_manifest(f)
79
+ f.puts "Bundle-Path: vendor/gems"
80
+ end
81
+ zipfile.mkdir("WEB-INF/classes")
82
+
83
+ ["lib","models","views", "#{target}/vendor"].each do |d|
84
+ Dir.glob("#{d}/**/*") do |f|
85
+ if !File.directory? f
86
+ zipfile.add("WEB-INF/classes/#{f.gsub("#{target}/",'')}",f)
87
+ end
88
+ end
89
+ end
90
+ end
91
+ puts "#{::PluginName} plugin #{::PluginVersion} built to #{file_name}"
92
+ end
93
+
94
+ desc "resolve dependency plugins into #{work}/plugins"
95
+ task :'resolve-dependency-plugins' => [work] do
96
+ FileUtils.mkdir_p("#{work}/plugins")
97
+
98
+ puts "Copying plugin dependencies into #{work}/plugins"
99
+ ::PluginDeps.each do |short_name,version|
100
+ FileUtils.cp Jenkins::Plugin::Tools::Hpi::resolve(short_name,version), "#{work}/plugins/#{short_name}.hpi", :verbose=>true
101
+ end
102
+ end
103
+
104
+ desc "run a Jenkins server with this plugin"
105
+ task :server => :'resolve-dependency-plugins' do
106
+ require 'jenkins/war'
107
+ require 'zip/zip'
108
+ require 'fileutils'
109
+
110
+ loadpath = Jenkins::Plugin::Tools::Loadpath.new
111
+
112
+ # generate the plugin manifest
113
+ FileUtils.mkdir_p("#{work}/plugins")
114
+ File.open("#{work}/plugins/#{::PluginName}.hpl",mode="w+") do |f|
115
+ Jenkins.generate_manifest f
116
+
117
+ # f.puts "Libraries: "+["lib","models","pkg/vendor"].collect{|r| Dir.pwd+'/'+r}.join(",")
118
+ # TODO: where do we put views?
119
+ # TODO: where do we put static resources?
120
+ f.puts "Load-Path: #{loadpath.to_a.join(':')}"
121
+ f.puts "Resource-Path: #{Dir.pwd}/views"
122
+ f.puts "Lib-Path: #{Dir.pwd}/lib/"
123
+ f.puts "Models-Path: #{Dir.pwd}/models"
124
+ end
125
+
126
+ # TODO: assemble dependency plugins
127
+
128
+ # execute Jenkins
129
+ args = []
130
+ args << "java"
131
+ args << "-Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n"
132
+ args << "-DJENKINS_HOME=#{work}"
133
+ args << "-jar"
134
+ args << Jenkins::War::LOCATION
135
+ exec *args
136
+ end
137
+
138
+ end
139
+ end
140
+ end
metadata ADDED
@@ -0,0 +1,167 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jenkins-plugin
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Charles Lowell
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-09-02 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rubyzip
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: thor
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: jenkins-war
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 857
58
+ segments:
59
+ - 1
60
+ - 427
61
+ version: "1.427"
62
+ type: :runtime
63
+ version_requirements: *id003
64
+ - !ruby/object:Gem::Dependency
65
+ name: bundler
66
+ prerelease: false
67
+ requirement: &id004 !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 1923831889
73
+ segments:
74
+ - 1
75
+ - 1
76
+ - pre
77
+ - 8
78
+ version: 1.1.pre.8
79
+ type: :runtime
80
+ version_requirements: *id004
81
+ - !ruby/object:Gem::Dependency
82
+ name: rspec
83
+ prerelease: false
84
+ requirement: &id005 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ hash: 3
90
+ segments:
91
+ - 2
92
+ - 0
93
+ version: "2.0"
94
+ type: :development
95
+ version_requirements: *id005
96
+ - !ruby/object:Gem::Dependency
97
+ name: cucumber
98
+ prerelease: false
99
+ requirement: &id006 !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ~>
103
+ - !ruby/object:Gem::Version
104
+ hash: 15
105
+ segments:
106
+ - 1
107
+ - 0
108
+ version: "1.0"
109
+ type: :development
110
+ version_requirements: *id006
111
+ description: I'll think of a better description later, but if you're reading this, then I haven't
112
+ email:
113
+ - cowboyd@thefrontside.net
114
+ executables:
115
+ - jpi
116
+ extensions: []
117
+
118
+ extra_rdoc_files: []
119
+
120
+ files:
121
+ - .gitignore
122
+ - Gemfile
123
+ - README.md
124
+ - Rakefile
125
+ - bin/jpi
126
+ - features/create-new-plugin.feature
127
+ - jenkins-plugin.gemspec
128
+ - lib/jenkins/plugin/tools/hpi.rb
129
+ - lib/jenkins/plugin/tools/loadpath.rb
130
+ - lib/jenkins/plugin/version.rb
131
+ - lib/jenkins/rake.rb
132
+ has_rdoc: true
133
+ homepage: http://github.com/cowboyd/jenkins-plugin
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
+ hash: 3
147
+ segments:
148
+ - 0
149
+ version: "0"
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ none: false
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ hash: 3
156
+ segments:
157
+ - 0
158
+ version: "0"
159
+ requirements: []
160
+
161
+ rubyforge_project: jenkins-plugin
162
+ rubygems_version: 1.6.2
163
+ signing_key:
164
+ specification_version: 3
165
+ summary: Tools for creating and building Jenkins Ruby plugins
166
+ test_files:
167
+ - features/create-new-plugin.feature