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