rallycat 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +2 -2
- data/TODO +12 -3
- data/lib/rallycat/cli.rb +39 -2
- data/lib/rallycat/connection.rb +4 -1
- data/lib/rallycat/help.rb +28 -0
- data/lib/rallycat/update.rb +38 -0
- data/lib/rallycat/version.rb +1 -1
- data/lib/rallycat.rb +2 -0
- data/spec/integration_spec.rb +99 -10
- data/spec/lib/rallycat/cat_spec.rb +2 -2
- data/spec/lib/rallycat/cli_spec.rb +1 -1
- data/spec/lib/rallycat/update_spec.rb +95 -0
- data/spec/support/rally_defect_responder.rb +23 -25
- data/spec/support/rally_story_responder.rb +66 -68
- data/spec/support/rally_task_update_responder.rb +88 -0
- metadata +15 -9
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rallycat (0.
|
4
|
+
rallycat (0.2.0)
|
5
5
|
builder
|
6
6
|
nokogiri
|
7
7
|
rally_rest_api
|
@@ -15,7 +15,7 @@ GEM
|
|
15
15
|
coderay (1.0.6)
|
16
16
|
diff-lcs (1.1.3)
|
17
17
|
method_source (0.7.1)
|
18
|
-
nokogiri (1.5.
|
18
|
+
nokogiri (1.5.5)
|
19
19
|
pry (0.9.9.6)
|
20
20
|
coderay (~> 1.0.5)
|
21
21
|
method_source (~> 0.7.1)
|
data/TODO
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
# Rallycat TODO
|
2
2
|
|
3
|
+
* add update behavior for stories
|
4
|
+
* add update behavior for defects
|
5
|
+
* add sub-command support (so we can use -p for in-progress)
|
6
|
+
* give user friendly error messages
|
7
|
+
* when you don't pass in a task
|
8
|
+
* when task does not exist
|
9
|
+
* when owner cannot be found
|
10
|
+
* update help
|
11
|
+
* make "help" default output
|
3
12
|
* Slow as balls? Make nice wait messages
|
4
|
-
* Reconcile USER vs username (cli arg vs config attribute)
|
5
|
-
* Add help
|
6
13
|
* Add man page
|
7
|
-
* Integration specs
|
8
14
|
|
9
15
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
10
16
|
|
@@ -38,6 +44,9 @@ rally.vim -> Making User Stories from Vim
|
|
38
44
|
|
39
45
|
## Rallycat Futures
|
40
46
|
|
47
|
+
* current iteration (or iteration) output (just story numbers and titles)
|
48
|
+
|
49
|
+
|
41
50
|
cat tasks | rallycat boilerplate
|
42
51
|
|
43
52
|
[DESCRIPTION] [ESTIMATE] [TO-DO]
|
data/lib/rallycat/cli.rb
CHANGED
@@ -10,13 +10,33 @@ module Rallycat
|
|
10
10
|
def run
|
11
11
|
options = {}
|
12
12
|
option_parser = OptionParser.new do |opts|
|
13
|
-
opts.on('-u
|
13
|
+
opts.on('-u USERNAME', '--username') do |user|
|
14
14
|
options[:user] = user
|
15
15
|
end
|
16
16
|
|
17
|
-
opts.on('-p PASSWORD') do |password|
|
17
|
+
opts.on('-p PASSWORD', '--password') do |password|
|
18
18
|
options[:password] = password
|
19
19
|
end
|
20
|
+
|
21
|
+
opts.on('-b', '--blocked') do |blocked|
|
22
|
+
options[:blocked] = true
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on('-i', '--in-progress') do |in_progress|
|
26
|
+
options[:in_progress] = true
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on('-c', '--completed') do |completed|
|
30
|
+
options[:completed] = true
|
31
|
+
end
|
32
|
+
|
33
|
+
opts.on('-d', '--defined') do |defined|
|
34
|
+
options[:defined] = true
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on('-o OWNER', '--owner') do |owner|
|
38
|
+
options[:owner] = owner
|
39
|
+
end
|
20
40
|
end
|
21
41
|
|
22
42
|
option_parser.parse! @argv
|
@@ -26,6 +46,23 @@ module Rallycat
|
|
26
46
|
api = Rallycat::Connection.new(options[:user], options[:password]).api
|
27
47
|
|
28
48
|
@stdout.puts Rallycat::Cat.new(api).story(@argv.shift)
|
49
|
+
when 'update'
|
50
|
+
api = Rallycat::Connection.new(options[:user], options[:password]).api
|
51
|
+
|
52
|
+
|
53
|
+
task_number = @argv.shift
|
54
|
+
|
55
|
+
opts = {}
|
56
|
+
opts[:blocked] = true if options[:blocked]
|
57
|
+
opts[:state] = "In-Progress" if options[:in_progress]
|
58
|
+
opts[:state] = "Completed" if options[:completed]
|
59
|
+
opts[:state] = "Defined" if options[:defined]
|
60
|
+
opts[:owner] = options[:owner] if options[:owner]
|
61
|
+
|
62
|
+
@stdout.puts Rallycat::Update.new(api).task(task_number, opts)
|
63
|
+
when 'help'
|
64
|
+
# `puts` calls `to_s`
|
65
|
+
@stdout.puts Rallycat::Help.new
|
29
66
|
else
|
30
67
|
@stdout.puts 'only support for `cat` exists at the moment.'
|
31
68
|
end
|
data/lib/rallycat/connection.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'rally_rest_api'
|
3
|
+
require 'logger'
|
3
4
|
|
4
5
|
module Rallycat
|
5
6
|
class InvalidConfigError < StandardError; end
|
@@ -18,7 +19,9 @@ module Rallycat
|
|
18
19
|
@api = RallyRestAPI.new \
|
19
20
|
base_url: 'https://rally1.rallydev.com/slm',
|
20
21
|
username: config.fetch('username'),
|
21
|
-
password: config.fetch('password')
|
22
|
+
password: config.fetch('password'),
|
23
|
+
logger: Logger.new(nil)
|
24
|
+
|
22
25
|
rescue Rally::NotAuthenticatedError
|
23
26
|
raise InvalidCredentialsError.new('Your Rally credentials are invalid.')
|
24
27
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Rallycat
|
2
|
+
class Help
|
3
|
+
def to_s
|
4
|
+
<<-HELP
|
5
|
+
Rallycat is a command line utility for interacting with Rally.
|
6
|
+
|
7
|
+
Configuration:
|
8
|
+
Configuration is available through a ~/.rallycatrc file formatted as YAML.
|
9
|
+
The file should have two keys: `username` and `password` for authenticating
|
10
|
+
with the Rally API.
|
11
|
+
|
12
|
+
Additionally, the `-u [USERNAME]` and `-p [PASSWORD]` flags may be provided
|
13
|
+
at runtime and will take higher precedence than the configuration file.
|
14
|
+
|
15
|
+
Global Options:
|
16
|
+
-u [USERNAME] # The Rally user
|
17
|
+
-p [PASSWORD] # The password for the Rally user
|
18
|
+
-h, --help # Displays this help text
|
19
|
+
|
20
|
+
Commands:
|
21
|
+
rallycat cat [STORY NUMBER] # Displays the user story
|
22
|
+
rallycat help # Displays this help text
|
23
|
+
|
24
|
+
|
25
|
+
HELP
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Rallycat
|
2
|
+
class Update
|
3
|
+
def initialize(api)
|
4
|
+
@api = api
|
5
|
+
end
|
6
|
+
|
7
|
+
def task(task_number, attributes)
|
8
|
+
results = @api.find(:task) do
|
9
|
+
equal :formatted_id, task_number
|
10
|
+
end
|
11
|
+
|
12
|
+
task = results.first
|
13
|
+
|
14
|
+
if attributes[:state] && !attributes[:blocked]
|
15
|
+
attributes[:blocked] = false
|
16
|
+
end
|
17
|
+
|
18
|
+
user_name = attributes[:owner]
|
19
|
+
|
20
|
+
if user_name
|
21
|
+
user_results = @api.find(:user) do
|
22
|
+
equal :display_name, user_name
|
23
|
+
end
|
24
|
+
attributes[:owner] = user_results.first.login_name
|
25
|
+
end
|
26
|
+
|
27
|
+
task.update(attributes)
|
28
|
+
|
29
|
+
messages = []
|
30
|
+
|
31
|
+
messages << %{Task (#{task_number}) was set to "#{attributes[:state]}".} if attributes[:state]
|
32
|
+
messages << "Task (#{task_number}) was blocked." if attributes[:blocked]
|
33
|
+
messages << %{Task (#{task_number}) was assigned to "#{user_name}".} if attributes[:owner]
|
34
|
+
|
35
|
+
messages.join("\n")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/rallycat/version.rb
CHANGED
data/lib/rallycat.rb
CHANGED
data/spec/integration_spec.rb
CHANGED
@@ -5,21 +5,13 @@ describe 'Rallycat' do
|
|
5
5
|
context 'cat' do
|
6
6
|
|
7
7
|
it 'fetches, parses and outputs the rally story requested by the user' do
|
8
|
-
auth_responder = lambda do |env|
|
9
|
-
# 'https://rally1.rallydev.com/slm/webservice/current/user'
|
10
|
-
[200, {}, ['<foo>bar</foo>']]
|
11
|
-
end
|
12
|
-
|
13
8
|
sout = StringIO.new
|
14
|
-
cli = nil
|
15
9
|
|
16
|
-
|
17
|
-
cli = Rallycat::CLI.new %w{ cat US4567 -u=foo.bar@rallycat.com -p=password'}, sout
|
18
|
-
end
|
10
|
+
cli = Rallycat::CLI.new %w{ cat US4567 -u foo.bar@rallycat.com -p password }, sout
|
19
11
|
|
20
12
|
story_responder = RallyStoryResponder.new
|
21
13
|
|
22
|
-
Artifice.activate_with story_responder
|
14
|
+
Artifice.activate_with story_responder do
|
23
15
|
cli.run
|
24
16
|
end
|
25
17
|
|
@@ -27,4 +19,101 @@ describe 'Rallycat' do
|
|
27
19
|
sout.read.should include('# [US4567] - [Rework] Change link to button')
|
28
20
|
end
|
29
21
|
end
|
22
|
+
|
23
|
+
context 'help' do
|
24
|
+
it 'displays a help screen to the user' do
|
25
|
+
string_io = StringIO.new
|
26
|
+
|
27
|
+
cli = Rallycat::CLI.new %w{ help }, string_io
|
28
|
+
|
29
|
+
cli.run
|
30
|
+
|
31
|
+
string_io.rewind
|
32
|
+
expected = string_io.read
|
33
|
+
|
34
|
+
expected.should include("rallycat cat [STORY NUMBER]")
|
35
|
+
expected.should include("Displays the user story")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'update' do
|
40
|
+
|
41
|
+
context 'task' do
|
42
|
+
|
43
|
+
it 'sets the state to in-progress' do
|
44
|
+
sout = StringIO.new
|
45
|
+
|
46
|
+
cli = Rallycat::CLI.new %w{ update -i TA6666 -u foo.bar@rallycat.com -p password }, sout
|
47
|
+
|
48
|
+
task_responder = RallyTaskUpdateResponder.new
|
49
|
+
|
50
|
+
Artifice.activate_with task_responder do
|
51
|
+
cli.run
|
52
|
+
end
|
53
|
+
|
54
|
+
sout.rewind
|
55
|
+
sout.read.should include('Task (TA6666) was set to "In-Progress".')
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'sets the state to defined' do
|
59
|
+
sout = StringIO.new
|
60
|
+
|
61
|
+
cli = Rallycat::CLI.new %w{ update -d TA6666 -u foo.bar@rallycat.com -p password }, sout
|
62
|
+
|
63
|
+
task_responder = RallyTaskUpdateResponder.new
|
64
|
+
|
65
|
+
Artifice.activate_with task_responder do
|
66
|
+
cli.run
|
67
|
+
end
|
68
|
+
|
69
|
+
sout.rewind
|
70
|
+
sout.read.should include('Task (TA6666) was set to "Defined".')
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'sets the state to completed' do
|
74
|
+
sout = StringIO.new
|
75
|
+
|
76
|
+
cli = Rallycat::CLI.new %w{ update -c TA6666 -u foo.bar@rallycat.com -p password }, sout
|
77
|
+
|
78
|
+
task_responder = RallyTaskUpdateResponder.new
|
79
|
+
|
80
|
+
Artifice.activate_with task_responder do
|
81
|
+
cli.run
|
82
|
+
end
|
83
|
+
|
84
|
+
sout.rewind
|
85
|
+
sout.read.should include('Task (TA6666) was set to "Completed".')
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'blocks the task' do
|
89
|
+
sout = StringIO.new
|
90
|
+
|
91
|
+
cli = Rallycat::CLI.new %w{ update -b TA6666 -u foo.bar@rallycat.com -p password }, sout
|
92
|
+
|
93
|
+
task_responder = RallyTaskUpdateResponder.new
|
94
|
+
|
95
|
+
Artifice.activate_with task_responder do
|
96
|
+
cli.run
|
97
|
+
end
|
98
|
+
|
99
|
+
sout.rewind
|
100
|
+
sout.read.should include('Task (TA6666) was blocked.')
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'assigns the owner of the task' do
|
104
|
+
sout = StringIO.new
|
105
|
+
|
106
|
+
cli = Rallycat::CLI.new %w{ update -o Freddy\ Fender TA6666 -u foo.bar@rallycat.com -p password }, sout
|
107
|
+
|
108
|
+
task_responder = RallyTaskUpdateResponder.new
|
109
|
+
|
110
|
+
Artifice.activate_with task_responder do
|
111
|
+
cli.run
|
112
|
+
end
|
113
|
+
|
114
|
+
sout.rewind
|
115
|
+
sout.read.should include('Task (TA6666) was assigned to "Freddy Fender".')
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
30
119
|
end
|
@@ -45,7 +45,7 @@ STORY
|
|
45
45
|
|
46
46
|
responder = RallyStoryResponder.new
|
47
47
|
|
48
|
-
Artifice.activate_with responder
|
48
|
+
Artifice.activate_with responder do
|
49
49
|
story_num = 'US7176'
|
50
50
|
cat = Rallycat::Cat.new(@api)
|
51
51
|
cat.story(story_num).should == expected
|
@@ -75,7 +75,7 @@ STORY
|
|
75
75
|
|
76
76
|
responder = RallyDefectResponder.new
|
77
77
|
|
78
|
-
Artifice.activate_with responder
|
78
|
+
Artifice.activate_with responder do
|
79
79
|
story_num = 'DE1234'
|
80
80
|
cat = Rallycat::Cat.new(@api)
|
81
81
|
cat.story(story_num).should == expected
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rallycat::Update do
|
4
|
+
before do
|
5
|
+
auth_responder = lambda do |env|
|
6
|
+
# 'https://rally1.rallydev.com/slm/webservice/current/user'
|
7
|
+
[200, {}, ['<foo>bar</foo>']]
|
8
|
+
end
|
9
|
+
|
10
|
+
Artifice.activate_with auth_responder do
|
11
|
+
@api = Rallycat::Connection.new('foo.bar@rallycat.com', 'password').api
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "Tasks" do
|
16
|
+
|
17
|
+
it 'updates the state and removes block' do
|
18
|
+
|
19
|
+
responder = RallyTaskUpdateResponder.new
|
20
|
+
|
21
|
+
Artifice.activate_with responder do
|
22
|
+
task_num = "TA6666"
|
23
|
+
update = Rallycat::Update.new(@api)
|
24
|
+
update.task(task_num, state: "In-Progress")
|
25
|
+
end
|
26
|
+
|
27
|
+
post_request = responder.requests[2] # this is the request that actually updates the task
|
28
|
+
post_request.should be_post
|
29
|
+
post_request.url.should == 'https://rally1.rallydev.com/slm/webservice/1.17/task/12345'
|
30
|
+
|
31
|
+
body = post_request.body.tap(&:rewind).read
|
32
|
+
body.should include('<Blocked>false</Blocked>')
|
33
|
+
body.should include('<State>In-Progress</State>')
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'updates the state and preserves blocked if blocked given' do
|
37
|
+
|
38
|
+
responder = RallyTaskUpdateResponder.new
|
39
|
+
|
40
|
+
Artifice.activate_with responder do
|
41
|
+
task_num = "TA6666"
|
42
|
+
update = Rallycat::Update.new(@api)
|
43
|
+
message = update.task(task_num, state: "In-Progress", blocked: true)
|
44
|
+
message.should include('Task (TA6666) was set to "In-Progress"')
|
45
|
+
end
|
46
|
+
|
47
|
+
post_request = responder.requests[2] # this is the request that actually updates the task
|
48
|
+
post_request.should be_post
|
49
|
+
post_request.url.should == 'https://rally1.rallydev.com/slm/webservice/1.17/task/12345'
|
50
|
+
|
51
|
+
body = post_request.body.tap(&:rewind).read
|
52
|
+
body.should include('<Blocked>true</Blocked>')
|
53
|
+
body.should include('<State>In-Progress</State>')
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
it 'blocks the task' do
|
58
|
+
responder = RallyTaskUpdateResponder.new
|
59
|
+
|
60
|
+
Artifice.activate_with responder do
|
61
|
+
task_num = "TA6666"
|
62
|
+
update = Rallycat::Update.new(@api)
|
63
|
+
message = update.task(task_num, blocked: true)
|
64
|
+
message.should include('Task (TA6666) was blocked.')
|
65
|
+
end
|
66
|
+
|
67
|
+
post_request = responder.requests[2] # this is the request that actually updates the task
|
68
|
+
post_request.should be_post
|
69
|
+
post_request.url.should == 'https://rally1.rallydev.com/slm/webservice/1.17/task/12345'
|
70
|
+
|
71
|
+
body = post_request.body.tap(&:rewind).read
|
72
|
+
body.should include('<Blocked>true</Blocked>')
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'assigns the owner' do
|
76
|
+
responder = RallyTaskUpdateResponder.new
|
77
|
+
|
78
|
+
Artifice.activate_with responder do
|
79
|
+
task_num = "TA6666"
|
80
|
+
update = Rallycat::Update.new(@api)
|
81
|
+
message = update.task(task_num, state: 'Completed', owner: 'Freddy Fender')
|
82
|
+
message.should include('Task (TA6666) was assigned to "Freddy Fender"')
|
83
|
+
end
|
84
|
+
|
85
|
+
# require "pry"; binding.pry
|
86
|
+
post_request = responder.requests[4] # this is the request that actually updates the task
|
87
|
+
post_request.should be_post
|
88
|
+
post_request.url.should == 'https://rally1.rallydev.com/slm/webservice/1.17/task/12345'
|
89
|
+
|
90
|
+
body = post_request.body.tap(&:rewind).read
|
91
|
+
body.should include('<State>Completed</State>')
|
92
|
+
body.should include('<Owner>fred.fender@testing.com</Owner>')
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -10,33 +10,31 @@ class RallyDefectResponder
|
|
10
10
|
@requests.last
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
14
|
-
|
15
|
-
@requests << request = Rack::Request.new(env)
|
13
|
+
def call(env)
|
14
|
+
@requests << request = Rack::Request.new(env)
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
16
|
+
case request.url
|
17
|
+
when "https://rally1.rallydev.com/slm/webservice/current/Defect?query=%28FormattedId+%3D+DE1234%29&fetch=true"
|
18
|
+
[200, {}, [
|
19
|
+
<<-XML
|
20
|
+
<QueryResult>
|
21
|
+
<Results>
|
22
|
+
<Object>
|
23
|
+
<FormattedID>DE1234</FormattedID>
|
24
|
+
<Name>[Rework] Change link to button</Name>
|
25
|
+
<PlanEstimate>1.0</PlanEstimate>
|
26
|
+
<ScheduleState>In-Progress</ScheduleState>
|
27
|
+
<TaskActualTotal>0.0</TaskActualTotal>
|
28
|
+
<TaskEstimateTotal>6.5</TaskEstimateTotal>
|
29
|
+
<TaskRemainingTotal>0.5</TaskRemainingTotal>
|
30
|
+
<Owner>scootin@fruity.com</Owner>
|
31
|
+
<Description>#{ CGI::escapeHTML('<div><p>This is a defect.</p></div>') }</Description>
|
32
|
+
</Object>
|
33
|
+
</Results>
|
34
|
+
<TotalResultCount>1</TotalResultCount>
|
35
|
+
</QueryResult>
|
37
36
|
XML
|
38
|
-
|
39
|
-
end
|
37
|
+
]]
|
40
38
|
end
|
41
39
|
end
|
42
40
|
end
|
@@ -12,80 +12,78 @@ class RallyStoryResponder
|
|
12
12
|
@requests.last
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
16
|
-
|
17
|
-
@requests << request = Rack::Request.new(env)
|
15
|
+
def call(env)
|
16
|
+
@requests << request = Rack::Request.new(env)
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
18
|
+
case request.url
|
19
|
+
when 'https://rally1.rallydev.com/slm/webservice/1.17/task/1'
|
20
|
+
[200, {}, [
|
21
|
+
<<-XML
|
22
|
+
<Task refObjectName="Change link to button">
|
23
|
+
<FormattedID>TA1234</FormattedID>
|
24
|
+
<State>Complete</State>
|
25
|
+
<TaskIndex>1</TaskIndex>
|
26
|
+
</Task>
|
28
27
|
XML
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
28
|
+
]]
|
29
|
+
when 'https://rally1.rallydev.com/slm/webservice/1.17/task/2'
|
30
|
+
[200, {}, [
|
31
|
+
<<-XML
|
32
|
+
<Task refObjectName="Add confirmation">
|
33
|
+
<FormattedID>TA1235</FormattedID>
|
34
|
+
<State>In-Progress</State>
|
35
|
+
<TaskIndex>2</TaskIndex>
|
36
|
+
</Task>
|
38
37
|
XML
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
38
|
+
]]
|
39
|
+
when 'https://rally1.rallydev.com/slm/webservice/1.17/task/3'
|
40
|
+
[200, {}, [
|
41
|
+
<<-XML
|
42
|
+
<Task refObjectName="Code Review">
|
43
|
+
<FormattedID>TA1236</FormattedID>
|
44
|
+
<State>Defined</State>
|
45
|
+
<TaskIndex>3</TaskIndex>
|
46
|
+
</Task>
|
48
47
|
XML
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
48
|
+
]]
|
49
|
+
when 'https://rally1.rallydev.com/slm/webservice/1.17/task/4'
|
50
|
+
[200, {}, [
|
51
|
+
<<-XML
|
52
|
+
<Task refObjectName="QA Test">
|
53
|
+
<FormattedID>TA1237</FormattedID>
|
54
|
+
<State>Defined</State>
|
55
|
+
<TaskIndex>4</TaskIndex>
|
56
|
+
</Task>
|
58
57
|
XML
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
58
|
+
]]
|
59
|
+
else
|
60
|
+
# https://rally1.rallydev.com/slm/webservice/current/HierarchicalRequirement?query=%28FormattedId+%3D+US7176%29&fetch=true
|
61
|
+
[200, {}, [
|
62
|
+
<<-XML
|
63
|
+
<QueryResult>
|
64
|
+
<Results>
|
65
|
+
<Object>
|
66
|
+
<FormattedID>US4567</FormattedID>
|
67
|
+
<Name>[Rework] Change link to button</Name>
|
68
|
+
<PlanEstimate>1.0</PlanEstimate>
|
69
|
+
<ScheduleState>In-Progress</ScheduleState>
|
70
|
+
<TaskActualTotal>0.0</TaskActualTotal>
|
71
|
+
<TaskEstimateTotal>6.5</TaskEstimateTotal>
|
72
|
+
<TaskRemainingTotal>0.5</TaskRemainingTotal>
|
73
|
+
<Owner>scootin@fruity.com</Owner>
|
74
|
+
<Description>#{ CGI::escapeHTML('<div><p>This is the story</p></div><ul><li>Remember to do this.</li><li>And this too.</li></ul>') }</Description>
|
75
|
+
<Tasks>
|
76
|
+
<Task ref="https://rally1.rallydev.com/slm/webservice/1.17/task/1" />
|
77
|
+
<Task ref="https://rally1.rallydev.com/slm/webservice/1.17/task/2" />
|
78
|
+
<Task ref="https://rally1.rallydev.com/slm/webservice/1.17/task/3" />
|
79
|
+
<Task ref="https://rally1.rallydev.com/slm/webservice/1.17/task/4" />
|
80
|
+
</Tasks>
|
81
|
+
</Object>
|
82
|
+
</Results>
|
83
|
+
<TotalResultCount>1</TotalResultCount>
|
84
|
+
</QueryResult>
|
86
85
|
XML
|
87
|
-
|
88
|
-
end
|
86
|
+
]]
|
89
87
|
end
|
90
88
|
end
|
91
89
|
end
|
@@ -0,0 +1,88 @@
|
|
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
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
@requests << request = Rack::Request.new(env)
|
15
|
+
|
16
|
+
if request.url == 'https://rally1.rallydev.com/slm/webservice/current/Task?query=%28FormattedId+%3D+TA6666%29'
|
17
|
+
[200, {}, [
|
18
|
+
<<-XML
|
19
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
20
|
+
<QueryResult rallyAPIMajor="1" rallyAPIMinor="17">
|
21
|
+
<TotalResultCount>1</TotalResultCount>
|
22
|
+
<StartIndex>1</StartIndex>
|
23
|
+
<PageSize>20</PageSize>
|
24
|
+
<Results>
|
25
|
+
<Object rallyAPIMajor="1" rallyAPIMinor="17" ref="https://rally1.rallydev.com/slm/webservice/1.17/task/12345" refObjectName="Tie your shoes!" type="Task" />
|
26
|
+
</Results>
|
27
|
+
</QueryResult>
|
28
|
+
XML
|
29
|
+
]]
|
30
|
+
elsif request.get? && request.url == 'https://rally1.rallydev.com/slm/webservice/1.17/task/12345'
|
31
|
+
[200, {}, [
|
32
|
+
<<-XML
|
33
|
+
<Task rallyAPIMajor="1" rallyAPIMinor="17" ref="https://rally1.rallydev.com/slm/webservice/1.17/task/12345" objectVersion="8" refObjectName="Tie your shoes!" CreatedAt="today at 8:31 pm">
|
34
|
+
<CreationDate>2012-07-17T03:31:33.801Z</CreationDate>
|
35
|
+
<ObjectID>12345</ObjectID>
|
36
|
+
<Description />
|
37
|
+
<Discussion />
|
38
|
+
<FormattedID>TA6666</FormattedID>
|
39
|
+
<LastUpdateDate>2012-07-17T04:00:35.888Z</LastUpdateDate>
|
40
|
+
<Name>Tie your shoes!</Name>
|
41
|
+
<Notes />
|
42
|
+
<Owner>tester@testing.com</Owner>
|
43
|
+
<Tags />
|
44
|
+
<Attachments />
|
45
|
+
<Blocked>false</Blocked>
|
46
|
+
<Rank>4000</Rank>
|
47
|
+
<State>Defined</State>
|
48
|
+
<TaskIndex>2</TaskIndex>
|
49
|
+
<ToDo>2.0</ToDo>
|
50
|
+
</Task>
|
51
|
+
XML
|
52
|
+
]]
|
53
|
+
elsif request.post? && request.url == 'https://rally1.rallydev.com/slm/webservice/1.17/task/12345'
|
54
|
+
[200, {}, ['<?xml version="1.0" encoding="UTF-8"?><OperationResult rallyAPIMajor="1" rallyAPIMinor="17"><Errors /><Warnings /></OperationResult>']]
|
55
|
+
elsif request.url == 'https://rally1.rallydev.com/slm/webservice/current/User?query=%28DisplayName+%3D+%22Freddy+Fender%22%29'
|
56
|
+
[200, {}, [
|
57
|
+
<<-XML
|
58
|
+
<QueryResult rallyAPIMajor="1" rallyAPIMinor="17">
|
59
|
+
<Errors />
|
60
|
+
<Warnings />
|
61
|
+
<TotalResultCount>1</TotalResultCount>
|
62
|
+
<StartIndex>1</StartIndex>
|
63
|
+
<PageSize>20</PageSize>
|
64
|
+
<Results>
|
65
|
+
<Object rallyAPIMajor="1" rallyAPIMinor="17" ref="https://rally1.rallydev.com/slm/webservice/1.17/user/4567" refObjectName="Freddy Fender" type="User" />
|
66
|
+
</Results>
|
67
|
+
</QueryResult>
|
68
|
+
XML
|
69
|
+
]]
|
70
|
+
elsif request.url == 'https://rally1.rallydev.com/slm/webservice/1.17/user/4567'
|
71
|
+
[200, {}, [
|
72
|
+
<<-XML
|
73
|
+
<User rallyAPIMajor="1" rallyAPIMinor="17" ref="https://rally1.rallydev.com/slm/webservice/1.17/user/4567" objectVersion="50" refObjectName="Freddy Fender">
|
74
|
+
<ObjectID>4567</ObjectID>
|
75
|
+
<Disabled>false</Disabled>
|
76
|
+
<DisplayName>Freddy Fender</DisplayName>
|
77
|
+
<EmailAddress>fred.fender@testing.com</EmailAddress>
|
78
|
+
<FirstName>Freddy</FirstName>
|
79
|
+
<LastName>Fender</LastName>
|
80
|
+
<LoginName>fred.fender@testing.com</LoginName>
|
81
|
+
</User>
|
82
|
+
XML
|
83
|
+
]]
|
84
|
+
else
|
85
|
+
[200, {}, ['<else />']]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
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.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -14,7 +14,7 @@ date: 2012-07-17 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: builder
|
17
|
-
requirement: &
|
17
|
+
requirement: &70176499099720 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70176499099720
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: rally_rest_api
|
28
|
-
requirement: &
|
28
|
+
requirement: &70176499099160 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *70176499099160
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: nokogiri
|
39
|
-
requirement: &
|
39
|
+
requirement: &70176499098740 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,7 +44,7 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :runtime
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *70176499098740
|
48
48
|
description: The Rally website sucks. CLI is better.
|
49
49
|
email:
|
50
50
|
- adam@adamtanner.org
|
@@ -67,7 +67,9 @@ files:
|
|
67
67
|
- lib/rallycat/cat.rb
|
68
68
|
- lib/rallycat/cli.rb
|
69
69
|
- lib/rallycat/connection.rb
|
70
|
+
- lib/rallycat/help.rb
|
70
71
|
- lib/rallycat/html_to_text_converter.rb
|
72
|
+
- lib/rallycat/update.rb
|
71
73
|
- lib/rallycat/version.rb
|
72
74
|
- rallycat.gemspec
|
73
75
|
- spec/integration_spec.rb
|
@@ -75,9 +77,11 @@ files:
|
|
75
77
|
- spec/lib/rallycat/cli_spec.rb
|
76
78
|
- spec/lib/rallycat/connection_spec.rb
|
77
79
|
- spec/lib/rallycat/html_to_text_converter_spec.rb
|
80
|
+
- spec/lib/rallycat/update_spec.rb
|
78
81
|
- spec/spec_helper.rb
|
79
82
|
- spec/support/rally_defect_responder.rb
|
80
83
|
- spec/support/rally_story_responder.rb
|
84
|
+
- spec/support/rally_task_update_responder.rb
|
81
85
|
homepage: https://github.com/adamtanner/rallycat
|
82
86
|
licenses: []
|
83
87
|
post_install_message:
|
@@ -92,7 +96,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
92
96
|
version: '0'
|
93
97
|
segments:
|
94
98
|
- 0
|
95
|
-
hash:
|
99
|
+
hash: 333992134023580695
|
96
100
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
101
|
none: false
|
98
102
|
requirements:
|
@@ -101,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
105
|
version: '0'
|
102
106
|
segments:
|
103
107
|
- 0
|
104
|
-
hash:
|
108
|
+
hash: 333992134023580695
|
105
109
|
requirements: []
|
106
110
|
rubyforge_project:
|
107
111
|
rubygems_version: 1.8.7
|
@@ -114,6 +118,8 @@ test_files:
|
|
114
118
|
- spec/lib/rallycat/cli_spec.rb
|
115
119
|
- spec/lib/rallycat/connection_spec.rb
|
116
120
|
- spec/lib/rallycat/html_to_text_converter_spec.rb
|
121
|
+
- spec/lib/rallycat/update_spec.rb
|
117
122
|
- spec/spec_helper.rb
|
118
123
|
- spec/support/rally_defect_responder.rb
|
119
124
|
- spec/support/rally_story_responder.rb
|
125
|
+
- spec/support/rally_task_update_responder.rb
|