torque 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +79 -3
- data/VERSION +2 -2
- data/bin/config +24 -13
- data/bin/email +10 -20
- data/bin/format +170 -0
- data/bin/project +14 -23
- data/bin/torque +27 -21
- data/lib/torque.rb +20 -34
- data/lib/torque/date_settings.rb +2 -2
- data/lib/torque/field_filter.rb +8 -9
- data/lib/torque/file_system.rb +6 -6
- data/lib/torque/format_string.rb +107 -0
- data/lib/torque/iteration.rb +1 -1
- data/lib/torque/mailer.rb +0 -5
- data/lib/torque/pivotal.rb +8 -8
- data/lib/torque/pivotal_html_parser.rb +2 -2
- data/lib/torque/project/project.rb +4 -0
- data/lib/torque/project/project_manager.rb +4 -5
- data/lib/torque/record_pathname_settings.rb +1 -1
- data/lib/torque/settings.rb +19 -11
- data/lib/torque/story.rb +32 -21
- data/lib/torque/torque_info_parser.rb +20 -8
- data/lib/torque/version.rb +1 -1
- metadata +4 -2
data/lib/torque/iteration.rb
CHANGED
@@ -38,7 +38,7 @@ class Torque
|
|
38
38
|
##
|
39
39
|
# @param iterations A list of iterations
|
40
40
|
#
|
41
|
-
#
|
41
|
+
# @return A list of iterations sorted from most to least recent
|
42
42
|
def self.sort_list(iterations)
|
43
43
|
sorted = iterations.sort {|i1, i2| Integer(i2.number) - Integer(i1.number) }
|
44
44
|
sorted
|
data/lib/torque/mailer.rb
CHANGED
@@ -28,11 +28,6 @@ class Torque
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
# ##
|
32
|
-
# # Returns true if the email and password combination is valid, else false
|
33
|
-
# def verify
|
34
|
-
# end
|
35
|
-
|
36
31
|
# @param notes_string The release notes file in string form
|
37
32
|
# @param subject_line The subject line to use in the email
|
38
33
|
# @param address_list A comma-separated list of email addresses to which to send the notes
|
data/lib/torque/pivotal.rb
CHANGED
@@ -13,7 +13,7 @@ class Torque
|
|
13
13
|
end
|
14
14
|
|
15
15
|
##
|
16
|
-
#
|
16
|
+
# @return True if a connection to www.pivotaltracker.com exists, else false
|
17
17
|
def self.connection?
|
18
18
|
begin
|
19
19
|
TCPSocket.new "www.pivotaltracker.com", 80
|
@@ -24,7 +24,7 @@ class Torque
|
|
24
24
|
end
|
25
25
|
|
26
26
|
##
|
27
|
-
#
|
27
|
+
# @return True if the token supplied is a valid token, else false
|
28
28
|
def check_token
|
29
29
|
begin
|
30
30
|
get_project_data
|
@@ -35,9 +35,9 @@ class Torque
|
|
35
35
|
end
|
36
36
|
|
37
37
|
##
|
38
|
-
#
|
38
|
+
# @return A string of html data from Pivotal Tracker with data on each of a user's projects
|
39
39
|
#
|
40
|
-
#
|
40
|
+
# Sends a request through the Pivotal Tracker API
|
41
41
|
def get_project_data
|
42
42
|
|
43
43
|
host="pivotaltracker.com"
|
@@ -66,9 +66,9 @@ class Torque
|
|
66
66
|
##
|
67
67
|
# @param project The ID of the Pivotal Tracker project from which to get data
|
68
68
|
#
|
69
|
-
#
|
69
|
+
# @return A string of html data from Pivotal Tracker with data on the stories for the given project
|
70
70
|
#
|
71
|
-
#
|
71
|
+
# Sends a request through the Pivotal Tracker API
|
72
72
|
def get_project_stories(project)
|
73
73
|
|
74
74
|
# Polls story data from pivotal tracker
|
@@ -103,9 +103,9 @@ class Torque
|
|
103
103
|
# @param project The ID of the Pivotal Tracker project from which to get data
|
104
104
|
# @param number The number of project iterations to fetch
|
105
105
|
#
|
106
|
-
#
|
106
|
+
# @return A string of html data from Pivotal Tracker with data on finished iterations of a project
|
107
107
|
#
|
108
|
-
#
|
108
|
+
# Sends a request throgh the Pivotal Tracker API
|
109
109
|
def get_project_iterations(project, number=1)
|
110
110
|
|
111
111
|
# Polls story data from pivotal tracker
|
@@ -38,7 +38,7 @@ class Torque
|
|
38
38
|
##
|
39
39
|
# @param project_html_string An html string containing the story data for a Pivotal Tracker project
|
40
40
|
#
|
41
|
-
#
|
41
|
+
# @return A list of all Story objects parsed from project_html_string (least recent to most recent date accepted)
|
42
42
|
#
|
43
43
|
# Applies during processing any filters that have been added
|
44
44
|
def process_project(project_html_string)
|
@@ -51,7 +51,7 @@ class Torque
|
|
51
51
|
##
|
52
52
|
# @param project_html_string An html string containing iteration data for a Pivotal Tracker project
|
53
53
|
#
|
54
|
-
#
|
54
|
+
# @return A list of Iteration objects parsed from project_html_string (least recent to most recent iteration)
|
55
55
|
def process_project_iterations(project_html_string)
|
56
56
|
|
57
57
|
project_html = Nokogiri::HTML(project_html_string)
|
@@ -16,6 +16,10 @@ class Torque
|
|
16
16
|
# The project name
|
17
17
|
attr_reader :name
|
18
18
|
|
19
|
+
##
|
20
|
+
# @param id The project's ID
|
21
|
+
# @param name The project's name
|
22
|
+
# @param current True if this is the current project, else false
|
19
23
|
def initialize(id, name, current=false)
|
20
24
|
@current = current
|
21
25
|
@id = id
|
@@ -27,17 +27,16 @@ class Torque
|
|
27
27
|
|
28
28
|
##
|
29
29
|
# @param token A Pivotal Tracker API token (default: Loads token from .torqueinfo.yaml)
|
30
|
+
# @return the project list
|
30
31
|
#
|
31
32
|
# Requests and processes the project list from the Pivotal Tracker API
|
32
|
-
#
|
33
|
-
# Returns the project list
|
34
33
|
def load_project_list(token=nil)
|
35
34
|
get_project_list(token)
|
36
35
|
@project_list
|
37
36
|
end
|
38
37
|
|
39
38
|
##
|
40
|
-
#
|
39
|
+
# @return The project list if 'load_project_list' has been called, else returns nil
|
41
40
|
#
|
42
41
|
# Does not do any processing
|
43
42
|
def project_list
|
@@ -45,7 +44,7 @@ class Torque
|
|
45
44
|
end
|
46
45
|
|
47
46
|
##
|
48
|
-
#
|
47
|
+
# @return The current project if 'load_project_list' has been called and one exists, else returns nil
|
49
48
|
def current_project
|
50
49
|
@project_list.nil? \
|
51
50
|
? nil
|
@@ -53,7 +52,7 @@ class Torque
|
|
53
52
|
end
|
54
53
|
|
55
54
|
##
|
56
|
-
#
|
55
|
+
# @return The project list formatted as a printable string
|
57
56
|
#
|
58
57
|
# Prepends an asterisk to the current project
|
59
58
|
def format_project_list
|
data/lib/torque/settings.rb
CHANGED
@@ -2,6 +2,7 @@ require 'date'
|
|
2
2
|
require_relative 'date_settings'
|
3
3
|
require_relative 'field_filter'
|
4
4
|
require_relative 'file_system'
|
5
|
+
require_relative 'format_string'
|
5
6
|
require_relative 'record_pathname_settings'
|
6
7
|
require_relative 'torque_info_parser'
|
7
8
|
require_relative 'error/missing_project_error'
|
@@ -62,6 +63,10 @@ class Torque
|
|
62
63
|
# True if field filters are being used for stories, else false
|
63
64
|
attr_reader :filters_on
|
64
65
|
|
66
|
+
##
|
67
|
+
# The FormatString object to use to generate notes
|
68
|
+
attr_reader :format_string
|
69
|
+
|
65
70
|
##
|
66
71
|
# The number of iterations of the project to generate notes for, or nil if not using iterations
|
67
72
|
attr_reader :iterations
|
@@ -141,11 +146,23 @@ class Torque
|
|
141
146
|
|
142
147
|
@email_address = torque_info.email_address
|
143
148
|
@email_password = torque_info.email_password
|
144
|
-
|
145
|
-
|
149
|
+
email_to_raw = torque_info.email_to
|
150
|
+
format_string_raw = torque_info.format
|
151
|
+
output_dir_raw = torque_info.output_dir
|
146
152
|
@project = torque_info.project
|
147
153
|
@token = torque_info.token
|
148
154
|
|
155
|
+
if email_to_raw.class == NilClass; @email_to = []
|
156
|
+
elsif email_to_raw.class == String; @email_to = [email_to_raw]
|
157
|
+
elsif email_to_raw.class == Array; @email_to = email_to_raw
|
158
|
+
else; raise "Unknown parsing error on .torqueinfo.yaml's 'email_to' field: #{@email_to}"
|
159
|
+
end
|
160
|
+
|
161
|
+
@format_string = Torque::FormatString.new(format_string_raw)
|
162
|
+
|
163
|
+
output_dir_raw = "release_notes" if output_dir_raw.blank?
|
164
|
+
@output_dir = "#{@root_dir}/#{output_dir_raw}"
|
165
|
+
|
149
166
|
raise MissingTokenError.new(
|
150
167
|
"API token for Pivotal Tracker has not been set"
|
151
168
|
) if @token.blank?
|
@@ -153,15 +170,6 @@ class Torque
|
|
153
170
|
"Project ID for Pivotal Tracker has not been set"
|
154
171
|
) if @project.blank?
|
155
172
|
|
156
|
-
@output_dir = "release_notes" if @output_dir.blank?
|
157
|
-
@output_dir = "#{@root_dir}/#{@output_dir}"
|
158
|
-
|
159
|
-
if @email_to.class == NilClass; @email_to = []
|
160
|
-
elsif @email_to.class == String; @email_to = [@email_to]
|
161
|
-
elsif @email_to.class == Array; @email_to = @email_to
|
162
|
-
else; raise "Unknown parsing error on .torqueinfo.yaml's 'email_to' field: #{@email_to}"
|
163
|
-
end
|
164
|
-
|
165
173
|
# Sets up the output directory, throwing an error if it cannot be found
|
166
174
|
|
167
175
|
if !@fs.path_exist? @output_dir
|
data/lib/torque/story.rb
CHANGED
@@ -6,48 +6,48 @@ class Torque
|
|
6
6
|
|
7
7
|
##
|
8
8
|
# The current state of the story (finished, accepted, etc)
|
9
|
-
|
9
|
+
attr_accessor :current_state
|
10
10
|
|
11
11
|
##
|
12
12
|
# The date that the story was accepted, or nil if it has not been accepted yet
|
13
|
-
|
13
|
+
attr_accessor :date_accepted
|
14
14
|
|
15
15
|
##
|
16
16
|
# The story description
|
17
|
-
|
17
|
+
attr_accessor :description
|
18
18
|
|
19
19
|
##
|
20
20
|
# The estimate for the story
|
21
|
-
|
21
|
+
attr_accessor :estimate
|
22
|
+
|
23
|
+
##
|
24
|
+
# The story's ID
|
25
|
+
attr_accessor :id
|
22
26
|
|
23
27
|
##
|
24
28
|
# The labels for the story
|
25
|
-
|
29
|
+
attr_accessor :labels
|
26
30
|
|
27
31
|
##
|
28
32
|
# The name of the story
|
29
|
-
|
33
|
+
attr_accessor :name
|
30
34
|
|
31
35
|
##
|
32
36
|
# The owner of the story
|
33
|
-
|
37
|
+
attr_accessor :owner
|
34
38
|
|
35
39
|
##
|
36
40
|
# The ID of the story's project
|
37
|
-
|
38
|
-
|
39
|
-
##
|
40
|
-
# The story's ID
|
41
|
-
attr_reader :story_id
|
41
|
+
attr_accessor :project_id
|
42
42
|
|
43
43
|
##
|
44
44
|
# The story's type (feature, chore, etc)
|
45
|
-
|
45
|
+
attr_accessor :type
|
46
46
|
|
47
47
|
##
|
48
48
|
# @param html_hash A hash (of html elements keyed by their tags) generated from Pivotal Tracker story html
|
49
49
|
#
|
50
|
-
#
|
50
|
+
# @return A new story whose fields were parsed from the html_hash provided
|
51
51
|
def self.create(html_hash)
|
52
52
|
Story.new(html_hash).parse
|
53
53
|
end
|
@@ -67,25 +67,34 @@ class Torque
|
|
67
67
|
end
|
68
68
|
private :handle_nil
|
69
69
|
|
70
|
-
|
70
|
+
##
|
71
|
+
# @return The url pointing to the story
|
72
|
+
def url
|
73
|
+
"https://www.pivotaltracker.com/story/show/#{id}"
|
74
|
+
end
|
71
75
|
|
72
76
|
##
|
73
77
|
# Parses the story's fields from its html hash
|
78
|
+
#
|
79
|
+
# @return The story (self)
|
74
80
|
def parse
|
75
81
|
html_hash = @html_hash
|
76
82
|
|
77
83
|
# Default values
|
84
|
+
|
78
85
|
@current_state = ""
|
79
|
-
@date_accepted = nil #
|
86
|
+
@date_accepted = nil # [Date]
|
80
87
|
@description = ""
|
81
88
|
@estimate = -1
|
82
|
-
@
|
89
|
+
@id = -1
|
90
|
+
@labels = "" # [Array]
|
83
91
|
@name = ""
|
84
92
|
@owner = ""
|
85
93
|
@project_id = -1
|
86
|
-
@story_id = -1
|
87
94
|
@type = ""
|
88
95
|
|
96
|
+
# Processes each field
|
97
|
+
|
89
98
|
@current_state = handle_nil(@current_state, html_hash["current_state"])
|
90
99
|
@description = handle_nil(@description, html_hash["description"])
|
91
100
|
@name = handle_nil(@name, html_hash["name"])
|
@@ -94,7 +103,7 @@ class Torque
|
|
94
103
|
|
95
104
|
@estimate = Integer(handle_nil(@estimate, html_hash["estimate"]))
|
96
105
|
@project_id = Integer(handle_nil(@project_id, html_hash["project_id"]))
|
97
|
-
@
|
106
|
+
@id = Integer(handle_nil(@id, html_hash["id"]))
|
98
107
|
|
99
108
|
@labels = handle_nil(@labels, html_hash["labels"])
|
100
109
|
@labels = @labels.split(",")
|
@@ -104,12 +113,14 @@ class Torque
|
|
104
113
|
@date_accepted = Date.strptime(date_acceptedString, "%Y/%m/%d")
|
105
114
|
end
|
106
115
|
|
107
|
-
# Returns the
|
116
|
+
# Returns the parsed story
|
117
|
+
|
108
118
|
self
|
109
119
|
end
|
110
120
|
|
111
121
|
##
|
112
|
-
#
|
122
|
+
# @param stories A list of stories
|
123
|
+
# @return The list of stories sorted from most to least recently accepted
|
113
124
|
def self.sort_list(stories)
|
114
125
|
sorted = stories.sort { |s1, s2| -(s1.date_accepted <=> s2.date_accepted) }
|
115
126
|
sorted
|
@@ -21,6 +21,10 @@ class Torque
|
|
21
21
|
# The email_to field (String or Array)
|
22
22
|
attr_reader :email_to
|
23
23
|
|
24
|
+
##
|
25
|
+
# The format string to use for the project
|
26
|
+
attr_reader :format
|
27
|
+
|
24
28
|
##
|
25
29
|
# The project field (Fixnum)
|
26
30
|
attr_reader :project
|
@@ -45,9 +49,10 @@ class Torque
|
|
45
49
|
end
|
46
50
|
|
47
51
|
##
|
52
|
+
# @return The TorqueInfoParser (self)
|
53
|
+
#
|
48
54
|
# Parses the file, storing the results as public instnance fields
|
49
55
|
# Stores each field with no corresponding value in the file as 'nil'
|
50
|
-
# Returns self
|
51
56
|
def parse
|
52
57
|
|
53
58
|
if !@fs.path_exist?(@file_path)
|
@@ -59,12 +64,13 @@ class Torque
|
|
59
64
|
begin
|
60
65
|
torque_info_hash = YAML::load(@fs.file_read(@file_path)) || {}
|
61
66
|
rescue Psych::SyntaxError
|
62
|
-
#
|
67
|
+
# TODO Implement custom error, raise/rescue paths to catch this problem
|
63
68
|
end
|
64
69
|
|
65
70
|
@email_address = torque_info_hash["email_address"]
|
66
71
|
@email_password = torque_info_hash["email_password"]
|
67
72
|
@email_to = torque_info_hash["email_to"]
|
73
|
+
@format = torque_info_hash["format"]
|
68
74
|
@project = torque_info_hash["project"]
|
69
75
|
@output_dir = torque_info_hash["output_dir"]
|
70
76
|
@token = torque_info_hash["token"]
|
@@ -73,7 +79,8 @@ class Torque
|
|
73
79
|
end
|
74
80
|
|
75
81
|
##
|
76
|
-
#
|
82
|
+
# @param field The field to set
|
83
|
+
# @param value The value to set the field to
|
77
84
|
def set(field, value)
|
78
85
|
file_string = @fs.file_read(@file_path)
|
79
86
|
new_file_string = set_string(field, value, file_string)
|
@@ -81,7 +88,8 @@ class Torque
|
|
81
88
|
end
|
82
89
|
|
83
90
|
##
|
84
|
-
#
|
91
|
+
# @param field The field to add to
|
92
|
+
# @param values A list of values to add to the field
|
85
93
|
def add(field, values)
|
86
94
|
file_string = @fs.file_read(@file_path)
|
87
95
|
new_file_string = add_string(field, values, file_string)
|
@@ -89,8 +97,10 @@ class Torque
|
|
89
97
|
end
|
90
98
|
|
91
99
|
##
|
92
|
-
#
|
93
|
-
#
|
100
|
+
# @param field The field to add to
|
101
|
+
# @param values A list of values to add to the field
|
102
|
+
#
|
103
|
+
# @return A list of all values that were added (ie that were not duplicates)
|
94
104
|
def add_no_duplicates(field, values)
|
95
105
|
file_string = @fs.file_read(@file_path)
|
96
106
|
values_copy = values.clone
|
@@ -101,8 +111,10 @@ class Torque
|
|
101
111
|
end
|
102
112
|
|
103
113
|
##
|
104
|
-
#
|
105
|
-
#
|
114
|
+
# @param field The field to remove from
|
115
|
+
# @param values A list of values to remove from the field
|
116
|
+
#
|
117
|
+
# @return A list of the values that were removed (ie that could be found)
|
106
118
|
def rm(field, values)
|
107
119
|
file_string = @fs.file_read(@file_path)
|
108
120
|
values_copy = values.clone
|
data/lib/torque/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: torque
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nico Adams, Scrimmage
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-08-
|
11
|
+
date: 2013-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: highline
|
@@ -92,6 +92,7 @@ extra_rdoc_files:
|
|
92
92
|
files:
|
93
93
|
- bin/config
|
94
94
|
- bin/email
|
95
|
+
- bin/format
|
95
96
|
- bin/project
|
96
97
|
- bin/torque
|
97
98
|
- lib/torque/date_settings.rb
|
@@ -104,6 +105,7 @@ files:
|
|
104
105
|
- lib/torque/error/pivotal_api_error.rb
|
105
106
|
- lib/torque/field_filter.rb
|
106
107
|
- lib/torque/file_system.rb
|
108
|
+
- lib/torque/format_string.rb
|
107
109
|
- lib/torque/iteration.rb
|
108
110
|
- lib/torque/mailer.rb
|
109
111
|
- lib/torque/pivotal.rb
|