trackinator 0.0.14 → 0.0.15
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/README.md +12 -10
- data/lib/trackinator/importer.rb +15 -5
- data/lib/trackinator/version.rb +1 -1
- data/lib/trackinator/you_track.rb +21 -9
- data/lib/trackinator.rb +8 -1
- data/spec/trackinator/importer_spec.rb +18 -12
- metadata +2 -2
data/README.md
CHANGED
@@ -12,11 +12,11 @@ benefits to this approach:
|
|
12
12
|
|
13
13
|
The format of the spreadsheet is as follows (columns can be in any order):
|
14
14
|
|
15
|
-
####project
|
15
|
+
####project (required)
|
16
16
|
The abbreviation for the project in YouTrack. The project must
|
17
17
|
exist in YouTrack already, this gem will not create the project for you
|
18
18
|
|
19
|
-
####id
|
19
|
+
####id (required)
|
20
20
|
Similar to a version number. Must be unique in this test plan. Follows
|
21
21
|
the format x.y.z (this example is 3 levels deep) and there is no limit
|
22
22
|
to nesting depth. Each level denotes sub-tickets that will be created
|
@@ -25,29 +25,29 @@ and associated to the level above.
|
|
25
25
|
####type
|
26
26
|
"Story" for top level items, "Features" and "Tasks" for items one or more
|
27
27
|
levels below "Story". “Features” are user facing and "Tasks" are
|
28
|
-
implementation details. "Tasks" will not be acceptance tested.
|
28
|
+
implementation details. "Tasks" will not be acceptance tested. Defaults to "bug"
|
29
29
|
|
30
|
-
####
|
30
|
+
####subsystem (required)
|
31
|
+
This is one of iOS, Android, Backend
|
32
|
+
|
33
|
+
####summary (required)
|
31
34
|
A one-line summarizing of the feature.
|
32
35
|
|
33
|
-
####description
|
36
|
+
####description (required)
|
34
37
|
A description of the feature including steps to use the feature.
|
35
38
|
|
36
|
-
####outcome
|
39
|
+
####outcome (required)
|
37
40
|
The expected outcome if the feature is used per the steps in the description.
|
38
41
|
|
39
42
|
####notes
|
40
43
|
Any additional notes (which will show up as a comment) that might be useful
|
41
44
|
for the developer or tester.
|
42
45
|
|
43
|
-
####
|
46
|
+
####design reference
|
44
47
|
A reference to the design document. The format should be wf/c-<page>-<screen
|
45
48
|
(or range)>. E.g. wf-12-5 or c-9-2-3 (where "wf" refers to wireframe and "c"
|
46
49
|
refers to composition)
|
47
50
|
|
48
|
-
####platform
|
49
|
-
This is usually one of iOS, iPhone, iPad, Android, Desktop Web, Mobile Web
|
50
|
-
|
51
51
|
####priority
|
52
52
|
One of Low, Normal, High, Show-stopper
|
53
53
|
|
@@ -76,6 +76,8 @@ Options:
|
|
76
76
|
--youtrack-host, -o <s>: YouTrack host
|
77
77
|
--youtrack-port, -r <i>: YouTrack port (default: 80)
|
78
78
|
--youtrack-path-prefix, -e <s>: YouTrack path prefix (e.g. '/youtrack/') (default: /)
|
79
|
+
--create-rc, -c: Create a .trackinatorrc file in your home dir
|
80
|
+
--dry-run, -d: Try it out but don't actually import
|
79
81
|
--help, -h: Show this message
|
80
82
|
filename: File name in Google Docs
|
81
83
|
</pre>
|
data/lib/trackinator/importer.rb
CHANGED
@@ -18,7 +18,9 @@ module Trackinator
|
|
18
18
|
def import file_name
|
19
19
|
ticket_data = @google.get_tickets file_name
|
20
20
|
|
21
|
-
issues =
|
21
|
+
issues = []
|
22
|
+
issues.concat validate_headings(ticket_data[0])
|
23
|
+
issues.concat validate_tickets(ticket_data)
|
22
24
|
|
23
25
|
if issues.length == 0 && !@dry_run
|
24
26
|
puts "importing..."
|
@@ -34,6 +36,10 @@ module Trackinator
|
|
34
36
|
|
35
37
|
private
|
36
38
|
|
39
|
+
def validate_headings headings
|
40
|
+
[]
|
41
|
+
end
|
42
|
+
|
37
43
|
def validate_tickets tickets
|
38
44
|
puts "validating..."
|
39
45
|
issues = []
|
@@ -47,7 +53,7 @@ module Trackinator
|
|
47
53
|
issues.concat(@you_track.project_exists?(project))
|
48
54
|
|
49
55
|
tickets.each do |ticket|
|
50
|
-
issues.concat(@you_track.
|
56
|
+
issues.concat(@you_track.required_you_track_fields_defined?(project))
|
51
57
|
|
52
58
|
issues.concat(validate_fields(ticket))
|
53
59
|
issues.concat(validate_formats(ticket))
|
@@ -59,7 +65,7 @@ module Trackinator
|
|
59
65
|
def validate_fields ticket
|
60
66
|
issues = []
|
61
67
|
|
62
|
-
|
68
|
+
GOOGLE_REQUIRED.each do |req_field|
|
63
69
|
unless ticket.keys.include?(req_field) || ticket["type"].downcase.eql?("story")
|
64
70
|
issues << "Validation Error: Ticket with ID: #{ticket["id"]} is missing required field '#{req_field}'"
|
65
71
|
end
|
@@ -72,7 +78,9 @@ module Trackinator
|
|
72
78
|
issues = []
|
73
79
|
|
74
80
|
ticket.keys.each do |key|
|
75
|
-
validate_format(key, ticket[key])
|
81
|
+
unless validate_format(key, ticket[key])
|
82
|
+
issues << "Validation Error: Ticket with ID: #{ticket["id"]} has field '#{key}' with invalid format"
|
83
|
+
end
|
76
84
|
end
|
77
85
|
|
78
86
|
issues
|
@@ -80,7 +88,9 @@ module Trackinator
|
|
80
88
|
|
81
89
|
def validate_format key, value
|
82
90
|
if Trackinator.const_defined?("#{key.upcase}") && Trackinator.const_get("#{key.upcase}").match(value.downcase).nil?
|
83
|
-
|
91
|
+
false
|
92
|
+
else
|
93
|
+
true
|
84
94
|
end
|
85
95
|
end
|
86
96
|
end
|
data/lib/trackinator/version.rb
CHANGED
@@ -52,23 +52,35 @@ module Trackinator
|
|
52
52
|
issues
|
53
53
|
end
|
54
54
|
|
55
|
-
|
55
|
+
# Here's a potential approach for validating that YouTrack fields are present
|
56
|
+
#
|
57
|
+
# get YouTrack fields from server
|
58
|
+
# augment YouTrack fields where necessary (import identifier?)
|
59
|
+
# copy YouTrack fields and normalize copy (remove spaces, downcase)
|
60
|
+
# create map of YouTrack fields to nYouTrack fields
|
61
|
+
# get Google fields from doc
|
62
|
+
# normalize Google fields (remove spaces, downcase)
|
63
|
+
# subtract nGoogle from nYouTrack (leaving only missing YouTrack fields)
|
64
|
+
# subtract nYouTrack from nGoogle (leaving only missing Google fields)
|
65
|
+
# warn on missing nGoogle
|
66
|
+
# fail validation on nYouTrack using map to get actual field names for display
|
67
|
+
# ...
|
68
|
+
# or, just hard code the fucking thing and be done with it
|
69
|
+
|
70
|
+
def required_you_track_fields_defined?(project)
|
71
|
+
you_track_fields = []
|
56
72
|
issues = []
|
57
73
|
|
58
74
|
response = @connection.get("#{@path_prefix}rest/admin/project/#{project}/customfield", { 'Cookie' => @cookie, 'Content-Type' => 'text/plain; charset=utf-8' })
|
59
75
|
response_xml = REXML::Document.new(response.body)
|
60
76
|
|
61
|
-
you_track_fields = %w{ notes }
|
62
|
-
|
63
77
|
response_xml.elements.each('projectCustomFieldRefs/projectCustomField') do |element|
|
64
|
-
you_track_fields << element.attributes["name"]
|
78
|
+
you_track_fields << element.attributes["name"]
|
65
79
|
end
|
66
80
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
unless you_track_fields.include?(document_field)
|
71
|
-
issues << "Validation Error: Custom field '#{document_field}' not found in YouTrack"
|
81
|
+
YOU_TRACK_REQUIRED.each do |required_field|
|
82
|
+
unless you_track_fields.include?(required_field)
|
83
|
+
issues << "Validation Error: Required field '#{required_field}' not found in YouTrack project"
|
72
84
|
end
|
73
85
|
end
|
74
86
|
|
data/lib/trackinator.rb
CHANGED
@@ -13,14 +13,21 @@ module Trackinator
|
|
13
13
|
|
14
14
|
SUBSYSTEM = /^android$|^backend$|^ios$/
|
15
15
|
|
16
|
-
|
16
|
+
GOOGLE_REQUIRED = %w{
|
17
17
|
project
|
18
18
|
id
|
19
|
+
subsystem
|
19
20
|
summary
|
20
21
|
description
|
21
22
|
outcome
|
22
23
|
}
|
23
24
|
|
25
|
+
YOU_TRACK_REQUIRED = [
|
26
|
+
"Type",
|
27
|
+
"Subsystem",
|
28
|
+
"Import Identifier"
|
29
|
+
]
|
30
|
+
|
24
31
|
TRACKINATOR_RC = %w{
|
25
32
|
youtrack_username
|
26
33
|
youtrack_password
|
@@ -68,36 +68,42 @@ module Trackinator
|
|
68
68
|
end
|
69
69
|
|
70
70
|
it "#validate_fields should return no issues and validate feature" do
|
71
|
-
issues = @importer.send(:validate_fields, { "
|
71
|
+
issues = @importer.send(:validate_fields, { "project" => "YTTP", "id" => "1.2", "type" => "feature", "subsystem" => "ios", "summary" => "A summary", "description" => "A description", "outcome" => "An outcome" })
|
72
72
|
issues.should == []
|
73
73
|
end
|
74
74
|
|
75
75
|
it "#validate_fields should return 1 issue: missing project" do
|
76
|
-
issues = @importer.send(:validate_fields, { "type" => "feature", "
|
76
|
+
issues = @importer.send(:validate_fields, { "id" => "1.2", "type" => "feature", "subsystem" => "ios", "summary" => "A summary", "description" => "A description", "outcome" => "An outcome" })
|
77
77
|
issues.size.should == 1
|
78
78
|
issues[0].should == "Validation Error: Ticket with ID: 1.2 is missing required field 'project'"
|
79
79
|
end
|
80
80
|
|
81
81
|
it "#validate_fields should return 1 issue: missing id" do
|
82
|
-
issues = @importer.send(:validate_fields, { "type" => "feature", "
|
82
|
+
issues = @importer.send(:validate_fields, { "project" => "YTTP", "type" => "feature", "subsystem" => "ios", "summary" => "A summary", "description" => "A description", "outcome" => "An outcome" })
|
83
83
|
issues.size.should == 1
|
84
84
|
issues[0].should == "Validation Error: Ticket with ID: is missing required field 'id'"
|
85
85
|
end
|
86
86
|
|
87
|
+
it "#validate_fields should return 1 issue: missing subsystem" do
|
88
|
+
issues = @importer.send(:validate_fields, { "project" => "YTTP", "id" => "1.2", "type" => "feature", "summary" => "A summary", "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 'subsystem'"
|
91
|
+
end
|
92
|
+
|
87
93
|
it "#validate_fields should return 1 issue: missing summary" do
|
88
|
-
issues = @importer.send(:validate_fields, { "
|
94
|
+
issues = @importer.send(:validate_fields, { "project" => "YTTP", "id" => "1.2", "type" => "feature", "subsystem" => "ios", "description" => "A description", "outcome" => "An outcome" })
|
89
95
|
issues.size.should == 1
|
90
96
|
issues[0].should == "Validation Error: Ticket with ID: 1.2 is missing required field 'summary'"
|
91
97
|
end
|
92
98
|
|
93
99
|
it "#validate_fields should return 1 issue: missing description" do
|
94
|
-
issues = @importer.send(:validate_fields, { "
|
100
|
+
issues = @importer.send(:validate_fields, { "project" => "YTTP", "id" => "1.2", "type" => "feature", "subsystem" => "ios", "summary" => "A summary", "outcome" => "An outcome" })
|
95
101
|
issues.size.should == 1
|
96
102
|
issues[0].should == "Validation Error: Ticket with ID: 1.2 is missing required field 'description'"
|
97
103
|
end
|
98
104
|
|
99
105
|
it "#validate_fields should return 1 issue: missing outcome" do
|
100
|
-
issues = @importer.send(:validate_fields, { "
|
106
|
+
issues = @importer.send(:validate_fields, { "project" => "YTTP", "id" => "1.2", "type" => "feature", "subsystem" => "ios", "summary" => "A summary", "description" => "A description" })
|
101
107
|
issues.size.should == 1
|
102
108
|
issues[0].should == "Validation Error: Ticket with ID: 1.2 is missing required field 'outcome'"
|
103
109
|
end
|
@@ -111,34 +117,34 @@ module Trackinator
|
|
111
117
|
@importer = Importer.new @you_track, @google
|
112
118
|
end
|
113
119
|
|
114
|
-
it "#validate_formats should return no issues and validate" do
|
120
|
+
it "#validate_formats should return no issues and validate type" do
|
115
121
|
issues = @importer.send(:validate_formats, { "type" => "feature" })
|
116
122
|
issues.should == []
|
117
123
|
end
|
118
124
|
|
119
|
-
it "#validate_formats should
|
125
|
+
it "#validate_formats should fail validation on type" do
|
120
126
|
issues = @importer.send(:validate_formats, { "type" => "foo" })
|
121
127
|
issues.size.should == 1
|
122
128
|
issues[0].should == "Validation Error: Ticket with ID: has field 'type' with invalid format"
|
123
129
|
end
|
124
130
|
|
125
|
-
it "#validate_formats should
|
131
|
+
it "#validate_formats should fail validation on id" do
|
126
132
|
issues = @importer.send(:validate_formats, { "id" => "1.2" })
|
127
133
|
issues.should == []
|
128
134
|
end
|
129
135
|
|
130
|
-
it "#validate_formats should
|
136
|
+
it "#validate_formats should fail validation on id" do
|
131
137
|
issues = @importer.send(:validate_formats, { "id" => "junk" })
|
132
138
|
issues.size.should == 1
|
133
139
|
issues[0].should == "Validation Error: Ticket with ID: junk has field 'id' with invalid format"
|
134
140
|
end
|
135
141
|
|
136
|
-
it "#validate_formats should return no issues and validate" do
|
142
|
+
it "#validate_formats should return no issues and validate priority" do
|
137
143
|
issues = @importer.send(:validate_formats, { "priority" => "normal" })
|
138
144
|
issues.should == []
|
139
145
|
end
|
140
146
|
|
141
|
-
it "#validate_formats should
|
147
|
+
it "#validate_formats should fail validation on priority" do
|
142
148
|
issues = @importer.send(:validate_formats, { "priority" => "junk" })
|
143
149
|
issues.size.should == 1
|
144
150
|
issues[0].should == "Validation Error: Ticket with ID: has field 'priority' with invalid format"
|
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.15
|
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-09-
|
12
|
+
date: 2012-09-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: gdata_19
|