pt 0.1
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/Changelog.md +3 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +49 -0
- data/RakeFile +11 -0
- data/bin/pt +8 -0
- data/lib/pt.rb +11 -0
- data/lib/pt/client.rb +96 -0
- data/lib/pt/data_row.rb +22 -0
- data/lib/pt/data_table.rb +62 -0
- data/lib/pt/ui.rb +292 -0
- metadata +125 -0
data/Changelog.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Raul Murciano raul@murciano.net
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# pt
|
2
|
+
|
3
|
+
Minimal client to use Pivotal Tracker from the console.
|
4
|
+
|
5
|
+
## Setup
|
6
|
+
|
7
|
+
gem install pt
|
8
|
+
|
9
|
+
The first time you run it, `pt` will ask you some data about your Pivotal Tracker account and your current project.
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
Run `pt` from the root folder of your project.
|
14
|
+
|
15
|
+
pt # shows your "My work" tasks list
|
16
|
+
|
17
|
+
Run `pt create` to create a new bug, chore or feature.
|
18
|
+
|
19
|
+
The rest of the commands will open you a list of your tasks and let you interact with it:
|
20
|
+
|
21
|
+
pt open # open a task in the browser
|
22
|
+
|
23
|
+
pt assign # assign owner
|
24
|
+
|
25
|
+
pt comment # add a comment
|
26
|
+
|
27
|
+
pt estimate # estimate a task in points scale
|
28
|
+
|
29
|
+
pt start # mark a task as started
|
30
|
+
|
31
|
+
pt finish # indicate you've finished a task
|
32
|
+
|
33
|
+
pt deliver # indicate the task is delivered
|
34
|
+
|
35
|
+
pt accept # mark a task as accepted
|
36
|
+
|
37
|
+
pt reject # mark a task as rejected, explaining why
|
38
|
+
|
39
|
+
## Thanks to...
|
40
|
+
|
41
|
+
- the [Pivotal Tracker](https://www.pivotaltracker.com) guys for making a planning tool that doesn't suck and has an API
|
42
|
+
- [Justin Smestad](https://github.com/jsmestad) for his nice `pivotal-tracker` gem
|
43
|
+
- [Bryan Liles](http://smartic.us/) for letting me take over the gem name
|
44
|
+
|
45
|
+
## License
|
46
|
+
See the LICENSE file included in the distribution.
|
47
|
+
|
48
|
+
## Copyright
|
49
|
+
Copyright (C) 2011 Raul Murciano <raul@murciano.net>.
|
data/RakeFile
ADDED
data/bin/pt
ADDED
data/lib/pt.rb
ADDED
data/lib/pt/client.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'pivotal-tracker'
|
2
|
+
|
3
|
+
class PT::Client
|
4
|
+
|
5
|
+
def self.get_api_token(email, password)
|
6
|
+
PivotalTracker::Client.token(email, password)
|
7
|
+
rescue RestClient::Unauthorized
|
8
|
+
raise PT::InputError.new("Bad email/password combination.")
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(api_number)
|
12
|
+
PivotalTracker::Client.token = api_number
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_projects
|
16
|
+
PivotalTracker::Project.all
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_project(project_id)
|
20
|
+
PivotalTracker::Project.find(project_id)
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_membership(project, email)
|
24
|
+
PivotalTracker::Membership.all(project).select{ |m| m.email == email }.first
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_current_iteration(project)
|
28
|
+
PivotalTracker::Iteration.current(project)
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_my_work(project, user_name)
|
32
|
+
project.stories.all :mywork => user_name
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_my_open_tasks(project, user_name)
|
36
|
+
project.stories.all :owner => user_name
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_my_tasks_to_estimate(project, user_name)
|
40
|
+
project.stories.all(:owner => user_name, :story_type => 'feature').select{ |t| t.estimate == -1 }
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_my_tasks_to_start(project, user_name)
|
44
|
+
tasks = project.stories.all(:owner => user_name, :current_state => 'unscheduled,rejected')
|
45
|
+
tasks.reject{ |t| (t.story_type == 'feature') && (t.estimate == -1) }
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_my_tasks_to_finish(project, user_name)
|
49
|
+
project.stories.all(:owner => user_name, :current_state => 'started')
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_my_tasks_to_deliver(project, user_name)
|
53
|
+
project.stories.all(:owner => user_name, :current_state => 'finished')
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_my_tasks_to_accept(project, user_name)
|
57
|
+
project.stories.all(:owner => user_name, :current_state => 'delivered')
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_my_tasks_to_reject(project, user_name)
|
61
|
+
project.stories.all(:owner => user_name, :current_state => 'delivered')
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_tasks_to_assign(project, user_name)
|
65
|
+
project.stories.all.select{ |t| t.owned_by == nil }
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_members(project)
|
69
|
+
project.memberships.all
|
70
|
+
end
|
71
|
+
|
72
|
+
def mark_task_as(project, task, state)
|
73
|
+
task = PivotalTracker::Story.find(task.id, project.id)
|
74
|
+
task.update(:current_state => state)
|
75
|
+
end
|
76
|
+
|
77
|
+
def estimate_task(project, task, points)
|
78
|
+
task = PivotalTracker::Story.find(task.id, project.id)
|
79
|
+
task.update(:estimate => points)
|
80
|
+
end
|
81
|
+
|
82
|
+
def assign_task(project, task, owner)
|
83
|
+
task = PivotalTracker::Story.find(task.id, project.id)
|
84
|
+
task.update(:owned_by => owner)
|
85
|
+
end
|
86
|
+
|
87
|
+
def comment_task(project, task, comment)
|
88
|
+
task = PivotalTracker::Story.find(task.id, project.id)
|
89
|
+
task.notes.create(:text => comment)
|
90
|
+
end
|
91
|
+
|
92
|
+
def create_task(project, name, owner, requester, task_type)
|
93
|
+
project.stories.create(:name => name, :owned_by => owner, :requested_by => requester, :story_type => task_type)
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
data/lib/pt/data_row.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
class PT::DataRow
|
2
|
+
|
3
|
+
attr_accessor :num, :record
|
4
|
+
|
5
|
+
def initialize(orig, dataset)
|
6
|
+
@record = orig
|
7
|
+
@num = dataset.index(orig) + 1
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing(method)
|
11
|
+
@record.send method
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
@record.send(self.to_s_attribute)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s_attribute
|
19
|
+
@n.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'hirb'
|
2
|
+
|
3
|
+
module PT
|
4
|
+
|
5
|
+
class DataTable
|
6
|
+
|
7
|
+
extend ::Hirb::Console
|
8
|
+
|
9
|
+
def initialize(dataset)
|
10
|
+
@rows = dataset.map{ |row| DataRow.new(row, dataset) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def print
|
14
|
+
if @rows.empty?
|
15
|
+
puts "\n -- empty list -- \n"
|
16
|
+
else
|
17
|
+
self.class.table @rows, :fields => [:num] + self.class.fields, :unicode => true, :description => false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def [](pos)
|
22
|
+
pos = pos.to_i
|
23
|
+
(pos < 1 || pos > @rows.length) ? nil : @rows[pos-1].record
|
24
|
+
end
|
25
|
+
|
26
|
+
def length
|
27
|
+
@rows.length
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.fields
|
31
|
+
[]
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
class ProjectTable < DataTable
|
38
|
+
|
39
|
+
def self.fields
|
40
|
+
[:name]
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
class TasksTable < DataTable
|
47
|
+
|
48
|
+
def self.fields
|
49
|
+
[:name, :current_state]
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
class MembersTable < DataTable
|
55
|
+
|
56
|
+
def self.fields
|
57
|
+
[:name]
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
data/lib/pt/ui.rb
ADDED
@@ -0,0 +1,292 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'colored'
|
3
|
+
require 'highline'
|
4
|
+
|
5
|
+
class PT::UI
|
6
|
+
|
7
|
+
GLOBAL_CONFIG_PATH = ENV['HOME'] + "/.pt"
|
8
|
+
LOCAL_CONFIG_PATH = Dir.pwd + '/.pt'
|
9
|
+
|
10
|
+
def initialize(args)
|
11
|
+
@io = HighLine.new
|
12
|
+
@global_config = load_global_config
|
13
|
+
@client = PT::Client.new(@global_config[:api_number])
|
14
|
+
@local_config = load_local_config
|
15
|
+
@project = @client.get_project(@local_config[:project_id])
|
16
|
+
command = args[0].to_sym rescue :my_work
|
17
|
+
params = args[1..-1]
|
18
|
+
commands.include?(command.to_sym) ? send(command.to_sym) : help(command)
|
19
|
+
end
|
20
|
+
|
21
|
+
def my_work
|
22
|
+
title("My Work for #{user_s} in #{project_to_s}")
|
23
|
+
stories = @client.get_my_work(@project, @local_config[:user_name])
|
24
|
+
PT::TasksTable.new(stories).print
|
25
|
+
end
|
26
|
+
|
27
|
+
def create
|
28
|
+
title("Let's create a new task:")
|
29
|
+
name = ask("Name for the new task:")
|
30
|
+
if ask('Do you want to assign it now? (y/n)').downcase == 'y'
|
31
|
+
members = @client.get_members(@project)
|
32
|
+
table = PT::MembersTable.new(members)
|
33
|
+
owner = select("Please select a member to assign him the task", table).name
|
34
|
+
else
|
35
|
+
owner = nil
|
36
|
+
end
|
37
|
+
requester = @local_config[:user_name]
|
38
|
+
task_type = ask('Type? (c)hore, (b)ug, anything else for feature)')
|
39
|
+
task_type = case task_type
|
40
|
+
when 'c', 'chore'
|
41
|
+
'chore'
|
42
|
+
when 'b', 'bug'
|
43
|
+
'bug'
|
44
|
+
else
|
45
|
+
'feature'
|
46
|
+
end
|
47
|
+
result = @client.create_task(@project, name, owner, requester, task_type)
|
48
|
+
if result.errors.any?
|
49
|
+
error(result.errors.errors)
|
50
|
+
else
|
51
|
+
congrats("Task created, yay!")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def open
|
56
|
+
title("Tasks for #{user_s} in #{project_to_s}")
|
57
|
+
tasks = @client.get_my_open_tasks(@project, @local_config[:user_name])
|
58
|
+
table = PT::TasksTable.new(tasks)
|
59
|
+
task = select("Please select a story to open it in the browser", table)
|
60
|
+
`open #{task.url}`
|
61
|
+
end
|
62
|
+
|
63
|
+
def comment
|
64
|
+
title("Tasks for #{user_s} in #{project_to_s}")
|
65
|
+
tasks = @client.get_my_work(@project, @local_config[:user_name])
|
66
|
+
table = PT::TasksTable.new(tasks)
|
67
|
+
task = select("Please select a story to comment it", table)
|
68
|
+
comment = ask("Write your comment")
|
69
|
+
if @client.comment_task(@project, task, comment)
|
70
|
+
congrats("Comment sent, thanks!")
|
71
|
+
else
|
72
|
+
error("Ummm, something went wrong.")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def assign
|
77
|
+
title("Tasks for #{user_s} in #{project_to_s}")
|
78
|
+
tasks = @client.get_tasks_to_assign(@project, @local_config[:user_name])
|
79
|
+
table = PT::TasksTable.new(tasks)
|
80
|
+
task = select("Please select a task to assign it an owner", table)
|
81
|
+
members = @client.get_members(@project)
|
82
|
+
table = PT::MembersTable.new(members)
|
83
|
+
owner = select("Please select a member to assign him the task", table).name
|
84
|
+
result = @client.assign_task(@project, task, owner)
|
85
|
+
if result.errors.any?
|
86
|
+
error(result.errors.errors)
|
87
|
+
else
|
88
|
+
congrats("Task assigned, thanks!")
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
def estimate
|
94
|
+
title("Tasks for #{user_s} in #{project_to_s}")
|
95
|
+
tasks = @client.get_my_tasks_to_estimate(@project, @local_config[:user_name])
|
96
|
+
table = PT::TasksTable.new(tasks)
|
97
|
+
task = select("Please select a story to estimate it", table)
|
98
|
+
estimation = ask("How many points you estimate for it? (#{@project.point_scale})")
|
99
|
+
result = @client.estimate_task(@project, task, estimation)
|
100
|
+
if result.errors.any?
|
101
|
+
error(result.errors.errors)
|
102
|
+
else
|
103
|
+
congrats("Task estimated, thanks!")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def start
|
108
|
+
title("Tasks for #{user_s} in #{project_to_s}")
|
109
|
+
tasks = @client.get_my_tasks_to_start(@project, @local_config[:user_name])
|
110
|
+
table = PT::TasksTable.new(tasks)
|
111
|
+
task = select("Please select a story to mark it as started", table)
|
112
|
+
result = @client.mark_task_as(@project, task, 'started')
|
113
|
+
if result.errors.any?
|
114
|
+
error(result.errors.errors)
|
115
|
+
else
|
116
|
+
congrats("Task started, go for it!")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def finish
|
121
|
+
title("Tasks for #{user_s} in #{project_to_s}")
|
122
|
+
tasks = @client.get_my_tasks_to_finish(@project, @local_config[:user_name])
|
123
|
+
table = PT::TasksTable.new(tasks)
|
124
|
+
task = select("Please select a story to mark it as finished", table)
|
125
|
+
if task.story_type == 'chore'
|
126
|
+
result = @client.mark_task_as(@project, task, 'accepted')
|
127
|
+
else
|
128
|
+
result = @client.mark_task_as(@project, task, 'finished')
|
129
|
+
end
|
130
|
+
if result.errors.any?
|
131
|
+
error(result.errors.errors)
|
132
|
+
else
|
133
|
+
congrats("Another task bites the dust, yeah!")
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def deliver
|
138
|
+
title("Tasks for #{user_s} in #{project_to_s}")
|
139
|
+
tasks = @client.get_my_tasks_to_deliver(@project, @local_config[:user_name])
|
140
|
+
table = PT::TasksTable.new(tasks)
|
141
|
+
task = select("Please select a story to mark it as delivered", table)
|
142
|
+
result = @client.mark_task_as(@project, task, 'delivered')
|
143
|
+
error(result.errors.errors) if result.errors.any?
|
144
|
+
if result.errors.any?
|
145
|
+
error(result.errors.errors)
|
146
|
+
else
|
147
|
+
congrats("Task delivered, congrats!")
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def accept
|
152
|
+
title("Tasks for #{user_s} in #{project_to_s}")
|
153
|
+
tasks = @client.get_my_tasks_to_accept(@project, @local_config[:user_name])
|
154
|
+
table = PT::TasksTable.new(tasks)
|
155
|
+
task = select("Please select a story to mark it as accepted", table)
|
156
|
+
result = @client.mark_task_as(@project, task, 'accepted')
|
157
|
+
if result.errors.any?
|
158
|
+
error(result.errors.errors)
|
159
|
+
else
|
160
|
+
congrats("Task accepted, hooray!")
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def reject
|
165
|
+
title("Tasks for #{user_s} in #{project_to_s}")
|
166
|
+
tasks = @client.get_my_tasks_to_reject(@project, @local_config[:user_name])
|
167
|
+
table = PT::TasksTable.new(tasks)
|
168
|
+
task = select("Please select a story to mark it as rejected", table)
|
169
|
+
comment = ask("Please explain why are you rejecting the task")
|
170
|
+
if @client.comment_task(@project, task, comment)
|
171
|
+
result = @client.mark_task_as(@project, task, 'rejected')
|
172
|
+
congrats("Task rejected, thanks!")
|
173
|
+
else
|
174
|
+
error("Ummm, something went wrong.")
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
protected
|
179
|
+
|
180
|
+
def commands
|
181
|
+
(public_methods - Object.public_methods).sort
|
182
|
+
end
|
183
|
+
|
184
|
+
# Config
|
185
|
+
|
186
|
+
def load_global_config
|
187
|
+
config = YAML.load(File.read(GLOBAL_CONFIG_PATH)) rescue {}
|
188
|
+
if config.empty?
|
189
|
+
message "I can't find info about your Pivotal Tracker account in #{GLOBAL_CONFIG_PATH}"
|
190
|
+
while !config[:api_number] do
|
191
|
+
config[:email] = ask "What is your email?"
|
192
|
+
password = ask_secret "And your password? (won't be displayed on screen)"
|
193
|
+
begin
|
194
|
+
config[:api_number] = PT::Client.get_api_token(config[:email], password)
|
195
|
+
rescue PT::InputError => e
|
196
|
+
error e.message + " Please try again."
|
197
|
+
end
|
198
|
+
end
|
199
|
+
congrats "Thanks!",
|
200
|
+
"Your API id is " + config[:api_number],
|
201
|
+
"I'm saving it in #{GLOBAL_CONFIG_PATH} to don't ask you again."
|
202
|
+
save_config(config, GLOBAL_CONFIG_PATH)
|
203
|
+
end
|
204
|
+
config
|
205
|
+
end
|
206
|
+
|
207
|
+
def load_local_config
|
208
|
+
config = YAML.load(File.read(LOCAL_CONFIG_PATH)) rescue {}
|
209
|
+
if config.empty?
|
210
|
+
message "I can't find info about this project in #{LOCAL_CONFIG_PATH}"
|
211
|
+
projects = PT::ProjectTable.new(@client.get_projects)
|
212
|
+
project = select("Please select the project for the current directory", projects)
|
213
|
+
config[:project_id], config[:project_name] = project.id, project.name
|
214
|
+
membership = @client.get_membership(project, @global_config[:email])
|
215
|
+
config[:user_name], config[:user_id], config[:user_initials] = membership.name, membership.id, membership.initials
|
216
|
+
congrats "Thanks! I'm saving this project's info",
|
217
|
+
"in #{LOCAL_CONFIG_PATH}: remember to .gitignore it!"
|
218
|
+
save_config(config, LOCAL_CONFIG_PATH)
|
219
|
+
end
|
220
|
+
config
|
221
|
+
end
|
222
|
+
|
223
|
+
def save_config(config, path)
|
224
|
+
File.new(path, 'w') unless File.exists?(path)
|
225
|
+
File.open(path, 'w') {|f| f.write(config.to_yaml) }
|
226
|
+
end
|
227
|
+
|
228
|
+
# I/O
|
229
|
+
|
230
|
+
def split_lines(text)
|
231
|
+
text.respond_to?(:join) ? text.join("\n") : text
|
232
|
+
end
|
233
|
+
|
234
|
+
def title(*msg)
|
235
|
+
puts "\n#{split_lines(msg)}".bold
|
236
|
+
end
|
237
|
+
|
238
|
+
def congrats(*msg)
|
239
|
+
puts "\n#{split_lines(msg).green.bold}"
|
240
|
+
end
|
241
|
+
|
242
|
+
def message(*msg)
|
243
|
+
puts "\n#{split_lines(msg)}"
|
244
|
+
end
|
245
|
+
|
246
|
+
def error(*msg)
|
247
|
+
puts "\n#{split_lines(msg).red.bold}"
|
248
|
+
end
|
249
|
+
|
250
|
+
def select(msg, table)
|
251
|
+
if table.length > 0
|
252
|
+
begin
|
253
|
+
table.print
|
254
|
+
row = ask "#{msg} (1-#{table.length}, 'q' to exit)"
|
255
|
+
quit if row == 'q'
|
256
|
+
selected = table[row]
|
257
|
+
error "Invalid selection, try again:" unless selected
|
258
|
+
end until selected
|
259
|
+
selected
|
260
|
+
else
|
261
|
+
table.print
|
262
|
+
message "Sorry, there are no options to select."
|
263
|
+
quit
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def quit
|
268
|
+
message "bye!"
|
269
|
+
exit
|
270
|
+
end
|
271
|
+
|
272
|
+
def ask(msg)
|
273
|
+
@io.ask("#{msg.bold}")
|
274
|
+
end
|
275
|
+
|
276
|
+
def ask_secret(msg)
|
277
|
+
@io.ask("#{msg.bold}"){ |q| q.echo = '*' }
|
278
|
+
end
|
279
|
+
|
280
|
+
def help(command)
|
281
|
+
error "Command <#{command}> unknown.", "Available commands:" + commands.map{ |c| "\n- #{c}" }.join
|
282
|
+
end
|
283
|
+
|
284
|
+
def user_s
|
285
|
+
"#{@local_config[:user_name]} (#{@local_config[:user_initials]})"
|
286
|
+
end
|
287
|
+
|
288
|
+
def project_to_s
|
289
|
+
"Project #{@local_config[:project_name].upcase}"
|
290
|
+
end
|
291
|
+
|
292
|
+
end
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pt
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
version: "0.1"
|
9
|
+
platform: ruby
|
10
|
+
authors:
|
11
|
+
- Raul Murciano
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
15
|
+
|
16
|
+
date: 2011-06-30 00:00:00 -07:00
|
17
|
+
default_executable:
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
20
|
+
name: pivotal-tracker
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: hirb
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
segments:
|
41
|
+
- 0
|
42
|
+
version: "0"
|
43
|
+
type: :runtime
|
44
|
+
version_requirements: *id002
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: colored
|
47
|
+
prerelease: false
|
48
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
segments:
|
54
|
+
- 0
|
55
|
+
version: "0"
|
56
|
+
type: :runtime
|
57
|
+
version_requirements: *id003
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: highline
|
60
|
+
prerelease: false
|
61
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
segments:
|
67
|
+
- 0
|
68
|
+
version: "0"
|
69
|
+
type: :runtime
|
70
|
+
version_requirements: *id004
|
71
|
+
description: Minimalist, opinionated client to manage your Pivotal Tracker tasks from the command line.
|
72
|
+
email:
|
73
|
+
- raul@murciano.net
|
74
|
+
executables:
|
75
|
+
- pt
|
76
|
+
extensions: []
|
77
|
+
|
78
|
+
extra_rdoc_files: []
|
79
|
+
|
80
|
+
files:
|
81
|
+
- lib/pt/client.rb
|
82
|
+
- lib/pt/data_row.rb
|
83
|
+
- lib/pt/data_table.rb
|
84
|
+
- lib/pt/ui.rb
|
85
|
+
- lib/pt.rb
|
86
|
+
- Changelog.md
|
87
|
+
- Gemfile
|
88
|
+
- LICENSE
|
89
|
+
- RakeFile
|
90
|
+
- README.md
|
91
|
+
- bin/pt
|
92
|
+
has_rdoc: true
|
93
|
+
homepage: http://www.github.com/raul/pt
|
94
|
+
licenses: []
|
95
|
+
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
segments:
|
107
|
+
- 0
|
108
|
+
version: "0"
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
segments:
|
115
|
+
- 0
|
116
|
+
version: "0"
|
117
|
+
requirements: []
|
118
|
+
|
119
|
+
rubyforge_project: pt
|
120
|
+
rubygems_version: 1.3.7
|
121
|
+
signing_key:
|
122
|
+
specification_version: 3
|
123
|
+
summary: Client to use Pivotal Tracker from the console.
|
124
|
+
test_files: []
|
125
|
+
|