codecov 0.2.15 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 85521bfddce47e0bea574c2ad37daac2f5ad37531ab7fb52fd17061f3a485bae
4
- data.tar.gz: 16a6e6657c28a3575dbce4c8a55de32faff1ab1e0d60490943e952af4d14b54b
3
+ metadata.gz: a56df245cb4eb2c44db6415aa240cb5275be7200974612f875c4c0d63c4c0538
4
+ data.tar.gz: 8d506d9afb7752ba7d2de41e0d81cbfefb33c4c9b6cb12b822778c170be1b85c
5
5
  SHA512:
6
- metadata.gz: 2924a697d2a0c0b51f157ddc4e8f5b7d235c886d20757fa27203f155316a090b66ceb156c1a1ddd55e9315b0ec87e6e9e68b134e8141c0859ff27d078e1bb13e
7
- data.tar.gz: 4dd840917cefb25b835e9477af2969f9c698d772b2765ce4bd6efd4b82ae7152ae10dd7125483564bb753d509030da09f6607a789ccc6c7f76ea85a009a88e93
6
+ metadata.gz: 21ab3799a0d563047fb5f38cefd0105ea4439defac9856d3509257af0c65ce3910864c3f5b28e49bc1e56a2eb90ef4aec9e11efe330c33e0832e81e2b27202f8
7
+ data.tar.gz: 2c0a3e8a9705d1d040ee9b4f6fc6b6a0fcba7c5b69e4d23b2c07c8911e1cb36290b24c836d77f456cbacb15e8881874596bfc67d10fa657368eb627d886bfd85
data/lib/codecov.rb CHANGED
@@ -6,621 +6,12 @@ require 'net/http'
6
6
  require 'simplecov'
7
7
  require 'zlib'
8
8
 
9
- require_relative 'codecov/version'
9
+ require_relative 'codecov/formatter'
10
+ require_relative 'codecov/uploader'
10
11
 
11
12
  class SimpleCov::Formatter::Codecov
12
- ### CIs
13
- RECOGNIZED_CIS = [
14
- APPVEYOR = 'Appveyor CI',
15
- AZUREPIPELINES = 'Azure Pipelines',
16
- BITBUCKET = 'Bitbucket',
17
- BITRISE = 'Bitrise CI',
18
- BUILDKITE = 'Buildkite CI',
19
- CIRCLE = 'Circle CI',
20
- CODEBUILD = 'Codebuild CI',
21
- CODESHIP = 'Codeship CI',
22
- DRONEIO = 'Drone CI',
23
- GITHUB = 'GitHub Actions',
24
- GITLAB = 'GitLab CI',
25
- HEROKU = 'Heroku CI',
26
- JENKINS = 'Jenkins CI',
27
- SEMAPHORE = 'Semaphore CI',
28
- SHIPPABLE = 'Shippable',
29
- SOLANO = 'Solano CI',
30
- TEAMCITY = 'TeamCity CI',
31
- TRAVIS = 'Travis CI',
32
- WERCKER = 'Wercker CI'
33
- ].freeze
34
-
35
- def display_header
36
- puts [
37
- '',
38
- ' _____ _',
39
- ' / ____| | |',
40
- '| | ___ __| | ___ ___ _____ __',
41
- '| | / _ \ / _\`|/ _ \/ __/ _ \ \ / /',
42
- '| |___| (_) | (_| | __/ (_| (_) \ V /',
43
- ' \_____\___/ \__,_|\___|\___\___/ \_/',
44
- " Ruby-#{::Codecov::VERSION}",
45
- ''
46
- ].join("\n")
47
- end
48
-
49
- def detect_ci
50
- ci = if (ENV['CI'] == 'True') && (ENV['APPVEYOR'] == 'True')
51
- APPVEYOR
52
- elsif !ENV['TF_BUILD'].nil?
53
- AZUREPIPELINES
54
- elsif (ENV['CI'] == 'true') && !ENV['BITBUCKET_BRANCH'].nil?
55
- BITBUCKET
56
- elsif (ENV['CI'] == 'true') && (ENV['BITRISE_IO'] == 'true')
57
- BITRISE
58
- elsif (ENV['CI'] == 'true') && (ENV['BUILDKITE'] == 'true')
59
- BUILDKITE
60
- elsif (ENV['CI'] == 'true') && (ENV['CIRCLECI'] == 'true')
61
- CIRCLE
62
- elsif ENV['CODEBUILD_CI'] == 'true'
63
- CODEBUILD
64
- elsif (ENV['CI'] == 'true') && (ENV['CI_NAME'] == 'codeship')
65
- CODESHIP
66
- elsif ((ENV['CI'] == 'true') || (ENV['CI'] == 'drone')) && (ENV['DRONE'] == 'true')
67
- DRONEIO
68
- elsif (ENV['CI'] == 'true') && (ENV['GITHUB_ACTIONS'] == 'true')
69
- GITHUB
70
- elsif !ENV['GITLAB_CI'].nil?
71
- GITLAB
72
- elsif ENV['HEROKU_TEST_RUN_ID']
73
- HEROKU
74
- elsif !ENV['JENKINS_URL'].nil?
75
- JENKINS
76
- elsif (ENV['CI'] == 'true') && (ENV['SEMAPHORE'] == 'true')
77
- SEMAPHORE
78
- elsif (ENV['CI'] == 'true') && (ENV['SHIPPABLE'] == 'true')
79
- SHIPPABLE
80
- elsif ENV['TDDIUM'] == 'true'
81
- SOLANO
82
- elsif ENV['CI_SERVER_NAME'] == 'TeamCity'
83
- TEAMCITY
84
- elsif (ENV['CI'] == 'true') && (ENV['TRAVIS'] == 'true')
85
- TRAVIS
86
- elsif (ENV['CI'] == 'true') && !ENV['WERCKER_GIT_BRANCH'].nil?
87
- WERCKER
88
- end
89
-
90
- if !RECOGNIZED_CIS.include?(ci)
91
- puts [red('x>'), 'No CI provider detected.'].join(' ')
92
- else
93
- puts "==> #{ci} detected"
94
- end
95
-
96
- ci
97
- end
98
-
99
- def build_params(ci)
100
- params = {
101
- 'token' => ENV['CODECOV_TOKEN'],
102
- 'flags' => ENV['CODECOV_FLAG'] || ENV['CODECOV_FLAGS'],
103
- 'package' => "ruby-#{::Codecov::VERSION}"
104
- }
105
-
106
- case ci
107
- when APPVEYOR
108
- # http://www.appveyor.com/docs/environment-variables
109
- params[:service] = 'appveyor'
110
- params[:branch] = ENV['APPVEYOR_REPO_BRANCH']
111
- params[:build] = ENV['APPVEYOR_JOB_ID']
112
- params[:pr] = ENV['APPVEYOR_PULL_REQUEST_NUMBER']
113
- params[:job] = ENV['APPVEYOR_ACCOUNT_NAME'] + '/' + ENV['APPVEYOR_PROJECT_SLUG'] + '/' + ENV['APPVEYOR_BUILD_VERSION']
114
- params[:slug] = ENV['APPVEYOR_REPO_NAME']
115
- params[:commit] = ENV['APPVEYOR_REPO_COMMIT']
116
- when AZUREPIPELINES
117
- params[:service] = 'azure_pipelines'
118
- params[:branch] = ENV['BUILD_SOURCEBRANCH']
119
- params[:pull_request] = ENV['SYSTEM_PULLREQUEST_PULLREQUESTNUMBER']
120
- params[:job] = ENV['SYSTEM_JOBID']
121
- params[:build] = ENV['BUILD_BUILDID']
122
- params[:build_url] = "#{ENV['SYSTEM_TEAMFOUNDATIONSERVERURI']}/#{ENV['SYSTEM_TEAMPROJECT']}/_build/results?buildId=#{ENV['BUILD_BUILDID']}"
123
- params[:commit] = ENV['BUILD_SOURCEVERSION']
124
- params[:slug] = ENV['BUILD_REPOSITORY_ID']
125
- when BITBUCKET
126
- # https://confluence.atlassian.com/bitbucket/variables-in-pipelines-794502608.html
127
- params[:service] = 'bitbucket'
128
- params[:branch] = ENV['BITBUCKET_BRANCH']
129
- # BITBUCKET_COMMIT does not always provide full commit sha due to a bug https://jira.atlassian.com/browse/BCLOUD-19393#
130
- params[:commit] = (ENV['BITBUCKET_COMMIT'].length < 40 ? nil : ENV['BITBUCKET_COMMIT'])
131
- params[:build] = ENV['BITBUCKET_BUILD_NUMBER']
132
- when BITRISE
133
- # http://devcenter.bitrise.io/faq/available-environment-variables/
134
- params[:service] = 'bitrise'
135
- params[:branch] = ENV['BITRISE_GIT_BRANCH']
136
- params[:pr] = ENV['BITRISE_PULL_REQUEST']
137
- params[:build] = ENV['BITRISE_BUILD_NUMBER']
138
- params[:build_url] = ENV['BITRISE_BUILD_URL']
139
- params[:commit] = ENV['BITRISE_GIT_COMMIT']
140
- params[:slug] = ENV['BITRISEIO_GIT_REPOSITORY_OWNER'] + '/' + ENV['BITRISEIO_GIT_REPOSITORY_SLUG']
141
- when BUILDKITE
142
- # https://buildkite.com/docs/guides/environment-variables
143
- params[:service] = 'buildkite'
144
- params[:branch] = ENV['BUILDKITE_BRANCH']
145
- params[:build] = ENV['BUILDKITE_BUILD_NUMBER']
146
- params[:job] = ENV['BUILDKITE_JOB_ID']
147
- params[:build_url] = ENV['BUILDKITE_BUILD_URL']
148
- params[:slug] = ENV['BUILDKITE_PROJECT_SLUG']
149
- params[:commit] = ENV['BUILDKITE_COMMIT']
150
- when CIRCLE
151
- # https://circleci.com/docs/environment-variables
152
- params[:service] = 'circleci'
153
- params[:build] = ENV['CIRCLE_BUILD_NUM']
154
- params[:job] = ENV['CIRCLE_NODE_INDEX']
155
- params[:slug] = if !ENV['CIRCLE_PROJECT_REPONAME'].nil?
156
- ENV['CIRCLE_PROJECT_USERNAME'] + '/' + ENV['CIRCLE_PROJECT_REPONAME']
157
- else
158
- ENV['CIRCLE_REPOSITORY_URL'].gsub(/^.*:/, '').gsub(/\.git$/, '')
159
- end
160
- params[:pr] = ENV['CIRCLE_PR_NUMBER']
161
- params[:branch] = ENV['CIRCLE_BRANCH']
162
- params[:commit] = ENV['CIRCLE_SHA1']
163
- when CODEBUILD
164
- # https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html
165
- params[:service] = 'codebuild'
166
- params[:branch] = ENV['CODEBUILD_WEBHOOK_HEAD_REF'].split('/')[2]
167
- params[:build] = ENV['CODEBUILD_BUILD_ID']
168
- params[:commit] = ENV['CODEBUILD_RESOLVED_SOURCE_VERSION']
169
- params[:job] = ENV['CODEBUILD_BUILD_ID']
170
- params[:slug] = ENV['CODEBUILD_SOURCE_REPO_URL'].match(/.*github.com\/(?<slug>.*).git/)['slug']
171
- params[:pr] = if ENV['CODEBUILD_SOURCE_VERSION']
172
- matched = ENV['CODEBUILD_SOURCE_VERSION'].match(%r{pr/(?<pr>.*)})
173
- matched.nil? ? ENV['CODEBUILD_SOURCE_VERSION'] : matched['pr']
174
- end
175
- when CODESHIP
176
- # https://www.codeship.io/documentation/continuous-integration/set-environment-variables/
177
- params[:service] = 'codeship'
178
- params[:branch] = ENV['CI_BRANCH']
179
- params[:commit] = ENV['CI_COMMIT_ID']
180
- params[:build] = ENV['CI_BUILD_NUMBER']
181
- params[:build_url] = ENV['CI_BUILD_URL']
182
- when DRONEIO
183
- # https://semaphoreapp.com/docs/available-environment-variables.html
184
- params[:service] = 'drone.io'
185
- params[:branch] = ENV['DRONE_BRANCH']
186
- params[:commit] = ENV['DRONE_COMMIT_SHA']
187
- params[:job] = ENV['DRONE_JOB_NUMBER']
188
- params[:build] = ENV['DRONE_BUILD_NUMBER']
189
- params[:build_url] = ENV['DRONE_BUILD_LINK'] || ENV['DRONE_BUILD_URL'] || ENV['CI_BUILD_URL']
190
- params[:pr] = ENV['DRONE_PULL_REQUEST']
191
- params[:tag] = ENV['DRONE_TAG']
192
- when GITHUB
193
- # https://help.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables#default-environment-variables
194
- params[:service] = 'github-actions'
195
- if (ENV['GITHUB_HEAD_REF'] || '').empty?
196
- params[:branch] = ENV['GITHUB_REF'].sub('refs/heads/', '')
197
- else
198
- params[:branch] = ENV['GITHUB_HEAD_REF']
199
- # PR refs are in the format: refs/pull/7/merge for pull_request events
200
- params[:pr] = ENV['GITHUB_REF'].split('/')[2]
201
- end
202
- params[:slug] = ENV['GITHUB_REPOSITORY']
203
- params[:build] = ENV['GITHUB_RUN_ID']
204
- params[:commit] = ENV['GITHUB_SHA']
205
- when GITLAB
206
- # http://doc.gitlab.com/ci/examples/README.html#environmental-variables
207
- # https://gitlab.com/gitlab-org/gitlab-ci-runner/blob/master/lib/build.rb#L96
208
- # GitLab Runner v9 renamed some environment variables, so we check both old and new variable names.
209
- params[:service] = 'gitlab'
210
- params[:branch] = ENV['CI_BUILD_REF_NAME'] || ENV['CI_COMMIT_REF_NAME']
211
- params[:build] = ENV['CI_BUILD_ID'] || ENV['CI_JOB_ID']
212
- slug = ENV['CI_BUILD_REPO'] || ENV['CI_REPOSITORY_URL']
213
- params[:slug] = slug.split('/', 4)[-1].sub('.git', '') if slug
214
- params[:commit] = ENV['CI_BUILD_REF'] || ENV['CI_COMMIT_SHA']
215
- when HEROKU
216
- params[:service] = 'heroku'
217
- params[:branch] = ENV['HEROKU_TEST_RUN_BRANCH']
218
- params[:build] = ENV['HEROKU_TEST_RUN_ID']
219
- params[:commit] = ENV['HEROKU_TEST_RUN_COMMIT_VERSION']
220
- when JENKINS
221
- # https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project
222
- # https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin#GitHubpullrequestbuilderplugin-EnvironmentVariables
223
- params[:service] = 'jenkins'
224
- params[:branch] = ENV['ghprbSourceBranch'] || ENV['GIT_BRANCH']
225
- params[:commit] = ENV['ghprbActualCommit'] || ENV['GIT_COMMIT']
226
- params[:pr] = ENV['ghprbPullId']
227
- params[:build] = ENV['BUILD_NUMBER']
228
- params[:root] = ENV['WORKSPACE']
229
- params[:build_url] = ENV['BUILD_URL']
230
- when SEMAPHORE
231
- # https://semaphoreapp.com/docs/available-environment-variables.html
232
- params[:service] = 'semaphore'
233
- params[:branch] = ENV['BRANCH_NAME']
234
- params[:commit] = ENV['REVISION']
235
- params[:build] = ENV['SEMAPHORE_BUILD_NUMBER']
236
- params[:job] = ENV['SEMAPHORE_CURRENT_THREAD']
237
- params[:slug] = ENV['SEMAPHORE_REPO_SLUG']
238
- when SHIPPABLE
239
- # http://docs.shippable.com/en/latest/config.html#common-environment-variables
240
- params[:service] = 'shippable'
241
- params[:branch] = ENV['BRANCH']
242
- params[:build] = ENV['BUILD_NUMBER']
243
- params[:build_url] = ENV['BUILD_URL']
244
- params[:pull_request] = ENV['PULL_REQUEST']
245
- params[:slug] = ENV['REPO_NAME']
246
- params[:commit] = ENV['COMMIT']
247
- when SOLANO
248
- # http://docs.solanolabs.com/Setup/tddium-set-environment-variables/
249
- params[:service] = 'solano'
250
- params[:branch] = ENV['TDDIUM_CURRENT_BRANCH']
251
- params[:commit] = ENV['TDDIUM_CURRENT_COMMIT']
252
- params[:build] = ENV['TDDIUM_TID']
253
- params[:pr] = ENV['TDDIUM_PR_ID']
254
- when TEAMCITY
255
- # https://confluence.jetbrains.com/display/TCD8/Predefined+Build+Parameters
256
- # Teamcity does not automatically make build parameters available as environment variables.
257
- # Add the following environment parameters to the build configuration
258
- # env.TEAMCITY_BUILD_BRANCH = %teamcity.build.branch%
259
- # env.TEAMCITY_BUILD_ID = %teamcity.build.id%
260
- # env.TEAMCITY_BUILD_URL = %teamcity.serverUrl%/viewLog.html?buildId=%teamcity.build.id%
261
- # env.TEAMCITY_BUILD_COMMIT = %system.build.vcs.number%
262
- # env.TEAMCITY_BUILD_REPOSITORY = %vcsroot.<YOUR TEAMCITY VCS NAME>.url%
263
- params[:service] = 'teamcity'
264
- params[:branch] = ENV['TEAMCITY_BUILD_BRANCH']
265
- params[:build] = ENV['TEAMCITY_BUILD_ID']
266
- params[:build_url] = ENV['TEAMCITY_BUILD_URL']
267
- params[:commit] = ENV['TEAMCITY_BUILD_COMMIT']
268
- params[:slug] = ENV['TEAMCITY_BUILD_REPOSITORY'].split('/', 4)[-1].sub('.git', '')
269
- when TRAVIS
270
- # http://docs.travis-ci.com/user/ci-environment/#Environment-variables
271
- params[:service] = 'travis'
272
- params[:branch] = ENV['TRAVIS_BRANCH']
273
- params[:pull_request] = ENV['TRAVIS_PULL_REQUEST']
274
- params[:job] = ENV['TRAVIS_JOB_ID']
275
- params[:slug] = ENV['TRAVIS_REPO_SLUG']
276
- params[:build] = ENV['TRAVIS_JOB_NUMBER']
277
- params[:commit] = ENV['TRAVIS_COMMIT']
278
- params[:env] = ENV['TRAVIS_RUBY_VERSION']
279
- when WERCKER
280
- # http://devcenter.wercker.com/articles/steps/variables.html
281
- params[:service] = 'wercker'
282
- params[:branch] = ENV['WERCKER_GIT_BRANCH']
283
- params[:build] = ENV['WERCKER_MAIN_PIPELINE_STARTED']
284
- params[:slug] = ENV['WERCKER_GIT_OWNER'] + '/' + ENV['WERCKER_GIT_REPOSITORY']
285
- params[:commit] = ENV['WERCKER_GIT_COMMIT']
286
- end
287
-
288
- if params[:branch].nil?
289
- # find branch, commit, repo from git command
290
- branch = `git rev-parse --abbrev-ref HEAD`.strip
291
- params[:branch] = branch != 'HEAD' ? branch : 'master'
292
- end
293
-
294
- if !ENV['VCS_COMMIT_ID'].nil?
295
- params[:commit] = ENV['VCS_COMMIT_ID']
296
-
297
- elsif params[:commit].nil?
298
- params[:commit] = `git rev-parse HEAD`.strip
299
- end
300
-
301
- slug = ENV['CODECOV_SLUG']
302
- params[:slug] = slug unless slug.nil?
303
-
304
- params[:pr] = params[:pr].sub('#', '') unless params[:pr].nil?
305
-
306
- params
307
- end
308
-
309
- def retry_request(req, https)
310
- retries = 3
311
- begin
312
- response = https.request(req)
313
- rescue Timeout::Error, SocketError => e
314
- retries -= 1
315
-
316
- if retries.zero?
317
- puts 'Timeout or connection error uploading coverage reports to Codecov. Out of retries.'
318
- puts e
319
- return response
320
- end
321
-
322
- puts 'Timeout or connection error uploading coverage reports to Codecov. Retrying...'
323
- puts e
324
- retry
325
- rescue StandardError => e
326
- puts 'Error uploading coverage reports to Codecov. Sorry'
327
- puts e.class.name
328
- puts e
329
- puts "Backtrace:\n\t#{e.backtrace}"
330
- return response
331
- end
332
-
333
- response
334
- end
335
-
336
- def create_report(report)
337
- result = {
338
- 'meta' => {
339
- 'version' => 'codecov-ruby/v' + ::Codecov::VERSION
340
- }
341
- }
342
- result.update(result_to_codecov(report))
343
- result
344
- end
345
-
346
- def gzip_report(report)
347
- puts [green('==>'), 'Gzipping contents'].join(' ')
348
-
349
- io = StringIO.new
350
- gzip = Zlib::GzipWriter.new(io)
351
- gzip << report
352
- gzip.close
353
-
354
- io.string
355
- end
356
-
357
- def upload_to_codecov(ci, report)
358
- url = ENV['CODECOV_URL'] || 'https://codecov.io'
359
- is_enterprise = url != 'https://codecov.io'
360
-
361
- params = build_params(ci)
362
- params_secret_token = params.clone
363
- params_secret_token['token'] = 'secret'
364
-
365
- query = URI.encode_www_form(params)
366
- query_without_token = URI.encode_www_form(params_secret_token)
367
-
368
- gzipped_report = gzip_report(report['codecov'])
369
-
370
- report['params'] = params
371
- report['query'] = query
372
-
373
- puts [green('==>'), 'Uploading reports'].join(' ')
374
- puts " url: #{url}"
375
- puts " query: #{query_without_token}"
376
-
377
- response = false
378
- unless is_enterprise
379
- response = upload_to_v4(url, gzipped_report, query, query_without_token)
380
- return false if response == false
381
- end
382
-
383
- response || upload_to_v2(url, gzipped_report, query, query_without_token)
384
- end
385
-
386
- def upload_to_v4(url, report, query, query_without_token)
387
- uri = URI.parse(url.chomp('/') + '/upload/v4')
388
- https = Net::HTTP.new(uri.host, uri.port)
389
- https.use_ssl = !url.match(/^https/).nil?
390
-
391
- puts [green('-> '), 'Pinging Codecov'].join(' ')
392
- puts "#{url}#{uri.path}?#{query_without_token}"
393
-
394
- req = Net::HTTP::Post.new(
395
- "#{uri.path}?#{query}",
396
- {
397
- 'X-Reduced-Redundancy' => 'false',
398
- 'X-Content-Encoding' => 'application/x-gzip',
399
- 'Content-Type' => 'text/plain'
400
- }
401
- )
402
- response = retry_request(req, https)
403
- if !response&.code || response.code == '400'
404
- puts red(response&.body)
405
- return false
406
- end
407
-
408
- reports_url = response.body.lines[0]
409
- s3target = response.body.lines[1]
410
- puts [green('-> '), 'Uploading to'].join(' ')
411
- puts s3target
412
-
413
- uri = URI(s3target)
414
- https = Net::HTTP.new(uri.host, uri.port)
415
- https.use_ssl = true
416
- req = Net::HTTP::Put.new(
417
- s3target,
418
- {
419
- 'Content-Encoding' => 'gzip',
420
- 'Content-Type' => 'text/plain'
421
- }
422
- )
423
- req.body = report
424
- res = retry_request(req, https)
425
- if res&.body == ''
426
- {
427
- 'uploaded' => true,
428
- 'url' => reports_url,
429
- 'meta' => {
430
- 'status' => res.code
431
- },
432
- 'message' => 'Coverage reports upload successfully'
433
- }.to_json
434
- else
435
- puts [black('-> '), 'Could not upload reports via v4 API, defaulting to v2'].join(' ')
436
- puts red(res&.body || 'nil')
437
- nil
438
- end
439
- end
440
-
441
- def upload_to_v2(url, report, query, query_without_token)
442
- uri = URI.parse(url.chomp('/') + '/upload/v2')
443
- https = Net::HTTP.new(uri.host, uri.port)
444
- https.use_ssl = !url.match(/^https/).nil?
445
-
446
- puts [green('-> '), 'Uploading to Codecov'].join(' ')
447
- puts "#{url}#{uri.path}?#{query_without_token}"
448
-
449
- req = Net::HTTP::Post.new(
450
- "#{uri.path}?#{query}",
451
- {
452
- 'Accept' => 'application/json',
453
- 'Content-Encoding' => 'gzip',
454
- 'Content-Type' => 'text/plain',
455
- 'X-Content-Encoding' => 'gzip'
456
- }
457
- )
458
- req.body = report
459
- res = retry_request(req, https)
460
- res&.body
461
- end
462
-
463
- def handle_report_response(report)
464
- if report['result']['uploaded']
465
- puts " View reports at #{report['result']['url']}"
466
- else
467
- puts red(' X> Failed to upload coverage reports')
468
- end
469
- end
470
-
471
13
  def format(result, disable_net_blockers = true)
472
- net_blockers(:off) if disable_net_blockers
473
-
474
- display_header
475
- ci = detect_ci
476
- report = create_report(result)
477
- response = upload_to_codecov(ci, report)
478
- if response == false
479
- report['result'] = { 'uploaded' => false }
480
- return report
481
- end
482
-
483
- report['result'] = JSON.parse(response)
484
- handle_report_response(report)
485
-
486
- net_blockers(:on) if disable_net_blockers
487
- report
488
- end
489
-
490
- private
491
-
492
- # Format SimpleCov coverage data for the Codecov.io API.
493
- #
494
- # @param result [SimpleCov::Result] The coverage data to process.
495
- # @return [Hash]
496
- def result_to_codecov(result)
497
- {
498
- 'codecov' => result_to_codecov_report(result),
499
- 'coverage' => result_to_codecov_coverage(result),
500
- 'messages' => result_to_codecov_messages(result)
501
- }
502
- end
503
-
504
- def result_to_codecov_report(result)
505
- report = file_network.join("\n").concat("\n")
506
- report = report.concat({ 'coverage' => result_to_codecov_coverage(result) }.to_json)
507
- report
508
- end
509
-
510
- def file_network
511
- invalid_file_types = [
512
- 'woff', 'eot', 'otf', # fonts
513
- 'gif', 'png', 'jpg', 'jpeg', 'psd', # images
514
- 'ptt', 'pptx', 'numbers', 'pages', 'md', 'txt', 'xlsx', 'docx', 'doc', 'pdf', 'csv', # docs
515
- 'yml', 'yaml', '.gitignore'
516
- ].freeze
517
-
518
- invalid_directories = [
519
- 'node_modules/',
520
- 'public/',
521
- 'storage/',
522
- 'tmp/',
523
- 'vendor/'
524
- ]
525
-
526
- puts [green('==>'), 'Appending file network'].join(' ')
527
- network = []
528
- Dir['**/*'].keep_if do |file|
529
- if File.file?(file) && !file.end_with?(*invalid_file_types) && invalid_directories.none? { |dir| file.include?(dir) }
530
- network.push(file)
531
- end
532
- end
533
-
534
- network.push('<<<<<< network')
535
- network
536
- end
537
-
538
- # Format SimpleCov coverage data for the Codecov.io coverage API.
539
- #
540
- # @param result [SimpleCov::Result] The coverage data to process.
541
- # @return [Hash<String, Array>]
542
- def result_to_codecov_coverage(result)
543
- result.files.each_with_object({}) do |file, memo|
544
- memo[shortened_filename(file)] = file_to_codecov(file)
545
- end
546
- end
547
-
548
- # Format SimpleCov coverage data for the Codecov.io messages API.
549
- #
550
- # @param result [SimpleCov::Result] The coverage data to process.
551
- # @return [Hash<String, Hash>]
552
- def result_to_codecov_messages(result)
553
- result.files.each_with_object({}) do |file, memo|
554
- memo[shortened_filename(file)] = file.lines.each_with_object({}) do |line, lines_memo|
555
- lines_memo[line.line_number.to_s] = 'skipped' if line.skipped?
556
- end
557
- end
558
- end
559
-
560
- # Format coverage data for a single file for the Codecov.io API.
561
- #
562
- # @param file [SimpleCov::SourceFile] The file to process.
563
- # @return [Array<nil, Integer>]
564
- def file_to_codecov(file)
565
- # Initial nil is required to offset line numbers.
566
- [nil] + file.lines.map do |line|
567
- if line.skipped?
568
- nil
569
- else
570
- line.coverage
571
- end
572
- end
573
- end
574
-
575
- # Get a filename relative to the project root. Based on
576
- # https://github.com/colszowka/simplecov-html, copyright Christoph Olszowka.
577
- #
578
- # @param file [SimeplCov::SourceFile] The file to use.
579
- # @return [String]
580
- def shortened_filename(file)
581
- file.filename.gsub(/^#{SimpleCov.root}/, '.').gsub(%r{^\./}, '')
582
- end
583
-
584
- # Toggle VCR and WebMock on or off
585
- #
586
- # @param switch Toggle switch for Net Blockers.
587
- # @return [Boolean]
588
- def net_blockers(switch)
589
- throw 'Only :on or :off' unless %i[on off].include? switch
590
-
591
- if defined?(VCR)
592
- case switch
593
- when :on
594
- VCR.turn_on!
595
- when :off
596
- VCR.turn_off!(ignore_cassettes: true)
597
- end
598
- end
599
-
600
- if defined?(WebMock)
601
- # WebMock on by default
602
- # VCR depends on WebMock 1.8.11; no method to check whether enabled.
603
- case switch
604
- when :on
605
- WebMock.enable!
606
- when :off
607
- WebMock.disable!
608
- end
609
- end
610
-
611
- true
612
- end
613
-
614
- # Convenience color methods
615
- def black(str)
616
- str.nil? ? '' : "\e[30m#{str}\e[0m"
617
- end
618
-
619
- def red(str)
620
- str.nil? ? '' : "\e[31m#{str}\e[0m"
621
- end
622
-
623
- def green(str)
624
- str.nil? ? '' : "\e[32m#{str}\e[0m"
14
+ report = Codecov::SimpleCov::Formatter.new.format(result)
15
+ Codecov::Uploader.upload(report, disable_net_blockers)
625
16
  end
626
17
  end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'simplecov'
4
+
5
+ require_relative 'version'
6
+
7
+ module Codecov
8
+ module SimpleCov
9
+ class Formatter
10
+ RESULT_FILE_NAME = 'codecov-result.json'
11
+
12
+ def format(report)
13
+ result = {
14
+ 'meta' => {
15
+ 'version' => "codecov-ruby/v#{::Codecov::VERSION}"
16
+ }
17
+ }
18
+ result.update(result_to_codecov(report))
19
+
20
+ begin
21
+ result_path = File.join(::SimpleCov.coverage_path, RESULT_FILE_NAME)
22
+ File.write(result_path, result['codecov'])
23
+ overflow = result['coverage'].to_s.length > 256 ? '...' : ''
24
+ puts "Coverage report generated to #{result_path}.\n#{result['coverage'].to_s.[](0, 255)}#{overflow}"
25
+ rescue Errno::ENOENT => e
26
+ puts e
27
+ puts "Could not write coverage report to file.\n#{result}"
28
+ end
29
+
30
+ result
31
+ end
32
+
33
+ private
34
+
35
+ # Format SimpleCov coverage data for the Codecov.io API.
36
+ #
37
+ # @param result [SimpleCov::Result] The coverage data to process.
38
+ # @return [Hash]
39
+ def result_to_codecov(result)
40
+ {
41
+ 'codecov' => result_to_codecov_report(result),
42
+ 'coverage' => result_to_codecov_coverage(result),
43
+ 'messages' => result_to_codecov_messages(result)
44
+ }
45
+ end
46
+
47
+ def result_to_codecov_report(result)
48
+ report = file_network.join("\n").concat("\n")
49
+ report.concat({ 'coverage' => result_to_codecov_coverage(result) }.to_json)
50
+ end
51
+
52
+ def file_network
53
+ invalid_file_types = [
54
+ 'woff', 'eot', 'otf', # fonts
55
+ 'gif', 'png', 'jpg', 'jpeg', 'psd', # images
56
+ 'ptt', 'pptx', 'numbers', 'pages', 'md', 'txt', 'xlsx', 'docx', 'doc', 'pdf', 'csv', # docs
57
+ 'yml', 'yaml', '.gitignore'
58
+ ].freeze
59
+
60
+ invalid_directories = [
61
+ 'node_modules/',
62
+ 'public/',
63
+ 'storage/',
64
+ 'tmp/',
65
+ 'vendor/'
66
+ ]
67
+
68
+ network = []
69
+ Dir['**/*'].keep_if do |file|
70
+ if File.file?(file) && !file.end_with?(*invalid_file_types) && invalid_directories.none? { |dir| file.include?(dir) }
71
+ network.push(file)
72
+ end
73
+ end
74
+
75
+ network.push('<<<<<< network')
76
+ network
77
+ end
78
+
79
+ # Format SimpleCov coverage data for the Codecov.io coverage API.
80
+ #
81
+ # @param result [SimpleCov::Result] The coverage data to process.
82
+ # @return [Hash<String, Array>]
83
+ def result_to_codecov_coverage(result)
84
+ result.files.each_with_object({}) do |file, memo|
85
+ memo[shortened_filename(file)] = file_to_codecov(file)
86
+ end
87
+ end
88
+
89
+ # Format SimpleCov coverage data for the Codecov.io messages API.
90
+ #
91
+ # @param result [SimpleCov::Result] The coverage data to process.
92
+ # @return [Hash<String, Hash>]
93
+ def result_to_codecov_messages(result)
94
+ result.files.each_with_object({}) do |file, memo|
95
+ memo[shortened_filename(file)] = file.lines.each_with_object({}) do |line, lines_memo|
96
+ lines_memo[line.line_number.to_s] = 'skipped' if line.skipped?
97
+ end
98
+ end
99
+ end
100
+
101
+ # Format coverage data for a single file for the Codecov.io API.
102
+ #
103
+ # @param file [SimpleCov::SourceFile] The file to process.
104
+ # @return [Array<nil, Integer>]
105
+ def file_to_codecov(file)
106
+ # Initial nil is required to offset line numbers.
107
+ [nil] + file.lines.map do |line|
108
+ if line.skipped?
109
+ nil
110
+ else
111
+ line.coverage
112
+ end
113
+ end
114
+ end
115
+
116
+ # Get a filename relative to the project root. Based on
117
+ # https://github.com/colszowka/simplecov-html, copyright Christoph Olszowka.
118
+ #
119
+ # @param file [SimpleCov::SourceFile] The file to use.
120
+ # @return [String]
121
+ def shortened_filename(file)
122
+ file.filename.gsub(/^#{::SimpleCov.root}/, '.').gsub(%r{^\./}, '')
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,523 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+ require 'json'
5
+ require 'net/http'
6
+ require 'simplecov'
7
+ require 'zlib'
8
+
9
+ require_relative 'version'
10
+
11
+ class Codecov::Uploader
12
+ ### CIs
13
+ RECOGNIZED_CIS = [
14
+ APPVEYOR = 'Appveyor CI',
15
+ AZUREPIPELINES = 'Azure Pipelines',
16
+ BITBUCKET = 'Bitbucket',
17
+ BITRISE = 'Bitrise CI',
18
+ BUILDKITE = 'Buildkite CI',
19
+ CIRCLE = 'Circle CI',
20
+ CODEBUILD = 'Codebuild CI',
21
+ CODESHIP = 'Codeship CI',
22
+ DRONEIO = 'Drone CI',
23
+ GITHUB = 'GitHub Actions',
24
+ GITLAB = 'GitLab CI',
25
+ HEROKU = 'Heroku CI',
26
+ JENKINS = 'Jenkins CI',
27
+ SEMAPHORE = 'Semaphore CI',
28
+ SHIPPABLE = 'Shippable',
29
+ SOLANO = 'Solano CI',
30
+ TEAMCITY = 'TeamCity CI',
31
+ TRAVIS = 'Travis CI',
32
+ WERCKER = 'Wercker CI'
33
+ ].freeze
34
+
35
+ def self.upload(report, disable_net_blockers = true)
36
+ net_blockers(:off) if disable_net_blockers
37
+
38
+ display_header
39
+ ci = detect_ci
40
+ response = upload_to_codecov(ci, report)
41
+ if response == false
42
+ report['result'] = { 'uploaded' => false }
43
+ return report
44
+ end
45
+
46
+ report['result'] = JSON.parse(response)
47
+ handle_report_response(report)
48
+
49
+ net_blockers(:on) if disable_net_blockers
50
+ report
51
+ end
52
+
53
+ def self.display_header
54
+ puts [
55
+ '',
56
+ ' _____ _',
57
+ ' / ____| | |',
58
+ '| | ___ __| | ___ ___ _____ __',
59
+ '| | / _ \ / _\`|/ _ \/ __/ _ \ \ / /',
60
+ '| |___| (_) | (_| | __/ (_| (_) \ V /',
61
+ ' \_____\___/ \__,_|\___|\___\___/ \_/',
62
+ " Ruby-#{::Codecov::VERSION}",
63
+ ''
64
+ ].join("\n")
65
+ end
66
+
67
+ def self.detect_ci
68
+ ci = if (ENV['CI'] == 'True') && (ENV['APPVEYOR'] == 'True')
69
+ APPVEYOR
70
+ elsif !ENV['TF_BUILD'].nil?
71
+ AZUREPIPELINES
72
+ elsif (ENV['CI'] == 'true') && !ENV['BITBUCKET_BRANCH'].nil?
73
+ BITBUCKET
74
+ elsif (ENV['CI'] == 'true') && (ENV['BITRISE_IO'] == 'true')
75
+ BITRISE
76
+ elsif (ENV['CI'] == 'true') && (ENV['BUILDKITE'] == 'true')
77
+ BUILDKITE
78
+ elsif (ENV['CI'] == 'true') && (ENV['CIRCLECI'] == 'true')
79
+ CIRCLE
80
+ elsif ENV['CODEBUILD_CI'] == 'true'
81
+ CODEBUILD
82
+ elsif (ENV['CI'] == 'true') && (ENV['CI_NAME'] == 'codeship')
83
+ CODESHIP
84
+ elsif ((ENV['CI'] == 'true') || (ENV['CI'] == 'drone')) && (ENV['DRONE'] == 'true')
85
+ DRONEIO
86
+ elsif (ENV['CI'] == 'true') && (ENV['GITHUB_ACTIONS'] == 'true')
87
+ GITHUB
88
+ elsif !ENV['GITLAB_CI'].nil?
89
+ GITLAB
90
+ elsif ENV['HEROKU_TEST_RUN_ID']
91
+ HEROKU
92
+ elsif !ENV['JENKINS_URL'].nil?
93
+ JENKINS
94
+ elsif (ENV['CI'] == 'true') && (ENV['SEMAPHORE'] == 'true')
95
+ SEMAPHORE
96
+ elsif (ENV['CI'] == 'true') && (ENV['SHIPPABLE'] == 'true')
97
+ SHIPPABLE
98
+ elsif ENV['TDDIUM'] == 'true'
99
+ SOLANO
100
+ elsif ENV['CI_SERVER_NAME'] == 'TeamCity'
101
+ TEAMCITY
102
+ elsif (ENV['CI'] == 'true') && (ENV['TRAVIS'] == 'true')
103
+ TRAVIS
104
+ elsif (ENV['CI'] == 'true') && !ENV['WERCKER_GIT_BRANCH'].nil?
105
+ WERCKER
106
+ end
107
+
108
+ if !RECOGNIZED_CIS.include?(ci)
109
+ puts [red('x>'), 'No CI provider detected.'].join(' ')
110
+ else
111
+ puts "==> #{ci} detected"
112
+ end
113
+
114
+ ci
115
+ end
116
+
117
+ def self.build_params(ci)
118
+ params = {
119
+ 'token' => ENV['CODECOV_TOKEN'],
120
+ 'flags' => ENV['CODECOV_FLAG'] || ENV['CODECOV_FLAGS'],
121
+ 'package' => "ruby-#{::Codecov::VERSION}"
122
+ }
123
+
124
+ case ci
125
+ when APPVEYOR
126
+ # http://www.appveyor.com/docs/environment-variables
127
+ params[:service] = 'appveyor'
128
+ params[:branch] = ENV['APPVEYOR_REPO_BRANCH']
129
+ params[:build] = ENV['APPVEYOR_JOB_ID']
130
+ params[:pr] = ENV['APPVEYOR_PULL_REQUEST_NUMBER']
131
+ params[:job] = ENV['APPVEYOR_ACCOUNT_NAME'] + '/' + ENV['APPVEYOR_PROJECT_SLUG'] + '/' + ENV['APPVEYOR_BUILD_VERSION']
132
+ params[:slug] = ENV['APPVEYOR_REPO_NAME']
133
+ params[:commit] = ENV['APPVEYOR_REPO_COMMIT']
134
+ when AZUREPIPELINES
135
+ params[:service] = 'azure_pipelines'
136
+ params[:branch] = ENV['BUILD_SOURCEBRANCH']
137
+ params[:pull_request] = ENV['SYSTEM_PULLREQUEST_PULLREQUESTNUMBER']
138
+ params[:job] = ENV['SYSTEM_JOBID']
139
+ params[:build] = ENV['BUILD_BUILDID']
140
+ params[:build_url] = "#{ENV['SYSTEM_TEAMFOUNDATIONSERVERURI']}/#{ENV['SYSTEM_TEAMPROJECT']}/_build/results?buildId=#{ENV['BUILD_BUILDID']}"
141
+ params[:commit] = ENV['BUILD_SOURCEVERSION']
142
+ params[:slug] = ENV['BUILD_REPOSITORY_ID']
143
+ when BITBUCKET
144
+ # https://confluence.atlassian.com/bitbucket/variables-in-pipelines-794502608.html
145
+ params[:service] = 'bitbucket'
146
+ params[:branch] = ENV['BITBUCKET_BRANCH']
147
+ # BITBUCKET_COMMIT does not always provide full commit sha due to a bug https://jira.atlassian.com/browse/BCLOUD-19393#
148
+ params[:commit] = (ENV['BITBUCKET_COMMIT'].length < 40 ? nil : ENV['BITBUCKET_COMMIT'])
149
+ params[:build] = ENV['BITBUCKET_BUILD_NUMBER']
150
+ when BITRISE
151
+ # http://devcenter.bitrise.io/faq/available-environment-variables/
152
+ params[:service] = 'bitrise'
153
+ params[:branch] = ENV['BITRISE_GIT_BRANCH']
154
+ params[:pr] = ENV['BITRISE_PULL_REQUEST']
155
+ params[:build] = ENV['BITRISE_BUILD_NUMBER']
156
+ params[:build_url] = ENV['BITRISE_BUILD_URL']
157
+ params[:commit] = ENV['BITRISE_GIT_COMMIT']
158
+ params[:slug] = ENV['BITRISEIO_GIT_REPOSITORY_OWNER'] + '/' + ENV['BITRISEIO_GIT_REPOSITORY_SLUG']
159
+ when BUILDKITE
160
+ # https://buildkite.com/docs/guides/environment-variables
161
+ params[:service] = 'buildkite'
162
+ params[:branch] = ENV['BUILDKITE_BRANCH']
163
+ params[:build] = ENV['BUILDKITE_BUILD_NUMBER']
164
+ params[:job] = ENV['BUILDKITE_JOB_ID']
165
+ params[:build_url] = ENV['BUILDKITE_BUILD_URL']
166
+ params[:slug] = ENV['BUILDKITE_PROJECT_SLUG']
167
+ params[:commit] = ENV['BUILDKITE_COMMIT']
168
+ when CIRCLE
169
+ # https://circleci.com/docs/environment-variables
170
+ params[:service] = 'circleci'
171
+ params[:build] = ENV['CIRCLE_BUILD_NUM']
172
+ params[:job] = ENV['CIRCLE_NODE_INDEX']
173
+ params[:slug] = if !ENV['CIRCLE_PROJECT_REPONAME'].nil?
174
+ ENV['CIRCLE_PROJECT_USERNAME'] + '/' + ENV['CIRCLE_PROJECT_REPONAME']
175
+ else
176
+ ENV['CIRCLE_REPOSITORY_URL'].gsub(/^.*:/, '').gsub(/\.git$/, '')
177
+ end
178
+ params[:pr] = ENV['CIRCLE_PR_NUMBER']
179
+ params[:branch] = ENV['CIRCLE_BRANCH']
180
+ params[:commit] = ENV['CIRCLE_SHA1']
181
+ when CODEBUILD
182
+ # https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html
183
+ params[:service] = 'codebuild'
184
+ params[:branch] = ENV['CODEBUILD_WEBHOOK_HEAD_REF'].split('/')[2]
185
+ params[:build] = ENV['CODEBUILD_BUILD_ID']
186
+ params[:commit] = ENV['CODEBUILD_RESOLVED_SOURCE_VERSION']
187
+ params[:job] = ENV['CODEBUILD_BUILD_ID']
188
+ params[:slug] = ENV['CODEBUILD_SOURCE_REPO_URL'].match(/.*github.com\/(?<slug>.*).git/)['slug']
189
+ params[:pr] = if ENV['CODEBUILD_SOURCE_VERSION']
190
+ matched = ENV['CODEBUILD_SOURCE_VERSION'].match(%r{pr/(?<pr>.*)})
191
+ matched.nil? ? ENV['CODEBUILD_SOURCE_VERSION'] : matched['pr']
192
+ end
193
+ when CODESHIP
194
+ # https://www.codeship.io/documentation/continuous-integration/set-environment-variables/
195
+ params[:service] = 'codeship'
196
+ params[:branch] = ENV['CI_BRANCH']
197
+ params[:commit] = ENV['CI_COMMIT_ID']
198
+ params[:build] = ENV['CI_BUILD_NUMBER']
199
+ params[:build_url] = ENV['CI_BUILD_URL']
200
+ when DRONEIO
201
+ # https://semaphoreapp.com/docs/available-environment-variables.html
202
+ params[:service] = 'drone.io'
203
+ params[:branch] = ENV['DRONE_BRANCH']
204
+ params[:commit] = ENV['DRONE_COMMIT_SHA']
205
+ params[:job] = ENV['DRONE_JOB_NUMBER']
206
+ params[:build] = ENV['DRONE_BUILD_NUMBER']
207
+ params[:build_url] = ENV['DRONE_BUILD_LINK'] || ENV['DRONE_BUILD_URL'] || ENV['CI_BUILD_URL']
208
+ params[:pr] = ENV['DRONE_PULL_REQUEST']
209
+ params[:tag] = ENV['DRONE_TAG']
210
+ when GITHUB
211
+ # https://help.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables#default-environment-variables
212
+ params[:service] = 'github-actions'
213
+ if (ENV['GITHUB_HEAD_REF'] || '').empty?
214
+ params[:branch] = ENV['GITHUB_REF'].sub('refs/heads/', '')
215
+ else
216
+ params[:branch] = ENV['GITHUB_HEAD_REF']
217
+ # PR refs are in the format: refs/pull/7/merge for pull_request events
218
+ params[:pr] = ENV['GITHUB_REF'].split('/')[2]
219
+ end
220
+ params[:slug] = ENV['GITHUB_REPOSITORY']
221
+ params[:build] = ENV['GITHUB_RUN_ID']
222
+ params[:commit] = ENV['GITHUB_SHA']
223
+ when GITLAB
224
+ # http://doc.gitlab.com/ci/examples/README.html#environmental-variables
225
+ # https://gitlab.com/gitlab-org/gitlab-ci-runner/blob/master/lib/build.rb#L96
226
+ # GitLab Runner v9 renamed some environment variables, so we check both old and new variable names.
227
+ params[:service] = 'gitlab'
228
+ params[:branch] = ENV['CI_BUILD_REF_NAME'] || ENV['CI_COMMIT_REF_NAME']
229
+ params[:build] = ENV['CI_BUILD_ID'] || ENV['CI_JOB_ID']
230
+ slug = ENV['CI_BUILD_REPO'] || ENV['CI_REPOSITORY_URL']
231
+ params[:slug] = slug.split('/', 4)[-1].sub('.git', '') if slug
232
+ params[:commit] = ENV['CI_BUILD_REF'] || ENV['CI_COMMIT_SHA']
233
+ when HEROKU
234
+ params[:service] = 'heroku'
235
+ params[:branch] = ENV['HEROKU_TEST_RUN_BRANCH']
236
+ params[:build] = ENV['HEROKU_TEST_RUN_ID']
237
+ params[:commit] = ENV['HEROKU_TEST_RUN_COMMIT_VERSION']
238
+ when JENKINS
239
+ # https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project
240
+ # https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin#GitHubpullrequestbuilderplugin-EnvironmentVariables
241
+ params[:service] = 'jenkins'
242
+ params[:branch] = ENV['ghprbSourceBranch'] || ENV['GIT_BRANCH']
243
+ params[:commit] = ENV['ghprbActualCommit'] || ENV['GIT_COMMIT']
244
+ params[:pr] = ENV['ghprbPullId']
245
+ params[:build] = ENV['BUILD_NUMBER']
246
+ params[:root] = ENV['WORKSPACE']
247
+ params[:build_url] = ENV['BUILD_URL']
248
+ when SEMAPHORE
249
+ # https://semaphoreapp.com/docs/available-environment-variables.html
250
+ params[:service] = 'semaphore'
251
+ params[:branch] = ENV['BRANCH_NAME']
252
+ params[:commit] = ENV['REVISION']
253
+ params[:build] = ENV['SEMAPHORE_BUILD_NUMBER']
254
+ params[:job] = ENV['SEMAPHORE_CURRENT_THREAD']
255
+ params[:slug] = ENV['SEMAPHORE_REPO_SLUG']
256
+ when SHIPPABLE
257
+ # http://docs.shippable.com/en/latest/config.html#common-environment-variables
258
+ params[:service] = 'shippable'
259
+ params[:branch] = ENV['BRANCH']
260
+ params[:build] = ENV['BUILD_NUMBER']
261
+ params[:build_url] = ENV['BUILD_URL']
262
+ params[:pull_request] = ENV['PULL_REQUEST']
263
+ params[:slug] = ENV['REPO_NAME']
264
+ params[:commit] = ENV['COMMIT']
265
+ when SOLANO
266
+ # http://docs.solanolabs.com/Setup/tddium-set-environment-variables/
267
+ params[:service] = 'solano'
268
+ params[:branch] = ENV['TDDIUM_CURRENT_BRANCH']
269
+ params[:commit] = ENV['TDDIUM_CURRENT_COMMIT']
270
+ params[:build] = ENV['TDDIUM_TID']
271
+ params[:pr] = ENV['TDDIUM_PR_ID']
272
+ when TEAMCITY
273
+ # https://confluence.jetbrains.com/display/TCD8/Predefined+Build+Parameters
274
+ # Teamcity does not automatically make build parameters available as environment variables.
275
+ # Add the following environment parameters to the build configuration
276
+ # env.TEAMCITY_BUILD_BRANCH = %teamcity.build.branch%
277
+ # env.TEAMCITY_BUILD_ID = %teamcity.build.id%
278
+ # env.TEAMCITY_BUILD_URL = %teamcity.serverUrl%/viewLog.html?buildId=%teamcity.build.id%
279
+ # env.TEAMCITY_BUILD_COMMIT = %system.build.vcs.number%
280
+ # env.TEAMCITY_BUILD_REPOSITORY = %vcsroot.<YOUR TEAMCITY VCS NAME>.url%
281
+ params[:service] = 'teamcity'
282
+ params[:branch] = ENV['TEAMCITY_BUILD_BRANCH']
283
+ params[:build] = ENV['TEAMCITY_BUILD_ID']
284
+ params[:build_url] = ENV['TEAMCITY_BUILD_URL']
285
+ params[:commit] = ENV['TEAMCITY_BUILD_COMMIT']
286
+ params[:slug] = ENV['TEAMCITY_BUILD_REPOSITORY'].split('/', 4)[-1].sub('.git', '')
287
+ when TRAVIS
288
+ # http://docs.travis-ci.com/user/ci-environment/#Environment-variables
289
+ params[:service] = 'travis'
290
+ params[:branch] = ENV['TRAVIS_BRANCH']
291
+ params[:pull_request] = ENV['TRAVIS_PULL_REQUEST']
292
+ params[:job] = ENV['TRAVIS_JOB_ID']
293
+ params[:slug] = ENV['TRAVIS_REPO_SLUG']
294
+ params[:build] = ENV['TRAVIS_JOB_NUMBER']
295
+ params[:commit] = ENV['TRAVIS_COMMIT']
296
+ params[:env] = ENV['TRAVIS_RUBY_VERSION']
297
+ when WERCKER
298
+ # http://devcenter.wercker.com/articles/steps/variables.html
299
+ params[:service] = 'wercker'
300
+ params[:branch] = ENV['WERCKER_GIT_BRANCH']
301
+ params[:build] = ENV['WERCKER_MAIN_PIPELINE_STARTED']
302
+ params[:slug] = ENV['WERCKER_GIT_OWNER'] + '/' + ENV['WERCKER_GIT_REPOSITORY']
303
+ params[:commit] = ENV['WERCKER_GIT_COMMIT']
304
+ end
305
+
306
+ if params[:branch].nil?
307
+ # find branch, commit, repo from git command
308
+ branch = `git rev-parse --abbrev-ref HEAD`.strip
309
+ params[:branch] = branch != 'HEAD' ? branch : 'master'
310
+ end
311
+
312
+ if !ENV['VCS_COMMIT_ID'].nil?
313
+ params[:commit] = ENV['VCS_COMMIT_ID']
314
+
315
+ elsif params[:commit].nil?
316
+ params[:commit] = `git rev-parse HEAD`.strip
317
+ end
318
+
319
+ slug = ENV['CODECOV_SLUG']
320
+ params[:slug] = slug unless slug.nil?
321
+
322
+ params[:pr] = params[:pr].sub('#', '') unless params[:pr].nil?
323
+
324
+ params
325
+ end
326
+
327
+ def self.retry_request(req, https)
328
+ retries = 3
329
+ begin
330
+ response = https.request(req)
331
+ rescue Timeout::Error, SocketError => e
332
+ retries -= 1
333
+
334
+ if retries.zero?
335
+ puts 'Timeout or connection error uploading coverage reports to Codecov. Out of retries.'
336
+ puts e
337
+ return response
338
+ end
339
+
340
+ puts 'Timeout or connection error uploading coverage reports to Codecov. Retrying...'
341
+ puts e
342
+ retry
343
+ rescue StandardError => e
344
+ puts 'Error uploading coverage reports to Codecov. Sorry'
345
+ puts e.class.name
346
+ puts e
347
+ puts "Backtrace:\n\t#{e.backtrace}"
348
+ return response
349
+ end
350
+
351
+ response
352
+ end
353
+
354
+ def self.gzip_report(report)
355
+ puts [green('==>'), 'Gzipping contents'].join(' ')
356
+
357
+ io = StringIO.new
358
+ gzip = Zlib::GzipWriter.new(io)
359
+ gzip << report
360
+ gzip.close
361
+
362
+ io.string
363
+ end
364
+
365
+ def self.upload_to_codecov(ci, report)
366
+ url = ENV['CODECOV_URL'] || 'https://codecov.io'
367
+ is_enterprise = url != 'https://codecov.io'
368
+
369
+ params = build_params(ci)
370
+ params_secret_token = params.clone
371
+ params_secret_token['token'] = 'secret'
372
+
373
+ query = URI.encode_www_form(params)
374
+ query_without_token = URI.encode_www_form(params_secret_token)
375
+
376
+ gzipped_report = gzip_report(report['codecov'])
377
+
378
+ report['params'] = params
379
+ report['query'] = query
380
+
381
+ puts [green('==>'), 'Uploading reports'].join(' ')
382
+ puts " url: #{url}"
383
+ puts " query: #{query_without_token}"
384
+
385
+ response = false
386
+ unless is_enterprise
387
+ response = upload_to_v4(url, gzipped_report, query, query_without_token)
388
+ return false if response == false
389
+ end
390
+
391
+ response || upload_to_v2(url, gzipped_report, query, query_without_token)
392
+ end
393
+
394
+ def self.upload_to_v4(url, report, query, query_without_token)
395
+ uri = URI.parse(url.chomp('/') + '/upload/v4')
396
+ https = Net::HTTP.new(uri.host, uri.port)
397
+ https.use_ssl = !url.match(/^https/).nil?
398
+
399
+ puts [green('-> '), 'Pinging Codecov'].join(' ')
400
+ puts "#{url}#{uri.path}?#{query_without_token}"
401
+
402
+ req = Net::HTTP::Post.new(
403
+ "#{uri.path}?#{query}",
404
+ {
405
+ 'X-Reduced-Redundancy' => 'false',
406
+ 'X-Content-Encoding' => 'application/x-gzip',
407
+ 'Content-Type' => 'text/plain'
408
+ }
409
+ )
410
+ response = retry_request(req, https)
411
+ if !response&.code || response.code == '400'
412
+ puts red(response&.body)
413
+ return false
414
+ end
415
+
416
+ reports_url = response.body.lines[0]
417
+ s3target = response.body.lines[1]
418
+ puts [green('-> '), 'Uploading to'].join(' ')
419
+ puts s3target
420
+
421
+ uri = URI(s3target)
422
+ https = Net::HTTP.new(uri.host, uri.port)
423
+ https.use_ssl = true
424
+ req = Net::HTTP::Put.new(
425
+ s3target,
426
+ {
427
+ 'Content-Encoding' => 'gzip',
428
+ 'Content-Type' => 'text/plain'
429
+ }
430
+ )
431
+ req.body = report
432
+ res = retry_request(req, https)
433
+ if res&.body == ''
434
+ {
435
+ 'uploaded' => true,
436
+ 'url' => reports_url,
437
+ 'meta' => {
438
+ 'status' => res.code
439
+ },
440
+ 'message' => 'Coverage reports upload successfully'
441
+ }.to_json
442
+ else
443
+ puts [black('-> '), 'Could not upload reports via v4 API, defaulting to v2'].join(' ')
444
+ puts red(res&.body || 'nil')
445
+ nil
446
+ end
447
+ end
448
+
449
+ def self.upload_to_v2(url, report, query, query_without_token)
450
+ uri = URI.parse(url.chomp('/') + '/upload/v2')
451
+ https = Net::HTTP.new(uri.host, uri.port)
452
+ https.use_ssl = !url.match(/^https/).nil?
453
+
454
+ puts [green('-> '), 'Uploading to Codecov'].join(' ')
455
+ puts "#{url}#{uri.path}?#{query_without_token}"
456
+
457
+ req = Net::HTTP::Post.new(
458
+ "#{uri.path}?#{query}",
459
+ {
460
+ 'Accept' => 'application/json',
461
+ 'Content-Encoding' => 'gzip',
462
+ 'Content-Type' => 'text/plain',
463
+ 'X-Content-Encoding' => 'gzip'
464
+ }
465
+ )
466
+ req.body = report
467
+ res = retry_request(req, https)
468
+ res&.body
469
+ end
470
+
471
+ def self.handle_report_response(report)
472
+ if report['result']['uploaded']
473
+ puts " View reports at #{report['result']['url']}"
474
+ else
475
+ puts red(' X> Failed to upload coverage reports')
476
+ end
477
+ end
478
+
479
+ private
480
+
481
+ # Toggle VCR and WebMock on or off
482
+ #
483
+ # @param switch Toggle switch for Net Blockers.
484
+ # @return [Boolean]
485
+ def self.net_blockers(switch)
486
+ throw 'Only :on or :off' unless %i[on off].include? switch
487
+
488
+ if defined?(VCR)
489
+ case switch
490
+ when :on
491
+ VCR.turn_on!
492
+ when :off
493
+ VCR.turn_off!(ignore_cassettes: true)
494
+ end
495
+ end
496
+
497
+ if defined?(WebMock)
498
+ # WebMock on by default
499
+ # VCR depends on WebMock 1.8.11; no method to check whether enabled.
500
+ case switch
501
+ when :on
502
+ WebMock.enable!
503
+ when :off
504
+ WebMock.disable!
505
+ end
506
+ end
507
+
508
+ true
509
+ end
510
+
511
+ # Convenience color methods
512
+ def self.black(str)
513
+ str.nil? ? '' : "\e[30m#{str}\e[0m"
514
+ end
515
+
516
+ def self.red(str)
517
+ str.nil? ? '' : "\e[31m#{str}\e[0m"
518
+ end
519
+
520
+ def self.green(str)
521
+ str.nil? ? '' : "\e[32m#{str}\e[0m"
522
+ end
523
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Codecov
4
- VERSION = '0.2.15'
4
+ VERSION = '0.4.3'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: codecov
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.15
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Peak
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-12-22 00:00:00.000000000 Z
12
+ date: 2021-02-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: simplecov
@@ -20,7 +20,7 @@ dependencies:
20
20
  version: '0.15'
21
21
  - - "<"
22
22
  - !ruby/object:Gem::Version
23
- version: '0.21'
23
+ version: '0.22'
24
24
  type: :runtime
25
25
  prerelease: false
26
26
  version_requirements: !ruby/object:Gem::Requirement
@@ -30,7 +30,7 @@ dependencies:
30
30
  version: '0.15'
31
31
  - - "<"
32
32
  - !ruby/object:Gem::Version
33
- version: '0.21'
33
+ version: '0.22'
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: minitest
36
36
  requirement: !ruby/object:Gem::Requirement
@@ -123,6 +123,8 @@ extensions: []
123
123
  extra_rdoc_files: []
124
124
  files:
125
125
  - lib/codecov.rb
126
+ - lib/codecov/formatter.rb
127
+ - lib/codecov/uploader.rb
126
128
  - lib/codecov/version.rb
127
129
  homepage: https://github.com/codecov/codecov-ruby
128
130
  licenses:
@@ -134,9 +136,12 @@ require_paths:
134
136
  - lib
135
137
  required_ruby_version: !ruby/object:Gem::Requirement
136
138
  requirements:
137
- - - "~>"
139
+ - - ">="
138
140
  - !ruby/object:Gem::Version
139
141
  version: '2.4'
142
+ - - "<"
143
+ - !ruby/object:Gem::Version
144
+ version: '4'
140
145
  required_rubygems_version: !ruby/object:Gem::Requirement
141
146
  requirements:
142
147
  - - ">="