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 CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rallycat (0.1.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.3)
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 USER') do |user|
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Rallycat
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/rallycat.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  require 'rallycat/cat'
2
2
  require 'rallycat/cli'
3
3
  require 'rallycat/connection'
4
+ require 'rallycat/help'
4
5
  require 'rallycat/html_to_text_converter'
6
+ require 'rallycat/update'
5
7
  require 'rallycat/version'
6
8
 
7
9
  module Rallycat
@@ -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
- Artifice.activate_with auth_responder do
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.endpoint do
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.endpoint do
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.endpoint do
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
@@ -12,7 +12,7 @@ describe Rallycat::CLI, '#run' do
12
12
 
13
13
  it 'should execute command' do
14
14
  sout = StringIO.new
15
- cli = Rallycat::CLI.new ['help'], sout
15
+ cli = Rallycat::CLI.new ['foo'], sout
16
16
 
17
17
  cli.run
18
18
 
@@ -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 endpoint
14
- lambda do |env|
15
- @requests << request = Rack::Request.new(env)
13
+ def call(env)
14
+ @requests << request = Rack::Request.new(env)
16
15
 
17
- case request.url
18
- when "https://rally1.rallydev.com/slm/webservice/current/Defect?query=%28FormattedId+%3D+DE1234%29&fetch=true"
19
- [200, {}, [
20
- <<-XML
21
- <QueryResult>
22
- <Results>
23
- <Object>
24
- <FormattedID>DE1234</FormattedID>
25
- <Name>[Rework] Change link to button</Name>
26
- <PlanEstimate>1.0</PlanEstimate>
27
- <ScheduleState>In-Progress</ScheduleState>
28
- <TaskActualTotal>0.0</TaskActualTotal>
29
- <TaskEstimateTotal>6.5</TaskEstimateTotal>
30
- <TaskRemainingTotal>0.5</TaskRemainingTotal>
31
- <Owner>scootin@fruity.com</Owner>
32
- <Description>#{ CGI::escapeHTML('<div><p>This is a defect.</p></div>') }</Description>
33
- </Object>
34
- </Results>
35
- <TotalResultCount>1</TotalResultCount>
36
- </QueryResult>
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 endpoint
16
- lambda do |env|
17
- @requests << request = Rack::Request.new(env)
15
+ def call(env)
16
+ @requests << request = Rack::Request.new(env)
18
17
 
19
- case request.url
20
- when 'https://rally1.rallydev.com/slm/webservice/1.17/task/1'
21
- [200, {}, [
22
- <<-XML
23
- <Task refObjectName="Change link to button">
24
- <FormattedID>TA1234</FormattedID>
25
- <State>Complete</State>
26
- <TaskIndex>1</TaskIndex>
27
- </Task>
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
- when 'https://rally1.rallydev.com/slm/webservice/1.17/task/2'
31
- [200, {}, [
32
- <<-XML
33
- <Task refObjectName="Add confirmation">
34
- <FormattedID>TA1235</FormattedID>
35
- <State>In-Progress</State>
36
- <TaskIndex>2</TaskIndex>
37
- </Task>
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
- when 'https://rally1.rallydev.com/slm/webservice/1.17/task/3'
41
- [200, {}, [
42
- <<-XML
43
- <Task refObjectName="Code Review">
44
- <FormattedID>TA1236</FormattedID>
45
- <State>Defined</State>
46
- <TaskIndex>3</TaskIndex>
47
- </Task>
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
- when 'https://rally1.rallydev.com/slm/webservice/1.17/task/4'
51
- [200, {}, [
52
- <<-XML
53
- <Task refObjectName="QA Test">
54
- <FormattedID>TA1237</FormattedID>
55
- <State>Defined</State>
56
- <TaskIndex>4</TaskIndex>
57
- </Task>
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
- else
61
- # https://rally1.rallydev.com/slm/webservice/current/HierarchicalRequirement?query=%28FormattedId+%3D+US7176%29&fetch=true
62
- [200, {}, [
63
- <<-XML
64
- <QueryResult>
65
- <Results>
66
- <Object>
67
- <FormattedID>US4567</FormattedID>
68
- <Name>[Rework] Change link to button</Name>
69
- <PlanEstimate>1.0</PlanEstimate>
70
- <ScheduleState>In-Progress</ScheduleState>
71
- <TaskActualTotal>0.0</TaskActualTotal>
72
- <TaskEstimateTotal>6.5</TaskEstimateTotal>
73
- <TaskRemainingTotal>0.5</TaskRemainingTotal>
74
- <Owner>scootin@fruity.com</Owner>
75
- <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>
76
- <Tasks>
77
- <Task ref="https://rally1.rallydev.com/slm/webservice/1.17/task/1" />
78
- <Task ref="https://rally1.rallydev.com/slm/webservice/1.17/task/2" />
79
- <Task ref="https://rally1.rallydev.com/slm/webservice/1.17/task/3" />
80
- <Task ref="https://rally1.rallydev.com/slm/webservice/1.17/task/4" />
81
- </Tasks>
82
- </Object>
83
- </Results>
84
- <TotalResultCount>1</TotalResultCount>
85
- </QueryResult>
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.1.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: &70363599472260 !ruby/object:Gem::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: *70363599472260
25
+ version_requirements: *70176499099720
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: rally_rest_api
28
- requirement: &70363599471700 !ruby/object:Gem::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: *70363599471700
36
+ version_requirements: *70176499099160
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: nokogiri
39
- requirement: &70363599471120 !ruby/object:Gem::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: *70363599471120
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: -2940249692508219253
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: -2940249692508219253
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