Commit f4f7de6dbc0e3045d2e49d43264eb95268075d1f

Authored by Tracey Eubanks
1 parent fa4c7f79
Exists in master and in 1 other branch production

got the issue tracker fogbugz integration mostly working

@@ -2,7 +2,7 @@ source 'http://rubygems.org' @@ -2,7 +2,7 @@ source 'http://rubygems.org'
2 2
3 gem 'rails', '3.0.5' 3 gem 'rails', '3.0.5'
4 gem 'nokogiri' 4 gem 'nokogiri'
5 -gem 'mongoid', '2.0.0.rc.8' 5 +gem 'mongoid', '2.0.2'
6 gem 'haml' 6 gem 'haml'
7 gem 'will_paginate' 7 gem 'will_paginate'
8 gem 'devise', '~> 1.1.8' 8 gem 'devise', '~> 1.1.8'
@@ -45,7 +45,7 @@ GEM @@ -45,7 +45,7 @@ GEM
45 addressable (2.2.5) 45 addressable (2.2.5)
46 arel (2.0.9) 46 arel (2.0.9)
47 bcrypt-ruby (2.1.4) 47 bcrypt-ruby (2.1.4)
48 - bson (1.3.0) 48 + bson (1.3.1)
49 bson_ext (1.3.0) 49 bson_ext (1.3.0)
50 builder (2.1.2) 50 builder (2.1.2)
51 crack (0.1.8) 51 crack (0.1.8)
@@ -78,13 +78,12 @@ GEM @@ -78,13 +78,12 @@ GEM
78 mime-types (~> 1.16) 78 mime-types (~> 1.16)
79 treetop (~> 1.4.8) 79 treetop (~> 1.4.8)
80 mime-types (1.16) 80 mime-types (1.16)
81 - mongo (1.3.0)  
82 - bson (>= 1.3.0)  
83 - mongoid (2.0.0.rc.8) 81 + mongo (1.3.1)
  82 + bson (>= 1.3.1)
  83 + mongoid (2.0.2)
84 activemodel (~> 3.0) 84 activemodel (~> 3.0)
85 - mongo (~> 1.2) 85 + mongo (~> 1.3)
86 tzinfo (~> 0.3.22) 86 tzinfo (~> 0.3.22)
87 - will_paginate (~> 3.0.pre)  
88 mongoid_rails_migrations (0.0.10) 87 mongoid_rails_migrations (0.0.10)
89 activesupport (~> 3.0.0) 88 activesupport (~> 3.0.0)
90 bundler (>= 0.9.19) 89 bundler (>= 0.9.19)
@@ -161,7 +160,7 @@ DEPENDENCIES @@ -161,7 +160,7 @@ DEPENDENCIES
161 factory_girl_rails 160 factory_girl_rails
162 haml 161 haml
163 lighthouse-api 162 lighthouse-api
164 - mongoid (= 2.0.0.rc.8) 163 + mongoid (= 2.0.2)
165 mongoid_rails_migrations 164 mongoid_rails_migrations
166 nokogiri 165 nokogiri
167 pivotal-tracker 166 pivotal-tracker
app/helpers/application_helper.rb
@@ -42,4 +42,8 @@ module ApplicationHelper @@ -42,4 +42,8 @@ module ApplicationHelper
42 def pivotal_tracker? object 42 def pivotal_tracker? object
43 object.issue_tracker_type == "pivotal" 43 object.issue_tracker_type == "pivotal"
44 end 44 end
  45 +
  46 + def fogbugz_tracker? object
  47 + object.issue_tracker_type == 'fogbugz'
  48 + end
45 end 49 end
app/models/app.rb
@@ -21,7 +21,7 @@ class App @@ -21,7 +21,7 @@ class App
21 embeds_many :watchers 21 embeds_many :watchers
22 embeds_many :deploys 22 embeds_many :deploys
23 embeds_one :issue_tracker 23 embeds_one :issue_tracker
24 - references_many :errs, :dependent => :destroy 24 + has_many :errs, :dependent => :destroy
25 25
26 before_validation :generate_api_key, :on => :create 26 before_validation :generate_api_key, :on => :create
27 before_save :normalize_github_url 27 before_save :normalize_github_url
@@ -35,7 +35,7 @@ class App @@ -35,7 +35,7 @@ class App
35 accepts_nested_attributes_for :watchers, :allow_destroy => true, 35 accepts_nested_attributes_for :watchers, :allow_destroy => true,
36 :reject_if => proc { |attrs| attrs[:user_id].blank? && attrs[:email].blank? } 36 :reject_if => proc { |attrs| attrs[:user_id].blank? && attrs[:email].blank? }
37 accepts_nested_attributes_for :issue_tracker, :allow_destroy => true, 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 # Mongoid Bug: find(id) on association proxies returns an Enumerator 40 # Mongoid Bug: find(id) on association proxies returns an Enumerator
41 def self.find_by_id!(app_id) 41 def self.find_by_id!(app_id)
app/models/err.rb
@@ -16,8 +16,8 @@ class Err @@ -16,8 +16,8 @@ class Err
16 index :last_notice_at 16 index :last_notice_at
17 index :app_id 17 index :app_id
18 18
19 - referenced_in :app  
20 - references_many :notices 19 + belongs_to :app, inverse_of: :errs
  20 + has_many :notices
21 21
22 validates_presence_of :klass, :environment 22 validates_presence_of :klass, :environment
23 23
app/models/issue_tracker.rb
@@ -12,6 +12,8 @@ class IssueTracker @@ -12,6 +12,8 @@ class IssueTracker
12 field :account, :type => String 12 field :account, :type => String
13 field :api_token, :type => String 13 field :api_token, :type => String
14 field :project_id, :type => String 14 field :project_id, :type => String
  15 + field :username, :type => String
  16 + field :password, :type => String
15 field :issue_tracker_type, :type => String, :default => 'lighthouseapp' 17 field :issue_tracker_type, :type => String, :default => 'lighthouseapp'
16 18
17 def create_issue err 19 def create_issue err
@@ -68,18 +70,20 @@ class IssueTracker @@ -68,18 +70,20 @@ class IssueTracker
68 end 70 end
69 71
70 def create_fogbugz_issue err 72 def create_fogbugz_issue err
71 - fogbugz = Fogbugz::Interface.new(:email => email, :password => password, :uri => uri)  
72 - fogbugz.account = account  
73 - fogbugz.token = api_token 73 + fogbugz = Fogbugz::Interface.new(:email => username, :password => password, :uri => "https://#{account}.fogbugz.com")
  74 + fogbugz.authenticate
74 75
75 issue = {} 76 issue = {}
76 issue['sTitle'] = issue_title err 77 issue['sTitle'] = issue_title err
77 - issue['sProject'] = project_id 78 + issue['sArea'] = project_id
  79 + puts err.app.inspect
  80 + puts app_err_url(err.app, err)
78 issue['sEvent'] = self.class.fogbugz_body_template.result(binding) 81 issue['sEvent'] = self.class.fogbugz_body_template.result(binding)
79 - issue['sTags'] << 'errbit' 82 + issue['sTags'] = ['errbit'].join(',')
  83 + issue['cols'] = ['ixBug'].join(',')
80 84
81 - fogbugz.command(  
82 - # err.update_attribute :issue_link, "#{FogBugz::Issue.site.to_s.sub(/#{FogBugz::Issue.site.path}$/, '')}#{FogBugz::Issue.element_path(issue.id, :project => project_id}".sub(/\.xml$/, '') 85 + # fb_resp = fogbugz.command(:new, issue)
  86 + # err.update_attribute :issue_link, "https://#{account}.fogbugz.com/default.asp?#{fb_resp['case']['ixBug']}"
83 end 87 end
84 88
85 def issue_title err 89 def issue_title err
@@ -87,19 +91,24 @@ class IssueTracker @@ -87,19 +91,24 @@ class IssueTracker
87 end 91 end
88 92
89 def check_params 93 def check_params
90 - blank_flag_fields = %w(api_token project_id)  
91 - blank_flag_fields << 'account' if %w(lighthouseapp redmine).include? issue_tracker_type 94 + blank_flag_fields = %w(project_id)
  95 + if(%w(fogbugz).include?(issue_tracker_type))
  96 + blank_flag_fields += %w(username password)
  97 + else
  98 + blank_flag_fields << 'api_token'
  99 + end
  100 + blank_flag_fields << 'account' if(%w(fogbugz lighthouseapp redmine).include?(issue_tracker_type))
92 blank_flags = blank_flag_fields.map {|m| self[m].blank? } 101 blank_flags = blank_flag_fields.map {|m| self[m].blank? }
93 if blank_flags.any? && !blank_flags.all? 102 if blank_flags.any? && !blank_flags.all?
94 message = case issue_tracker_type 103 message = case issue_tracker_type
95 when 'lighthouseapp' 104 when 'lighthouseapp'
96 - "You must specify your Lighthouseapp account, api token and project id" 105 + 'You must specify your Lighthouseapp account, api token and project id'
97 when 'redmine' 106 when 'redmine'
98 - "You must specify your Redmine url, api token and project id" 107 + 'You must specify your Redmine url, api token and project id'
99 when 'pivotal' 108 when 'pivotal'
100 - "You must specify your Pivotal Tracker api token and project id" 109 + 'You must specify your Pivotal Tracker api token and project id'
101 when 'fogbugz' 110 when 'fogbugz'
102 - "You must specify your FogBugz account, project id, username, and password" 111 + 'You must specify your FogBugz Area Name, Username, and Password'
103 end 112 end
104 errors.add(:base, message) 113 errors.add(:base, message)
105 end 114 end
app/models/notice.rb
@@ -11,7 +11,7 @@ class Notice @@ -11,7 +11,7 @@ class Notice
11 field :request, :type => Hash 11 field :request, :type => Hash
12 field :notifier, :type => Hash 12 field :notifier, :type => Hash
13 13
14 - referenced_in :err 14 + belongs_to :err
15 index :err_id 15 index :err_id
16 16
17 after_create :cache_last_notice_at 17 after_create :cache_last_notice_at
app/views/apps/_fields.html.haml
@@ -45,13 +45,15 @@ @@ -45,13 +45,15 @@
45 = label_tag :issue_tracker_type_redmine, 'Redmine', :for => label_for_attr(w, 'issue_tracker_type_redmine') 45 = label_tag :issue_tracker_type_redmine, 'Redmine', :for => label_for_attr(w, 'issue_tracker_type_redmine')
46 = w.radio_button :issue_tracker_type, :pivotal 46 = w.radio_button :issue_tracker_type, :pivotal
47 = label_tag :issue_tracker_type_pivotal, 'Pivotal Tracker', :for => label_for_attr(w, 'issue_tracker_type_pivotal') 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 %div.tracker_params.lighthouseapp{:class => lighthouse_tracker?(w.object) ? 'chosen' : nil} 50 %div.tracker_params.lighthouseapp{:class => lighthouse_tracker?(w.object) ? 'chosen' : nil}
49 = w.label :account, "Account" 51 = w.label :account, "Account"
50 = w.text_field :account, :placeholder => "abc from abc.lighthouseapp.com" 52 = w.text_field :account, :placeholder => "abc from abc.lighthouseapp.com"
51 = w.label :api_token, "API token" 53 = w.label :api_token, "API token"
52 = w.text_field :api_token, :placeholder => "API Token for your account" 54 = w.text_field :api_token, :placeholder => "API Token for your account"
53 = w.label :project_id, "Project ID" 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 %div.tracker_params.redmine{:class => redmine_tracker?(w.object) ? 'chosen' : nil} 57 %div.tracker_params.redmine{:class => redmine_tracker?(w.object) ? 'chosen' : nil}
56 = w.label :account, "Redmine URL" 58 = w.label :account, "Redmine URL"
57 = w.text_field :account, :placeholder => "like http://www.redmine.org/" 59 = w.text_field :account, :placeholder => "like http://www.redmine.org/"
@@ -64,3 +66,12 @@ @@ -64,3 +66,12 @@
64 = w.text_field :project_id 66 = w.text_field :project_id
65 = w.label :api_token, "API token" 67 = w.label :api_token, "API token"
66 = w.text_field :api_token, :placeholder => "API Token for your account" 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/errs/fogbugz_body.txt.erb 0 → 100644
@@ -0,0 +1,31 @@ @@ -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 +
public/stylesheets/application.css
@@ -507,7 +507,7 @@ a.button.active { @@ -507,7 +507,7 @@ a.button.active {
507 } 507 }
508 508
509 /* Watchers and Issue Tracker Forms */ 509 /* Watchers and Issue Tracker Forms */
510 -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 {
511 display: none; 511 display: none;
512 } 512 }
513 div.nested.watcher .choosen, div.nested.issue_tracker .chosen { 513 div.nested.watcher .choosen, div.nested.issue_tracker .chosen {
spec/controllers/apps_controller_spec.rb
@@ -261,6 +261,33 @@ describe AppsController do @@ -261,6 +261,33 @@ describe AppsController do
261 response.body.should match(/You must specify your Pivotal Tracker api token and project id/) 261 response.body.should match(/You must specify your Pivotal Tracker api token and project id/)
262 end 262 end
263 end 263 end
  264 +
  265 + context "fogbugz" do
  266 + context 'with correct params' do
  267 + before do
  268 + put :update, :id => @app.id, :app => { :issue_tracker_attributes => {
  269 + :issue_tracker_type => 'fogbugz', :project_id => 'Service - Peon', :username => '1234', :password => '123123' } }
  270 + @app.reload
  271 + end
  272 +
  273 + subject {@app.issue_tracker}
  274 + its(:issue_tracker_type) {should == 'fogbugz'}
  275 + its(:project_id) {should == 'Service - Peon'}
  276 + its(:username) {should == '1234'}
  277 + its(:password) {should == '123123'}
  278 + end
  279 +
  280 + context 'insufficient params' do
  281 + it 'shows validation notice' do
  282 + put :update, :id => @app.id, :app => { :issue_tracker_attributes => {
  283 + :issue_tracker_type => 'fogbugz', :project_id => '1234' } }
  284 + @app.reload
  285 +
  286 + @app.issue_tracker.should be_nil
  287 + response.body.should match(/You must specify your FogBugz Area Name, Username, and Password/)
  288 + end
  289 + end
  290 + end
264 end 291 end
265 end 292 end
266 293