rallycat 0.1.0 → 0.2.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.
- 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
|