octopusci 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/README.markdown +132 -0
  2. data/bin/octopusci-reset-redis +26 -0
  3. data/bin/octopusci-skel +2 -7
  4. data/bin/octopusci-tentacles +2 -2
  5. data/config.ru +1 -1
  6. data/lib/octopusci.rb +3 -7
  7. data/lib/octopusci/config.rb +63 -49
  8. data/lib/octopusci/errors.rb +2 -0
  9. data/lib/octopusci/helpers.rb +16 -15
  10. data/lib/octopusci/io.rb +70 -0
  11. data/lib/octopusci/job.rb +145 -34
  12. data/lib/octopusci/job_store.rb +67 -0
  13. data/lib/octopusci/notifier.rb +7 -17
  14. data/lib/octopusci/notifier/job_complete.html.erb +76 -3
  15. data/lib/octopusci/queue.rb +14 -10
  16. data/lib/octopusci/server.rb +17 -20
  17. data/lib/octopusci/server/views/index.erb +3 -4
  18. data/lib/octopusci/server/views/job.erb +3 -3
  19. data/lib/octopusci/server/views/job_summary.erb +18 -18
  20. data/lib/octopusci/server/views/layout.erb +6 -5
  21. data/lib/octopusci/stage_locker.rb +11 -7
  22. data/lib/octopusci/version.rb +1 -1
  23. data/lib/octopusci/worker_launcher.rb +1 -1
  24. data/spec/lib/octopusci/config_spec.rb +195 -0
  25. data/spec/lib/octopusci/io_spec.rb +64 -0
  26. data/spec/lib/octopusci/job_spec.rb +122 -0
  27. data/spec/lib/octopusci/job_store_spec.rb +155 -0
  28. data/spec/lib/octopusci/notifier_spec.rb +0 -15
  29. data/spec/lib/octopusci/queue_spec.rb +122 -0
  30. data/spec/lib/octopusci/server_spec.rb +92 -1
  31. data/spec/lib/octopusci/stage_locker_spec.rb +94 -0
  32. data/spec/spec_helper.rb +8 -0
  33. metadata +39 -58
  34. data/README +0 -63
  35. data/bin/octopusci-db-migrate +0 -10
  36. data/db/migrate/0001_init.rb +0 -29
  37. data/db/migrate/0002_add_status_job.rb +0 -19
  38. data/lib/octopusci/notifier/job_complete.text.erb +0 -5
  39. data/lib/octopusci/schema.rb +0 -140
@@ -1,16 +1,141 @@
1
1
  module Octopusci
2
2
  class Job
3
+ class << self
4
+ attr_accessor :context_stack
5
+
6
+ def inherited(subclass)
7
+ subclass.context_stack = []
8
+ end
9
+ end
10
+
3
11
  def self.run(job_rec)
4
- raise PureVirtualMethod, "The self.commit_run method needs to be defined on your Octopusci::Job."
12
+ raise Octopusci::PureVirtualMethod, "The self.run method needs to be defined on your Octopusci::Job based class."
13
+ end
14
+
15
+ def self.context(desc_str)
16
+ num_contexts_before = context_stack.length
17
+ context_lead_in = ' '*num_contexts_before
18
+ context_stack.push(desc_str)
19
+ num_contexts_now = context_stack.length
20
+ @output_lead_in = ' '*num_contexts_now
21
+ context_str = context_stack.join(' ')
22
+ output("\n\n#{desc_str}:\n\n")
23
+ begin
24
+ yield
25
+ Octopusci::Notifier.job_complete(@job, get_recip_email(), context_str, true).deliver
26
+ rescue Octopusci::JobRunFailed => e
27
+ write_exception(e)
28
+ Octopusci::Notifier.job_complete(@job, get_recip_email(), context_str, false).deliver
29
+ # setup notification and send notification
30
+ raise JobHalted.new("JobRunFailed:\n Context: #{context_str}\n Message: #{e.message}")
31
+ ensure
32
+ context_stack.pop
33
+ end
34
+ end
35
+
36
+ def self.run_shell_cmd(cmd_str, output_to_log=false)
37
+ horiz_line = "-"*30
38
+ @io.write_raw_output(output_to_log) do |out_f|
39
+ out_f << "\n\n#{@output_lead_in}Running: #{cmd_str}\n"
40
+ out_f << "#{@output_lead_in}#{horiz_line}"
41
+ out_f << "\n"
42
+ out_f.flush
43
+
44
+ in_f = ::IO.popen(cmd_str)
45
+ while(cur_line = in_f.gets) do
46
+ out_f << "#{@output_lead_in}#{cur_line}"
47
+ out_f.flush
48
+ end
49
+
50
+ in_f.close
51
+ end
52
+
53
+ return $?.exitstatus.to_i
54
+ end
55
+
56
+ def self.run_shell_cmd!(cmd_str, output_to_log=false)
57
+ r = self.run_shell_cmd(cmd_str, output_to_log)
58
+ if (r != 0)
59
+ raise Octopusci::JobRunFailed.new("#{cmd_str} exited with non-zero return value (#{r})")
60
+ else
61
+ return 0
62
+ end
63
+ end
64
+
65
+ def self.failed!(msg = "")
66
+ raise Octopusci::JobRunFailed.new(msg)
67
+ end
68
+
69
+ def self.output(msg)
70
+ @io.write_raw_output(false, "#{@output_lead_in}#{msg}")
71
+ end
72
+
73
+ def self.log(msg)
74
+ @io.write_raw_output(true) do |f|
75
+ f << "\n#{context_stack.join(' ')}:\n\t#{msg}"
76
+ end
77
+ end
78
+
79
+ def self.write_exception(e)
80
+ @io.write_raw_output do |f|
81
+ f << "\n\nException: #{e.message}\n"
82
+ f << "-"*30
83
+ f << "\n"
84
+ f << e.backtrace.join("\n")
85
+ end
86
+ end
87
+
88
+ def self.record_start(stage)
89
+ @job['started_at'] = Time.new
90
+ @job['stage'] = stage
91
+ @job['status'] = 'running'
92
+ Octopusci::JobStore.set(@job['id'], @job)
93
+ end
94
+
95
+ def self.workspace_path
96
+ return "#{Octopusci::Config['general']['workspace_base_path']}/#{@job['stage']}"
97
+ end
98
+
99
+ def self.repository_path
100
+ return "#{workspace_path}/#{@job['repo_name']}"
101
+ end
102
+
103
+ def self.clone_code(job_conf)
104
+ if File.directory?(repository_path)
105
+ return 0
106
+ else
107
+ if !Dir.exists?(workspace_path)
108
+ FileUtils.mkdir_p(workspace_path)
109
+ end
110
+ return run_shell_cmd("cd #{workspace_path} 2>&1 && git clone #{job_conf['repo_uri']} #{@job['repo_name']} 2>&1", true)
111
+ end
112
+ end
113
+
114
+ def self.checkout_branch(job_conf)
115
+ return run_shell_cmd("cd #{repository_path} 2>&1 && git fetch --all -p 2>&1 && git checkout #{@job['branch_name']} 2>&1 && git pull -f origin #{@job['branch_name']}:#{@job['branch_name']} 2>&1", true)
116
+ end
117
+
118
+ def self.get_recip_email
119
+ recip_email = nil
120
+ if @job['branch_name'] == 'master'
121
+ recip_email = @job_conf['default_email']
122
+ else
123
+ if @job['payload']['pusher']['email']
124
+ recip_email = @job['payload']['pusher']['email']
125
+ else
126
+ recip_email = @job_conf['default_email']
127
+ end
128
+ end
5
129
  end
6
-
130
+
7
131
  def self.perform(project_name, branch_name, job_id, job_conf)
8
- ActiveRecord::Base.verify_active_connections!
132
+ context_stack = []
133
+ @job_conf = job_conf
9
134
 
10
135
  # Note: There is no logic for handling stage coming back as nil because
11
136
  # it should never happen because there are the same number of resque
12
137
  # workers as there are stages at all times.
13
- if Octopusci::CONFIG.has_key?('stages')
138
+ if Octopusci::Config.has_key?('stages')
14
139
  # Get the next available stage from redis which locks it by removing it
15
140
  # from the list of available
16
141
  stage = Octopusci::StageLocker.pop
@@ -20,44 +145,30 @@ module Octopusci
20
145
  # Using redis to get the associated github_payload
21
146
  github_payload = Octopusci::Queue.github_payload(project_name, branch_name)
22
147
 
23
- job = ::Job.where("jobs.repo_name = ? && jobs.ref = ?", github_payload['repository']['name'], github_payload['ref']).order('jobs.created_at DESC').first
24
- if job
25
- job.started_at = Time.new
26
- job.stage = stage
27
- job.status = 'running'
28
- job.save
148
+ @job = Octopusci::JobStore.list_repo_branch(github_payload['repository']['name'], github_payload['ref'].split('/').last, 0, 1).first
149
+ if @job
150
+ @io = Octopusci::IO.new(@job)
151
+ record_start(stage)
29
152
 
30
153
  begin
31
- job.clone_code(job_conf)
32
- job.checkout_branch(job_conf)
154
+ clone_code(job_conf)
155
+ checkout_branch(job_conf)
33
156
 
34
- rv = self.run(job)
35
- if ::Job::STATUS.keys.include?(rv)
36
- job.status = 0
37
- else
38
- if rv == 0
39
- job.status = 'successful'
40
- else
41
- job.status = 'failed'
42
- end
43
- end
157
+ self.run(@job)
158
+
159
+ @job['status'] = 'successful'
160
+ rescue JobHalted => e
161
+ @job['status'] = 'failed'
44
162
  rescue => e
45
- File.open(job.abs_output_file_path, 'a') { |f|
46
- f << "\n\nException: #{e.message}\n"
47
- f << "-"*30
48
- f << "\n"
49
- f << e.backtrace.join("\n")
50
- }
51
- job.status = 'error'
163
+ write_exception(e)
164
+ @job['status'] = 'error'
52
165
  ensure
53
- job.ended_at = Time.new
54
- job.save
55
-
56
- Octopusci::Notifier.job_complete(job, job_conf, job.successful?)
166
+ @job['ended_at'] = Time.new
167
+ Octopusci::JobStore.set(@job['id'], @job)
57
168
  end
58
169
  end
59
170
  ensure
60
- if Octopusci::CONFIG.has_key?('stages')
171
+ if Octopusci::Config.has_key?('stages')
61
172
  # Unlock the stage by adding it back to the list of available stages
62
173
  Octopusci::StageLocker.push(stage)
63
174
  end
@@ -0,0 +1,67 @@
1
+ module Octopusci
2
+ class JobStore
3
+ def self.prepend(job)
4
+ job_id = redis.incr('octopusci:job_count')
5
+ self.set(job_id, job.merge({ 'id' => job_id }))
6
+ redis.lpush("octopusci:jobs", job_id)
7
+ redis.lpush("octopusci:#{job['repo_name']}:#{job['ref'].split('/').last}:jobs", job_id)
8
+ return job_id
9
+ end
10
+
11
+ def self.set(job_id, job)
12
+ redis.set("octopusci:jobs:#{job_id}", YAML.dump(job))
13
+ end
14
+
15
+ def self.get(job_id)
16
+ job = redis.get("octopusci:jobs:#{job_id}")
17
+ if job
18
+ return YAML.load(job)
19
+ end
20
+ return nil
21
+ end
22
+
23
+ def self.size
24
+ redis.llen("octopusci:jobs")
25
+ end
26
+
27
+ def self.repo_branch_size(repo_name, branch_name)
28
+ redis.llen("octopusci:#{repo_name}:#{branch_name}:jobs")
29
+ end
30
+
31
+ def self.list_job_ids(start_idx, num_jobs)
32
+ len = size()
33
+ end_idx = len - 1
34
+
35
+ range_idx = start_idx + num_jobs
36
+ if (end_idx - start_idx < num_jobs)
37
+ range_idx = end_idx
38
+ end
39
+ redis.lrange("octopusci:jobs", 0, range_idx)
40
+ end
41
+
42
+ def self.list_repo_branch_job_ids(repo_name, branch_name, start_idx, num_jobs)
43
+ len = repo_branch_size(repo_name, branch_name)
44
+ end_idx = len - 1
45
+
46
+ range_idx = start_idx + num_jobs
47
+ if (end_idx - start_idx < num_jobs)
48
+ range_idx = end_idx
49
+ end
50
+ redis.lrange("octopusci:#{repo_name}:#{branch_name}:jobs", 0, range_idx)
51
+ end
52
+
53
+ def self.list(start_idx, num_jobs)
54
+ job_ids = list_job_ids(start_idx, num_jobs)
55
+ job_ids.map { |id| self.get(id) }
56
+ end
57
+
58
+ def self.list_repo_branch(repo_name, branch_name, start_idx, num_jobs)
59
+ job_ids = list_repo_branch_job_ids(repo_name, branch_name, start_idx, num_jobs)
60
+ job_ids.map { |id| self.get(id) }
61
+ end
62
+
63
+ def self.redis
64
+ Resque.redis
65
+ end
66
+ end
67
+ end
@@ -6,28 +6,18 @@ require 'action_mailer'
6
6
  ActionMailer::Base.view_paths = File.dirname(__FILE__) + '/../'
7
7
 
8
8
  module Octopusci
9
- class Notifier < ActionMailer::Base
10
- def job_complete(job_rec, job_conf, success=false)
11
- @job = job_rec
9
+ class Notifier < ActionMailer::Base
10
+ def job_complete(job, recip_email, context_str, success=false)
11
+ @job = job
12
+ @success = success
13
+ @context_str = context_str
12
14
  if success
13
15
  @status_str = 'success'
14
16
  else
15
17
  @status_str = 'failed'
16
18
  end
17
-
18
- recip_email = nil
19
- if job_rec.branch_name == 'master'
20
- recip_email = job_conf['default_email']
21
- else
22
- if job_rec.payload['pusher']['email']
23
- recip_email = job_rec.payload['pusher']['email']
24
- else
25
- recip_email = job_conf['default_email']
26
- end
27
- end
28
-
29
- mail(:to => recip_email, :subject => "Octopusci Build (#{@status_str}) - #{@job.repo_name} / #{@job.branch_name}") do |format|
30
- format.text
19
+
20
+ mail(:to => recip_email, :subject => "Octopusci Build (#{@status_str}) - #{context_str} - #{@job['repo_name']} / #{@job['branch_name']}") do |format|
31
21
  format.html
32
22
  end
33
23
  end
@@ -1,11 +1,84 @@
1
+ <% j = @job %>
1
2
  <!DOCTYPE html>
2
3
  <html>
3
4
  <head>
4
5
  <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
5
6
  </head>
6
7
  <body>
7
- <h1>Octopusci Build (<%= @status_str %>) - <%= @job.repo_name %> / <%= @job.branch_name %></h1>
8
- <h2>Output:</h2>
9
- <pre><code><%= @job.output %></code></pre>
8
+ <div style="background-color: #333; color: #fff; width: 100%;">
9
+ <div style="padding: 10px; font-size: 16px;">Octopusci Build (<%= @status_str %>) - <a style="color: #fff" href="<%= @job['payload']['repository']['url'] %>"><%= @job['repo_name'] %></a> / <a style="color: #fff" href="<%= Octopusci::Config['general']['base_url'] %>/<%= @job['repo_name'] %>/<%= @job['branch_name'] %>"><%= @job['branch_name'] %></a></div>
10
+ <div style="background-color: #e2e2e2; padding: 20px;">
11
+ <div style="background-color: #ffffff; color: #333;">
12
+ <div style="background-color: #F9F9F9; padding: 10px; border: 1px dotted #E6E6E6;">
13
+ <div style="padding: 10px; color: #7A7A7A;">
14
+ <table style="color: #7A7A7A;">
15
+ <tr>
16
+ <td style="text-align: right;">Status:</td>
17
+ <td style="width: 200px;"><span style="<% if @success %>color: #78be3f;<% else %>color: red;<% end %>"><%= @status_str %></span></td>
18
+ </tr>
19
+ <tr>
20
+ <td style="text-align: right;">Job:</td>
21
+ <td style="width: 200px;"><a style="color: #333;" href="<%= Octopusci::Config['general']['base_url'] %>/jobs/<%= j['id'] %>"><%= j['id'] %></a></td>
22
+ <td style="text-align: right;">Before Commit:</td>
23
+ <td>
24
+ <% if !j['payload']['created'] %>
25
+ <%= j['payload']['before'] %>
26
+ <% else %>
27
+ No before commit, remote branch was created with this push.
28
+ <% end %>
29
+ </td>
30
+ </tr>
31
+ <tr>
32
+ <td style="text-align: right;">Finished:</td>
33
+ <td>
34
+ <% if j['ended_at'] %>
35
+ <%= j['ended_at'].ago_in_words %>
36
+ <% else %>
37
+ -
38
+ <% end %>
39
+ </td>
40
+ <td style="text-align: right;">After Commit:</td>
41
+ <td>
42
+ <%= j['payload']['after'] %>
43
+ </td>
44
+ </tr>
45
+ <tr>
46
+ <td style="text-align: right;">Duration:</td>
47
+ <td>
48
+ <% if j['ended_at'] && j['started_at'] %>
49
+ <%= ((j['ended_at'] - j['started_at'])/60).to_i %> minutes
50
+ <% else %>
51
+ -
52
+ <% end %>
53
+ </td>
54
+ <td style="text-align: right;">Compare:</td>
55
+ <td><a style="color: #333;" href="<%= j['compare'] %>"><%= j['compare'] %></a></td>
56
+ </tr>
57
+ <tr>
58
+ <td style="text-align: right;">Stage:</td>
59
+ <td><%= j['stage'] %></td>
60
+ <td style="text-align: right;">Pusher:</td>
61
+ <td>
62
+ <% if j['payload']['pusher']['email'] %>
63
+ <a style="color: #333;" href="mailto:<%= j['payload']['pusher']['name'] %>"><%= j['payload']['pusher']['name'] %></a>
64
+ <% else %>
65
+ <%= j['payload']['pusher']['name'] %>
66
+ <% end %>
67
+ </td>
68
+ </tr>
69
+ <tr>
70
+ <td style="text-align: right;">Output:</td>
71
+ <td></td>
72
+ <td style="text-align: right;">Context:</td>
73
+ <td><%= @context_str %></td>
74
+ </tr>
75
+ </table>
76
+ </div>
77
+ <div style="background-color: #333; color: #fff; padding: 10px;">
78
+ <pre><code><%= Octopusci::IO.new(@job).read_all_out %></code></pre>
79
+ </div>
80
+ </div>
81
+ </div>
82
+ </div>
10
83
  </body>
11
84
  </html>
@@ -7,18 +7,18 @@ module Octopusci
7
7
  gh_pl_key = github_payload_key(proj_name, branch_name)
8
8
 
9
9
  if lismember('octopusci:commit', resque_opts)
10
- Resque.redis.set(gh_pl_key, Resque::encode(github_payload))
11
- # Get the most recent job for this project and update it with the data
12
- job = ::Job.where("jobs.repo_name = ? && jobs.ref = ?", proj_name, '/refs/heads/' + branch_name).order('jobs.created_at DESC').first
10
+ self.redis.set(gh_pl_key, Resque::encode(github_payload))
11
+
12
+ job = Octopusci::JobStore.list_repo_branch(proj_name, branch_name, 0, 1).first
13
13
  if job
14
- job.update_attributes(Octopusci::Helpers.gh_payload_to_job_attrs(github_payload))
15
- end
14
+ Octopusci::JobStore.set(job['id'], job.merge(Octopusci::Helpers.gh_payload_to_job_attrs(github_payload)))
15
+ end
16
16
  else
17
17
  # Create a new job for this project with the appropriate data
18
- job = ::Job.create(Octopusci::Helpers.gh_payload_to_job_attrs(github_payload).merge(:status => 'pending'))
19
- resque_opts["args"] << job.id
18
+ job_id = Octopusci::JobStore.prepend(Octopusci::Helpers.gh_payload_to_job_attrs(github_payload).merge('status' => 'pending'))
19
+ resque_opts["args"] << job_id
20
20
  resque_opts["args"] << job_conf
21
- Resque.redis.set(gh_pl_key, Resque::encode(github_payload))
21
+ self.redis.set(gh_pl_key, Resque::encode(github_payload))
22
22
  Resque.push('octopusci:commit', resque_opts)
23
23
  end
24
24
  end
@@ -31,11 +31,15 @@ module Octopusci
31
31
  end
32
32
 
33
33
  def self.github_payload(project_name, branch_name)
34
- Resque::decode(Resque.redis.get(github_payload_key(project_name, branch_name)))
34
+ Resque::decode(self.redis.get(github_payload_key(project_name, branch_name)))
35
35
  end
36
36
 
37
37
  def self.github_payload_key(proj_name, branch_name)
38
- "octpusci:github_payload:#{proj_name}:#{branch_name}"
38
+ "octopusci:github_payload:#{proj_name}:#{branch_name}"
39
+ end
40
+
41
+ def self.redis
42
+ Resque.redis
39
43
  end
40
44
  end
41
45
  end
@@ -8,13 +8,9 @@ module Octopusci
8
8
  dir = File.dirname(File.expand_path(__FILE__))
9
9
 
10
10
  set :views, "#{dir}/server/views"
11
- set :public, "#{dir}/server/public"
11
+ set :public_folder, "#{dir}/server/public"
12
12
  set :static, true
13
13
 
14
- before do
15
- ActiveRecord::Base.verify_active_connections!
16
- end
17
-
18
14
  helpers do
19
15
  def protected!
20
16
  unless authorized?
@@ -25,53 +21,53 @@ module Octopusci
25
21
 
26
22
  def authorized?
27
23
  @auth ||= Rack::Auth::Basic::Request.new(request.env)
28
- @auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == [ Octopusci::CONFIG['http_basic']['username'], Octopusci::CONFIG['http_basic']['password'] ]
24
+ @auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == [ Octopusci::Config['http_basic']['username'], Octopusci::Config['http_basic']['password'] ]
29
25
  end
30
26
  end
31
27
 
32
28
  get '/' do
33
29
  protected!
34
- @jobs = ::Job.order('jobs.created_at DESC').limit(20)
30
+ @jobs = Octopusci::JobStore.list(0, 20)
35
31
  erb :index
36
32
  end
37
-
33
+
38
34
  get '/:repo_name/:branch_name/jobs' do
39
35
  protected!
40
36
  @page_logo = "#{params[:repo_name]} / #{params[:branch_name]}"
41
- @jobs = ::Job.where(:repo_name => params[:repo_name], :ref => "refs/heads/#{params[:branch_name]}").order('jobs.created_at DESC').limit(20)
37
+ @jobs = Octopusci::JobStore.list_repo_branch(params[:repo_name], params[:branch_name], 0, 20)
42
38
  erb :index
43
39
  end
44
40
 
45
41
  get '/jobs/:job_id' do
46
42
  protected!
47
- @job = ::Job.find(params[:job_id])
43
+ @job = Octopusci::JobStore.get(params[:job_id])
48
44
  erb :job
49
45
  end
50
46
 
51
47
  get '/jobs/:job_id/output' do
52
48
  protected!
53
- @job = ::Job.find(params[:job_id])
49
+ @job = Octopusci::JobStore.get(params[:job_id])
54
50
  content_type('text/plain')
55
- return @job.output
51
+ return Octopusci::IO.new(@job).read_all_out
56
52
  end
57
53
 
58
54
  get '/jobs/:job_id/silent_output' do
59
55
  protected!
60
- @job = ::Job.find(params[:job_id])
56
+ @job = Octopusci::JobStore.get(params[:job_id])
61
57
  content_type('text/plain')
62
- return @job.silent_output
58
+ return Octopusci::IO.new(@job).read_all_log
63
59
  end
64
60
 
65
61
  get '/jobs/:job_id/status' do
66
62
  protected!
67
- @job = ::Job.find(params[:job_id])
63
+ @job = Octopusci::JobStore.get(params[:job_id])
68
64
  content_type('text/plain')
69
- return @job.status
65
+ return @job['status']
70
66
  end
71
67
 
72
68
  get '/jobs/:job_id/ajax_summary' do
73
69
  protected!
74
- @job = ::Job.find(params[:job_id])
70
+ @job = Octopusci::JobStore.get(params[:job_id])
75
71
  erb :job_summary, :layout => false, :locals => { :j => @job }
76
72
  end
77
73
 
@@ -80,22 +76,23 @@ module Octopusci
80
76
  raise "No payload paramater found, it is a required parameter."
81
77
  end
82
78
  github_payload = Octopusci::Helpers.decode(params["payload"])
83
-
79
+
84
80
  # Make sure that the request is for a project Octopusci knows about
85
81
  proj_info = Octopusci::Helpers.get_project_info(github_payload["repository"]["name"], github_payload["repository"]["owner"]["name"])
86
82
  if proj_info.nil?
87
83
  return 404
88
84
  end
89
-
85
+
90
86
  if (github_payload["ref"] =~ /refs\/heads\//) && (github_payload["deleted"] != true)
91
87
  branch_name = github_payload["ref"].gsub(/refs\/heads\//, '')
92
88
 
93
89
  # Queue the job appropriately
94
90
  Octopusci::Queue.enqueue(proj_info['job_klass'], github_payload["repository"]["name"], branch_name, github_payload, proj_info)
91
+ return 200
95
92
  else
96
93
  return 200
97
94
  end
98
95
  end
99
-
96
+
100
97
  end
101
98
  end