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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b758a1a40b981493fc10c574974eddb9d65aa6c
|
4
|
+
data.tar.gz: 9e937f2bbeb8e3af7b6b1939d61014c8b5f96d29
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74e771fe69f47007a1badc7cd1b33e24dc1f077ef1025a433549abe4e8f42ab6b1876196d1f8fcfd0380138fbbb06b6f30b29a40730f6ba57e8ab3d4731860db
|
7
|
+
data.tar.gz: 16205617e5a71c342f41611cb74b103ff966111970098c59f7121ba29d6ce1448fa11503f6b82be0f3260e201f99660bd40ba8c9fafc2525a69860084d2ccbc2
|
data/README.md
CHANGED
@@ -91,17 +91,22 @@ To filter your results by story label, owner or type:
|
|
91
91
|
# torque --owner "list + of , owners"
|
92
92
|
# torque --type "list, of + story types"
|
93
93
|
|
94
|
-
When using filters
|
94
|
+
When using filters:
|
95
|
+
* "," => OR
|
96
|
+
* "+" => AND
|
97
|
+
* "+" is evaluated before ","
|
98
|
+
|
99
|
+
For example, "ios + android, ios + web" becomes
|
95
100
|
|
96
101
|
("ios" AND "android") OR ("ios" AND "web")
|
97
102
|
|
98
|
-
|
103
|
+
The "owner" filter will try to match against first/middle/last names as well as full names. For instance, '--owner Lee' will match stories owned by (eg) "Lee Grant", "Jake Lee", or "John Lee Jones".
|
99
104
|
|
100
105
|
To email the release notes from a personal email to Torque's mailing list:
|
101
106
|
|
102
107
|
# torque --email
|
103
108
|
|
104
|
-
Running with
|
109
|
+
Running with '-v/--verbose' will print a running list of stories as they are added. Running with '-s/--silent' will silence all output.
|
105
110
|
|
106
111
|
To display all available Pivotal Tracker projects or change your current project:
|
107
112
|
|
@@ -111,6 +116,77 @@ To set up automatic emailing of the notes and add/remove from the mailing list:
|
|
111
116
|
|
112
117
|
# torque email
|
113
118
|
|
119
|
+
To view/change the format of the notes that Torque generates:
|
120
|
+
|
121
|
+
# torque format
|
122
|
+
|
123
|
+
Formatting
|
124
|
+
----------
|
125
|
+
|
126
|
+
By default, stories are formatted like this:
|
127
|
+
|
128
|
+
12345678
|
129
|
+
Story Name
|
130
|
+
Accepted on 2012/12/21
|
131
|
+
https://www.pivotaltracker.com/story/show/12345678
|
132
|
+
Short description of story goes here
|
133
|
+
- This is a side note
|
134
|
+
- This is another side note
|
135
|
+
|
136
|
+
To change the way that stories are formatted, use 'torque format -s/--set'. Alternately, use 'torque format -e/--example' to see some sample output from a new format.
|
137
|
+
|
138
|
+
The format is set by way of a "formatting string", a mix of plain text and parameters (eg "%a") that act as placeholders for elements of a story.
|
139
|
+
|
140
|
+
Parameters:
|
141
|
+
* %a => Date accepted (MM/DD)
|
142
|
+
* %A => Date accepted (YYYY/MM/DD)
|
143
|
+
* %d => Description
|
144
|
+
* %D => Description (tabbed once on each newline)
|
145
|
+
* %e => Estimate
|
146
|
+
* %i => ID
|
147
|
+
* %l => Labels (separated by ", ")
|
148
|
+
* %n => Newline character
|
149
|
+
* %N => Name
|
150
|
+
* %o => Owner of the story
|
151
|
+
* %p => ID of the story's project
|
152
|
+
* %u => URL pointing to the story
|
153
|
+
* %t => Tab character
|
154
|
+
* %T => Type (feature, bug, etc)
|
155
|
+
|
156
|
+
Exit Codes
|
157
|
+
----------
|
158
|
+
|
159
|
+
The following is a list of exit codes that are thrown on various errors for each of the Torque scripts.
|
160
|
+
|
161
|
+
(general)
|
162
|
+
3 Invalid arguments
|
163
|
+
4 Cannot connect to Pivotal Tracker API
|
164
|
+
|
165
|
+
torque
|
166
|
+
5 Missing torque info file
|
167
|
+
6 Missing output directory
|
168
|
+
7 Missing token
|
169
|
+
8 Invalid token
|
170
|
+
9 Missing project
|
171
|
+
10 Invalid project
|
172
|
+
11 Misc. Pivotal Tracker API request error
|
173
|
+
12 Misc argument error
|
174
|
+
|
175
|
+
torque config
|
176
|
+
5 Pre-existing output directory
|
177
|
+
6 Pre-existing torque info file
|
178
|
+
7 Invalid output directory
|
179
|
+
|
180
|
+
torque email
|
181
|
+
5 Missing torque info file
|
182
|
+
|
183
|
+
torque format
|
184
|
+
5 Missing torque info file
|
185
|
+
|
186
|
+
torque project
|
187
|
+
5 Missing torque info file
|
188
|
+
6 Project not found
|
189
|
+
|
114
190
|
License
|
115
191
|
-------
|
116
192
|
|
data/VERSION
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
major:0
|
2
|
-
minor:
|
3
|
-
patch:
|
2
|
+
minor:4
|
3
|
+
patch:0
|
data/bin/config
CHANGED
@@ -11,6 +11,7 @@ require 'highline/import'
|
|
11
11
|
require 'net/http'
|
12
12
|
require 'optparse'
|
13
13
|
require 'pathname'
|
14
|
+
require "#{lib_dir}/torque/format_string"
|
14
15
|
require "#{lib_dir}/torque/pivotal"
|
15
16
|
require "#{lib_dir}/torque/torque_info_parser"
|
16
17
|
require "#{lib_dir}/torque/project/project"
|
@@ -62,7 +63,7 @@ begin
|
|
62
63
|
rescue OptionParser::InvalidOption, OptionParser::MissingArgument
|
63
64
|
puts $!.to_s
|
64
65
|
puts option_parser
|
65
|
-
exit
|
66
|
+
exit 3
|
66
67
|
end
|
67
68
|
|
68
69
|
# Handles special cases and exceptions
|
@@ -74,7 +75,7 @@ if ((ARGV.member? "help") || options[:help])
|
|
74
75
|
elsif !ARGV.empty?
|
75
76
|
puts "Unknown arguments: #{ARGV.join(", ")}"
|
76
77
|
puts option_parser.help
|
77
|
-
exit
|
78
|
+
exit 3
|
78
79
|
end
|
79
80
|
|
80
81
|
# Checks for a connection to Pivotal Tracker
|
@@ -82,7 +83,7 @@ end
|
|
82
83
|
if !Torque::Pivotal.connection?
|
83
84
|
puts "ABORTING"
|
84
85
|
puts "Cannot connect to www.pivotaltracker.com. A connection is required to configure Torque"
|
85
|
-
exit
|
86
|
+
exit 4
|
86
87
|
end
|
87
88
|
|
88
89
|
# Configures the directory
|
@@ -102,7 +103,7 @@ if !options[:token]
|
|
102
103
|
puts "The default output directory, #{default_output_dir}, already exists."
|
103
104
|
puts "(Use -o to manually choose an existing output directory or create a new one)"
|
104
105
|
puts "(Use -f to overwrite an existing directory)"
|
105
|
-
exit
|
106
|
+
exit 5
|
106
107
|
end
|
107
108
|
|
108
109
|
|
@@ -113,7 +114,7 @@ if !options[:token]
|
|
113
114
|
puts "A .torqueinfo.yaml file already exists in this directory."
|
114
115
|
puts "(Use -o to ignore this file and change only the output directory)"
|
115
116
|
puts "(Use -f to overwrite this file)"
|
116
|
-
exit
|
117
|
+
exit 6
|
117
118
|
end
|
118
119
|
|
119
120
|
|
@@ -132,7 +133,13 @@ if !options[:token]
|
|
132
133
|
puts "- Creating directory #{output_dir}"
|
133
134
|
end
|
134
135
|
|
135
|
-
|
136
|
+
begin
|
137
|
+
FileUtils.mkdir_p("#{output_dir}/previous")
|
138
|
+
rescue Errno::EACCES => e
|
139
|
+
puts "ABORTING"
|
140
|
+
puts "Cannot use output directory \"#{output_dir}\""
|
141
|
+
exit 7
|
142
|
+
end
|
136
143
|
|
137
144
|
if options[:force] && torque_info_path.exist?
|
138
145
|
puts "- Overwriting file .torqueinfo.yaml"
|
@@ -157,7 +164,7 @@ end
|
|
157
164
|
|
158
165
|
# Determines whether to set up a new API token and project ID
|
159
166
|
|
160
|
-
|
167
|
+
should_setup_torque_info = true
|
161
168
|
if retained_torque_info_file
|
162
169
|
valid = /^\s*(y|Y|n|N)\s*$/
|
163
170
|
setup_info_prompt = ask("Existing Torque info file found. Would you like to set up a new API token? [y/n]") {
|
@@ -165,11 +172,11 @@ if retained_torque_info_file
|
|
165
172
|
q.validate = valid
|
166
173
|
}
|
167
174
|
setup_info_prompt.strip!
|
168
|
-
|
175
|
+
should_setup_torque_info = (setup_info_prompt =~ /y|Y/)
|
169
176
|
end
|
170
177
|
|
171
178
|
|
172
|
-
if
|
179
|
+
if should_setup_torque_info
|
173
180
|
|
174
181
|
# Adds the API token to the torque info file
|
175
182
|
|
@@ -247,12 +254,16 @@ if should_setup_info
|
|
247
254
|
end
|
248
255
|
end
|
249
256
|
|
250
|
-
# Finishes
|
251
257
|
|
258
|
+
# Sets the default format string
|
259
|
+
|
260
|
+
Torque::TorqueInfoParser.new.set("format", Torque::FormatString.default)
|
261
|
+
|
262
|
+
# Finishes
|
252
263
|
|
253
264
|
puts
|
254
265
|
puts "Configuration complete!"
|
255
|
-
|
266
|
+
unless options[:token] || (options[:output_dir] && !should_setup_torque_info)
|
256
267
|
puts "WARNING: Do not check .torqueinfo.yaml into your version control system! (Contains sensitive information)"
|
257
|
-
|
258
|
-
|
268
|
+
puts
|
269
|
+
end
|
data/bin/email
CHANGED
@@ -10,8 +10,8 @@ working_dir = "."
|
|
10
10
|
require 'highline/import'
|
11
11
|
require 'mail'
|
12
12
|
require 'optparse'
|
13
|
-
require "#{lib_dir}/torque/torque_info_parser"
|
14
13
|
require "#{lib_dir}/torque/pivotal"
|
14
|
+
require "#{lib_dir}/torque/torque_info_parser"
|
15
15
|
|
16
16
|
# Parses the options
|
17
17
|
options = {}
|
@@ -60,7 +60,7 @@ begin
|
|
60
60
|
rescue OptionParser::InvalidOption, OptionParser::MissingArgument
|
61
61
|
puts $!.to_s
|
62
62
|
puts option_parser
|
63
|
-
exit
|
63
|
+
exit 3
|
64
64
|
end
|
65
65
|
|
66
66
|
# Handles special cases and exceptions
|
@@ -72,15 +72,7 @@ if ((ARGV.member? "help") || options[:help])
|
|
72
72
|
elsif !ARGV.empty?
|
73
73
|
puts "Unknown arguments: #{ARGV.join(", ")}"
|
74
74
|
puts option_parser.help
|
75
|
-
exit
|
76
|
-
end
|
77
|
-
|
78
|
-
# Checks for a connection to Pivotal Tracker
|
79
|
-
|
80
|
-
if !Torque::Pivotal.connection?
|
81
|
-
puts "ABORTING"
|
82
|
-
puts "Cannot connect to www.pivotaltracker.com. A connection is required to use Torque"
|
83
|
-
exit 1
|
75
|
+
exit 3
|
84
76
|
end
|
85
77
|
|
86
78
|
# Parses the torque info file
|
@@ -92,7 +84,7 @@ rescue Torque::MissingTorqueInfoFileError => e
|
|
92
84
|
puts "ABORTING"
|
93
85
|
puts e.message
|
94
86
|
puts "Run 'torque config' in this directory, or change your working directory"
|
95
|
-
exit
|
87
|
+
exit 5
|
96
88
|
end
|
97
89
|
|
98
90
|
# Util method to display the current email settings
|
@@ -137,12 +129,6 @@ if options[:setup]
|
|
137
129
|
|
138
130
|
end
|
139
131
|
|
140
|
-
# Validates all emails to be added
|
141
|
-
|
142
|
-
options[:add].each do |email|
|
143
|
-
|
144
|
-
end
|
145
|
-
|
146
132
|
# Adds and removes emails from the email list
|
147
133
|
|
148
134
|
unless (options[:add].empty? && options[:rm].empty?)
|
@@ -169,9 +155,13 @@ unless (options[:add].empty? && options[:rm].empty?)
|
|
169
155
|
|
170
156
|
end
|
171
157
|
|
172
|
-
#
|
158
|
+
# Displays the current email settings
|
159
|
+
|
160
|
+
options_empty = options.size == 2 && options[:add].empty? && options[:rm].empty?
|
173
161
|
|
174
162
|
torque_info.parse
|
163
|
+
puts "(When torque is run with the '--email' option, these addresses will receive a copy of the notes)" \
|
164
|
+
if options_empty
|
175
165
|
puts
|
176
166
|
disp_email(torque_info)
|
177
|
-
puts
|
167
|
+
puts
|
data/bin/format
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Controls the format of the release notes that Torque generates.
|
4
|
+
# Prompts for/sets the format string, and/or prints an example of the current format settings
|
5
|
+
|
6
|
+
lib_dir = File.expand_path("../lib", File.dirname(__FILE__))
|
7
|
+
template_dir = File.expand_path("../template", File.dirname(__FILE__))
|
8
|
+
working_dir = "."
|
9
|
+
|
10
|
+
require 'highline/import'
|
11
|
+
require 'optparse'
|
12
|
+
require "#{lib_dir}/torque/format_string"
|
13
|
+
require "#{lib_dir}/torque/story"
|
14
|
+
require "#{lib_dir}/torque/torque_info_parser"
|
15
|
+
require "#{lib_dir}/torque/error/missing_torque_info_file_error"
|
16
|
+
|
17
|
+
# Parses the options
|
18
|
+
options = {}
|
19
|
+
option_parser = OptionParser.new do |opts|
|
20
|
+
|
21
|
+
help_message = "Sets the format string that Torque uses to generate release notes, or prints the current format " \
|
22
|
+
"string settings if run with no arguments"
|
23
|
+
help_message += "\nThe format string consists of plain text as well as a series of parameters (eg. \"%a\") that " \
|
24
|
+
"act as placeholders for elements of a story"
|
25
|
+
help_message += "\n"
|
26
|
+
help_message += "\nA format string of \"default\" will return the format string to its default value " \
|
27
|
+
"(\"#{Torque::FormatString.default}\")"
|
28
|
+
help_message += "\n"
|
29
|
+
help_message += "\n"
|
30
|
+
help_message +=
|
31
|
+
<<-END_STR
|
32
|
+
Parameters:
|
33
|
+
%a => Date accepted (MM/DD)
|
34
|
+
%A => Date accepted (YYYY/MM/DD)
|
35
|
+
%d => Description
|
36
|
+
%D => Description (tabbed once on each newline)
|
37
|
+
%e => Estimate
|
38
|
+
%i => ID
|
39
|
+
%l => Labels (separated by ", ")
|
40
|
+
%n => Newline character
|
41
|
+
%N => Name
|
42
|
+
%o => Owner of the story
|
43
|
+
%p => ID of the story's project
|
44
|
+
%u => URL pointing to the story
|
45
|
+
%t => Tab character
|
46
|
+
%T => Type (feature, bug, etc)
|
47
|
+
END_STR
|
48
|
+
|
49
|
+
opts.banner = "\nUsage:"
|
50
|
+
opts.banner += "\n torque format [options]"
|
51
|
+
opts.banner += "\n"
|
52
|
+
opts.banner += "\n#{help_message}"
|
53
|
+
opts.banner += "\n"
|
54
|
+
|
55
|
+
opts.on("-e", "--example", "Optionally sets your format string after printing an example story") do
|
56
|
+
|arg|
|
57
|
+
options[:example] = arg
|
58
|
+
end
|
59
|
+
|
60
|
+
opts.on("-h", "--help", "Displays this help screen") do
|
61
|
+
|arg|
|
62
|
+
options[:help] = arg
|
63
|
+
end
|
64
|
+
|
65
|
+
opts.on("-s", "--set", "Sets your format string") do
|
66
|
+
|arg|
|
67
|
+
options[:set] = arg
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
# Parses options and handles exceptions
|
73
|
+
|
74
|
+
begin
|
75
|
+
option_parser.parse!
|
76
|
+
|
77
|
+
rescue OptionParser::InvalidOption, OptionParser::MissingArgument
|
78
|
+
puts $!.to_s
|
79
|
+
puts option_parser
|
80
|
+
exit 3
|
81
|
+
end
|
82
|
+
|
83
|
+
# Handles special cases and exceptions
|
84
|
+
|
85
|
+
if ((ARGV.member? "help") || options[:help])
|
86
|
+
puts "(Ran with 'help' option; other options ignored)"
|
87
|
+
puts option_parser
|
88
|
+
exit
|
89
|
+
elsif !ARGV.empty?
|
90
|
+
puts "Unknown arguments: #{ARGV.join(", ")}"
|
91
|
+
puts option_parser.help
|
92
|
+
exit 3
|
93
|
+
elsif (options.has_key? :example) && (options.has_key? :set)
|
94
|
+
puts "Conflicting options: -e/--example and -s/--set. Choose either 'example' or 'set'."
|
95
|
+
exit 3
|
96
|
+
end
|
97
|
+
|
98
|
+
# An example story for display purposes
|
99
|
+
|
100
|
+
sample_story = Torque::Story.new({})
|
101
|
+
|
102
|
+
sample_story.current_state = "accepted"
|
103
|
+
sample_story.date_accepted = Date.new(2012, 12, 21)
|
104
|
+
sample_story.description = "Short description of story goes here\n- This is a side note\n- This is another side note"
|
105
|
+
sample_story.estimate = 3
|
106
|
+
sample_story.id = 12345678
|
107
|
+
sample_story.labels = ["label-1", "label-2"]
|
108
|
+
sample_story.name = "Story Name"
|
109
|
+
sample_story.owner = "Owner Smith"
|
110
|
+
sample_story.project_id = 123456
|
111
|
+
sample_story.type = "feature"
|
112
|
+
|
113
|
+
# Instantiates a TorqueInfoParser
|
114
|
+
|
115
|
+
begin
|
116
|
+
torque_info = Torque::TorqueInfoParser.new.parse
|
117
|
+
rescue Torque::MissingTorqueInfoFileError => e
|
118
|
+
puts "ABORTING"
|
119
|
+
puts e.message
|
120
|
+
puts "Run 'torque config' in this directory, or change your working directory"
|
121
|
+
exit 5
|
122
|
+
end
|
123
|
+
|
124
|
+
# If run with -e/--example or -s/--setup: Takes in a string, optionally verifies format settings, sets format string
|
125
|
+
|
126
|
+
if options[:example] || options[:set]
|
127
|
+
|
128
|
+
default = false # True if the default format string should be used
|
129
|
+
should_set = true # True if the format string should be changed on file
|
130
|
+
|
131
|
+
format = (ask("Enter a format string below:") {|q| q.readline = true}).to_s
|
132
|
+
|
133
|
+
if format == 'default'
|
134
|
+
default = true
|
135
|
+
format = Torque::FormatString.default
|
136
|
+
end
|
137
|
+
|
138
|
+
# If -e/--example, prints and validates the new settings
|
139
|
+
|
140
|
+
if options[:example]
|
141
|
+
puts "---"
|
142
|
+
puts Torque::FormatString.new(format).apply(sample_story)
|
143
|
+
puts "---"
|
144
|
+
|
145
|
+
valid = /^\s*(y|Y|n|N)\s*$/
|
146
|
+
should_set_prompt = ask("Would you like to set this as your format? [y/n]") {
|
147
|
+
|q|
|
148
|
+
q.validate = valid
|
149
|
+
}
|
150
|
+
should_set_prompt.strip!
|
151
|
+
should_set = (should_set_prompt =~ /y|Y/)
|
152
|
+
end
|
153
|
+
|
154
|
+
if should_set
|
155
|
+
torque_info.set("format", format)
|
156
|
+
|
157
|
+
to_print = "Set format string to "
|
158
|
+
to_print += (default ? "default" : "\"#{format}\"")
|
159
|
+
puts to_print
|
160
|
+
end
|
161
|
+
|
162
|
+
# If run with no arguments, displays the current format settings
|
163
|
+
|
164
|
+
else
|
165
|
+
puts
|
166
|
+
puts "Current format string: \"#{torque_info.format}\""
|
167
|
+
puts "---"
|
168
|
+
puts Torque::FormatString.new(torque_info.format).apply(sample_story)
|
169
|
+
puts "---"
|
170
|
+
end
|