class SimpleCov::Formatter::Codecov
Constants
- RECOGNIZED_CIS
CIs
- VERSION
Public Instance Methods
# File lib/yankedcodecov.rb, line 95 def build_params(ci) params = { 'token' => ENV['CODECOV_TOKEN'], 'flags' => ENV['CODECOV_FLAG'] || ENV['CODECOV_FLAGS'] } case ci when APPVEYOR # http://www.appveyor.com/docs/environment-variables params[:service] = 'appveyor' params[:branch] = ENV['APPVEYOR_REPO_BRANCH'] params[:build] = ENV['APPVEYOR_JOB_ID'] params[:pr] = ENV['APPVEYOR_PULL_REQUEST_NUMBER'] params[:job] = ENV['APPVEYOR_ACCOUNT_NAME'] + '/' + ENV['APPVEYOR_PROJECT_SLUG'] + '/' + ENV['APPVEYOR_BUILD_VERSION'] params[:slug] = ENV['APPVEYOR_REPO_NAME'] params[:commit] = ENV['APPVEYOR_REPO_COMMIT'] when AZUREPIPELINES params[:service] = 'azure_pipelines' params[:branch] = ENV['BUILD_SOURCEBRANCH'] params[:pull_request] = ENV['SYSTEM_PULLREQUEST_PULLREQUESTNUMBER'] params[:job] = ENV['SYSTEM_JOBID'] params[:build] = ENV['BUILD_BUILDID'] params[:build_url] = "#{ENV['SYSTEM_TEAMFOUNDATIONSERVERURI']}/#{ENV['SYSTEM_TEAMPROJECT']}/_build/results?buildId=#{ENV['BUILD_BUILDID']}" params[:commit] = ENV['BUILD_SOURCEVERSION'] params[:slug] = ENV['BUILD_REPOSITORY_ID'] when BITBUCKET # https://confluence.atlassian.com/bitbucket/variables-in-pipelines-794502608.html params[:service] = 'bitbucket' params[:branch] = ENV['BITBUCKET_BRANCH'] # BITBUCKET_COMMIT does not always provide full commit sha due to a bug https://jira.atlassian.com/browse/BCLOUD-19393# params[:commit] = (ENV['BITBUCKET_COMMIT'].length < 40 ? nil : ENV['BITBUCKET_COMMIT']) params[:build] = ENV['BITBUCKET_BUILD_NUMBER'] when BITRISE # http://devcenter.bitrise.io/faq/available-environment-variables/ params[:service] = 'bitrise' params[:branch] = ENV['BITRISE_GIT_BRANCH'] params[:pr] = ENV['BITRISE_PULL_REQUEST'] params[:build] = ENV['BITRISE_BUILD_NUMBER'] params[:build_url] = ENV['BITRISE_BUILD_URL'] params[:commit] = ENV['BITRISE_GIT_COMMIT'] params[:slug] = ENV['BITRISEIO_GIT_REPOSITORY_OWNER'] + '/' + ENV['BITRISEIO_GIT_REPOSITORY_SLUG'] when BUILDKITE # https://buildkite.com/docs/guides/environment-variables params[:service] = 'buildkite' params[:branch] = ENV['BUILDKITE_BRANCH'] params[:build] = ENV['BUILDKITE_BUILD_NUMBER'] params[:job] = ENV['BUILDKITE_JOB_ID'] params[:build_url] = ENV['BUILDKITE_BUILD_URL'] params[:slug] = ENV['BUILDKITE_PROJECT_SLUG'] params[:commit] = ENV['BUILDKITE_COMMIT'] when CIRCLE # https://circleci.com/docs/environment-variables params[:service] = 'circleci' params[:build] = ENV['CIRCLE_BUILD_NUM'] params[:job] = ENV['CIRCLE_NODE_INDEX'] params[:slug] = if !ENV['CIRCLE_PROJECT_REPONAME'].nil? ENV['CIRCLE_PROJECT_USERNAME'] + '/' + ENV['CIRCLE_PROJECT_REPONAME'] else ENV['CIRCLE_REPOSITORY_URL'].gsub(/^.*:/, '').gsub(/\.git$/, '') end params[:pr] = ENV['CIRCLE_PR_NUMBER'] params[:branch] = ENV['CIRCLE_BRANCH'] params[:commit] = ENV['CIRCLE_SHA1'] when CODESHIP # https://www.codeship.io/documentation/continuous-integration/set-environment-variables/ params[:service] = 'codeship' params[:branch] = ENV['CI_BRANCH'] params[:commit] = ENV['CI_COMMIT_ID'] params[:build] = ENV['CI_BUILD_NUMBER'] params[:build_url] = ENV['CI_BUILD_URL'] when DRONEIO # https://semaphoreapp.com/docs/available-environment-variables.html params[:service] = 'drone.io' params[:branch] = ENV['DRONE_BRANCH'] params[:commit] = ENV['DRONE_COMMIT_SHA'] params[:job] = ENV['DRONE_JOB_NUMBER'] params[:build] = ENV['DRONE_BUILD_NUMBER'] params[:build_url] = ENV['DRONE_BUILD_LINK'] || ENV['DRONE_BUILD_URL'] || ENV['CI_BUILD_URL'] params[:pr] = ENV['DRONE_PULL_REQUEST'] params[:tag] = ENV['DRONE_TAG'] when GITLAB # http://doc.gitlab.com/ci/examples/README.html#environmental-variables # https://gitlab.com/gitlab-org/gitlab-ci-runner/blob/master/lib/build.rb#L96 # GitLab Runner v9 renamed some environment variables, so we check both old and new variable names. params[:service] = 'gitlab' params[:branch] = ENV['CI_BUILD_REF_NAME'] || ENV['CI_COMMIT_REF_NAME'] params[:build] = ENV['CI_BUILD_ID'] || ENV['CI_JOB_ID'] slug = ENV['CI_BUILD_REPO'] || ENV['CI_REPOSITORY_URL'] params[:slug] = slug.split('/', 4)[-1].sub('.git', '') if slug params[:commit] = ENV['CI_BUILD_REF'] || ENV['CI_COMMIT_SHA'] when HEROKU params[:service] = 'heroku' params[:branch] = ENV['HEROKU_TEST_RUN_BRANCH'] params[:build] = ENV['HEROKU_TEST_RUN_ID'] params[:commit] = ENV['HEROKU_TEST_RUN_COMMIT_VERSION'] when JENKINS # https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project # https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin#GitHubpullrequestbuilderplugin-EnvironmentVariables params[:service] = 'jenkins' params[:branch] = ENV['ghprbSourceBranch'] || ENV['GIT_BRANCH'] params[:commit] = ENV['ghprbActualCommit'] || ENV['GIT_COMMIT'] params[:pr] = ENV['ghprbPullId'] params[:build] = ENV['BUILD_NUMBER'] params[:root] = ENV['WORKSPACE'] params[:build_url] = ENV['BUILD_URL'] when SEMAPHORE # https://semaphoreapp.com/docs/available-environment-variables.html params[:service] = 'semaphore' params[:branch] = ENV['BRANCH_NAME'] params[:commit] = ENV['REVISION'] params[:build] = ENV['SEMAPHORE_BUILD_NUMBER'] params[:job] = ENV['SEMAPHORE_CURRENT_THREAD'] params[:slug] = ENV['SEMAPHORE_REPO_SLUG'] when SHIPPABLE # http://docs.shippable.com/en/latest/config.html#common-environment-variables params[:service] = 'shippable' params[:branch] = ENV['BRANCH'] params[:build] = ENV['BUILD_NUMBER'] params[:build_url] = ENV['BUILD_URL'] params[:pull_request] = ENV['PULL_REQUEST'] params[:slug] = ENV['REPO_NAME'] params[:commit] = ENV['COMMIT'] when SOLANO # http://docs.solanolabs.com/Setup/tddium-set-environment-variables/ params[:service] = 'solano' params[:branch] = ENV['TDDIUM_CURRENT_BRANCH'] params[:commit] = ENV['TDDIUM_CURRENT_COMMIT'] params[:build] = ENV['TDDIUM_TID'] params[:pr] = ENV['TDDIUM_PR_ID'] when TEAMCITY # https://confluence.jetbrains.com/display/TCD8/Predefined+Build+Parameters # Teamcity does not automatically make build parameters available as environment variables. # Add the following environment parameters to the build configuration # env.TEAMCITY_BUILD_BRANCH = %teamcity.build.branch% # env.TEAMCITY_BUILD_ID = %teamcity.build.id% # env.TEAMCITY_BUILD_URL = %teamcity.serverUrl%/viewLog.html?buildId=%teamcity.build.id% # env.TEAMCITY_BUILD_COMMIT = %system.build.vcs.number% # env.TEAMCITY_BUILD_REPOSITORY = %vcsroot.<YOUR TEAMCITY VCS NAME>.url% params[:service] = 'teamcity' params[:branch] = ENV['TEAMCITY_BUILD_BRANCH'] params[:build] = ENV['TEAMCITY_BUILD_ID'] params[:build_url] = ENV['TEAMCITY_BUILD_URL'] params[:commit] = ENV['TEAMCITY_BUILD_COMMIT'] params[:slug] = ENV['TEAMCITY_BUILD_REPOSITORY'].split('/', 4)[-1].sub('.git', '') when TRAVIS # http://docs.travis-ci.com/user/ci-environment/#Environment-variables params[:service] = 'travis' params[:branch] = ENV['TRAVIS_BRANCH'] params[:pull_request] = ENV['TRAVIS_PULL_REQUEST'] params[:job] = ENV['TRAVIS_JOB_ID'] params[:slug] = ENV['TRAVIS_REPO_SLUG'] params[:build] = ENV['TRAVIS_JOB_NUMBER'] params[:commit] = ENV['TRAVIS_COMMIT'] params[:env] = ENV['TRAVIS_RUBY_VERSION'] when WERCKER # http://devcenter.wercker.com/articles/steps/variables.html params[:service] = 'wercker' params[:branch] = ENV['WERCKER_GIT_BRANCH'] params[:build] = ENV['WERCKER_MAIN_PIPELINE_STARTED'] params[:slug] = ENV['WERCKER_GIT_OWNER'] + '/' + ENV['WERCKER_GIT_REPOSITORY'] params[:commit] = ENV['WERCKER_GIT_COMMIT'] end if params[:branch].nil? # find branch, commit, repo from git command branch = `git rev-parse --abbrev-ref HEAD`.strip params[:branch] = branch != 'HEAD' ? branch : 'master' end if !ENV['VCS_COMMIT_ID'].nil? params[:commit] = ENV['VCS_COMMIT_ID'] elsif params[:commit].nil? params[:commit] = `git rev-parse HEAD`.strip end slug = ENV['CODECOV_SLUG'] params[:slug] = slug unless slug.nil? params[:pr] = params[:pr].sub('#', '') unless params[:pr].nil? params end
# File lib/yankedcodecov.rb, line 304 def create_report(report) result = { 'meta' => { 'version' => 'codecov-ruby/v' + SimpleCov::Formatter::Codecov::VERSION } } result.update(result_to_codecov(report)) result end
# File lib/yankedcodecov.rb, line 49 def detect_ci ci = if (ENV['CI'] == 'True') && (ENV['APPVEYOR'] == 'True') APPVEYOR elsif !ENV['TF_BUILD'].nil? AZUREPIPELINES elsif (ENV['CI'] == 'true') && !ENV['BITBUCKET_BRANCH'].nil? BITBUCKET elsif (ENV['CI'] == 'true') && (ENV['BITRISE_IO'] == 'true') BITRISE elsif (ENV['CI'] == 'true') && (ENV['BUILDKITE'] == 'true') BUILDKITE elsif (ENV['CI'] == 'true') && (ENV['CIRCLECI'] == 'true') CIRCLE elsif (ENV['CI'] == 'true') && (ENV['CI_NAME'] == 'codeship') CODESHIP elsif ((ENV['CI'] == 'true') || (ENV['CI'] == 'drone')) && (ENV['DRONE'] == 'true') DRONEIO elsif !ENV['GITLAB_CI'].nil? GITLAB elsif ENV['HEROKU_TEST_RUN_ID'] HEROKU elsif !ENV['JENKINS_URL'].nil? JENKINS elsif (ENV['CI'] == 'true') && (ENV['SEMAPHORE'] == 'true') SEMAPHORE elsif (ENV['CI'] == 'true') && (ENV['SHIPPABLE'] == 'true') SHIPPABLE elsif ENV['TDDIUM'] == 'true' SOLANO elsif ENV['CI_SERVER_NAME'] == 'TeamCity' TEAMCITY elsif (ENV['CI'] == 'true') && (ENV['TRAVIS'] == 'true') TRAVIS elsif (ENV['CI'] == 'true') && !ENV['WERCKER_GIT_BRANCH'].nil? WERCKER end if !RECOGNIZED_CIS.include?(ci) puts ['x>'.red, 'No CI provider detected.'].join(' ') else puts "==> #{ci} detected" end ci end
# File lib/yankedcodecov.rb, line 35 def display_header puts [ '', ' _____ _', ' / ____| | |', '| | ___ __| | ___ ___ _____ __', '| | / _ \ / _\`|/ _ \/ __/ _ \ \ / /', '| |___| (_) | (_| | __/ (_| (_) \ V /', ' \_____\___/ \__,_|\___|\___\___/ \_/', " Ruby-#{VERSION}", '' ].join("\n") end
# File lib/yankedcodecov.rb, line 377 def format(result) net_blockers(:off) display_header ci = detect_ci report = create_report(result) response = upload_to_codecov(ci, report) report['result'] = JSON.parse(response.body) handle_report_response(report) net_blockers(:on) report end
# File lib/yankedcodecov.rb, line 314 def gzip_report(report) puts ['==>'.green, 'Gzipping contents'].join(' ') file = Tempfile.new Zlib::GzipWriter.open(file.path) do |gz| gz.write report end file.rewind gzipped_report = file.read file.close gzipped_report end
# File lib/yankedcodecov.rb, line 369 def handle_report_response(report) if report['result']['uploaded'] puts " View reports at #{report['result']['url']}" else puts ' X> Failed to upload coverage reports'.red end end
# File lib/yankedcodecov.rb, line 279 def retry_request(req, https) retries = 3 begin response = https.request(req) rescue Timeout::Error => e retries -= 1 if retries.zero? puts 'Timeout error uploading coverage reports to Codecov. Out of retries.' puts e return response end puts 'Timeout error uploading coverage reports to Codecov. Retrying...' puts e retry rescue StandardError => e puts 'Error uploading coverage reports to Codecov. Sorry' puts e return response end response end
# File lib/yankedcodecov.rb, line 328 def upload_to_codecov(ci, report) url = ENV['CODECOV_URL'] || 'https://codecov.io' params = build_params(ci) params_secret_token = params.clone params_secret_token['token'] = 'secret' query = URI.encode_www_form(params) query_without_token = URI.encode_www_form(params_secret_token) gzipped_report = gzip_report(report) report['params'] = params report['query'] = query puts ['==>'.green, 'Uploading reports'].join(' ') puts " url: #{url}" puts " query: #{query_without_token}" upload_to_v2(url, gzipped_report, query, query_without_token) end
# File lib/yankedcodecov.rb, line 350 def upload_to_v2(url, report, query, query_without_token) uri = URI.parse(url.chomp('/') + '/upload/v2') https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = !url.match(/^https/).nil? puts ['-> '.green, 'Uploading to Codecov'].join(' ') puts "#{url}/#{uri.path}?#{query_without_token}" req = Net::HTTP::Post.new( "#{uri.path}?#{query}", { 'X-Reduced-Redundancy' => 'false', 'Content-Type' => 'text/plain' } ) req.body = report retry_request(req, https) end
Private Instance Methods
Format coverage data for a single file for the Codecov.io API.
@param file [SimpleCov::SourceFile] The file to process. @return [Array<nil, Integer>]
# File lib/yankedcodecov.rb, line 429 def file_to_codecov(file) # Initial nil is required to offset line numbers. [nil] + file.lines.map do |line| if line.skipped? nil else line.coverage end end end
Toggle VCR and WebMock on or off
@param switch Toggle switch for Net Blockers. @return [Boolean]
# File lib/yankedcodecov.rb, line 453 def net_blockers(switch) throw 'Only :on or :off' unless %i[on off].include? switch if defined?(VCR) case switch when :on VCR.turn_on! when :off VCR.turn_off!(ignore_cassettes: true) end end if defined?(WebMock) # WebMock on by default # VCR depends on WebMock 1.8.11; no method to check whether enabled. case switch when :on WebMock.enable! when :off WebMock.disable! end end true end
Format SimpleCov
coverage data for the Codecov.io API.
@param result [SimpleCov::Result] The coverage data to process. @return [Hash]
# File lib/yankedcodecov.rb, line 396 def result_to_codecov(result) { 'coverage' => result_to_codecov_coverage(result), 'messages' => result_to_codecov_messages(result) } end
Format SimpleCov
coverage data for the Codecov.io coverage API.
@param result [SimpleCov::Result] The coverage data to process. @return [Hash<String, Array>]
# File lib/yankedcodecov.rb, line 407 def result_to_codecov_coverage(result) result.files.each_with_object({}) do |file, memo| memo[shortened_filename(file)] = file_to_codecov(file) end end
Format SimpleCov
coverage data for the Codecov.io messages API.
@param result [SimpleCov::Result] The coverage data to process. @return [Hash<String, Hash>]
# File lib/yankedcodecov.rb, line 417 def result_to_codecov_messages(result) result.files.each_with_object({}) do |file, memo| memo[shortened_filename(file)] = file.lines.each_with_object({}) do |line, lines_memo| lines_memo[line.line_number.to_s] = 'skipped' if line.skipped? end end end
Get a filename relative to the project root. Based on github.com/colszowka/simplecov-html, copyright Christoph Olszowka.
@param file [SimeplCov::SourceFile] The file to use. @return [String]
# File lib/yankedcodecov.rb, line 445 def shortened_filename(file) file.filename.gsub(/^#{SimpleCov.root}/, '.').gsub(%r{^\./}, '') end