semaphore_client 2.3.1 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,101 +5,71 @@ class SemaphoreClient
5
5
  @http_client = http_client
6
6
  end
7
7
 
8
- def list_for_org(org_id, query = nil)
9
- list_for_org!(org_id, query)
10
- rescue SemaphoreClient::Exceptions::RequestFailed
11
- end
12
8
 
13
- def list_for_team(team_id, query = nil)
14
- list_for_team!(team_id, query)
15
- rescue SemaphoreClient::Exceptions::RequestFailed
9
+ def list_for_org(org_id, params = nil, options = {})
10
+ list_for_org!(org_id, params, options)
11
+ rescue SemaphoreClient::Exceptions::ResponseError
16
12
  end
17
13
 
18
- def attach_to_team(user_id, team_id)
19
- attach_to_team!(user_id, team_id)
20
- rescue SemaphoreClient::Exceptions::RequestFailed
21
- end
14
+ def list_for_org!(org_id, params = nil, options = {})
15
+ path = "/orgs/#{org_id}/users"
22
16
 
23
- def detach_from_team(user_id, team_id)
24
- detach_from_team!(user_id, team_id)
25
- rescue SemaphoreClient::Exceptions::RequestFailed
17
+ @http_client.get(path, params, options = {}).body.map { |e| SemaphoreClient::Model::User.load(e) }
26
18
  end
27
19
 
28
- def list_for_project(project_id, query = nil)
29
- list_for_project!(project_id, query)
30
- rescue SemaphoreClient::Exceptions::RequestFailed
31
- end
32
20
 
33
- def list_for_org!(org_id, query = nil)
34
- query_string =
35
- unless query.nil? || query.empty?
36
- "?" + query.map { |key, value| "#{key}=#{value}" }.join("&")
37
- end
38
21
 
39
- response = @http_client.get([:orgs, org_id, :users, query_string].compact)
40
-
41
- assert_response_status(response, 200)
22
+ def list_for_team(team_id, params = nil, options = {})
23
+ list_for_team!(team_id, params, options)
24
+ rescue SemaphoreClient::Exceptions::ResponseError
25
+ end
42
26
 
43
- content = JSON.parse(response.body)
27
+ def list_for_team!(team_id, params = nil, options = {})
28
+ path = "/teams/#{team_id}/users"
44
29
 
45
- content.map do |entity|
46
- SemaphoreClient::Model::User.load(entity)
47
- end
30
+ @http_client.get(path, params, options = {}).body.map { |e| SemaphoreClient::Model::User.load(e) }
48
31
  end
49
32
 
50
- def list_for_team!(team_id, query = nil)
51
- query_string =
52
- unless query.nil? || query.empty?
53
- "?" + query.map { |key, value| "#{key}=#{value}" }.join("&")
54
- end
55
33
 
56
- response = @http_client.get([:teams, team_id, :users, query_string].compact)
57
34
 
58
- assert_response_status(response, 200)
35
+ def attach_to_team(user_id, team_id, params = nil, options = {})
36
+ attach_to_team!(user_id, team_id, params, options)
37
+ rescue SemaphoreClient::Exceptions::ResponseError
38
+ end
59
39
 
60
- content = JSON.parse(response.body)
40
+ def attach_to_team!(user_id, team_id, params = nil, options = {})
41
+ path = "/teams/#{team_id}/users/#{user_id}"
61
42
 
62
- content.map do |entity|
63
- SemaphoreClient::Model::User.load(entity)
64
- end
43
+ @http_client.post(path, params, options)
65
44
  end
66
45
 
67
- def attach_to_team!(user_id, team_id)
68
- response = @http_client.post([:teams, team_id, :users, user_id])
69
46
 
70
- assert_response_status(response, 204)
47
+
48
+ def detach_from_team(user_id, team_id, params = nil, options = {})
49
+ detach_from_team!(user_id, team_id, params, options)
50
+ rescue SemaphoreClient::Exceptions::ResponseError
71
51
  end
72
52
 
73
- def detach_from_team!(user_id, team_id)
74
- response = @http_client.delete([:teams, team_id, :users, user_id])
53
+ def detach_from_team!(user_id, team_id, params = nil, options = {})
54
+ path = "/teams/#{team_id}/users/#{user_id}"
75
55
 
76
- assert_response_status(response, 204)
56
+ @http_client.delete(path, params, options)
77
57
  end
78
58
 
79
- def list_for_project!(project_id, query = nil)
80
- query_string =
81
- unless query.nil? || query.empty?
82
- "?" + query.map { |key, value| "#{key}=#{value}" }.join("&")
83
- end
84
59
 
85
- response = @http_client.get([:projects, project_id, :users, query_string].compact)
86
60
 
87
- assert_response_status(response, 200)
61
+ def list_for_project(project_id, params = nil, options = {})
62
+ list_for_project!(project_id, params, options)
63
+ rescue SemaphoreClient::Exceptions::ResponseError
64
+ end
88
65
 
89
- content = JSON.parse(response.body)
66
+ def list_for_project!(project_id, params = nil, options = {})
67
+ path = "/projects/#{project_id}/users"
90
68
 
91
- content.map do |entity|
92
- SemaphoreClient::Model::User.load(entity)
93
- end
69
+ @http_client.get(path, params, options = {}).body.map { |e| SemaphoreClient::Model::User.load(e) }
94
70
  end
95
71
 
96
- private
97
72
 
98
- def assert_response_status(response, expected_status)
99
- return if response.status == expected_status
100
-
101
- raise SemaphoreClient::Exceptions::RequestFailed, response.status
102
- end
103
73
  end
104
74
  end
105
75
  end
@@ -1,6 +1,38 @@
1
1
  class SemaphoreClient
2
2
  class Exceptions
3
- class AttributeNotAvailable < StandardError; end
4
- class RequestFailed < StandardError; end
3
+ class Base < StandardError; end
4
+
5
+ class AttributeNotAvailable < Base; end
6
+
7
+ class ResponseError < Base
8
+ attr_reader :env
9
+
10
+ def initialize(env)
11
+ @env = env
12
+
13
+ super(env[:message])
14
+ end
15
+ end
16
+
17
+ # 400
18
+ class BadRequest < ResponseError; end
19
+
20
+ # 401
21
+ class Unauthorized < ResponseError; end
22
+
23
+ # 404
24
+ class NotFound < ResponseError; end
25
+
26
+ # 405
27
+ class NotAllowed < ResponseError; end
28
+
29
+ # 409
30
+ class Conflict < ResponseError; end
31
+
32
+ # 422
33
+ class UnprocessableEntity < ResponseError; end
34
+
35
+ # 500+
36
+ class ServerError < ResponseError; end
5
37
  end
6
38
  end
@@ -1,87 +1,107 @@
1
1
  class SemaphoreClient
2
+
2
3
  class HttpClient
3
- class RouteNotSupported < StandardError; end
4
4
 
5
- def initialize(auth_token, api_url, api_version, verbose, logger)
5
+ class ResponseErrorMiddleware < Faraday::Middleware
6
+ def call(env)
7
+ @app.call(env).on_complete do |env|
8
+ case env[:status]
9
+ when 401
10
+ raise SemaphoreClient::Exceptions::Unauthorized, env
11
+ when 404
12
+ raise SemaphoreClient::Exceptions::NotFound, env
13
+ when 405
14
+ raise SemaphoreClient::Exceptions::NotAllowed, env
15
+ when 409
16
+ raise SemaphoreClient::Exceptions::Conflict, env
17
+ when 422
18
+ raise SemaphoreClient::Exceptions::UnprocessableEntity, env
19
+ when 400...500
20
+ raise SemaphoreClient::Exceptions::BadRequest, env
21
+ when 500...600
22
+ raise SemaphoreClient::Exceptions::ServerError, env
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ def initialize(auth_token, api_url, api_version, verbose, logger, auto_paginate)
6
29
  @auth_token = auth_token
7
30
  @api_url = api_url
8
31
  @api_version = api_version
9
32
  @verbose = verbose
10
33
  @logger = logger
34
+ @auto_paginate = auto_paginate
11
35
  end
12
36
 
13
- def get(route_elements)
14
- route = route(route_elements)
37
+ def get(path, params = nil, options = {})
38
+ api_call(:get, path, params, options)
39
+ end
15
40
 
16
- trace("GET", route) do
17
- connection.get(route)
18
- end
41
+ def post(path, params = nil, options = {})
42
+ api_call(:post, path, params, options)
19
43
  end
20
44
 
21
- def post(route_elements, content = nil)
22
- route = route(route_elements)
45
+ def patch(path, params = nil, options = {})
46
+ api_call(:patch, path, params, options)
47
+ end
23
48
 
24
- if content
25
- trace("POST", route, content) do
26
- connection.post(route, content)
27
- end
28
- else
29
- trace("POST", route) do
30
- connection.post(route)
31
- end
32
- end
49
+ def delete(path, params = nil, options = {})
50
+ api_call(:delete, path, params, options)
33
51
  end
34
52
 
35
- def patch(route_elements, content = nil)
36
- route = route(route_elements)
53
+ private
37
54
 
38
- if content
39
- trace("PATCH", route, content) do
40
- connection.patch(route, content)
41
- end
42
- else
43
- trace("PATCH", route) do
44
- connection.patch(route)
55
+ def api_call(method, path, params = nil, options = {})
56
+ response = connection.public_send(method, "/#{@api_version}/#{path}", params)
57
+
58
+ if auto_paginate?(options)
59
+ links = parse_links(response)
60
+
61
+ if links[:next]
62
+ # recursivly follow the :next link
63
+ next_response = api_call(method, links[:next], params, options)
64
+
65
+ # append the rest to the body of the original request
66
+ response.body.concat(next_response.body)
45
67
  end
46
68
  end
69
+
70
+ response
47
71
  end
48
72
 
49
- def delete(route_elements)
50
- route = route(route_elements)
73
+ def auto_paginate?(options)
74
+ # first check the options, then the global settings
75
+ options.key?(:auto_paginate) ? options[:auto_paginate] : @auto_paginate
76
+ end
51
77
 
52
- trace("DELETE", route) do
53
- connection.delete(route)
78
+ def parse_links(response)
79
+ links = ( response.headers["Link"] || "" ).split(', ').map do |link|
80
+ href, name = link.match(/<(.*?)>; rel="(\w+)"/).captures
81
+
82
+ [name.to_sym, href.gsub("#{@api_url}/v2", "")]
54
83
  end
55
- end
56
84
 
57
- private
85
+ Hash[*links.flatten]
86
+ end
58
87
 
59
- def trace(method, path, content = nil)
60
- if @verbose == true
61
- id = SecureRandom.hex
62
- started_at = Time.now.to_f
88
+ def connection
89
+ @connection ||= Faraday.new(:url => @api_url, :headers => headers) do |conn|
90
+ conn.request :json
91
+ conn.response :json
63
92
 
64
- @logger.info "#{id} #{method} #{path} body: #{content.inspect}"
65
- response = yield
93
+ if @verbose
94
+ conn.response :logger, @logger, :headers => false, :bodies => true
95
+ end
66
96
 
67
- finished_at = Time.now.to_f
68
- @logger.info "#{id} #{response.status} duration: #{finished_at - started_at}s body: #{response.body}"
97
+ conn.use SemaphoreClient::HttpClient::ResponseErrorMiddleware
69
98
 
70
- response
71
- else
72
- yield
99
+ conn.adapter Faraday.default_adapter
73
100
  end
74
101
  end
75
102
 
76
- def route(route_elements)
77
- ["", @api_version, *route_elements].compact.join("/")
78
- end
79
-
80
- def connection
81
- @connection ||= Faraday.new(
82
- :url => @api_url,
83
- :headers => { "Authorization" => "Token #{@auth_token}" }
84
- )
103
+ def headers
104
+ { "Authorization" => "Token #{@auth_token}" }
85
105
  end
86
106
  end
87
107
  end
@@ -1,3 +1,3 @@
1
1
  class SemaphoreClient
2
- VERSION = "2.3.1"
2
+ VERSION = "2.4.0"
3
3
  end
@@ -20,7 +20,9 @@ Gem::Specification.new do |spec|
20
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ["lib"]
22
22
 
23
- spec.add_dependency "faraday"
23
+ spec.add_dependency "faraday", "~> 0.13.1"
24
+ spec.add_dependency "faraday_middleware", "~> 0.12.2"
25
+
24
26
  spec.add_development_dependency "byebug"
25
27
  spec.add_development_dependency "bundler", "~> 1.14"
26
28
  spec.add_development_dependency "rake", "~> 10.0"
metadata CHANGED
@@ -1,29 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: semaphore_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.1
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jovan Ivanović
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-09-25 00:00:00.000000000 Z
11
+ date: 2017-09-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: 0.13.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: 0.13.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday_middleware
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.12.2
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.12.2
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: byebug
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -137,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
151
  version: '0'
138
152
  requirements: []
139
153
  rubyforge_project:
140
- rubygems_version: 2.4.8
154
+ rubygems_version: 2.6.13
141
155
  signing_key:
142
156
  specification_version: 4
143
157
  summary: Client for Semaphore's API.