Permalink
Browse files

Add support for Pivotal Tracker issue creation

  • Loading branch information...
1 parent 6858ff3 commit a02dacae093789471b601c378f6015690a527fc5 @benlangfeld benlangfeld committed Apr 25, 2011
View
@@ -8,6 +8,7 @@ gem 'will_paginate'
gem 'devise', '~> 1.1.8'
gem 'lighthouse-api'
gem 'redmine_client', :git => "git://github.com/oruen/redmine_client.git"
+gem 'pivotal-tracker'
platform :ruby do
gem 'bson_ext', '~> 1.2'
View
@@ -54,7 +54,10 @@ GEM
factory_girl (~> 1.3)
railties (>= 3.0.0)
haml (3.0.25)
+ happymapper (0.3.2)
+ libxml-ruby (~> 1.1.3)
i18n (0.5.0)
+ libxml-ruby (1.1.4)
lighthouse-api (2.0)
activeresource (>= 3.0.0)
activesupport (>= 3.0.0)
@@ -72,6 +75,11 @@ GEM
tzinfo (~> 0.3.22)
will_paginate (~> 3.0.pre)
nokogiri (1.4.4)
+ pivotal-tracker (0.2.0)
+ builder
+ happymapper (>= 0.2.4)
+ nokogiri (~> 1.4.1)
+ rest-client (~> 1.5.1)
polyglot (0.3.1)
rack (1.2.2)
rack-mount (0.6.13)
@@ -92,6 +100,8 @@ GEM
rake (>= 0.8.7)
thor (~> 0.14.4)
rake (0.8.7)
+ rest-client (1.5.1)
+ mime-types (>= 1.16)
rspec (2.5.0)
rspec-core (~> 2.5.0)
rspec-expectations (~> 2.5.0)
@@ -128,6 +138,7 @@ DEPENDENCIES
lighthouse-api
mongoid (~> 2.0.0.rc.7)
nokogiri
+ pivotal-tracker
rails (= 3.0.5)
redmine_client!
rspec (~> 2.5)
View
@@ -92,17 +92,23 @@ for you. Checkout [Hoptoad](http://hoptoadapp.com) from the guys over at
Lighthouseapp integration
-------------------------
-* Account is the name of your subdomain, i.e. **litcafe** for project at http://litcafe.lighthouseapp.com/projects/73466-face/overview
+* Account is the name of your subdomain, i.e. **litcafe** for project at http://litcafe.lighthouseapp.com/projects/73466-face/overview
* Errbit uses token-based authentication. Get your API Token or visit [http://help.lighthouseapp.com/kb/api/how-do-i-get-an-api-token](http://help.lighthouseapp.com/kb/api/how-do-i-get-an-api-token) to learn how to get it.
* Project id is number identifier of your project, i.e. **73466** for project at http://litcafe.lighthouseapp.com/projects/73466-face/overview
Redmine integration
-------------------------
-* Account is the host of your redmine installation, i.e. **http://redmine.org**
+* Account is the host of your redmine installation, i.e. **http://redmine.org**
* Errbit uses token-based authentication. Get your API Key or visit [http://www.redmine.org/projects/redmine/wiki/Rest_api#Authentication](http://www.redmine.org/projects/redmine/wiki/Rest_api#Authentication) to learn how to get it.
* Project id is an identifier of your project, i.e. **chilliproject** for project at http://www.redmine.org/projects/chilliproject
+Pivotal Tracker integration
+-------------------------
+
+* Errbit uses token-based authentication. Get your API Key or visit [http://www.pivotaltracker.com/help/api](http://www.pivotaltracker.com/help/api) to learn how to get it.
+* Project id is an identifier of your project, i.e. **24324** for project at http://www.pivotaltracker.com/projects/24324
+
TODO
----
@@ -2,4 +2,12 @@ module ApplicationHelper
def lighthouse_tracker? object
object.issue_tracker_type == "lighthouseapp"
end
+
+ def redmine_tracker? object
+ object.issue_tracker_type == "redmine"
+ end
+
+ def pivotal_tracker? object
+ object.issue_tracker_type == "pivotal"
+ end
end
View
@@ -1,7 +1,7 @@
class App
include Mongoid::Document
include Mongoid::Timestamps
-
+
field :name, :type => String
field :api_key
field :resolve_errs_on_deploy, :type => Boolean, :default => false
@@ -21,29 +21,29 @@ class App
embeds_many :deploys
embeds_one :issue_tracker
references_many :errs, :dependent => :destroy
-
+
before_validation :generate_api_key, :on => :create
-
+
validates_presence_of :name, :api_key
validates_uniqueness_of :name, :allow_blank => true
validates_uniqueness_of :api_key, :allow_blank => true
validates_associated :watchers
validate :check_issue_tracker
-
+
accepts_nested_attributes_for :watchers, :allow_destroy => true,
:reject_if => proc { |attrs| attrs[:user_id].blank? && attrs[:email].blank? }
accepts_nested_attributes_for :issue_tracker, :allow_destroy => true,
- :reject_if => proc { |attrs| !%w( lighthouseapp redmine ).include?(attrs[:issue_tracker_type]) }
-
+ :reject_if => proc { |attrs| !%w(lighthouseapp redmine pivotal).include?(attrs[:issue_tracker_type]) }
+
# Mongoid Bug: find(id) on association proxies returns an Enumerator
def self.find_by_id!(app_id)
where(:_id => app_id).first || raise(Mongoid::Errors::DocumentNotFound.new(self,app_id))
end
-
+
def self.find_by_api_key!(key)
where(:api_key => key).first || raise(Mongoid::Errors::DocumentNotFound.new(self,key))
end
-
+
def last_deploy_at
deploys.last && deploys.last.created_at
end
@@ -58,9 +58,9 @@ def notify_on_deploys
!(self[:notify_on_deploys] == false)
end
alias :notify_on_deploys? :notify_on_deploys
-
+
protected
-
+
def generate_api_key
self.api_key ||= ActiveSupport::SecureRandom.hex
end
@@ -6,7 +6,7 @@ class IssueTracker
default_url_options[:host] = Errbit::Application.config.action_mailer.default_url_options[:host]
validate :check_params
-
+
embedded_in :app, :inverse_of => :issue_tracker
field :account, :type => String
@@ -15,8 +15,14 @@ class IssueTracker
field :issue_tracker_type, :type => String, :default => 'lighthouseapp'
def create_issue err
- return create_lighthouseapp_issue err if issue_tracker_type == 'lighthouseapp'
- create_redmine_issue err if issue_tracker_type == 'redmine'
+ case issue_tracker_type
+ when 'lighthouseapp'
+ create_lighthouseapp_issue err
+ when 'redmine'
+ create_redmine_issue err
+ when 'pivotal'
+ create_pivotal_issue err
+ end
end
protected
@@ -34,6 +40,14 @@ def create_redmine_issue err
err.update_attribute :issue_link, "#{RedmineClient::Issue.site.to_s.sub(/#{RedmineClient::Issue.site.path}$/, '')}#{RedmineClient::Issue.element_path(issue.id, :project_id => project_id)}".sub(/\.xml\?project_id=#{project_id}$/, "\?project_id=#{project_id}")
end
+ def create_pivotal_issue err
+ PivotalTracker::Client.token = api_token
+ PivotalTracker::Client.use_ssl = true
+ project = PivotalTracker::Project.find project_id.to_i
+ story = project.stories.create :name => issue_title(err), :story_type => 'bug', :description => self.class.pivotal_body_template.result(binding)
+ err.update_attribute :issue_link, "https://www.pivotaltracker.com/story/show/#{story.id}"
+ end
+
def create_lighthouseapp_issue err
Lighthouse.account = account
Lighthouse.token = api_token
@@ -56,12 +70,17 @@ def issue_title err
end
def check_params
- blank_flags = %w( api_token project_id account ).map {|m| self[m].blank? }
+ blank_flag_fields = %w(api_token project_id)
+ blank_flag_fields << 'account' if %w(lighthouseapp redmine).include? issue_tracker_type
+ blank_flags = blank_flag_fields.map {|m| self[m].blank? }
if blank_flags.any? && !blank_flags.all?
- message = if issue_tracker_type == 'lighthouseapp'
+ message = case issue_tracker_type
+ when 'lighthouseapp'
"You must specify your Lighthouseapp account, api token and project id"
- else
+ when 'redmine'
"You must specify your Redmine url, api token and project id"
+ when 'pivotal'
+ "You must specify your Pivotal Tracker api token and project id"
end
errors.add(:base, message)
end
@@ -71,9 +90,13 @@ class << self
def lighthouseapp_body_template
@@lighthouseapp_body_template ||= ERB.new(File.read(Rails.root + "app/views/errs/lighthouseapp_body.txt.erb").gsub(/^\s*/, ''))
end
-
+
def redmine_body_template
@@redmine_body_template ||= ERB.new(File.read(Rails.root + "app/views/errs/redmine_body.txt.erb"))
end
+
+ def pivotal_body_template
+ @@pivotal_body_template ||= ERB.new(File.read(Rails.root + "app/views/errs/pivotal_body.txt.erb"))
+ end
end
end
@@ -3,7 +3,7 @@
%div.required
= f.label :name
= f.text_field :name
-
+
%div.checkbox
= f.check_box :notify_on_errs
= f.label :notify_on_errs, 'Notify on errors'
@@ -39,19 +39,24 @@
= label_tag :issue_tracker_type_lighthouseapp, 'Lighthouse', :for => label_for_attr(w, 'issue_tracker_type_lighthouseapp')
= w.radio_button :issue_tracker_type, :redmine
= label_tag :issue_tracker_type_redmine, 'Redmine', :for => label_for_attr(w, 'issue_tracker_type_redmine')
- %div.tracker_params{:class => lighthouse_tracker?(w.object) ? 'choosen' : nil}
+ = w.radio_button :issue_tracker_type, :pivotal
+ = label_tag :issue_tracker_type_pivotal, 'Pivotal Tracker', :for => label_for_attr(w, 'issue_tracker_type_pivotal')
+ %div.tracker_params.lighthouseapp{:class => lighthouse_tracker?(w.object) ? 'chosen' : nil}
= w.label :account, "Account"
= w.text_field :account, :placeholder => "abc from abc.lighthouseapp.com"
= w.label :api_token, "API token"
= w.text_field :api_token, :placeholder => "API Token for your account"
= w.label :project_id, "Project ID"
= w.text_field :project_id, :placeholder => "123 from abc from abc.lighthouseapp.com/projects/123"
- %div.tracker_params{:class => lighthouse_tracker?(w.object) ? nil : 'choosen'}
+ %div.tracker_params.redmine{:class => redmine_tracker?(w.object) ? 'chosen' : nil}
= w.label :account, "Redmine URL"
= w.text_field :account, :placeholder => "like http://www.redmine.org/"
= w.label :api_token, "API token"
= w.text_field :api_token, :placeholder => "API Token for your account"
= w.label :project_id, "Project ID"
= w.text_field :project_id
-
-
+ %div.tracker_params.pivotal{:class => pivotal_tracker?(w.object) ? 'chosen' : nil}
+ = w.label :project_id, "Project ID"
+ = w.text_field :project_id
+ = w.label :api_token, "API token"
+ = w.text_field :api_token, :placeholder => "API Token for your account"
@@ -0,0 +1,21 @@
+See this exception on Errbit: <%= app_err_url err.app, err %>
+<% if notice = err.notices.first %>
+ <% if notice.request['url'].present? %>URL: <%= notice.request['url'] %><% end %>
+ Where: <%= notice.err.where %>
+ Occurred: <%= notice.created_at.to_s :micro %>
+ Similar: <%= (notice.err.notices.count - 1).to_s %>
+
+ Params:
+ <%= pretty_hash notice.params %>
+
+ Session:
+ <%= pretty_hash notice.session %>
+
+ Backtrace:
+ <%= notice.backtrace.map { |line| "#{line['number']}: #{line['file'].sub(/^\[PROJECT_ROOT\]/, '')} -> *#{line['method']}*" }.join "\n" %>
+
+ Environment:
+ <% notice.env_vars.each do |key, val| %>
+ <%= "#{key}: #{val}" %>
+ <% end %>
+<% end %>
View
@@ -1,6 +1,6 @@
$(function(){
activateNestedForms();
-
+
if($('div.watcher.nested').length)
activateWatcherTypeSelector();
@@ -11,9 +11,9 @@ $(function(){
function activateNestedForms() {
$('.nested-wrapper').each(function(){
var wrapper = $(this);
-
+
makeNestedItemsDestroyable(wrapper);
-
+
var addLink = $('<a/>').text('add another').addClass('add-nested');
addLink.click(appendNestedItem);
wrapper.append(addLink);
@@ -35,7 +35,7 @@ function appendNestedItem() {
var nestedItem = addLink.parent().find('.nested').first().clone().show();
var timestamp = new Date();
timestamp = timestamp.valueOf();
-
+
nestedItem.find('input, select').each(function(){
var input = $(this);
input.attr('id', input.attr('id').replace(/([_\[])\d+([\]_])/,'$1'+timestamp+'$2'));
@@ -73,17 +73,10 @@ function activateWatcherTypeSelector() {
}
function activateIssueTrackerTypeSelector() {
- var not_choosen = $("div.tracker_params").filter(function () {
- return !$(this).hasClass("choosen");
- });
- window.hiddenTracker = not_choosen.html();
- not_choosen.remove();
$('div.issue_tracker input[name*=issue_tracker_type]').live('click', function(){
- var choosen = $(this).val();
+ var chosen = $(this).val();
var wrapper = $(this).closest('.nested');
- var tmp;
- tmp = wrapper.find('div.choosen').html();
- wrapper.find('div.choosen').html(window.hiddenTracker);
- window.hiddenTracker = tmp;
+ wrapper.find('div.chosen').removeClass('chosen');
+ wrapper.find('div.'+chosen).addClass('chosen');
});
}
Oops, something went wrong.

0 comments on commit a02daca

Please sign in to comment.