Commit e5e6ce94b24155d18551e3299e6808eafa50841f

Authored by Nick Recobra
2 parents a724c092 7a0fdea0
Exists in master and in 1 other branch production

Merge branch 'fogbugz_integration' of https://github.com/narshlob/errbit into pull-request-43

Conflicts:
	app/models/app.rb
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
... ... @@ -42,4 +42,8 @@ module ApplicationHelper
42 42 def pivotal_tracker? object
43 43 object.issue_tracker_type == "pivotal"
44 44 end
  45 +
  46 + def fogbugz_tracker? object
  47 + object.issue_tracker_type == 'fogbugz'
  48 + end
45 49 end
... ...
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
... ... @@ -16,8 +16,8 @@ class Err
16 16 index :last_notice_at
17 17 index :app_id
18 18  
19   - referenced_in :app
20   - references_many :notices
  19 + belongs_to :app
  20 + has_many :notices
21 21  
22 22 validates_presence_of :klass, :environment
23 23  
... ...
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
... ... @@ -11,7 +11,7 @@ class Notice
11 11 field :request, :type => Hash
12 12 field :notifier, :type => Hash
13 13  
14   - referenced_in :err
  14 + belongs_to :err
15 15 index :err_id
16 16  
17 17 after_create :cache_last_notice_at
... ...
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
... ...
app/views/errs/fogbugz_body.txt.erb 0 → 100644
... ... @@ -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
1 1 .window
2   - %pre.hash= pretty_hash notice.params
3   -
4 2 \ No newline at end of file
  3 + .raw_data
  4 + %pre.hash= pretty_hash notice.params
  5 +
... ...
app/views/notices/_session.html.haml
1 1 .window
2   - %pre.hash= pretty_hash notice.session
3 2 \ No newline at end of file
  3 + .raw_data
  4 + %pre.hash= pretty_hash notice.session
... ...
config/initializers/overrides.rb 0 → 100644
... ... @@ -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
... ...
lib/overrides/mongoid/relations/builder.rb 0 → 100644
... ... @@ -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
... ...
public/images/fogbugz_create.png 0 → 100644

4.78 KB

public/images/fogbugz_goto.png 0 → 100644

4.78 KB

public/javascripts/apps.show.js 0 → 100644
... ... @@ -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  
... ...