sbci 0.1.0

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