Commit ced5a311fe743b262a8ed936b7cbf52ad8834dba

Authored by Barry Hess
1 parent 3a3e21a5
Exists in master and in 1 other branch production

Added ability to tie an app to a GitHub repository. Notices then include links t…

…o the file in the GitHub repo.

Conflicts:

	app/helpers/errs_helper.rb
	app/models/app.rb
	app/models/notice.rb
	app/views/apps/_fields.html.haml
	app/views/notices/_summary.html.haml
	spec/models/notice_spec.rb
app/helpers/errs_helper.rb
... ... @@ -7,4 +7,12 @@ module ErrsHelper
7 7 def err_confirm
8 8 Errbit::Config.confirm_resolve_err === false ? nil : 'Seriously?'
9 9 end
  10 +
  11 + def link_to_github app, notice
  12 + file_name = notice.top_in_app_backtrace_line['file'].split('/').last
  13 + file_path = notice.top_in_app_backtrace_line['file'].gsub('[PROJECT_ROOT]', '')
  14 + line_number = notice.top_in_app_backtrace_line['number']
  15 + link_to(file_name, "#{app.github_url_to_file(file_path)}#L#{line_number}", :target => '_blank')
  16 + end
  17 +
10 18 end
11 19 \ No newline at end of file
... ...
app/models/app.rb
... ... @@ -4,6 +4,7 @@ class App
4 4  
5 5 field :name, :type => String
6 6 field :api_key
  7 + field :github_url
7 8 field :resolve_errs_on_deploy, :type => Boolean, :default => false
8 9 field :notify_on_errs, :type => Boolean, :default => true
9 10 field :notify_on_deploys, :type => Boolean, :default => true
... ... @@ -23,7 +24,8 @@ class App
23 24 references_many :errs, :dependent => :destroy
24 25  
25 26 before_validation :generate_api_key, :on => :create
26   -
  27 + before_save :normalize_github_url
  28 +
27 29 validates_presence_of :name, :api_key
28 30 validates_uniqueness_of :name, :allow_blank => true
29 31 validates_uniqueness_of :api_key, :allow_blank => true
... ... @@ -58,7 +60,15 @@ class App
58 60 !(self[:notify_on_deploys] == false)
59 61 end
60 62 alias :notify_on_deploys? :notify_on_deploys
61   -
  63 +
  64 + def github_url?
  65 + self.github_url.present?
  66 + end
  67 +
  68 + def github_url_to_file(file)
  69 + "#{self.github_url}/blob/master#{file}"
  70 + end
  71 +
62 72 protected
63 73  
64 74 def generate_api_key
... ... @@ -73,4 +83,12 @@ class App
73 83 end if issue_tracker.errors
74 84 end
75 85 end
  86 +
  87 + def normalize_github_url
  88 + return if self.github_url.blank?
  89 + self.github_url.gsub!(%r{^http://|git@}, 'https://')
  90 + self.github_url.gsub!(/github\.com:/, 'github.com/')
  91 + self.github_url.gsub!(/\.git$/, '')
  92 + end
  93 +
76 94 end
... ...
app/models/notice.rb
... ... @@ -79,7 +79,11 @@ class Notice
79 79 def cache_last_notice_at
80 80 err.update_attributes(:last_notice_at => created_at)
81 81 end
82   -
  82 +
  83 + def top_in_app_backtrace_line
  84 + @top_in_app_backtrace_line ||= self.backtrace.find {|line| line['file'] =~ %r{^\[PROJECT_ROOT\]/(?!(vendor))} }
  85 + end
  86 +
83 87 protected
84 88  
85 89 def should_notify?
... ...
app/views/apps/_fields.html.haml
... ... @@ -8,6 +8,10 @@
8 8 = f.check_box :notify_on_errs
9 9 = f.label :notify_on_errs, 'Notify on errors'
10 10  
  11 +%div
  12 + = f.label :github_url
  13 + = f.text_field :github_url
  14 +
11 15 %div.checkbox
12 16 = f.check_box :resolve_errs_on_deploy
13 17 = f.label :resolve_errs_on_deploy, 'Resolve errs on deploy'
... ...
app/views/apps/show.html.haml
... ... @@ -27,6 +27,16 @@
27 27 %td
28 28 %em Sadly, no one is watching this app
29 29  
  30 +- if @app.github_url?
  31 + %h3 Repository
  32 + %table.repository
  33 + %thead
  34 + %tr
  35 + %th GitHub
  36 + %tbody
  37 + %tr
  38 + %td= link_to(@app.github_url, @app.github_url, :target => '_blank')
  39 +
30 40 %h3 Latest Deploys
31 41 - if @deploys.any?
32 42 %table.deploys
... ...
app/views/notices/_summary.html.haml
... ... @@ -19,3 +19,7 @@
19 19 %tr
20 20 %th Browser
21 21 %td= user_agent_graph(notice.err)
  22 + - if @app.github_url?
  23 + %tr
  24 + %th GitHub
  25 + %td= link_to_github(@app, notice)
... ...
spec/models/app_spec.rb
... ... @@ -36,6 +36,55 @@ describe App do
36 36 app = Factory(:app)
37 37 app.api_key.should match(/^[a-f0-9]{32}$/)
38 38 end
  39 +
  40 + it 'is fine with blank github urls' do
  41 + app = Factory.build(:app, :github_url => "")
  42 + app.save
  43 + app.github_url.should == ""
  44 + end
  45 +
  46 + it 'does not touch https github urls' do
  47 + app = Factory.build(:app, :github_url => "https://github.com/jdpace/errbit")
  48 + app.save
  49 + app.github_url.should == "https://github.com/jdpace/errbit"
  50 + end
  51 +
  52 + it 'normalizes http github urls' do
  53 + app = Factory.build(:app, :github_url => "http://github.com/jdpace/errbit")
  54 + app.save
  55 + app.github_url.should == "https://github.com/jdpace/errbit"
  56 + end
  57 +
  58 + it 'normalizes public git repo as a github url' do
  59 + app = Factory.build(:app, :github_url => "https://github.com/jdpace/errbit.git")
  60 + app.save
  61 + app.github_url.should == "https://github.com/jdpace/errbit"
  62 + end
  63 +
  64 + it 'normalizes private git repo as a github url' do
  65 + app = Factory.build(:app, :github_url => "git@github.com:jdpace/errbit.git")
  66 + app.save
  67 + app.github_url.should == "https://github.com/jdpace/errbit"
  68 + end
  69 + end
  70 +
  71 + context '#github_url_to_file' do
  72 + it 'resolves to full path to file' do
  73 + app = Factory(:app, :github_url => "https://github.com/jdpace/errbit")
  74 + app.github_url_to_file('/path/to/file').should == "https://github.com/jdpace/errbit/blob/master/path/to/file"
  75 + end
  76 + end
  77 +
  78 + context '#github_url?' do
  79 + it 'is true when there is a github_url' do
  80 + app = Factory(:app, :github_url => "https://github.com/jdpace/errbit")
  81 + app.github_url?.should be_true
  82 + end
  83 +
  84 + it 'is false when no github_url' do
  85 + app = Factory(:app)
  86 + app.github_url?.should be_false
  87 + end
39 88 end
40 89  
41 90 end
... ...
spec/models/notice_spec.rb
... ... @@ -21,7 +21,36 @@ describe Notice do
21 21 notice.errors[:notifier].should include("can't be blank")
22 22 end
23 23 end
24   -
  24 +
  25 + context '#top_in_app_backtrace_line' do
  26 + before do
  27 + backtrace = [{
  28 + 'number' => rand(999),
  29 + 'file' => '[GEM_ROOT]/gems/actionpack-3.0.4/lib/action_controller/metal/rescue.rb',
  30 + 'method' => ActiveSupport.methods.shuffle.first
  31 + }, {
  32 + 'number' => rand(999),
  33 + 'file' => '[PROJECT_ROOT]/vendor/plugins/seamless_database_pool/lib/seamless_database_pool/controller_filter.rb',
  34 + 'method' => ActiveSupport.methods.shuffle.first
  35 + }, {
  36 + 'number' => rand(999),
  37 + 'file' => '[PROJECT_ROOT]/lib/set_headers.rb',
  38 + 'method' => ActiveSupport.methods.shuffle.first
  39 + }, {
  40 + 'number' => rand(999),
  41 + 'file' => '[PROJECT_ROOT]/lib/detect_api.rb',
  42 + 'method' => ActiveSupport.methods.shuffle.first
  43 + }]
  44 +
  45 + @notice = Factory(:notice, :backtrace => backtrace)
  46 + end
  47 +
  48 + it 'finds the correct line' do
  49 + line = @notice.top_in_app_backtrace_line
  50 + line['file'].should == '[PROJECT_ROOT]/lib/set_headers.rb'
  51 + end
  52 + end
  53 +
25 54 context '#from_xml' do
26 55 before do
27 56 @xml = Rails.root.join('spec','fixtures','hoptoad_test_notice.xml').read
... ...