v2gpti 1.1.9 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/git-deliver +1 -1
- data/bin/git-finish +1 -1
- data/bin/git-newbug +1 -1
- data/bin/git-newfeature +1 -1
- data/bin/git-qa +1 -1
- data/bin/git-release +1 -1
- data/bin/git-report +1 -1
- data/bin/git-start +1 -1
- data/bin/git-uat +1 -1
- data/config_template +16 -0
- data/lib/git-pivotal-tracker-integration/command/base.rb +235 -322
- data/lib/git-pivotal-tracker-integration/command/configuration.rb +183 -109
- data/lib/git-pivotal-tracker-integration/command/deliver.rb +145 -200
- data/lib/git-pivotal-tracker-integration/command/finish.rb +70 -63
- data/lib/git-pivotal-tracker-integration/command/newbug.rb +36 -39
- data/lib/git-pivotal-tracker-integration/command/newfeature.rb +43 -42
- data/lib/git-pivotal-tracker-integration/command/release.rb +171 -203
- data/lib/git-pivotal-tracker-integration/command/report.rb +33 -36
- data/lib/git-pivotal-tracker-integration/command/start.rb +74 -78
- data/lib/git-pivotal-tracker-integration/util/git.rb +202 -204
- data/lib/git-pivotal-tracker-integration/util/shell.rb +19 -16
- data/lib/git-pivotal-tracker-integration/util/story.rb +155 -177
- data/lib/git-pivotal-tracker-integration/version-update/gradle.rb +44 -40
- data/lib/git-pivotal-tracker-integration.rb +44 -0
- data/spec/git-pivotal-tracker-integration/command/configuration_spec.rb +1 -2
- data/spec/git-pivotal-tracker-integration/command/finish_spec.rb +1 -1
- data/spec/git-pivotal-tracker-integration/command/release_spec.rb +1 -1
- data/spec/git-pivotal-tracker-integration/command/start_spec.rb +1 -1
- data/spec/git-pivotal-tracker-integration/util/story_spec.rb +21 -32
- data/tracker_api/lib/tracker_api/client.rb +241 -0
- data/tracker_api/lib/tracker_api/endpoints/activity.rb +38 -0
- data/tracker_api/lib/tracker_api/endpoints/comments.rb +27 -0
- data/tracker_api/lib/tracker_api/endpoints/epic.rb +17 -0
- data/tracker_api/lib/tracker_api/endpoints/epics.rb +20 -0
- data/tracker_api/lib/tracker_api/endpoints/file_attachment.rb +18 -0
- data/tracker_api/lib/tracker_api/endpoints/iterations.rb +20 -0
- data/tracker_api/lib/tracker_api/endpoints/me.rb +17 -0
- data/tracker_api/lib/tracker_api/endpoints/memberships.rb +20 -0
- data/tracker_api/lib/tracker_api/endpoints/notifications.rb +20 -0
- data/tracker_api/lib/tracker_api/endpoints/project.rb +17 -0
- data/tracker_api/lib/tracker_api/endpoints/projects.rb +18 -0
- data/tracker_api/lib/tracker_api/endpoints/stories.rb +20 -0
- data/tracker_api/lib/tracker_api/endpoints/story.rb +37 -0
- data/tracker_api/lib/tracker_api/endpoints/tasks.rb +20 -0
- data/tracker_api/lib/tracker_api/error.rb +18 -0
- data/tracker_api/lib/tracker_api/logger.rb +31 -0
- data/tracker_api/lib/tracker_api/resources/account.rb +18 -0
- data/tracker_api/lib/tracker_api/resources/activity.rb +24 -0
- data/tracker_api/lib/tracker_api/resources/base.rb +71 -0
- data/tracker_api/lib/tracker_api/resources/change.rb +15 -0
- data/tracker_api/lib/tracker_api/resources/comment.rb +20 -0
- data/tracker_api/lib/tracker_api/resources/epic.rb +17 -0
- data/tracker_api/lib/tracker_api/resources/file_attachment.rb +23 -0
- data/tracker_api/lib/tracker_api/resources/iteration.rb +24 -0
- data/tracker_api/lib/tracker_api/resources/label.rb +14 -0
- data/tracker_api/lib/tracker_api/resources/me.rb +21 -0
- data/tracker_api/lib/tracker_api/resources/membership_summary.rb +15 -0
- data/tracker_api/lib/tracker_api/resources/notification.rb +26 -0
- data/tracker_api/lib/tracker_api/resources/person.rb +14 -0
- data/tracker_api/lib/tracker_api/resources/primary_resource.rb +13 -0
- data/tracker_api/lib/tracker_api/resources/project.rb +131 -0
- data/tracker_api/lib/tracker_api/resources/project_membership.rb +16 -0
- data/tracker_api/lib/tracker_api/resources/story.rb +102 -0
- data/tracker_api/lib/tracker_api/resources/task.rb +16 -0
- data/tracker_api/lib/tracker_api/resources/time_zone.rb +13 -0
- data/tracker_api/lib/tracker_api/version.rb +3 -0
- data/tracker_api/lib/tracker_api.rb +60 -0
- metadata +202 -53
- data/lib/git-pivotal-tracker-integration/command/command.rb +0 -20
- data/lib/git-pivotal-tracker-integration/util/util.rb +0 -20
- data/lib/git-pivotal-tracker-integration/version-update/version_update.rb +0 -20
- 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 '
|
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
|
-
|
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
|
-
|
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
|
-
|
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(:
|
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(@
|
87
|
-
@
|
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
|
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(
|
106
|
-
|
107
|
-
:
|
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(
|
126
|
-
|
127
|
-
:
|
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,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
|