semaphore_client 2.3.1 → 2.4.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.
@@ -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.