rallycat 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/TODO +9 -0
- data/lib/rallycat/cat.rb +0 -1
- data/lib/rallycat/cli.rb +29 -18
- data/lib/rallycat/update.rb +6 -0
- data/lib/rallycat/version.rb +1 -1
- data/spec/integration_spec.rb +8 -8
- data/spec/lib/rallycat/cat_spec.rb +0 -3
- data/spec/lib/rallycat/cli_spec.rb +44 -1
- data/spec/lib/rallycat/update_spec.rb +18 -0
- data/spec/support/generic_responder.rb +15 -0
- data/spec/support/rally_defect_responder.rb +1 -11
- data/spec/support/rally_no_results_responder.rb +2 -11
- data/spec/support/rally_story_responder.rb +1 -11
- data/spec/support/rally_task_update_responder.rb +1 -11
- metadata +28 -11
data/Gemfile.lock
CHANGED
data/TODO
CHANGED
@@ -1,10 +1,19 @@
|
|
1
1
|
# Rallycat TODO
|
2
2
|
|
3
3
|
* update help (use option_parser help or custom help)
|
4
|
+
* todo time
|
5
|
+
* set todo time
|
6
|
+
* set notes on a task (-n overwrite, -N to append)
|
4
7
|
* add update behavior for stories (maybe)
|
5
8
|
* add update behavior for defects (maybe)
|
6
9
|
* Slow as balls? Make nice wait messages
|
7
10
|
* Add man page
|
11
|
+
* Ordering of arguments matters? (rallycat update TA1234 -b silently fails)
|
12
|
+
* Create .rallycatrc file on first run?
|
13
|
+
* Listing stories
|
14
|
+
* Per iteration
|
15
|
+
* Per project (project configured in rc or passed in?)
|
16
|
+
* AC-only story view
|
8
17
|
|
9
18
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
10
19
|
|
data/lib/rallycat/cat.rb
CHANGED
data/lib/rallycat/cli.rb
CHANGED
@@ -2,21 +2,26 @@ require 'optparse'
|
|
2
2
|
|
3
3
|
module Rallycat
|
4
4
|
class CLI
|
5
|
+
attr_reader :options
|
6
|
+
|
5
7
|
def initialize(argv, stdout=STDOUT)
|
6
8
|
@argv = argv
|
7
9
|
@stdout = stdout
|
10
|
+
|
11
|
+
parse_global_options!
|
12
|
+
parse_command_options!
|
8
13
|
end
|
9
14
|
|
10
|
-
def
|
11
|
-
options
|
15
|
+
def parse_global_options!
|
16
|
+
@options ||= {}
|
12
17
|
|
13
18
|
global = OptionParser.new do |opts|
|
14
|
-
opts.on('-u USERNAME', '--username') do |
|
15
|
-
options[:
|
19
|
+
opts.on('-u USERNAME', '--username') do |username|
|
20
|
+
@options[:username] = username
|
16
21
|
end
|
17
22
|
|
18
23
|
opts.on('-p PASSWORD', '--password') do |password|
|
19
|
-
options[:password] = password
|
24
|
+
@options[:password] = password
|
20
25
|
end
|
21
26
|
|
22
27
|
opts.on('-h', '--help') do
|
@@ -25,6 +30,12 @@ module Rallycat
|
|
25
30
|
end
|
26
31
|
end
|
27
32
|
|
33
|
+
global.order! @argv
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_command_options!
|
37
|
+
@options ||= {}
|
38
|
+
|
28
39
|
commands = {
|
29
40
|
'cat' => OptionParser.new,
|
30
41
|
|
@@ -32,37 +43,37 @@ module Rallycat
|
|
32
43
|
opts.banner = 'Usage: rallycat update <story number> [options]'
|
33
44
|
|
34
45
|
opts.on('-b', '--blocked') do |blocked|
|
35
|
-
options[:blocked] = true
|
46
|
+
@options[:blocked] = true
|
36
47
|
end
|
37
48
|
|
38
49
|
opts.on('-p', '--in-progress') do |in_progress|
|
39
|
-
options[:in_progress] = true
|
50
|
+
@options[:in_progress] = true
|
40
51
|
end
|
41
52
|
|
42
53
|
opts.on('-c', '--completed') do |completed|
|
43
|
-
options[:completed] = true
|
54
|
+
@options[:completed] = true
|
44
55
|
end
|
45
56
|
|
46
57
|
opts.on('-d', '--defined') do |defined|
|
47
|
-
options[:defined] = true
|
58
|
+
@options[:defined] = true
|
48
59
|
end
|
49
60
|
|
50
61
|
opts.on('-o OWNER', '--owner') do |owner|
|
51
|
-
options[:owner] = owner
|
62
|
+
@options[:owner] = owner
|
52
63
|
end
|
53
64
|
end,
|
54
65
|
|
55
66
|
'help' => OptionParser.new
|
56
67
|
}
|
57
68
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
commands[command].order! @argv if commands.has_key? command
|
69
|
+
@command = @argv.shift
|
70
|
+
commands[@command].parse! @argv if commands.has_key? @command
|
71
|
+
end
|
62
72
|
|
63
|
-
|
73
|
+
def run
|
74
|
+
case @command
|
64
75
|
when 'cat'
|
65
|
-
api = Rallycat::Connection.new(options[:
|
76
|
+
api = Rallycat::Connection.new(options[:username], options[:password]).api
|
66
77
|
|
67
78
|
story_number = @argv.shift
|
68
79
|
|
@@ -74,7 +85,7 @@ module Rallycat
|
|
74
85
|
abort e.message
|
75
86
|
end
|
76
87
|
when 'update'
|
77
|
-
api = Rallycat::Connection.new(options[:
|
88
|
+
api = Rallycat::Connection.new(options[:username], options[:password]).api
|
78
89
|
|
79
90
|
task_number = @argv.shift
|
80
91
|
|
@@ -96,7 +107,7 @@ module Rallycat
|
|
96
107
|
# `puts` calls `to_s`
|
97
108
|
@stdout.puts Rallycat::Help.new
|
98
109
|
else
|
99
|
-
@stdout.puts "'#{command}' is not a supported command. See 'rallycat help'."
|
110
|
+
@stdout.puts "'#{@command}' is not a supported command. See 'rallycat help'."
|
100
111
|
end
|
101
112
|
end
|
102
113
|
end
|
data/lib/rallycat/update.rb
CHANGED
@@ -29,6 +29,12 @@ module Rallycat
|
|
29
29
|
attributes[:owner] = login_name
|
30
30
|
end
|
31
31
|
|
32
|
+
# If the task is marked as 'Complete', we should remove the remaining
|
33
|
+
# hours.
|
34
|
+
if attributes[:state] == "Completed"
|
35
|
+
attributes[:to_do] = 0.0
|
36
|
+
end
|
37
|
+
|
32
38
|
task.update(attributes)
|
33
39
|
|
34
40
|
messages = []
|
data/lib/rallycat/version.rb
CHANGED
data/spec/integration_spec.rb
CHANGED
@@ -7,7 +7,7 @@ describe 'Rallycat' do
|
|
7
7
|
it 'fetches, parses and outputs the rally story requested by the user' do
|
8
8
|
sout = StringIO.new
|
9
9
|
|
10
|
-
cli = Rallycat::CLI.new %w{
|
10
|
+
cli = Rallycat::CLI.new %w{ -u foo.bar@rallycat.com -p password cat US4567 }, sout
|
11
11
|
|
12
12
|
story_responder = RallyStoryResponder.new
|
13
13
|
|
@@ -68,7 +68,7 @@ describe 'Rallycat' do
|
|
68
68
|
it 'sets the state to in-progress' do
|
69
69
|
sout = StringIO.new
|
70
70
|
|
71
|
-
cli = Rallycat::CLI.new %w{
|
71
|
+
cli = Rallycat::CLI.new %w{ -u foo.bar@rallycat.com -p password update -p TA6666 }, sout
|
72
72
|
|
73
73
|
task_responder = RallyTaskUpdateResponder.new
|
74
74
|
|
@@ -83,7 +83,7 @@ describe 'Rallycat' do
|
|
83
83
|
it 'sets the state to defined' do
|
84
84
|
sout = StringIO.new
|
85
85
|
|
86
|
-
cli = Rallycat::CLI.new %w{
|
86
|
+
cli = Rallycat::CLI.new %w{ -u foo.bar@rallycat.com -p password update -d TA6666 }, sout
|
87
87
|
|
88
88
|
task_responder = RallyTaskUpdateResponder.new
|
89
89
|
|
@@ -98,7 +98,7 @@ describe 'Rallycat' do
|
|
98
98
|
it 'sets the state to completed' do
|
99
99
|
sout = StringIO.new
|
100
100
|
|
101
|
-
cli = Rallycat::CLI.new %w{
|
101
|
+
cli = Rallycat::CLI.new %w{ -u foo.bar@rallycat.com -p password update -c TA6666 }, sout
|
102
102
|
|
103
103
|
task_responder = RallyTaskUpdateResponder.new
|
104
104
|
|
@@ -113,7 +113,7 @@ describe 'Rallycat' do
|
|
113
113
|
it 'blocks the task' do
|
114
114
|
sout = StringIO.new
|
115
115
|
|
116
|
-
cli = Rallycat::CLI.new %w{
|
116
|
+
cli = Rallycat::CLI.new %w{ -u foo.bar@rallycat.com -p password update -b TA6666 }, sout
|
117
117
|
|
118
118
|
task_responder = RallyTaskUpdateResponder.new
|
119
119
|
|
@@ -128,7 +128,7 @@ describe 'Rallycat' do
|
|
128
128
|
it 'assigns the owner of the task' do
|
129
129
|
sout = StringIO.new
|
130
130
|
|
131
|
-
cli = Rallycat::CLI.new %w{
|
131
|
+
cli = Rallycat::CLI.new %w{ -u foo.bar@rallycat.com -p password update -o Freddy\ Fender TA6666 }, sout
|
132
132
|
|
133
133
|
task_responder = RallyTaskUpdateResponder.new
|
134
134
|
|
@@ -143,7 +143,7 @@ describe 'Rallycat' do
|
|
143
143
|
it 'aborts when the owner does not exist' do
|
144
144
|
sout = StringIO.new
|
145
145
|
|
146
|
-
cli = Rallycat::CLI.new %w{
|
146
|
+
cli = Rallycat::CLI.new %w{ -u foo.bar@rallycat.com -p password update -o Norman\ Notreal TA6666 }, sout
|
147
147
|
|
148
148
|
task_responder = RallyTaskUpdateResponder.new
|
149
149
|
|
@@ -171,7 +171,7 @@ describe 'Rallycat' do
|
|
171
171
|
it 'aborts when a task does not exist' do
|
172
172
|
sout = StringIO.new
|
173
173
|
|
174
|
-
cli = Rallycat::CLI.new %w{
|
174
|
+
cli = Rallycat::CLI.new %w{ -u foo.bar@rallycat.com -p password update -i TA9999 }, sout
|
175
175
|
|
176
176
|
task_responder = RallyNoResultsResponder.new
|
177
177
|
|
@@ -22,7 +22,6 @@ describe Rallycat::Cat, '#story' do
|
|
22
22
|
|
23
23
|
Plan Estimate: 1.0
|
24
24
|
State: In-Progress
|
25
|
-
Task Actual: 0.0
|
26
25
|
Task Estimate: 6.5
|
27
26
|
Task Remaining: 0.5
|
28
27
|
Owner: scootin@fruity.com
|
@@ -60,7 +59,6 @@ STORY
|
|
60
59
|
|
61
60
|
Plan Estimate: 1.0
|
62
61
|
State: In-Progress
|
63
|
-
Task Actual: 0.0
|
64
62
|
Task Estimate: 6.5
|
65
63
|
Task Remaining: 0.5
|
66
64
|
Owner: scootin@fruity.com
|
@@ -108,7 +106,6 @@ XML
|
|
108
106
|
|
109
107
|
Plan Estimate:
|
110
108
|
State:
|
111
|
-
Task Actual:
|
112
109
|
Task Estimate:
|
113
110
|
Task Remaining:
|
114
111
|
Owner:
|
@@ -9,7 +9,6 @@ describe Rallycat::CLI do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
describe Rallycat::CLI, '#run' do
|
12
|
-
|
13
12
|
it 'should execute command' do
|
14
13
|
sout = StringIO.new
|
15
14
|
cli = Rallycat::CLI.new ['foo'], sout
|
@@ -20,3 +19,47 @@ describe Rallycat::CLI, '#run' do
|
|
20
19
|
sout.read.should == "'foo' is not a supported command. See 'rallycat help'.\n"
|
21
20
|
end
|
22
21
|
end
|
22
|
+
|
23
|
+
describe Rallycat::CLI, '#options' do
|
24
|
+
|
25
|
+
it 'parses global options' do
|
26
|
+
sout = StringIO.new
|
27
|
+
cli = Rallycat::CLI.new %w{ -u foo.bar@rallycat.com -p password help }, sout
|
28
|
+
|
29
|
+
cli.options.should == {
|
30
|
+
username: 'foo.bar@rallycat.com',
|
31
|
+
password: 'password'
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'raises if global options do not appear before the command' do
|
36
|
+
sout = StringIO.new
|
37
|
+
|
38
|
+
lambda {
|
39
|
+
cli = Rallycat::CLI.new %w{ help -u foo.bar@rallycat.com -p password }, sout
|
40
|
+
}.should raise_error(OptionParser::InvalidOption, 'invalid option: -u')
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'parses all options' do
|
44
|
+
sout = StringIO.new
|
45
|
+
cli = Rallycat::CLI.new %w{ -u foo.bar@rallycat.com -p password update -p TA6666 -b }, sout
|
46
|
+
|
47
|
+
cli.options.should == {
|
48
|
+
username: 'foo.bar@rallycat.com',
|
49
|
+
password: 'password',
|
50
|
+
in_progress: true,
|
51
|
+
blocked: true
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'parses command options (no global options)' do
|
56
|
+
sout = StringIO.new
|
57
|
+
cli = Rallycat::CLI.new %w{ update TA6666 -pb }, sout
|
58
|
+
|
59
|
+
cli.options.should == {
|
60
|
+
in_progress: true,
|
61
|
+
blocked: true
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
@@ -53,6 +53,24 @@ describe Rallycat::Update do
|
|
53
53
|
body.should include('<State>In-Progress</State>')
|
54
54
|
end
|
55
55
|
|
56
|
+
it 'sets the todo hours to zero when completing the task' do
|
57
|
+
responder = RallyTaskUpdateResponder.new
|
58
|
+
|
59
|
+
Artifice.activate_with responder do
|
60
|
+
task_num = "TA6666"
|
61
|
+
update = Rallycat::Update.new(@api)
|
62
|
+
message = update.task(task_num, state: "Completed")
|
63
|
+
end
|
64
|
+
|
65
|
+
post_request = responder.requests[2] # this is the request that actually updates the task
|
66
|
+
post_request.should be_post
|
67
|
+
post_request.url.should == 'https://rally1.rallydev.com/slm/webservice/1.17/task/12345'
|
68
|
+
|
69
|
+
body = post_request.body.tap(&:rewind).read
|
70
|
+
body.should include('<State>Completed</State>')
|
71
|
+
body.should include('<ToDo>0.0</ToDo>')
|
72
|
+
end
|
73
|
+
|
56
74
|
|
57
75
|
it 'blocks the task' do
|
58
76
|
responder = RallyTaskUpdateResponder.new
|
@@ -1,14 +1,4 @@
|
|
1
|
-
class RallyDefectResponder
|
2
|
-
|
3
|
-
attr_reader :requests
|
4
|
-
|
5
|
-
def initialize
|
6
|
-
@requests = []
|
7
|
-
end
|
8
|
-
|
9
|
-
def last_request
|
10
|
-
@requests.last
|
11
|
-
end
|
1
|
+
class RallyDefectResponder < GenericResponder
|
12
2
|
|
13
3
|
def call(env)
|
14
4
|
@requests << request = Rack::Request.new(env)
|
@@ -1,13 +1,4 @@
|
|
1
|
-
class RallyNoResultsResponder
|
2
|
-
attr_reader :requests
|
3
|
-
|
4
|
-
def initialize
|
5
|
-
@requests = []
|
6
|
-
end
|
7
|
-
|
8
|
-
def last_request
|
9
|
-
@requests.last
|
10
|
-
end
|
1
|
+
class RallyNoResultsResponder < GenericResponder
|
11
2
|
|
12
3
|
def call(env)
|
13
4
|
@requests << request = Rack::Request.new(env)
|
@@ -25,4 +16,4 @@ class RallyNoResultsResponder
|
|
25
16
|
XML
|
26
17
|
]]
|
27
18
|
end
|
28
|
-
end
|
19
|
+
end
|
@@ -1,16 +1,6 @@
|
|
1
1
|
require 'cgi'
|
2
2
|
|
3
|
-
class RallyStoryResponder
|
4
|
-
|
5
|
-
attr_reader :requests
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
@requests = []
|
9
|
-
end
|
10
|
-
|
11
|
-
def last_request
|
12
|
-
@requests.last
|
13
|
-
end
|
3
|
+
class RallyStoryResponder < GenericResponder
|
14
4
|
|
15
5
|
def call(env)
|
16
6
|
@requests << request = Rack::Request.new(env)
|
@@ -1,14 +1,4 @@
|
|
1
|
-
class RallyTaskUpdateResponder
|
2
|
-
|
3
|
-
attr_reader :requests
|
4
|
-
|
5
|
-
def initialize
|
6
|
-
@requests = []
|
7
|
-
end
|
8
|
-
|
9
|
-
def last_request
|
10
|
-
@requests.last
|
11
|
-
end
|
1
|
+
class RallyTaskUpdateResponder < GenericResponder
|
12
2
|
|
13
3
|
def call(env)
|
14
4
|
@requests << request = Rack::Request.new(env)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rallycat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-07-
|
13
|
+
date: 2012-07-19 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: builder
|
17
|
-
requirement:
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,15 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements:
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
26
31
|
- !ruby/object:Gem::Dependency
|
27
32
|
name: rally_rest_api
|
28
|
-
requirement:
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
29
34
|
none: false
|
30
35
|
requirements:
|
31
36
|
- - ! '>='
|
@@ -33,10 +38,15 @@ dependencies:
|
|
33
38
|
version: '0'
|
34
39
|
type: :runtime
|
35
40
|
prerelease: false
|
36
|
-
version_requirements:
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
37
47
|
- !ruby/object:Gem::Dependency
|
38
48
|
name: nokogiri
|
39
|
-
requirement:
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
40
50
|
none: false
|
41
51
|
requirements:
|
42
52
|
- - ! '>='
|
@@ -44,7 +54,12 @@ dependencies:
|
|
44
54
|
version: '0'
|
45
55
|
type: :runtime
|
46
56
|
prerelease: false
|
47
|
-
version_requirements:
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
48
63
|
description: The Rally website sucks. CLI is better.
|
49
64
|
email:
|
50
65
|
- adam@adamtanner.org
|
@@ -79,6 +94,7 @@ files:
|
|
79
94
|
- spec/lib/rallycat/html_to_text_converter_spec.rb
|
80
95
|
- spec/lib/rallycat/update_spec.rb
|
81
96
|
- spec/spec_helper.rb
|
97
|
+
- spec/support/generic_responder.rb
|
82
98
|
- spec/support/rally_defect_responder.rb
|
83
99
|
- spec/support/rally_no_results_responder.rb
|
84
100
|
- spec/support/rally_story_responder.rb
|
@@ -97,7 +113,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
97
113
|
version: '0'
|
98
114
|
segments:
|
99
115
|
- 0
|
100
|
-
hash:
|
116
|
+
hash: 1844620157454279745
|
101
117
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
118
|
none: false
|
103
119
|
requirements:
|
@@ -106,10 +122,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
106
122
|
version: '0'
|
107
123
|
segments:
|
108
124
|
- 0
|
109
|
-
hash:
|
125
|
+
hash: 1844620157454279745
|
110
126
|
requirements: []
|
111
127
|
rubyforge_project:
|
112
|
-
rubygems_version: 1.8.
|
128
|
+
rubygems_version: 1.8.23
|
113
129
|
signing_key:
|
114
130
|
specification_version: 3
|
115
131
|
summary: The Rally website sucks. CLI is better.
|
@@ -121,6 +137,7 @@ test_files:
|
|
121
137
|
- spec/lib/rallycat/html_to_text_converter_spec.rb
|
122
138
|
- spec/lib/rallycat/update_spec.rb
|
123
139
|
- spec/spec_helper.rb
|
140
|
+
- spec/support/generic_responder.rb
|
124
141
|
- spec/support/rally_defect_responder.rb
|
125
142
|
- spec/support/rally_no_results_responder.rb
|
126
143
|
- spec/support/rally_story_responder.rb
|