pt 0.8.6 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog.md +4 -0
- data/Gemfile +1 -0
- data/README.md +2 -45
- data/bin/pt +1 -1
- data/lib/pt.rb +3 -1
- data/lib/pt/action.rb +151 -0
- data/lib/pt/cli.rb +183 -0
- data/lib/pt/client.rb +60 -50
- data/lib/pt/data_row.rb +5 -1
- data/lib/pt/data_table.rb +12 -1
- data/lib/pt/helper.rb +271 -0
- data/lib/pt/version.rb +1 -1
- data/pt.gemspec +6 -1
- metadata +75 -3
- data/lib/pt/ui.rb +0 -771
data/lib/pt/data_row.rb
CHANGED
@@ -3,7 +3,7 @@ require 'iconv' unless "older_ruby?".respond_to?(:force_encoding)
|
|
3
3
|
module PT
|
4
4
|
class DataRow
|
5
5
|
|
6
|
-
attr_accessor :num, :record, :state
|
6
|
+
attr_accessor :num, :record, :state, :owners
|
7
7
|
|
8
8
|
def initialize(orig, dataset)
|
9
9
|
@record = orig
|
@@ -11,6 +11,10 @@ module PT
|
|
11
11
|
if defined? orig.current_state
|
12
12
|
@state = orig.current_state
|
13
13
|
end
|
14
|
+
|
15
|
+
if defined? orig.owners
|
16
|
+
@owners = orig.owners.map(&:initials).join(',')
|
17
|
+
end
|
14
18
|
end
|
15
19
|
|
16
20
|
def method_missing(method)
|
data/lib/pt/data_table.rb
CHANGED
@@ -20,6 +20,9 @@ module PT
|
|
20
20
|
if config[:max_width] && config[:max_width] < max_width
|
21
21
|
max_width = config[:max_width]
|
22
22
|
end
|
23
|
+
headers = [:num]
|
24
|
+
|
25
|
+
headers += self.class.headers.present? ? self.class.headers : self.class.fields
|
23
26
|
|
24
27
|
self.class.table @rows, :fields => [:num] + self.class.fields,
|
25
28
|
:change_fields => %w{num pt_id},
|
@@ -41,6 +44,10 @@ module PT
|
|
41
44
|
[]
|
42
45
|
end
|
43
46
|
|
47
|
+
def self.headers
|
48
|
+
[]
|
49
|
+
end
|
50
|
+
|
44
51
|
end
|
45
52
|
|
46
53
|
|
@@ -56,7 +63,11 @@ module PT
|
|
56
63
|
class TasksTable < DataTable
|
57
64
|
|
58
65
|
def self.fields
|
59
|
-
[:name, :state, :id]
|
66
|
+
[:name, :owners, :story_type, :estimate, :state, :id]
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.headers
|
70
|
+
[:name, :owners, :type, :point, :state, :id]
|
60
71
|
end
|
61
72
|
|
62
73
|
end
|
data/lib/pt/helper.rb
ADDED
@@ -0,0 +1,271 @@
|
|
1
|
+
module PT
|
2
|
+
module Helper
|
3
|
+
|
4
|
+
GLOBAL_CONFIG_PATH = ENV['HOME'] + "/.pt"
|
5
|
+
LOCAL_CONFIG_PATH = Dir.pwd + '/.pt'
|
6
|
+
|
7
|
+
def load_global_config
|
8
|
+
|
9
|
+
# skip global config if env vars are set
|
10
|
+
if ENV['PIVOTAL_EMAIL'] and ENV['PIVOTAL_API_KEY']
|
11
|
+
config = {
|
12
|
+
:email => ENV['PIVOTAL_EMAIL'],
|
13
|
+
:api_number => ENV['PIVOTAL_API_KEY']
|
14
|
+
}
|
15
|
+
return config
|
16
|
+
end
|
17
|
+
|
18
|
+
config = YAML.load(File.read(GLOBAL_CONFIG_PATH)) rescue {}
|
19
|
+
if config.empty?
|
20
|
+
message "I can't find info about your Pivotal Tracker account in #{GLOBAL_CONFIG_PATH}."
|
21
|
+
while !config[:api_number] do
|
22
|
+
config[:api_number] = ask "What is your token?"
|
23
|
+
end
|
24
|
+
congrats "Thanks!",
|
25
|
+
"Your API id is " + config[:api_number],
|
26
|
+
"I'm saving it in #{GLOBAL_CONFIG_PATH} so you don't have to log in again."
|
27
|
+
save_config(config, GLOBAL_CONFIG_PATH)
|
28
|
+
end
|
29
|
+
config
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_local_config_path
|
33
|
+
# If the local config path does not exist, check to see if we're in a git repo
|
34
|
+
# And if so, try the top level of the checkout
|
35
|
+
if (!File.exist?(LOCAL_CONFIG_PATH) && system('git rev-parse 2> /dev/null'))
|
36
|
+
return `git rev-parse --show-toplevel`.chomp() + '/.pt'
|
37
|
+
else
|
38
|
+
return LOCAL_CONFIG_PATH
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def load_local_config
|
43
|
+
check_local_config_path
|
44
|
+
config = YAML.load(File.read(get_local_config_path())) rescue {}
|
45
|
+
|
46
|
+
|
47
|
+
if ENV['PIVOTAL_PROJECT_ID']
|
48
|
+
|
49
|
+
config[:project_id] = ENV['PIVOTAL_PROJECT_ID']
|
50
|
+
|
51
|
+
@client = Client.new(@global_config[:api_number])
|
52
|
+
project = @client.get_project(config[:project_id])
|
53
|
+
config[:project_name] = project.name
|
54
|
+
|
55
|
+
membership = @client.get_my_info
|
56
|
+
config[:user_name], config[:user_id], config[:user_initials] = membership.name, membership.id, membership.initials
|
57
|
+
save_config(config, get_local_config_path())
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
if config.empty?
|
62
|
+
message "I can't find info about this project in #{get_local_config_path()}"
|
63
|
+
@client = Client.new(@global_config[:api_number])
|
64
|
+
projects = ProjectTable.new(@client.get_projects)
|
65
|
+
project = select("Please select the project for the current directory", projects)
|
66
|
+
config[:project_id], config[:project_name] = project.id, project.name
|
67
|
+
project = @client.get_project(project.id)
|
68
|
+
membership = @client.get_my_info
|
69
|
+
config[:user_name], config[:user_id], config[:user_initials] = membership.name, membership.id, membership.initials
|
70
|
+
congrats "Thanks! I'm saving this project's info",
|
71
|
+
"in #{get_local_config_path()}: remember to .gitignore it!"
|
72
|
+
save_config(config, get_local_config_path())
|
73
|
+
end
|
74
|
+
config
|
75
|
+
end
|
76
|
+
|
77
|
+
def check_local_config_path
|
78
|
+
if GLOBAL_CONFIG_PATH == get_local_config_path()
|
79
|
+
error("Please execute .pt inside your project directory and not in your home.")
|
80
|
+
exit
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def save_config(config, path)
|
85
|
+
File.new(path, 'w') unless File.exists?(path)
|
86
|
+
File.open(path, 'w') {|f| f.write(config.to_yaml) }
|
87
|
+
end
|
88
|
+
|
89
|
+
# I/O
|
90
|
+
|
91
|
+
def split_lines(text)
|
92
|
+
text.respond_to?(:join) ? text.join("\n") : text
|
93
|
+
end
|
94
|
+
|
95
|
+
def title(*msg)
|
96
|
+
puts "\n#{split_lines(msg)}".bold
|
97
|
+
end
|
98
|
+
|
99
|
+
def congrats(*msg)
|
100
|
+
puts "\n#{split_lines(msg).green.bold}"
|
101
|
+
end
|
102
|
+
|
103
|
+
def message(*msg)
|
104
|
+
puts "\n#{split_lines(msg)}"
|
105
|
+
end
|
106
|
+
|
107
|
+
def compact_message(*msg)
|
108
|
+
puts "#{split_lines(msg)}"
|
109
|
+
end
|
110
|
+
|
111
|
+
def error(*msg)
|
112
|
+
puts "\n#{split_lines(msg).red.bold}"
|
113
|
+
end
|
114
|
+
|
115
|
+
def select(msg, table)
|
116
|
+
if table.length > 0
|
117
|
+
begin
|
118
|
+
table.print @global_config
|
119
|
+
row = ask "#{msg} (1-#{table.length}, 'n' to fetch next data, 'p' to fetch previous data, 'q' to exit)"
|
120
|
+
case row
|
121
|
+
when 'q'
|
122
|
+
quit
|
123
|
+
when 'n'
|
124
|
+
return 'n'
|
125
|
+
when 'p'
|
126
|
+
return 'p'
|
127
|
+
end
|
128
|
+
selected = table[row]
|
129
|
+
error "Invalid selection, try again:" unless selected
|
130
|
+
end until selected
|
131
|
+
selected
|
132
|
+
else
|
133
|
+
table.print @global_config
|
134
|
+
message "Sorry, there are no options to select."
|
135
|
+
quit
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def quit
|
140
|
+
message "bye!"
|
141
|
+
exit
|
142
|
+
end
|
143
|
+
|
144
|
+
def ask(msg)
|
145
|
+
@io.ask("#{msg.bold}")
|
146
|
+
end
|
147
|
+
|
148
|
+
def ask_secret(msg)
|
149
|
+
@io.ask("#{msg.bold}"){ |q| q.echo = '*' }
|
150
|
+
end
|
151
|
+
|
152
|
+
def user_s
|
153
|
+
"#{@local_config[:user_name]} (#{@local_config[:user_initials]})"
|
154
|
+
end
|
155
|
+
|
156
|
+
def project_to_s
|
157
|
+
"Project #{@local_config[:project_name].upcase}"
|
158
|
+
end
|
159
|
+
|
160
|
+
def task_type_or_nil query
|
161
|
+
if (["feature", "bug", "chore"].index query)
|
162
|
+
return query
|
163
|
+
end
|
164
|
+
nil
|
165
|
+
end
|
166
|
+
|
167
|
+
def task_by_id_or_pt_id id
|
168
|
+
if id < 1000
|
169
|
+
tasks = @client.get_my_work(@local_config[:user_name])
|
170
|
+
table = TasksTable.new(tasks)
|
171
|
+
table[id]
|
172
|
+
else
|
173
|
+
@client.get_task_by_id id
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def find_task query
|
178
|
+
members = @client.get_members
|
179
|
+
members.each do | member |
|
180
|
+
if member.name.downcase.index query
|
181
|
+
return member.name
|
182
|
+
end
|
183
|
+
end
|
184
|
+
nil
|
185
|
+
end
|
186
|
+
|
187
|
+
def find_owner query
|
188
|
+
if query
|
189
|
+
member = @client.get_member(query)
|
190
|
+
return member ? member.person : nil
|
191
|
+
end
|
192
|
+
nil
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
def show_activity(activity, tasks)
|
197
|
+
message("#{activity.message}")
|
198
|
+
end
|
199
|
+
|
200
|
+
def get_open_story_task_from_params(task)
|
201
|
+
title "Pending tasks for '#{task.name}'"
|
202
|
+
task_struct = Struct.new(:description, :position)
|
203
|
+
|
204
|
+
pending_tasks = [
|
205
|
+
task_struct.new('<< Add new task >>', -1)
|
206
|
+
]
|
207
|
+
|
208
|
+
task.tasks.each{ |t| pending_tasks << t unless t.complete }
|
209
|
+
table = TodoTaskTable.new(pending_tasks)
|
210
|
+
select("Pick task to edit, 1 to add new task", table)
|
211
|
+
end
|
212
|
+
|
213
|
+
def edit_story_task(task)
|
214
|
+
action_class = Struct.new(:action, :key)
|
215
|
+
|
216
|
+
table = ActionTable.new([
|
217
|
+
action_class.new('Complete', :complete),
|
218
|
+
# action_class.new('Delete', :delete),
|
219
|
+
action_class.new('Edit', :edit)
|
220
|
+
# Move?
|
221
|
+
])
|
222
|
+
action_to_execute = select('What to do with todo?', table)
|
223
|
+
|
224
|
+
task.project_id = project.id
|
225
|
+
task.client = project.client
|
226
|
+
case action_to_execute.key
|
227
|
+
when :complete then
|
228
|
+
task.complete = true
|
229
|
+
congrats('Todo task completed!')
|
230
|
+
# when :delete then
|
231
|
+
# task.delete
|
232
|
+
# congrats('Todo task removed')
|
233
|
+
when :edit then
|
234
|
+
new_description = ask('New task description')
|
235
|
+
task.description = new_description
|
236
|
+
congrats("Todo task changed to: \"#{task.description}\"")
|
237
|
+
end
|
238
|
+
task.save
|
239
|
+
end
|
240
|
+
|
241
|
+
def save_recent_task( task_id )
|
242
|
+
# save list of recently accessed tasks
|
243
|
+
unless (@local_config[:recent_tasks])
|
244
|
+
@local_config[:recent_tasks] = Array.new();
|
245
|
+
end
|
246
|
+
@local_config[:recent_tasks].unshift( task_id )
|
247
|
+
@local_config[:recent_tasks] = @local_config[:recent_tasks].uniq()
|
248
|
+
if @local_config[:recent_tasks].length > 10
|
249
|
+
@local_config[:recent_tasks].pop()
|
250
|
+
end
|
251
|
+
save_config( @local_config, get_local_config_path() )
|
252
|
+
end
|
253
|
+
|
254
|
+
def select_story_from_paginated_table(&block)
|
255
|
+
prompt = "Please select a story"
|
256
|
+
page = 0
|
257
|
+
begin
|
258
|
+
stories = block.call(page)
|
259
|
+
table = TasksTable.new(stories)
|
260
|
+
story = select(prompt, table)
|
261
|
+
if story == 'n'
|
262
|
+
page+=1
|
263
|
+
elsif story == 'p'
|
264
|
+
page-=1
|
265
|
+
end
|
266
|
+
end while story.kind_of?(String)
|
267
|
+
story
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
data/lib/pt/version.rb
CHANGED
data/pt.gemspec
CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.summary = "Pivotal Tracker CLI (API v5)"
|
14
14
|
spec.description = "Pivotal Tracker Command Line Interface"
|
15
15
|
spec.executables = ["pt"]
|
16
|
-
|
16
|
+
|
17
17
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
18
|
f.match(%r{^(test|spec|features)/})
|
19
19
|
end
|
@@ -23,10 +23,15 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_development_dependency "bundler", "~> 1.13"
|
24
24
|
spec.add_development_dependency "rake", "~> 10.0"
|
25
25
|
spec.add_development_dependency "pry"
|
26
|
+
spec.add_development_dependency 'rspec'
|
27
|
+
spec.add_development_dependency 'aruba'
|
28
|
+
spec.add_development_dependency 'vcr'
|
29
|
+
spec.add_development_dependency 'fakeweb'
|
26
30
|
|
27
31
|
spec.add_dependency 'hirb', '~> 0.7', '>= 0.7.3'
|
28
32
|
spec.add_dependency 'hirb-unicode', '~> 0.0.5', '>= 0.0.5'
|
29
33
|
spec.add_dependency 'colored', '~> 1.2'
|
30
34
|
spec.add_dependency 'highline'
|
31
35
|
spec.add_dependency 'tracker_api', '~> 1.6.0'
|
36
|
+
spec.add_dependency 'thor'
|
32
37
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Slamet Kristanto
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2017-02-
|
14
|
+
date: 2017-02-08 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -55,6 +55,62 @@ dependencies:
|
|
55
55
|
- - ">="
|
56
56
|
- !ruby/object:Gem::Version
|
57
57
|
version: '0'
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rspec
|
60
|
+
requirement: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
type: :development
|
66
|
+
prerelease: false
|
67
|
+
version_requirements: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
- !ruby/object:Gem::Dependency
|
73
|
+
name: aruba
|
74
|
+
requirement: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
type: :development
|
80
|
+
prerelease: false
|
81
|
+
version_requirements: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
- !ruby/object:Gem::Dependency
|
87
|
+
name: vcr
|
88
|
+
requirement: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
type: :development
|
94
|
+
prerelease: false
|
95
|
+
version_requirements: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
- !ruby/object:Gem::Dependency
|
101
|
+
name: fakeweb
|
102
|
+
requirement: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
type: :development
|
108
|
+
prerelease: false
|
109
|
+
version_requirements: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
58
114
|
- !ruby/object:Gem::Dependency
|
59
115
|
name: hirb
|
60
116
|
requirement: !ruby/object:Gem::Requirement
|
@@ -137,6 +193,20 @@ dependencies:
|
|
137
193
|
- - "~>"
|
138
194
|
- !ruby/object:Gem::Version
|
139
195
|
version: 1.6.0
|
196
|
+
- !ruby/object:Gem::Dependency
|
197
|
+
name: thor
|
198
|
+
requirement: !ruby/object:Gem::Requirement
|
199
|
+
requirements:
|
200
|
+
- - ">="
|
201
|
+
- !ruby/object:Gem::Version
|
202
|
+
version: '0'
|
203
|
+
type: :runtime
|
204
|
+
prerelease: false
|
205
|
+
version_requirements: !ruby/object:Gem::Requirement
|
206
|
+
requirements:
|
207
|
+
- - ">="
|
208
|
+
- !ruby/object:Gem::Version
|
209
|
+
version: '0'
|
140
210
|
description: Pivotal Tracker Command Line Interface
|
141
211
|
email:
|
142
212
|
- cakmet14@gmail.com
|
@@ -160,12 +230,14 @@ files:
|
|
160
230
|
- bin/pt
|
161
231
|
- bin/setup
|
162
232
|
- lib/pt.rb
|
233
|
+
- lib/pt/action.rb
|
234
|
+
- lib/pt/cli.rb
|
163
235
|
- lib/pt/client.rb
|
164
236
|
- lib/pt/data_row.rb
|
165
237
|
- lib/pt/data_table.rb
|
166
238
|
- lib/pt/debugger.rb
|
239
|
+
- lib/pt/helper.rb
|
167
240
|
- lib/pt/switch_ssl.rb
|
168
|
-
- lib/pt/ui.rb
|
169
241
|
- lib/pt/version.rb
|
170
242
|
- pt.gemspec
|
171
243
|
homepage: http://www.github.com/raul/pt
|