trackinator 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|