Commit 6c7ee3be8cbccd84a97c222afb07f1337c8f39a6

Authored by Cyril Mougel
2 parents bd5e76aa 09f89ac8
Exists in master and in 1 other branch production

Merge pull request #428 from parallel588/master

Unfuddle Tracker
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
... ...
app/assets/images/unfuddle_create.png 0 → 100644

2.29 KB

app/assets/images/unfuddle_goto.png 0 → 100644

2.29 KB

app/assets/images/unfuddle_inactive.png 0 → 100644

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   -
... ...
app/models/issue_trackers/unfuddle_tracker.rb 0 → 100644
... ... @@ -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 =&gt; :issue_tracker, :class_name =&gt; &quot;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
... ...