Commit f4f7de6dbc0e3045d2e49d43264eb95268075d1f
1 parent
fa4c7f79
Exists in
master
and in
1 other branch
got the issue tracker fogbugz integration mostly working
Showing
11 changed files
with
109 additions
and
28 deletions
Show diff stats
Gemfile
| @@ -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' |
Gemfile.lock
| @@ -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' |
| @@ -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 |