v2gpti 1.1.9 → 1.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.
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