tpope-pickler 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +12 -11
- data/lib/pickler/feature.rb +1 -22
- data/lib/pickler/runner.rb +333 -68
- data/lib/pickler/tracker/iteration.rb +4 -0
- data/lib/pickler/tracker/note.rb +1 -1
- data/lib/pickler/tracker/story.rb +9 -3
- data/lib/pickler/tracker.rb +8 -4
- data/lib/pickler.rb +5 -5
- data/pickler.gemspec +1 -1
- metadata +1 -1
data/README.rdoc
CHANGED
@@ -7,6 +7,7 @@ Synchronize user stories in Pivotal Tracker with Cucumber features.
|
|
7
7
|
gem install tpope-pickler --source=http://gems.github.com
|
8
8
|
echo "api_token: ..." > ~/.tracker.yml
|
9
9
|
echo "project_id: ..." > ~/my/app/features/tracker.yml
|
10
|
+
pickler --help
|
10
11
|
|
11
12
|
For details about the Pivotal Tracker API, including where to find your API
|
12
13
|
token and project id, see http://www.pivotaltracker.com/help/api .
|
@@ -19,9 +20,7 @@ feature's body. Keep this in mind when entering stories into Pivotal Tracker.
|
|
19
20
|
|
20
21
|
pickler pull
|
21
22
|
|
22
|
-
Download all well formed stories to the features/ directory.
|
23
|
-
unseen stories will be given a numeric filename that you are encouraged to
|
24
|
-
change.
|
23
|
+
Download all well formed stories to the features/ directory.
|
25
24
|
|
26
25
|
pickler push
|
27
26
|
|
@@ -31,19 +30,21 @@ Upload all features with a tracker url in a comment on the first line.
|
|
31
30
|
|
32
31
|
List all stories matching the given query.
|
33
32
|
|
34
|
-
pickler
|
33
|
+
pickler start <story>
|
35
34
|
|
36
|
-
|
35
|
+
Pull a given feature and change its state to started.
|
37
36
|
|
38
|
-
pickler
|
37
|
+
pickler finish <story>
|
39
38
|
|
40
|
-
|
41
|
-
and no local file exists, features/basename.feature will be created in lieu
|
42
|
-
of features/id.feature.
|
39
|
+
Push a given feature and change its state to finished.
|
43
40
|
|
44
|
-
pickler
|
41
|
+
pickler --help
|
45
42
|
|
46
|
-
|
43
|
+
Full list of commands.
|
44
|
+
|
45
|
+
pickler <command> --help
|
46
|
+
|
47
|
+
Further help for a given command.
|
47
48
|
|
48
49
|
== Disclaimer
|
49
50
|
|
data/lib/pickler/feature.rb
CHANGED
@@ -47,10 +47,8 @@ class Pickler
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def pull(default = nil)
|
50
|
-
body = "# http://www.pivotaltracker.com/story/show/#{id}\n" <<
|
51
|
-
normalize_feature(story.to_s)
|
52
50
|
filename = filename() || pickler.features_path("#{default||id}.feature")
|
53
|
-
File.open(filename,'w') {|f| f.puts
|
51
|
+
File.open(filename,'w') {|f| f.puts story}
|
54
52
|
@filename = filename
|
55
53
|
end
|
56
54
|
|
@@ -84,24 +82,5 @@ class Pickler
|
|
84
82
|
@story ||= @pickler.project.story(id) if id
|
85
83
|
end
|
86
84
|
|
87
|
-
protected
|
88
|
-
|
89
|
-
def normalize_feature(body)
|
90
|
-
return body unless ast = pickler.parser.parse(body)
|
91
|
-
feature = ast.compile
|
92
|
-
new = ''
|
93
|
-
(feature.header.chomp << "\n").each_line do |l|
|
94
|
-
new << ' ' unless new.empty?
|
95
|
-
new << l.strip << "\n"
|
96
|
-
end
|
97
|
-
feature.scenarios.each do |scenario|
|
98
|
-
new << "\n Scenario: #{scenario.name}\n"
|
99
|
-
scenario.steps.each do |step|
|
100
|
-
new << " #{step.keyword} #{step.name}\n"
|
101
|
-
end
|
102
|
-
end
|
103
|
-
new
|
104
|
-
end
|
105
|
-
|
106
85
|
end
|
107
86
|
end
|
data/lib/pickler/runner.rb
CHANGED
@@ -1,15 +1,331 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
1
3
|
class Pickler
|
2
4
|
class Runner
|
3
5
|
|
4
|
-
|
6
|
+
class Base
|
7
|
+
attr_reader :argv
|
8
|
+
|
9
|
+
def initialize(argv)
|
10
|
+
@argv = argv
|
11
|
+
@tty = $stdout.tty?
|
12
|
+
@opts = OptionParser.new
|
13
|
+
@opts.version = "0.0"
|
14
|
+
@opts.banner = "Usage: pickler #{self.class.command_name} #{self.class.banner_arguments}"
|
15
|
+
@opts.base.long["help"] = OptionParser::Switch::NoArgument.new do
|
16
|
+
help = @opts.help.chomp.chomp + "\n"
|
17
|
+
help += "\n#{self.class.description}" if self.class.description
|
18
|
+
puts help
|
19
|
+
@exit = 0
|
20
|
+
end
|
21
|
+
@opts.separator("")
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.options
|
25
|
+
@options ||= []
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.on(*args, &block)
|
29
|
+
options << args
|
30
|
+
define_method("option_#{args.object_id}", &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.banner_arguments(value = nil)
|
34
|
+
if value
|
35
|
+
@banner_arguments = value
|
36
|
+
else
|
37
|
+
@banner_arguments || (arity.zero? ? "" : "...")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.summary(value = nil)
|
42
|
+
if value
|
43
|
+
@summary = value
|
44
|
+
else
|
45
|
+
@summary
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.description(value = nil)
|
50
|
+
if value
|
51
|
+
@description = value
|
52
|
+
else
|
53
|
+
@description || "#@summary."
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.command_name
|
58
|
+
name.split('::').last.gsub(/(.)([A-Z])/) {"#$1-#$2"}.downcase
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.method_name
|
62
|
+
command_name.gsub('-','_')
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.process(&block)
|
66
|
+
define_method(:process, &block)
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.arity
|
70
|
+
instance_method(:process).arity
|
71
|
+
end
|
72
|
+
|
73
|
+
def arity
|
74
|
+
self.class.arity
|
75
|
+
end
|
76
|
+
|
77
|
+
def pickler
|
78
|
+
@pickler ||= Pickler.new(Dir.getwd)
|
79
|
+
end
|
80
|
+
|
81
|
+
def abort(message)
|
82
|
+
raise Error, message
|
83
|
+
end
|
84
|
+
|
85
|
+
def too_many
|
86
|
+
abort "too many arguments"
|
87
|
+
end
|
88
|
+
|
89
|
+
def run
|
90
|
+
self.class.options.each do |arguments|
|
91
|
+
@opts.on(*arguments, &method("option_#{arguments.object_id}"))
|
92
|
+
end
|
93
|
+
begin
|
94
|
+
@opts.parse!(@argv)
|
95
|
+
rescue OptionParser::InvalidOption
|
96
|
+
abort $!.message
|
97
|
+
end
|
98
|
+
return @exit if @exit
|
99
|
+
minimum = arity < 0 ? -1 - arity : arity
|
100
|
+
if arity >= 0 && arity < @argv.size
|
101
|
+
too_many
|
102
|
+
elsif minimum > @argv.size
|
103
|
+
abort "not enough arguments"
|
104
|
+
end
|
105
|
+
process(*@argv)
|
106
|
+
end
|
107
|
+
|
108
|
+
def process(*argv)
|
109
|
+
pickler.send(self.class.method_name,*argv)
|
110
|
+
end
|
111
|
+
|
112
|
+
def color?
|
113
|
+
case pickler.config["color"]
|
114
|
+
when "always" then true
|
115
|
+
when "never" then false
|
116
|
+
else
|
117
|
+
@tty && RUBY_PLATFORM !~ /mswin|mingw/
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def puts_summary(story)
|
122
|
+
summary = "%6d " % story.id
|
123
|
+
type = story.estimate || TYPE_SYMBOLS[story.story_type]
|
124
|
+
state = STATE_SYMBOLS[story.current_state]
|
125
|
+
if color?
|
126
|
+
summary << "\e[3#{STATE_COLORS[story.current_state]}m#{state}\e[00m "
|
127
|
+
summary << "\e[01;3#{TYPE_COLORS[story.story_type]}m#{type}\e[00m "
|
128
|
+
else
|
129
|
+
summary << "#{state} #{type} "
|
130
|
+
end
|
131
|
+
summary << story.name
|
132
|
+
puts summary
|
133
|
+
end
|
134
|
+
|
135
|
+
def paginated_output
|
136
|
+
stdout = $stdout
|
137
|
+
if @tty && pager = pickler.config["pager"]
|
138
|
+
# Modeled after git
|
139
|
+
ENV["LESS"] ||= "FRSX"
|
140
|
+
IO.popen(pager,"w") do |io|
|
141
|
+
$stdout = io
|
142
|
+
yield
|
143
|
+
end
|
144
|
+
else
|
145
|
+
yield
|
146
|
+
end
|
147
|
+
ensure
|
148
|
+
$stdout = stdout
|
149
|
+
end
|
5
150
|
|
6
|
-
|
7
|
-
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.[](command)
|
154
|
+
klass_name = command.to_s.capitalize.gsub(/[-_](.)/) { $1.upcase }
|
155
|
+
if klass_name =~ /^[A-Z]\w*$/ && const_defined?(klass_name)
|
156
|
+
klass = const_get(klass_name)
|
157
|
+
if Class === klass && klass < Base
|
158
|
+
return klass
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def self.commands
|
164
|
+
constants.map {|c| Runner.const_get(c)}.select {|c| Class === c && c < Runner::Base}.sort_by {|r| r.command_name}.uniq
|
165
|
+
end
|
166
|
+
|
167
|
+
def self.command(name, &block)
|
168
|
+
const_set(name.to_s.capitalize.gsub(/[-_](.)/) { $1.upcase },Class.new(Base,&block))
|
169
|
+
end
|
170
|
+
|
171
|
+
command :show do
|
172
|
+
banner_arguments "<story>"
|
173
|
+
summary "Show details for a story"
|
174
|
+
|
175
|
+
process do |*args|
|
176
|
+
case args.size
|
177
|
+
when 0
|
178
|
+
puts "#{pickler.project_id} #{pickler.project.name}"
|
179
|
+
when 1
|
180
|
+
story = pickler.project.story(args.first)
|
181
|
+
paginated_output do
|
182
|
+
puts story
|
183
|
+
end
|
184
|
+
else
|
185
|
+
too_many
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
command :search do
|
191
|
+
banner_arguments "[query]"
|
192
|
+
summary "List all stories matching a query"
|
193
|
+
|
194
|
+
def modifications
|
195
|
+
@modifications ||= {}
|
196
|
+
end
|
197
|
+
[:label, :type, :state].each do |o|
|
198
|
+
on "--#{o} #{o.to_s.upcase}" do |value|
|
199
|
+
modifications[o] = value
|
200
|
+
end
|
201
|
+
end
|
202
|
+
[:requester, :owner, :mywork].each do |o|
|
203
|
+
on "--#{o} USERNAME" do |value|
|
204
|
+
modifications[o] = value
|
205
|
+
end
|
206
|
+
end
|
207
|
+
on "--[no-]includedone", "include accepted stories" do |value|
|
208
|
+
modifications[:includedone] = value
|
209
|
+
end
|
210
|
+
|
211
|
+
attr_writer :current
|
212
|
+
on "-c", "--current", "filter results to current iteration" do |b|
|
213
|
+
self.current = b
|
214
|
+
end
|
215
|
+
|
216
|
+
process do |*argv|
|
217
|
+
argv << modifications unless modifications.empty?
|
218
|
+
if argv == [{:includedone => true}]
|
219
|
+
# Bypass the 200 search results limitation
|
220
|
+
stories = pickler.project.stories
|
221
|
+
else
|
222
|
+
stories = pickler.project.stories(*argv)
|
223
|
+
end
|
224
|
+
stories.reject! {|s| !s.current?} if argv.empty? || @current
|
225
|
+
paginated_output do
|
226
|
+
stories.each do |story|
|
227
|
+
puts_summary story
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
command :push do
|
234
|
+
banner_arguments "[story] ..."
|
235
|
+
summary "Upload stories"
|
236
|
+
description <<-EOF
|
237
|
+
Upload the given story or all features with a tracker url in a comment on the
|
238
|
+
first line.
|
239
|
+
EOF
|
240
|
+
end
|
241
|
+
|
242
|
+
command :pull do
|
243
|
+
banner_arguments "[story] ..."
|
244
|
+
summary "Download stories"
|
245
|
+
description <<-EOF
|
246
|
+
Download the given story or all well formed stories to the features/ directory.
|
247
|
+
Previously unseen stories will be given a numeric filename that you are
|
248
|
+
encouraged to change.
|
249
|
+
EOF
|
250
|
+
end
|
251
|
+
|
252
|
+
command :start do
|
253
|
+
banner_arguments "<story> [basename]"
|
254
|
+
summary "Pull a story and mark it started"
|
255
|
+
description <<-EOF
|
256
|
+
Pull a given story and change its state to started. If basename is given
|
257
|
+
and no local file exists, features/basename.feature will be created in lieu
|
258
|
+
of features/id.feature.
|
259
|
+
EOF
|
260
|
+
|
261
|
+
process do |story_id, *args|
|
262
|
+
pickler.start(story_id, args.first)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
command :finish do
|
267
|
+
banner_arguments "<story>"
|
268
|
+
summary "Push a story and mark it finished"
|
269
|
+
|
270
|
+
process do |story_id|
|
271
|
+
super
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
command :deliver do
|
276
|
+
banner_arguments "[story] ..."
|
277
|
+
summary "Mark stories delivered"
|
278
|
+
on "--all-finished", "deliver all finished stories" do
|
279
|
+
@all = true
|
280
|
+
end
|
281
|
+
process do |*args|
|
282
|
+
if @all
|
283
|
+
pickler.deliver_all_finished_stories
|
284
|
+
end
|
285
|
+
args.each do |arg|
|
286
|
+
pickler.story(arg).transition!('delivered')
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
command :browse do
|
292
|
+
banner_arguments "[story]"
|
293
|
+
summary "Open a story in the web browser"
|
294
|
+
description <<-EOF
|
295
|
+
Open project or a story in the web browser.
|
296
|
+
|
297
|
+
Requires launchy (gem install launchy).
|
298
|
+
EOF
|
299
|
+
|
300
|
+
on "--dashboard" do
|
301
|
+
@special = "dashboard"
|
302
|
+
end
|
303
|
+
on "--faq" do
|
304
|
+
@special = "help"
|
305
|
+
end
|
306
|
+
on "--profile", "get your API Token here" do
|
307
|
+
@special = "profile"
|
308
|
+
end
|
309
|
+
on "--time", "not publicly available" do
|
310
|
+
@special = "time_shifts?project=#{pickler.project_id}"
|
311
|
+
end
|
312
|
+
|
313
|
+
process do |*args|
|
314
|
+
too_many if args.size > 1 || @special && args.first
|
315
|
+
if args.first
|
316
|
+
url = pickler.story(args.first).url
|
317
|
+
elsif @special
|
318
|
+
url = "http://www.pivotaltracker.com/#@special"
|
319
|
+
else
|
320
|
+
url = "http://www.pivotaltracker.com/projects/#{pickler.project_id}/stories"
|
321
|
+
end
|
322
|
+
require 'launchy'
|
323
|
+
Launchy.open(url)
|
324
|
+
end
|
8
325
|
end
|
9
326
|
|
10
327
|
def initialize(argv)
|
11
328
|
@argv = argv
|
12
|
-
@tty = $stdout.tty?
|
13
329
|
end
|
14
330
|
|
15
331
|
COLORS = {
|
@@ -58,73 +374,22 @@ class Pickler
|
|
58
374
|
"bug" => "/"
|
59
375
|
}
|
60
376
|
|
61
|
-
def color?
|
62
|
-
case pickler.config["color"]
|
63
|
-
when "always" then true
|
64
|
-
when "never" then false
|
65
|
-
else
|
66
|
-
@tty && RUBY_PLATFORM !~ /mswin|mingw/
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def puts_summary(story)
|
71
|
-
summary = "%6d " % story.id
|
72
|
-
type = story.estimate || TYPE_SYMBOLS[story.story_type]
|
73
|
-
state = STATE_SYMBOLS[story.current_state]
|
74
|
-
if color?
|
75
|
-
summary << "\e[3#{STATE_COLORS[story.current_state]}m#{state}\e[00m "
|
76
|
-
summary << "\e[01;3#{TYPE_COLORS[story.story_type]}m#{type}\e[00m "
|
77
|
-
else
|
78
|
-
summary << "#{state} #{type} "
|
79
|
-
end
|
80
|
-
summary << story.name
|
81
|
-
puts summary
|
82
|
-
end
|
83
|
-
|
84
|
-
def paginated_output
|
85
|
-
stdout = $stdout
|
86
|
-
if @tty && pager = pickler.config["pager"]
|
87
|
-
# Modeled after git
|
88
|
-
ENV["LESS"] ||= "FRSX"
|
89
|
-
IO.popen(pager,"w") do |io|
|
90
|
-
$stdout = io
|
91
|
-
yield
|
92
|
-
end
|
93
|
-
else
|
94
|
-
yield
|
95
|
-
end
|
96
|
-
ensure
|
97
|
-
$stdout = stdout
|
98
|
-
end
|
99
|
-
|
100
377
|
def run
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
stories.each do |story|
|
112
|
-
puts_summary story
|
113
|
-
end
|
378
|
+
command = @argv.shift
|
379
|
+
if klass = self.class[command]
|
380
|
+
result = klass.new(@argv).run
|
381
|
+
exit result.respond_to?(:to_int) ? result.to_int : 0
|
382
|
+
elsif ['help', '--help', '-h', '', nil].include?(command)
|
383
|
+
puts "usage: pickler <command> [options] [arguments]"
|
384
|
+
puts
|
385
|
+
puts "Commands:"
|
386
|
+
self.class.commands.each do |command|
|
387
|
+
puts " %-19s %s" % [command.command_name, command.summary]
|
114
388
|
end
|
115
|
-
|
116
|
-
pickler
|
117
|
-
when 'pull'
|
118
|
-
pickler.pull(*argv)
|
119
|
-
when 'start'
|
120
|
-
pickler.start(argv.first,argv[1])
|
121
|
-
when 'finish'
|
122
|
-
pickler.finish(argv.first)
|
123
|
-
when 'help', '--help', '-h', '', nil
|
124
|
-
puts 'pickler commands: [show|start|finish] <id>, search <query>, push, pull'
|
389
|
+
puts
|
390
|
+
puts "Run pickler <command> --help for help with a given command"
|
125
391
|
else
|
126
|
-
|
127
|
-
exit 1
|
392
|
+
raise Error, "Unknown pickler command #{command}"
|
128
393
|
end
|
129
394
|
rescue Pickler::Error
|
130
395
|
$stderr.puts "#$!"
|
@@ -18,6 +18,10 @@ class Pickler
|
|
18
18
|
start...finish
|
19
19
|
end
|
20
20
|
|
21
|
+
def include?(date)
|
22
|
+
range.include?(date)
|
23
|
+
end
|
24
|
+
|
21
25
|
def succ
|
22
26
|
self.class.new(project, 'number' => number.succ.to_s, 'start' => @attributes['finish'], 'finish' => (finish + (finish - start)).strftime("%b %d, %Y"))
|
23
27
|
end
|
data/lib/pickler/tracker/note.rb
CHANGED
@@ -28,6 +28,10 @@ class Pickler
|
|
28
28
|
raise Pickler::Tracker::Error, Array(error).join("\n"), caller unless error == true
|
29
29
|
end
|
30
30
|
|
31
|
+
def current?(as_of = Date.today)
|
32
|
+
iteration && iteration.include?(as_of)
|
33
|
+
end
|
34
|
+
|
31
35
|
def complete?
|
32
36
|
%w(finished delivered accepted).include?(current_state)
|
33
37
|
end
|
@@ -84,14 +88,16 @@ class Pickler
|
|
84
88
|
|
85
89
|
def comment!(body)
|
86
90
|
raise ArgumentError if body.strip.empty? || body.size > 5000
|
87
|
-
response = tracker.request_xml(:post, "#{resource_url}/notes",{:text => body}.to_xml(:root => 'note'))
|
91
|
+
response = tracker.request_xml(:post, "#{resource_url}/notes",{:text => body}.to_xml(:dasherize => false, :root => 'note'))
|
88
92
|
Note.new(self, response["note"])
|
89
93
|
end
|
90
94
|
|
91
95
|
def to_xml
|
92
|
-
hash = @attributes.
|
96
|
+
hash = @attributes.reject do |k,v|
|
97
|
+
!%w(current_state deadline description estimate name owned_by requested_by story_type).include?(k)
|
98
|
+
end
|
93
99
|
hash["labels"] = Array(@attributes["labels"]).join(", ")
|
94
|
-
hash.to_xml(:root => "story")
|
100
|
+
hash.to_xml(:dasherize => false, :root => "story")
|
95
101
|
end
|
96
102
|
|
97
103
|
def destroy
|
data/lib/pickler/tracker.rb
CHANGED
@@ -12,7 +12,8 @@ class Pickler
|
|
12
12
|
attr_reader :token
|
13
13
|
|
14
14
|
def initialize(token)
|
15
|
-
require 'active_support'
|
15
|
+
require 'active_support/core_ext/blank'
|
16
|
+
require 'active_support/core_ext/hash'
|
16
17
|
@token = token
|
17
18
|
end
|
18
19
|
|
@@ -52,8 +53,11 @@ class Pickler
|
|
52
53
|
end
|
53
54
|
|
54
55
|
class Abstract
|
55
|
-
def initialize(attributes)
|
56
|
-
@attributes =
|
56
|
+
def initialize(attributes = {})
|
57
|
+
@attributes = {}
|
58
|
+
(attributes || {}).each do |k,v|
|
59
|
+
@attributes[k.to_s] = v
|
60
|
+
end
|
57
61
|
yield self if block_given?
|
58
62
|
end
|
59
63
|
|
@@ -78,7 +82,7 @@ class Pickler
|
|
78
82
|
reader :id
|
79
83
|
|
80
84
|
def to_xml(options = nil)
|
81
|
-
@attributes.to_xml({:root => self.class.name.split('::').last.downcase}.merge(options||{}))
|
85
|
+
@attributes.to_xml({:dasherize => false, :root => self.class.name.split('::').last.downcase}.merge(options||{}))
|
82
86
|
end
|
83
87
|
|
84
88
|
end
|
data/lib/pickler.rb
CHANGED
@@ -5,6 +5,10 @@ class Pickler
|
|
5
5
|
class Error < RuntimeError
|
6
6
|
end
|
7
7
|
|
8
|
+
autoload :Runner, 'pickler/runner'
|
9
|
+
autoload :Feature, 'pickler/feature'
|
10
|
+
autoload :Tracker, 'pickler/tracker'
|
11
|
+
|
8
12
|
def self.config
|
9
13
|
@config ||= {'api_token' => ENV["TRACKER_API_TOKEN"]}.merge(
|
10
14
|
if File.exist?(path = File.expand_path('~/.tracker.yml'))
|
@@ -14,7 +18,6 @@ class Pickler
|
|
14
18
|
end
|
15
19
|
|
16
20
|
def self.run(argv)
|
17
|
-
require 'pickler/runner'
|
18
21
|
Runner.new(argv).run
|
19
22
|
end
|
20
23
|
|
@@ -91,7 +94,7 @@ class Pickler
|
|
91
94
|
def pull(*args)
|
92
95
|
if args.empty?
|
93
96
|
args = project.stories(scenario_word, :includedone => true).reject do |s|
|
94
|
-
s.current_state
|
97
|
+
%(unscheduled unstarted).include?(s.current_state)
|
95
98
|
end.select do |s|
|
96
99
|
s.to_s =~ /^\s*#{Regexp.escape(scenario_word)}:/ && parser.parse(s.to_s)
|
97
100
|
end
|
@@ -120,6 +123,3 @@ class Pickler
|
|
120
123
|
protected
|
121
124
|
|
122
125
|
end
|
123
|
-
|
124
|
-
require 'pickler/feature'
|
125
|
-
require 'pickler/tracker'
|
data/pickler.gemspec
CHANGED