pt 0.8.6 → 0.9.0
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.
- 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
|