torque 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: abb92afe8ffbc8574c523dc0edc68438b75ccdeb
4
+ data.tar.gz: 5e0715da5458863001a6c9ff66cfa591704ff830
5
+ SHA512:
6
+ metadata.gz: 63143235c62b8ddd4b95d6a8b6a654f78b17e4b2e4e9592009a51679eaa7f971cc0542246029938df55b473124bd9d91e49f370ca64cd26cb3a2ce73668c9435
7
+ data.tar.gz: f0ebb0b09dda8ae970bcd116eeb78ece99d183a21e625074de6638557efa65b0fd9adab1520ef9afeeeddfe22f8515377e4a38256dbe49cc2e47f9c493f912fd
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2013 Scrimmage
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,116 @@
1
+ Torque
2
+ ======
3
+
4
+ Introduction
5
+ ------------
6
+
7
+ Torque is a command line utility packaged as a Ruby gem. It compiles online data from a Pivotal Tracker project into a set of release notes for that project.
8
+
9
+ At start, Torque requests a Pivotal Tracker API token, which gives Torque access to information from your Pivotal Tracker projects. Torque then asks the user to choose one of their projects to begin to generate notes from.
10
+
11
+ Once configured, Torque requests data on the accepted stories from the current Pivotal project. It then compiles these stories into a first-draft release notes document. Depending on how consistently your team uses Pivotal Tracker, this document will contain:
12
+
13
+ * A record of each feature that was added to the project since the last time Torque was run
14
+ * A description of the feature
15
+ * The date that this feature was accepted
16
+ * A link to the Pivotal Tracker story that tracks this feature
17
+
18
+ Torque's default behavior is to document all the stories that were accepted since the last time Torque was run. For instance, if Torque was run on June 1st and then on June 10th, it would generate release notes from the stories that were accepted between June 1st and June 10th (inclusive). This is designed to make it easy to generate release notes each time new features are pushed to production: If Torque is run at the time of each new release, then it will generate notes for all the features that were added since the previous release. If needed, Torque can also generate notes for a custom date range.
19
+
20
+ Torque was designed and tested in a Ruby 2.0 environment.
21
+
22
+ Current Features
23
+ ----------------
24
+
25
+ * Automatically compiles all Pivotal Tracker stories accepted between the current date and the last time Torque was run
26
+ * Compile stories accepted within a custom date range
27
+ * Stores a record of each document as it's generated
28
+ * Configuration script that automatically sets up a directory to use Torque
29
+ * Project script that automatically displays/switches between your Pivotal Tracker projects
30
+ * Ability to email the finished release notes from a personal email account to a pre-specified mailing list. (Currently can only send from accounts hosted by Gmail)
31
+
32
+ Note on Confidentiality
33
+ -----------------------
34
+
35
+ During usage, Torque will request some confidential information -- namely, your Pivotal Tracker API token and your email username/password. This information is stored in a local config file on your computer and is only used to access (respectively) Pivotal Tracker and your email server. It is never collected, sent to a 3rd party, or used for any other purpose.
36
+
37
+ Torque stores this data in a file called '.torqueinfo.yaml': Do not commit this file to your version control system!
38
+
39
+ Installation
40
+ ------------
41
+
42
+ # gem install torque
43
+
44
+ Configuration
45
+ -------------
46
+
47
+ To configure Torque, run in your project's root directory
48
+
49
+ # torque config
50
+
51
+ The configuration script will request a Pivotal Tracker API token, which can be found at https://www.pivotaltracker.com/profile#api. The token can be reset at any time by running:
52
+
53
+ # 'torque config -t/--token'
54
+
55
+ To change the output directory Torque writes its release notes to:
56
+
57
+ # 'torque config -o/--output [directory]'
58
+
59
+ To overwrite the Torque settings and/or output directory:
60
+
61
+ # 'torque config -f/--force'
62
+
63
+ Usage
64
+ -----
65
+
66
+ In a directory that has been configured, run
67
+
68
+ # torque
69
+
70
+ Alternately, run Torque from a different directory by using the --root option:
71
+
72
+ # torque --root [configured/torque/directory]
73
+
74
+ This will compile release notes for all stories accepted since the last time you ran Torque in this directory.
75
+
76
+ To compile release notes for stories within a custom date range:
77
+
78
+ # torque -f [from] -t [to]
79
+
80
+ If [from] is set, [to] will default to today. If [to] is set, [from] will default to 1/1/1900.
81
+
82
+ To email the release notes from a personal email to Torque's mailing list:
83
+
84
+ # torque --email
85
+
86
+ Running with the 'verbose' option will print a running list of stories as they are added. Running with the 'silent' option will silence all output.
87
+
88
+ To display all available Pivotal Tracker projects or change your current project:
89
+
90
+ # torque project
91
+
92
+ To set up automatic emailing when the notes and add/remove from the mailing list:
93
+
94
+ # torque email
95
+
96
+ License
97
+ -------
98
+
99
+ Copyright (c) 2013 Scrimmage
100
+
101
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
102
+ this software and associated documentation files (the "Software"), to deal in
103
+ the Software without restriction, including without limitation the rights to
104
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
105
+ the Software, and to permit persons to whom the Software is furnished to do so,
106
+ subject to the following conditions:
107
+
108
+ The above copyright notice and this permission notice shall be included in all
109
+ copies or substantial portions of the Software.
110
+
111
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
112
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
113
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
114
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
115
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
116
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/VERSION ADDED
@@ -0,0 +1,3 @@
1
+ major:0
2
+ minor:0
3
+ patch:1
data/bin/config ADDED
@@ -0,0 +1,257 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Configuration script for Torque. Sets up an output directory and settings file
4
+
5
+ lib_dir = File.expand_path("../lib", File.dirname(__FILE__))
6
+ template_dir = File.expand_path("../template", File.dirname(__FILE__))
7
+ working_dir = "."
8
+
9
+ require 'fileutils'
10
+ require 'highline/import'
11
+ require 'net/http'
12
+ require 'optparse'
13
+ require 'pathname'
14
+ require "#{lib_dir}/torque/pivotal"
15
+ require "#{lib_dir}/torque/torque_info_parser"
16
+ require "#{lib_dir}/torque/project/project"
17
+ require "#{lib_dir}/torque/project/project_manager"
18
+
19
+ # Parses the options
20
+ options = {}
21
+ option_parser = OptionParser.new do |opts|
22
+
23
+ help_message = "Configures a directory to use Torque."
24
+ help_message += "\n"
25
+ help_message += "\nThis script will create a template for .torqueinfo.yaml and set up an output directory. It " \
26
+ "will also set up access to the Pivotal Tracker API"
27
+
28
+ opts.banner = "\nUsage:"
29
+ opts.banner += "\n torque config [options]"
30
+ opts.banner += "\n"
31
+ opts.banner += "\n#{help_message}"
32
+ opts.banner += "\n"
33
+ opts.banner += "\n"
34
+
35
+ opts.on("-f", "--force", "Force a configuration, overwriting any existing .torqueinfo file or output directory") do
36
+ |arg|
37
+ options[:force] = arg
38
+ end
39
+
40
+ opts.on("-h", "--help", "Display this help screen") do
41
+ |arg|
42
+ options[:help] = arg
43
+ end
44
+
45
+ opts.on("-o", "--output OUTPUT", "Set the output directory to the directory specified (default: release_notes)") do
46
+ |arg|
47
+ options[:output_dir] = arg
48
+ end
49
+
50
+ opts.on("-t", "--token", "Set the API token and Pivotal project only (do not change the filesystem)") do
51
+ |arg|
52
+ options[:token] = arg
53
+ end
54
+
55
+ end
56
+
57
+ # Parses options and handles exceptions
58
+
59
+ begin
60
+ option_parser.parse!
61
+
62
+ rescue OptionParser::InvalidOption, OptionParser::MissingArgument
63
+ puts $!.to_s
64
+ puts option_parser
65
+ exit
66
+ end
67
+
68
+ # Handles special cases and exceptions
69
+
70
+ if ARGV.member? "help" || options[:help]
71
+ puts "(Ran with 'help' option; other options ignored)"
72
+ puts option_parser
73
+ exit
74
+ elsif !ARGV.empty?
75
+ puts "Unknown arguments: #{ARGV.join(", ")}"
76
+ puts option_parser.help
77
+ exit
78
+ end
79
+
80
+ # Checks for a connection to Pivotal Tracker
81
+
82
+ if !Torque::Pivotal.connection?
83
+ puts "ABORTING"
84
+ puts "Cannot connect to www.pivotaltracker.com. A connection is required to configure Torque"
85
+ exit 1
86
+ end
87
+
88
+ # Configures the directory
89
+
90
+ if !options[:token]
91
+
92
+ puts "Configuring directory for Torque..."
93
+
94
+ # Checks that configuration is possible
95
+
96
+ default_output_dir = "release_notes"
97
+ output_dir = options[:output_dir] || default_output_dir
98
+ output_path = Pathname.new(output_dir)
99
+
100
+ if !options[:force] && !options[:output_dir] && output_path.exist?
101
+ puts "ABORTING"
102
+ puts "The default output directory, #{default_output_dir}, already exists."
103
+ puts "(Use -o to choose an existing output directory or create a new one)"
104
+ puts "(Use -f to overwrite an existing directory)"
105
+ exit
106
+ end
107
+
108
+
109
+ torque_info_path = Pathname.new(".torqueinfo.yaml")
110
+
111
+ if !options[:force] && !options[:output_dir] && torque_info_path.exist?
112
+ puts "ABORTING"
113
+ puts "A .torqueinfo.yaml file already exists in this directory."
114
+ puts "(Use -o to ignore this file and change only the output directory)"
115
+ puts "(Use -f to overwrite this file)"
116
+ exit
117
+ end
118
+
119
+
120
+ # Configures the directory
121
+
122
+ retained_torque_info_file = false # True if the torque info file is the same after configuration
123
+
124
+ if options[:force] && output_path.exist?
125
+ puts "- Overwriting directory #{output_dir}"
126
+ FileUtils.rm_r(output_dir)
127
+
128
+ elsif options[:output_dir] && output_path.exist?
129
+ puts "- Setting output directory to #{output_dir}"
130
+
131
+ else
132
+ puts "- Creating directory #{output_dir}"
133
+ end
134
+
135
+ FileUtils.mkdir_p("#{output_dir}/previous")
136
+
137
+ if options[:force] && torque_info_path.exist?
138
+ puts "- Overwriting file .torqueinfo.yaml"
139
+ FileUtils.rm(".torqueinfo.yaml")
140
+
141
+ elsif options[:output_dir] && torque_info_path.exist?
142
+ retained_torque_info_file = true
143
+
144
+ else
145
+ puts "- Creating file .torqueinfo.yaml"
146
+ end
147
+
148
+ FileUtils.touch("./.torqueinfo.yaml")
149
+
150
+ File.open(".torqueinfo.yaml", "a+") do |file|
151
+ file.write("\n\n")
152
+ end
153
+ Torque::TorqueInfoParser.new.set("output_dir", output_dir)
154
+
155
+ end
156
+
157
+
158
+ # Determines whether to set up a new API token and project ID
159
+
160
+ should_setup_info = true
161
+ if retained_torque_info_file
162
+ valid = /^\s*(y|Y|n|N)\s*$/
163
+ setup_info_prompt = ask("Existing Torque info file found. Would you like to set up a new API token? [y/n]") {
164
+ |q|
165
+ q.validate = valid
166
+ }
167
+ setup_info_prompt.strip!
168
+ should_setup_info = (setup_info_prompt =~ /y|Y/)
169
+ end
170
+
171
+
172
+ if should_setup_info
173
+
174
+ # Adds the API token to the torque info file
175
+
176
+ project_manager = Torque::ProjectManager.new
177
+
178
+ puts
179
+ puts "In order to generate release notes, Torque needs your account's Pivotal Tracker API token"
180
+
181
+ # Input loop
182
+ while true
183
+ token_input = ask("Please paste your Pivotal Tracker API token below: https://www.pivotaltracker.com/profile#api") {
184
+ |q| q.echo = "*"
185
+ }
186
+ token = token_input.to_s
187
+
188
+ Torque::Pivotal.new(token).check_token ? break : (puts "Token was invalid. Try again")
189
+ end
190
+
191
+ File.open(".torqueinfo.yaml", "a+") do |file|
192
+ Torque::TorqueInfoParser.new.set("token", token)
193
+ end
194
+
195
+ # Adds the project ID to the torque info file
196
+
197
+ project_manager.load_project_list(token)
198
+ project_list = project_manager.project_list
199
+
200
+ if project_list.empty?
201
+ puts "No projects found for your Pivotal Tracker account. Add a project to your account, then use 'torque " \
202
+ "project' to set your Torque project"
203
+
204
+ else
205
+
206
+ # If only one project exists, defaults to it
207
+ if project_list.length == 1
208
+ project_index = 0
209
+ puts
210
+
211
+ # Allows user to choose between multiple projects
212
+ else
213
+ choice_str = "Please select one of the following projects. Torque will use the stories from this project to " \
214
+ "generate release notes"
215
+ choice_str += "\n(Enter a number)"
216
+ project_list.each_with_index do
217
+ |project, index|
218
+ choice_str += "\n#{index} : #{project.id} #{project.name}"
219
+ end
220
+
221
+ # Short util method for parsing numbers from strings
222
+ # Returns nil if no number can be parsed from string or if the number parsed is >= max
223
+ def parse_index(string, max)
224
+ index = nil
225
+ begin; index = Integer(string)
226
+ rescue ArgumentError; return nil
227
+ end
228
+ (index >= max || index < 0) ? nil : index
229
+ end
230
+
231
+ # Input loop
232
+ puts
233
+ while true
234
+ puts choice_str
235
+ num_str = ask("")
236
+ project_index = parse_index(num_str, project_list.length)
237
+ project_index ? break : (puts "Choice was invalid. Try again")
238
+ end
239
+
240
+ end
241
+
242
+ project = project_list[project_index]
243
+ Torque::TorqueInfoParser.new.set("project", Integer(project.id))
244
+ puts "Set project to #{project.id} - '#{project.name}'"
245
+ puts "Use 'torque project' to change this project"
246
+
247
+ end
248
+ end
249
+
250
+ # Finishes
251
+
252
+ unless options[:token]
253
+ puts
254
+ puts "Configuration complete!"
255
+ puts "WARNING: Do not check .torqueinfo.yaml into your version control system! (Contains sensitive information)"
256
+ puts
257
+ end
data/bin/email ADDED
@@ -0,0 +1,172 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Manages email settings for Torque.
4
+ # Prompts for and stores a user's email and password, adds to/removes from the email_to list
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 'mail'
12
+ require 'optparse'
13
+ require "#{lib_dir}/torque/torque_info_parser"
14
+ require "#{lib_dir}/torque/pivotal"
15
+
16
+ # Parses the options
17
+ options = {}
18
+ option_parser = OptionParser.new do |opts|
19
+
20
+ help_message = "Handles email settings for Torque. Allows users to set up their own email address, add or remove " \
21
+ "emails from the email_to list, and display the current email settings"
22
+
23
+ opts.banner = "\nUsage:"
24
+ opts.banner += "\n torque email [options]"
25
+ opts.banner += "\n"
26
+ opts.banner += "\n#{help_message}"
27
+ opts.banner += "\n"
28
+ opts.banner += "\n"
29
+
30
+ options[:add] = []
31
+ options[:rm] = []
32
+
33
+ opts.on("-a", "--add ADDRESS", "Add an email address to the list") do
34
+ |arg|
35
+ options[:add] << arg
36
+ end
37
+
38
+ opts.on("-r", "--rm ADDRESS", "Remove an email address from the list") do
39
+ |arg|
40
+ options[:rm] << arg
41
+ end
42
+
43
+ opts.on("-s", "--setup", "Sets up a personal email address (Gmail only)") do
44
+ |arg|
45
+ options[:setup] = arg
46
+ end
47
+
48
+ end
49
+
50
+ # Parses options and handles exceptions
51
+
52
+ begin
53
+ option_parser.parse!
54
+
55
+ rescue OptionParser::InvalidOption, OptionParser::MissingArgument
56
+ puts $!.to_s
57
+ puts option_parser
58
+ exit
59
+ end
60
+
61
+ # Handles special cases and exceptions
62
+
63
+ if ARGV.member? "help" || options[:help]
64
+ puts "(Ran with 'help' option; other options ignored)"
65
+ puts option_parser
66
+ exit
67
+ elsif !ARGV.empty?
68
+ puts "Unknown arguments: #{ARGV.join(", ")}"
69
+ puts option_parser.help
70
+ exit
71
+ end
72
+
73
+ # Checks for a connection to Pivotal Tracker
74
+
75
+ if !Torque::Pivotal.connection?
76
+ puts "ABORTING"
77
+ puts "Cannot connect to www.pivotaltracker.com. A connection is required to use Torque"
78
+ exit 1
79
+ end
80
+
81
+ # Parses the torque info file
82
+
83
+ torque_info = Torque::TorqueInfoParser.new
84
+ begin
85
+ torque_info.parse
86
+ rescue Torque::MissingTorqueInfoFileError => e
87
+ puts "ABORTING"
88
+ puts e.message
89
+ puts "Run 'torque config' in this directory, or change your working directory"
90
+ exit 2
91
+ end
92
+
93
+ # Util method to display the current email settings
94
+ # Passes in the current TorqueInfoParser
95
+ def disp_email(torque_info)
96
+
97
+ if !torque_info.email_address
98
+ puts "No user email found. (Set up your email address with 'torque email -s/--setup')"
99
+ elsif !torque_info.email_password
100
+ puts "No password found for current user email, '#{torque_info.email_address}'. (Set this with 'torque email " \
101
+ "--setup')"
102
+ else
103
+ puts "Email: #{torque_info.email_address}"
104
+ end
105
+
106
+ if torque_info.email_to.nil? || torque_info.email_to.empty?
107
+ puts "Mailing list: <empty>"
108
+ else
109
+ puts "Mailing list:"
110
+ torque_info.email_to.each do |email|
111
+ puts " #{email}"
112
+ end
113
+ end
114
+
115
+ end
116
+
117
+ # Sets up the user's email and password
118
+
119
+ if options[:setup]
120
+
121
+ puts "Enter the email address and password for the account you wish to send emails from. (Only Gmail accounts are " \
122
+ "currently supported)"
123
+ email_address = ( ask("Address:") ).to_s
124
+ email_password = ( ask("Password:") {|p| p.echo = "*"} ).to_s
125
+
126
+ torque_info.set("email_address", email_address)
127
+ torque_info.set("email_password", email_password)
128
+
129
+ puts "Ready to email!"
130
+
131
+ puts "---" unless (options[:add].empty? && options[:rm].empty?)
132
+
133
+ end
134
+
135
+ # Validates all emails to be added
136
+
137
+ options[:add].each do |email|
138
+
139
+ end
140
+
141
+ # Adds and removes emails from the email list
142
+
143
+ unless (options[:add].empty? && options[:rm].empty?)
144
+
145
+ emails_added = torque_info.add_no_duplicates("email_to", options[:add])
146
+ options[:add].each do |email|
147
+ if emails_added.member? email
148
+ puts "'#{email}' added"
149
+ emails_added.delete(email)
150
+ else
151
+ puts "(add: '#{email}' is already on the list)"
152
+ end
153
+ end
154
+
155
+ emails_removed = torque_info.rm("email_to", options[:rm])
156
+ options[:rm].each do |email|
157
+ if emails_removed.member? email
158
+ puts "'#{email}' removed"
159
+ emails_removed.delete("#{email}")
160
+ else
161
+ puts "(rm: '#{email}' is not on the list)"
162
+ end
163
+ end
164
+
165
+ end
166
+
167
+ # Finishes
168
+
169
+ torque_info.parse
170
+ puts
171
+ disp_email(torque_info)
172
+ puts