percy-client 1.12.0 → 1.13.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8556dfa5a032fd21caa62af7e38c2b93ce945a40
4
- data.tar.gz: 0d176888922bc1309e4bdd217b34e6c6835356a0
3
+ metadata.gz: b94954861b98e83a57b9320d28682b66a66e49ee
4
+ data.tar.gz: b6b9a044bab771d3f3fa37ab4922a865c3cc465a
5
5
  SHA512:
6
- metadata.gz: 22b2d8ef3a9d9c79f106687ef66c4fb893354512598448c3c36cc193205f8d1746d1902b998a8a8ea90d73f6cfdc1b2edb09ac6a4ce9bab7e11ec288eacaefa1
7
- data.tar.gz: 0ce75d192a413664ff2c032c326f688b17748b8cd30cac51746620b5081aedf5271d89ad73da6c02ef66f611602b7faab090e80e51d2426edf1032e8d7816b03
6
+ metadata.gz: 9c70290afed751c1612eb3dec8024511c4bc5cb127f3919f84eb1ccec87e30ad2df515153d7c1d0ed4be78423f026ca021847d43bc8a21b20b62f9fa9278573a
7
+ data.tar.gz: 0637dcf07a4c97a5f8904bb4653ce9d6bfac3aa8f576c39a550a35a1cc0fd5716a84d074f62bef4980d67aa13b4b4fe9492dd9ee7fbf7349edd4228ede60c8da
data/Gemfile CHANGED
@@ -5,6 +5,10 @@ gemspec
5
5
 
6
6
  gem 'guard-rspec', require: false
7
7
 
8
+ group :test, :development do
9
+ gem 'pry'
10
+ end
11
+
8
12
  group :test do
9
13
  gem 'rubocop'
10
14
  gem 'rubocop-rspec'
@@ -15,8 +15,15 @@ module Percy
15
15
  # API client based on configured options.
16
16
  #
17
17
  # @return [Percy::Client] API client.
18
- def self.client
19
- @client = Percy::Client.new(config: config) if !defined?(@client) || !@client
18
+ def self.client(options = {})
19
+ if !defined?(@client) || !@client
20
+ @client = Percy::Client.new(
21
+ config: config,
22
+ client_info: options[:client_info],
23
+ environment_info: options[:environment_info],
24
+ )
25
+ end
26
+
20
27
  @client
21
28
  end
22
29
 
@@ -45,10 +45,12 @@ module Percy
45
45
  class BadGatewayError < ServerError; end # 502.
46
46
  class ServiceUnavailableError < ServerError; end # 503.
47
47
 
48
- attr_reader :config
48
+ attr_reader :config, :client_info, :environment_info
49
49
 
50
50
  def initialize(options = {})
51
51
  @config = options[:config] || Percy::Config.new
52
+ @client_info = options[:client_info]
53
+ @environment_info = options[:environment_info]
52
54
  end
53
55
  end
54
56
  end
@@ -14,6 +14,7 @@ module Percy
14
14
  # Only pass parallelism data if it all exists and there is more than 1 shard.
15
15
  in_parallel_environment = parallel_nonce && \
16
16
  parallel_total_shards && parallel_total_shards > 1
17
+
17
18
  unless in_parallel_environment
18
19
  parallel_nonce = nil
19
20
  parallel_total_shards = nil
@@ -44,6 +45,7 @@ module Percy
44
45
  raise ArgumentError,
45
46
  'resources argument must be an iterable of Percy::Client::Resource objects'
46
47
  end
48
+
47
49
  relationships_data = {
48
50
  'relationships' => {
49
51
  'resources' => {
@@ -51,16 +53,19 @@ module Percy
51
53
  },
52
54
  },
53
55
  }
56
+
54
57
  data['data'].merge!(relationships_data)
55
58
  end
56
59
 
57
60
  build_data = post("#{config.api_url}/repos/#{repo}/builds/", data)
58
61
  Percy.logger.debug { "Build #{build_data['data']['id']} created" }
62
+
59
63
  parallelism_msg = if parallel_total_shards
60
64
  "#{parallel_total_shards} shards detected (nonce: #{parallel_nonce.inspect})"
61
65
  else
62
66
  'not detected'
63
67
  end
68
+
64
69
  Percy.logger.debug { "Parallel test environment: #{parallelism_msg}" }
65
70
  build_data
66
71
  end
@@ -20,6 +20,7 @@ module Percy
20
20
 
21
21
  def on_complete(env)
22
22
  error_class = nil
23
+
23
24
  case env[:status]
24
25
  when 400
25
26
  error_class = Percy::Client::BadRequestError
@@ -42,7 +43,9 @@ module Percy
42
43
  when CLIENT_ERROR_STATUS_RANGE # Catchall.
43
44
  error_class = Percy::Client::HttpError
44
45
  end
46
+
45
47
  return unless error_class
48
+
46
49
  raise error_class.new(
47
50
  env.status, env.method.upcase, env.url, env.body,
48
51
  "Got #{env.status} (#{env.method.upcase} #{env.url}):\n#{env.body}",
@@ -52,23 +55,27 @@ module Percy
52
55
 
53
56
  def connection
54
57
  return @connection if defined?(@connection)
58
+
55
59
  parsed_uri = URI.parse(config.api_url)
56
60
  base_url = "#{parsed_uri.scheme}://#{parsed_uri.host}:#{parsed_uri.port}"
61
+
57
62
  @connection = Faraday.new(url: base_url) do |faraday|
58
63
  faraday.request :token_auth, config.access_token if config.access_token
59
64
 
60
65
  faraday.use Percy::Client::Connection::NoCookiesHTTPClientAdapter
61
66
  faraday.use Percy::Client::Connection::NiceErrorMiddleware
62
67
  end
68
+
63
69
  @connection
64
70
  end
65
71
 
66
72
  def get(path, options = {})
67
73
  retries = options[:retries] || 3
74
+
68
75
  begin
69
76
  response = connection.get do |request|
70
77
  request.url(path)
71
- request.headers['Content-Type'] = 'application/vnd.api+json'
78
+ request.headers.merge! _headers
72
79
  end
73
80
  rescue Faraday::TimeoutError
74
81
  raise Percy::Client::TimeoutError
@@ -87,10 +94,11 @@ module Percy
87
94
 
88
95
  def post(path, data, options = {})
89
96
  retries = options[:retries] || 3
97
+
90
98
  begin
91
99
  response = connection.post do |request|
92
100
  request.url(path)
93
- request.headers['Content-Type'] = 'application/vnd.api+json'
101
+ request.headers.merge! _headers
94
102
  request.body = data.to_json
95
103
  end
96
104
  rescue Faraday::TimeoutError
@@ -102,10 +110,49 @@ module Percy
102
110
  sleep(rand(1..3))
103
111
  retry
104
112
  end
113
+
105
114
  raise e
106
115
  end
116
+
107
117
  JSON.parse(response.body)
108
118
  end
119
+
120
+ def _headers
121
+ {
122
+ 'Content-Type' => 'application/vnd.api+json',
123
+ 'User-Agent' => _user_agent,
124
+ }
125
+ end
126
+
127
+ def _user_agent
128
+ @_user_agent ||= begin
129
+ client = [
130
+ "Percy/#{_api_version}",
131
+ client_info,
132
+ "percy-client/#{VERSION}",
133
+ ].compact.join(' ')
134
+
135
+ environment = [
136
+ environment_info,
137
+ "ruby/#{_ruby_version}",
138
+ Percy::Client::Environment.current_ci,
139
+ ].compact.join('; ')
140
+
141
+ "#{client} (#{environment})"
142
+ end
143
+ end
144
+
145
+ def _reset_user_agent
146
+ @_user_agent = nil
147
+ end
148
+
149
+ def _api_version
150
+ config.api_url.match(/\w+$/).to_s
151
+ end
152
+
153
+ def _ruby_version
154
+ "#{RUBY_VERSION}p#{RUBY_PATCHLEVEL}"
155
+ end
109
156
  end
110
157
  end
111
158
  end
@@ -1,5 +1,5 @@
1
1
  module Percy
2
2
  class Client
3
- VERSION = '1.12.0'.freeze
3
+ VERSION = '1.13.0'.freeze
4
4
  end
5
5
  end
@@ -55,6 +55,7 @@ RSpec.describe Percy::Client::Builds, :vcr do
55
55
  expect(build['data']['relationships']['missing-resources']['data']).to be
56
56
  expect(build['data']['relationships']['missing-resources']['data'].length).to eq(1)
57
57
  end
58
+
58
59
  context 'with env vars configured' do
59
60
  before(:each) do
60
61
  ENV['PERCY_BRANCH'] = 'foo-branch'
@@ -1,114 +1,143 @@
1
1
  RSpec.describe Percy::Client::Connection do
2
+ let(:user_agent) do
3
+ "Percy/#{api_version} #{client_info} percy-client/#{Percy::Client::VERSION} "\
4
+ "(#{environment_info}; ruby/#{ruby_version}; #{ci_name})"
5
+ end
6
+ let(:content_type) { 'application/vnd.api+json' }
7
+ let(:api_version) { 'v1' }
8
+ let(:ruby_version) { '2.2.6p396' }
9
+ let(:client_info) { 'percy-capybara/3.1.0' }
10
+ let(:environment_info) { 'Rails/4.2.1' }
11
+ let(:ci_name) { 'buildkite' }
12
+ let(:uri) { "#{Percy.config.api_url}/test" }
13
+
2
14
  describe '#connection' do
3
15
  it 'disables cookies on faraday httpclient adapter' do
4
16
  expect(Percy.client.connection.builder.app.client.cookie_manager).to be_nil
5
17
  end
6
18
  end
19
+
20
+ shared_examples_for 'a connection that sets headers with HTTP method' do |http_method|
21
+ it 'sets headers' do
22
+ stub_request(http_method, uri)
23
+ .with(headers: {'User-Agent' => user_agent, 'Content-Type' => content_type})
24
+ .to_return(body: {foo: true}.to_json)
25
+
26
+ expect(Percy.client).to receive(:_api_version).and_return(api_version)
27
+ expect(Percy.client).to receive(:_ruby_version).and_return(ruby_version)
28
+
29
+ expect(Percy.client).to receive(:client_info).and_return(client_info)
30
+ expect(Percy.client).to receive(:environment_info).and_return(environment_info)
31
+
32
+ expect(Percy::Client::Environment).to receive(:current_ci).and_return(ci_name)
33
+
34
+ expect(response).to eq('foo' => true)
35
+ end
36
+ end
37
+
7
38
  describe '#get' do
39
+ subject(:response) { Percy.client.get(uri) }
40
+
41
+ it_behaves_like 'a connection that sets headers with HTTP method', :get
42
+
8
43
  it 'performs a GET request to the api_url and parses response' do
9
- stub_request(:get, "#{Percy.config.api_url}/test").to_return(body: {foo: true}.to_json)
10
- data = Percy.client.get("#{Percy.config.api_url}/test")
11
- expect(data).to eq('foo' => true)
44
+ stub_request(:get, uri).to_return(body: {foo: true}.to_json)
45
+ expect(response).to eq('foo' => true)
12
46
  end
47
+
13
48
  it 'raises customized timeout errors' do
14
- stub_request(:get, "#{Percy.config.api_url}/test").to_raise(Faraday::TimeoutError)
15
- expect do
16
- Percy.client.get("#{Percy.config.api_url}/test")
17
- end.to raise_error(Percy::Client::TimeoutError)
49
+ stub_request(:get, uri).to_raise(Faraday::TimeoutError)
50
+ expect { response }.to raise_error(Percy::Client::TimeoutError)
18
51
  end
52
+
19
53
  it 'raises customized connection failed errors' do
20
- stub_request(:get, "#{Percy.config.api_url}/test").to_raise(Faraday::ConnectionFailed)
21
- expect do
22
- Percy.client.get("#{Percy.config.api_url}/test")
23
- end.to raise_error(Percy::Client::ConnectionFailed)
54
+ stub_request(:get, uri).to_raise(Faraday::ConnectionFailed)
55
+ expect { response }.to raise_error(Percy::Client::ConnectionFailed)
24
56
  end
57
+
25
58
  it 'retries on 502 errors' do
26
- stub_request(:get, "#{Percy.config.api_url}/test")
59
+ stub_request(:get, uri)
27
60
  .to_return(body: {foo: true}.to_json, status: 502)
28
61
  .then.to_return(body: {foo: true}.to_json, status: 200)
29
62
 
30
- data = Percy.client.get("#{Percy.config.api_url}/test")
31
- expect(data).to eq('foo' => true)
63
+ expect(response).to eq('foo' => true)
32
64
  end
65
+
33
66
  it 'raises error after 3 retries' do
34
- stub_request(:get, "#{Percy.config.api_url}/test")
67
+ stub_request(:get, uri)
35
68
  .to_return(body: {foo: true}.to_json, status: 502).times(3)
36
- expect do
37
- Percy.client.get("#{Percy.config.api_url}/test")
38
- end.to raise_error(Percy::Client::BadGatewayError)
69
+
70
+ expect { response }.to raise_error(Percy::Client::BadGatewayError)
39
71
  end
40
72
  end
73
+
41
74
  describe '#post' do
75
+ subject(:response) { Percy.client.post(uri, {}) }
76
+
77
+ it_behaves_like 'a connection that sets headers with HTTP method', :post
78
+
42
79
  it 'performs a POST request to the api_url and parses response' do
43
- stub_request(:post, "#{Percy.config.api_url}/test").to_return(body: {foo: true}.to_json)
44
- data = Percy.client.post("#{Percy.config.api_url}/test", {})
45
- expect(data).to eq('foo' => true)
80
+ stub_request(:post, uri).to_return(body: {foo: true}.to_json)
81
+ expect(response).to eq('foo' => true)
82
+ end
83
+
84
+ it 'passes through arguments' do
85
+ stub_request(:post, uri)
86
+ .with(headers: {'User-Agent' => user_agent, 'Content-Type' => content_type})
87
+ .to_return(body: {foo: true}.to_json)
88
+
89
+ expect(Percy.client).to receive(:_user_agent).and_return(user_agent)
90
+ expect(response).to eq('foo' => true)
46
91
  end
92
+
47
93
  it 'raises customized timeout errors' do
48
- stub_request(:post, "#{Percy.config.api_url}/test").to_raise(Faraday::TimeoutError)
49
- expect do
50
- Percy.client.post("#{Percy.config.api_url}/test", {})
51
- end.to raise_error(Percy::Client::TimeoutError)
94
+ stub_request(:post, uri).to_raise(Faraday::TimeoutError)
95
+ expect { response }.to raise_error(Percy::Client::TimeoutError)
52
96
  end
97
+
53
98
  it 'raises customized connection failed errors' do
54
- stub_request(:post, "#{Percy.config.api_url}/test").to_raise(Faraday::ConnectionFailed)
55
- expect do
56
- Percy.client.post("#{Percy.config.api_url}/test", {})
57
- end.to raise_error(Percy::Client::ConnectionFailed)
99
+ stub_request(:post, uri).to_raise(Faraday::ConnectionFailed)
100
+ expect { response }.to raise_error(Percy::Client::ConnectionFailed)
58
101
  end
59
- it 'raises custom error classes for some HTTP errors' do
60
- stub_request(:post, "#{Percy.config.api_url}/test")
61
- .to_return(body: {foo: true}.to_json, status: 400)
62
- .then.to_return(body: {foo: true}.to_json, status: 401)
63
- .then.to_return(body: {foo: true}.to_json, status: 402)
64
- .then.to_return(body: {foo: true}.to_json, status: 403)
65
- .then.to_return(body: {foo: true}.to_json, status: 404)
66
- .then.to_return(body: {foo: true}.to_json, status: 409)
67
- .then.to_return(body: {foo: true}.to_json, status: 500)
68
- .then.to_return(body: {foo: true}.to_json, status: 502)
69
- .then.to_return(body: {foo: true}.to_json, status: 503)
70
- expect do
71
- Percy.client.post("#{Percy.config.api_url}/test", {}, retries: 0)
72
- end.to raise_error(Percy::Client::BadRequestError)
73
- expect do
74
- Percy.client.post("#{Percy.config.api_url}/test", {}, retries: 0)
75
- end.to raise_error(Percy::Client::UnauthorizedError)
76
- expect do
77
- Percy.client.post("#{Percy.config.api_url}/test", {}, retries: 0)
78
- end.to raise_error(Percy::Client::PaymentRequiredError)
79
- expect do
80
- Percy.client.post("#{Percy.config.api_url}/test", {}, retries: 0)
81
- end.to raise_error(Percy::Client::ForbiddenError)
82
- expect do
83
- Percy.client.post("#{Percy.config.api_url}/test", {}, retries: 0)
84
- end.to raise_error(Percy::Client::NotFoundError)
85
- expect do
86
- Percy.client.post("#{Percy.config.api_url}/test", {}, retries: 0)
87
- end.to raise_error(Percy::Client::ConflictError)
88
- expect do
89
- Percy.client.post("#{Percy.config.api_url}/test", {}, retries: 0)
90
- end.to raise_error(Percy::Client::InternalServerError)
91
- expect do
92
- Percy.client.post("#{Percy.config.api_url}/test", {}, retries: 0)
93
- end.to raise_error(Percy::Client::BadGatewayError)
94
- expect do
95
- Percy.client.post("#{Percy.config.api_url}/test", {}, retries: 0)
96
- end.to raise_error(Percy::Client::ServiceUnavailableError)
102
+
103
+ shared_examples_for 'HTTP status raises custom error class' do |http_status, error_class|
104
+ subject(:request) { Percy.client.post(uri, {}, retries: 0) }
105
+
106
+ it 'raises custom error classes for some HTTP errors' do
107
+ stub_request(:post, uri).to_return(body: {foo: true}.to_json, status: http_status.to_i)
108
+ expect { request }.to raise_error(error_class)
109
+ end
110
+ end
111
+
112
+ http_errors = {
113
+ '400' => Percy::Client::BadRequestError,
114
+ '401' => Percy::Client::UnauthorizedError,
115
+ '402' => Percy::Client::PaymentRequiredError,
116
+ '403' => Percy::Client::ForbiddenError,
117
+ '404' => Percy::Client::NotFoundError,
118
+ '409' => Percy::Client::ConflictError,
119
+ '500' => Percy::Client::InternalServerError,
120
+ '502' => Percy::Client::BadGatewayError,
121
+ '503' => Percy::Client::ServiceUnavailableError,
122
+ }
123
+
124
+ http_errors.each do |http_status, error_class|
125
+ include_examples 'HTTP status raises custom error class', http_status, error_class
97
126
  end
127
+
98
128
  it 'retries on server errors' do
99
- stub_request(:post, "#{Percy.config.api_url}/test")
129
+ stub_request(:post, uri)
100
130
  .to_return(body: {foo: true}.to_json, status: 500)
101
131
  .then.to_return(body: {foo: true}.to_json, status: 200)
102
132
 
103
- data = Percy.client.post("#{Percy.config.api_url}/test", {})
104
- expect(data).to eq('foo' => true)
133
+ expect(response).to eq('foo' => true)
105
134
  end
135
+
106
136
  it 'raises error after 3 retries' do
107
- stub_request(:post, "#{Percy.config.api_url}/test")
137
+ stub_request(:post, uri)
108
138
  .to_return(body: {foo: true}.to_json, status: 502).times(3)
109
- expect do
110
- Percy.client.post("#{Percy.config.api_url}/test", {})
111
- end.to raise_error(Percy::Client::BadGatewayError)
139
+
140
+ expect { response }.to raise_error(Percy::Client::BadGatewayError)
112
141
  end
113
142
  end
114
143
  end
@@ -88,6 +88,7 @@ RSpec.describe Percy::Client::Environment do
88
88
  }
89
89
  clear_env_vars
90
90
  end
91
+
91
92
  after(:each) do
92
93
  clear_env_vars
93
94
  ENV['TRAVIS_BUILD_ID'] = @original_env['TRAVIS_BUILD_ID']
@@ -106,41 +107,50 @@ RSpec.describe Percy::Client::Environment do
106
107
  expect(Percy::Client::Environment.current_ci).to be_nil
107
108
  end
108
109
  end
110
+
109
111
  describe '#branch' do
110
112
  it 'returns master if not in a git repo' do
111
113
  expect(Percy::Client::Environment).to receive(:_raw_branch_output).and_return('')
112
114
  expect(Percy::Client::Environment.branch).to eq('master')
113
115
  end
116
+
114
117
  it 'reads from the current local repo' do
115
118
  expect(Percy::Client::Environment.branch).to_not be_empty
116
119
  end
120
+
117
121
  it 'can be overridden with PERCY_BRANCH' do
118
122
  ENV['PERCY_BRANCH'] = 'test-branch'
119
123
  expect(Percy::Client::Environment.branch).to eq('test-branch')
120
124
  end
121
125
  end
126
+
122
127
  describe '#target_branch' do
123
128
  it 'returns nil if unset' do
124
129
  expect(Percy::Client::Environment.target_branch).to be_nil
125
130
  end
131
+
126
132
  it 'can be set with PERCY_TARGET_BRANCH' do
127
133
  ENV['PERCY_TARGET_BRANCH'] = 'test-target-branch'
128
134
  expect(Percy::Client::Environment.target_branch).to eq('test-target-branch')
129
135
  end
130
136
  end
137
+
131
138
  describe '#_commit_sha' do
132
139
  it 'returns nil if no environment info can be found' do
133
140
  expect(Percy::Client::Environment._commit_sha).to be_nil
134
141
  end
142
+
135
143
  it 'can be overridden with PERCY_COMMIT' do
136
144
  ENV['PERCY_COMMIT'] = 'test-commit'
137
145
  expect(Percy::Client::Environment._commit_sha).to eq('test-commit')
138
146
  end
139
147
  end
148
+
140
149
  describe '#pull_request_number' do
141
150
  it 'returns nil if no CI environment' do
142
151
  expect(Percy::Client::Environment.pull_request_number).to be_nil
143
152
  end
153
+
144
154
  it 'can be overridden with PERCY_PULL_REQUEST' do
145
155
  ENV['PERCY_PULL_REQUEST'] = '123'
146
156
  ENV['TRAVIS_BUILD_ID'] = '1234'
@@ -148,18 +158,22 @@ RSpec.describe Percy::Client::Environment do
148
158
  expect(Percy::Client::Environment.pull_request_number).to eq('123')
149
159
  end
150
160
  end
161
+
151
162
  describe '#repo' do
152
163
  it 'returns the current local repo name' do
153
164
  expect(Percy::Client::Environment.repo).to eq('percy/percy-client')
154
165
  end
166
+
155
167
  it 'can be overridden with PERCY_PROJECT' do
156
168
  ENV['PERCY_PROJECT'] = 'percy/slug'
157
169
  expect(Percy::Client::Environment.repo).to eq('percy/slug')
158
170
  end
171
+
159
172
  it 'can be overridden with PERCY_REPO_SLUG (deprecated)' do
160
173
  ENV['PERCY_REPO_SLUG'] = 'percy/slug'
161
174
  expect(Percy::Client::Environment.repo).to eq('percy/slug')
162
175
  end
176
+
163
177
  it 'handles git ssh urls' do
164
178
  expect(Percy::Client::Environment).to receive(:_get_origin_url)
165
179
  .once.and_return('git@github.com:org-name/repo-name.git')
@@ -173,6 +187,7 @@ RSpec.describe Percy::Client::Environment do
173
187
  .once.and_return('git@custom-local-hostname:org-name/repo-name.org')
174
188
  expect(Percy::Client::Environment.repo).to eq('org-name/repo-name.org')
175
189
  end
190
+
176
191
  it 'handles git https urls' do
177
192
  expect(Percy::Client::Environment).to receive(:_get_origin_url)
178
193
  .once.and_return('https://github.com/org-name/repo-name.git')
@@ -186,6 +201,7 @@ RSpec.describe Percy::Client::Environment do
186
201
  .once.and_return("https://github.com/org-name/repo-name.org\n")
187
202
  expect(Percy::Client::Environment.repo).to eq('org-name/repo-name.org')
188
203
  end
204
+
189
205
  it 'errors if unable to parse local repo name' do
190
206
  expect(Percy::Client::Environment).to receive(:_get_origin_url).once.and_return('foo')
191
207
  expect { Percy::Client::Environment.repo }.to raise_error(
@@ -193,25 +209,38 @@ RSpec.describe Percy::Client::Environment do
193
209
  )
194
210
  end
195
211
  end
212
+
196
213
  describe '#parallel_nonce' do
197
214
  it 'returns nil' do
198
215
  expect(Percy::Client::Environment.parallel_nonce).to be_nil
199
216
  end
217
+
200
218
  it 'can be set with environment var' do
201
219
  ENV['PERCY_PARALLEL_NONCE'] = 'nonce'
202
220
  expect(Percy::Client::Environment.parallel_nonce).to eq('nonce')
203
221
  end
204
222
  end
223
+
205
224
  describe '#parallel_total_shards' do
206
225
  it 'returns nil' do
207
226
  expect(Percy::Client::Environment.parallel_nonce).to be_nil
208
227
  end
228
+
209
229
  it 'can be set with environment var' do
210
230
  ENV['PERCY_PARALLEL_TOTAL'] = '3'
211
231
  expect(Percy::Client::Environment.parallel_total_shards).to eq(3)
212
232
  end
213
233
  end
214
234
  end
235
+
236
+ RSpec.shared_examples 'an environment user agent that includes CI' do |ci_name|
237
+ it 'returns a user_agent that includes CI name' do
238
+ user_agent = "Percy/v1 percy-client/#{Percy::Client::VERSION} "\
239
+ "(ruby/#{RUBY_VERSION}p#{RUBY_PATCHLEVEL}; #{ci_name})"
240
+ expect(Percy::Client::Environment.user_agent).to eq user_agent
241
+ end
242
+ end
243
+
215
244
  context 'in Jenkins CI' do
216
245
  before(:each) do
217
246
  ENV['JENKINS_URL'] = 'http://localhost:8080/'
@@ -228,6 +257,7 @@ RSpec.describe Percy::Client::Environment do
228
257
  expect(Percy::Client::Environment.repo).to eq('percy/percy-client')
229
258
  end
230
259
  end
260
+
231
261
  context 'in Travis CI' do
232
262
  before(:each) do
233
263
  ENV['TRAVIS_BUILD_ID'] = '1234'
@@ -250,28 +280,33 @@ RSpec.describe Percy::Client::Environment do
250
280
  expect(Percy::Client::Environment.parallel_nonce).to eq('build-number')
251
281
  expect(Percy::Client::Environment.parallel_total_shards).to be_nil
252
282
  end
283
+
253
284
  context 'Pull Request build' do
254
285
  before(:each) do
255
286
  ENV['TRAVIS_PULL_REQUEST'] = '256'
256
287
  ENV['TRAVIS_PULL_REQUEST_BRANCH'] = 'travis-pr-branch'
257
288
  ENV['TRAVIS_PULL_REQUEST_SHA'] = 'travis-pr-head-commit-sha'
258
289
  end
290
+
259
291
  it 'has the correct properties' do
260
292
  expect(Percy::Client::Environment.branch).to eq('travis-pr-branch')
261
293
  expect(Percy::Client::Environment._commit_sha).to eq('travis-pr-head-commit-sha')
262
294
  expect(Percy::Client::Environment.pull_request_number).to eq('256')
263
295
  end
264
296
  end
297
+
265
298
  context 'parallel build' do
266
299
  before(:each) do
267
300
  ENV['CI_NODE_TOTAL'] = '3'
268
301
  end
302
+
269
303
  it 'has the correct properties' do
270
304
  expect(Percy::Client::Environment.parallel_nonce).to eq('build-number')
271
305
  expect(Percy::Client::Environment.parallel_total_shards).to eq(3)
272
306
  end
273
307
  end
274
308
  end
309
+
275
310
  context 'in Circle CI' do
276
311
  before(:each) do
277
312
  ENV['CIRCLECI'] = 'true'
@@ -293,16 +328,19 @@ RSpec.describe Percy::Client::Environment do
293
328
  expect(Percy::Client::Environment.parallel_nonce).to eq('build-number')
294
329
  expect(Percy::Client::Environment.parallel_total_shards).to be_nil
295
330
  end
331
+
296
332
  context 'parallel build' do
297
333
  before(:each) do
298
334
  ENV['CIRCLE_NODE_TOTAL'] = '3'
299
335
  end
336
+
300
337
  it 'has the correct properties' do
301
338
  expect(Percy::Client::Environment.parallel_nonce).to eq('build-number')
302
339
  expect(Percy::Client::Environment.parallel_total_shards).to eq(3)
303
340
  end
304
341
  end
305
342
  end
343
+
306
344
  context 'in Codeship' do
307
345
  before(:each) do
308
346
  ENV['CI_NAME'] = 'codeship'
@@ -322,16 +360,19 @@ RSpec.describe Percy::Client::Environment do
322
360
  expect(Percy::Client::Environment.parallel_nonce).to eq('codeship-build-number')
323
361
  expect(Percy::Client::Environment.parallel_total_shards).to be_nil
324
362
  end
363
+
325
364
  context 'parallel build' do
326
365
  before(:each) do
327
366
  ENV['CI_NODE_TOTAL'] = '3'
328
367
  end
368
+
329
369
  it 'has the correct properties' do
330
370
  expect(Percy::Client::Environment.parallel_nonce).to eq('codeship-build-number')
331
371
  expect(Percy::Client::Environment.parallel_total_shards).to eq(3)
332
372
  end
333
373
  end
334
374
  end
375
+
335
376
  context 'in Drone' do
336
377
  before(:each) do
337
378
  ENV['DRONE'] = 'true'
@@ -348,6 +389,7 @@ RSpec.describe Percy::Client::Environment do
348
389
  expect(Percy::Client::Environment.repo).to eq('percy/percy-client')
349
390
  end
350
391
  end
392
+
351
393
  context 'in Semaphore CI' do
352
394
  before(:each) do
353
395
  ENV['SEMAPHORE'] = 'true'
@@ -368,16 +410,19 @@ RSpec.describe Percy::Client::Environment do
368
410
  expect(Percy::Client::Environment.parallel_nonce).to eq('semaphore-build-number')
369
411
  expect(Percy::Client::Environment.parallel_total_shards).to be_nil
370
412
  end
413
+
371
414
  context 'parallel build' do
372
415
  before(:each) do
373
416
  ENV['SEMAPHORE_THREAD_COUNT'] = '3'
374
417
  end
418
+
375
419
  it 'has the correct properties' do
376
420
  expect(Percy::Client::Environment.parallel_nonce).to eq('semaphore-build-number')
377
421
  expect(Percy::Client::Environment.parallel_total_shards).to eq(3)
378
422
  end
379
423
  end
380
424
  end
425
+
381
426
  context 'in Buildkite' do
382
427
  before(:each) do
383
428
  ENV['BUILDKITE'] = 'true'
@@ -28,4 +28,10 @@ RSpec.configure do |config|
28
28
  # test failures related to randomization by passing the same `--seed` value
29
29
  # as the one that triggered the failure.
30
30
  Kernel.srand config.seed
31
+
32
+ config.after(:each) do |_example|
33
+ # After each run, clear the memoized `_user_agent` property to avoid polluting
34
+ # other tests with the incorrect values.
35
+ Percy.client._reset_user_agent
36
+ end
31
37
  end
@@ -5,6 +5,10 @@ VCR.configure do |c|
5
5
  c.cassette_library_dir = 'spec/cassettes'
6
6
  c.hook_into :webmock
7
7
 
8
+ # Uncomment this to get VCR logger debugging.
9
+ # Run: `rspec spec vcr.log` to get debugging output to vcr.log
10
+ # c.debug_logger = File.open(ARGV[1], 'w')
11
+
8
12
  c.default_cassette_options = {
9
13
  record: ENV['RECORD'] ? :new_episodes : :none,
10
14
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: percy-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.12.0
4
+ version: 1.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Perceptual Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-17 00:00:00.000000000 Z
11
+ date: 2017-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -189,7 +189,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
189
189
  version: '0'
190
190
  requirements: []
191
191
  rubyforge_project:
192
- rubygems_version: 2.6.12
192
+ rubygems_version: 2.4.5.2
193
193
  signing_key:
194
194
  specification_version: 4
195
195
  summary: Percy::Client