class SimpleCov::Formatter::Codecov

Constants

VERSION

Public Instance Methods

format(result) click to toggle source
# File lib/codecov.rb, line 7
def format(result)
  net_blockers(:off)

  # =================
  # Build JSON Report
  # =================
  report = {
    "meta" => {
      "version" => "codecov-ruby/v"+SimpleCov::Formatter::Codecov::VERSION,
    }
  }
  report.update(result_to_codecov(result))

  json = report.to_json

  # ==============
  # CI Environment
  # ==============
  # add params
  params = {
    "token" => ENV['CODECOV_TOKEN'],
    "flags" => ENV['CODECOV_FLAG'] || ENV['CODECOV_FLAGS']
  }

  # Travis CI
  # ---------
  if ENV['CI'] == "true" and ENV['TRAVIS'] == "true"
      # 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']

  # Codeship
  # --------
  elsif ENV['CI'] == "true" and ENV['CI_NAME'] == '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']

  # Solano
  # --------
  elsif ENV['TDDIUM'] == "true"
      # 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']

  # Circle CI
  # ---------
  elsif ENV['CI'] == "true" and ENV['CIRCLECI'] == 'true'
      # https://circleci.com/docs/environment-variables
      params[:service] = 'circleci'
      params[:build] = ENV['CIRCLE_BUILD_NUM']
      params[:job] = ENV['CIRCLE_NODE_INDEX']
      if ENV['CIRCLE_PROJECT_REPONAME'] != nil
        params[:slug] = ENV['CIRCLE_PROJECT_USERNAME'] + '/' + ENV['CIRCLE_PROJECT_REPONAME']
      else
        params[:slug] = ENV['CIRCLE_REPOSITORY_URL'].gsub(/^.*:/, '').gsub(/\.git$/, '')
      end
      params[:pr] = ENV['CIRCLE_PR_NUMBER']
      params[:branch] = ENV['CIRCLE_BRANCH']
      params[:commit] = ENV['CIRCLE_SHA1']

  # Buildkite
  # ---------
  elsif ENV['CI'] == "true" and ENV['BUILDKITE'] == "true"
    # 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']

  # Semaphore
  # ---------
  elsif ENV['CI'] == "true" and ENV['SEMAPHORE'] == "true"
      # 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']

  # Snap CI
  # -------
  elsif ENV['CI'] == "true" and ENV['SNAP_CI'] == "true"
      # https://docs.snap-ci.com/environment-variables/
      params[:service] = 'snap'
      params[:branch] = ENV['SNAP_BRANCH'] || ENV['SNAP_UPSTREAM_BRANCH']
      params[:commit] = ENV['SNAP_COMMIT'] || ENV['SNAP_UPSTREAM_COMMIT']
      params[:job] = ENV['SNAP_STAGE_NAME']
      params[:build] = ENV['SNAP_PIPELINE_COUNTER']
      params[:pr] = ENV['SNAP_PULL_REQUEST_NUMBER']

  # drone.io
  # --------
  elsif ENV['CI'] == "true" and ENV['DRONE'] == "true"
      # https://semaphoreapp.com/docs/available-environment-variables.html
      params[:service] = 'drone.io'
      params[:branch] = ENV['DRONE_BRANCH']
      params[:job] = ENV['DRONE_JOB_NUMBER']
      params[:build] = ENV['DRONE_BUILD_NUMBER']
      params[:build_url] = ENV['DRONE_BUILD_URL'] || ENV['CI_BUILD_URL']
      params[:pr] = ENV['DRONE_PULL_REQUEST']
      params[:tag] = ENV['DRONE_TAG']

  # Appveyor
  # --------
  elsif ENV['CI'] == "True" and ENV['APPVEYOR'] == 'True'
      # 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']

  # Wercker
  # -------
  elsif ENV['CI'] == "true" and ENV['WERCKER_GIT_BRANCH'] != nil
      # 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']

  # Jenkins
  # --------
  elsif ENV['JENKINS_URL'] != nil
      # 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']

  # Shippable
  # ---------
  elsif ENV['CI'] == 'true' and ENV['SHIPPABLE'] == "true"
      # 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']

  # GitLab CI
  # ---------
  elsif ENV['GITLAB_CI'] != nil
      # http://doc.gitlab.com/ci/examples/README.html#environmental-variables
      # https://gitlab.com/gitlab-org/gitlab-ci-runner/blob/master/lib/build.rb#L96
      params[:service] = 'gitlab'
      params[:branch] = ENV['CI_BUILD_REF_NAME']
      params[:build] = ENV['CI_BUILD_ID']
      params[:slug] = ENV['CI_BUILD_REPO'].split('/', 4)[-1].sub('.git', '')
      params[:commit] = ENV['CI_BUILD_REF']

  # Teamcity
  # ---------
  elsif ENV['CI_SERVER_NAME'] == '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', '')
  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 params[:commit] == nil
      params[:commit] = `git rev-parse HEAD`.strip
  end

  slug = ENV['CODECOV_SLUG']
  if slug != nil
      params[:slug] = slug
  end

  if params[:pr] != nil
    params[:pr] = params[:pr].sub('#', '')
  end

  # =================
  # Build URL Request
  # =================
  url = ENV['CODECOV_URL'] || "https://codecov.io"
  uri = URI.parse(url.chomp('/') + "/upload/v1")

  uri.query = URI.encode_www_form(params)

  # get https
  https = Net::HTTP.new(uri.host, uri.port)
  https.use_ssl = url.match(/^https/) != nil

  begin
    req = Net::HTTP::Post.new(uri.path + "?" + uri.query,
                              {
                                'Content-Type' => 'application/json',
                                'Accept' => 'application/json'
                              })

    req.body = json

    # make resquest
    response = https.request(req)

    # print to output
    puts response.body

    # join the response to report
    report['result'] = JSON.parse(response.body)
    report['params'] = params
    report['query'] = uri.query

    net_blockers(:on)

    # return json data
    report

  rescue StandardError => err
    puts 'Error uploading coverage reports to Codecov. Sorry'
    puts err
  end

end

Private Instance Methods

file_to_codecov(file) click to toggle source

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/codecov.rb, line 308
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
net_blockers(switch) click to toggle source

Toggle VCR and WebMock on or off

@param switch Toggle switch for Net Blockers. @return [Boolean]

# File lib/codecov.rb, line 333
def net_blockers(switch)
  throw 'Only :on or :off' unless [: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

  return true

end
result_to_codecov(result) click to toggle source

Format SimpleCov coverage data for the Codecov.io API.

@param result [SimpleCov::Result] The coverage data to process. @return [Hash]

# File lib/codecov.rb, line 272
def result_to_codecov(result)
  {
    'coverage' => result_to_codecov_coverage(result),
    'messages' => result_to_codecov_messages(result),
  }
end
result_to_codecov_coverage(result) click to toggle source

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/codecov.rb, line 283
def result_to_codecov_coverage(result)
  result.files.inject({}) do |memo, file|
    memo[shortened_filename(file)] = file_to_codecov(file)
    memo
  end
end
result_to_codecov_messages(result) click to toggle source

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/codecov.rb, line 294
def result_to_codecov_messages(result)
  result.files.inject({}) do |memo, file|
    memo[shortened_filename(file)] = file.lines.inject({}) do |lines_memo, line|
      lines_memo[line.line_number.to_s] = 'skipped' if line.skipped?
      lines_memo
    end
    memo
  end
end
shortened_filename(file) click to toggle source

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/codecov.rb, line 324
def shortened_filename(file)
  file.filename.gsub(/^#{SimpleCov.root}/, '.').gsub(/^\.\//, '')
end