Commit 5d56e80523035f6895d568ff4a737d588fbf14ce

Authored by Jared Pace
1 parent 2cecdbaa
Exists in master and in 1 other branch production

Add endpoint for deploys and deliver notifications on deploy

app/controllers/deploys_controller.rb 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +class DeploysController < ApplicationController
  2 +
  3 + def create
  4 + @project = Project.find_by_api_key!(params[:api_key])
  5 + @deploy = @project.deploys.create!({
  6 + :username => params[:deploy][:local_username],
  7 + :environment => params[:deploy][:rails_env],
  8 + :repository => params[:deploy][:scm_repository],
  9 + :revision => params[:deploy][:scm_revision]
  10 + })
  11 + render :xml => @deploy
  12 + end
  13 +
  14 +end
0 15 \ No newline at end of file
... ...
app/mailers/mailer.rb
... ... @@ -7,8 +7,18 @@ class Mailer &lt; ActionMailer::Base
7 7 @project = notice.err.project
8 8  
9 9 mail({
10   - :to => @project.watchers.map(&:email),
11   - :subject => "[#{@project.name}] #{@notice.err.message}"
  10 + :to => @project.watchers.map(&:email),
  11 + :subject => "[#{@project.name}] #{@notice.err.message}"
  12 + })
  13 + end
  14 +
  15 + def deploy_notification(deploy)
  16 + @deploy = deploy
  17 + @project = deploy.project
  18 +
  19 + mail({
  20 + :to => @project.watchers.map(&:email),
  21 + :subject => "[#{@project.name}] Deployed to #{@deploy.environment} by #{@deploy.username}"
12 22 })
13 23 end
14 24  
... ...
app/models/deploy.rb
... ... @@ -9,6 +9,18 @@ class Deploy
9 9  
10 10 embedded_in :project, :inverse_of => :deploys
11 11  
  12 + after_create :deliver_notification, :if => :should_notify?
  13 +
12 14 validates_presence_of :username, :environment
13 15  
  16 + def deliver_notification
  17 + Mailer.deploy_notification(self).deliver
  18 + end
  19 +
  20 + protected
  21 +
  22 + def should_notify?
  23 + project.watchers.any?
  24 + end
  25 +
14 26 end
... ...
app/models/err.rb
... ... @@ -19,7 +19,7 @@ class Err
19 19  
20 20 def self.for(attrs)
21 21 project = attrs.delete(:project)
22   - project.errs.unresolved.where(attrs).first || project.errs.create(attrs)
  22 + project.errs.unresolved.where(attrs).first || project.errs.create!(attrs)
23 23 end
24 24  
25 25 def resolve!
... ...
app/models/notice.rb
... ... @@ -28,7 +28,7 @@ class Notice
28 28 :environment => hoptoad_notice['server-environment']['environment-name']
29 29 })
30 30  
31   - error.notices.create({
  31 + error.notices.create!({
32 32 :backtrace => hoptoad_notice['error']['backtrace']['line'],
33 33 :server_environment => hoptoad_notice['server-environment'],
34 34 :request => hoptoad_notice['request'],
... ...
app/views/mailer/_signature.text.erb 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +All Glory,
  2 +Hypnotoad
0 3 \ No newline at end of file
... ...
app/views/mailer/deploy_notification.text.erb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +<%= @project.name %> was just deployed to <%= @deploy.environment %> by <%= @deploy.username %>.
  2 +
  3 +Details:
  4 +
  5 + What: <%= @project.name %><%= "@#{@deploy.revision}" unless @deploy.revision.blank? %>
  6 + When: <%= @deploy.created_at.to_s %>
  7 + From: <%= @deploy.repository.blank? ? 'n/a' : @deploy.repository %>
  8 +
  9 +<%= render :partial => 'signature' %>
0 10 \ No newline at end of file
... ...
app/views/mailer/error_notification.text.erb
... ... @@ -4,5 +4,4 @@ This error has occurred &lt;%= pluralize @notice.err.notices.count, &#39;time&#39; %&gt;. You
4 4  
5 5 <%= error_notice_url(@notice.err, @notice) %>
6 6  
7   -Your loyal servant,
8   -Hypnotoad
9 7 \ No newline at end of file
  8 +<%= render :partial => 'signature' %>
10 9 \ No newline at end of file
... ...
config/routes.rb
... ... @@ -2,9 +2,10 @@ Hypnotoad::Application.routes.draw do
2 2  
3 3 # Hoptoad Notifier Routes
4 4 match '/notifier_api/v2/notices' => 'notices#create'
5   - # match '/deploys.txt' => 'deploys#create'
  5 + match '/deploys.txt' => 'deploys#create'
6 6  
7   - resources :notices
  7 + resources :notices, :only => [:show]
  8 + resources :deploys, :only => [:show]
8 9 resources :errors do
9 10 resources :notices
10 11 end
... ...
spec/controllers/deploys_controller_spec.rb 0 → 100644
... ... @@ -0,0 +1,42 @@
  1 +require 'spec_helper'
  2 +
  3 +describe DeploysController do
  4 +
  5 + context 'POST #create' do
  6 + before do
  7 + @params = {
  8 + 'local_username' => 'john.doe',
  9 + 'scm_repository' => 'git@github.com/jdpace/hypnotoad.git',
  10 + 'rails_env' => 'production',
  11 + 'scm_revision' => '19d77837eef37902cf5df7e4445c85f392a8d0d5'
  12 + }
  13 + @project = Factory(:project_with_watcher, :api_key => 'ALLGLORYTOTHEHYPNOTOAD')
  14 + end
  15 +
  16 + it 'finds the project via the api key' do
  17 + Project.should_receive(:find_by_api_key!).with('ALLGLORYTOTHEHYPNOTOAD').and_return(@project)
  18 + post :create, :deploy => @params, :api_key => 'ALLGLORYTOTHEHYPNOTOAD'
  19 + end
  20 +
  21 + it 'creates a deploy' do
  22 + Project.stub(:find_by_api_key!).and_return(@project)
  23 + @project.deploys.should_receive(:create!).
  24 + with({
  25 + :username => 'john.doe',
  26 + :environment => 'production',
  27 + :repository => 'git@github.com/jdpace/hypnotoad.git',
  28 + :revision => '19d77837eef37902cf5df7e4445c85f392a8d0d5'
  29 + }).and_return(Factory(:deploy))
  30 + post :create, :deploy => @params, :api_key => 'ALLGLORYTOTHEHYPNOTOAD'
  31 + end
  32 +
  33 + it 'sends an email notification', :focused => true do
  34 + post :create, :deploy => @params, :api_key => 'ALLGLORYTOTHEHYPNOTOAD'
  35 + email = ActionMailer::Base.deliveries.last
  36 + email.to.should include(@project.watchers.first.email)
  37 + email.subject.should == "[#{@project.name}] Deployed to production by john.doe"
  38 + end
  39 +
  40 + end
  41 +
  42 +end
0 43 \ No newline at end of file
... ...
spec/controllers/notices_controller_spec.rb
... ... @@ -5,7 +5,8 @@ describe NoticesController do
5 5 context 'POST[XML] notices#create' do
6 6 before do
7 7 @xml = Rails.root.join('spec','fixtures','hoptoad_test_notice.xml').read
8   - Project.stub(:find_by_api_key!).and_return(Factory.build(:project))
  8 + @project = Factory(:project_with_watcher)
  9 + Project.stub(:find_by_api_key!).and_return(@project)
9 10 @notice = Notice.from_xml(@xml)
10 11  
11 12 request.env['Content-type'] = 'text/xml'
... ... @@ -17,6 +18,13 @@ describe NoticesController do
17 18 Notice.should_receive(:from_xml).with(@xml).and_return(@notice)
18 19 post :create
19 20 end
  21 +
  22 + it "sends a notification email" do
  23 + post :create
  24 + email = ActionMailer::Base.deliveries.last
  25 + email.to.should include(@project.watchers.first.email)
  26 + email.subject.should include(@notice.err.message)
  27 + end
20 28 end
21 29  
22 30 end
... ...
spec/factories/project_factories.rb
... ... @@ -5,6 +5,12 @@ Factory.define(:project) do |p|
5 5 p.name { Factory.next :project_name }
6 6 end
7 7  
  8 +Factory.define(:project_with_watcher, :parent => :project) do |p|
  9 + p.after_create {|project|
  10 + Factory(:watcher, :project => project)
  11 + }
  12 +end
  13 +
8 14 Factory.define(:watcher) do |w|
9 15 w.project {|p| p.association :project}
10 16 w.email { Factory.next :email }
... ...
spec/models/deploy_spec.rb
... ... @@ -16,4 +16,12 @@ describe Deploy do
16 16 end
17 17 end
18 18  
  19 + context 'being created' do
  20 + it 'should send an email notification' do
  21 + Mailer.should_receive(:deploy_notification).
  22 + and_return(mock('email', :deliver => true))
  23 + Factory(:deploy, :project => Factory(:project_with_watcher))
  24 + end
  25 + end
  26 +
19 27 end
... ...
spec/models/notice_spec.rb
... ... @@ -42,7 +42,7 @@ describe Notice do
42 42 :action => 'verify',
43 43 :environment => 'development'
44 44 }).and_return(err = Err.new)
45   - err.notices.stub(:create)
  45 + err.notices.stub(:create!)
46 46 @notice = Notice.from_xml(@xml)
47 47 end
48 48  
... ... @@ -81,8 +81,8 @@ describe Notice do
81 81  
82 82 describe "email notifications" do
83 83 before do
84   - @watcher = Factory(:watcher)
85   - @error = Factory(:err, :project => @watcher.project)
  84 + @project = Factory(:project_with_watcher)
  85 + @error = Factory(:err, :project => @project)
86 86 end
87 87  
88 88 App.email_at_notices.each do |threshold|
... ...