trackinator 0.0.13 → 0.0.14

Sign up to get free protection for your applications and to get access to all the features.
data/bin/trackinate CHANGED
@@ -13,6 +13,7 @@ opts = Trollop::options do
13
13
  opt :port, "YouTrack port", :type => :int, :default => 80, :short => "r"
14
14
  opt :path_prefix, "YouTrack path prefix (e.g. '/youtrack/')", :type => :string, :default => "/", :short =>"e"
15
15
  opt :create_rc, "Create a .trackinatorrc file in your home dir", :default => false, :short => "c"
16
+ opt :dry_run, "Try it out but don't actually import", :default => false, :short => "d"
16
17
  end
17
18
 
18
19
  unless opts[:create_rc]
@@ -36,7 +37,9 @@ Trollop::die :google_password, "is required" if opts[:google_password].nil?
36
37
  Trollop::die :host, "is required" if opts[:host].nil?
37
38
 
38
39
  you_track = Trackinator::YouTrack.new opts
39
- google = Trackinator::Google.new opts
40
+ you_track.login(opts[:youtrack_username], opts[:youtrack_password])
41
+ google = Trackinator::Google.new(GData::Client::Spreadsheets.new)
42
+ google.login(opts)
40
43
 
41
44
  Trollop::die "Check your YouTrack credentials and try again" unless you_track.is_logged_in?
42
45
  Trollop::die "Check your Google credentials and try again" unless google.is_logged_in?
@@ -63,6 +66,7 @@ end
63
66
 
64
67
  if ARGV.length == 1
65
68
  importer = Trackinator::Importer.new you_track, google
69
+ importer.dry_run = opts[:dry_run]
66
70
  issues = importer.import(ARGV[0])
67
71
 
68
72
  if issues.length > 0
@@ -70,4 +74,6 @@ if ARGV.length == 1
70
74
  p issue
71
75
  end
72
76
  end
77
+
78
+ puts "done..."
73
79
  end
@@ -1,10 +1,13 @@
1
1
  module Trackinator
2
2
  class Google
3
- def initialize opts
4
- @client = GData::Client::Spreadsheets.new
3
+ def initialize client
4
+ @client = client
5
+ end
6
+
7
+ def login opts
5
8
  begin
6
9
  @token = @client.clientlogin(opts[:google_username], opts[:google_password])
7
- rescue
10
+ rescue Exception => e
8
11
  @token = nil
9
12
  end
10
13
  end
@@ -16,9 +19,7 @@ module Trackinator
16
19
  def get_tickets file_name
17
20
  puts "reading document..."
18
21
 
19
- spreadsheet_feed = @client.get("http://spreadsheets.google.com/feeds/worksheets/#{get_spreadsheet_key(file_name)}/private/full").to_xml
20
- spreadsheet_list_data = @client.get(spreadsheet_feed.elements[1, 'entry'].elements[1, 'content'].attributes['src']).to_xml
21
-
22
+ spreadsheet_list_data = get_spreadsheet_list_data file_name
22
23
  tickets = []
23
24
 
24
25
  spreadsheet_list_data.elements.each('entry') do |entry|
@@ -30,6 +31,12 @@ module Trackinator
30
31
 
31
32
  private
32
33
 
34
+ def get_spreadsheet_list_data file_name
35
+ spreadsheet_feed = @client.get("http://spreadsheets.google.com/feeds/worksheets/#{get_spreadsheet_key(file_name)}/private/full").to_xml
36
+ spreadsheet_list_url = spreadsheet_feed.elements[1, 'entry'].elements[1, 'content'].attributes['src']
37
+ @client.get(spreadsheet_list_url).to_xml
38
+ end
39
+
33
40
  def get_spreadsheet_key file_name
34
41
  doc_feed = @client.get("http://spreadsheets.google.com/feeds/spreadsheets/private/full").to_xml
35
42
 
@@ -8,6 +8,8 @@ require 'trackinator'
8
8
  module Trackinator
9
9
  class Importer
10
10
 
11
+ attr_accessor :dry_run
12
+
11
13
  def initialize you_track, google
12
14
  @you_track = you_track
13
15
  @google = google
@@ -18,7 +20,7 @@ module Trackinator
18
20
 
19
21
  issues = validate_tickets(ticket_data)
20
22
 
21
- if issues.length == 0
23
+ if issues.length == 0 && !@dry_run
22
24
  puts "importing..."
23
25
 
24
26
  ticket_data.each do |entry|
@@ -27,8 +29,6 @@ module Trackinator
27
29
  end
28
30
  end
29
31
 
30
- puts "done..."
31
-
32
32
  issues
33
33
  end
34
34
 
@@ -38,12 +38,17 @@ module Trackinator
38
38
  puts "validating..."
39
39
  issues = []
40
40
 
41
+ if tickets.length == 0
42
+ return issues
43
+ end
44
+
41
45
  project = tickets[0]['project']
42
46
 
43
47
  issues.concat(@you_track.project_exists?(project))
44
48
 
45
49
  tickets.each do |ticket|
46
50
  issues.concat(@you_track.you_track_fields_defined?(project, ticket.keys.collect! { |key| key.downcase }))
51
+
47
52
  issues.concat(validate_fields(ticket))
48
53
  issues.concat(validate_formats(ticket))
49
54
  end
@@ -67,12 +72,16 @@ module Trackinator
67
72
  issues = []
68
73
 
69
74
  ticket.keys.each do |key|
70
- if Trackinator.const_defined?("#{key.upcase}") && Trackinator.const_get("#{key.upcase}").match(ticket[key].downcase).nil?
71
- issues << "Validation Error: Ticket with ID: #{ticket["id"]} has field '#{key}' with invalid format"
72
- end
75
+ validate_format(key, ticket[key])
73
76
  end
74
77
 
75
78
  issues
76
79
  end
80
+
81
+ def validate_format key, value
82
+ if Trackinator.const_defined?("#{key.upcase}") && Trackinator.const_get("#{key.upcase}").match(value.downcase).nil?
83
+ issues << "Validation Error: Ticket with ID: #{ticket["id"]} has field '#{key}' with invalid format"
84
+ end
85
+ end
77
86
  end
78
87
  end
@@ -1,3 +1,3 @@
1
1
  module Trackinator
2
- VERSION = "0.0.13"
2
+ VERSION = "0.0.14"
3
3
  end
@@ -9,8 +9,6 @@ module Trackinator
9
9
  @host = opts[:host]
10
10
  @port = opts[:port]
11
11
  @path_prefix = opts[:path_prefix]
12
-
13
- login opts[:youtrack_username], opts[:youtrack_password]
14
12
  end
15
13
 
16
14
  def is_logged_in?
@@ -34,7 +32,7 @@ module Trackinator
34
32
  end
35
33
 
36
34
  def update_ticket issue_id, data
37
- success = set_platform(issue_id, data['platform'])
35
+ success = set_subsystem(issue_id, data['subsystem'])
38
36
  success ? (success = set_summary_and_description(issue_id, data['summary'], data['description'], data['outcome'])) : (return success)
39
37
  success ? (success = set_type(issue_id, data['type'])) : (return success)
40
38
  success ? (success = set_import_identifier(issue_id, "#{data['project']}-#{data['id']}")) : (return success)
@@ -78,7 +76,7 @@ module Trackinator
78
76
  end
79
77
 
80
78
  def is_issue_exists? data
81
- find_response_xml = REXML::Document.new(@connection.get("#{@path_prefix}rest/issue/byproject/#{data['project']}?filter=Import+Identifier:+#{data['project']}-#{data['id']}", { 'Cookie' => @cookie, 'Content-Type' => 'text/plain; charset=utf-8' }).body)
79
+ find_response_xml = REXML::Document.new(@connection.get("#{@path_prefix}rest/issue/byproject/#{data['project']}?filter=Import+Identifier:+#{data['project']}-#{data['id']}+Subsystem:+#{data['subsystem']}", { 'Cookie' => @cookie, 'Content-Type' => 'text/plain; charset=utf-8' }).body)
82
80
  find_response_xml.elements['issues'].length > 0 ? find_response_xml.elements['issues/issue'].attributes['id'] : nil
83
81
  end
84
82
 
@@ -122,10 +120,10 @@ module Trackinator
122
120
  response.header.msg.eql? "OK"
123
121
  end
124
122
 
125
- def set_platform issue_id, platform
126
- return true if platform.nil?
123
+ def set_subsystem issue_id, subsystem
124
+ return true if subsystem.nil?
127
125
 
128
- response = @connection.post("#{@path_prefix}rest/issue/#{issue_id}/execute?command=Platform+#{URI.escape(platform)}&disableNotifications=true", nil, { 'Cookie' => @cookie })
126
+ response = @connection.post("#{@path_prefix}rest/issue/#{issue_id}/execute?command=Subsystem+#{URI.escape(subsystem)}&disableNotifications=true", nil, { 'Cookie' => @cookie })
129
127
  response.header.msg.eql? "OK"
130
128
  end
131
129
 
data/lib/trackinator.rb CHANGED
@@ -11,6 +11,8 @@ module Trackinator
11
11
 
12
12
  PRIORITY = /^low$|^normal$|^high$|^show-stopper$/
13
13
 
14
+ SUBSYSTEM = /^android$|^backend$|^ios$/
15
+
14
16
  REQUIRED = %w{
15
17
  project
16
18
  id
@@ -2,6 +2,65 @@ require File.expand_path(File.dirname(__FILE__)) + '/../spec_helper'
2
2
 
3
3
  module Trackinator
4
4
  describe Google do
5
- pending "write it"
5
+ context "login" do
6
+ before(:each) do
7
+ @client = mock(GData::Client::Spreadsheets)
8
+ @google = Google.new(@client)
9
+ end
10
+
11
+ it "#login should assign a token" do
12
+ @client.stub!(:clientlogin).and_return(true)
13
+ @google.login({})
14
+ @google.is_logged_in?.should == true
15
+ end
16
+
17
+ it "#login should not assign a token" do
18
+ @client.stub!(:clientlogin).and_raise(Exception.new)
19
+ @google.login({})
20
+ @google.is_logged_in?.should == false
21
+ end
22
+ end
23
+
24
+ context "get_tickets" do
25
+ before(:each) do
26
+ @client = mock(GData::Client::Spreadsheets)
27
+ @google = Google.new(@client)
28
+ @spreadsheet_list_data = mock(REXML::Document)
29
+ @spreadsheet_list_data.stub!(:elements).and_return(@spreadsheet_list_data)
30
+ @google.stub!(:get_spreadsheet_list_data).and_return(@spreadsheet_list_data)
31
+ @google.stub!(:get_ticket_data).and_return( {"foo" => "bar"} )
32
+ end
33
+
34
+ it "#get_tickets should return an empty array" do
35
+ @spreadsheet_list_data.stub!(:each).with("entry")
36
+ tickets = @google.get_tickets("filename")
37
+ tickets.length.should == 0
38
+ end
39
+
40
+ it "#get_tickets should return an array of 1" do
41
+ @spreadsheet_list_data.stub!(:each).with("entry").and_yield(%{entry})
42
+ tickets = @google.get_tickets("filename")
43
+ tickets.length.should == 1
44
+ tickets[0]["foo"].should == "bar"
45
+ end
46
+ end
47
+
48
+ context "get_spreadsheet_list_data" do
49
+ it "#get_spreadsheet_list_data should do something" do
50
+ pending
51
+ end
52
+ end
53
+
54
+ context "get_spreadsheet_key" do
55
+ it "#get_spreadsheet_key should do something" do
56
+ pending
57
+ end
58
+ end
59
+
60
+ context "get_ticket_data" do
61
+ it "#get_ticket_data should do something" do
62
+ pending
63
+ end
64
+ end
6
65
  end
7
66
  end
@@ -2,6 +2,147 @@ require File.expand_path(File.dirname(__FILE__)) + '/../spec_helper'
2
2
 
3
3
  module Trackinator
4
4
  describe Importer do
5
- pending "write it"
5
+ context "import" do
6
+ before(:each) do
7
+ @google = mock(Google)
8
+
9
+ @you_track = mock(YouTrack)
10
+ @you_track.stub!(:is_issue_exists?).and_return(nil)
11
+ @you_track.stub!(:create_ticket).and_return(true)
12
+
13
+ @importer = Importer.new @you_track, @google
14
+ @importer.stub!(:validate_tickets).and_return([])
15
+ end
16
+
17
+ it "#import should return no issues and import" do
18
+ @google.stub!(:get_tickets).and_return([{"type" => "story"}])
19
+ $stdout.should_receive(:puts).with("importing...")
20
+
21
+ issues = @importer.import "filename"
22
+ issues.should == []
23
+ end
24
+
25
+ it "#import should return no issues and not import" do
26
+ @google.stub!(:get_tickets).and_return([])
27
+ $stdout.should_receive(:puts).with("importing...")
28
+
29
+ issues = @importer.import "filename"
30
+ issues.should == []
31
+ end
32
+ end
33
+
34
+ context "validate_tickets" do
35
+ before(:each) do
36
+ @you_track = mock(YouTrack)
37
+ @you_track.stub!(:project_exists?).and_return([])
38
+ @you_track.stub!(:you_track_fields_defined?).and_return([])
39
+
40
+ @google = mock(Google)
41
+
42
+ @importer = Importer.new @you_track, @google
43
+ end
44
+
45
+ it "#validate_tickets should return no issues and validate" do
46
+ @importer.stub!(:validate_fields).and_return([])
47
+ @importer.stub!(:validate_formats).and_return([])
48
+
49
+ issues = @importer.send(:validate_tickets, [{}])
50
+ issues.should == []
51
+ end
52
+
53
+ it "#validate_tickets should return no issues and not validate" do
54
+ @importer.stub!(:validate_fields).and_return([])
55
+ @importer.stub!(:validate_formats).and_return([])
56
+
57
+ issues = @importer.send(:validate_tickets, [])
58
+ issues.should == []
59
+ end
60
+ end
61
+
62
+ context "validate_fields" do
63
+ before(:each) do
64
+ @you_track = mock(YouTrack)
65
+ @google = mock(Google)
66
+
67
+ @importer = Importer.new @you_track, @google
68
+ end
69
+
70
+ it "#validate_fields should return no issues and validate feature" do
71
+ issues = @importer.send(:validate_fields, { "type" => "feature", "project" => "YTTP", "id" => "1.2", "summary" => "A summary", "description" => "A description", "outcome" => "An outcome" })
72
+ issues.should == []
73
+ end
74
+
75
+ it "#validate_fields should return 1 issue: missing project" do
76
+ issues = @importer.send(:validate_fields, { "type" => "feature", "id" => "1.2", "summary" => "A summary", "description" => "A description", "outcome" => "An outcome" })
77
+ issues.size.should == 1
78
+ issues[0].should == "Validation Error: Ticket with ID: 1.2 is missing required field 'project'"
79
+ end
80
+
81
+ it "#validate_fields should return 1 issue: missing id" do
82
+ issues = @importer.send(:validate_fields, { "type" => "feature", "project" => "YTTP", "summary" => "A summary", "description" => "A description", "outcome" => "An outcome" })
83
+ issues.size.should == 1
84
+ issues[0].should == "Validation Error: Ticket with ID: is missing required field 'id'"
85
+ end
86
+
87
+ it "#validate_fields should return 1 issue: missing summary" do
88
+ issues = @importer.send(:validate_fields, { "type" => "feature", "project" => "YTTP", "id" => "1.2", "description" => "A description", "outcome" => "An outcome" })
89
+ issues.size.should == 1
90
+ issues[0].should == "Validation Error: Ticket with ID: 1.2 is missing required field 'summary'"
91
+ end
92
+
93
+ it "#validate_fields should return 1 issue: missing description" do
94
+ issues = @importer.send(:validate_fields, { "type" => "feature", "project" => "YTTP", "id" => "1.2", "summary" => "A summary", "outcome" => "An outcome" })
95
+ issues.size.should == 1
96
+ issues[0].should == "Validation Error: Ticket with ID: 1.2 is missing required field 'description'"
97
+ end
98
+
99
+ it "#validate_fields should return 1 issue: missing outcome" do
100
+ issues = @importer.send(:validate_fields, { "type" => "feature", "project" => "YTTP", "id" => "1.2", "summary" => "A summary", "description" => "A description" })
101
+ issues.size.should == 1
102
+ issues[0].should == "Validation Error: Ticket with ID: 1.2 is missing required field 'outcome'"
103
+ end
104
+ end
105
+
106
+ context "validate_formats" do
107
+ before(:each) do
108
+ @you_track = mock(YouTrack)
109
+ @google = mock(Google)
110
+
111
+ @importer = Importer.new @you_track, @google
112
+ end
113
+
114
+ it "#validate_formats should return no issues and validate" do
115
+ issues = @importer.send(:validate_formats, { "type" => "feature" })
116
+ issues.should == []
117
+ end
118
+
119
+ it "#validate_formats should return no issues and validate" do
120
+ issues = @importer.send(:validate_formats, { "type" => "foo" })
121
+ issues.size.should == 1
122
+ issues[0].should == "Validation Error: Ticket with ID: has field 'type' with invalid format"
123
+ end
124
+
125
+ it "#validate_formats should return no issues and validate" do
126
+ issues = @importer.send(:validate_formats, { "id" => "1.2" })
127
+ issues.should == []
128
+ end
129
+
130
+ it "#validate_formats should return no issues and validate" do
131
+ issues = @importer.send(:validate_formats, { "id" => "junk" })
132
+ issues.size.should == 1
133
+ issues[0].should == "Validation Error: Ticket with ID: junk has field 'id' with invalid format"
134
+ end
135
+
136
+ it "#validate_formats should return no issues and validate" do
137
+ issues = @importer.send(:validate_formats, { "priority" => "normal" })
138
+ issues.should == []
139
+ end
140
+
141
+ it "#validate_formats should return no issues and validate" do
142
+ issues = @importer.send(:validate_formats, { "priority" => "junk" })
143
+ issues.size.should == 1
144
+ issues[0].should == "Validation Error: Ticket with ID: has field 'priority' with invalid format"
145
+ end
146
+ end
6
147
  end
7
148
  end
@@ -2,6 +2,146 @@ require File.expand_path(File.dirname(__FILE__)) + '/../spec_helper'
2
2
 
3
3
  module Trackinator
4
4
  describe YouTrack do
5
- pending "write it"
5
+ context "login" do
6
+ it "#login should assign a cookie" do
7
+ pending
8
+ end
9
+ end
10
+
11
+ context "create_ticket" do
12
+ it "#create_ticket should return true" do
13
+ pending
14
+ end
15
+
16
+ it "#create_ticket should return false" do
17
+ pending
18
+ end
19
+ end
20
+
21
+ context "update_ticket" do
22
+ it "#update_ticket should return true" do
23
+ pending
24
+ end
25
+
26
+ it "#update_ticket should return false" do
27
+ pending
28
+ end
29
+ end
30
+
31
+ context "project_exists?" do
32
+ it "#project_exists? should return no issues" do
33
+ pending
34
+ end
35
+
36
+ it "#project_exists? should return 1 issue" do
37
+ pending
38
+ end
39
+ end
40
+
41
+ context "you_track_fields_defined?" do
42
+ it "#you_track_fields_defined? should return no issues" do
43
+ pending
44
+ end
45
+
46
+ it "#you_track_fields_defined? should return some issues" do
47
+ pending
48
+ end
49
+ end
50
+
51
+ context "is_issue_exists?" do
52
+ it "#is_issue_exists? should return nil" do
53
+ pending
54
+ end
55
+
56
+ it "#is_issue_exists? should return a YouTrack issue id" do
57
+ pending
58
+ end
59
+ end
60
+
61
+ context "update_dependencies" do
62
+ it "#update_dependencies should return true" do
63
+ pending
64
+ end
65
+
66
+ it "#update_dependencies should return false" do
67
+ pending
68
+ end
69
+ end
70
+
71
+ context "create_youtrack_ticket" do
72
+ it "#create_youtrack_ticket should return true" do
73
+ pending
74
+ end
75
+
76
+ it "#create_youtrack_ticket should return false" do
77
+ pending
78
+ end
79
+ end
80
+
81
+ context "create_dependency" do
82
+ it "#create_dependency should return true" do
83
+ pending
84
+ end
85
+
86
+ it "#create_dependency should return false" do
87
+ pending
88
+ end
89
+ end
90
+
91
+ context "set_summary_and_description" do
92
+ it "#set_summary_and_description should return true" do
93
+ pending
94
+ end
95
+
96
+ it "#set_summary_and_description should return false" do
97
+ pending
98
+ end
99
+ end
100
+
101
+ context "set_platform" do
102
+ it "#set_platform should return true" do
103
+ pending
104
+ end
105
+
106
+ it "#set_platform should return false" do
107
+ pending
108
+ end
109
+ end
110
+
111
+ context "set_type" do
112
+ it "#set_type should return true" do
113
+ pending
114
+ end
115
+
116
+ it "#set_type should return false" do
117
+ pending
118
+ end
119
+ end
120
+
121
+ context "set_import_identifier" do
122
+ it "#set_import_identifier should return true" do
123
+ pending
124
+ end
125
+
126
+ it "#set_import_identifier should return false" do
127
+ pending
128
+ end
129
+ end
130
+
131
+ context "set_design_reference" do
132
+ it "#set_design_reference should return true" do
133
+ pending
134
+ end
135
+
136
+ it "#set_design_reference should return false" do
137
+ pending
138
+ end
139
+ end
140
+
141
+ context "construct_description" do
142
+ it "#construct_description should render a template" do
143
+ pending
144
+ end
145
+ end
6
146
  end
7
147
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trackinator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.13
4
+ version: 0.0.14
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-16 00:00:00.000000000 Z
12
+ date: 2012-09-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: gdata_19