Commit e5e6ce94b24155d18551e3299e6808eafa50841f
Exists in
master
and in
1 other branch
Merge branch 'fogbugz_integration' of https://github.com/narshlob/errbit into pull-request-43
Conflicts: app/models/app.rb
Showing
26 changed files
with
409 additions
and
92 deletions
Show diff stats
Gemfile
... | ... | @@ -2,7 +2,7 @@ source 'http://rubygems.org' |
2 | 2 | |
3 | 3 | gem 'rails', '3.0.5' |
4 | 4 | gem 'nokogiri' |
5 | -gem 'mongoid', '2.0.0.rc.8' | |
5 | +gem 'mongoid', '2.0.2' | |
6 | 6 | gem 'haml' |
7 | 7 | gem 'will_paginate' |
8 | 8 | gem 'devise', '~> 1.1.8' |
... | ... | @@ -11,14 +11,16 @@ gem 'redmine_client', :git => "git://github.com/oruen/redmine_client.git" |
11 | 11 | gem 'mongoid_rails_migrations' |
12 | 12 | gem 'useragent', '~> 0.3.1' |
13 | 13 | gem 'pivotal-tracker' |
14 | +gem 'ruby-fogbugz', :require => 'fogbugz' | |
14 | 15 | |
15 | 16 | platform :ruby do |
16 | - gem 'bson_ext', '~> 1.2' | |
17 | + gem 'bson_ext', '~> 1.3.1' | |
17 | 18 | end |
18 | 19 | |
19 | 20 | group :development, :test do |
20 | 21 | gem 'rspec-rails', '~> 2.5' |
21 | 22 | gem 'webmock', :require => false |
23 | + gem 'ruby-debug19', :require => 'ruby-debug' | |
22 | 24 | end |
23 | 25 | |
24 | 26 | group :test do | ... | ... |
Gemfile.lock
... | ... | @@ -36,11 +36,13 @@ GEM |
36 | 36 | activesupport (= 3.0.5) |
37 | 37 | activesupport (3.0.5) |
38 | 38 | addressable (2.2.5) |
39 | + archive-tar-minitar (0.5.2) | |
39 | 40 | arel (2.0.9) |
40 | 41 | bcrypt-ruby (2.1.4) |
41 | - bson (1.3.0) | |
42 | - bson_ext (1.3.0) | |
42 | + bson (1.3.1) | |
43 | + bson_ext (1.3.1) | |
43 | 44 | builder (2.1.2) |
45 | + columnize (0.3.4) | |
44 | 46 | crack (0.1.8) |
45 | 47 | daemons (1.1.4) |
46 | 48 | database_cleaner (0.6.7) |
... | ... | @@ -65,19 +67,20 @@ GEM |
65 | 67 | lighthouse-api (2.0) |
66 | 68 | activeresource (>= 3.0.0) |
67 | 69 | activesupport (>= 3.0.0) |
70 | + linecache19 (0.5.12) | |
71 | + ruby_core_source (>= 0.1.4) | |
68 | 72 | mail (2.2.17) |
69 | 73 | activesupport (>= 2.3.6) |
70 | 74 | i18n (>= 0.4.0) |
71 | 75 | mime-types (~> 1.16) |
72 | 76 | treetop (~> 1.4.8) |
73 | 77 | mime-types (1.16) |
74 | - mongo (1.3.0) | |
75 | - bson (>= 1.3.0) | |
76 | - mongoid (2.0.0.rc.8) | |
78 | + mongo (1.3.1) | |
79 | + bson (>= 1.3.1) | |
80 | + mongoid (2.0.2) | |
77 | 81 | activemodel (~> 3.0) |
78 | - mongo (~> 1.2) | |
82 | + mongo (~> 1.3) | |
79 | 83 | tzinfo (~> 0.3.22) |
80 | - will_paginate (~> 3.0.pre) | |
81 | 84 | mongoid_rails_migrations (0.0.10) |
82 | 85 | activesupport (~> 3.0.0) |
83 | 86 | bundler (>= 0.9.19) |
... | ... | @@ -124,6 +127,19 @@ GEM |
124 | 127 | activesupport (~> 3.0) |
125 | 128 | railties (~> 3.0) |
126 | 129 | rspec (~> 2.5.0) |
130 | + ruby-debug-base19 (0.11.25) | |
131 | + columnize (>= 0.3.1) | |
132 | + linecache19 (>= 0.5.11) | |
133 | + ruby_core_source (>= 0.1.4) | |
134 | + ruby-debug19 (0.11.6) | |
135 | + columnize (>= 0.3.1) | |
136 | + linecache19 (>= 0.5.11) | |
137 | + ruby-debug-base19 (>= 0.11.19) | |
138 | + ruby-fogbugz (0.0.4) | |
139 | + crack | |
140 | + typhoeus | |
141 | + ruby_core_source (0.1.5) | |
142 | + archive-tar-minitar (>= 0.5.2) | |
127 | 143 | thin (1.2.11) |
128 | 144 | daemons (>= 1.0.9) |
129 | 145 | eventmachine (>= 0.12.6) |
... | ... | @@ -131,6 +147,9 @@ GEM |
131 | 147 | thor (0.14.6) |
132 | 148 | treetop (1.4.9) |
133 | 149 | polyglot (>= 0.3.1) |
150 | + typhoeus (0.2.4) | |
151 | + mime-types | |
152 | + mime-types | |
134 | 153 | tzinfo (0.3.26) |
135 | 154 | useragent (0.3.1) |
136 | 155 | warden (1.0.3) |
... | ... | @@ -144,14 +163,14 @@ PLATFORMS |
144 | 163 | ruby |
145 | 164 | |
146 | 165 | DEPENDENCIES |
147 | - bson_ext (~> 1.2) | |
166 | + bson_ext (~> 1.3.1) | |
148 | 167 | database_cleaner (~> 0.6.0) |
149 | 168 | devise (~> 1.1.8) |
150 | 169 | email_spec |
151 | 170 | factory_girl_rails |
152 | 171 | haml |
153 | 172 | lighthouse-api |
154 | - mongoid (= 2.0.0.rc.8) | |
173 | + mongoid (= 2.0.2) | |
155 | 174 | mongoid_rails_migrations |
156 | 175 | nokogiri |
157 | 176 | pivotal-tracker |
... | ... | @@ -159,6 +178,8 @@ DEPENDENCIES |
159 | 178 | redmine_client! |
160 | 179 | rspec (~> 2.5) |
161 | 180 | rspec-rails (~> 2.5) |
181 | + ruby-debug19 | |
182 | + ruby-fogbugz | |
162 | 183 | thin |
163 | 184 | useragent (~> 0.3.1) |
164 | 185 | webmock | ... | ... |
app/controllers/apps_controller.rb
... | ... | @@ -8,9 +8,17 @@ class AppsController < ApplicationController |
8 | 8 | end |
9 | 9 | |
10 | 10 | def show |
11 | + where_clause = {} | |
11 | 12 | respond_to do |format| |
12 | 13 | format.html do |
13 | - @errs = @app.errs.ordered.paginate(:page => params[:page], :per_page => current_user.per_page) | |
14 | + where_clause[:environment] = params[:environment] if(params[:environment].present?) | |
15 | + if(params[:all_errs]) | |
16 | + @errs = @app.errs.where(where_clause).ordered.paginate(:page => params[:page], :per_page => current_user.per_page) | |
17 | + @all_errs = true | |
18 | + else | |
19 | + @errs = @app.errs.unresolved.where(where_clause).ordered.paginate(:page => params[:page], :per_page => current_user.per_page) | |
20 | + @all_errs = false | |
21 | + end | |
14 | 22 | @deploys = @app.deploys.order_by(:created_at.desc).limit(5) |
15 | 23 | end |
16 | 24 | format.atom do | ... | ... |
app/controllers/errs_controller.rb
... | ... | @@ -5,12 +5,14 @@ class ErrsController < ApplicationController |
5 | 5 | |
6 | 6 | def index |
7 | 7 | app_scope = current_user.admin? ? App.all : current_user.apps |
8 | + where_clause = {} | |
9 | + where_clause[:environment] = params[:environment] if(params[:environment].present?) | |
8 | 10 | respond_to do |format| |
9 | 11 | format.html do |
10 | - @errs = Err.for_apps(app_scope).unresolved.ordered.paginate(:page => params[:page], :per_page => current_user.per_page) | |
12 | + @errs = Err.for_apps(app_scope).where(where_clause).unresolved.ordered.paginate(:page => params[:page], :per_page => current_user.per_page) | |
11 | 13 | end |
12 | 14 | format.atom do |
13 | - @errs = Err.for_apps(app_scope).unresolved.ordered | |
15 | + @errs = Err.for_apps(app_scope).where(where_clause).unresolved.ordered | |
14 | 16 | end |
15 | 17 | end |
16 | 18 | end |
... | ... | @@ -42,7 +44,7 @@ class ErrsController < ApplicationController |
42 | 44 | redirect_to app_err_path(@app, @err) |
43 | 45 | end |
44 | 46 | |
45 | - def clear_issue | |
47 | + def unlink_issue | |
46 | 48 | @err.update_attribute :issue_link, nil |
47 | 49 | redirect_to app_err_path(@app, @err) |
48 | 50 | end | ... | ... |
app/controllers/users_controller.rb
... | ... | @@ -6,7 +6,7 @@ class UsersController < ApplicationController |
6 | 6 | before_filter :require_user_edit_priviledges, :only => [:edit, :update] |
7 | 7 | |
8 | 8 | def index |
9 | - @users = User.paginate(:page => params[:page], :per_page => current_user.per_page) | |
9 | + @users = User.all.paginate(:page => params[:page], :per_page => current_user.per_page) | |
10 | 10 | end |
11 | 11 | |
12 | 12 | def show | ... | ... |
app/helpers/application_helper.rb
app/models/app.rb
... | ... | @@ -21,11 +21,11 @@ class App |
21 | 21 | embeds_many :watchers |
22 | 22 | embeds_many :deploys |
23 | 23 | embeds_one :issue_tracker |
24 | - references_many :errs, :dependent => :destroy | |
24 | + has_many :errs, :inverse_of => :app, :dependent => :destroy | |
25 | 25 | |
26 | 26 | before_validation :generate_api_key, :on => :create |
27 | 27 | before_save :normalize_github_url |
28 | - | |
28 | + | |
29 | 29 | validates_presence_of :name, :api_key |
30 | 30 | validates_uniqueness_of :name, :allow_blank => true |
31 | 31 | validates_uniqueness_of :api_key, :allow_blank => true |
... | ... | @@ -35,7 +35,7 @@ class App |
35 | 35 | accepts_nested_attributes_for :watchers, :allow_destroy => true, |
36 | 36 | :reject_if => proc { |attrs| attrs[:user_id].blank? && attrs[:email].blank? } |
37 | 37 | accepts_nested_attributes_for :issue_tracker, :allow_destroy => true, |
38 | - :reject_if => proc { |attrs| !%w(lighthouseapp redmine pivotal).include?(attrs[:issue_tracker_type]) } | |
38 | + :reject_if => proc { |attrs| !%w(lighthouseapp redmine pivotal fogbugz).include?(attrs[:issue_tracker_type]) } | |
39 | 39 | |
40 | 40 | # Mongoid Bug: find(id) on association proxies returns an Enumerator |
41 | 41 | def self.find_by_id!(app_id) |
... | ... | @@ -60,18 +60,19 @@ class App |
60 | 60 | !(self[:notify_on_deploys] == false) |
61 | 61 | end |
62 | 62 | alias :notify_on_deploys? :notify_on_deploys |
63 | - | |
63 | + | |
64 | 64 | def github_url? |
65 | 65 | self.github_url.present? |
66 | 66 | end |
67 | - | |
67 | + | |
68 | 68 | def github_url_to_file(file) |
69 | 69 | "#{self.github_url}/blob/master#{file}" |
70 | 70 | end |
71 | - | |
71 | + | |
72 | 72 | def issue_tracker_configured? |
73 | 73 | issue_tracker && !issue_tracker.project_id.blank? |
74 | 74 | end |
75 | + | |
75 | 76 | protected |
76 | 77 | |
77 | 78 | def generate_api_key |
... | ... | @@ -86,12 +87,12 @@ class App |
86 | 87 | end if issue_tracker.errors |
87 | 88 | end |
88 | 89 | end |
89 | - | |
90 | + | |
90 | 91 | def normalize_github_url |
91 | 92 | return if self.github_url.blank? |
92 | 93 | self.github_url.gsub!(%r{^http://|git@}, 'https://') |
93 | 94 | self.github_url.gsub!(/github\.com:/, 'github.com/') |
94 | 95 | self.github_url.gsub!(/\.git$/, '') |
95 | 96 | end |
96 | - | |
97 | + | |
97 | 98 | end | ... | ... |
app/models/err.rb
app/models/issue_tracker.rb
... | ... | @@ -12,6 +12,8 @@ class IssueTracker |
12 | 12 | field :account, :type => String |
13 | 13 | field :api_token, :type => String |
14 | 14 | field :project_id, :type => String |
15 | + field :username, :type => String | |
16 | + field :password, :type => String | |
15 | 17 | field :issue_tracker_type, :type => String, :default => 'lighthouseapp' |
16 | 18 | |
17 | 19 | def create_issue err |
... | ... | @@ -22,6 +24,8 @@ class IssueTracker |
22 | 24 | create_redmine_issue err |
23 | 25 | when 'pivotal' |
24 | 26 | create_pivotal_issue err |
27 | + when 'fogbugz' | |
28 | + create_fogbugz_issue err | |
25 | 29 | end |
26 | 30 | end |
27 | 31 | |
... | ... | @@ -65,22 +69,44 @@ class IssueTracker |
65 | 69 | err.update_attribute :issue_link, "#{Lighthouse::Ticket.site.to_s.sub(/#{Lighthouse::Ticket.site.path}$/, '')}#{Lighthouse::Ticket.element_path(ticket.id, :project_id => project_id)}".sub(/\.xml$/, '') |
66 | 70 | end |
67 | 71 | |
72 | + def create_fogbugz_issue err | |
73 | + fogbugz = Fogbugz::Interface.new(:email => username, :password => password, :uri => "https://#{account}.fogbugz.com") | |
74 | + fogbugz.authenticate | |
75 | + | |
76 | + issue = {} | |
77 | + issue['sTitle'] = issue_title err | |
78 | + issue['sArea'] = project_id | |
79 | + issue['sEvent'] = self.class.fogbugz_body_template.result(binding) | |
80 | + issue['sTags'] = ['errbit'].join(',') | |
81 | + issue['cols'] = ['ixBug'].join(',') | |
82 | + | |
83 | + fb_resp = fogbugz.command(:new, issue) | |
84 | + err.update_attribute :issue_link, "https://#{account}.fogbugz.com/default.asp?#{fb_resp['case']['ixBug']}" | |
85 | + end | |
86 | + | |
68 | 87 | def issue_title err |
69 | 88 | "[#{ err.environment }][#{ err.where }] #{err.message.to_s.truncate(100)}" |
70 | 89 | end |
71 | 90 | |
72 | 91 | def check_params |
73 | - blank_flag_fields = %w(api_token project_id) | |
74 | - blank_flag_fields << 'account' if %w(lighthouseapp redmine).include? issue_tracker_type | |
92 | + blank_flag_fields = %w(project_id) | |
93 | + if(%w(fogbugz).include?(issue_tracker_type)) | |
94 | + blank_flag_fields += %w(username password) | |
95 | + else | |
96 | + blank_flag_fields << 'api_token' | |
97 | + end | |
98 | + blank_flag_fields << 'account' if(%w(fogbugz lighthouseapp redmine).include?(issue_tracker_type)) | |
75 | 99 | blank_flags = blank_flag_fields.map {|m| self[m].blank? } |
76 | 100 | if blank_flags.any? && !blank_flags.all? |
77 | 101 | message = case issue_tracker_type |
78 | 102 | when 'lighthouseapp' |
79 | - "You must specify your Lighthouseapp account, api token and project id" | |
103 | + 'You must specify your Lighthouseapp account, api token and project id' | |
80 | 104 | when 'redmine' |
81 | - "You must specify your Redmine url, api token and project id" | |
105 | + 'You must specify your Redmine url, api token and project id' | |
82 | 106 | when 'pivotal' |
83 | - "You must specify your Pivotal Tracker api token and project id" | |
107 | + 'You must specify your Pivotal Tracker api token and project id' | |
108 | + when 'fogbugz' | |
109 | + 'You must specify your FogBugz Area Name, Username, and Password' | |
84 | 110 | end |
85 | 111 | errors.add(:base, message) |
86 | 112 | end |
... | ... | @@ -98,5 +124,9 @@ class IssueTracker |
98 | 124 | def pivotal_body_template |
99 | 125 | @@pivotal_body_template ||= ERB.new(File.read(Rails.root + "app/views/errs/pivotal_body.txt.erb")) |
100 | 126 | end |
127 | + | |
128 | + def fogbugz_body_template | |
129 | + @@fogbugz_body_template ||= ERB.new(File.read(Rails.root + "app/views/errs/fogbugz_body.txt.erb")) | |
130 | + end | |
101 | 131 | end |
102 | 132 | end | ... | ... |
app/models/notice.rb
app/views/apps/_fields.html.haml
... | ... | @@ -45,13 +45,15 @@ |
45 | 45 | = label_tag :issue_tracker_type_redmine, 'Redmine', :for => label_for_attr(w, 'issue_tracker_type_redmine') |
46 | 46 | = w.radio_button :issue_tracker_type, :pivotal |
47 | 47 | = label_tag :issue_tracker_type_pivotal, 'Pivotal Tracker', :for => label_for_attr(w, 'issue_tracker_type_pivotal') |
48 | + = w.radio_button :issue_tracker_type, :fogbugz | |
49 | + = label_tag :issue_tracker_type_fogbugz, 'FogBugz', :for => label_for_attr(w, 'issue_tracker_type_fogbugz') | |
48 | 50 | %div.tracker_params.lighthouseapp{:class => lighthouse_tracker?(w.object) ? 'chosen' : nil} |
49 | 51 | = w.label :account, "Account" |
50 | 52 | = w.text_field :account, :placeholder => "abc from abc.lighthouseapp.com" |
51 | 53 | = w.label :api_token, "API token" |
52 | 54 | = w.text_field :api_token, :placeholder => "API Token for your account" |
53 | 55 | = w.label :project_id, "Project ID" |
54 | - = w.text_field :project_id, :placeholder => "123 from abc from abc.lighthouseapp.com/projects/123" | |
56 | + = w.text_field :project_id, :placeholder => "123 from abc.lighthouseapp.com/projects/123" | |
55 | 57 | %div.tracker_params.redmine{:class => redmine_tracker?(w.object) ? 'chosen' : nil} |
56 | 58 | = w.label :account, "Redmine URL" |
57 | 59 | = w.text_field :account, :placeholder => "like http://www.redmine.org/" |
... | ... | @@ -64,3 +66,12 @@ |
64 | 66 | = w.text_field :project_id |
65 | 67 | = w.label :api_token, "API token" |
66 | 68 | = w.text_field :api_token, :placeholder => "API Token for your account" |
69 | + %div.tracker_params.fogbugz{:class => fogbugz_tracker?(w.object) ? 'chosen' : nil} | |
70 | + = w.label :project_id, "Area Name" | |
71 | + = w.text_field :project_id | |
72 | + = w.label :account, "FogBugz URL" | |
73 | + = w.text_field :account, :placeholder => "abc from http://abc.fogbugz.com/" | |
74 | + = w.label :username, 'account username' | |
75 | + = w.text_field :username, :placeholder => 'Username/Email for your account' | |
76 | + = w.label :password, 'account password' | |
77 | + = w.password_field :password, :placeholder => 'Password for your account' | ... | ... |
app/views/apps/show.html.haml
1 | 1 | - content_for :title, @app.name |
2 | 2 | - content_for :head do |
3 | 3 | = auto_discovery_link_tag :atom, app_url(@app, User.token_authentication_key => current_user.authentication_token, :format => "atom"), :title => "Errbit notices for #{@app.name} at #{root_url}" |
4 | + = javascript_include_tag 'apps.show' | |
4 | 5 | - content_for :meta do |
5 | 6 | %strong Errs Caught: |
6 | 7 | = @app.errs.count |
... | ... | @@ -12,53 +13,66 @@ |
12 | 13 | - if current_user.admin? |
13 | 14 | = link_to 'edit', edit_app_path(@app), :class => 'button' |
14 | 15 | = link_to 'destroy', app_path(@app), :method => :delete, :confirm => 'Seriously?', :class => 'button' |
16 | + - if @all_errs == true | |
17 | + = link_to 'unresolved errs', app_path(@app), :class => 'button' | |
18 | + - else | |
19 | + = link_to 'all errs', app_path(@app, {all_errs: true}), :class => 'button' | |
15 | 20 | |
16 | -%h3 Watchers | |
17 | -%table.watchers | |
18 | - %thead | |
19 | - %tr | |
20 | - %th User or Email | |
21 | - %tbody | |
22 | - - @app.watchers.each do |watcher| | |
23 | - %tr | |
24 | - %td= watcher.label | |
25 | - - if @app.watchers.none? | |
26 | - %tr | |
27 | - %td | |
28 | - %em Sadly, no one is watching this app | |
29 | - | |
30 | -- if @app.github_url? | |
31 | - %h3 Repository | |
32 | - %table.repository | |
21 | +%h3{:id => 'watchers_toggle'} | |
22 | + Watchers | |
23 | + %span{:class => 'click_span'} (show/hide) | |
24 | +#watchers_div | |
25 | + %table.watchers | |
33 | 26 | %thead |
34 | 27 | %tr |
35 | - %th GitHub | |
28 | + %th User or Email | |
36 | 29 | %tbody |
37 | - %tr | |
38 | - %td= link_to(@app.github_url, @app.github_url, :target => '_blank') | |
30 | + - @app.watchers.each do |watcher| | |
31 | + %tr | |
32 | + %td= watcher.label | |
33 | + - if @app.watchers.none? | |
34 | + %tr | |
35 | + %td | |
36 | + %em Sadly, no one is watching this app | |
39 | 37 | |
40 | -%h3 Latest Deploys | |
41 | -- if @deploys.any? | |
42 | - %table.deploys | |
43 | - %thead | |
44 | - %tr | |
45 | - %th When | |
46 | - %th Who | |
47 | - %th Message | |
48 | - %th Repository | |
49 | - %th Revision | |
38 | +- if @app.github_url? | |
39 | + %h3{:id => 'repository_toggle'} | |
40 | + Repository | |
41 | + %span{:class => 'click_span'} (show/hide) | |
42 | + #repository_div | |
43 | + %table.repository | |
44 | + %thead | |
45 | + %tr | |
46 | + %th GitHub | |
47 | + %tbody | |
48 | + %tr | |
49 | + %td= link_to(@app.github_url, @app.github_url, :target => '_blank') | |
50 | 50 | |
51 | - %tbody | |
52 | - - @deploys.each do |deploy| | |
51 | +%h3{:id => 'deploys_toggle'} | |
52 | + Latest Deploys | |
53 | + %span{:class => 'click_span'} (show/hide) | |
54 | +#deploys_div | |
55 | + - if @deploys.any? | |
56 | + %table.deploys | |
57 | + %thead | |
53 | 58 | %tr |
54 | - %td.when #{deploy.created_at.to_s(:micro)} | |
55 | - %td.who #{deploy.username} | |
56 | - %td.message #{deploy.message} | |
57 | - %td.repository #{deploy.repository} | |
58 | - %td.revision #{deploy.revision} | |
59 | - = link_to "All Deploys (#{@app.deploys.count})", app_deploys_path(@app), :class => 'button' | |
60 | -- else | |
61 | - %h3 No deploys | |
59 | + %th When | |
60 | + %th Who | |
61 | + %th Message | |
62 | + %th Repository | |
63 | + %th Revision | |
64 | + | |
65 | + %tbody | |
66 | + - @deploys.each do |deploy| | |
67 | + %tr | |
68 | + %td.when #{deploy.created_at.to_s(:micro)} | |
69 | + %td.who #{deploy.username} | |
70 | + %td.message #{deploy.message} | |
71 | + %td.repository #{deploy.repository} | |
72 | + %td.revision #{deploy.revision} | |
73 | + = link_to "All Deploys (#{@app.deploys.count})", app_deploys_path(@app), :class => 'button' | |
74 | + - else | |
75 | + %h3 No deploys | |
62 | 76 | |
63 | 77 | - if @app.errs.count > 0 |
64 | 78 | %h3.clear Errs | ... | ... |
app/views/errs/_table.html.haml
... | ... | @@ -12,7 +12,10 @@ |
12 | 12 | %tr{:class => err.resolved? ? 'resolved' : 'unresolved'} |
13 | 13 | %td.app |
14 | 14 | = link_to err.app.name, app_path(err.app) |
15 | - %span.environment= err.environment | |
15 | + - if(current_page?(:controller => 'errs')) | |
16 | + %span.environment= link_to err.environment, errs_path(environment: err.environment) | |
17 | + - else | |
18 | + %span.environment= link_to err.environment, app_path(environment: err.environment) | |
16 | 19 | %td.message |
17 | 20 | = link_to err.message, app_err_path(err.app, err) |
18 | 21 | %em= err.where | ... | ... |
... | ... | @@ -0,0 +1,31 @@ |
1 | +"See this exception on Errbit": <%= app_err_url(err.app, err) %> | |
2 | +<% if notice = err.notices.first %> | |
3 | + <%= notice.message %> | |
4 | + | |
5 | + Summary | |
6 | + - Where | |
7 | + <%= notice.err.where %> | |
8 | + | |
9 | + - Occured | |
10 | + <%= notice.created_at.to_s(:micro) %> | |
11 | + | |
12 | + - Similar | |
13 | + <%= (notice.err.notices_count - 1).to_s %> | |
14 | + | |
15 | + Params | |
16 | + <%= pretty_hash(notice.params) %> | |
17 | + | |
18 | + Session | |
19 | + <%= pretty_hash(notice.session) %> | |
20 | + | |
21 | + Backtrace | |
22 | + <% for line in notice.backtrace %> | |
23 | + <%= line['number'] %>: <%= line['file'].sub(/^\[PROJECT_ROOT\]/, '') %> | |
24 | + <% end %> | |
25 | + | |
26 | + Environment | |
27 | + <% for key, val in notice.env_vars %> | |
28 | + <%= key %>: <%= val %> | |
29 | + <% end %> | |
30 | +<% end %> | |
31 | + | ... | ... |
app/views/errs/show.html.haml
... | ... | @@ -5,6 +5,7 @@ |
5 | 5 | = @app.name |
6 | 6 | %strong Where: |
7 | 7 | = @err.where |
8 | + %br | |
8 | 9 | %strong Environment: |
9 | 10 | = @err.environment |
10 | 11 | %strong Last Notice: |
... | ... | @@ -15,7 +16,7 @@ |
15 | 16 | %span= link_to 'create issue', create_issue_app_err_path(@app, @err), :method => :post, :class => "#{@app.issue_tracker.issue_tracker_type}_create create-issue" |
16 | 17 | - else |
17 | 18 | %span= link_to 'go to issue', @err.issue_link, :class => "#{@app.issue_tracker.issue_tracker_type}_goto goto-issue" |
18 | - = link_to 'clear issue', clear_issue_app_err_path(@app, @err), :method => :delete, :confirm => "Clear err issues?", :class => "clear-issue" | |
19 | + = link_to 'unlink issue', unlink_issue_app_err_path(@app, @err), :method => :delete, :confirm => "Unlink err issues?", :class => "unlink-issue" | |
19 | 20 | - if @err.unresolved? |
20 | 21 | %span= link_to 'resolve', resolve_app_err_path(@app, @err), :method => :put, :confirm => err_confirm, :class => 'resolve' |
21 | 22 | ... | ... |
app/views/notices/_params.html.haml
app/views/notices/_session.html.haml
... | ... | @@ -0,0 +1 @@ |
1 | +require Rails.root.join('lib/overrides/mongoid/relations/builder.rb') | ... | ... |
config/routes.rb
1 | 1 | Errbit::Application.routes.draw do |
2 | - | |
2 | + | |
3 | 3 | devise_for :users |
4 | 4 | |
5 | 5 | # Hoptoad Notifier Routes |
6 | 6 | match '/notifier_api/v2/notices' => 'notices#create' |
7 | 7 | match '/deploys.txt' => 'deploys#create' |
8 | - | |
8 | + | |
9 | 9 | resources :notices, :only => [:show] |
10 | 10 | resources :deploys, :only => [:show] |
11 | 11 | resources :users |
... | ... | @@ -14,22 +14,22 @@ Errbit::Application.routes.draw do |
14 | 14 | get :all |
15 | 15 | end |
16 | 16 | end |
17 | - | |
17 | + | |
18 | 18 | resources :apps do |
19 | 19 | resources :errs do |
20 | 20 | resources :notices |
21 | 21 | member do |
22 | 22 | put :resolve |
23 | 23 | post :create_issue |
24 | - delete :clear_issue | |
24 | + delete :unlink_issue | |
25 | 25 | end |
26 | 26 | end |
27 | 27 | |
28 | 28 | resources :deploys, :only => [:index] |
29 | 29 | end |
30 | - | |
30 | + | |
31 | 31 | devise_for :users |
32 | - | |
32 | + | |
33 | 33 | root :to => 'apps#index' |
34 | - | |
34 | + | |
35 | 35 | end | ... | ... |
... | ... | @@ -0,0 +1,15 @@ |
1 | +# ruby-fogbugz requires crack. crack adds the attributes method to strings, | |
2 | +# thus breaking the relations of Mongoid. | |
3 | +# Tests reside in a separate fork of mongoid: | |
4 | +# https://github.com/mhs/mongoid/commit/e5b2b1346c73a2935c606317314b6ded07260429#diff-1 | |
5 | +module Mongoid | |
6 | + module Relations | |
7 | + class Builder | |
8 | + def query? | |
9 | + return true unless object.respond_to?(:to_a) | |
10 | + obj = object.to_a.first | |
11 | + !obj.is_a?(Mongoid::Document) && !obj.nil? | |
12 | + end | |
13 | + end | |
14 | + end | |
15 | +end | ... | ... |
4.78 KB
4.78 KB
... | ... | @@ -0,0 +1,11 @@ |
1 | +$(function() { | |
2 | + $("#watchers_toggle").click(function() { | |
3 | + $("#watchers_div").slideToggle("slow"); | |
4 | + }); | |
5 | + $("#repository_toggle").click(function() { | |
6 | + $("#repository_div").slideToggle("slow"); | |
7 | + }); | |
8 | + $("#deploys_toggle").click(function() { | |
9 | + $("#deploys_div").slideToggle("slow"); | |
10 | + }); | |
11 | +}); | ... | ... |
public/stylesheets/application.css
... | ... | @@ -376,13 +376,18 @@ table .main { width: 100%; } |
376 | 376 | table.single_user { |
377 | 377 | border-top: none; |
378 | 378 | } |
379 | + | |
380 | +.raw_data { | |
381 | + width: 100%; | |
382 | + color: #f0f0f0; | |
383 | + background-color: #222; | |
384 | + overflow: auto; | |
385 | +} | |
386 | + | |
379 | 387 | /* Code */ |
380 | 388 | pre { |
381 | 389 | padding: 0.8em; |
382 | 390 | margin-bottom: 1em; |
383 | - color: #f0f0f0; | |
384 | - background-color: #222; | |
385 | - border: 1px solid #444; | |
386 | 391 | font-family: monaco, courier, monospace; |
387 | 392 | font-size: 1.1em; |
388 | 393 | } |
... | ... | @@ -502,7 +507,7 @@ a.button.active { |
502 | 507 | } |
503 | 508 | |
504 | 509 | /* Watchers and Issue Tracker Forms */ |
505 | -div.nested.watcher .user, div.nested.watcher .email, div.issue_tracker.nested .lighthouseapp, div.issue_tracker.nested .redmine, div.issue_tracker.nested .pivotal { | |
510 | +div.nested.watcher .user, div.nested.watcher .email, div.issue_tracker.nested .lighthouseapp, div.issue_tracker.nested .redmine, div.issue_tracker.nested .pivotal, div.issue_tracker.nested .fogbugz { | |
506 | 511 | display: none; |
507 | 512 | } |
508 | 513 | div.nested.watcher .choosen, div.nested.issue_tracker .chosen { |
... | ... | @@ -612,6 +617,10 @@ table.tally th.value { |
612 | 617 | background: transparent url(/images/pivotal_create.png) 6px 5px no-repeat; |
613 | 618 | } |
614 | 619 | |
620 | +#action-bar a.fogbugz_create { | |
621 | + background: transparent url(/images/fogbugz_create.png) 6px 5px no-repeat; | |
622 | +} | |
623 | + | |
615 | 624 | #action-bar a.lighthouseapp_goto { |
616 | 625 | background: transparent url(/images/lighthouseapp_goto.png) 6px 5px no-repeat; |
617 | 626 | } |
... | ... | @@ -624,6 +633,10 @@ table.tally th.value { |
624 | 633 | background: transparent url(/images/pivotal_goto.png) 6px 5px no-repeat; |
625 | 634 | } |
626 | 635 | |
636 | +#action-bar a.fogbugz_goto { | |
637 | + background: transparent url(/images/fogbugz_goto.png) 6px 5px no-repeat; | |
638 | +} | |
639 | + | |
627 | 640 | /* Notices Pagination */ |
628 | 641 | .notice-pagination { |
629 | 642 | float: left; |
... | ... | @@ -636,9 +649,11 @@ table.tally th.value { |
636 | 649 | margin-bottom: 1em; |
637 | 650 | overflow: auto; |
638 | 651 | } |
652 | + | |
639 | 653 | .window table { |
640 | 654 | margin: 0; |
641 | 655 | } |
656 | + | |
642 | 657 | table.backtrace td { |
643 | 658 | width: 100%; |
644 | 659 | padding: 0; |
... | ... | @@ -660,3 +675,11 @@ table.backtrace li.in-app { |
660 | 675 | color: #2adb2e; |
661 | 676 | background-color: #2f2f2f; |
662 | 677 | } |
678 | + | |
679 | +span.click_span { | |
680 | + font-size: 0.7em; | |
681 | +} | |
682 | + | |
683 | +#deploys_div, #repository_div, #watchers_div { | |
684 | + display: none; | |
685 | +} | ... | ... |
spec/controllers/apps_controller_spec.rb
... | ... | @@ -74,6 +74,71 @@ describe AppsController do |
74 | 74 | assigns(:errs).size.should == 10 |
75 | 75 | end |
76 | 76 | end |
77 | + | |
78 | + context 'with resolved errors' do | |
79 | + before(:each) do | |
80 | + resolved_err = Factory.create(:err, app: @app, resolved: true) | |
81 | + Factory.create(:notice, err: resolved_err) | |
82 | + end | |
83 | + | |
84 | + context 'and no params' do | |
85 | + it 'shows only unresolved errs' do | |
86 | + get :show, id: @app.id | |
87 | + assigns(:errs).size.should == 1 | |
88 | + end | |
89 | + end | |
90 | + | |
91 | + context 'and all_errs=true params' do | |
92 | + it 'shows all errors' do | |
93 | + get :show, id: @app.id, all_errs: true | |
94 | + assigns(:errs).size.should == 2 | |
95 | + end | |
96 | + end | |
97 | + end | |
98 | + | |
99 | + context 'with environment filters' do | |
100 | + before(:each) do | |
101 | + environments = ['production', 'test', 'development', 'staging'] | |
102 | + 20.times do |i| | |
103 | + Factory.create(:err, app: @app, environment: environments[i % environments.length]) | |
104 | + end | |
105 | + end | |
106 | + | |
107 | + context 'no params' do | |
108 | + it 'shows errs for all environments' do | |
109 | + get :show, id: @app.id | |
110 | + assigns(:errs).size.should == 21 | |
111 | + end | |
112 | + end | |
113 | + | |
114 | + context 'environment production' do | |
115 | + it 'shows errs for just production' do | |
116 | + get :show, id: @app.id, environment: :production | |
117 | + assigns(:errs).size.should == 6 | |
118 | + end | |
119 | + end | |
120 | + | |
121 | + context 'environment staging' do | |
122 | + it 'shows errs for just staging' do | |
123 | + get :show, id: @app.id, environment: :staging | |
124 | + assigns(:errs).size.should == 5 | |
125 | + end | |
126 | + end | |
127 | + | |
128 | + context 'environment development' do | |
129 | + it 'shows errs for just development' do | |
130 | + get :show, id: @app.id, environment: :development | |
131 | + assigns(:errs).size.should == 5 | |
132 | + end | |
133 | + end | |
134 | + | |
135 | + context 'environment test' do | |
136 | + it 'shows errs for just test' do | |
137 | + get :show, id: @app.id, environment: :test | |
138 | + assigns(:errs).size.should == 5 | |
139 | + end | |
140 | + end | |
141 | + end | |
77 | 142 | end |
78 | 143 | |
79 | 144 | context 'logged in as a user' do |
... | ... | @@ -261,6 +326,34 @@ describe AppsController do |
261 | 326 | response.body.should match(/You must specify your Pivotal Tracker api token and project id/) |
262 | 327 | end |
263 | 328 | end |
329 | + | |
330 | + context "fogbugz" do | |
331 | + context 'with correct params' do | |
332 | + before do | |
333 | + put :update, :id => @app.id, :app => { :issue_tracker_attributes => { | |
334 | + :issue_tracker_type => 'fogbugz', :account => 'abc', :project_id => 'Service - Peon', :username => '1234', :password => '123123' } } | |
335 | + @app.reload | |
336 | + end | |
337 | + | |
338 | + subject {@app.issue_tracker} | |
339 | + its(:issue_tracker_type) {should == 'fogbugz'} | |
340 | + its(:account) {should == 'abc'} | |
341 | + its(:project_id) {should == 'Service - Peon'} | |
342 | + its(:username) {should == '1234'} | |
343 | + its(:password) {should == '123123'} | |
344 | + end | |
345 | + | |
346 | + context 'insufficient params' do | |
347 | + it 'shows validation notice' do | |
348 | + put :update, :id => @app.id, :app => { :issue_tracker_attributes => { | |
349 | + :issue_tracker_type => 'fogbugz', :project_id => '1234' } } | |
350 | + @app.reload | |
351 | + | |
352 | + @app.issue_tracker.should be_nil | |
353 | + response.body.should match(/You must specify your FogBugz Area Name, Username, and Password/) | |
354 | + end | |
355 | + end | |
356 | + end | |
264 | 357 | end |
265 | 358 | end |
266 | 359 | ... | ... |
spec/controllers/errs_controller_spec.rb
... | ... | @@ -54,6 +54,50 @@ describe ErrsController do |
54 | 54 | assigns(:errs).size.should == 10 |
55 | 55 | end |
56 | 56 | end |
57 | + | |
58 | + context 'with environment filters' do | |
59 | + before(:each) do | |
60 | + environments = ['production', 'test', 'development', 'staging'] | |
61 | + 20.times do |i| | |
62 | + Factory.create(:err, environment: environments[i % environments.length]) | |
63 | + end | |
64 | + end | |
65 | + | |
66 | + context 'no params' do | |
67 | + it 'shows errs for all environments' do | |
68 | + get :index | |
69 | + assigns(:errs).size.should == 21 | |
70 | + end | |
71 | + end | |
72 | + | |
73 | + context 'environment production' do | |
74 | + it 'shows errs for just production' do | |
75 | + get :index, environment: :production | |
76 | + assigns(:errs).size.should == 6 | |
77 | + end | |
78 | + end | |
79 | + | |
80 | + context 'environment staging' do | |
81 | + it 'shows errs for just staging' do | |
82 | + get :index, environment: :staging | |
83 | + assigns(:errs).size.should == 5 | |
84 | + end | |
85 | + end | |
86 | + | |
87 | + context 'environment development' do | |
88 | + it 'shows errs for just development' do | |
89 | + get :index, environment: :development | |
90 | + assigns(:errs).size.should == 5 | |
91 | + end | |
92 | + end | |
93 | + | |
94 | + context 'environment test' do | |
95 | + it 'shows errs for just test' do | |
96 | + get :index, environment: :test | |
97 | + assigns(:errs).size.should == 5 | |
98 | + end | |
99 | + end | |
100 | + end | |
57 | 101 | end |
58 | 102 | |
59 | 103 | context 'when logged in as a user' do |
... | ... | @@ -358,7 +402,7 @@ describe ErrsController do |
358 | 402 | end |
359 | 403 | end |
360 | 404 | |
361 | - describe "DELETE /apps/:app_id/errs/:id/clear_issue" do | |
405 | + describe "DELETE /apps/:app_id/errs/:id/unlink_issue" do | |
362 | 406 | before(:each) do |
363 | 407 | sign_in Factory(:admin) |
364 | 408 | end |
... | ... | @@ -367,7 +411,7 @@ describe ErrsController do |
367 | 411 | let(:err) { Factory :err, :issue_link => "http://some.host" } |
368 | 412 | |
369 | 413 | before(:each) do |
370 | - delete :clear_issue, :app_id => err.app.id, :id => err.id | |
414 | + delete :unlink_issue, :app_id => err.app.id, :id => err.id | |
371 | 415 | err.reload |
372 | 416 | end |
373 | 417 | |
... | ... | @@ -384,7 +428,7 @@ describe ErrsController do |
384 | 428 | let(:err) { Factory :err } |
385 | 429 | |
386 | 430 | before(:each) do |
387 | - delete :clear_issue, :app_id => err.app.id, :id => err.id | |
431 | + delete :unlink_issue, :app_id => err.app.id, :id => err.id | |
388 | 432 | err.reload |
389 | 433 | end |
390 | 434 | ... | ... |