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 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