sbci 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.
@@ -0,0 +1,21 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .jenkins/
7
+ spec/fixtures/.jenkins
8
+ spec/fixtures/jenkins
9
+ Gemfile.lock
10
+ InstalledFiles
11
+ _yardoc
12
+ coverage
13
+ doc/
14
+ lib/bundler/man
15
+ pkg
16
+ rdoc
17
+ spec/reports
18
+ test/tmp
19
+ test/version_tmp
20
+ tmp
21
+ /vendor/bundle
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,19 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', :version => 2 do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+ # Capybara request specs
17
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
18
+ end
19
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Egils Muzis
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,28 @@
1
+ # SBCI - Simply Business Continuous Integration
2
+
3
+ This command-line utility provides an easy way for Jenkins job configuration to be exported to disk.
4
+ Great for backup purposes and later restoring to the same or other Jenkins instances.
5
+
6
+ ## Installation
7
+
8
+ ### Through RVM global gemset (recommended)
9
+
10
+ rvm use gemset global
11
+ gem install sbci
12
+
13
+ ### Or per project basis only - Gemfile
14
+
15
+ gem 'sbci'
16
+
17
+ ## Example Usage
18
+
19
+ We recommend that you create a .jenkins directory checked into your project git repo to keep a backup of your Jenkins job configuration.
20
+
21
+ ### Exporting / Backing up a job from your Jenkins server
22
+ sbci dump --host localhost --port 8080 --job-name development --path .jenkins
23
+
24
+ ### Restoring / Updating a job from your backup
25
+ sbci publish --host localhost --port 8080 --job-name development --path .jenkins
26
+
27
+ ### To view other commands
28
+ sbci --help
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.dirname(__FILE__) + '/../lib') unless $:.include?(File.dirname(__FILE__) + '/../lib')
3
+
4
+ require 'trollop'
5
+ require 'sbci'
6
+
7
+ COMMANDS = %w(create dump publish delete)
8
+
9
+ opts = Trollop::options do
10
+ banner <<-EOS
11
+ Usage:
12
+
13
+ * Create a new configuration xml template file:
14
+
15
+ sbci create --job-name development --path .jenkins
16
+
17
+ * Dump a configuration xml from an existing project:
18
+
19
+ sbci dump --host localhost --port 8080 --job-name development --path .jenkins
20
+
21
+ * Publish a configuration xml to create a new Jenkins job:
22
+
23
+ sbci publish --host localhost --port 8080 --job-name development --path .jenkins
24
+
25
+ * Delete a Jenkins job:
26
+
27
+ sbci delete --host localhost --port 8080 --job-name development
28
+
29
+ * Force overwriting without getting prompt (e.g. create, publish, dump)
30
+
31
+ sbci dump --host localhost --port 8080 --job-name development --path .jenkins --force true
32
+
33
+ where [options] are:
34
+
35
+ EOS
36
+ opt :host, "Hostname", :type => String
37
+ opt :port, "Port number", :type => :int
38
+ opt :job_name, "Name of the Jenkins job", :type => String
39
+ opt :path, "Relative path", :type => String
40
+ opt :force, "Force overwriting"
41
+ end
42
+
43
+ cmd = ARGV.shift
44
+
45
+ if cmd == "debug"
46
+ puts YAML::dump(SBCI::Job.new(opts))
47
+ elsif COMMANDS.include?(cmd)
48
+ SBCI::Job.new(opts).send(cmd)
49
+ else
50
+ puts "Please enter a valid task name"
51
+ end
@@ -0,0 +1,103 @@
1
+ <?xml version='1.0' encoding='UTF-8'?>
2
+ <project>
3
+ <actions/>
4
+ <description>_PROJECT_NAME_</description>
5
+ <logRotator>
6
+ <daysToKeep>1</daysToKeep>
7
+ <numToKeep>5</numToKeep>
8
+ <artifactDaysToKeep>-1</artifactDaysToKeep>
9
+ <artifactNumToKeep>-1</artifactNumToKeep>
10
+ </logRotator>
11
+ <keepDependencies>false</keepDependencies>
12
+ <properties>
13
+ <com.coravy.hudson.plugins.github.GithubProjectProperty>
14
+ <projectUrl>_PROJECT_URL_</projectUrl>
15
+ </com.coravy.hudson.plugins.github.GithubProjectProperty>
16
+ </properties>
17
+ <scm class="hudson.plugins.git.GitSCM">
18
+ <configVersion>2</configVersion>
19
+ <userRemoteConfigs>
20
+ <hudson.plugins.git.UserRemoteConfig>
21
+ <name></name>
22
+ <refspec></refspec>
23
+ <url>_GIT_REPO_</url>
24
+ </hudson.plugins.git.UserRemoteConfig>
25
+ </userRemoteConfigs>
26
+ <branches>
27
+ <hudson.plugins.git.BranchSpec>
28
+ <name>_BRANCH_NAME_</name>
29
+ </hudson.plugins.git.BranchSpec>
30
+ </branches>
31
+ <disableSubmodules>false</disableSubmodules>
32
+ <recursiveSubmodules>false</recursiveSubmodules>
33
+ <doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
34
+ <authorOrCommitter>false</authorOrCommitter>
35
+ <clean>false</clean>
36
+ <wipeOutWorkspace>false</wipeOutWorkspace>
37
+ <pruneBranches>false</pruneBranches>
38
+ <remotePoll>false</remotePoll>
39
+ <ignoreNotifyCommit>false</ignoreNotifyCommit>
40
+ <buildChooser class="hudson.plugins.git.util.DefaultBuildChooser"/>
41
+ <gitTool>Default</gitTool>
42
+ <submoduleCfg class="list"/>
43
+ <relativeTargetDir></relativeTargetDir>
44
+ <reference></reference>
45
+ <excludedRegions></excludedRegions>
46
+ <excludedUsers></excludedUsers>
47
+ <gitConfigName></gitConfigName>
48
+ <gitConfigEmail></gitConfigEmail>
49
+ <skipTag>false</skipTag>
50
+ <includedRegions></includedRegions>
51
+ <scmName></scmName>
52
+ </scm>
53
+ <canRoam>true</canRoam>
54
+ <disabled>false</disabled>
55
+ <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
56
+ <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
57
+ <triggers class="vector">
58
+ <com.cloudbees.jenkins.GitHubPushTrigger>
59
+ <spec></spec>
60
+ </com.cloudbees.jenkins.GitHubPushTrigger>
61
+ <hudson.triggers.SCMTrigger>
62
+ <spec>* * * * *</spec>
63
+ </hudson.triggers.SCMTrigger>
64
+ </triggers>
65
+ <concurrentBuild>false</concurrentBuild>
66
+ <builders>
67
+ <hudson.tasks.Shell>
68
+ <command>rvm --force gemset empty _PROJECT_NAME_ &amp;&amp; bundle install</command>
69
+ </hudson.tasks.Shell>
70
+ <hudson.tasks.Shell>
71
+ <command>bundle exec rspec spec --format html -o doc/rspec.html</command>
72
+ </hudson.tasks.Shell>
73
+ </builders>
74
+ <publishers>
75
+ <hudson.tasks.ArtifactArchiver>
76
+ <artifacts>doc/*html</artifacts>
77
+ <latestOnly>false</latestOnly>
78
+ </hudson.tasks.ArtifactArchiver>
79
+ <htmlpublisher.HtmlPublisher>
80
+ <reportTargets>
81
+ <htmlpublisher.HtmlPublisherTarget>
82
+ <reportName>Rspec Report</reportName>
83
+ <reportDir>doc</reportDir>
84
+ <reportFiles>rspec.html</reportFiles>
85
+ <keepAll>true</keepAll>
86
+ <wrapperName>htmlpublisher-wrapper.html</wrapperName>
87
+ </htmlpublisher.HtmlPublisherTarget>
88
+ </reportTargets>
89
+ </htmlpublisher.HtmlPublisher>
90
+ <hudson.plugins.claim.ClaimPublisher/>
91
+ </publishers>
92
+ <buildWrappers>
93
+ <hudson.plugins.ansicolor.AnsiColorBuildWrapper/>
94
+ <ruby-proxy-object>
95
+ <ruby-object ruby-class="Jenkins::Plugin::Proxies::BuildWrapper" pluginid="rvm">
96
+ <object ruby-class="RvmWrapper" pluginid="rvm">
97
+ <impl pluginid="rvm" ruby-class="String">1.9.2-p290@_PROJECT_NAME_</impl>
98
+ </object>
99
+ <pluginid pluginid="rvm" ruby-class="String">rvm</pluginid>
100
+ </ruby-object>
101
+ </ruby-proxy-object>
102
+ </buildWrappers>
103
+ </project>
@@ -0,0 +1,145 @@
1
+ require "fileutils"
2
+ require "rest_client"
3
+ require "grit"
4
+ require "uri"
5
+ require "rubygems"
6
+ require "sbci/version"
7
+ require "yaml"
8
+
9
+ module SBCI
10
+
11
+ INITIAL_CONFIG_PATH = "#{File.expand_path("../..",__FILE__)}/lib/config.xml"
12
+ MESSAGES = {
13
+ :config_dir_exists => "Config already exists for this project",
14
+ :config_already_exists => "Config file already exists and will be overwritten",
15
+ :config_already_published => "Config file is already published and will be overwritten"
16
+ }
17
+
18
+ def self.pwd
19
+ @pwd = Dir.pwd
20
+ end
21
+
22
+ class Job
23
+
24
+ def self.repo_name
25
+ conf = Grit::Config.new(get_repo)
26
+ conf["remote.origin.url"].gsub(/\.git$/,"").split("/").last
27
+ end
28
+
29
+ def self.branch_name
30
+ Grit::Head.current(get_repo).name
31
+ end
32
+
33
+ def self.get_repo
34
+ Grit::Repo.new(".")
35
+ end
36
+
37
+ ATTRIBUTES = [
38
+ :host, :port, :branch_name, :job_name, :path, :force
39
+ ].freeze
40
+
41
+ DEFAULTS = {
42
+ :host => "localhost",
43
+ :port => 8080,
44
+ :path => "",
45
+ :job_name => self.repo_name,
46
+ :force => false
47
+ }
48
+
49
+ ATTRIBUTES.each do |attr|
50
+ attr_accessor attr
51
+ end
52
+
53
+ def initialize(args = nil)
54
+ args.delete_if{ |k,v| v.nil? || v == ""} if args.is_a?(Hash)
55
+ args = args ? DEFAULTS.merge(args) : DEFAULTS
56
+
57
+ ATTRIBUTES.each do |attr|
58
+ if (args.key?(attr))
59
+ instance_variable_set("@#{attr}", args[attr])
60
+ end
61
+ end
62
+ end
63
+
64
+ def create
65
+ prompt(SBCI::MESSAGES[:config_already_exists], config_exists?) do
66
+ FileUtils.cp(SBCI::INITIAL_CONFIG_PATH, config_file_path)
67
+ end
68
+ end
69
+
70
+ def publish
71
+ already_published = published?
72
+ url = if already_published
73
+ "#{host_with_port}/job/#{job_name}/config.xml"
74
+ else
75
+ "#{host_with_port}/createItem?name=#{job_name}"
76
+ end
77
+ prompt(SBCI::MESSAGES[:config_already_published], already_published) do
78
+ RestClient.post(URI.escape(url), File.read(config_file_path), :content_type => :xml)
79
+ end
80
+ end
81
+
82
+ def published?
83
+ begin
84
+ RestClient.get(URI.escape("#{host_with_port}/job/#{self.job_name}/config.xml"))
85
+ rescue
86
+ false
87
+ else
88
+ true
89
+ end
90
+ end
91
+
92
+ def dump
93
+ prompt(SBCI::MESSAGES[:config_already_exists], config_exists?) do
94
+ response = RestClient.get(URI.escape("#{host_with_port}/job/#{self.job_name}/config.xml"))
95
+ File.open(config_file_path, "w") {|f| f.write(response.body) }
96
+ response
97
+ end
98
+ end
99
+
100
+ def delete
101
+ begin
102
+ RestClient.post(URI.escape("#{host_with_port}/job/#{self.job_name}/doDelete"), {})
103
+ rescue RestClient::Found
104
+ true
105
+ end
106
+ end
107
+
108
+ def config_file_path
109
+ File.join(config_file_dir, "#{self.job_name}.xml")
110
+ end
111
+
112
+ def config_file_dir
113
+ file_dir = File.join(SBCI.pwd, self.path)
114
+ FileUtils.mkdir_p(file_dir)
115
+ file_dir
116
+ end
117
+
118
+ def config_exists?
119
+ File.exists?(config_file_path)
120
+ end
121
+
122
+ def host_with_port
123
+ "#{host}:#{port}"
124
+ end
125
+
126
+ def delete_config
127
+ FileUtils.rm(config_file_path) if File.exists?(config_file_path)
128
+ end
129
+
130
+ private
131
+
132
+ def prompt(message, condition = true, &block)
133
+ if !self.force && condition
134
+ message << "\nDo you want to continue [Y/n] ? "
135
+ print(message)
136
+ answer = gets
137
+ yield if answer.strip.downcase == "y"
138
+ else
139
+ yield
140
+ end
141
+ end
142
+
143
+ end
144
+
145
+ end
@@ -0,0 +1,3 @@
1
+ module SBCI
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/sbci/version', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.authors = ["Egils Muzis"]
6
+ s.email = ["egils.muzis@xbridge.com"]
7
+ s.description = "Utility to easily export or import and Jenkins job configuration"
8
+ s.summary = "Manage your Jenkins jobs through this easy to use command-line interface"
9
+ s.homepage = "https://github.com/simplybusiness/sbci"
10
+
11
+ s.files = `git ls-files`.split($\)
12
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
14
+ s.name = "sbci"
15
+ s.require_paths = ["lib"]
16
+ s.version = SBCI::VERSION
17
+
18
+ s.add_dependency "rest-client"
19
+ s.add_dependency "grit"
20
+ s.add_dependency "trollop"
21
+
22
+ s.add_development_dependency "bahia"
23
+ s.add_development_dependency "guard"
24
+ s.add_development_dependency "guard-rspec"
25
+ s.add_development_dependency "growl"
26
+ s.add_development_dependency "rspec"
27
+ s.add_development_dependency "vcr"
28
+ s.add_development_dependency "webmock"
29
+ end
Binary file
@@ -0,0 +1,42 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: http://localhost:8080/job/test_job/doDelete
6
+ body:
7
+ encoding: ASCII-8BIT
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - ! '*/*; q=0.5, application/xml'
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ Content-Length:
15
+ - '0'
16
+ Content-Type:
17
+ - application/x-www-form-urlencoded
18
+ User-Agent:
19
+ - Ruby
20
+ response:
21
+ status:
22
+ code: 302
23
+ message: Found
24
+ headers:
25
+ Server:
26
+ - Winstone Servlet Engine v0.9.10
27
+ Location:
28
+ - http://localhost:8080/
29
+ Content-Length:
30
+ - '0'
31
+ Connection:
32
+ - Keep-Alive
33
+ Date:
34
+ - Mon, 02 Jul 2012 11:49:49 GMT
35
+ X-Powered-By:
36
+ - Servlet/2.5 (Winstone/0.9.10)
37
+ body:
38
+ encoding: US-ASCII
39
+ string: ''
40
+ http_version: !!null
41
+ recorded_at: Mon, 02 Jul 2012 11:49:49 GMT
42
+ recorded_with: VCR 2.2.1