Commit 6c7ee3be8cbccd84a97c222afb07f1337c8f39a6
Exists in
master
and in
1 other branch
Merge pull request #428 from parallel588/master
Unfuddle Tracker
Showing
9 changed files
with
181 additions
and
1 deletions
Show diff stats
Gemfile
| ... | ... | @@ -43,6 +43,10 @@ gem 'gitlab', :git => 'https://github.com/NARKOZ/gitlab.git' |
| 43 | 43 | # Bitbucket Issues |
| 44 | 44 | gem 'bitbucket_rest_api' |
| 45 | 45 | |
| 46 | +# Unfuddle | |
| 47 | +gem "taskmapper", "~> 0.8.0" | |
| 48 | +gem "taskmapper-unfuddle", "~> 0.7.0" | |
| 49 | + | |
| 46 | 50 | # Notification services |
| 47 | 51 | # --------------------------------------- |
| 48 | 52 | # Campfire ( We can't upgrade to 1.0 because drop support of ruby 1.8 | ... | ... |
Gemfile.lock
| ... | ... | @@ -323,6 +323,13 @@ GEM |
| 323 | 323 | multi_json (~> 1.0) |
| 324 | 324 | rack (~> 1.0) |
| 325 | 325 | tilt (~> 1.1, != 1.3.0) |
| 326 | + taskmapper (0.8.0) | |
| 327 | + activeresource (~> 3.0) | |
| 328 | + activesupport (~> 3.0) | |
| 329 | + hashie (~> 1.2) | |
| 330 | + taskmapper-unfuddle (0.7.0) | |
| 331 | + addressable (~> 2.2) | |
| 332 | + taskmapper (~> 0.8) | |
| 326 | 333 | therubyracer (0.11.4) |
| 327 | 334 | libv8 (~> 3.11.8.12) |
| 328 | 335 | ref |
| ... | ... | @@ -414,6 +421,8 @@ DEPENDENCIES |
| 414 | 421 | ruby-debug |
| 415 | 422 | ruby-fogbugz |
| 416 | 423 | rushover |
| 424 | + taskmapper (~> 0.8.0) | |
| 425 | + taskmapper-unfuddle (~> 0.7.0) | |
| 417 | 426 | therubyracer |
| 418 | 427 | thin |
| 419 | 428 | timecop | ... | ... |
2.29 KB
2.29 KB
2.11 KB
app/models/issue_tracker.rb
| ... | ... | @@ -15,6 +15,7 @@ class IssueTracker |
| 15 | 15 | field :password, :type => String |
| 16 | 16 | field :ticket_properties, :type => String |
| 17 | 17 | field :subdomain, :type => String |
| 18 | + field :milestone_id, :type => String | |
| 18 | 19 | |
| 19 | 20 | validate :check_params |
| 20 | 21 | |
| ... | ... | @@ -40,4 +41,3 @@ class IssueTracker |
| 40 | 41 | project_id.present? |
| 41 | 42 | end |
| 42 | 43 | end |
| 43 | - | ... | ... |
| ... | ... | @@ -0,0 +1,69 @@ |
| 1 | +class IssueTrackers::UnfuddleTracker < IssueTracker | |
| 2 | + Label = "unfuddle" | |
| 3 | + Fields = [ | |
| 4 | + | |
| 5 | + [:account, { | |
| 6 | + :placeholder => "Your domain" | |
| 7 | + }], | |
| 8 | + | |
| 9 | + | |
| 10 | + [:username, { | |
| 11 | + :placeholder => "Your username" | |
| 12 | + }], | |
| 13 | + | |
| 14 | + [:password, { | |
| 15 | + :placeholder => "Your password" | |
| 16 | + }], | |
| 17 | + | |
| 18 | + [:project_id, { | |
| 19 | + :label => "Ticket Project", | |
| 20 | + :placeholder => "Project where tickets will be created" | |
| 21 | + }], | |
| 22 | + | |
| 23 | + [:milestone_id, { | |
| 24 | + :optional => true, | |
| 25 | + :label => "Ticket Milestone", | |
| 26 | + :placeholder => "Milestone where tickets will be created" | |
| 27 | + }] | |
| 28 | + | |
| 29 | + | |
| 30 | + ] | |
| 31 | + | |
| 32 | + def check_params | |
| 33 | + if Fields.detect {|f| self[f[0]].blank? && !f[1][:optional]} | |
| 34 | + errors.add :base, 'You must specify your Account, Username, Password and Project ID' | |
| 35 | + end | |
| 36 | + end | |
| 37 | + | |
| 38 | + def create_issue(problem, reported_by = nil) | |
| 39 | + unfuddle = TaskMapper.new(:unfuddle, :username => username, :password => password, :account => account) | |
| 40 | + | |
| 41 | + begin | |
| 42 | + issue_options = {:project_id => project_id, | |
| 43 | + :summary => issue_title(problem), | |
| 44 | + :priority => '5', | |
| 45 | + :status => "new", | |
| 46 | + :description => body_template.result(binding), | |
| 47 | + 'description-format' => 'textile' } | |
| 48 | + | |
| 49 | + issue_options[:milestone_id] = milestone_id if milestone_id.present? | |
| 50 | + | |
| 51 | + issue = unfuddle.project(project_id.to_i).ticket!(issue_options) | |
| 52 | + problem.update_attributes( | |
| 53 | + :issue_link => "https://#{account}.unfuddle.com/projects/#{project_id}/tickets/#{issue['id']}", | |
| 54 | + :issue_type => Label | |
| 55 | + ) | |
| 56 | + rescue ActiveResource::UnauthorizedAccess | |
| 57 | + raise ActiveResource::UnauthorizedAccess, "Could not authenticate with Unfuddle. Please check your username and password." | |
| 58 | + end | |
| 59 | + | |
| 60 | + end | |
| 61 | + | |
| 62 | + def body_template | |
| 63 | + @@body_template ||= ERB.new(File.read(Rails.root + "app/views/issue_trackers/textile_body.txt.erb")) | |
| 64 | + end | |
| 65 | + | |
| 66 | + def url | |
| 67 | + "https://devmen.unfuddle.com/projects/#{project_id}" | |
| 68 | + end | |
| 69 | +end | ... | ... |
spec/fabricators/issue_tracker_fabricator.rb
| ... | ... | @@ -33,3 +33,8 @@ Fabricator :bitbucket_issues_tracker, :from => :issue_tracker, :class_name => "I |
| 33 | 33 | project_id 'password' |
| 34 | 34 | api_token 'test_username' |
| 35 | 35 | end |
| 36 | + | |
| 37 | +Fabricator :unfuddle_issues_tracker, :from => :issue_tracker, :class_name => "IssueTrackers::UnfuddleTracker" do | |
| 38 | + account 'test' | |
| 39 | + project_id 15 | |
| 40 | +end | ... | ... |
spec/models/issue_trackers/unfuddle_issues_tracker_spec.rb
0 → 100644
| ... | ... | @@ -0,0 +1,93 @@ |
| 1 | +require 'spec_helper' | |
| 2 | + | |
| 3 | +describe IssueTrackers::UnfuddleTracker do | |
| 4 | + it "should create an issue on Unfuddle Issues with problem params, and set issue link for problem" do | |
| 5 | + repo = "test_user/test_repo" | |
| 6 | + notice = Fabricate :notice | |
| 7 | + tracker = Fabricate :unfuddle_issues_tracker, :app => notice.app | |
| 8 | + problem = notice.problem | |
| 9 | + | |
| 10 | + number = 123 | |
| 11 | + @issue_link = "https://test.unfuddle.com/projects/15/tickets/2436" | |
| 12 | + | |
| 13 | +project_xml = <<EOF | |
| 14 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 15 | +<project> | |
| 16 | + <account-id type="integer">1</account-id> | |
| 17 | + <archived type="boolean">false</archived> | |
| 18 | + <assignee-on-resolve>reporter</assignee-on-resolve> | |
| 19 | + <backup-frequency type="integer">0</backup-frequency> | |
| 20 | + <close-ticket-simultaneously-default type="boolean">false</close-ticket-simultaneously-default> | |
| 21 | + <default-ticket-report-id type="integer" nil="true"></default-ticket-report-id> | |
| 22 | + <description nil="true"></description> | |
| 23 | + <disk-usage type="integer">27932</disk-usage> | |
| 24 | + <enable-time-tracking type="boolean">true</enable-time-tracking> | |
| 25 | + <id type="integer">#{tracker.project_id}</id> | |
| 26 | + <s3-access-key-id></s3-access-key-id> | |
| 27 | + <s3-backup-enabled type="boolean">false</s3-backup-enabled> | |
| 28 | + <s3-bucket-name></s3-bucket-name> | |
| 29 | + <short-name>test-project</short-name> | |
| 30 | + <theme>blue</theme> | |
| 31 | + <ticket-field1-active type="boolean">false</ticket-field1-active> | |
| 32 | + <ticket-field1-disposition>text</ticket-field1-disposition> | |
| 33 | + <ticket-field1-title>Field 1</ticket-field1-title> | |
| 34 | + <ticket-field2-active type="boolean">false</ticket-field2-active> | |
| 35 | + <ticket-field2-disposition>text</ticket-field2-disposition> | |
| 36 | + <ticket-field2-title>Field 2</ticket-field2-title> | |
| 37 | + <ticket-field3-active type="boolean">false</ticket-field3-active> | |
| 38 | + <ticket-field3-disposition>text</ticket-field3-disposition> | |
| 39 | + <ticket-field3-title>Field 3</ticket-field3-title> | |
| 40 | + <title>test-project</title> | |
| 41 | + <created-at>2011-04-25T09:21:43Z</created-at> | |
| 42 | + <updated-at>2013-03-08T08:03:02Z</updated-at> | |
| 43 | +</project> | |
| 44 | +EOF | |
| 45 | + | |
| 46 | + ticket_xml =<<EOF | |
| 47 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 48 | +<ticket> | |
| 49 | + <assignee-id type="integer">40</assignee-id> | |
| 50 | + <component-id type="integer" nil="true"></component-id> | |
| 51 | + <description nil="true"></description> | |
| 52 | + <description-format>markdown</description-format> | |
| 53 | + <due-on type="date" nil="true"></due-on> | |
| 54 | + <field1-value-id type="integer" nil="true"></field1-value-id> | |
| 55 | + <field2-value-id type="integer" nil="true"></field2-value-id> | |
| 56 | + <field3-value-id type="integer" nil="true"></field3-value-id> | |
| 57 | + <hours-estimate-current type="float">1268.7</hours-estimate-current> | |
| 58 | + <hours-estimate-initial type="float">0.0</hours-estimate-initial> | |
| 59 | + <id type="integer">2436</id> | |
| 60 | + <milestone-id type="integer">78</milestone-id> | |
| 61 | + <number type="integer">119</number> | |
| 62 | + <priority>3</priority> | |
| 63 | + <project-id type="integer">15</project-id> | |
| 64 | + <reporter-id type="integer">40</reporter-id> | |
| 65 | + <resolution></resolution> | |
| 66 | + <resolution-description></resolution-description> | |
| 67 | + <resolution-description-format>markdown</resolution-description-format> | |
| 68 | + <severity-id type="integer" nil="true"></severity-id> | |
| 69 | + <status>reopened</status> | |
| 70 | + <summary>TEST-ticket.</summary> | |
| 71 | + <version-id type="integer" nil="true"></version-id> | |
| 72 | + <created-at>2012-06-27T17:49:06Z</created-at> | |
| 73 | + <updated-at>2013-03-07T16:04:05Z</updated-at> | |
| 74 | +</ticket> | |
| 75 | +EOF | |
| 76 | + stub_request(:get, "https://#{tracker.username}:#{tracker.password}@test.unfuddle.com/api/v1/projects/#{tracker.project_id}.xml"). | |
| 77 | + with(:headers => {'Accept'=>'application/xml', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}). | |
| 78 | + to_return(:status => 200, :body => project_xml, :headers => {}) | |
| 79 | + | |
| 80 | + | |
| 81 | + stub_request(:post, "https://#{tracker.username}:#{tracker.password}@test.unfuddle.com/api/v1/projects/#{tracker.project_id}/tickets.xml"). | |
| 82 | + to_return(:status => 200, :body => ticket_xml, :headers => {}) | |
| 83 | + | |
| 84 | + problem.app.issue_tracker.create_issue(problem) | |
| 85 | + problem.reload | |
| 86 | + | |
| 87 | + requested = have_requested(:post,"https://#{tracker.username}:#{tracker.password}@test.unfuddle.com/api/v1/projects/#{tracker.project_id}/tickets.xml" ) | |
| 88 | + WebMock.should requested.with(:title => /[production][foo#bar] FooError: Too Much Bar/) | |
| 89 | + WebMock.should requested.with(:content => /See this exception on Errbit/) | |
| 90 | + | |
| 91 | + problem.issue_link.should == @issue_link | |
| 92 | + end | |
| 93 | +end | ... | ... |