trackinator 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/trackinate +19 -2
- data/lib/trackinator/google.rb +11 -3
- data/lib/trackinator/importer.rb +54 -10
- data/lib/trackinator/version.rb +1 -1
- data/lib/trackinator/you_track.rb +44 -17
- data/lib/trackinator.rb +19 -2
- metadata +2 -2
data/bin/trackinate
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
#!/usr/bin/ruby
|
2
2
|
|
3
3
|
require 'trackinator/importer'
|
4
|
+
require 'trackinator/you_track'
|
5
|
+
require 'trackinator/google'
|
4
6
|
require 'trollop'
|
5
7
|
require 'etc'
|
6
8
|
|
@@ -34,6 +36,13 @@ Trollop::die :google_username, "is required" if opts[:google_username].nil?
|
|
34
36
|
Trollop::die :google_password, "is required" if opts[:google_password].nil?
|
35
37
|
Trollop::die :host, "is required" if opts[:host].nil?
|
36
38
|
|
39
|
+
you_track = Trackinator::YouTrack.new opts
|
40
|
+
google = Trackinator::Google.new opts
|
41
|
+
|
42
|
+
Trollop::die "Check your YouTrack credentials and try again" unless you_track.is_logged_in?
|
43
|
+
Trollop::die "Check your Google credentials and try again" unless google.is_logged_in?
|
44
|
+
Trollop::die "You must supply a Google doc filename to import" if ARGV.empty? && opts[:create_rc]
|
45
|
+
|
37
46
|
if opts[:create_rc]
|
38
47
|
unless File.exists?("#{Etc.getpwuid.dir}/.trackinatorrc")
|
39
48
|
file = File.new("#{Etc.getpwuid.dir}/.trackinatorrc", "w")
|
@@ -49,5 +58,13 @@ if opts[:create_rc]
|
|
49
58
|
end
|
50
59
|
end
|
51
60
|
|
52
|
-
|
53
|
-
importer.
|
61
|
+
if ARGV.length == 1
|
62
|
+
importer = Trackinator::Importer.new you_track, google
|
63
|
+
issues = importer.import ARGV[0], "YTTP"
|
64
|
+
|
65
|
+
if issues.length > 0
|
66
|
+
issues.each do |issue|
|
67
|
+
p issue
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/trackinator/google.rb
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
module Trackinator
|
2
2
|
class Google
|
3
|
-
@client
|
4
|
-
|
5
3
|
def initialize opts
|
6
4
|
@client = GData::Client::Spreadsheets.new
|
7
|
-
|
5
|
+
begin
|
6
|
+
@token = @client.clientlogin(opts[:google_username], opts[:google_password])
|
7
|
+
rescue
|
8
|
+
@token = nil
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def is_logged_in?
|
13
|
+
!@token.nil?
|
8
14
|
end
|
9
15
|
|
10
16
|
def get_tickets file_name
|
@@ -20,6 +26,8 @@ module Trackinator
|
|
20
26
|
tickets
|
21
27
|
end
|
22
28
|
|
29
|
+
private
|
30
|
+
|
23
31
|
def get_spreadsheet_key file_name
|
24
32
|
doc_feed = @client.get("http://spreadsheets.google.com/feeds/spreadsheets/private/full").to_xml
|
25
33
|
|
data/lib/trackinator/importer.rb
CHANGED
@@ -3,25 +3,69 @@ require 'CSV'
|
|
3
3
|
|
4
4
|
require 'gdata'
|
5
5
|
|
6
|
-
require 'trackinator
|
7
|
-
require 'trackinator/you_track'
|
6
|
+
require 'trackinator'
|
8
7
|
|
9
8
|
module Trackinator
|
10
9
|
class Importer
|
11
|
-
@you_track
|
12
10
|
|
13
|
-
def initialize
|
14
|
-
@you_track =
|
15
|
-
@google =
|
11
|
+
def initialize you_track, google
|
12
|
+
@you_track = you_track
|
13
|
+
@google = google
|
16
14
|
end
|
17
15
|
|
18
|
-
def import file_name
|
16
|
+
def import file_name, project = nil
|
19
17
|
ticket_data = @google.get_tickets file_name
|
20
18
|
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
issues = validate_tickets(project, ticket_data)
|
20
|
+
|
21
|
+
if issues.length == 0
|
22
|
+
ticket_data.each do |entry|
|
23
|
+
issue_id = @you_track.is_issue_exists? entry
|
24
|
+
#false unless !issue_id.nil? ? @you_track.update_ticket(issue_id, entry) : @you_track.create_ticket(entry)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
issues
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def validate_tickets project, tickets
|
34
|
+
issues = []
|
35
|
+
|
36
|
+
issues.concat(@you_track.project_exists?(project))
|
37
|
+
issues.concat(@you_track.you_track_fields_defined?(project, tickets[0].keys))
|
38
|
+
|
39
|
+
tickets.each do |ticket|
|
40
|
+
issues.concat(validate_fields(ticket))
|
41
|
+
issues.concat(validate_formats(ticket))
|
24
42
|
end
|
43
|
+
|
44
|
+
issues
|
45
|
+
end
|
46
|
+
|
47
|
+
def validate_fields ticket
|
48
|
+
issues = []
|
49
|
+
|
50
|
+
REQUIRED.each do |req_field|
|
51
|
+
unless ticket.keys.include?(req_field) || ticket["type"].downcase.eql?("story")
|
52
|
+
issues << "Validation Error: Ticket with ID: #{ticket["id"]} is missing required field '#{req_field}'"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
issues
|
57
|
+
end
|
58
|
+
|
59
|
+
def validate_formats ticket
|
60
|
+
issues = []
|
61
|
+
|
62
|
+
ticket.keys.each do |key|
|
63
|
+
if Trackinator.const_defined?("#{key.upcase}") && Trackinator.const_get("#{key.upcase}").match(ticket[key].downcase).nil?
|
64
|
+
issues << "Validation Error: Ticket with ID: #{ticket["id"]} has field '#{key}' with invalid format"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
issues
|
25
69
|
end
|
26
70
|
end
|
27
71
|
end
|
data/lib/trackinator/version.rb
CHANGED
@@ -1,14 +1,5 @@
|
|
1
1
|
module Trackinator
|
2
2
|
class YouTrack
|
3
|
-
@stack
|
4
|
-
|
5
|
-
@cookie
|
6
|
-
@connection
|
7
|
-
|
8
|
-
@host
|
9
|
-
@port
|
10
|
-
@path_prefix
|
11
|
-
|
12
3
|
def initialize opts
|
13
4
|
@stack = []
|
14
5
|
|
@@ -19,10 +10,16 @@ module Trackinator
|
|
19
10
|
login opts[:youtrack_username], opts[:youtrack_password]
|
20
11
|
end
|
21
12
|
|
13
|
+
def is_logged_in?
|
14
|
+
!@cookie.nil?
|
15
|
+
end
|
16
|
+
|
22
17
|
def login username, password
|
23
18
|
@connection = Net::HTTP.new @host, @port
|
24
19
|
response = @connection.post "#{@path_prefix}rest/user/login", "login=#{username}&password=#{password}"
|
25
|
-
|
20
|
+
if response.header.msg.eql? "OK"
|
21
|
+
@cookie = response.response['Set-Cookie'].split('; ')[0]
|
22
|
+
end
|
26
23
|
end
|
27
24
|
|
28
25
|
def create_ticket data
|
@@ -43,6 +40,43 @@ module Trackinator
|
|
43
40
|
success
|
44
41
|
end
|
45
42
|
|
43
|
+
def project_exists?(project)
|
44
|
+
issues = []
|
45
|
+
|
46
|
+
response = @connection.get("#{@path_prefix}rest/admin/project/#{project}", { 'Cookie' => @cookie, 'Content-Type' => 'text/plain; charset=utf-8' })
|
47
|
+
if response.header.msg.eql?("Not Found")
|
48
|
+
issues << "Project Error: Project doesn't exist!"
|
49
|
+
end
|
50
|
+
|
51
|
+
issues
|
52
|
+
end
|
53
|
+
|
54
|
+
def you_track_fields_defined?(project, fields)
|
55
|
+
issues = []
|
56
|
+
|
57
|
+
response = @connection.get("#{@path_prefix}rest/admin/project/#{project}/customfield", { 'Cookie' => @cookie, 'Content-Type' => 'text/plain; charset=utf-8' })
|
58
|
+
response_xml = REXML::Document.new(response.body)
|
59
|
+
|
60
|
+
you_track_fields = []
|
61
|
+
|
62
|
+
response_xml.elements.each('projectCustomFieldRefs/projectCustomField') { |element| you_track_fields << element.attributes["name"].downcase }
|
63
|
+
|
64
|
+
(fields - REQUIRED).each do |document_field|
|
65
|
+
unless you_track_fields.include?(document_field)
|
66
|
+
issues << "Validation Error: Custom field '#{document_field}' not found in YouTrack"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
issues
|
71
|
+
end
|
72
|
+
|
73
|
+
def is_issue_exists? data
|
74
|
+
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)
|
75
|
+
find_response_xml.elements['issues'].length > 0 ? find_response_xml.elements['issues/issue'].attributes['id'] : nil
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
46
80
|
def update_dependencies issue
|
47
81
|
issue_id = issue[0]
|
48
82
|
issue_level = issue[1]
|
@@ -66,13 +100,6 @@ module Trackinator
|
|
66
100
|
end
|
67
101
|
end
|
68
102
|
|
69
|
-
# YouTrack API calls
|
70
|
-
|
71
|
-
def is_issue_exists? data
|
72
|
-
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)
|
73
|
-
find_response_xml.elements['issues'].length > 0 ? find_response_xml.elements['issues/issue'].attributes['id'] : nil
|
74
|
-
end
|
75
|
-
|
76
103
|
def create_youtrack_ticket data
|
77
104
|
response = @connection.put("#{@path_prefix}rest/issue?project=#{data['project']}&summary=#{data['summary']}&description=#{data['description']}&priority=#{data['priority']}", nil, { 'Cookie' => @cookie, 'Content-Type' => 'text/plain; charset=utf-8' })
|
78
105
|
return response.header["Location"].split("/").last, response.header.msg
|
data/lib/trackinator.rb
CHANGED
@@ -1,5 +1,22 @@
|
|
1
|
-
require
|
1
|
+
require 'trackinator/version'
|
2
|
+
require 'trackinator/google'
|
3
|
+
require 'trackinator/you_track'
|
4
|
+
|
2
5
|
|
3
6
|
module Trackinator
|
4
|
-
|
7
|
+
|
8
|
+
ID = /^(?:\d+\.?)+$/
|
9
|
+
|
10
|
+
TYPE = /^story$|^feature$|^task$|^bug$/
|
11
|
+
|
12
|
+
PRIORITY = /^low$|^normal$|^high$|^show-stopper$/
|
13
|
+
|
14
|
+
REQUIRED = %w{
|
15
|
+
project
|
16
|
+
id
|
17
|
+
summary
|
18
|
+
description
|
19
|
+
outcome
|
20
|
+
}
|
21
|
+
|
5
22
|
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.
|
4
|
+
version: 0.0.8
|
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-
|
12
|
+
date: 2012-08-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: gdata_19
|