ucb_rails_ci 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7fd00d015b13a606625896918ba8ba848a39e7c0
4
+ data.tar.gz: c53a1860d8fda5030635caee14840f8ff6c08cc5
5
+ SHA512:
6
+ metadata.gz: 9b25c28b48232f954e30155acbcf71b76a23a602bde491eda844bb40b5ba055f5dd95870e521cb4a2a9aa651ea93044195992a90df811a80c47b2e1f5274a9fc
7
+ data.tar.gz: bae199cd74d50285bdd896e3bb63574dc8fe1197fd90ac5d3db73f634f0562008402b70d798e011180d81ad38809511b1290ccb4974d978b3092f09bcd430029
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+
2
+ source 'https://rubygems.org'
3
+
4
+ gemspec
@@ -0,0 +1,102 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ucb_rails_ci (1.0.0)
5
+ builder
6
+ bundler
7
+ github_api
8
+ rake
9
+ travis
10
+ warbler
11
+
12
+ GEM
13
+ remote: https://rubygems.org/
14
+ specs:
15
+ addressable (2.3.7)
16
+ backports (3.6.4)
17
+ builder (3.2.2)
18
+ coderay (1.1.0)
19
+ descendants_tracker (0.0.4)
20
+ thread_safe (~> 0.3, >= 0.3.1)
21
+ ethon (0.7.3)
22
+ ffi (>= 1.3.0)
23
+ faraday (0.9.1)
24
+ multipart-post (>= 1.2, < 3)
25
+ faraday_middleware (0.9.1)
26
+ faraday (>= 0.7.4, < 0.10)
27
+ ffi (1.9.3)
28
+ gh (0.14.0)
29
+ addressable
30
+ backports
31
+ faraday (~> 0.8)
32
+ multi_json (~> 1.0)
33
+ net-http-persistent (>= 2.7)
34
+ net-http-pipeline
35
+ github_api (0.12.2)
36
+ addressable (~> 2.3)
37
+ descendants_tracker (~> 0.0.4)
38
+ faraday (~> 0.8, < 0.10)
39
+ hashie (>= 3.3)
40
+ multi_json (>= 1.7.5, < 2.0)
41
+ nokogiri (~> 1.6.3)
42
+ oauth2
43
+ hashie (3.3.2)
44
+ highline (1.7.0)
45
+ jruby-jars (1.7.17)
46
+ jruby-rack (1.1.18)
47
+ json (1.8.1)
48
+ jwt (1.2.1)
49
+ launchy (2.4.3)
50
+ addressable (~> 2.3)
51
+ method_source (0.8.2)
52
+ mini_portile (0.6.2)
53
+ multi_json (1.10.1)
54
+ multi_xml (0.5.5)
55
+ multipart-post (2.0.0)
56
+ net-http-persistent (2.9.4)
57
+ net-http-pipeline (1.0.1)
58
+ nokogiri (1.6.6.2)
59
+ mini_portile (~> 0.6.0)
60
+ oauth2 (1.0.0)
61
+ faraday (>= 0.8, < 0.10)
62
+ jwt (~> 1.0)
63
+ multi_json (~> 1.3)
64
+ multi_xml (~> 0.5)
65
+ rack (~> 1.2)
66
+ pry (0.9.12.4)
67
+ coderay (~> 1.0)
68
+ method_source (~> 0.8)
69
+ slop (~> 3.4)
70
+ pusher-client (0.6.0)
71
+ json
72
+ websocket (~> 1.0)
73
+ rack (1.6.0)
74
+ rake (10.4.2)
75
+ rubyzip (1.1.7)
76
+ slop (3.4.7)
77
+ thread_safe (0.3.4)
78
+ travis (1.7.5)
79
+ addressable (~> 2.3)
80
+ backports
81
+ faraday (~> 0.9)
82
+ faraday_middleware (~> 0.9, >= 0.9.1)
83
+ gh (~> 0.13)
84
+ highline (~> 1.6)
85
+ launchy (~> 2.1)
86
+ pry (~> 0.9, < 0.10)
87
+ pusher-client (~> 0.4)
88
+ typhoeus (~> 0.6, >= 0.6.8)
89
+ typhoeus (0.7.1)
90
+ ethon (>= 0.7.1)
91
+ warbler (1.4.5)
92
+ jruby-jars (>= 1.5.6, < 2.0)
93
+ jruby-rack (>= 1.1.1, < 1.3)
94
+ rake (>= 0.9.6)
95
+ rubyzip (>= 0.9, < 1.2)
96
+ websocket (1.0.7)
97
+
98
+ PLATFORMS
99
+ ruby
100
+
101
+ DEPENDENCIES
102
+ ucb_rails_ci!
@@ -0,0 +1,49 @@
1
+ Rakefile
2
+ ========
3
+
4
+ Rake commands for command line deployment. Basic usage:
5
+
6
+ ```
7
+ # SVN/jenkins deploys
8
+
9
+ rake deploy APP=<app name> # defaults to trunk
10
+ rake deploy APP=<app name> BRANCH=<branch name>
11
+ rake deploy APP=<app name> TAG=<tag>
12
+
13
+ # Github/Travis-CI deploys
14
+ rake gdeploy APP=<app name> # defaults to master
15
+ rake gdeploy APP=<app name> BRANCH=<branch name>
16
+ rake gdeploy APP=<app name> TAG=<tag>
17
+
18
+ # Restarting
19
+ rake restart APP=<app name>
20
+ ```
21
+
22
+ ucb\_rails\_ci.rake
23
+ =======
24
+
25
+ Automatically included in any project that wants to be deployed via
26
+ Github/Travis. Basic tasks for prepping and precompiling a rails project.
27
+
28
+ Examples:
29
+
30
+ ```bash
31
+ rake ci:setup # any preliminary setup
32
+ rake ci:war # Build a war file for JRuby deployment
33
+ ```
34
+
35
+ ci.rb
36
+ =====
37
+
38
+ Simple scripts to supplement CI build. This applies to jenkins only -- Travis
39
+ uses a different mechanism.
40
+
41
+ Usage:
42
+
43
+ ```
44
+ ci.rb APP_NAME [--run-specs-false] [--compile-assets-flag]
45
+
46
+ --run-specs-flag (defaults is true)
47
+ --compile-assets-flag (defaults is true)
48
+ ```
49
+
@@ -0,0 +1,370 @@
1
+ require 'fileutils'
2
+ require 'erb'
3
+ require 'yaml'
4
+ require 'ostruct'
5
+ require 'github_api'
6
+
7
+ sync = true
8
+
9
+ ################################################################################
10
+ # Initialization
11
+ ################################################################################
12
+ task :default => :deploy
13
+
14
+ desc "deploy the application"
15
+
16
+ task :do_deploy => [:symlink_configs, :disable_web, :tomcat_stop,
17
+ :deploy_war, :load_crontab, :tomcat_start, :enable_web]
18
+
19
+ task :deploy => [:parse_args, :svn_export, :do_deploy]
20
+ task :gdeploy => [:parse_args, :github_release_export, :do_deploy]
21
+
22
+ desc "Full restart without deploy"
23
+ task :restart => [:disable_web, :tomcat_stop, :tomcat_start, :enable_web]
24
+
25
+ task :parse_args do
26
+ unless ENV['APP']
27
+ $stderr.puts "Usage: rake APP=<app_name>"
28
+ exit(1)
29
+ end
30
+
31
+ base_dir = ENV['DEPLOY_BASE'] || ENV['HOME']
32
+ config_dir = "#{base_dir}/.deploy_config/#{ENV['APP']}"
33
+ work_dir = "#{base_dir}/.deploy_work"
34
+
35
+ $config = OpenStruct.new(YAML.load_file("#{config_dir}/deploy.yml"))
36
+ $config.config_dir = config_dir
37
+ $config.debug = (ENV['DEBUG'] == 'true')
38
+ $config.app_name = ENV['APP']
39
+ $config.app_user = "app_#{ENV['APP']}"
40
+ $config.tag = ENV['TAG']
41
+ $config.branch = ENV['BRANCH'] || $config.tag || 'master'
42
+ $config.war = ENV['WAR'] || ($config.branch == 'master') ? 'trunk.war' : "#{$config.branch}.war"
43
+ $config.release_url = "#{$config.svn_project_url}/#{$config.war}"
44
+ $config.work_dir = "#{work_dir}/#{$config.app_name}"
45
+
46
+ if $config.github_api_token
47
+ $github = Github.new do |c|
48
+ c.oauth_token = $config.github_api_token
49
+ c.user = 'ucb-ist-eas'
50
+ c.repo = $config.app_name
51
+ end
52
+ end
53
+
54
+ if $config.debug
55
+ puts($config.inspect)
56
+ end
57
+ end
58
+
59
+
60
+ ################################################################################
61
+ # Deploy War
62
+ ################################################################################
63
+ desc "Deploy the war file to tomcat webapps dir"
64
+ task :deploy_war => [:parse_args, :ensure_work_directory] do
65
+ progress "Deploying war to tomcat" do
66
+
67
+ webapps = $config.webapps_dir
68
+ app = $config.app_name
69
+ root = "ROOT"
70
+ app_user = $config.app_user
71
+
72
+ FileUtils.cd($config.work_dir) do
73
+ run_cmd "sudo -u #{app_user} rm -rf #{webapps}/#{root}/*"
74
+ run_cmd "rm -rf #{webapps}/#{root}"
75
+ run_cmd "cp -R . #{webapps}/#{app}"
76
+ run_cmd "mv #{webapps}/#{app} #{webapps}/#{root}"
77
+ end
78
+
79
+ end
80
+ end
81
+
82
+
83
+ ################################################################################
84
+ # Start/Stop Tomcat
85
+ ################################################################################
86
+ desc "stop tomcat application server"
87
+ task :tomcat_stop => [:parse_args] do
88
+ unless $dry_run
89
+ status_cmd = "sudo service tomcat6-#{$config.app_name} status"
90
+ stop_cmd = "sudo service tomcat6-#{$config.app_name} stop"
91
+
92
+ output = `#{status_cmd}`.chomp
93
+ if $?.exitstatus == 3
94
+ puts(output)
95
+ else
96
+ output = `#{stop_cmd}`.chomp
97
+ if $?.exitstatus == 0
98
+ puts(output)
99
+ else
100
+ $stderr.puts(output)
101
+ exit(1)
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ desc "start tomcat application server"
108
+ task :tomcat_start => [:parse_args] do
109
+ unless $dry_run
110
+ output = `sudo service tomcat6-#{$config.app_name} start`.chomp
111
+ puts(output)
112
+ end
113
+ end
114
+
115
+
116
+ ################################################################################
117
+ # Checkout Source Code
118
+ ################################################################################
119
+ def copy_yml_configs
120
+ Dir["#{$config.config_dir}/*.yml"].each do |file_path|
121
+ file_name = File.basename(file_path)
122
+ unless file_name == "deploy.yml"
123
+ `cp #{file_path} ./WEB-INF/config/#{file_name}`
124
+ end
125
+ end
126
+ end
127
+
128
+ def configure_web_xml
129
+ web_xml = "WEB-INF/web.xml"
130
+
131
+ lines = File.readlines(web_xml)
132
+ File.open(web_xml, "w") do |f|
133
+ lines.each do |line|
134
+ if line =~ /<param-value>production<\/param-value>/
135
+ f.puts("<param-value>#{$config.rails_env}<\/param-value>")
136
+ elsif line =~ /<param-value>ci<\/param-value>/
137
+ f.puts("<param-value>#{$config.rails_env}<\/param-value>")
138
+ else
139
+ f.puts(line)
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+ def symlink_tmp_to_temp
146
+ `ln -s /var/lib/tomcat6-#{$config.app_name}/temp WEB-INF/tmp`
147
+ end
148
+
149
+ def extract_war
150
+ `jar -xvf *.war`
151
+ `rm -rf *.war`
152
+ end
153
+
154
+ desc "Embed and link configs"
155
+ task :symlink_configs => [:ensure_work_directory] do
156
+ progress "Embedding configs and linking directories" do
157
+
158
+ FileUtils.cd($config.work_dir) do
159
+ extract_war
160
+ copy_yml_configs
161
+ configure_web_xml
162
+ symlink_tmp_to_temp
163
+ end
164
+
165
+ end
166
+ end
167
+
168
+ desc "download project from svn"
169
+ task :svn_export => [:parse_args, :svn_war_exists, :ensure_work_directory] do
170
+ progress "Exporting code from SVN (#{$config.release_url})" do
171
+
172
+ app_dir = $config.app_name
173
+
174
+ if File.exists?(app_dir)
175
+ puts "App dir #{app_dir} already exists. Incomplete deploy?"
176
+ exit(1)
177
+ end
178
+
179
+ run_cmd("svn export #{$config.release_url}")
180
+
181
+ end
182
+ end
183
+
184
+ desc "download project from github"
185
+ task :github_release_export => [:parse_args, :ensure_work_directory] do
186
+ if $config.tag.nil?
187
+
188
+ # Look at the list of releases and pick with the highest number matching the branch
189
+ releases = $github.repos.releases.list('ucb-ist-eas', $config.app_name)
190
+ branch_tags = releases.map(&:tag_name).select { |t| t =~ /\A#{$config.branch}-\d+\Z/ }
191
+ branch_tags.sort_by! { |t| t =~ /-(\d+)\Z/; $1.to_i }
192
+
193
+ if branch_tags.empty?
194
+ puts "No tags found for BRANCH=#{$config.branch}. Use TAG variable to specify a particular tag."
195
+ exit 1
196
+ else
197
+ $config.tag = branch_tags.last
198
+ end
199
+ end
200
+
201
+ progress "Exporting war file from GitHub for tag #{$config.tag}" do
202
+
203
+ app_dir = $config.app_name
204
+ orig_war = "#{$config.app_name}.war"
205
+
206
+ cmd = %{github-release download
207
+ -s #{$config.github_api_token}
208
+ -u ucb-ist-eas
209
+ -r #{$config.app_name}
210
+ -t #{$config.tag}
211
+ -n #{orig_war}}
212
+
213
+ cmd.gsub!(/[[:space:]]+/, " ")
214
+
215
+ run_cmd cmd, fail_msg: "Could not download the release. Is the tag right? Is github-release installed?"
216
+
217
+ FileUtils.mv(orig_war, $config.war)
218
+
219
+ end
220
+ end
221
+
222
+ task :svn_war_exists => [:svn_project_exists] do
223
+ run_cmd "svn ls #{$config.release_url} 2>&1",
224
+ fail_msg: "SVN URL not found: #{$config.release_url}"
225
+ end
226
+
227
+ task :svn_project_exists => [:parse_args] do
228
+ run_cmd "svn ls #{$config.svn_project_url} 2>&1",
229
+ fail_msg: "SVN URL not found: #{$config.svn_project_url}"
230
+ end
231
+
232
+ desc "Create work directory if necessary"
233
+ task :ensure_work_directory => [:parse_args] do
234
+ run_cmd "mkdir -p #{$config.work_dir}",
235
+ fail_msg: "Cannot create work directory: #{$config.work_dir}"
236
+
237
+ FileUtils.cd($config.work_dir)
238
+ end
239
+
240
+ ################################################################################
241
+ # Enable/Disable web
242
+ ################################################################################
243
+ desc "remove maintenance file and enable web access to app"
244
+ task :enable_web => [:parse_args] do
245
+ progress "Enabling tomcat proxy, remove maint message" do
246
+
247
+ file = $config.work_dir
248
+ FileUtils.rm_rf(file) if File.exists?(file)
249
+ FileUtils.rm_rf($config.maint_file) if File.exists?($config.maint_file)
250
+
251
+ end
252
+ end
253
+
254
+ desc "display maintenance file and disable web access to app"
255
+ task :disable_web => [:parse_args] do
256
+ progress "Disabling tomcat proxy, display maint message" do
257
+
258
+ maint_start = Time.now.strftime("%m-%d-%Y %H:%M:%S")
259
+ template = ERB.new($template)
260
+ File.open($config.maint_file, "w") do |f|
261
+ f.puts template.result(binding)
262
+ end
263
+
264
+ raise "file is missing" unless File.exists?($config.maint_file)
265
+ end
266
+ end
267
+
268
+ $template = %q{
269
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
270
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
271
+
272
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
273
+
274
+ <head>
275
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
276
+ <title>Site Maintenance</title>
277
+ <style type="text/css">
278
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
279
+ div.dialog {
280
+ width: 35em;
281
+ padding: 0 3em;
282
+ margin: 3em auto 0 auto;
283
+ border: 1px solid #ccc;
284
+ border-right-color: #999;
285
+ border-bottom-color: #999;
286
+ }
287
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
288
+ </style>
289
+ </head>
290
+
291
+ <body>
292
+ <div class="dialog">
293
+ <h1>Site Maintenance</h1>
294
+ <p>
295
+ The site is down for maintenance as of: <strong><%= maint_start %></strong> <br/>
296
+ it should be available shortly.
297
+ </p>
298
+ </div>
299
+ </body>
300
+ </html>
301
+ }
302
+
303
+
304
+ ################################################################################
305
+ # Cron Jobs
306
+ ################################################################################
307
+
308
+ desc "load cron jobs from crontab"
309
+ task :load_crontab do
310
+ crontab_file = "#{$config.app_name}/config/crontab.txt"
311
+ if $config.rails_env == "production" && File.exists?(crontab_file)
312
+ `/usr/bin/crontab -u app_#{$config.app_name} #{crontab_file}`
313
+ end
314
+ end
315
+
316
+ ################################################################################
317
+ # Misc
318
+ ################################################################################
319
+
320
+ desc "curls the ~/app_monitor url and performs a basic health check"
321
+ task :health_check => [:parse_args] do
322
+ progress "Performing health check" do
323
+
324
+ result = `curl -m 10 -s localhost:#{$config.tomcat_port}/app_monitor`.chomp
325
+
326
+ raise result unless result == "OK"
327
+
328
+ end
329
+ end
330
+
331
+ def run_cmd(cmd_str, opts = {})
332
+ IO.popen(cmd_str) { |f|0
333
+ until f.eof?
334
+ str = f.gets
335
+ puts(str) if $debug_mode
336
+ end
337
+ }
338
+
339
+ if opts[:fail_msg] && $?.exitstatus.to_i != 0
340
+ raise(opts[:fail_msg])
341
+ end
342
+ end
343
+
344
+ def progress(msg)
345
+ print "%-59s" % [msg + ":"]
346
+ yield
347
+ puts "[#{" OK ".green}]"
348
+ rescue
349
+ puts "[#{"FAILED".red}]"
350
+ exit(1)
351
+ end
352
+
353
+ class String
354
+ # colorization
355
+ def colorize(color_code)
356
+ "\e[#{color_code}m#{self}\e[0m"
357
+ end
358
+
359
+ def red
360
+ colorize(31)
361
+ end
362
+
363
+ def green
364
+ colorize(32)
365
+ end
366
+ end
367
+
368
+
369
+
370
+
data/ci.rb ADDED
@@ -0,0 +1,244 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'fileutils'
5
+ require 'warbler'
6
+
7
+ class CiBuild
8
+ attr_accessor :app_name, :workspace_path, :jenkins_home, :run_specs_flag, :compile_assets_flag, :build_number
9
+
10
+ def initialize(args={})
11
+ @app_name = args.fetch(:app_name)
12
+ @workspace_path = args.fetch(:workspace_path)
13
+ @jenkins_home = args.fetch(:jenkins_home)
14
+
15
+ @run_specs_flag = args.fetch(:run_specs_flag, true)
16
+ @compile_assets_flag = args.fetch(:compile_assets_flag, true)
17
+
18
+ @build_number = args.fetch(:build_number, nil)
19
+ end
20
+
21
+ def run
22
+ Dir.chdir(workspace_path) do
23
+ clean_workspace
24
+ run_bundle_install
25
+ setup_dot_yml_files
26
+
27
+ if run_specs_flag
28
+ setup_db
29
+ run_rspec_suite
30
+ end
31
+
32
+ compile_assets if compile_assets_flag
33
+
34
+ record_build_number
35
+ archive_war_file
36
+ end
37
+ end
38
+
39
+
40
+ private
41
+
42
+ def clean_workspace
43
+ FileUtils.rm_rf("#{workspace_path}/.rvmrc") if File.exists?("#{workspace_path}/.rvmrc")
44
+ end
45
+
46
+ def job_name
47
+ workspace_path =~ /jobs\/(.+)\/workspace$/
48
+ $1
49
+ end
50
+
51
+ def war_archive_url
52
+ "#{war_archive_root}/#{app_name}/"
53
+ end
54
+
55
+ def war_archive_root
56
+ "svn+ssh://svn@code.berkeley.edu/eas-rails/wars"
57
+ end
58
+
59
+ def war_name
60
+ if git_repo?
61
+ git_war_name
62
+ elsif svn_repo?
63
+ svn_war_name
64
+ else
65
+ raise "Unrecognized SCM"
66
+ end
67
+ end
68
+
69
+ def git_repo?
70
+ Dir["#{workspace_path}/.*"].any? { |f| File.basename(f) == ".git" }
71
+ end
72
+
73
+ def svn_repo?
74
+ Dir["#{workspace_path}/.*"].any? { |f| File.basename(f) == ".svn" }
75
+ end
76
+
77
+ def svn_war_name
78
+ ENV['SVN_URL'].split("/").pop
79
+ end
80
+
81
+ def git_war_name
82
+ branch = ENV['GIT_BRANCH']
83
+ (branch == "master") ? "trunk" : branch
84
+ end
85
+
86
+ def default_env_vars
87
+ ["WEBKIT=false", "QMAKE=/usr/bin/qmake-qt47"]
88
+ end
89
+
90
+ def run_cmd(cmd, env_vars = [])
91
+ # TODO: Enable after qt47 is installed
92
+ # env = (default_env_vars + env_vars).join(" ")
93
+
94
+ env = env_vars.join(" ")
95
+ full_cmd = "#{env} #{cmd}"
96
+ $stdout.puts("#{full_cmd} ... ")
97
+
98
+ output = `#{full_cmd} 2>&1`
99
+ $stdout.puts(output)
100
+
101
+ if $?.success?
102
+ $stdout.puts("[OK]")
103
+ else
104
+ $stdout.puts("[FAILED]")
105
+ $stdout.puts($?.exitstatus)
106
+ exit($?.exitstatus)
107
+ end
108
+
109
+ output
110
+ end
111
+
112
+ def run_bundle_install
113
+ run_cmd("bundle install")
114
+ end
115
+
116
+ def setup_dot_yml_files
117
+ create_db_yml
118
+ Dir.glob("config/*.yml.example").each do |file_path|
119
+ file_name = File.basename(file_path).split(".")[0..1].join(".")
120
+ next if file_name == "database.yml"
121
+ dir_name = File.dirname(file_path)
122
+ FileUtils.cp(file_path, File.join(dir_name, file_name))
123
+ end
124
+ end
125
+
126
+ def setup_db
127
+ run_cmd("bundle exec rake db:migrate", ["RAILS_ENV=test"])
128
+ end
129
+
130
+ def create_db_yml
131
+ db_yml_contents = <<-DB
132
+ test: &test
133
+ adapter: sqlite3
134
+ database: #{app_name}
135
+ username: jenkins
136
+ password: jenkins
137
+ host: localhost
138
+
139
+ legacy_test: &legacy_test
140
+ adapter: sqlite3
141
+ database: db/legacy_test.sqlite3
142
+
143
+ ci:
144
+ <<: *test
145
+
146
+ legacy_ci:
147
+ <<: *legacy_test
148
+
149
+ DB
150
+ File.open("config/database.yml", "w") do |f|
151
+ f.write(db_yml_contents)
152
+ end
153
+ end
154
+
155
+ def run_rspec_suite
156
+ run_cmd("bundle exec rspec spec --tag ~js --format RspecJunitFormatter --out results.xml", ["RAILS_ENV=test"])
157
+ end
158
+
159
+ def compile_assets
160
+ cache_compiled_assets
161
+ run_cmd("bundle exec rake assets:precompile", ["RAILS_ENV=ci"])
162
+ end
163
+
164
+ def cache_compiled_assets
165
+ link = "#{jenkins_home}/.jenkins/jobs/#{job_name}/workspace/tmp"
166
+ target = "#{jenkins_home}/tmp/#{job_name}"
167
+
168
+ FileUtils.mkdir(target) unless File.exists?(target)
169
+ FileUtils.rm_rf(link) if File.exists?(link)
170
+ File.symlink(target, link) unless File.symlink?(link)
171
+ end
172
+
173
+ def record_build_number
174
+ if build_number
175
+ path = File.join(workspace_path, 'BUILD')
176
+ File.open(path, "w") do |f|
177
+ puts "Storing build number #{build_number} into #{path}"
178
+ f.write(build_number)
179
+ end
180
+ end
181
+ end
182
+
183
+ def archive_war_file
184
+ create_war
185
+ remove_war if war_checked_in?
186
+ commit_war
187
+ end
188
+
189
+ def create_war
190
+ RakeFileUtils.verbose_flag = true
191
+ Warbler::Task.new('trunk')
192
+
193
+ $stdout.print("Building war file: ")
194
+ Rake::Task['trunk'].invoke()
195
+
196
+ FileUtils.mv("workspace.war", "#{war_name}.war")
197
+ end
198
+
199
+ def war_checked_in?
200
+ wars = run_cmd("svn list #{war_archive_url}").split("\n")
201
+ wars.include?("#{war_name}.war")
202
+ end
203
+
204
+ def remove_war
205
+ run_cmd("svn rm #{war_archive_url}/#{war_name}.war -m 'removing war #{war_name}.war' &")
206
+ run_cmd("sleep 2s")
207
+ end
208
+
209
+ def commit_war
210
+ run_cmd("svn import #{war_name}.war #{war_archive_url}/#{war_name}.war -m 'committing war #{war_name}.war'")
211
+ end
212
+ end
213
+
214
+
215
+ if __FILE__ == $PROGRAM_NAME
216
+ def extract_optional_args(optional_args)
217
+ optional_args.inject({}) do |hash, arg|
218
+ key, val = arg.split("=")
219
+ if val == "false"
220
+ val = false
221
+ elsif val.nil?
222
+ val = true
223
+ else
224
+ val = val
225
+ end
226
+
227
+ key = key[2..-1].gsub("-", "_").to_sym
228
+ hash[key] = val
229
+ hash
230
+ end
231
+ end
232
+
233
+ args = {
234
+ :app_name => ARGV[0],
235
+ :workspace_path => ENV['WORKSPACE'],
236
+ :jenkins_home => ENV['HOME'],
237
+ }
238
+
239
+ optional_args = extract_optional_args(ARGV[1..-1])
240
+
241
+
242
+ p args.merge(optional_args)
243
+ CiBuild.new(args.merge(optional_args)).run
244
+ end
@@ -0,0 +1,3 @@
1
+ module UcbRailsCi
2
+ require 'ucb_rails_ci/railtie' if defined?(Rails)
3
+ end
@@ -0,0 +1,11 @@
1
+ require 'ucb_rails_ci'
2
+ require 'rails'
3
+ module UcbRailsCi
4
+ class Railtie < Rails::Railtie
5
+ railtie_name :ucb_rails_ci
6
+
7
+ rake_tasks do
8
+ load File.join(File.dirname(__FILE__), '..', '..', 'tasks', 'ucb_rails_ci.rake')
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,161 @@
1
+
2
+ require 'warbler'
3
+
4
+ namespace :ci do
5
+
6
+ desc "Run CI setup tasks"
7
+ task :setup => %w[ config:copy_defaults ]
8
+
9
+ desc "Run Rspec for CI"
10
+ task :spec => %w[ setup spec ]
11
+
12
+ task :war => %w[ war:archive ]
13
+
14
+ namespace :war do
15
+
16
+ task :archive do
17
+ if war_branch?
18
+ Rake::Task['ci:war:prepare'].invoke
19
+ Rake::Task['ci:war:create'].invoke
20
+ else
21
+ puts "Not creating a war because this is a personal branch (has a / in it)"
22
+ exit 1
23
+ end
24
+ end
25
+
26
+ task :create do
27
+ create_war
28
+ end
29
+
30
+ task :prepare => %w[ assets:precompile ] do
31
+ record_build_number
32
+ end
33
+ end
34
+
35
+ def record_build_number
36
+ if build_number = ENV['TRAVIS_BUILD_NUMBER']
37
+ path = File.join(workspace_path, 'BUILD')
38
+ File.open(path, "w") do |f|
39
+ puts "Storing build number #{build_number} into #{path}"
40
+ f.write(build_number)
41
+ end
42
+ end
43
+ end
44
+
45
+ def create_war
46
+ RakeFileUtils.verbose_flag = true
47
+ Warbler::Task.new(branch)
48
+
49
+ $stdout.print("Building war file: ")
50
+ Rake::Task[branch].invoke()
51
+ end
52
+
53
+ def branch
54
+ branch = ENV['TRAVIS_BRANCH']
55
+
56
+ unless branch
57
+ branch = `git rev-parse --abbrev-ref HEAD`.strip
58
+ end
59
+
60
+ branch = 'trunk' if branch == 'master'
61
+ branch
62
+ end
63
+
64
+ def war_name
65
+ branch
66
+ end
67
+
68
+ def war_branch?
69
+ !branch.include?('/')
70
+ end
71
+
72
+ def workspace_path
73
+ ENV['TRAVIS_BUILD_DIR'] || '.'
74
+ end
75
+
76
+ def app_name
77
+ if ENV['TRAVIS_REPO_SLUG']
78
+ ENV['TRAVIS_REPO_SLUG'].split('/').last
79
+ else
80
+ url = `git config --get remote.origin.url`
81
+ if url =~ /ucb-ist-eas\/(.*)\.git/
82
+ $1
83
+ else
84
+ raise "cannot determine branch"
85
+ end
86
+ end
87
+ end
88
+
89
+ def run_cmd(cmd, env_vars = [])
90
+ # TODO: Enable after qt47 is installed
91
+ # env = (default_env_vars + env_vars).join(" ")
92
+
93
+ env = env_vars.join(" ")
94
+ full_cmd = "#{env} #{cmd}"
95
+ $stdout.puts("#{full_cmd} ... ")
96
+
97
+ output = `#{full_cmd} 2>&1`
98
+ $stdout.puts(output)
99
+
100
+ if $?.success?
101
+ $stdout.puts("[OK]")
102
+ else
103
+ $stdout.puts("[FAILED]")
104
+ $stdout.puts($?.exitstatus)
105
+ exit($?.exitstatus)
106
+ end
107
+
108
+ output
109
+ end
110
+
111
+ end
112
+
113
+ namespace :config do
114
+
115
+ desc "copy .example files into their real locations"
116
+ task :copy_defaults do
117
+ Dir.glob("config/*.yml.example").each do |file_path|
118
+ file_name = File.basename(file_path).split(".")[0..1].join(".")
119
+ dir_name = File.dirname(file_path)
120
+ FileUtils.cp(file_path, File.join(dir_name, file_name))
121
+ end
122
+ end
123
+
124
+ desc "Generate .travis.yml file for use with Travis-CI"
125
+ task :generate_travis_yml do
126
+
127
+ require 'erb'
128
+
129
+ `travis help`
130
+ if $? == 1
131
+ puts "This command requires the travis CLI. Install it with 'gem install travis'"
132
+ exit 1
133
+ end
134
+
135
+ filename = File.join(File.dirname(__FILE__), "..", "templates", "travis.yml.erb")
136
+ input = File.read(filename)
137
+ erb = ERB.new(input)
138
+
139
+ print "App Name: "
140
+ app_name = $stdin.gets.strip
141
+
142
+ print "Github API Key: "
143
+ api_key = $stdin.gets.strip
144
+
145
+ print "Slack Integration Key (optional): "
146
+ slack_key = $stdin.gets.strip
147
+ slack_key = nil if slack_key == ''
148
+
149
+ text = erb.result(binding)
150
+ File.write(Rails.root.join('.travis.yml'), text)
151
+
152
+ `travis encrypt --add deploy.api-key #{api_key}`
153
+
154
+ if slack_key
155
+ `travis encrypt --add notifications.slack #{slack_key}`
156
+ end
157
+
158
+ `travis lint`
159
+
160
+ end
161
+ end
@@ -0,0 +1,36 @@
1
+ branches:
2
+ except:
3
+ - /^.*-\d+$/ # exclude build tags
4
+ - /^.*\/.*+$/ # exclude private branches (with slash)
5
+ language: ruby
6
+ env: SQLITE=true
7
+ rvm:
8
+ - jruby-19mode
9
+ install: bundle install --full-index --without='development production' --path vendor/bundle --jobs=3 --retry=3
10
+ script:
11
+ - bundle exec rake ci:setup
12
+ - bundle exec rake db:migrate
13
+ - bundle exec rake db:test:prepare
14
+ - mkdir -p tmp/cache
15
+ - xvfb-run bundle exec rspec
16
+ cache:
17
+ directories:
18
+ - vendor/bundle
19
+ before_deploy:
20
+ - bundle exec rake ci:war RAILS_ENV=ci
21
+ - git tag $TRAVIS_BRANCH-$TRAVIS_BUILD_NUMBER # remove this if you want to tag manually
22
+ deploy:
23
+ provider: releases
24
+ api-key:
25
+ file: <%= app_name %>.war
26
+ skip_cleanup: true
27
+ on:
28
+ #tags: true # enable if you want to only build via manual tags
29
+ all_branches: true
30
+ # addons:
31
+ # code_climate:
32
+ # repo_token: (insert repo token from code climate)
33
+ <% if slack_key %>
34
+ notifications:
35
+ slack:
36
+ <% end %>
@@ -0,0 +1,19 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'ucb_rails_ci'
3
+ s.version = '1.0.1'
4
+ s.summary = "CI and deployment integration for UCB Rails apps"
5
+ s.description = "Tools for enabling Rails apps to be built on Travis and deployed from GitHub"
6
+ s.authors = ["Ken Miller"]
7
+ s.email = 'ken@berkeley.edu'
8
+ s.date = Time.now.utc.strftime("%Y-%m-%d")
9
+ s.files = `git ls-files`.split("\n")
10
+ s.homepage = 'https://github.com/ucb-ist-eas/ucb_rails_ci'
11
+ s.bindir = 'bin'
12
+
13
+ s.add_runtime_dependency 'rake'
14
+ s.add_runtime_dependency 'bundler'
15
+ s.add_runtime_dependency 'builder'
16
+ s.add_runtime_dependency 'warbler'
17
+ s.add_runtime_dependency 'github_api'
18
+ s.add_runtime_dependency 'travis'
19
+ end
metadata ADDED
@@ -0,0 +1,137 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ucb_rails_ci
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ken Miller
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-01-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: builder
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: warbler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: github_api
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: travis
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Tools for enabling Rails apps to be built on Travis and deployed from
98
+ GitHub
99
+ email: ken@berkeley.edu
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - Gemfile
105
+ - Gemfile.lock
106
+ - README.md
107
+ - Rakefile
108
+ - ci.rb
109
+ - lib/ucb_rails_ci.rb
110
+ - lib/ucb_rails_ci/railtie.rb
111
+ - tasks/ucb_rails_ci.rake
112
+ - templates/travis.yml.erb
113
+ - ucb_rails_ci.gemspec
114
+ homepage: https://github.com/ucb-ist-eas/ucb_rails_ci
115
+ licenses: []
116
+ metadata: {}
117
+ post_install_message:
118
+ rdoc_options: []
119
+ require_paths:
120
+ - lib
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - '>='
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ requirements: []
132
+ rubyforge_project:
133
+ rubygems_version: 2.2.2
134
+ signing_key:
135
+ specification_version: 4
136
+ summary: CI and deployment integration for UCB Rails apps
137
+ test_files: []