v2gpti 1.1.9 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/bin/git-deliver +1 -1
  3. data/bin/git-finish +1 -1
  4. data/bin/git-newbug +1 -1
  5. data/bin/git-newfeature +1 -1
  6. data/bin/git-qa +1 -1
  7. data/bin/git-release +1 -1
  8. data/bin/git-report +1 -1
  9. data/bin/git-start +1 -1
  10. data/bin/git-uat +1 -1
  11. data/config_template +16 -0
  12. data/lib/git-pivotal-tracker-integration/command/base.rb +235 -322
  13. data/lib/git-pivotal-tracker-integration/command/configuration.rb +183 -109
  14. data/lib/git-pivotal-tracker-integration/command/deliver.rb +145 -200
  15. data/lib/git-pivotal-tracker-integration/command/finish.rb +70 -63
  16. data/lib/git-pivotal-tracker-integration/command/newbug.rb +36 -39
  17. data/lib/git-pivotal-tracker-integration/command/newfeature.rb +43 -42
  18. data/lib/git-pivotal-tracker-integration/command/release.rb +171 -203
  19. data/lib/git-pivotal-tracker-integration/command/report.rb +33 -36
  20. data/lib/git-pivotal-tracker-integration/command/start.rb +74 -78
  21. data/lib/git-pivotal-tracker-integration/util/git.rb +202 -204
  22. data/lib/git-pivotal-tracker-integration/util/shell.rb +19 -16
  23. data/lib/git-pivotal-tracker-integration/util/story.rb +155 -177
  24. data/lib/git-pivotal-tracker-integration/version-update/gradle.rb +44 -40
  25. data/lib/git-pivotal-tracker-integration.rb +44 -0
  26. data/spec/git-pivotal-tracker-integration/command/configuration_spec.rb +1 -2
  27. data/spec/git-pivotal-tracker-integration/command/finish_spec.rb +1 -1
  28. data/spec/git-pivotal-tracker-integration/command/release_spec.rb +1 -1
  29. data/spec/git-pivotal-tracker-integration/command/start_spec.rb +1 -1
  30. data/spec/git-pivotal-tracker-integration/util/story_spec.rb +21 -32
  31. data/tracker_api/lib/tracker_api/client.rb +241 -0
  32. data/tracker_api/lib/tracker_api/endpoints/activity.rb +38 -0
  33. data/tracker_api/lib/tracker_api/endpoints/comments.rb +27 -0
  34. data/tracker_api/lib/tracker_api/endpoints/epic.rb +17 -0
  35. data/tracker_api/lib/tracker_api/endpoints/epics.rb +20 -0
  36. data/tracker_api/lib/tracker_api/endpoints/file_attachment.rb +18 -0
  37. data/tracker_api/lib/tracker_api/endpoints/iterations.rb +20 -0
  38. data/tracker_api/lib/tracker_api/endpoints/me.rb +17 -0
  39. data/tracker_api/lib/tracker_api/endpoints/memberships.rb +20 -0
  40. data/tracker_api/lib/tracker_api/endpoints/notifications.rb +20 -0
  41. data/tracker_api/lib/tracker_api/endpoints/project.rb +17 -0
  42. data/tracker_api/lib/tracker_api/endpoints/projects.rb +18 -0
  43. data/tracker_api/lib/tracker_api/endpoints/stories.rb +20 -0
  44. data/tracker_api/lib/tracker_api/endpoints/story.rb +37 -0
  45. data/tracker_api/lib/tracker_api/endpoints/tasks.rb +20 -0
  46. data/tracker_api/lib/tracker_api/error.rb +18 -0
  47. data/tracker_api/lib/tracker_api/logger.rb +31 -0
  48. data/tracker_api/lib/tracker_api/resources/account.rb +18 -0
  49. data/tracker_api/lib/tracker_api/resources/activity.rb +24 -0
  50. data/tracker_api/lib/tracker_api/resources/base.rb +71 -0
  51. data/tracker_api/lib/tracker_api/resources/change.rb +15 -0
  52. data/tracker_api/lib/tracker_api/resources/comment.rb +20 -0
  53. data/tracker_api/lib/tracker_api/resources/epic.rb +17 -0
  54. data/tracker_api/lib/tracker_api/resources/file_attachment.rb +23 -0
  55. data/tracker_api/lib/tracker_api/resources/iteration.rb +24 -0
  56. data/tracker_api/lib/tracker_api/resources/label.rb +14 -0
  57. data/tracker_api/lib/tracker_api/resources/me.rb +21 -0
  58. data/tracker_api/lib/tracker_api/resources/membership_summary.rb +15 -0
  59. data/tracker_api/lib/tracker_api/resources/notification.rb +26 -0
  60. data/tracker_api/lib/tracker_api/resources/person.rb +14 -0
  61. data/tracker_api/lib/tracker_api/resources/primary_resource.rb +13 -0
  62. data/tracker_api/lib/tracker_api/resources/project.rb +131 -0
  63. data/tracker_api/lib/tracker_api/resources/project_membership.rb +16 -0
  64. data/tracker_api/lib/tracker_api/resources/story.rb +102 -0
  65. data/tracker_api/lib/tracker_api/resources/task.rb +16 -0
  66. data/tracker_api/lib/tracker_api/resources/time_zone.rb +13 -0
  67. data/tracker_api/lib/tracker_api/version.rb +3 -0
  68. data/tracker_api/lib/tracker_api.rb +60 -0
  69. metadata +202 -53
  70. data/lib/git-pivotal-tracker-integration/command/command.rb +0 -20
  71. data/lib/git-pivotal-tracker-integration/util/util.rb +0 -20
  72. data/lib/git-pivotal-tracker-integration/version-update/version_update.rb +0 -20
  73. data/lib/git_pivotal_tracker_integration.rb +0 -18
@@ -15,7 +15,7 @@
15
15
 
16
16
  require 'spec_helper'
17
17
  require 'git-pivotal-tracker-integration/util/story'
18
- require 'pivotal-tracker'
18
+ require 'tracker_api'
19
19
 
20
20
  describe GitPivotalTrackerIntegration::Util::Story do
21
21
 
@@ -33,9 +33,9 @@ describe GitPivotalTrackerIntegration::Util::Story do
33
33
  story = double('story')
34
34
  story.should_receive(:name)
35
35
  story.should_receive(:description).and_return("description-1\ndescription-2")
36
- PivotalTracker::Note.should_receive(:all).and_return([
37
- PivotalTracker::Note.new(:noted_at => Date.new, :text => 'note-1')
38
- ])
36
+ # PivotalTracker::Note.should_receive(:all).and_return([
37
+ # PivotalTracker::Note.new(:noted_at => Date.new, :text => 'note-1')
38
+ # ])
39
39
 
40
40
  GitPivotalTrackerIntegration::Util::Story.pretty_print story
41
41
 
@@ -43,7 +43,6 @@ describe GitPivotalTrackerIntegration::Util::Story do
43
43
  " Title: \n" +
44
44
  "Description: description-1\n" +
45
45
  " description-2\n" +
46
- " Note 1: note-1\n" +
47
46
  "\n")
48
47
  end
49
48
 
@@ -51,7 +50,7 @@ describe GitPivotalTrackerIntegration::Util::Story do
51
50
  story = double('story')
52
51
  story.should_receive(:name)
53
52
  story.should_receive(:description)
54
- PivotalTracker::Note.should_receive(:all).and_return([])
53
+ story.should_receive(:comments).and_return([])
55
54
 
56
55
  GitPivotalTrackerIntegration::Util::Story.pretty_print story
57
56
 
@@ -64,7 +63,8 @@ describe GitPivotalTrackerIntegration::Util::Story do
64
63
  story = double('story')
65
64
  story.should_receive(:name)
66
65
  story.should_receive(:description).and_return('')
67
- PivotalTracker::Note.should_receive(:all).and_return([])
66
+ story.should_receive(:comments).and_return([])
67
+
68
68
 
69
69
  GitPivotalTrackerIntegration::Util::Story.pretty_print story
70
70
 
@@ -74,8 +74,7 @@ describe GitPivotalTrackerIntegration::Util::Story do
74
74
  end
75
75
 
76
76
  it 'should select a story directly if the filter is a number' do
77
- @project.should_receive(:stories).and_return(@stories)
78
- @stories.should_receive(:find).with(12345678).and_return(@story)
77
+ @project.should_receive(:story).and_return(@story)
79
78
 
80
79
  story = GitPivotalTrackerIntegration::Util::Story.select_story @project, '12345678'
81
80
 
@@ -83,37 +82,30 @@ describe GitPivotalTrackerIntegration::Util::Story do
83
82
  end
84
83
 
85
84
  it 'should select a story if the result of the query is a single story' do
86
- @project.should_receive(:stories).and_return(@stories)
87
- @stories.should_receive(:all).with(
88
- :current_state => %w(rejected unstarted unscheduled),
89
- :limit => 1,
90
- :story_type => 'release'
91
- ).and_return([@story])
92
- @story.stub(:story_type) {'release'}
85
+ @project.should_receive(:stories).and_return([@story])
86
+ @story.stub(:story_type) {'feature'}
93
87
  @story.stub(:name) {'story_name'}
88
+ @story.stub(:labels){''}
89
+ @story.stub(:estimate){ 1}
94
90
 
95
91
  @menu.stub(:prompt=)
96
92
  @menu.stub(:choice)
97
93
  GitPivotalTrackerIntegration::Util::Story.should_receive(:choose) { |&arg| arg.call @menu }.and_return(@story)
98
94
 
99
- story = GitPivotalTrackerIntegration::Util::Story.select_story @project, 'release', 1
95
+ story = GitPivotalTrackerIntegration::Util::Story.select_story @project
100
96
 
101
97
  expect(story).to be(@story)
102
98
  end
103
99
 
104
100
  it 'should prompt the user for a story if the result of the query is more than a single story' do
105
- @project.should_receive(:stories).and_return(@stories)
106
- @stories.should_receive(:all).with(
107
- :current_state => %w(rejected unstarted unscheduled),
108
- :limit => 5,
109
- :story_type => 'feature'
110
- ).and_return([
111
- PivotalTracker::Story.new(:name => 'name-1'),
112
- PivotalTracker::Story.new(:name => 'name-2')
101
+ @project.should_receive(:stories).and_return([
102
+ TrackerApi::Resources::Story.new(:name => 'name-1',:estimate => 1,:story_type => 'feature'),
103
+ TrackerApi::Resources::Story.new(:name => 'name-2',:estimate => 1)
113
104
  ])
114
105
  @menu.should_receive(:prompt=)
115
106
  @menu.should_receive(:choice).with('name-1')
116
107
  @menu.should_receive(:choice).with('name-2')
108
+ @menu.should_receive(:choice).with('Quit')
117
109
  GitPivotalTrackerIntegration::Util::Story.should_receive(:choose) { |&arg| arg.call @menu }.and_return(@story)
118
110
 
119
111
  story = GitPivotalTrackerIntegration::Util::Story.select_story @project, 'feature'
@@ -122,17 +114,14 @@ describe GitPivotalTrackerIntegration::Util::Story do
122
114
  end
123
115
 
124
116
  it 'should prompt the user with the story type if no filter is specified' do
125
- @project.should_receive(:stories).and_return(@stories)
126
- @stories.should_receive(:all).with(
127
- :current_state => %w(rejected unstarted unscheduled),
128
- :limit => 5
129
- ).and_return([
130
- PivotalTracker::Story.new(:story_type => 'chore', :name => 'name-1'),
131
- PivotalTracker::Story.new(:story_type => 'bug', :name => 'name-2')
117
+ @project.should_receive(:stories).and_return([
118
+ TrackerApi::Resources::Story.new(:story_type => 'chore', :name => 'name-1'),
119
+ TrackerApi::Resources::Story.new(:story_type => 'bug', :name => 'name-2')
132
120
  ])
133
121
  @menu.should_receive(:prompt=)
134
122
  @menu.should_receive(:choice).with('CHORE name-1')
135
123
  @menu.should_receive(:choice).with('BUG name-2')
124
+ @menu.should_receive(:choice).with('Quit')
136
125
  GitPivotalTrackerIntegration::Util::Story.should_receive(:choose) { |&arg| arg.call @menu }.and_return(@story)
137
126
 
138
127
  story = GitPivotalTrackerIntegration::Util::Story.select_story @project
@@ -0,0 +1,241 @@
1
+ module TrackerApi
2
+ class Client
3
+ USER_AGENT = "Ruby/#{RUBY_VERSION} (#{RUBY_PLATFORM}; #{RUBY_ENGINE}) TrackerApi/#{TrackerApi::VERSION} Faraday/#{Faraday::VERSION}".freeze
4
+
5
+ # Header keys that can be passed in options hash to {#get},{#paginate}
6
+ CONVENIENCE_HEADERS = Set.new([:accept, :content_type])
7
+
8
+ attr_reader :url, :api_version, :token, :logger, :connection, :auto_paginate, :last_response
9
+
10
+ # Create Pivotal Tracker API client.
11
+ #
12
+ # @param [Hash] options the connection options
13
+ # @option options [String] :token API token to use for requests
14
+ # @option options [String] :url Main HTTP API root
15
+ # @option options [Boolean] :auto_paginate Client should perform pagination automatically. Default true.
16
+ # @option options [String] :api_version The API version URL path
17
+ # @option options [String] :logger Custom logger
18
+ # @option options [String] :adapter Custom http adapter to configure Faraday with
19
+ # @option options [String] :connection_options Connection options to pass to Faraday
20
+ #
21
+ # @example Creating a Client
22
+ # Client.new token: 'my-super-special-token'
23
+ def initialize(options={})
24
+ url = options.fetch(:url, 'https://www.pivotaltracker.com')
25
+ @url = Addressable::URI.parse(url).to_s
26
+ @api_version = options.fetch(:api_version, '/services/v5')
27
+ @logger = options.fetch(:logger, ::Logger.new(nil))
28
+ adapter = options.fetch(:adapter, :excon)
29
+ connection_options = options.fetch(:connection_options, { ssl: { verify: true } })
30
+ @auto_paginate = options.fetch(:auto_paginate, true)
31
+ @token = options[:token]
32
+ raise 'Missing required options: :token' unless @token
33
+
34
+ @connection = Faraday.new({ url: @url }.merge(connection_options)) do |builder|
35
+ # response
36
+ builder.use Faraday::Response::RaiseError
37
+ builder.response :json
38
+
39
+ # request
40
+ builder.request :multipart
41
+ builder.request :json
42
+
43
+ builder.use TrackerApi::Logger, @logger
44
+ builder.adapter adapter
45
+ end
46
+ end
47
+
48
+ # Make a HTTP GET request
49
+ #
50
+ # @param path [String] The path, relative to api endpoint
51
+ # @param options [Hash] Query and header params for request
52
+ # @return [Faraday::Response]
53
+ def get(path, options = {})
54
+ request(:get, parse_query_and_convenience_headers(path, options))
55
+ end
56
+
57
+ # Make a HTTP POST request
58
+ #
59
+ # @param path [String] The path, relative to api endpoint
60
+ # @param options [Hash] Query and header params for request
61
+ # @return [Faraday::Response]
62
+ def post(path, options = {})
63
+ request(:post, parse_query_and_convenience_headers(path, options))
64
+ end
65
+
66
+ # Make a HTTP PUT request
67
+ #
68
+ # @param path [String] The path, relative to api endpoint
69
+ # @param options [Hash] Query and header params for request
70
+ # @return [Faraday::Response]
71
+ def put(path, options = {})
72
+ request(:put, parse_query_and_convenience_headers(path, options))
73
+ end
74
+
75
+ # Make one or more HTTP GET requests, optionally fetching
76
+ # the next page of results from information passed back in headers
77
+ # based on value in {#auto_paginate}.
78
+ #
79
+ # @param path [String] The path, relative to {#api_endpoint}
80
+ # @param options [Hash] Query and header params for request
81
+ # @param block [Block] Block to perform the data concatenation of the
82
+ # multiple requests. The block is called with two parameters, the first
83
+ # contains the contents of the requests so far and the second parameter
84
+ # contains the latest response.
85
+ # @return [Array]
86
+ def paginate(path, options = {}, &block)
87
+ opts = parse_query_and_convenience_headers path, options.dup
88
+ auto_paginate = opts[:params].delete(:auto_paginate) { |k| @auto_paginate }
89
+ @last_response = request :get, opts
90
+ data = @last_response.body
91
+ raise TrackerApi::Errors::UnexpectedData, 'Array expected' unless data.is_a? Array
92
+
93
+ if auto_paginate
94
+ pager = Pagination.new @last_response.headers
95
+
96
+ while pager.more?
97
+ opts[:params].update(pager.next_page_params)
98
+
99
+ @last_response = request :get, opts
100
+ pager = Pagination.new @last_response.headers
101
+ if block_given?
102
+ yield(data, @last_response)
103
+ else
104
+ data.concat(@last_response.body) if @last_response.body.is_a?(Array)
105
+ end
106
+ end
107
+ end
108
+
109
+ data
110
+ end
111
+
112
+ # Get projects
113
+ #
114
+ # @param [Hash] params
115
+ # @return [Array[TrackerApi::Resources::Project]]
116
+ def projects(params={})
117
+ Endpoints::Projects.new(self).get(params)
118
+ end
119
+
120
+ # Get project
121
+ #
122
+ # @param [Hash] params
123
+ # @return [TrackerApi::Resources::Project]
124
+ def project(id, params={})
125
+ Endpoints::Project.new(self).get(id, params)
126
+ end
127
+
128
+ # Get information about the authenticated user
129
+ #
130
+ # @return [TrackerApi::Resources::Me]
131
+ def me
132
+ Endpoints::Me.new(self).get
133
+ end
134
+
135
+ # Get information about a client story without knowing what project the story belongs to
136
+ #
137
+ # @param [String] story_id
138
+ # @return [TrackerApi::Resources::Story]
139
+ def story(story_id)
140
+ Endpoints::Story.new(self).get_story(story_id)
141
+ end
142
+
143
+ # Get notifications for the authenticated person
144
+ #
145
+ # @param [Hash] params
146
+ # @return [Array[TrackerApi::Resources::Notification]]
147
+ def notifications(params={})
148
+ Endpoints::Notifications.new(self).get(params)
149
+ end
150
+
151
+ # Provides a list of all the activity performed the authenticated person.
152
+ #
153
+ # @param [Hash] params
154
+ # @return [Array[TrackerApi::Resources::Activity]]
155
+ def activity(params={})
156
+ Endpoints::Activity.new(self).get(params)
157
+ end
158
+
159
+ private
160
+
161
+ def parse_query_and_convenience_headers(path, options)
162
+ raise 'Path can not be blank.' if path.to_s.empty?
163
+
164
+ opts = { body: options[:body] }
165
+
166
+ opts[:url] = options[:url] || File.join(@url, @api_version, path.to_s)
167
+ opts[:method] = options[:method] || :get
168
+ opts[:params] = options[:params] || {}
169
+ opts[:token] = options[:token] || @token
170
+ headers = { 'User-Agent' => USER_AGENT,
171
+ 'X-TrackerToken' => opts.fetch(:token) }.merge(options.fetch(:headers, {}))
172
+
173
+ CONVENIENCE_HEADERS.each do |h|
174
+ if header = options[h]
175
+ headers[h] = header
176
+ end
177
+ end
178
+ opts[:headers] = headers
179
+
180
+ opts
181
+ end
182
+
183
+ def request(method, options = {})
184
+ url = options.fetch(:url)
185
+ params = options[:params] || {}
186
+ body = options[:body]
187
+ headers = options[:headers]
188
+
189
+ if (method == :post || method == :put) && options[:body].nil?
190
+ body = params.to_json
191
+ headers['Content-Type'] = 'application/json'
192
+
193
+ params = {}
194
+ end
195
+
196
+ @last_response = response = connection.send(method) do |req|
197
+ req.url(url)
198
+ req.headers.merge!(headers)
199
+ req.params.merge!(params)
200
+ req.body = body
201
+ end
202
+ response
203
+ rescue Faraday::Error::ClientError => e
204
+ raise TrackerApi::Error.new(e)
205
+ end
206
+
207
+ class Pagination
208
+ attr_accessor :headers, :total, :limit, :offset, :returned
209
+
210
+ def initialize(headers)
211
+ @headers = headers
212
+ @total = headers['x-tracker-pagination-total'].to_i
213
+ @limit = headers['x-tracker-pagination-limit'].to_i
214
+ @offset = headers['x-tracker-pagination-offset'].to_i
215
+ @returned = headers['x-tracker-pagination-returned'].to_i
216
+
217
+ # if offset is negative (e.g. Iterations Endpoint).
218
+ # For the 'Done' scope, negative numbers can be passed, which
219
+ # specifies the number of iterations preceding the 'Current' iteration.
220
+ # then need to adjust the negative offset to account for a smaller total,
221
+ # and set total to zero since we are paginating from -X to 0.
222
+ if @offset < 0
223
+ @offset = -@total if @offset.abs > @total
224
+ @total = 0
225
+ end
226
+ end
227
+
228
+ def more?
229
+ (offset + limit) < total
230
+ end
231
+
232
+ def next_offset
233
+ offset + limit
234
+ end
235
+
236
+ def next_page_params
237
+ { limit: limit, offset: next_offset }
238
+ end
239
+ end
240
+ end
241
+ end
@@ -0,0 +1,38 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Activity
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get(params={})
11
+ data = client.paginate("/my/activity", params: params)
12
+ raise TrackerApi::Errors::UnexpectedData, 'Array of activities expected' unless data.is_a? Array
13
+
14
+ data.map do |activity|
15
+ Resources::Activity.new({ client: client }.merge(activity))
16
+ end
17
+ end
18
+
19
+ def get_project(project_id, params={})
20
+ data = client.paginate("/projects/#{project_id}/activity", params: params)
21
+ raise TrackerApi::Errors::UnexpectedData, 'Array of activities expected' unless data.is_a? Array
22
+
23
+ data.map do |activity|
24
+ Resources::Activity.new({ client: client }.merge(activity))
25
+ end
26
+ end
27
+
28
+ def get_story(project_id, story_id, params={})
29
+ data = client.paginate("/projects/#{project_id}/stories/#{story_id}/activity", params: params)
30
+ raise TrackerApi::Errors::UnexpectedData, 'Array of activities expected' unless data.is_a? Array
31
+
32
+ data.map do |activity|
33
+ Resources::Activity.new({ client: client }.merge(activity))
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,27 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Comments
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get(project_id, story_id, params = {})
11
+ data = client.paginate("/projects/#{project_id}/stories/#{story_id}/comments", params: params)
12
+ raise TrackerApi::Errors::UnexpectedData, 'Array of comments expected' unless data.is_a? Array
13
+
14
+ data.map do |comment|
15
+ Resources::Comment.new({ story_id: story_id }.merge(comment))
16
+ end
17
+ end
18
+
19
+ def create_with_attachment(project_id, story_id, text, file_attachment)
20
+ comment = {:text => text, :file_attachments => [file_attachment.attributes]}
21
+ data = client.post("/projects/#{project_id}/stories/#{story_id}/comments", params: comment).body
22
+
23
+ Resources::Comment.new({ client: client }.merge(data))
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Epic
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get(project_id, id)
11
+ data = client.get("/projects/#{project_id}/epics/#{id}").body
12
+
13
+ Resources::Epic.new({ project_id: project_id }.merge(data))
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Epics
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get(project_id, params={})
11
+ data = client.paginate("/projects/#{project_id}/epics", params: params)
12
+ raise TrackerApi::Errors::UnexpectedData, 'Array of epics expected' unless data.is_a? Array
13
+
14
+ data.map do |epic|
15
+ Resources::Epic.new({ project_id: project_id }.merge(epic))
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class FileAttachment
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def create(project_id, file_name, content_type)
11
+ body = {file: Faraday::UploadIO.new(file_name, content_type)}
12
+ data = client.post("/projects/#{project_id}/uploads", body: body).body
13
+ Resources::FileAttachment.new({ client: client }.merge(data))
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Iterations
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get(project_id, params={})
11
+ data = client.paginate("/projects/#{project_id}/iterations", params: params)
12
+ raise TrackerApi::Errors::UnexpectedData, 'Array of iterations expected' unless data.is_a? Array
13
+
14
+ data.map do |iteration|
15
+ Resources::Iteration.new({ client: client, project_id: project_id }.merge(iteration))
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Me
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get
11
+ data = client.get("/me").body
12
+
13
+ Resources::Me.new(data)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Memberships
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get(project_id, params={})
11
+ data = client.paginate("/projects/#{project_id}/memberships", params: params)
12
+ raise TrackerApi::Errors::UnexpectedData, 'Array of memberships expected' unless data.is_a? Array
13
+
14
+ data.map do |membership|
15
+ Resources::ProjectMembership.new({ project_id: project_id }.merge(membership))
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Notifications
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get(params={})
11
+ data = client.paginate('/my/notifications', params: params)
12
+ raise TrackerApi::Errors::UnexpectedData, 'Array of notifications expected' unless data.is_a? Array
13
+
14
+ data.map do |notification|
15
+ Resources::Notification.new({ client: client }.merge(notification))
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Project
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get(id, params={})
11
+ data = client.get("/projects/#{id}", params: params).body
12
+
13
+ Resources::Project.new({ client: client }.merge(data))
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Projects
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get(params={})
11
+ data = client.paginate('/projects', params: params)
12
+ raise TrackerApi::Errors::UnexpectedData, 'Array of projects expected' unless data.is_a? Array
13
+
14
+ data.map { |project| Resources::Project.new({ client: client }.merge(project)) }
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Stories
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get(project_id, params={})
11
+ data = client.paginate("/projects/#{project_id}/stories", params: params)
12
+ raise TrackerApi::Errors::UnexpectedData, 'Array of stories expected' unless data.is_a? Array
13
+
14
+ data.map do |story|
15
+ Resources::Story.new({ client: client, project_id: project_id }.merge(story))
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,37 @@
1
+ module TrackerApi
2
+ module Endpoints
3
+ class Story
4
+ attr_accessor :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get(project_id, id)
11
+ data = client.get("/projects/#{project_id}/stories/#{id}").body
12
+
13
+ Resources::Story.new({ client: client, project_id: project_id }.merge(data))
14
+ end
15
+
16
+ def get_story(story_id)
17
+ data = client.get("/stories/#{story_id}").body
18
+
19
+ Resources::Story.new({ client: client }.merge(data))
20
+ end
21
+
22
+ def create(project_id, params={})
23
+ data = client.post("/projects/#{project_id}/stories", params: params).body
24
+
25
+ Resources::Story.new({ client: client }.merge(data))
26
+ end
27
+
28
+ def update(story, params={})
29
+ raise ArgumentError, 'Valid story required to update.' unless story.instance_of?(Resources::Story)
30
+
31
+ data = client.put("/projects/#{story.project_id}/stories/#{story.id}", params: params).body
32
+
33
+ story.attributes = data
34
+ end
35
+ end
36
+ end
37
+ end