├── .circleci └── config.yml ├── .editorconfig ├── .github ├── dependabot.yml └── workflows │ └── ruby.yml ├── .gitignore ├── CHANGELOG.md ├── Gemfile ├── LICENSE ├── Makefile ├── README.md ├── Rakefile ├── codecov.gemspec ├── codecov.yml ├── lib ├── codecov.rb └── codecov │ ├── configuration.rb │ ├── formatter.rb │ ├── uploader.rb │ └── version.rb └── test ├── helper.rb └── test_codecov.rb /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | jobs: 4 | build: # our first job, named "build" 5 | docker: 6 | - image: circleci/ruby:2.7 7 | steps: 8 | - checkout # pull down our git code. 9 | - run: 10 | name: Install bundler 11 | command: gem install bundler 12 | - run: 13 | name: Bundle install 14 | command: bundle install 15 | - run: 16 | name: Run rakefile 17 | command: bundle exec rake 18 | - store_test_results: 19 | path: '.' 20 | 21 | workflow: 22 | version: 2.1 23 | build-test: 24 | jobs: 25 | - build 26 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: bundler 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | -------------------------------------------------------------------------------- /.github/workflows/ruby.yml: -------------------------------------------------------------------------------- 1 | name: Ruby 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | ruby: 11 | - 2.4 12 | - 2.5 13 | - 2.6 14 | - 2.7 15 | - 3.0 16 | - head 17 | - jruby 18 | - jruby-head 19 | steps: 20 | - uses: actions/checkout@v2 21 | - name: Set up Ruby 22 | uses: ruby/setup-ruby@v1 23 | with: 24 | ruby-version: ${{ matrix.ruby }} 25 | # Runs 'bundle install' and caches installed gems automatically 26 | bundler-cache: true 27 | - name: Run tests 28 | run: bundle exec rake 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | /.config 4 | /coverage/ 5 | /InstalledFiles 6 | /pkg/ 7 | /spec/reports/ 8 | /test/tmp/ 9 | /test/version_tmp/ 10 | /test/reports/ 11 | /tmp/ 12 | 13 | ## Specific to RubyMotion: 14 | .dat* 15 | .repl_history 16 | build/ 17 | 18 | ## Documentation cache and generated files: 19 | /.yardoc/ 20 | /_yardoc/ 21 | /doc/ 22 | /rdoc/ 23 | 24 | ## Environment normalisation: 25 | /.bundle/ 26 | /lib/bundler/man/ 27 | 28 | # for a library or gem, you might want to ignore these files since the code is 29 | # intended to run in multiple environments; otherwise, check them in: 30 | # Gemfile.lock 31 | # .ruby-version 32 | # .ruby-gemset 33 | 34 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 35 | .rvmrc 36 | 37 | .DS_Store 38 | 39 | vendor 40 | coverage 41 | 42 | Gemfile.lock 43 | tmp.json 44 | 45 | *.sw[opn] 46 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### `0.6.0` 2 | - #145 Fixes issue with nil URI and provides more token information 3 | 4 | ### `0.5.2` 5 | - #141 Add Cirrus CI support 6 | 7 | ### `0.5.1` 8 | - #138 Update pass_ci_if_error flag 9 | 10 | ### `0.5.0` 11 | - #137 Place uploader in try/rescue block and add pass_ci_if_error flag 12 | 13 | ### `0.4.3` 14 | - #135 Shorten coverage message on formatter 15 | 16 | ### `0.4.2` 17 | - #134 Wrap file creation in try/catch 18 | 19 | ### `0.4.1` 20 | - #133 Write down to file when using the formatter 21 | 22 | ### `0.4.0` 23 | - #130 Split uploader from formatter 24 | 25 | ### `0.3.0` 26 | - #124 Ruby 3.0 support 27 | - #125 open simplecov requirement to 0.21.x 28 | 29 | ### `0.2.15` 30 | - #118 Include codecov/version in the gem 31 | 32 | ### `0.2.14` 33 | - #107 Add EditorConfig file 34 | - #113 Return version constant, don't duplicate version value 35 | - #117 Update simplecov dependency versions 36 | 37 | ### `0.2.13` 38 | - [#105](https://github.com/codecov/codecov-ruby/pull/105) Remove unnecessary dependency for ruby standard gem 39 | - [#110](https://github.com/codecov/codecov-ruby/pull/110) Fix GitHub Actions 40 | - [#111](https://github.com/codecov/codecov-ruby/pull/111) Fix branch name detection for GitHub Actions CI 41 | 42 | ### `0.2.12` 43 | - [#102](https://github.com/codecov/codecov-ruby/pull/102) Fix value of params[:pr] when useing CodeBuild 44 | 45 | ### `0.2.11` 46 | - Add vendor/ to invalid directories 47 | 48 | ### `0.2.10` 49 | - Adds better logging on error cases 50 | - Add more invalid directories in the network 51 | 52 | ### `0.2.9` 53 | - Remove `String` specific colors 54 | - Add support for Codebuild CI 55 | 56 | ### `0.2.8` 57 | - Remove `colorize` dependency 58 | 59 | ### `0.2.7` 60 | - Fix for enterprise users unable to upload using the v4 uploader 61 | 62 | ### `0.2.6` 63 | - Fix issue with `push` events on GitHub Actions 64 | 65 | ### `0.2.5` 66 | - Revert single use of VERSION 67 | 68 | ### `0.2.4` 69 | - Adds support for GitHub Actions CI 70 | 71 | ### `0.2.3` 72 | - Support uploads for jruby 9.1 and 9.2 73 | 74 | ### `0.2.2` 75 | - Handle SocketError and better error handling of v4 failures 76 | 77 | ### `0.2.1` 78 | - Properly handle 400 cases when using the v4 endpoint 79 | 80 | ### `0.2.0` 81 | - move to the v4 upload endpoint with the v2 as a fallback 82 | 83 | ### `0.1.20` 84 | - fix critical upload issues on V2 endpoint 85 | 86 | ### `0.1.19` 87 | - fix colorize 88 | 89 | ### `0.1.18` 90 | - refactor and move to use v2 endpoint 91 | - use Timeout::Error 92 | 93 | ### `0.1.17` 94 | - refactor upload method and add more logging 95 | 96 | ### `0.1.10` 97 | - update numerous ci environments 98 | - dont fail if cannot upload to codecov 99 | 100 | ### `0.1.3` 101 | - add buildkite 102 | 103 | ### `0.1.2` 104 | - add slug argument 105 | - use slug for uploading 106 | - add Accept to uploads 107 | 108 | ### `0.1.1` 109 | - fix #6, thanks @justmatt 110 | - add semaphore thread number 111 | 112 | ### `0.1.0` 113 | - added more CircleCI env 114 | 115 | ### `0.0.11` 116 | - send AppVeyor pr# with reports 117 | 118 | ### `0.0.10` 119 | - fix AppVeyor for public repos 120 | 121 | ### `0.0.9` 122 | - remove tmp.json creation 123 | 124 | ### `0.0.8` 125 | - added more jenkins environment references 126 | 127 | ### `0.0.7` 128 | - added GitLab CI Runner support 129 | 130 | ### `0.0.5` 131 | - added line messages by @coderanger 132 | - fixed skip lines during reporting by @coderanger 133 | 134 | ### `0.0.4` 135 | - added more test 136 | - added more CI providers 137 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License (MIT) 2 | 3 | Copyright (c) 2015 Codecov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test install build deploy 2 | 3 | deploy: 4 | $(eval VERSION := $(shell cat lib/codecov/version.rb | grep 'VERSION = ' | cut -d\' -f2)) 5 | git tag v$(VERSION) -m "" 6 | git push origin v$(VERSION) 7 | gem build codecov.gemspec 8 | gem push codecov-$(VERSION).gem 9 | 10 | install: 11 | rm -rf vendor .bundle 12 | bundle install 13 | 14 | test: 15 | bundle exec rake 16 | 17 | compare: 18 | hub compare $(shell git tag --sort=refname | tail -1)...master 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 🚨🚨 Deprecation Notice 🚨🚨 2 | 3 | This uploader is being deprecated by the Codecov team. We recommend migrating to our [new uploader](https://docs.codecov.com/docs/codecov-uploader) as soon as possible to prevent any lapses in coverage. 4 | 5 | You can visit our [migration guide](https://docs.codecov.com/docs/deprecated-uploader-migration-guide#ruby-uploader) for help moving to our new uploader, and our blog post to learn more about our [deprecation plan](https://about.codecov.io/blog/codecov-uploader-deprecation-plan/), 6 | 7 | **On February 1, 2022 this uploader will be completely deprecated and will no longer be able to upload coverage to Codecov.** 8 | 9 | # Codecov Ruby Uploader 10 | 11 | [![Codecov](https://codecov.io/github/codecov/codecov-ruby/coverage.svg?branch=master)](https://codecov.io/github/codecov/codecov-ruby?branch=master) 12 | [![Gem Version](https://badge.fury.io/rb/codecov.svg)](https://rubygems.org/gems/codecov) 13 | [![Build Status](https://secure.travis-ci.org/codecov/codecov-ruby.svg?branch=master)](http://travis-ci.org/codecov/codecov-ruby) 14 | [![Codecov](https://circleci.com/gh/codecov/codecov-ruby.svg?style=svg)](https://circleci.com/gh/codecov/codecov-ruby) 15 | [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fcodecov%2Fcodecov-ruby.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fcodecov%2Fcodecov-ruby?ref=badge_shield) 16 | 17 | 18 | [Codecov.io](https://codecov.io/) upload support for Ruby. 19 | 20 | ## Quick Start 21 | 22 | Add to your `Gemfile`: 23 | 24 | ```ruby 25 | gem 'codecov', require: false, group: 'test' 26 | ``` 27 | 28 | Add to the top of your `tests/helper.rb` file: 29 | 30 | ```ruby 31 | require 'simplecov' 32 | SimpleCov.start 33 | 34 | require 'codecov' 35 | SimpleCov.formatter = SimpleCov::Formatter::Codecov 36 | ``` 37 | 38 | Add CI Environment Variable: 39 | 40 | ```sh 41 | CODECOV_TOKEN="your repo token" 42 | ``` 43 | 44 | Find you repo token on your repo page at [codecov.io](https://codecov.io). 45 | Repo tokens are **not** required for public repos on Travis-Ci, CircleCI, or AppVeyor CI. 46 | 47 | ## Supported CIs 48 | | CI/CD | 49 | | ----- | 50 | | [AppVeyor CI](https://www.appveyor.com/) | 51 | | [Azure Pipelines](https://azure.microsoft.com/en-us/services/devops/pipelines/) | 52 | | [Bitbucket Pipelines](https://bitbucket.org/product/features/pipelines) | 53 | | [Bitrise CI](https://www.bitrise.io/) | 54 | | [Buildkite CI](https://buildkite.com/) | 55 | | [CodeBuild CI](https://aws.amazon.com/codebuild/) | 56 | | [CodePipeline](https://aws.amazon.com/codepipeline/) | 57 | | [Circle CI](https://circleci.com/) | 58 | | [Codeship CI](https://codeship.com/) | 59 | | [Drone CI](https://drone.io/) | 60 | | [GitLab CI](https://docs.gitlab.com/ee/ci/) | 61 | | [Heroku CI](https://www.heroku.com/continuous-integration) | 62 | | [Jenkins CI](https://www.jenkins.io/) | 63 | | [Semaphore CI](https://semaphoreci.com/) | 64 | | [Shippable](https://www.shippable.com/) | 65 | | [Solano CI](https://xebialabs.com/technology/solano-ci/) | 66 | | [TeamCity CI](https://www.jetbrains.com/teamcity/) | 67 | | [Travis CI](https://travis-ci.org/) | 68 | | [Wercker CI](https://devcenter.wercker.com/) | 69 | 70 | ## Advanced Usage 71 | 72 | #### Submit only in CI example 73 | 74 | ```ruby 75 | if ENV['CI'] == 'true' 76 | require 'codecov' 77 | SimpleCov.formatter = SimpleCov::Formatter::Codecov 78 | end 79 | ``` 80 | 81 | ## Useful Links 82 | 83 | [FAQ](https://docs.codecov.io/docs/frequently-asked-questions) 84 | [Recipe List](https://docs.codecov.io/docs/common-recipe-list) 85 | [Error Reference](https://docs.codecov.io/docs/error-reference) 86 | [Changelog](./CHANGELOG.md) 87 | [Support](https://codecov.io/support) 88 | [Community Boards](https://community.codecov.io) 89 | 90 | ## Caveats 91 | 92 | 1. There are known issues when `Simplecov.track_files` is enabled. We recommend that you require all code files in your tests so that SimpleCov can provide Codecov with properly mapped coverage report metrics. [codecov/support#133]( https://github.com/codecov/support/issues/133) 93 | - https://github.com/colszowka/simplecov/blob/master/README.md#default-root-filter-and-coverage-for-things-outside-of-it 94 | 2. `git` must be installed. 95 | - https://github.com/codecov/codecov-ruby/blob/5e3dae3/lib/codecov.rb#L284-L295 96 | 97 | ## Maintainers 98 | 99 | - [thomasrockhu](https://github.com/thomasrockhu) 100 | 101 | ## Enterprise 102 | 103 | For companies using Codecov Enterprise you will need to specify the following parameters: 104 | 105 | ```sh 106 | CODECOV_URL="https://codecov.mycompany.com" 107 | CODECOV_SLUG="owner/repo" 108 | CODECOV_TOKEN="repository token or global token" 109 | ``` 110 | 111 | ## License 112 | [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fcodecov%2Fcodecov-ruby.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fcodecov%2Fcodecov-ruby?ref=badge_large) 113 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler' 4 | require 'rubygems' 5 | require 'rake/testtask' 6 | 7 | helper = Bundler::GemHelper.new 8 | helper.install_gem 9 | Bundler::GemHelper.install_tasks 10 | 11 | Rake::TestTask.new(:test) do |test| 12 | test.libs << 'lib' << 'test' 13 | test.pattern = 'test/test_*.rb' 14 | test.verbose = true 15 | end 16 | 17 | task default: :test 18 | -------------------------------------------------------------------------------- /codecov.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'lib/codecov/version' 4 | 5 | Gem::Specification.new do |s| 6 | s.name = 'codecov' 7 | s.authors = ['Steve Peak', 'Tom Hu'] 8 | s.summary = 'Hosted code coverage' 9 | s.description = 'Hosted code coverage Ruby reporter.' 10 | s.email = ['hello@codecov.io'] 11 | s.files = Dir[ 12 | 'lib/**/*.rb', 'README.md', 'LICENSE', 'CHANGELOG.md' 13 | ] 14 | s.license = 'MIT' 15 | s.version = ::Codecov::VERSION 16 | 17 | github_uri = 'https://github.com/codecov/codecov-ruby' 18 | 19 | s.homepage = github_uri 20 | 21 | s.metadata = { 22 | 'bug_tracker_uri' => "#{github_uri}/issues", 23 | 'changelog_uri' => "#{github_uri}/blob/v#{s.version}/CHANGELOG.md", 24 | 'documentation_uri' => 25 | "http://www.rubydoc.info/gems/#{s.name}/#{s.version}", 26 | 'homepage_uri' => s.homepage, 27 | 'source_code_uri' => github_uri 28 | } 29 | 30 | s.platform = Gem::Platform::RUBY 31 | s.required_ruby_version = '>= 2.4', '< 4' 32 | 33 | s.add_dependency 'simplecov', '>= 0.15', '< 0.22' 34 | 35 | s.add_development_dependency 'minitest', '~> 5.0' 36 | s.add_development_dependency 'mocha', '~> 1.0' 37 | s.add_development_dependency 'rake', '~> 13.0' 38 | s.add_development_dependency 'rubocop', '~> 1.0' 39 | s.add_development_dependency 'webmock', '~> 3.0' 40 | end 41 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | informational: true 6 | patch: 7 | default: 8 | informational: true 9 | -------------------------------------------------------------------------------- /lib/codecov.rb: -------------------------------------------------------------------------------- 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 'codecov/formatter' 10 | require_relative 'codecov/uploader' 11 | 12 | class SimpleCov::Formatter::Codecov 13 | def format(result, disable_net_blockers = true) 14 | report = Codecov::SimpleCov::Formatter.new.format(result) 15 | Codecov::Uploader.upload(report, disable_net_blockers) 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/codecov/configuration.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Codecov 4 | module Configuration 5 | attr_accessor :pass_ci_if_error 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/codecov/formatter.rb: -------------------------------------------------------------------------------- 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 | 'storage/', 63 | 'tmp/', 64 | 'vendor/' 65 | ] 66 | 67 | network = [] 68 | Dir['**/*'].keep_if do |file| 69 | if File.file?(file) && !file.end_with?(*invalid_file_types) && invalid_directories.none? { |dir| file.include?(dir) } 70 | network.push(file) 71 | end 72 | end 73 | 74 | network.push('<<<<<< network') 75 | network 76 | end 77 | 78 | # Format SimpleCov coverage data for the Codecov.io coverage API. 79 | # 80 | # @param result [SimpleCov::Result] The coverage data to process. 81 | # @return [Hash] 82 | def result_to_codecov_coverage(result) 83 | result.files.each_with_object({}) do |file, memo| 84 | memo[shortened_filename(file)] = file_to_codecov(file) 85 | end 86 | end 87 | 88 | # Format SimpleCov coverage data for the Codecov.io messages API. 89 | # 90 | # @param result [SimpleCov::Result] The coverage data to process. 91 | # @return [Hash] 92 | def result_to_codecov_messages(result) 93 | result.files.each_with_object({}) do |file, memo| 94 | memo[shortened_filename(file)] = file.lines.each_with_object({}) do |line, lines_memo| 95 | lines_memo[line.line_number.to_s] = 'skipped' if line.skipped? 96 | end 97 | end 98 | end 99 | 100 | # Format coverage data for a single file for the Codecov.io API. 101 | # 102 | # @param file [SimpleCov::SourceFile] The file to process. 103 | # @return [Array] 104 | def file_to_codecov(file) 105 | # Initial nil is required to offset line numbers. 106 | [nil] + file.lines.map do |line| 107 | if line.skipped? 108 | nil 109 | else 110 | line.coverage 111 | end 112 | end 113 | end 114 | 115 | # Get a filename relative to the project root. Based on 116 | # https://github.com/colszowka/simplecov-html, copyright Christoph Olszowka. 117 | # 118 | # @param file [SimpleCov::SourceFile] The file to use. 119 | # @return [String] 120 | def shortened_filename(file) 121 | file.filename.gsub(/^#{::SimpleCov.root}/, '.').gsub(%r{^\./}, '') 122 | end 123 | end 124 | end 125 | end 126 | -------------------------------------------------------------------------------- /lib/codecov/uploader.rb: -------------------------------------------------------------------------------- 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 | CIRRUS = 'Cirrus CI', 21 | CODEBUILD = 'Codebuild CI', 22 | CODESHIP = 'Codeship CI', 23 | DRONEIO = 'Drone CI', 24 | GITHUB = 'GitHub Actions', 25 | GITLAB = 'GitLab CI', 26 | HEROKU = 'Heroku CI', 27 | JENKINS = 'Jenkins CI', 28 | SEMAPHORE = 'Semaphore CI', 29 | SHIPPABLE = 'Shippable', 30 | SOLANO = 'Solano CI', 31 | TEAMCITY = 'TeamCity CI', 32 | TRAVIS = 'Travis CI', 33 | WERCKER = 'Wercker CI' 34 | ].freeze 35 | 36 | def self.upload(report, disable_net_blockers = true) 37 | net_blockers(:off) if disable_net_blockers 38 | 39 | display_header 40 | ci = detect_ci 41 | 42 | begin 43 | response = upload_to_codecov(ci, report) 44 | rescue StandardError => e 45 | puts e.message 46 | puts e.backtrace.join("\n") 47 | raise e unless ::Codecov.pass_ci_if_error 48 | 49 | response = false 50 | end 51 | 52 | net_blockers(:on) if disable_net_blockers 53 | 54 | unless response 55 | report['result'] = { 'uploaded' => false } 56 | raise StandardError.new 'Could not upload reports to Codecov' unless ::Codecov.pass_ci_if_error 57 | return report 58 | end 59 | report['result'] = JSON.parse(response) 60 | handle_report_response(report) 61 | report 62 | end 63 | 64 | def self.display_header 65 | puts [ 66 | '', 67 | ' _____ _', 68 | ' / ____| | |', 69 | '| | ___ __| | ___ ___ _____ __', 70 | '| | / _ \ / _\`|/ _ \/ __/ _ \ \ / /', 71 | '| |___| (_) | (_| | __/ (_| (_) \ V /', 72 | ' \_____\___/ \__,_|\___|\___\___/ \_/', 73 | " Ruby-#{::Codecov::VERSION}", 74 | '' 75 | ].join("\n") 76 | end 77 | 78 | def self.detect_ci 79 | ci = if (ENV['CI'] == 'True') && (ENV['APPVEYOR'] == 'True') 80 | APPVEYOR 81 | elsif !ENV['TF_BUILD'].nil? 82 | AZUREPIPELINES 83 | elsif (ENV['CI'] == 'true') && !ENV['BITBUCKET_BRANCH'].nil? 84 | BITBUCKET 85 | elsif (ENV['CI'] == 'true') && (ENV['BITRISE_IO'] == 'true') 86 | BITRISE 87 | elsif (ENV['CI'] == 'true') && (ENV['BUILDKITE'] == 'true') 88 | BUILDKITE 89 | elsif (ENV['CI'] == 'true') && (ENV['CIRCLECI'] == 'true') 90 | CIRCLE 91 | elsif !ENV['CIRRUS_CI'].nil? 92 | CIRRUS 93 | elsif ENV['CODEBUILD_CI'] == 'true' 94 | CODEBUILD 95 | elsif (ENV['CI'] == 'true') && (ENV['CI_NAME'] == 'codeship') 96 | CODESHIP 97 | elsif ((ENV['CI'] == 'true') || (ENV['CI'] == 'drone')) && (ENV['DRONE'] == 'true') 98 | DRONEIO 99 | elsif (ENV['CI'] == 'true') && (ENV['GITHUB_ACTIONS'] == 'true') 100 | GITHUB 101 | elsif !ENV['GITLAB_CI'].nil? 102 | GITLAB 103 | elsif ENV['HEROKU_TEST_RUN_ID'] 104 | HEROKU 105 | elsif !ENV['JENKINS_URL'].nil? 106 | JENKINS 107 | elsif (ENV['CI'] == 'true') && (ENV['SEMAPHORE'] == 'true') 108 | SEMAPHORE 109 | elsif (ENV['CI'] == 'true') && (ENV['SHIPPABLE'] == 'true') 110 | SHIPPABLE 111 | elsif ENV['TDDIUM'] == 'true' 112 | SOLANO 113 | elsif ENV['CI_SERVER_NAME'] == 'TeamCity' 114 | TEAMCITY 115 | elsif (ENV['CI'] == 'true') && (ENV['TRAVIS'] == 'true') 116 | TRAVIS 117 | elsif (ENV['CI'] == 'true') && !ENV['WERCKER_GIT_BRANCH'].nil? 118 | WERCKER 119 | end 120 | 121 | if !RECOGNIZED_CIS.include?(ci) 122 | puts [red('x>'), 'No CI provider detected.'].join(' ') 123 | else 124 | puts "==> #{ci} detected" 125 | end 126 | 127 | ci 128 | end 129 | 130 | def self.build_params(ci) 131 | puts [red('x>'), 'No token specified or token is empty'].join(' ') if 132 | ENV['CODECOV_TOKEN'].nil? || ENV['CODECOV_TOKEN'].empty? 133 | 134 | params = { 135 | 'token' => ENV['CODECOV_TOKEN'], 136 | 'flags' => ENV['CODECOV_FLAG'] || ENV['CODECOV_FLAGS'], 137 | 'package' => "ruby-#{::Codecov::VERSION}" 138 | } 139 | 140 | case ci 141 | when APPVEYOR 142 | # http://www.appveyor.com/docs/environment-variables 143 | params[:service] = 'appveyor' 144 | params[:branch] = ENV['APPVEYOR_REPO_BRANCH'] 145 | params[:build] = ENV['APPVEYOR_JOB_ID'] 146 | params[:pr] = ENV['APPVEYOR_PULL_REQUEST_NUMBER'] 147 | params[:job] = ENV['APPVEYOR_ACCOUNT_NAME'] + '/' + ENV['APPVEYOR_PROJECT_SLUG'] + '/' + ENV['APPVEYOR_BUILD_VERSION'] 148 | params[:slug] = ENV['APPVEYOR_REPO_NAME'] 149 | params[:commit] = ENV['APPVEYOR_REPO_COMMIT'] 150 | when AZUREPIPELINES 151 | params[:service] = 'azure_pipelines' 152 | params[:branch] = ENV['BUILD_SOURCEBRANCH'] 153 | params[:pull_request] = ENV['SYSTEM_PULLREQUEST_PULLREQUESTNUMBER'] 154 | params[:job] = ENV['SYSTEM_JOBID'] 155 | params[:build] = ENV['BUILD_BUILDID'] 156 | params[:build_url] = "#{ENV['SYSTEM_TEAMFOUNDATIONSERVERURI']}/#{ENV['SYSTEM_TEAMPROJECT']}/_build/results?buildId=#{ENV['BUILD_BUILDID']}" 157 | params[:commit] = ENV['BUILD_SOURCEVERSION'] 158 | params[:slug] = ENV['BUILD_REPOSITORY_ID'] 159 | when BITBUCKET 160 | # https://confluence.atlassian.com/bitbucket/variables-in-pipelines-794502608.html 161 | params[:service] = 'bitbucket' 162 | params[:branch] = ENV['BITBUCKET_BRANCH'] 163 | # BITBUCKET_COMMIT does not always provide full commit sha due to a bug https://jira.atlassian.com/browse/BCLOUD-19393# 164 | params[:commit] = (ENV['BITBUCKET_COMMIT'].length < 40 ? nil : ENV['BITBUCKET_COMMIT']) 165 | params[:build] = ENV['BITBUCKET_BUILD_NUMBER'] 166 | when BITRISE 167 | # http://devcenter.bitrise.io/faq/available-environment-variables/ 168 | params[:service] = 'bitrise' 169 | params[:branch] = ENV['BITRISE_GIT_BRANCH'] 170 | params[:pr] = ENV['BITRISE_PULL_REQUEST'] 171 | params[:build] = ENV['BITRISE_BUILD_NUMBER'] 172 | params[:build_url] = ENV['BITRISE_BUILD_URL'] 173 | params[:commit] = ENV['BITRISE_GIT_COMMIT'] 174 | params[:slug] = ENV['BITRISEIO_GIT_REPOSITORY_OWNER'] + '/' + ENV['BITRISEIO_GIT_REPOSITORY_SLUG'] 175 | when BUILDKITE 176 | # https://buildkite.com/docs/guides/environment-variables 177 | params[:service] = 'buildkite' 178 | params[:branch] = ENV['BUILDKITE_BRANCH'] 179 | params[:build] = ENV['BUILDKITE_BUILD_NUMBER'] 180 | params[:job] = ENV['BUILDKITE_JOB_ID'] 181 | params[:build_url] = ENV['BUILDKITE_BUILD_URL'] 182 | params[:slug] = ENV['BUILDKITE_PROJECT_SLUG'] 183 | params[:commit] = ENV['BUILDKITE_COMMIT'] 184 | when CIRCLE 185 | # https://circleci.com/docs/environment-variables 186 | params[:service] = 'circleci' 187 | params[:build] = ENV['CIRCLE_BUILD_NUM'] 188 | params[:job] = ENV['CIRCLE_NODE_INDEX'] 189 | params[:slug] = if !ENV['CIRCLE_PROJECT_REPONAME'].nil? 190 | ENV['CIRCLE_PROJECT_USERNAME'] + '/' + ENV['CIRCLE_PROJECT_REPONAME'] 191 | else 192 | ENV['CIRCLE_REPOSITORY_URL'].gsub(/^.*:/, '').gsub(/\.git$/, '') 193 | end 194 | params[:pr] = ENV['CIRCLE_PR_NUMBER'] 195 | params[:branch] = ENV['CIRCLE_BRANCH'] 196 | params[:commit] = ENV['CIRCLE_SHA1'] 197 | when CIRRUS 198 | # https://cirrus-ci.org/guide/writing-tasks/#environment-variables 199 | params[:branch] = ENV['CIRRUS_BRANCH'] 200 | params[:build] = ENV['CIRRUS_BUILD_ID'] 201 | params[:build_url] = "https://cirrus-ci.com/tasks/#{ENV['CIRRUS_TASK_ID']}" 202 | params[:commit] = ENV['CIRRUS_CHANGE_IN_REPO'] 203 | params[:job] = ENV['CIRRUS_TASK_NAME'] 204 | params[:pr] = ENV['CIRRUS_PR'] 205 | params[:service] = 'cirrus-ci' 206 | params[:slug] = ENV['CIRRUS_REPO_FULL_NAME'] 207 | when CODEBUILD 208 | # https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html 209 | # To use CodePipeline as CodeBuild source which sets no branch and slug variable: 210 | # 211 | # 1. Set up CodeStarSourceConnection as source action provider 212 | # https://docs.aws.amazon.com/codepipeline/latest/userguide/action-reference-CodestarConnectionSource.html 213 | # 2. Add a Namespace to your source action. Example: "CodeStar". 214 | # https://docs.aws.amazon.com/codepipeline/latest/userguide/reference-variables.html#reference-variables-concepts-namespaces 215 | # 3. Add these environment variables to your CodeBuild action: 216 | # - CODESTAR_BRANCH_NAME: #{CodeStar.BranchName} 217 | # - CODESTAR_FULL_REPOSITORY_NAME: #{CodeStar.FullRepositoryName} (optional) 218 | # https://docs.aws.amazon.com/codepipeline/latest/userguide/action-reference-CodeBuild.html#action-reference-CodeBuild-config 219 | # 220 | # PRs are not supported with CodePipeline. 221 | params[:service] = 'codebuild' 222 | params[:branch] = ENV['CODEBUILD_WEBHOOK_HEAD_REF']&.split('/')&.[](2) || ENV['CODESTAR_BRANCH_NAME'] 223 | params[:build] = ENV['CODEBUILD_BUILD_ID'] 224 | params[:commit] = ENV['CODEBUILD_RESOLVED_SOURCE_VERSION'] 225 | params[:job] = ENV['CODEBUILD_BUILD_ID'] 226 | params[:slug] = ENV['CODEBUILD_SOURCE_REPO_URL']&.match(/.*github.com\/(?.*).git/)&.[]('slug') || ENV['CODESTAR_FULL_REPOSITORY_NAME'] 227 | params[:pr] = if ENV['CODEBUILD_SOURCE_VERSION'] && !(ENV['CODEBUILD_INITIATOR'] =~ /codepipeline/) 228 | matched = ENV['CODEBUILD_SOURCE_VERSION'].match(%r{pr/(?.*)}) 229 | matched.nil? ? ENV['CODEBUILD_SOURCE_VERSION'] : matched['pr'] 230 | end 231 | params[:build_url] = ENV['CODEBUILD_BUILD_URL'] 232 | when CODESHIP 233 | # https://www.codeship.io/documentation/continuous-integration/set-environment-variables/ 234 | params[:service] = 'codeship' 235 | params[:branch] = ENV['CI_BRANCH'] 236 | params[:commit] = ENV['CI_COMMIT_ID'] 237 | params[:build] = ENV['CI_BUILD_NUMBER'] 238 | params[:build_url] = ENV['CI_BUILD_URL'] 239 | when DRONEIO 240 | # https://semaphoreapp.com/docs/available-environment-variables.html 241 | params[:service] = 'drone.io' 242 | params[:branch] = ENV['DRONE_BRANCH'] 243 | params[:commit] = ENV['DRONE_COMMIT_SHA'] 244 | params[:job] = ENV['DRONE_JOB_NUMBER'] 245 | params[:build] = ENV['DRONE_BUILD_NUMBER'] 246 | params[:build_url] = ENV['DRONE_BUILD_LINK'] || ENV['DRONE_BUILD_URL'] || ENV['CI_BUILD_URL'] 247 | params[:pr] = ENV['DRONE_PULL_REQUEST'] 248 | params[:tag] = ENV['DRONE_TAG'] 249 | when GITHUB 250 | # https://help.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables#default-environment-variables 251 | params[:service] = 'github-actions' 252 | if (ENV['GITHUB_HEAD_REF'] || '').empty? 253 | params[:branch] = ENV['GITHUB_REF'].sub('refs/heads/', '') 254 | else 255 | params[:branch] = ENV['GITHUB_HEAD_REF'] 256 | # PR refs are in the format: refs/pull/7/merge for pull_request events 257 | params[:pr] = ENV['GITHUB_REF'].split('/')[2] 258 | end 259 | params[:slug] = ENV['GITHUB_REPOSITORY'] 260 | params[:build] = ENV['GITHUB_RUN_ID'] 261 | params[:commit] = ENV['GITHUB_SHA'] 262 | when GITLAB 263 | # http://doc.gitlab.com/ci/examples/README.html#environmental-variables 264 | # https://gitlab.com/gitlab-org/gitlab-ci-runner/blob/master/lib/build.rb#L96 265 | # GitLab Runner v9 renamed some environment variables, so we check both old and new variable names. 266 | params[:service] = 'gitlab' 267 | params[:branch] = ENV['CI_BUILD_REF_NAME'] || ENV['CI_COMMIT_REF_NAME'] 268 | params[:build] = ENV['CI_BUILD_ID'] || ENV['CI_JOB_ID'] 269 | slug = ENV['CI_BUILD_REPO'] || ENV['CI_REPOSITORY_URL'] 270 | params[:slug] = slug.split('/', 4)[-1].sub('.git', '') if slug 271 | params[:commit] = ENV['CI_BUILD_REF'] || ENV['CI_COMMIT_SHA'] 272 | when HEROKU 273 | params[:service] = 'heroku' 274 | params[:branch] = ENV['HEROKU_TEST_RUN_BRANCH'] 275 | params[:build] = ENV['HEROKU_TEST_RUN_ID'] 276 | params[:commit] = ENV['HEROKU_TEST_RUN_COMMIT_VERSION'] 277 | when JENKINS 278 | # https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project 279 | # https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin#GitHubpullrequestbuilderplugin-EnvironmentVariables 280 | params[:service] = 'jenkins' 281 | params[:branch] = ENV['ghprbSourceBranch'] || ENV['GIT_BRANCH'] 282 | params[:commit] = ENV['ghprbActualCommit'] || ENV['GIT_COMMIT'] 283 | params[:pr] = ENV['ghprbPullId'] 284 | params[:build] = ENV['BUILD_NUMBER'] 285 | params[:root] = ENV['WORKSPACE'] 286 | params[:build_url] = ENV['BUILD_URL'] 287 | when SEMAPHORE 288 | # https://semaphoreapp.com/docs/available-environment-variables.html 289 | params[:service] = 'semaphore' 290 | params[:branch] = ENV['BRANCH_NAME'] 291 | params[:commit] = ENV['REVISION'] 292 | params[:build] = ENV['SEMAPHORE_BUILD_NUMBER'] 293 | params[:job] = ENV['SEMAPHORE_CURRENT_THREAD'] 294 | params[:slug] = ENV['SEMAPHORE_REPO_SLUG'] 295 | when SHIPPABLE 296 | # http://docs.shippable.com/en/latest/config.html#common-environment-variables 297 | params[:service] = 'shippable' 298 | params[:branch] = ENV['BRANCH'] 299 | params[:build] = ENV['BUILD_NUMBER'] 300 | params[:build_url] = ENV['BUILD_URL'] 301 | params[:pull_request] = ENV['PULL_REQUEST'] 302 | params[:slug] = ENV['REPO_NAME'] 303 | params[:commit] = ENV['COMMIT'] 304 | when SOLANO 305 | # http://docs.solanolabs.com/Setup/tddium-set-environment-variables/ 306 | params[:service] = 'solano' 307 | params[:branch] = ENV['TDDIUM_CURRENT_BRANCH'] 308 | params[:commit] = ENV['TDDIUM_CURRENT_COMMIT'] 309 | params[:build] = ENV['TDDIUM_TID'] 310 | params[:pr] = ENV['TDDIUM_PR_ID'] 311 | when TEAMCITY 312 | # https://confluence.jetbrains.com/display/TCD8/Predefined+Build+Parameters 313 | # Teamcity does not automatically make build parameters available as environment variables. 314 | # Add the following environment parameters to the build configuration 315 | # env.TEAMCITY_BUILD_BRANCH = %teamcity.build.branch% 316 | # env.TEAMCITY_BUILD_ID = %teamcity.build.id% 317 | # env.TEAMCITY_BUILD_URL = %teamcity.serverUrl%/viewLog.html?buildId=%teamcity.build.id% 318 | # env.TEAMCITY_BUILD_COMMIT = %system.build.vcs.number% 319 | # env.TEAMCITY_BUILD_REPOSITORY = %vcsroot..url% 320 | params[:service] = 'teamcity' 321 | params[:branch] = ENV['TEAMCITY_BUILD_BRANCH'] 322 | params[:build] = ENV['TEAMCITY_BUILD_ID'] 323 | params[:build_url] = ENV['TEAMCITY_BUILD_URL'] 324 | params[:commit] = ENV['TEAMCITY_BUILD_COMMIT'] 325 | params[:slug] = ENV['TEAMCITY_BUILD_REPOSITORY'].split('/', 4)[-1].sub('.git', '') 326 | when TRAVIS 327 | # http://docs.travis-ci.com/user/ci-environment/#Environment-variables 328 | params[:service] = 'travis' 329 | params[:branch] = ENV['TRAVIS_BRANCH'] 330 | params[:pull_request] = ENV['TRAVIS_PULL_REQUEST'] 331 | params[:job] = ENV['TRAVIS_JOB_ID'] 332 | params[:slug] = ENV['TRAVIS_REPO_SLUG'] 333 | params[:build] = ENV['TRAVIS_JOB_NUMBER'] 334 | params[:commit] = ENV['TRAVIS_COMMIT'] 335 | params[:env] = ENV['TRAVIS_RUBY_VERSION'] 336 | when WERCKER 337 | # http://devcenter.wercker.com/articles/steps/variables.html 338 | params[:service] = 'wercker' 339 | params[:branch] = ENV['WERCKER_GIT_BRANCH'] 340 | params[:build] = ENV['WERCKER_MAIN_PIPELINE_STARTED'] 341 | params[:slug] = ENV['WERCKER_GIT_OWNER'] + '/' + ENV['WERCKER_GIT_REPOSITORY'] 342 | params[:commit] = ENV['WERCKER_GIT_COMMIT'] 343 | end 344 | 345 | if params[:branch].nil? 346 | # find branch, commit, repo from git command 347 | branch = `git rev-parse --abbrev-ref HEAD`.strip 348 | params[:branch] = branch != 'HEAD' ? branch : 'master' 349 | end 350 | 351 | if !ENV['VCS_COMMIT_ID'].nil? 352 | params[:commit] = ENV['VCS_COMMIT_ID'] 353 | 354 | elsif params[:commit].nil? 355 | params[:commit] = `git rev-parse HEAD`.strip 356 | end 357 | 358 | slug = ENV['CODECOV_SLUG'] 359 | params[:slug] = slug unless slug.nil? 360 | 361 | params[:pr] = params[:pr].sub('#', '') unless params[:pr].nil? 362 | 363 | params 364 | end 365 | 366 | def self.retry_request(req, https) 367 | retries = 3 368 | begin 369 | response = https.request(req) 370 | rescue Timeout::Error, SocketError => e 371 | retries -= 1 372 | 373 | if retries.zero? 374 | puts 'Timeout or connection error uploading coverage reports to Codecov. Out of retries.' 375 | puts e 376 | return response 377 | end 378 | 379 | puts 'Timeout or connection error uploading coverage reports to Codecov. Retrying...' 380 | puts e 381 | retry 382 | rescue StandardError => e 383 | puts 'Error uploading coverage reports to Codecov. Sorry' 384 | puts e.class.name 385 | puts e 386 | puts "Backtrace:\n\t#{e.backtrace}" 387 | return response 388 | end 389 | 390 | response 391 | end 392 | 393 | def self.gzip_report(report) 394 | puts [green('==>'), 'Gzipping contents'].join(' ') 395 | 396 | io = StringIO.new 397 | gzip = Zlib::GzipWriter.new(io) 398 | gzip << report 399 | gzip.close 400 | 401 | io.string 402 | end 403 | 404 | def self.upload_to_codecov(ci, report) 405 | url = ENV['CODECOV_URL'] || 'https://codecov.io' 406 | is_enterprise = url != 'https://codecov.io' 407 | 408 | params = build_params(ci) 409 | params_secret_token = params.clone 410 | params_secret_token['token'] = 'secret' 411 | 412 | query = URI.encode_www_form(params) 413 | query_without_token = URI.encode_www_form(params_secret_token) 414 | 415 | gzipped_report = gzip_report(report['codecov']) 416 | 417 | report['params'] = params 418 | report['query'] = query 419 | 420 | puts [green('==>'), 'Uploading reports'].join(' ') 421 | puts " url: #{url}" 422 | puts " query: #{query_without_token}" 423 | 424 | response = false 425 | unless is_enterprise 426 | response = upload_to_v4(url, gzipped_report, query, query_without_token) 427 | return false if response == false 428 | end 429 | 430 | response || upload_to_v2(url, gzipped_report, query, query_without_token) 431 | end 432 | 433 | def self.upload_to_v4(url, report, query, query_without_token) 434 | uri = URI.parse(url.chomp('/') + '/upload/v4') 435 | https = Net::HTTP.new(uri.host, uri.port) 436 | https.use_ssl = !url.match(/^https/).nil? 437 | 438 | puts [green('-> '), 'Pinging Codecov'].join(' ') 439 | puts "#{url}#{uri.path}?#{query_without_token}" 440 | 441 | req = Net::HTTP::Post.new( 442 | "#{uri.path}?#{query}", 443 | { 444 | 'X-Reduced-Redundancy' => 'false', 445 | 'X-Content-Encoding' => 'application/x-gzip', 446 | 'Content-Type' => 'text/plain' 447 | } 448 | ) 449 | response = retry_request(req, https) 450 | if !response&.code || response.code == '400' 451 | puts red(response&.body) 452 | return false 453 | end 454 | 455 | reports_url = response.body.lines[0] 456 | s3target = response.body.lines[1] 457 | 458 | if s3target.nil? || s3target.empty? 459 | puts red(response.body) 460 | return false 461 | end 462 | 463 | puts [green('-> '), 'Uploading to'].join(' ') 464 | puts s3target 465 | 466 | uri = URI(s3target) 467 | https = Net::HTTP.new(uri.host, uri.port) 468 | https.use_ssl = true 469 | req = Net::HTTP::Put.new( 470 | s3target, 471 | { 472 | 'Content-Encoding' => 'gzip', 473 | 'Content-Type' => 'text/plain' 474 | } 475 | ) 476 | req.body = report 477 | res = retry_request(req, https) 478 | if res&.body == '' 479 | { 480 | 'uploaded' => true, 481 | 'url' => reports_url, 482 | 'meta' => { 483 | 'status' => res.code 484 | }, 485 | 'message' => 'Coverage reports upload successfully' 486 | }.to_json 487 | else 488 | puts [black('-> '), 'Could not upload reports via v4 API, defaulting to v2'].join(' ') 489 | puts red(res&.body || 'nil') 490 | nil 491 | end 492 | end 493 | 494 | def self.upload_to_v2(url, report, query, query_without_token) 495 | uri = URI.parse(url.chomp('/') + '/upload/v2') 496 | https = Net::HTTP.new(uri.host, uri.port) 497 | https.use_ssl = !url.match(/^https/).nil? 498 | 499 | puts [green('-> '), 'Uploading to Codecov'].join(' ') 500 | puts "#{url}#{uri.path}?#{query_without_token}" 501 | 502 | req = Net::HTTP::Post.new( 503 | "#{uri.path}?#{query}", 504 | { 505 | 'Accept' => 'application/json', 506 | 'Content-Encoding' => 'gzip', 507 | 'Content-Type' => 'text/plain', 508 | 'X-Content-Encoding' => 'gzip' 509 | } 510 | ) 511 | req.body = report 512 | res = retry_request(req, https) 513 | res&.body 514 | end 515 | 516 | def self.handle_report_response(report) 517 | if report['result']['uploaded'] 518 | puts " View reports at #{report['result']['url']}" 519 | else 520 | puts red(' X> Failed to upload coverage reports') 521 | end 522 | end 523 | 524 | private 525 | 526 | # Toggle VCR and WebMock on or off 527 | # 528 | # @param switch Toggle switch for Net Blockers. 529 | # @return [Boolean] 530 | def self.net_blockers(switch) 531 | throw 'Only :on or :off' unless %i[on off].include? switch 532 | 533 | if defined?(VCR) 534 | case switch 535 | when :on 536 | VCR.turn_on! 537 | when :off 538 | VCR.turn_off!(ignore_cassettes: true) 539 | end 540 | end 541 | 542 | if defined?(WebMock) 543 | # WebMock on by default 544 | # VCR depends on WebMock 1.8.11; no method to check whether enabled. 545 | case switch 546 | when :on 547 | WebMock.enable! 548 | when :off 549 | WebMock.disable! 550 | end 551 | end 552 | 553 | true 554 | end 555 | 556 | # Convenience color methods 557 | def self.black(str) 558 | str.nil? ? '' : "\e[30m#{str}\e[0m" 559 | end 560 | 561 | def self.red(str) 562 | str.nil? ? '' : "\e[31m#{str}\e[0m" 563 | end 564 | 565 | def self.green(str) 566 | str.nil? ? '' : "\e[32m#{str}\e[0m" 567 | end 568 | end 569 | 570 | require_relative 'configuration' 571 | Codecov.extend Codecov::Configuration 572 | -------------------------------------------------------------------------------- /lib/codecov/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Codecov 4 | VERSION = '0.6.0' 5 | end 6 | -------------------------------------------------------------------------------- /test/helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rubygems' 4 | require 'bundler/setup' 5 | 6 | require 'simplecov' 7 | SimpleCov.start do 8 | add_filter '/test/' 9 | end 10 | require_relative '../lib/codecov' 11 | SimpleCov.formatter = SimpleCov::Formatter::Codecov if ENV['CI'] == 'true' 12 | Codecov.pass_ci_if_error = false 13 | 14 | require 'minitest/autorun' 15 | require 'mocha/minitest' 16 | require 'webmock/minitest' 17 | -------------------------------------------------------------------------------- /test/test_codecov.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'helper' 4 | 5 | class TestCodecov < Minitest::Test 6 | CI = Codecov::Uploader.detect_ci 7 | 8 | REALENV = 9 | case CI 10 | when Codecov::Uploader::CIRCLE 11 | { 12 | 'CIRCLECI' => ENV['CIRCLECI'], 13 | 'CIRCLE_BUILD_NUM' => ENV['CIRCLE_BUILD_NUM'], 14 | 'CIRCLE_NODE_INDEX' => ENV['CIRCLE_NODE_INDEX'], 15 | 'CIRCLE_PROJECT_REPONAME' => ENV['CIRCLE_PROJECT_REPONAME'], 16 | 'CIRCLE_PROJECT_USERNAME' => ENV['CIRCLE_PROJECT_USERNAME'], 17 | 'CIRCLE_REPOSITORY_URL' => ENV['CIRCLE_REPOSITORY_URL'], 18 | 'CIRCLE_PR_NUMBER' => ENV['CIRCLE_PR_NUMBER'], 19 | 'CIRCLE_BRANCH' => ENV['CIRCLE_BRANCH'], 20 | 'CIRCLE_SHA1' => ENV['CIRCLE_SHA1'], 21 | 'CODECOV_TOKEN' => ENV['CODECOV_TOKEN'] 22 | } 23 | when Codecov::Uploader::GITHUB 24 | { 25 | 'CODECOV_TOKEN' => ENV['CODECOV_TOKEN'], 26 | 'GITHUB_ACTIONS' => ENV['GITHUB_ACTIONS'], 27 | 'GITHUB_HEAD_REF' => ENV['GITHUB_HEAD_REF'], 28 | 'GITHUB_REF' => ENV['GITHUB_REF'], 29 | 'GITHUB_REPOSITORY' => ENV['GITHUB_REPOSITORY'], 30 | 'GITHUB_RUN_ID' => ENV['GITHUB_RUN_ID'], 31 | 'GITHUB_SHA' => ENV['GITHUB_SHA'] 32 | } 33 | when Codecov::Uploader::TRAVIS 34 | { 35 | 'CODECOV_TOKEN' => ENV['CODECOV_TOKEN'], 36 | 'TRAVIS' => ENV['TRAVIS'], 37 | 'TRAVIS_BRANCH' => ENV['TRAVIS_BRANCH'], 38 | 'TRAVIS_COMMIT' => ENV['TRAVIS_COMMIT'], 39 | 'TRAVIS_REPO_SLUG' => ENV['TRAVIS_REPO_SLUG'], 40 | 'TRAVIS_JOB_NUMBER' => ENV['TRAVIS_JOB_NUMBER'], 41 | 'TRAVIS_PULL_REQUEST' => ENV['TRAVIS_PULL_REQUEST'], 42 | 'TRAVIS_JOB_ID' => ENV['TRAVIS_JOB_ID'] 43 | } 44 | else 45 | { 46 | 'CODECOV_TOKEN' => ENV['CODECOV_TOKEN'] 47 | } 48 | end.freeze 49 | 50 | def url 51 | ENV['CODECOV_URL'] || 'https://codecov.io' 52 | end 53 | 54 | def test_defined 55 | assert defined?(SimpleCov::Formatter::Codecov) 56 | assert defined?(::Codecov::VERSION) 57 | end 58 | 59 | def stub_file(filename, coverage) 60 | lines = coverage.each_with_index.map do |cov, i| 61 | skipped = false 62 | if cov == :skipped 63 | skipped = true 64 | cov = 0 65 | end 66 | stub('SimpleCov::SourceFile::Line', skipped?: skipped, line_number: i + 1, coverage: cov) 67 | end 68 | stub('SimpleCov::SourceFile', filename: filename, lines: lines) 69 | end 70 | 71 | def upload(success = true) 72 | WebMock.enable! 73 | formatter = SimpleCov::Formatter::Codecov.new 74 | result = stub('SimpleCov::Result', files: [ 75 | stub_file('path/lib/something.rb', [1, 0, 0, nil, 1, nil]), 76 | stub_file('path/lib/somefile.rb', [1, nil, 1, 1, 1, 0, 0, nil, 1, nil]) 77 | ]) 78 | SimpleCov.stubs(:root).returns('path') 79 | success_stubs if success 80 | data = formatter.format(result, false) 81 | puts data 82 | puts data['params'] 83 | assert_successful_upload(data) if success 84 | WebMock.reset! 85 | data 86 | end 87 | 88 | def success_stubs 89 | stub_request(:post, %r{https:\/\/codecov.io\/upload\/v4}) 90 | .to_return( 91 | status: 200, 92 | body: "https://codecov.io/gh/fake\n" \ 93 | 'https://storage.googleapis.com/codecov/fake' 94 | ) 95 | stub_request(:put, %r{https:\/\/storage.googleapis.com\/}) 96 | .to_return( 97 | status: 200, 98 | body: '' 99 | ) 100 | end 101 | 102 | def assert_successful_upload(data) 103 | assert_equal(data['result']['uploaded'], true) 104 | assert_equal(data['result']['message'], 'Coverage reports upload successfully') 105 | assert_equal(data['meta']['version'], 'codecov-ruby/v' + ::Codecov::VERSION) 106 | assert_equal(data['coverage'].to_json, { 107 | 'lib/something.rb' => [nil, 1, 0, 0, nil, 1, nil], 108 | 'lib/somefile.rb' => [nil, 1, nil, 1, 1, 1, 0, 0, nil, 1, nil] 109 | }.to_json) 110 | end 111 | 112 | def setup 113 | ENV['CI'] = nil 114 | ENV['CIRCLECI'] = nil 115 | ENV['GITHUB_ACTIONS'] = nil 116 | ENV['TRAVIS'] = nil 117 | ::Codecov.pass_ci_if_error = true 118 | end 119 | 120 | def teardown 121 | # needed for sending this projects coverage 122 | ENV['APPVEYOR'] = nil 123 | ENV['APPVEYOR_ACCOUNT_NAME'] = nil 124 | ENV['APPVEYOR_BUILD_VERSION'] = nil 125 | ENV['APPVEYOR_JOB_ID'] = nil 126 | ENV['APPVEYOR_PROJECT_SLUG'] = nil 127 | ENV['APPVEYOR_PULL_REQUEST_NUMBER'] = nil 128 | ENV['APPVEYOR_REPO_BRANCH'] = nil 129 | ENV['APPVEYOR_REPO_COMMIT'] = nil 130 | ENV['APPVEYOR_REPO_NAME'] = nil 131 | ENV['BITBUCKET_BRANCH'] = nil 132 | ENV['BITBUCKET_BUILD_NUMBER'] = nil 133 | ENV['BITBUCKET_COMMIT'] = nil 134 | ENV['BITRISE_BUILD_NUMBER'] = nil 135 | ENV['BITRISE_BUILD_URL'] = nil 136 | ENV['BITRISE_GIT_BRANCH'] = nil 137 | ENV['BITRISE_GIT_COMMIT'] = nil 138 | ENV['BITRISE_IO'] = nil 139 | ENV['BITRISE_PULL_REQUEST'] = nil 140 | ENV['BITRISEIO_GIT_REPOSITORY_OWNER'] = nil 141 | ENV['BITRISEIO_GIT_REPOSITORY_SLUG'] = nil 142 | ENV['BRANCH'] = nil 143 | ENV['BRANCH_NAME'] = nil 144 | ENV['BUILD_ID'] = nil 145 | ENV['BUILD_NUMBER'] = nil 146 | ENV['BUILD_NUMBER'] = nil 147 | ENV['BUILD_URL'] = nil 148 | ENV['BUILDKITE'] = nil 149 | ENV['BUILDKITE_BRANCH'] = nil 150 | ENV['BUILDKITE_JOB_ID'] = nil 151 | ENV['BUILDKITE_BUILD_NUMBER'] = nil 152 | ENV['BUILDKITE_BUILD_URL'] = nil 153 | ENV['BUILDKITE_PROJECT_SLUG'] = nil 154 | ENV['BUILDKITE_COMMIT'] = nil 155 | ENV['CI'] = 'true' 156 | ENV['CI_BRANCH'] = nil 157 | ENV['CI_BUILD_ID'] = nil 158 | ENV['CI_BUILD_NUMBER'] = nil 159 | ENV['CI_BUILD_REF'] = nil 160 | ENV['CI_BUILD_REF_NAME'] = nil 161 | ENV['CI_BUILD_REPO'] = nil 162 | ENV['CI_BUILD_URL'] = nil 163 | ENV['CI_COMMIT'] = nil 164 | ENV['CI_COMMIT_ID'] = nil 165 | ENV['CI_NAME'] = nil 166 | ENV['CI_PROJECT_DIR'] = nil 167 | ENV['CI_SERVER_NAME'] = nil 168 | ENV['CI_SERVER_NAME'] = nil 169 | ENV['CIRCLE_BRANCH'] = nil 170 | ENV['CIRCLE_BUILD_NUM'] = nil 171 | ENV['CIRCLE_NODE_INDEX'] = nil 172 | ENV['CIRCLE_PR_NUMBER'] = nil 173 | ENV['CIRCLE_PROJECT_REPONAME'] = nil 174 | ENV['CIRCLE_PROJECT_USERNAME'] = nil 175 | ENV['CIRCLE_SHA1'] = nil 176 | ENV['CIRCLECI'] = nil 177 | ENV['CIRRUS_CI'] = nil 178 | ENV['CIRRUS_BRANCH'] = nil 179 | ENV['CIRRUS_BUILD_ID'] = nil 180 | ENV['CIRRUS_TASK_ID'] = nil 181 | ENV['CIRRUS_CHANGE_IN_REPO'] = nil 182 | ENV['CIRRUS_TASK_NAME'] = nil 183 | ENV['CIRRUS_PR'] = nil 184 | ENV['CIRRUS_REPO_FULL_NAME'] = nil 185 | ENV['CODEBUILD_CI'] = nil 186 | ENV['CODEBUILD_BUILD_ID'] = nil 187 | ENV['CODEBUILD_BUILD_URL'] = nil 188 | ENV['CODEBUILD_INITIATOR'] = nil 189 | ENV['CODEBUILD_RESOLVED_SOURCE_VERSION'] = nil 190 | ENV['CODEBUILD_WEBHOOK_HEAD_REF'] = nil 191 | ENV['CODEBUILD_SOURCE_VERSION'] = nil 192 | ENV['CODEBUILD_SOURCE_REPO_URL'] = nil 193 | ENV['CODESTAR_BRANCH_NAME'] = nil 194 | ENV['CODESTAR_FULL_REPOSITORY_NAME'] = nil 195 | ENV['CODECOV_ENV'] = nil 196 | ENV['CODECOV_SLUG'] = nil 197 | ENV['CODECOV_TOKEN'] = nil 198 | ENV['CODECOV_URL'] = nil 199 | ENV['COMMIT'] = nil 200 | ENV['DRONE'] = nil 201 | ENV['DRONE_BRANCH'] = nil 202 | ENV['DRONE_BUILD_URL'] = nil 203 | ENV['DRONE_COMMIT'] = nil 204 | ENV['ghprbActualCommit'] = nil 205 | ENV['ghprbPullId'] = nil 206 | ENV['ghprbSourceBranch'] = nil 207 | ENV['GIT_BRANCH'] = nil 208 | ENV['GIT_COMMIT'] = nil 209 | ENV['GITHUB_ACTIONS'] = nil 210 | ENV['GITHUB_REF'] = nil 211 | ENV['GITHUB_HEAD_REF'] = nil 212 | ENV['GITHUB_REPOSITORY'] = nil 213 | ENV['GITHUB_RUN_ID'] = nil 214 | ENV['GITHUB_SHA'] = nil 215 | ENV['GITLAB_CI'] = nil 216 | ENV['HEROKU_TEST_RUN_ID'] = nil 217 | ENV['HEROKU_TEST_RUN_BRANCH'] = nil 218 | ENV['HEROKU_TEST_RUN_COMMIT_VERSION'] = nil 219 | ENV['JENKINS_URL'] = nil 220 | ENV['MAGNUM'] = nil 221 | ENV['PULL_REQUEST'] = nil 222 | ENV['REPO_NAME'] = nil 223 | ENV['REVISION'] = nil 224 | ENV['SEMAPHORE'] = nil 225 | ENV['SEMAPHORE_BUILD_NUMBER'] = nil 226 | ENV['SEMAPHORE_CURRENT_THREAD'] = nil 227 | ENV['SEMAPHORE_REPO_SLUG'] = nil 228 | ENV['SHIPPABLE'] = nil 229 | ENV['TF_BUILD'] = nil 230 | ENV['TRAVIS'] = nil 231 | ENV['TRAVIS_BRANCH'] = nil 232 | ENV['TRAVIS_COMMIT'] = nil 233 | ENV['TRAVIS_JOB_ID'] = nil 234 | ENV['TRAVIS_JOB_NUMBER'] = nil 235 | ENV['TRAVIS_PULL_REQUEST'] = nil 236 | ENV['TRAVIS_REPO_SLUG'] = nil 237 | ENV['VCS_COMMIT_ID'] = nil 238 | ENV['WERCKER_GIT_BRANCH'] = nil 239 | ENV['WERCKER_GIT_COMMIT'] = nil 240 | ENV['WERCKER_GIT_OWNER'] = nil 241 | ENV['WERCKER_GIT_REPOSITORY'] = nil 242 | ENV['WERCKER_MAIN_PIPELINE_STARTED'] = nil 243 | ENV['WORKSPACE'] = nil 244 | 245 | REALENV.each_pair { |k, v| ENV[k] = v } 246 | ::Codecov.pass_ci_if_error = false 247 | end 248 | 249 | def test_git 250 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 251 | result = upload 252 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 253 | branch = `git rev-parse --abbrev-ref HEAD`.strip 254 | assert_equal(branch != 'HEAD' ? branch : 'master', result['params'][:branch]) 255 | assert_equal(`git rev-parse HEAD`.strip, result['params'][:commit]) 256 | end 257 | 258 | def test_enterprise 259 | stub_request(:post, %r{https://example.com/upload/v2}) 260 | .to_return( 261 | status: 200, 262 | body: "{\"id\": \"12345678-1234-abcd-ef12-1234567890ab\", \"message\": \"Coverage reports upload successfully\", \"meta\": { \"status\": 200 }, \"queued\": true, \"uploaded\": true, \"url\": \"https://example.com/github/codecov/codecov-bash/commit/2f6b51562b93e72c610671644fe2a303c5c0e8e5\"}" 263 | ) 264 | 265 | ENV['CODECOV_URL'] = 'https://example.com' 266 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 267 | result = upload 268 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 269 | assert_equal('12345678-1234-abcd-ef12-1234567890ab', result['result']['id']) 270 | branch = `git rev-parse --abbrev-ref HEAD`.strip 271 | assert_equal(branch != 'HEAD' ? branch : 'master', result['params'][:branch]) 272 | assert_equal(`git rev-parse HEAD`.strip, result['params'][:commit]) 273 | end 274 | 275 | def test_travis 276 | ENV['CI'] = 'true' 277 | ENV['TRAVIS'] = 'true' 278 | ENV['TRAVIS_BRANCH'] = 'master' 279 | ENV['TRAVIS_COMMIT'] = 'c739768fcac68144a3a6d82305b9c4106934d31a' 280 | ENV['TRAVIS_JOB_ID'] = '33116958' 281 | ENV['TRAVIS_PULL_REQUEST'] = 'false' 282 | ENV['TRAVIS_JOB_NUMBER'] = '1' 283 | ENV['TRAVIS_REPO_SLUG'] = 'codecov/ci-repo' 284 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 285 | result = upload 286 | assert_equal('travis', result['params'][:service]) 287 | assert_equal('c739768fcac68144a3a6d82305b9c4106934d31a', result['params'][:commit]) 288 | assert_equal('codecov/ci-repo', result['params'][:slug]) 289 | assert_equal('1', result['params'][:build]) 290 | assert_equal('33116958', result['params'][:job]) 291 | assert_equal('false', result['params'][:pull_request]) 292 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 293 | end 294 | 295 | def test_codeship 296 | ENV['CI'] = 'true' 297 | ENV['CI_NAME'] = 'codeship' 298 | ENV['CI_BRANCH'] = 'master' 299 | ENV['CI_BUILD_NUMBER'] = '1' 300 | ENV['CI_COMMIT_ID'] = '743b04806ea677403aa2ff26c6bdeb85005de658' 301 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 302 | result = upload 303 | assert_equal('codeship', result['params'][:service]) 304 | assert_equal('743b04806ea677403aa2ff26c6bdeb85005de658', result['params'][:commit]) 305 | assert_equal('1', result['params'][:build]) 306 | assert_equal('master', result['params'][:branch]) 307 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 308 | end 309 | 310 | def test_buildkite 311 | ENV['CI'] = 'true' 312 | ENV['BUILDKITE'] = 'true' 313 | ENV['BUILDKITE_BRANCH'] = 'master' 314 | ENV['BUILDKITE_BUILD_NUMBER'] = '1' 315 | ENV['BUILDKITE_JOB_ID'] = '2' 316 | ENV['BUILDKITE_BUILD_URL'] = 'http://demo' 317 | ENV['BUILDKITE_PROJECT_SLUG'] = 'owner/repo' 318 | ENV['BUILDKITE_COMMIT'] = '743b04806ea677403aa2ff26c6bdeb85005de658' 319 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 320 | result = upload 321 | assert_equal('buildkite', result['params'][:service]) 322 | assert_equal('743b04806ea677403aa2ff26c6bdeb85005de658', result['params'][:commit]) 323 | assert_equal('1', result['params'][:build]) 324 | assert_equal('2', result['params'][:job]) 325 | assert_equal('master', result['params'][:branch]) 326 | assert_equal('owner/repo', result['params'][:slug]) 327 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 328 | end 329 | 330 | def test_jenkins 331 | ENV['JENKINS_URL'] = 'true' 332 | ENV['ghprbSourceBranch'] = 'master' 333 | ENV['BUILD_NUMBER'] = '1' 334 | ENV['ghprbActualCommit'] = '743b04806ea677403aa2ff26c6bdeb85005de658' 335 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 336 | ENV['BUILD_URL'] = 'https://jenkins' 337 | ENV['ghprbPullId'] = '1' 338 | result = upload 339 | assert_equal('jenkins', result['params'][:service]) 340 | assert_equal('743b04806ea677403aa2ff26c6bdeb85005de658', result['params'][:commit]) 341 | assert_equal('1', result['params'][:build]) 342 | assert_equal('1', result['params'][:pr]) 343 | assert_equal('master', result['params'][:branch]) 344 | assert_equal('https://jenkins', result['params'][:build_url]) 345 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 346 | end 347 | 348 | def test_jenkins_2 349 | ENV['JENKINS_URL'] = 'true' 350 | ENV['GIT_BRANCH'] = 'master' 351 | ENV['BUILD_NUMBER'] = '1' 352 | ENV['GIT_COMMIT'] = '743b04806ea677403aa2ff26c6bdeb85005de658' 353 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 354 | ENV['BUILD_URL'] = 'https://jenkins' 355 | result = upload 356 | assert_equal('jenkins', result['params'][:service]) 357 | assert_equal('743b04806ea677403aa2ff26c6bdeb85005de658', result['params'][:commit]) 358 | assert_equal('1', result['params'][:build]) 359 | assert_equal('master', result['params'][:branch]) 360 | assert_equal('https://jenkins', result['params'][:build_url]) 361 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 362 | end 363 | 364 | def test_shippable 365 | ENV['CI'] = 'true' 366 | ENV['SHIPPABLE'] = 'true' 367 | ENV['BRANCH'] = 'master' 368 | ENV['BUILD_NUMBER'] = '1' 369 | ENV['BUILD_URL'] = 'http://shippable.com/...' 370 | ENV['PULL_REQUEST'] = 'false' 371 | ENV['REPO_NAME'] = 'owner/repo' 372 | ENV['COMMIT'] = '743b04806ea677403aa2ff26c6bdeb85005de658' 373 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 374 | result = upload 375 | assert_equal('shippable', result['params'][:service]) 376 | assert_equal('743b04806ea677403aa2ff26c6bdeb85005de658', result['params'][:commit]) 377 | assert_equal('false', result['params'][:pull_request]) 378 | assert_equal('1', result['params'][:build]) 379 | assert_equal('http://shippable.com/...', result['params'][:build_url]) 380 | assert_equal('master', result['params'][:branch]) 381 | assert_equal('owner/repo', result['params'][:slug]) 382 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 383 | end 384 | 385 | def test_appveyor 386 | ENV['CI'] = 'True' 387 | ENV['APPVEYOR'] = 'True' 388 | ENV['APPVEYOR_REPO_BRANCH'] = 'master' 389 | ENV['APPVEYOR_JOB_ID'] = 'build' 390 | ENV['APPVEYOR_PULL_REQUEST_NUMBER'] = '1' 391 | ENV['APPVEYOR_ACCOUNT_NAME'] = 'owner' 392 | ENV['APPVEYOR_PROJECT_SLUG'] = 'repo' 393 | ENV['APPVEYOR_BUILD_VERSION'] = 'job' 394 | ENV['APPVEYOR_REPO_NAME'] = 'owner/repo' 395 | ENV['APPVEYOR_REPO_COMMIT'] = '743b04806ea677403aa2ff26c6bdeb85005de658' 396 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 397 | result = upload 398 | assert_equal('appveyor', result['params'][:service]) 399 | assert_equal('743b04806ea677403aa2ff26c6bdeb85005de658', result['params'][:commit]) 400 | assert_equal('master', result['params'][:branch]) 401 | assert_equal('owner/repo', result['params'][:slug]) 402 | assert_equal('1', result['params'][:pr]) 403 | assert_equal('build', result['params'][:build]) 404 | assert_equal('owner/repo/job', result['params'][:job]) 405 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 406 | end 407 | 408 | def test_circleci 409 | ENV['CI'] = 'true' 410 | ENV['CIRCLECI'] = 'true' 411 | ENV['CIRCLE_BRANCH'] = 'master' 412 | ENV['CIRCLE_BUILD_NUM'] = '1' 413 | ENV['CIRCLE_NODE_INDEX'] = '2' 414 | ENV['CIRCLE_PR_NUMBER'] = '3' 415 | ENV['CIRCLE_PROJECT_USERNAME'] = 'owner' 416 | ENV['CIRCLE_PROJECT_REPONAME'] = 'repo' 417 | ENV['CIRCLE_SHA1'] = '743b04806ea677403aa2ff26c6bdeb85005de658' 418 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 419 | result = upload 420 | assert_equal('circleci', result['params'][:service]) 421 | assert_equal('743b04806ea677403aa2ff26c6bdeb85005de658', result['params'][:commit]) 422 | assert_equal('1', result['params'][:build]) 423 | assert_equal('2', result['params'][:job]) 424 | assert_equal('3', result['params'][:pr]) 425 | assert_equal('master', result['params'][:branch]) 426 | assert_equal('owner/repo', result['params'][:slug]) 427 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 428 | end 429 | 430 | def test_semaphore 431 | ENV['CI'] = 'true' 432 | ENV['SEMAPHORE'] = 'true' 433 | ENV['BRANCH_NAME'] = 'master' 434 | ENV['SEMAPHORE_REPO_SLUG'] = 'owner/repo' 435 | ENV['SEMAPHORE_BUILD_NUMBER'] = '1' 436 | ENV['SEMAPHORE_CURRENT_THREAD'] = '2' 437 | ENV['REVISION'] = '743b04806ea677403aa2ff26c6bdeb85005de658' 438 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 439 | result = upload 440 | assert_equal('semaphore', result['params'][:service]) 441 | assert_equal('743b04806ea677403aa2ff26c6bdeb85005de658', result['params'][:commit]) 442 | assert_equal('1', result['params'][:build]) 443 | assert_equal('2', result['params'][:job]) 444 | assert_equal('master', result['params'][:branch]) 445 | assert_equal('owner/repo', result['params'][:slug]) 446 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 447 | end 448 | 449 | def test_drone 450 | ENV['CI'] = 'true' 451 | ENV['DRONE'] = 'true' 452 | ENV['DRONE_BRANCH'] = 'master' 453 | ENV['DRONE_BUILD_NUMBER'] = '1' 454 | ENV['DRONE_BUILD_URL'] = 'https://drone.io/...' 455 | ENV['DRONE_COMMIT'] = '1123566' 456 | ENV['CODECOV_SLUG'] = 'codecov/ci-repo' 457 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 458 | result = upload 459 | assert_equal('drone.io', result['params'][:service]) 460 | assert_equal(`git rev-parse HEAD`.strip, result['params'][:commit]) 461 | assert_equal('1', result['params'][:build]) 462 | assert_equal('https://drone.io/...', result['params'][:build_url]) 463 | assert_equal('codecov/ci-repo', result['params'][:slug]) 464 | assert_equal('master', result['params'][:branch]) 465 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 466 | end 467 | 468 | def test_wercker 469 | ENV['CI'] = 'true' 470 | ENV['WERCKER_GIT_BRANCH'] = 'master' 471 | ENV['WERCKER_MAIN_PIPELINE_STARTED'] = '1' 472 | ENV['WERCKER_GIT_OWNER'] = 'owner' 473 | ENV['WERCKER_GIT_REPOSITORY'] = 'repo' 474 | ENV['WERCKER_GIT_COMMIT'] = '743b04806ea677403aa2ff26c6bdeb85005de658' 475 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 476 | result = upload 477 | assert_equal('wercker', result['params'][:service]) 478 | assert_equal('743b04806ea677403aa2ff26c6bdeb85005de658', result['params'][:commit]) 479 | assert_equal('1', result['params'][:build]) 480 | assert_equal('master', result['params'][:branch]) 481 | assert_equal('owner/repo', result['params'][:slug]) 482 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 483 | end 484 | 485 | def test_github_pull_request 486 | ENV['CI'] = 'true' 487 | ENV['GITHUB_ACTIONS'] = 'true' 488 | ENV['GITHUB_HEAD_REF'] = 'patch-2' 489 | ENV['GITHUB_REF'] = 'refs/pull/7/merge' 490 | ENV['GITHUB_REPOSITORY'] = 'codecov/ci-repo' 491 | ENV['GITHUB_RUN_ID'] = '1' 492 | ENV['GITHUB_SHA'] = 'c739768fcac68144a3a6d82305b9c4106934d31a' 493 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 494 | result = upload 495 | assert_equal('github-actions', result['params'][:service]) 496 | assert_equal('c739768fcac68144a3a6d82305b9c4106934d31a', result['params'][:commit]) 497 | assert_equal('codecov/ci-repo', result['params'][:slug]) 498 | assert_equal('1', result['params'][:build]) 499 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 500 | assert_equal('patch-2', result['params'][:branch]) 501 | assert_equal('7', result['params'][:pr]) 502 | end 503 | 504 | def test_github_push 505 | ENV['CI'] = 'true' 506 | ENV['GITHUB_ACTIONS'] = 'true' 507 | ENV['GITHUB_HEAD_REF'] = '' 508 | ENV['GITHUB_REF'] = 'refs/heads/master' 509 | ENV['GITHUB_REPOSITORY'] = 'codecov/ci-repo' 510 | ENV['GITHUB_RUN_ID'] = '1' 511 | ENV['GITHUB_SHA'] = 'c739768fcac68144a3a6d82305b9c4106934d31a' 512 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 513 | result = upload 514 | assert_equal('github-actions', result['params'][:service]) 515 | assert_equal('c739768fcac68144a3a6d82305b9c4106934d31a', result['params'][:commit]) 516 | assert_equal('codecov/ci-repo', result['params'][:slug]) 517 | assert_equal('1', result['params'][:build]) 518 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 519 | assert_equal('master', result['params'][:branch]) 520 | assert_equal(false, result['params'].key?(:pr)) 521 | end 522 | 523 | def test_gitlab 524 | ENV['GITLAB_CI'] = 'true' 525 | ENV['CI_BUILD_REF_NAME'] = 'master' 526 | ENV['CI_BUILD_ID'] = '1' 527 | ENV['CI_BUILD_REPO'] = 'https://gitlab.com/owner/repo.git' 528 | ENV['CI_BUILD_REF'] = '743b04806ea677403aa2ff26c6bdeb85005de658' 529 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 530 | result = upload 531 | assert_equal('gitlab', result['params'][:service]) 532 | assert_equal('743b04806ea677403aa2ff26c6bdeb85005de658', result['params'][:commit]) 533 | assert_equal('1', result['params'][:build]) 534 | assert_equal('master', result['params'][:branch]) 535 | assert_equal('owner/repo', result['params'][:slug]) 536 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 537 | end 538 | 539 | def test_bitrise 540 | ENV['CI'] = 'true' 541 | ENV['BITRISE_IO'] = 'true' 542 | ENV['BITRISE_BUILD_NUMBER'] = '1' 543 | ENV['BITRISE_BUILD_URL'] = 'https://app.bitrise.io/build/123' 544 | ENV['BITRISE_GIT_BRANCH'] = 'master' 545 | ENV['BITRISE_PULL_REQUEST'] = '2' 546 | ENV['BITRISEIO_GIT_REPOSITORY_OWNER'] = 'owner' 547 | ENV['BITRISEIO_GIT_REPOSITORY_SLUG'] = 'repo' 548 | ENV['BITRISE_GIT_COMMIT'] = '743b04806ea677403aa2ff26c6bdeb85005de658' 549 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 550 | result = upload 551 | assert_equal('bitrise', result['params'][:service]) 552 | assert_equal('1', result['params'][:build]) 553 | assert_equal('https://app.bitrise.io/build/123', result['params'][:build_url]) 554 | assert_equal('master', result['params'][:branch]) 555 | assert_equal('2', result['params'][:pr]) 556 | assert_equal('owner/repo', result['params'][:slug]) 557 | assert_equal('743b04806ea677403aa2ff26c6bdeb85005de658', result['params'][:commit]) 558 | end 559 | 560 | def test_teamcity 561 | ENV['CI_SERVER_NAME'] = 'TeamCity' 562 | ENV['TEAMCITY_BUILD_BRANCH'] = 'master' 563 | ENV['TEAMCITY_BUILD_ID'] = '1' 564 | ENV['TEAMCITY_BUILD_URL'] = 'http://teamcity/...' 565 | ENV['TEAMCITY_BUILD_COMMIT'] = '743b04806ea677403aa2ff26c6bdeb85005de658' 566 | ENV['TEAMCITY_BUILD_REPOSITORY'] = 'https://github.com/owner/repo.git' 567 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 568 | result = upload 569 | assert_equal('teamcity', result['params'][:service]) 570 | assert_equal('743b04806ea677403aa2ff26c6bdeb85005de658', result['params'][:commit]) 571 | assert_equal('1', result['params'][:build]) 572 | assert_equal('master', result['params'][:branch]) 573 | assert_equal('owner/repo', result['params'][:slug]) 574 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 575 | end 576 | 577 | def test_azure_pipelines 578 | ENV['TF_BUILD'] = '1' 579 | ENV['BUILD_SOURCEBRANCH'] = 'master' 580 | ENV['SYSTEM_JOBID'] = '92a2fa25-f940-5df6-a185-81eb9ae2031d' 581 | ENV['BUILD_BUILDID'] = '1' 582 | ENV['SYSTEM_TEAMFOUNDATIONSERVERURI'] = 'https://dev.azure.com/codecov/' 583 | ENV['SYSTEM_TEAMPROJECT'] = 'repo' 584 | ENV['BUILD_SOURCEVERSION'] = '743b04806ea677403aa2ff26c6bdeb85005de658' 585 | ENV['BUILD_REPOSITORY_ID'] = 'owner/repo' 586 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 587 | result = upload 588 | assert_equal('azure_pipelines', result['params'][:service]) 589 | assert_equal('743b04806ea677403aa2ff26c6bdeb85005de658', result['params'][:commit]) 590 | assert_equal('1', result['params'][:build]) 591 | assert_equal('master', result['params'][:branch]) 592 | assert_equal('owner/repo', result['params'][:slug]) 593 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 594 | end 595 | 596 | def test_heroku 597 | ENV['HEROKU_TEST_RUN_ID'] = '454f5dc9-afa4-433f-bb28-84678a00fd98' 598 | ENV['HEROKU_TEST_RUN_BRANCH'] = 'master' 599 | ENV['HEROKU_TEST_RUN_COMMIT_VERSION'] = '743b04806ea677403aa2ff26c6bdeb85005de658' 600 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 601 | 602 | result = upload 603 | assert_equal('heroku', result['params'][:service]) 604 | assert_equal('743b04806ea677403aa2ff26c6bdeb85005de658', result['params'][:commit]) 605 | assert_equal('454f5dc9-afa4-433f-bb28-84678a00fd98', result['params'][:build]) 606 | assert_equal('master', result['params'][:branch]) 607 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 608 | end 609 | 610 | def test_bitbucket_pr 611 | ENV['CI'] = 'true' 612 | ENV['BITBUCKET_BUILD_NUMBER'] = '100' 613 | ENV['BITBUCKET_BRANCH'] = 'master' 614 | ENV['BITBUCKET_COMMIT'] = '743b04806ea67' 615 | ENV['VCS_COMMIT_ID'] = '743b04806ea677403aa2ff26c6bdeb85005de658' 616 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 617 | 618 | result = upload 619 | assert_equal('bitbucket', result['params'][:service]) 620 | assert_equal('743b04806ea677403aa2ff26c6bdeb85005de658', result['params'][:commit]) 621 | assert_equal('100', result['params'][:build]) 622 | assert_equal('master', result['params'][:branch]) 623 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 624 | end 625 | 626 | def test_bitbucket 627 | ENV['CI'] = 'true' 628 | ENV['BITBUCKET_BUILD_NUMBER'] = '100' 629 | ENV['BITBUCKET_BRANCH'] = 'master' 630 | ENV['BITBUCKET_COMMIT'] = '743b04806ea677403aa2ff26c6bdeb85005de658' 631 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 632 | 633 | result = upload 634 | assert_equal('bitbucket', result['params'][:service]) 635 | assert_equal('743b04806ea677403aa2ff26c6bdeb85005de658', result['params'][:commit]) 636 | assert_equal('100', result['params'][:build]) 637 | assert_equal('master', result['params'][:branch]) 638 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 639 | end 640 | 641 | def test_codebuild 642 | ENV['CODEBUILD_CI'] = "true" 643 | ENV['CODEBUILD_BUILD_ID'] = "codebuild-project:458dq3q8-7354-4513-8702-ea7b9c81efb3" 644 | ENV['CODEBUILD_RESOLVED_SOURCE_VERSION'] = 'd653b934ed59c1a785cc1cc79d08c9aaa4eba73b' 645 | ENV['CODEBUILD_WEBHOOK_HEAD_REF'] = 'refs/heads/master' 646 | ENV['CODEBUILD_SOURCE_VERSION'] = 'pr/123' 647 | ENV['CODEBUILD_SOURCE_REPO_URL'] = 'https://github.com/owner/repo.git' 648 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 649 | 650 | result = upload 651 | 652 | assert_equal("codebuild", result['params'][:service]) 653 | assert_equal("d653b934ed59c1a785cc1cc79d08c9aaa4eba73b", result['params'][:commit]) 654 | assert_equal("codebuild-project:458dq3q8-7354-4513-8702-ea7b9c81efb3", result['params'][:build]) 655 | assert_equal("codebuild-project:458dq3q8-7354-4513-8702-ea7b9c81efb3", result['params'][:job]) 656 | assert_equal("owner/repo", result['params'][:slug]) 657 | assert_equal("master", result['params'][:branch]) 658 | assert_equal("123", result['params'][:pr]) 659 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 660 | end 661 | 662 | def test_codebuild_codepipeline 663 | ENV['CODEBUILD_CI'] = "true" 664 | ENV['CODEBUILD_INITIATOR'] = "codepipeline/codepipeline-name" 665 | ENV['CODEBUILD_BUILD_ID'] = "codebuild-project:458dq3q8-7354-4513-8702-ea7b9c81efb3" 666 | ENV['CODEBUILD_BUILD_URL'] = "http://codebuild" 667 | ENV['CODEBUILD_RESOLVED_SOURCE_VERSION'] = 'd653b934ed59c1a785cc1cc79d08c9aaa4eba73b' 668 | ENV['CODEBUILD_WEBHOOK_HEAD_REF'] = nil 669 | ENV['CODEBUILD_SOURCE_VERSION'] = 'arn:aws:s3:::bucket/codepipeline-name/SourceActionName/cf4IT8b' 670 | ENV['CODEBUILD_SOURCE_REPO_URL'] = nil 671 | # set CodeStarSourceConnection namespace and CodeBuild variables manually in CodePipeline, see source code comments 672 | ENV['CODESTAR_BRANCH_NAME'] = 'branch-name' 673 | ENV['CODESTAR_FULL_REPOSITORY_NAME'] = 'owner/repo' 674 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 675 | 676 | result = upload 677 | 678 | assert_equal("codebuild", result['params'][:service]) 679 | assert_equal("d653b934ed59c1a785cc1cc79d08c9aaa4eba73b", result['params'][:commit]) 680 | assert_equal("codebuild-project:458dq3q8-7354-4513-8702-ea7b9c81efb3", result['params'][:build]) 681 | assert_equal("http://codebuild", result['params'][:build_url]) 682 | assert_equal("codebuild-project:458dq3q8-7354-4513-8702-ea7b9c81efb3", result['params'][:job]) 683 | assert_equal("owner/repo", result['params'][:slug]) 684 | assert_equal("branch-name", result['params'][:branch]) 685 | assert_nil(result['params'][:pr]) 686 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 687 | end 688 | 689 | def test_codebuild_source_version_is_other_than_pr_number 690 | ENV['CODEBUILD_CI'] = 'true' 691 | ENV['CODEBUILD_BUILD_ID'] = 'codebuild-project:458dq3q8-7354-4513-8702-ea7b9c81efb3' 692 | ENV['CODEBUILD_RESOLVED_SOURCE_VERSION'] = 'd653b934ed59c1a785cc1cc79d08c9aaa4eba73b' 693 | ENV['CODEBUILD_WEBHOOK_HEAD_REF'] = 'refs/heads/master' 694 | ENV['CODEBUILD_SOURCE_VERSION'] = 'git-commit-hash-12345' 695 | ENV['CODEBUILD_SOURCE_REPO_URL'] = 'https://github.com/owner/repo.git' 696 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 697 | 698 | result = upload 699 | 700 | assert_equal('codebuild', result['params'][:service]) 701 | assert_equal('d653b934ed59c1a785cc1cc79d08c9aaa4eba73b', result['params'][:commit]) 702 | assert_equal('codebuild-project:458dq3q8-7354-4513-8702-ea7b9c81efb3', result['params'][:build]) 703 | assert_equal('git-commit-hash-12345', result['params'][:pr]) 704 | assert_equal('owner/repo', result['params'][:slug]) 705 | assert_equal('master', result['params'][:branch]) 706 | assert_equal('f881216b-b5c0-4eb1-8f21-b51887d1d506', result['params']['token']) 707 | end 708 | 709 | def test_cirrus_ci 710 | ENV['CIRRUS_CI'] = 'true' 711 | ENV['CIRRUS_BRANCH'] = 'master' 712 | ENV['CIRRUS_BUILD_ID'] = '12345' 713 | ENV['CIRRUS_TASK_ID'] = '54321' 714 | ENV['CIRRUS_CHANGE_IN_REPO'] = 'd653b934ed59c1a785cc1cc79d08c9aaa4eba73b' 715 | ENV['CIRRUS_TASK_NAME'] = 'test' 716 | ENV['CIRRUS_PR'] = '10' 717 | ENV['CIRRUS_REPO_FULL_NAME'] = 'owner/repo' 718 | 719 | result = upload 720 | 721 | assert_equal('cirrus-ci', result['params'][:service]) 722 | assert_equal('d653b934ed59c1a785cc1cc79d08c9aaa4eba73b', result['params'][:commit]) 723 | assert_equal('12345', result['params'][:build]) 724 | assert_equal('10', result['params'][:pr]) 725 | assert_equal('owner/repo', result['params'][:slug]) 726 | assert_equal('master', result['params'][:branch]) 727 | end 728 | 729 | def test_filenames_are_shortened_correctly 730 | ENV['CODECOV_TOKEN'] = 'f881216b-b5c0-4eb1-8f21-b51887d1d506' 731 | 732 | formatter = SimpleCov::Formatter::Codecov.new 733 | result = stub('SimpleCov::Result', files: [ 734 | stub_file('path/lib/something.rb', []), 735 | stub_file('path/path/lib/path_somefile.rb', []) 736 | ]) 737 | SimpleCov.stubs(:root).returns('path') 738 | data = formatter.format(result) 739 | puts data 740 | puts data['params'] 741 | assert_equal(data['coverage'].to_json, { 742 | 'lib/something.rb' => [nil], 743 | 'path/lib/path_somefile.rb' => [nil] 744 | }.to_json) 745 | end 746 | 747 | def test_invalid_token 748 | stub_request(:post, %r{https:\/\/codecov.io\/upload}) 749 | .to_return( 750 | status: 400, 751 | body: "HTTP 400\n" \ 752 | 'Provided token is not a UUID.' 753 | ) 754 | 755 | ENV['CODECOV_TOKEN'] = 'fake' 756 | result = upload(false) 757 | assert_equal(false, result['result']['uploaded']) 758 | branch = `git rev-parse --abbrev-ref HEAD`.strip 759 | assert_equal(branch != 'HEAD' ? branch : 'master', result['params'][:branch]) 760 | assert_equal(`git rev-parse HEAD`.strip, result['params'][:commit]) 761 | end 762 | end 763 | --------------------------------------------------------------------------------