kstrano 0.0.4

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/bin/kumafy ADDED
@@ -0,0 +1,251 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'fileutils'
5
+ require 'highline'
6
+ require 'net/http'
7
+ require 'net/https'
8
+ require 'uri'
9
+
10
+ DEPLOY_GIST = "https://raw.github.com/Kunstmaan/kStrano/master/config/deploy.rb"
11
+ PRODUCTION_GIST = "https://raw.github.com/Kunstmaan/kStrano/master/config/production.rb"
12
+ STAGING_GIST = "https://raw.github.com/Kunstmaan/kStrano/master/config/staging.rb"
13
+
14
+ BUILD_GIST = "https://raw.github.com/Kunstmaan/kStrano/master/config/build.xml"
15
+ PHPCS_GIST = "https://raw.github.com/Kunstmaan/kStrano/master/config/phpcs.xml"
16
+ PHPMD_GIST = "https://raw.github.com/Kunstmaan/kStrano/master/config/phpmd.xml"
17
+ PHPUNIT_GIST = "https://raw.github.com/Kunstmaan/kStrano/master/config/phpunit.xml.dist"
18
+
19
+ def update_capfile(base, context, force)
20
+ file = File.join(base, "Capfile")
21
+
22
+ if !File.exists?("Capfile")
23
+ abort "Make sure the project has been capified or capifonied."
24
+ else
25
+ includestr = "load Gem.find_files('kstrano.rb').last.to_s"
26
+ fcontent = ""
27
+ File.open(file, "r") do |f|
28
+ f.each do |line|
29
+ fcontent << line
30
+ if line.include? includestr
31
+ abort "This project is already kumafied!" unless force
32
+ return
33
+ end
34
+ end
35
+ end
36
+
37
+ File.open(file, "w") do |f|
38
+ fcontent.each_line do |line|
39
+ if line.include? "load 'app/config/deploy'"
40
+ f.print includestr + "\r\n"
41
+ end
42
+ f.print line
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ def update_deploy_config(ui, base, context, force)
49
+
50
+ deploy = File.join(base, "app", "config", "deploy.rb")
51
+ write_deploy = true
52
+ #if File.exists?(deploy)
53
+ #overwrite = ui.ask("The file #{deploy} already exists, do you want to override it? ") { |q| q.default = 'n' }
54
+ #if !overwrite.match(/^y/)
55
+ # write_deploy = false
56
+ #end
57
+ #end
58
+
59
+ if write_deploy
60
+ deploy_gist = get_plain_secure(DEPLOY_GIST).body
61
+ context["app_name"] ||= ui.ask("What's the name of the application?")
62
+ app_name = context["app_name"]
63
+ deploy_gist.gsub!(/(:application,\s)(\"\")/, '\1' + "\"#{app_name}\"")
64
+ deploy_gist.gsub!(/(:admin_runner,\s)(\"\")/, '\1' + "\"#{app_name}\"")
65
+
66
+ campfire_room = ui.ask("What's the name of the campfire room for this project?")
67
+ if !campfire_room.nil? && !campfire_room.empty?
68
+ deploy_gist.gsub!(/(:campfire_room,\s)(nil)/, '\1' + "\"#{campfire_room}\"")
69
+ context["campfire_room"] = campfire_room
70
+ end
71
+
72
+ airbrake_api_key = ui.ask("What's the api key of this project for airbrake?")
73
+ if !airbrake_api_key.nil? && !airbrake_api_key.empty?
74
+ deploy_gist.gsub!(/(:airbrake_api_key,\s)(nil)/, '\1' + "\"#{airbrake_api_key}\"")
75
+ context["airbrake_api_key"] = airbrake_api_key
76
+ end
77
+
78
+ File.open(deploy, "w") do |f|
79
+ deploy_gist.each_line do |line|
80
+ f.print line
81
+ end
82
+ end
83
+ end
84
+
85
+ deploy_dir = File.join(base, "app", "config", "deploy")
86
+ Dir.mkdir(deploy_dir) unless File.directory?(deploy_dir)
87
+
88
+ {
89
+ "production" => PRODUCTION_GIST,
90
+ "staging" => STAGING_GIST
91
+ }.each do |env, gist|
92
+ file = File.join(deploy_dir, "#{env}.rb")
93
+ write = true
94
+
95
+ if File.exists?(file)
96
+ overwrite = ui.ask("The file #{file} already exists, do you want to override it? ") { |q| q.default = 'n' }
97
+ if !overwrite.match(/^y/)
98
+ write = false
99
+ end
100
+ end
101
+
102
+ if write
103
+ gist_body = get_plain_secure(gist).body
104
+ server = ui.ask("On which server is the #{env} environment deployed?")
105
+ if !server.match(/^.*\.kunstmaan\.be$/)
106
+ server = "#{server}.kunstmaan.be"
107
+ end
108
+
109
+ gist_body.gsub!(/(:domain,\s)(\"\")/, '\1' + "\"#{server}\"")
110
+
111
+ File.open(file, "w") do |f|
112
+ gist_body.each_line do |line|
113
+ f.print line
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ end
120
+
121
+ def update_jenkins_config(ui, base, context, force)
122
+ file = File.join(base, "build.xml")
123
+ write = true
124
+
125
+ if File.exists?(file)
126
+ overwrite = ui.ask("The file #{file} already exists, do you want to override it? ") { |q| q.default = 'n' }
127
+ if !overwrite.match(/^y/)
128
+ write = false
129
+ end
130
+ end
131
+
132
+ if write
133
+ gist_body = get_plain_secure(BUILD_GIST).body
134
+
135
+ context["app_name"] ||= ui.ask("What's the name of the application?")
136
+ app_name = context["app_name"]
137
+ gist_body.gsub!(/(\<project\sname=)(\"\")/, '\1' + "\"#{app_name}\"")
138
+
139
+ File.open(file, "w") do |f|
140
+ gist_body.each_line do |line|
141
+ f.print line
142
+ end
143
+ end
144
+ end
145
+
146
+ build_dir = File.join(base, "build")
147
+ Dir.mkdir(build_dir) unless File.directory?(build_dir)
148
+
149
+ {
150
+ File.join(build_dir, "phpcs.xml") => PHPCS_GIST,
151
+ File.join(build_dir, "phpmd.xml") => PHPMD_GIST,
152
+ File.join(base, "app", "phpunit.xml.dist") => PHPUNIT_GIST
153
+ }.each do |file, gist|
154
+ write = true
155
+
156
+ if File.exists?(file)
157
+ overwrite = ui.ask("The file #{file} already exists, do you want to override it? ") { |q| q.default = 'n' }
158
+ if !overwrite.match(/^y/)
159
+ write = false
160
+ end
161
+ end
162
+
163
+ if write
164
+ gist_body = get_plain_secure(gist).body
165
+
166
+ File.open(file, "w") do |f|
167
+ gist_body.each_line do |line|
168
+ f.print line
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ end
175
+
176
+ def get_plain_secure(url)
177
+ uri = URI.parse url
178
+ http = Net::HTTP.new(uri.host, uri.port)
179
+ http.use_ssl = uri.is_a?(URI::HTTPS)
180
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl?
181
+ http.start { |http| http.get(uri.path, {}) }
182
+ end
183
+
184
+ def validate_path
185
+ if ARGV.empty?
186
+ abort "Please specify the directory to kumafy, e.g. `#{File.basename($0)} .'"
187
+ elsif !File.exists?(ARGV.first)
188
+ abort "`#{ARGV.first}' does not exist."
189
+ elsif !File.directory?(ARGV.first)
190
+ abort "`#{ARGV.first}' is not a directory."
191
+ elsif ARGV.length > 1
192
+ abort "Too many arguments; please specify only the directory to kumafy."
193
+ end
194
+ end
195
+
196
+ force = false
197
+
198
+ OptionParser.new do |opts|
199
+ opts.banner = "Usage: #{File.basename($0)} [path]"
200
+
201
+ opts.on("-h", "--help", "Displays this help info") do
202
+ puts opts
203
+ exit 0
204
+ end
205
+
206
+ opts.on("-c", "--config", "Creates the configuration files needed for deployment") do
207
+ validate_path
208
+ ui = HighLine.new
209
+ base = ARGV.shift
210
+ context = Hash.new
211
+ update_deploy_config ui, base, context, force
212
+ exit 0
213
+ end
214
+
215
+ opts.on("-j", "--jenkins", "Creates the jenkins configuration files for this project") do
216
+ validate_path
217
+ ui = HighLine.new
218
+ base = ARGV.shift
219
+ context = Hash.new
220
+ update_jenkins_config ui, base, context, force
221
+ exit 0
222
+ end
223
+
224
+ opts.on("-f", "--force", "This will force the kumafying of the project") do
225
+ force = true
226
+ end
227
+
228
+ begin
229
+ opts.parse!(ARGV)
230
+ rescue OptionParser::ParseError => e
231
+ warn e.message
232
+ puts opts
233
+ exit 1
234
+ end
235
+ end
236
+
237
+ validate_path
238
+
239
+ ui = HighLine.new
240
+ base = ARGV.shift
241
+ context = Hash.new
242
+
243
+ puts "[start] kcapifony"
244
+ %x(kcapifony .)
245
+ puts "[end] kcapifony"
246
+
247
+ update_capfile base, context, force
248
+ update_deploy_config ui, base, context, force
249
+ update_jenkins_config ui, base, context, force
250
+
251
+ puts "[done] project kumafied!"
@@ -0,0 +1,33 @@
1
+ module Kumastrano
2
+ # Using the gem https://github.com/airbrake/airbrake doesn't work because it's made for rails apps, it needs rake etc. + you need to have the i18n gem
3
+ # This will integrate a very easy command to tell airbrake a deploy has been done
4
+ class AirbrakeHelper
5
+
6
+ require 'net/http'
7
+ require 'uri'
8
+ require 'etc'
9
+
10
+ def self.notify(api_key, revision, repository, environment = 'production', username = Etc.getlogin.capitalize)
11
+ uri = URI.parse("http://airbrake.io")
12
+
13
+ params = {
14
+ 'api_key' => api_key,
15
+ 'deploy[rails_env]' => environment, # Environment of the deploy (production, staging), this needs to be the current environment
16
+ 'deploy[scm_revision]' => revision, # The given revision/sha that is being deployed, this needs to be the current_revision variable
17
+ 'deploy[scm_repository]' => repository, # Address of your repository to help with code lookups
18
+ 'deploy[local_username]' => username # Who is deploying
19
+ }
20
+
21
+ post = Net::HTTP::Post.new("/deploys")
22
+ post.set_form_data(params)
23
+
24
+ res = Net::HTTP.start(uri.host, uri.port) {|http| http.request(post)}
25
+
26
+ if res.code.to_i == 200
27
+ return true
28
+ else
29
+ return false
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ module Kumastrano
2
+ class CampfireHelper
3
+
4
+ require 'broach'
5
+
6
+ def self.speak(campfire_account, campfire_token, campfire_room, message="")
7
+ ## extracted this to here, because i don't know how to call capistrano tasks with arguments
8
+ ## else i just had to make one capistrano task which i could call
9
+ if !campfire_account.nil? && !campfire_token.nil? && !campfire_room.nil?
10
+
11
+ Broach.settings = {
12
+ 'account' => campfire_account,
13
+ 'token' => campfire_token,
14
+ 'use_ssl' => true
15
+ }
16
+
17
+ room = Broach::Room.find_by_name campfire_room
18
+
19
+ if !room.nil?
20
+ room.speak message
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,36 @@
1
+ module Kumastrano
2
+ class GitHelper
3
+
4
+ require 'cgi'
5
+
6
+ def self.fetch
7
+ %x(git fetch)
8
+ end
9
+
10
+ def self.merge_base(commit1, commit2 = "HEAD")
11
+ base = %x(git merge-base #{commit1} #{commit2})
12
+ base.strip
13
+ end
14
+
15
+ def self.commit_hash(commit = "HEAD")
16
+ hash = %x(git rev-parse #{commit})
17
+ hash.strip
18
+ end
19
+
20
+ def self.branch_name(commit = "HEAD")
21
+ name = %x(git name-rev --name-only #{commit})
22
+ name.strip
23
+ end
24
+
25
+ def self.origin_refspec
26
+ refspec = %x(git config remote.origin.fetch)
27
+ refspec.strip
28
+ end
29
+
30
+ def self.origin_url
31
+ url = %x(git config remote.origin.url)
32
+ url.strip
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,132 @@
1
+ module Kumastrano
2
+ class JenkinsHelper
3
+
4
+ require 'cgi'
5
+ require 'net/http'
6
+ require 'uri'
7
+ require 'json'
8
+
9
+ def self.available?(base_uri)
10
+ res = get_plain("#{base_uri}")
11
+ res.code.to_i == 200
12
+ end
13
+
14
+ def self.build_and_wait(job_uri, timeout=300, interval=2)
15
+ success = false
16
+ last_build_info = nil
17
+ prev_build = Kumastrano::JenkinsHelper.last_build_number(job_uri)
18
+ Kumastrano::JenkinsHelper.build_job(job_uri)
19
+ Kumastrano.poll("A timeout occured", timeout, interval) do
20
+ ## wait for the building to be finished
21
+ last_build_info = Kumastrano::JenkinsHelper.build_info(job_uri)
22
+ result = last_build_info['result'] ## SUCCESS or FAILURE
23
+ building = last_build_info['building']
24
+ number = last_build_info['number']
25
+ if number == (prev_build + 1) && "false" == building.to_s && !result.nil?
26
+ if "SUCCESS" == result
27
+ success = true
28
+ else
29
+ success = false
30
+ end
31
+ true
32
+ else
33
+ false
34
+ end
35
+ end
36
+ return success, last_build_info
37
+ end
38
+
39
+ def self.fetch_build_hash_from_build_info(build_info, branch_name)
40
+ actions = build_info['actions']
41
+
42
+ build_hash = nil
43
+ actions.each do |list|
44
+ last_revision = list['lastBuiltRevision']
45
+ if !last_revision.nil? && branch_name == last_revision['branch'][0]['name'].sub("origin/", "")
46
+ build_hash = last_revision['branch'][0]['SHA1']
47
+ break
48
+ end
49
+ end
50
+
51
+ build_hash
52
+ end
53
+
54
+ def self.make_safe_job_name(app_name, branch_name)
55
+ job_name = "#{app_name} (#{branch_name})"
56
+ job_name.gsub(/[#*\/\\]/, "-") # \/#* is unsafe for jenkins job name, because not uri safe
57
+ end
58
+
59
+ def self.job_url_for_branch(jenkins_base_uri, branch_name)
60
+ current_job_url = nil
61
+ Kumastrano::JenkinsHelper.list_jobs(jenkins_base_uri).each do |job|
62
+ name = job["name"]
63
+ url = job["url"]
64
+ if /.*\(#{branch_name}\)/.match(name)
65
+ current_job_url = url
66
+ break
67
+ end
68
+ end
69
+ current_job_url
70
+ end
71
+
72
+ def self.job_url_for_name(jenkins_base_uri, job_name)
73
+ current_job_url = nil
74
+ Kumastrano::JenkinsHelper.list_jobs(jenkins_base_uri).each do |job|
75
+ name = job["name"]
76
+ url = job["url"]
77
+ if job_name == name
78
+ current_job_url = url
79
+ break
80
+ end
81
+ end
82
+ current_job_url
83
+ end
84
+
85
+ def self.list_jobs(base_uri)
86
+ res = get_plain("#{base_uri}/api/json?tree=jobs[name,url]")
87
+ parsed_res = JSON.parse(res.body)["jobs"]
88
+ end
89
+
90
+ def self.create_new_job(base_uri, job_name, config)
91
+ uri = URI.parse("#{base_uri}/createItem/api/json")
92
+ request = Net::HTTP::Post.new(uri.path + "?name=#{CGI.escape(job_name)}")
93
+ request.body = config
94
+ request["Content-Type"] = "application/xml"
95
+ res = Net::HTTP.start(uri.host, uri.port) {|http| http.request(request)}
96
+ if res.code.to_i == 200
97
+ puts "job created"
98
+ else
99
+ puts "job not created"
100
+ puts res.body
101
+ end
102
+ end
103
+
104
+ def self.retrieve_config_xml(job_uri)
105
+ res = get_plain("#{job_uri}/config.xml").body
106
+ end
107
+
108
+ def self.build_job(job_uri)
109
+ res = get_plain("#{job_uri}/build")
110
+ res.code.to_i == 302
111
+ end
112
+
113
+ def self.last_build_number(job_uri)
114
+ res = get_plain("#{job_uri}/api/json?tree=lastBuild[number]")
115
+ parsed_res = JSON.parse(res.body)
116
+ parsed_res['lastBuild']['number']
117
+ end
118
+
119
+ def self.build_info(job_uri, build="lastBuild")
120
+ res = get_plain("#{job_uri}/#{build}/api/json")
121
+ parsed_res = JSON.parse(res.body)
122
+ end
123
+
124
+ private
125
+
126
+ def self.get_plain(uri)
127
+ uri = URI.parse uri
128
+ res = Net::HTTP.start(uri.host, uri.port) { |http| http.get(uri.path, {}) }
129
+ end
130
+
131
+ end
132
+ end
@@ -0,0 +1,27 @@
1
+ module Kumastrano
2
+
3
+ def poll(msg=nil, seconds=10.0, interval_seconds=1.0)
4
+ (seconds / interval_seconds).to_i.times do
5
+ result = yield
6
+ return if result
7
+ sleep interval_seconds
8
+ end
9
+ msg ||= "polling failed after #{seconds} seconds"
10
+ raise msg
11
+ end
12
+
13
+ def say(text)
14
+ Capistrano::CLI.ui.say(" * #{text}")
15
+ end
16
+
17
+ def ask(question, default='n')
18
+ agree = Capistrano::CLI.ui.agree(" #{question} ") do |q|
19
+ q.default = default
20
+ end
21
+
22
+ agree
23
+ end
24
+
25
+ module_function :poll, :say, :ask
26
+
27
+ end
data/lib/kstrano.rb ADDED
@@ -0,0 +1,298 @@
1
+ set :jenkins_base_uri, ""
2
+ set :jenkins_base_job_name, "Default"
3
+ set :jenkins_poll_timeout, 300
4
+ set :jenkins_poll_interval, 2
5
+ set :jenkins_enabled, false
6
+
7
+ set :campfire_room, nil
8
+ set :campfire_token, "" ## kbot
9
+ set :campfire_account, "Kunstmaan"
10
+
11
+ set :airbrake_api_key, nil
12
+
13
+
14
+ require "#{File.dirname(__FILE__)}/helpers/git_helper.rb"
15
+ require "#{File.dirname(__FILE__)}/helpers/jenkins_helper.rb"
16
+ require "#{File.dirname(__FILE__)}/helpers/airbrake_helper.rb"
17
+ require "#{File.dirname(__FILE__)}/helpers/campfire_helper.rb"
18
+ require "#{File.dirname(__FILE__)}/helpers/kuma_helper.rb"
19
+ require 'rexml/document'
20
+ require 'etc'
21
+
22
+ namespace :kuma do
23
+
24
+ desc "Run fixcron for the current project"
25
+ task :fixcron do
26
+ sudo "sh -c 'if [ -f /opt/kDeploy/tools/fixcron.py ] ; then cd /opt/kDeploy/tools/; python fixcron.py #{application}; fi'"
27
+ end
28
+
29
+ desc "Run fixperms for the current project"
30
+ task :fixperms do
31
+ sudo "sh -c 'if [ -f /opt/kDeploy/tools/fixperms.py ] ; then cd /opt/kDeploy/tools/; python fixperms.py #{application}; fi'"
32
+ end
33
+
34
+ end
35
+
36
+ namespace :airbrake do
37
+
38
+ desc "Register a deploy with airbrake.io"
39
+ task :notify do
40
+ if !airbrake_api_key.nil?
41
+ revision = Kumastrano::GitHelper::commit_hash
42
+ repository = Kumastrano::GitHelper::origin_url
43
+ env ||= "production"
44
+ success = Kumastrano::AirbrakeHelper.notify airbrake_api_key, revision, repository, env
45
+ Kumastrano.say "Failed notifying airbrake of the new deploy" unless success
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+ namespace :campfire do
52
+
53
+ desc "Say something on campfire"
54
+ task:say do
55
+ if !campfire_room.nil?
56
+ message = ARGV.join(' ').gsub('campfire:say', '')
57
+ Kumastrano::CampfireHelper.speak campfire_account, campfire_token, campfire_room, message
58
+ exit
59
+ end
60
+ end
61
+
62
+ end
63
+
64
+ namespace :jenkins do
65
+
66
+ desc "create a job for the current branch and application on Jenkins"
67
+ task:create_job do
68
+ ## 1. locate the job in jenkins
69
+ current_branch = Kumastrano::GitHelper.branch_name
70
+ job_name = Kumastrano::JenkinsHelper.make_safe_job_name(application, current_branch)
71
+ current_job_url = Kumastrano::JenkinsHelper.job_url_for_name(jenkins_base_uri, job_name)
72
+
73
+ ## 2. if no job was found, first create a job for this branch
74
+ if current_job_url.nil?
75
+ Kumastrano.say "no job found for branch #{current_branch} on #{application}, we'll create one now"
76
+ default_job_url = Kumastrano::JenkinsHelper.job_url_for_name(jenkins_base_uri, jenkins_base_job_name)
77
+ if !default_job_url.nil?
78
+ current_refspec = Kumastrano::GitHelper.origin_refspec
79
+ current_url = Kumastrano::GitHelper.origin_url
80
+
81
+ default_job_config = Kumastrano::JenkinsHelper.retrieve_config_xml default_job_url
82
+ document = REXML::Document.new default_job_config
83
+ root = document.root
84
+
85
+ ## change the description
86
+ root.elements['description'].text = "This job will be used for testing the branch #{current_branch}"
87
+
88
+ ## change the git config
89
+ git_element = root.elements["scm[@class='hudson.plugins.git.GitSCM']"]
90
+ git_element.elements["userRemoteConfigs/hudson.plugins.git.UserRemoteConfig/refspec"].text = current_refspec
91
+ git_element.elements["userRemoteConfigs/hudson.plugins.git.UserRemoteConfig/url"].text = current_url
92
+ git_element.elements["branches/hudson.plugins.git.BranchSpec/name"].text = current_branch
93
+
94
+ ## create the new job based on the modified git config
95
+ Kumastrano::JenkinsHelper.create_new_job(jenkins_base_uri, job_name, document.to_s)
96
+ current_job_url = Kumastrano::JenkinsHelper.job_url_for_name(jenkins_base_uri, job_name)
97
+ end
98
+ else
99
+ Kumastrano.say "there was already a job available on Jenkins for branch #{current_branch} on #{application}"
100
+ end
101
+
102
+ current_job_url
103
+ end
104
+
105
+ desc "Try to build the current branch on Jenkins"
106
+ task:build do
107
+ current_job_url = jenkins::create_job
108
+ current_branch = Kumastrano::GitHelper.branch_name
109
+
110
+ if !current_job_url.nil?
111
+ job_name = Kumastrano::JenkinsHelper.make_safe_job_name(application, current_branch)
112
+ prev_build = Kumastrano::JenkinsHelper.last_build_number current_job_url
113
+ Kumastrano.say "start building build ##{(prev_build + 1)} on job #{job_name}, this can take a while"
114
+
115
+ result, last_build_info = Kumastrano::JenkinsHelper.build_and_wait current_job_url, jenkins_poll_timeout, jenkins_poll_interval
116
+
117
+ message = ""
118
+ if result
119
+ Kumastrano.say "the build was succesful"
120
+ message = "was a success"
121
+ else
122
+ Kumastrano.say "the build failed"
123
+ message = "failed"
124
+ end
125
+
126
+ Kumastrano::CampfireHelper.speak campfire_account, campfire_token, campfire_room, "#{Etc.getlogin.capitalize} just builded a new version of #{current_branch} on #{application} and it #{message}. You can view the results here #{current_job_url}/lastBuild."
127
+ else
128
+ Kumastrano.say "no job found for #{job_name}, cannot build"
129
+ end
130
+ end
131
+
132
+ end
133
+
134
+ namespace :deploy do
135
+
136
+ task :symlink, :except => { :no_release => true } do
137
+ on_rollback do
138
+ if previous_release
139
+ try_sudo "ln -sf #{previous_release} #{current_path}; true"
140
+ else
141
+ logger.important "no previous release to rollback to, rollback of symlink skipped"
142
+ end
143
+ end
144
+
145
+ try_sudo "ln -sfT #{latest_release} #{current_path}"
146
+ end
147
+
148
+ end
149
+
150
+ ## Capistrano callbacks ##
151
+
152
+ # Before deploy:
153
+ ## Check if there is a build on jenkins. If none is available, it will create one.
154
+ ## Notify on Campfire what the deployer did.
155
+ before :deploy do
156
+ ## only do this in production environment
157
+ if env == 'production' and jenkins_enabled
158
+ can_deploy = false
159
+ current_branch = Kumastrano::GitHelper.branch_name
160
+ current_hash = Kumastrano::GitHelper.commit_hash
161
+
162
+ if Kumastrano::JenkinsHelper.available? jenkins_base_uri
163
+ ## Allways fetch the latest information from git
164
+ Kumastrano::GitHelper.fetch
165
+
166
+ job_name = Kumastrano::JenkinsHelper.make_safe_job_name(application, current_branch)
167
+ current_job_url = Kumastrano::JenkinsHelper.job_url_for_name(jenkins_base_uri, job_name)
168
+
169
+ if current_job_url.nil?
170
+ ## No job exists for the current branch, we'll create a job.
171
+ if Kumastrano.ask "no job found for the current branch, do you want to create a job for #{current_branch} on #{application}?", 'y'
172
+ current_job_url = jenkins::create_job
173
+ end
174
+ end
175
+
176
+ if !current_job_url.nil?
177
+ ## we have a job url, get info of the lastBuild
178
+ last_build_info = Kumastrano::JenkinsHelper.build_info current_job_url
179
+ result = last_build_info['result'] ## SUCCESS or FAILURE
180
+ build_hash = Kumastrano::JenkinsHelper.fetch_build_hash_from_build_info(last_build_info, current_branch)
181
+
182
+ if !build_hash.nil?
183
+ if build_hash == current_hash
184
+ if "SUCCESS" == result
185
+ ## The hash of the last build is the same as my hash we can deploy
186
+ can_deploy = true
187
+ else
188
+ ## The hash of the last build is the same as the current hash, but the build failed.
189
+ if Kumastrano.ask "the last build for the branch #{current_branch} for commit #{current_hash} failed, do you want to build again?", 'y'
190
+ prev_build = Kumastrano::JenkinsHelper.last_build_number current_job_url
191
+ Kumastrano.say "start building build ##{(prev_build + 1)} on job #{job_name}, this can take a while"
192
+ result, last_build_info = Kumastrano::JenkinsHelper.build_and_wait current_job_url, jenkins_poll_timeout, jenkins_poll_interval
193
+ new_build_hash = Kumastrano::JenkinsHelper.fetch_build_hash_from_build_info(last_build_info, current_branch)
194
+ if !result.nil? && result && !new_build_hash.nil? && new_build_hash = current_hash
195
+ can_deploy = true
196
+ else
197
+ Kumastrano.say "there is still something wrong with #{current_branch} on #{application}, please check manually and try deploying again afterwards!"
198
+ end
199
+ end
200
+ end
201
+ else
202
+ merge_base = Kumastrano::GitHelper.merge_base(build_hash, current_hash)
203
+ if merge_base == build_hash
204
+ ## The build commit is an ancestor of HEAD
205
+ if Kumastrano.ask "the last build for the branch #{current_branch} is from an older commit do you want to build again? (jenkins=#{build_hash}, local=#{current_hash})", 'y'
206
+ prev_build = Kumastrano::JenkinsHelper.last_build_number current_job_url
207
+ Kumastrano.say "start building build ##{(prev_build + 1)} on job #{job_name}, this can take a while"
208
+ result, last_build_info = Kumastrano::JenkinsHelper.build_and_wait current_job_url, jenkins_poll_timeout, jenkins_poll_interval
209
+ new_build_hash = Kumastrano::JenkinsHelper.fetch_build_hash_from_build_info(last_build_info, current_branch)
210
+ if !result.nil? && result && !new_build_hash.nil? && new_build_hash = current_hash
211
+ can_deploy = true
212
+ else
213
+ Kumastrano.say "there is still something wrong with #{current_branch} on #{application}, please check manually and try deploying again afterwards!"
214
+ end
215
+ end
216
+ elsif merge_base == current_hash
217
+ ## The current HEAD is an ancestor of the build hash
218
+ Kumastrano.say "the latest build is of a newer commit, someone else is probably working on the same branch, try updating your local repository first. (jenkins=#{build_hash}, local=#{current_hash})"
219
+ else
220
+ ## Something is wrong, we don't know what try building again
221
+ if Kumastrano.ask "the latest build isn't a valid build, do you want to try building again? (jenkins=#{build_hash}, local=#{current_hash})", 'y'
222
+ prev_build = Kumastrano::JenkinsHelper.last_build_number current_job_url
223
+ Kumastrano.say "start building build ##{(prev_build + 1)} on job #{job_name}, this can take a while"
224
+ result, last_build_info = Kumastrano::JenkinsHelper.build_and_wait current_job_url, jenkins_poll_timeout, jenkins_poll_interval
225
+ new_build_hash = Kumastrano::JenkinsHelper.fetch_build_hash_from_build_info(last_build_info, current_branch)
226
+ if !result.nil? && result && !new_build_hash.nil? && new_build_hash = current_hash
227
+ can_deploy = true
228
+ else
229
+ Kumastrano.say "there is still something wrong with #{current_branch} on #{application}, please check manually and try deploying again afterwards!"
230
+ end
231
+ end
232
+ end
233
+ end
234
+ else
235
+ ## No build found, try building it
236
+ if Kumastrano.ask "no build found, do you want to try building it?", 'y'
237
+ prev_build = Kumastrano::JenkinsHelper.last_build_number current_job_url
238
+ Kumastrano.say "start building build ##{(prev_build + 1)} on job #{job_name}, this can take a while"
239
+ result, last_build_info = Kumastrano::JenkinsHelper.build_and_wait current_job_url, jenkins_poll_timeout, jenkins_poll_interval
240
+ new_build_hash = Kumastrano::JenkinsHelper.fetch_build_hash_from_build_info(last_build_info, current_branch)
241
+ if !result.nil? && result && !new_build_hash.nil? && new_build_hash = current_hash
242
+ can_deploy = true
243
+ else
244
+ Kumastrano.say "there is still something wrong with #{current_branch} on #{application}, please check manually and try deploying again afterwards!"
245
+ end
246
+ end
247
+ end
248
+ end
249
+ end
250
+
251
+ if !can_deploy
252
+ if Kumastrano.ask "no valid build found for #{current_hash} on branch #{current_branch}, do you still want to deploy?"
253
+ Kumastrano::CampfireHelper.speak campfire_account, campfire_token, campfire_room, "#{Etc.getlogin.capitalize} ignored the fact there was something wrong with #{current_branch} on #{application} and still went on with deploying it!!"
254
+ else
255
+ Kumastrano::CampfireHelper.speak campfire_account, campfire_token, campfire_room, "#{Etc.getlogin.capitalize} wanted to deploy #{current_branch} on #{application} but there is something wrong with the code, so he cancelled it!"
256
+ exit
257
+ end
258
+ else
259
+ Kumastrano::CampfireHelper.speak campfire_account, campfire_token, campfire_room, "#{Etc.getlogin.capitalize} is deploying #{current_branch} for #{application}"
260
+ end
261
+ else
262
+ Kumastrano.say "jenkins on demand is disabled, skipping..."
263
+ end
264
+ end
265
+
266
+ # Before update_code:
267
+ ## Make the cached_copy readable for the current user
268
+ before "deploy:update_code" do
269
+ user = Etc.getlogin
270
+ sudo "sh -c 'if [ -d #{shared_path}/cached-copy ] ; then chown -R #{user}:#{user} #{shared_path}/cached-copy; fi'" if deploy_via == :rsync_with_remote_cache || deploy_via == :remote_cache
271
+ end
272
+
273
+ # After update_code:
274
+ ## Fix the permissions of the cached_copy so that it's readable for the project user
275
+ after "deploy:update_code" do
276
+ sudo "sh -c 'if [ -d #{shared_path}/cached-copy ] ; then chown -R #{application}:#{application} #{shared_path}/cached-copy; fi'" if deploy_via == :rsync_with_remote_cache || deploy_via == :remote_cache
277
+ end
278
+
279
+ # Before finalize_update:
280
+ ## Create the parameters.ini if it's a symfony project
281
+ ## Fix the permissions of the latest release, so that it's readable for the project user
282
+ before "deploy:finalize_update" do
283
+ sudo "sh -c 'if [ -d #{shared_path}/cached-copy ] ; then chmod -R ug+rx #{latest_release}/paramDecode; fi'"
284
+ sudo "sh -c 'if [ -f #{latest_release}/paramDecode ] ; then cd #{latest_release} && ./paramDecode; fi'" # Symfony specific: will generate the parameters.ini
285
+ sudo "chown -R #{application}:#{application} #{latest_release}"
286
+ sudo "setfacl -R -m group:admin:rwx #{latest_release}"
287
+ end
288
+
289
+ # After deploy:
290
+ ## Notify the people on campfire of this deploy
291
+ ## Notify airbrake to add a new deploy to the deploy history
292
+ after :deploy do
293
+ current_branch = Kumastrano::GitHelper.branch_name
294
+ Kumastrano::CampfireHelper.speak campfire_account, campfire_token, campfire_room, "#{Etc.getlogin.capitalize} successfuly deployed #{current_branch} for #{application}"
295
+ airbrake::notify
296
+ deploy::cleanup ## cleanup old releases
297
+ kuma::fixcron
298
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kstrano
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Kunstmaan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: capistrano
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 2.12.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 2.12.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: capistrano-ext
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 1.2.1
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 1.2.1
46
+ - !ruby/object:Gem::Dependency
47
+ name: capistrano_colors
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: 0.5.5
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.5.5
62
+ - !ruby/object:Gem::Dependency
63
+ name: kcapifony
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: 2.1.3
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: 2.1.3
78
+ - !ruby/object:Gem::Dependency
79
+ name: json
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: 1.6.6
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: 1.6.6
94
+ - !ruby/object:Gem::Dependency
95
+ name: broach
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: 0.2.1
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: 0.2.1
110
+ - !ruby/object:Gem::Dependency
111
+ name: highline
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: 1.6.11
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: 1.6.11
126
+ description: Deploying applications with Capistrano, Jenkins and GIT.
127
+ email: support@kunstmaan.be
128
+ executables:
129
+ - kumafy
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - lib/helpers/airbrake_helper.rb
134
+ - lib/helpers/campfire_helper.rb
135
+ - lib/helpers/git_helper.rb
136
+ - lib/helpers/jenkins_helper.rb
137
+ - lib/helpers/kuma_helper.rb
138
+ - lib/kstrano.rb
139
+ - bin/kumafy
140
+ homepage: https://github.com/Kunstmaan/kStrano
141
+ licenses: []
142
+ post_install_message:
143
+ rdoc_options: []
144
+ require_paths:
145
+ - lib
146
+ required_ruby_version: !ruby/object:Gem::Requirement
147
+ none: false
148
+ requirements:
149
+ - - ! '>='
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 1.8.23
161
+ signing_key:
162
+ specification_version: 3
163
+ summary: Deploying applications with Capistrano, Jenkins and GIT.
164
+ test_files: []