circleci-coverage_reporter 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5d57e277c4ae42ade0ad0c319de9c2a17699c8e5
4
+ data.tar.gz: 3861f10bb0fbc4428a9c90f2e5af9081f224d738
5
+ SHA512:
6
+ metadata.gz: 9d2e5c7d83571b05ec2b81451d646242e986cb9f8b1a9cb30194e10201c72b6667c5e89c2f6b01e4c289a6b74237e92c83178925810bf1b5dd4437a01b5a5471
7
+ data.tar.gz: acb7bba6f2a64c0ae0ae82b11ba5f38684fc7c185dc25ec41b7e2be77243446940e0a2dd340d97202d12e0833c31f9095b7ce0358ca1a6938efcdd359e22781d
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/examples.txt
9
+ /spec/reports/
10
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,11 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.4
3
+
4
+ Metrics/LineLength:
5
+ Max: 125
6
+
7
+ Style/Documentation:
8
+ Enabled: false
9
+
10
+ Style/FrozenStringLiteralComment:
11
+ Enabled: false
@@ -0,0 +1,10 @@
1
+ # Change Log
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](http://keepachangelog.com/)
5
+ and this project adheres to [Semantic Versioning](http://semver.org/).
6
+
7
+ ## 0.0.0 - 2017-03-12
8
+ ### Added
9
+
10
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development, :test do
6
+ gem 'rake', '~> 11.0'
7
+ gem 'rspec', '~> 3.5'
8
+ gem 'rspec_junit_formatter', '~> 0.2', require: false
9
+ gem 'rubocop', '~> 0.42'
10
+ gem 'simplecov', '~> 0.13'
11
+ gem 'yard', '~> 0.9'
12
+ end
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Increments inc,
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.
@@ -0,0 +1,57 @@
1
+ # CircleCI::CoverageReporter
2
+
3
+ [![CircleCI](https://circleci.com/gh/increments/circleci-coverage_reporter.svg?style=svg)](https://circleci.com/gh/increments/circleci-coverage_reporter)
4
+
5
+ **CircleCI::CoverageReporter** reports test coverage to your GitHub repository.
6
+
7
+ ## Getting started
8
+
9
+ 1. Add CircleCI::CoverageReporter to your `Gemfile` and `bundle install`:
10
+
11
+ ```ruby
12
+ gem 'circleci-coverage_reporter', group: :test
13
+ ```
14
+
15
+ 2. Load `circleci/coverage_reporter/rake_task` in your `Rakefile`:
16
+
17
+ ```ruby
18
+ require 'circleci/coverage_reporter/rake_task' if ENV['CIRCLECI']
19
+ ```
20
+
21
+ 3. Issue CircleCI and GitHub token and add them to build environment variables with the following nameing convention:
22
+
23
+ Name | Value
24
+ -----------------------------------|----------------------------------------------------------------
25
+ `COVERAGE_REPORTER_CIRCLECI_TOKEN` | CircleCI API token with "view-builds" scope
26
+ `COVERAGE_REPORTER_VCS_TOKEN` | GitHub personal access token with "repo" or "public_repo" scope
27
+
28
+ 4. Add the following steop to your `circle.yml`:
29
+
30
+ ```yaml
31
+ test:
32
+ post:
33
+ - bundle exec circleci:report_coverage
34
+ ```
35
+
36
+ ## Example
37
+
38
+ ![image](https://cloud.githubusercontent.com/assets/96157/23824715/e16f0eac-06be-11e7-81e8-f818b14a52b4.png)
39
+
40
+ ## Configuring CircleCI::CoverageReporter
41
+
42
+ ```ruby
43
+ CircleCI::CoverageReporter.configure do |config|
44
+ config.circleci_token = YOUR_CIRCLECI_API_TOKEN
45
+ config.vcr_token = YOUR_GITHUB_PERSONAL_ACCESS_TOKEN
46
+ end
47
+ ```
48
+
49
+ then:
50
+
51
+ ```ruby
52
+ CircleCI::CoverageReporter.run
53
+ ```
54
+
55
+ ## License
56
+
57
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,15 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+ require 'yard'
5
+ require 'circleci/coverage_reporter/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new do |task|
8
+ task.verbose = false
9
+ end
10
+
11
+ RuboCop::RakeTask.new
12
+
13
+ YARD::Rake::YardocTask.new
14
+
15
+ task default: [:spec, :rubocop]
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,9 @@
1
+ machine:
2
+ ruby:
3
+ version: 2.4.0
4
+ test:
5
+ override:
6
+ - bundle exec rspec --format progress --require rspec_junit_formatter --format RspecJunitFormatter -o $CIRCLE_TEST_REPORTS/rspec/junit.xml
7
+ - bundle exec rubocop
8
+ post:
9
+ - bundle exec rake circleci:report_coverage
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'circleci/coverage_reporter/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'circleci-coverage_reporter'
8
+ spec.version = CircleCI::CoverageReporter::Version.to_s
9
+ spec.authors = ['Yuku Takahashi']
10
+ spec.email = ['yuku@qiita.com']
11
+
12
+ spec.summary = 'Report test coverage to your GitHub repository'
13
+ spec.description = spec.summary
14
+ spec.homepage = 'https://github.com/increments/circleci-coverage_reporter'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^spec/}) }
18
+ spec.bindir = 'exe'
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_dependency 'faraday', '~> 0.9'
23
+ spec.add_development_dependency 'bundler', '~> 1.12'
24
+ end
@@ -0,0 +1,29 @@
1
+ require_relative 'coverage_reporter/configuration'
2
+ require_relative 'coverage_reporter/client'
3
+ require_relative 'coverage_reporter/runner'
4
+
5
+ module CircleCI
6
+ module CoverageReporter
7
+ # @return [Configuration]
8
+ def self.configuration
9
+ @configuration ||= Configuration.new
10
+ end
11
+
12
+ # @return [Client]
13
+ def self.client
14
+ @client ||= Client.new(configuration)
15
+ end
16
+
17
+ # Yields the global configuration to a block.
18
+ #
19
+ # @yield [Configuration]
20
+ def self.configure
21
+ yield configuration if block_given?
22
+ end
23
+
24
+ # @return [void]
25
+ def self.run
26
+ Runner.new.run
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,44 @@
1
+ require_relative 'report'
2
+
3
+ module CircleCI
4
+ module CoverageReporter
5
+ # @abstract Subclass and override {#name}, {#create_build_result} and {#create_current_result}
6
+ # to implement a custom Reporter class.
7
+ class AbstractReporter
8
+ # @param base_build [Build, nil]
9
+ # @param previous_build [Build, nil]
10
+ # @return [Report]
11
+ def report(base_build, previous_build)
12
+ Report.new(
13
+ self,
14
+ current: create_current_result,
15
+ base: create_build_result(base_build),
16
+ previous: create_build_result(previous_build)
17
+ )
18
+ end
19
+
20
+ # @return [String]
21
+ def name
22
+ raise NotImplementedError
23
+ end
24
+
25
+ private
26
+
27
+ # @param build [Build, nil]
28
+ # @return [AbstractResult, nil]
29
+ def create_build_result(build) # rubocop:disable Lint/UnusedMethodArgument
30
+ raise NotImplementedError
31
+ end
32
+
33
+ # @return [AbstractResult]
34
+ def create_current_result
35
+ raise NotImplementedError
36
+ end
37
+
38
+ # @return [Client]
39
+ def client
40
+ CoverageReporter.client
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,16 @@
1
+ module CircleCI
2
+ module CoverageReporter
3
+ # @abstract Subclass and override {#coverage} to implement a custom Result class.
4
+ class AbstractResult
5
+ # @return [Float]
6
+ def coverage
7
+ raise NotImplementedError
8
+ end
9
+
10
+ # @return [String] URL for coverage index.html
11
+ def url
12
+ raise NotImplementedError
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ module CircleCI
2
+ module CoverageReporter
3
+ # @abstract Subclass and override {#create_comment} to implement a custom VCS client class.
4
+ class AbstractVCSClient
5
+ # @param token [String]
6
+ def initialize(token)
7
+ @token = token
8
+ end
9
+
10
+ # @param reports [Array<Report>]
11
+ # @return [void]
12
+ def create_comment(reports) # rubocop:disable Lint/UnusedMethodArgument
13
+ raise NotImplementedError
14
+ end
15
+
16
+ private
17
+
18
+ attr_reader :token
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ module CircleCI
2
+ module CoverageReporter
3
+ # Encapsulate a CircleCI artifact
4
+ Artifact = Struct.new(:path, :pretty_path, :node_index, :url) do
5
+ # @return [Boolean]
6
+ def end_with?(value)
7
+ pretty_path.end_with?(value)
8
+ end
9
+
10
+ # @return [String]
11
+ def body
12
+ @body ||= CoverageReporter.client.get(url).body
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ module CircleCI
2
+ module CoverageReporter
3
+ # Encapsulate a CircleCI build
4
+ Build = Struct.new(:vcs_revision, :build_number) do
5
+ # @param revision [String]
6
+ # @return [Boolean]
7
+ def match?(revision)
8
+ vcs_revision.start_with?(revision)
9
+ end
10
+
11
+ # @return [Array<Artifact>]
12
+ def artifacts
13
+ @artifacts ||= CoverageReporter.client.artifacts(build_number)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,103 @@
1
+ require 'faraday'
2
+
3
+ require_relative 'artifact'
4
+ require_relative 'build'
5
+
6
+ module CircleCI
7
+ module CoverageReporter
8
+ class Client
9
+ CIRCLECI_ENDPOINT = 'https://circleci.com/api/v1.1'.freeze
10
+
11
+ # @return [Configuration]
12
+ attr_reader :configuration
13
+
14
+ # @param configuration [Configuration]
15
+ def initialize(configuration)
16
+ @configuration = configuration
17
+ end
18
+
19
+ # @param build_number [Integer, nil]
20
+ # @return [Build, nil]
21
+ def single_build(build_number)
22
+ return unless build_number
23
+ create_build(JSON.parse(get(single_build_url(build_number)).body))
24
+ end
25
+
26
+ # @param build_number [Integer]
27
+ # @return [Array<Artifact>]
28
+ def artifacts(build_number)
29
+ JSON.parse(get(artifacts_url(build_number)).body).map do |hash|
30
+ Artifact.new(hash['path'], hash['pretty_path'], hash['node_index'], hash['url'])
31
+ end
32
+ end
33
+
34
+ # @param revision [String]
35
+ # @param branch [String, nil]
36
+ # @return [Integer, nil]
37
+ def build_number_by_revision(revision, branch: nil)
38
+ build = recent_builds(branch).find { |b| b.match?(revision) }
39
+ build ? build.build_number : nil
40
+ end
41
+
42
+ # @param url [String]
43
+ # @param params [Hash]
44
+ # @return [Faraday::Response]
45
+ def get(url, params = {})
46
+ params['circle-token'] = configuration.circleci_token
47
+ Faraday.get(url + '?' + params.map { |k, v| "#{k}=#{v}" }.join('&'))
48
+ end
49
+
50
+ private
51
+
52
+ # @param build_number [Integer]
53
+ # @return [String]
54
+ def artifacts_url(build_number)
55
+ [
56
+ CIRCLECI_ENDPOINT,
57
+ 'project',
58
+ configuration.vcs_type,
59
+ configuration.project,
60
+ build_number,
61
+ 'artifacts'
62
+ ].join('/')
63
+ end
64
+
65
+ # @param branch [String, nil]
66
+ # @return [Array<Build>]
67
+ def recent_builds(branch)
68
+ JSON.parse(get(recent_builds_url(branch), limit: 100).body).map(&method(:create_build))
69
+ end
70
+
71
+ # @param branch [String, nil]
72
+ # @return [String]
73
+ def recent_builds_url(branch)
74
+ elements = [
75
+ CIRCLECI_ENDPOINT,
76
+ 'project',
77
+ configuration.vcs_type,
78
+ configuration.project
79
+ ]
80
+ elements += ['tree', branch] if branch
81
+ elements.join('/')
82
+ end
83
+
84
+ # @param build_number [Integer]
85
+ # @return [String]
86
+ def single_build_url(build_number)
87
+ [
88
+ CIRCLECI_ENDPOINT,
89
+ 'project',
90
+ configuration.vcs_type,
91
+ configuration.project,
92
+ build_number
93
+ ].join('/')
94
+ end
95
+
96
+ # @param hash [Hash]
97
+ # @return [Build]
98
+ def create_build(hash)
99
+ Build.new(hash['vcs_revision'], hash['build_num'])
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,64 @@
1
+ require_relative 'simplecov/reporter'
2
+
3
+ module CircleCI
4
+ module CoverageReporter
5
+ class Configuration
6
+ DEFAULT_REPORTERS = [SimpleCov::Reporter.new].freeze
7
+ DEFAULT_VCS_TYPE = 'github'.freeze
8
+
9
+ attr_accessor :circleci_token, :vcs_token
10
+ attr_writer :artifacts_dir, :base_revision, :current_build_number, :current_revision, :previous_build_number,
11
+ :reporters, :repository_name, :user_name, :vcs_type
12
+
13
+ # @return [String]
14
+ def project
15
+ "#{user_name}/#{repository_name}"
16
+ end
17
+
18
+ # @return [Array<AbstractReporter>]
19
+ def reporters
20
+ @reporters ||= DEFAULT_REPORTERS
21
+ end
22
+
23
+ # @return [String]
24
+ def vcs_type
25
+ @vcs_type ||= DEFAULT_VCS_TYPE
26
+ end
27
+
28
+ # @return [String]
29
+ def artifacts_dir
30
+ @artifacts_dir ||= ENV['CIRCLE_ARTIFACTS']
31
+ end
32
+
33
+ # @return [String]
34
+ def base_revision
35
+ @base_revision ||= `git merge-base origin/master HEAD`.strip
36
+ end
37
+
38
+ # @return [Integer]
39
+ def current_build_number
40
+ @current_build_number ||= ENV['CIRCLE_BUILD_NUM']
41
+ end
42
+
43
+ # @return [String]
44
+ def current_revision
45
+ @current_revision ||= ENV['CIRCLE_SHA1']
46
+ end
47
+
48
+ # @return [Integer]
49
+ def previous_build_number
50
+ @previous_build_number ||= ENV['CIRCLE_PREVIOUS_BUILD_NUM'].to_i
51
+ end
52
+
53
+ # @return [String]
54
+ def repository_name
55
+ @repository_name ||= ENV['CIRCLE_PROJECT_REPONAME']
56
+ end
57
+
58
+ # @return [String]
59
+ def user_name
60
+ @user_name ||= ENV['CIRCLE_PROJECT_USERNAME']
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,26 @@
1
+ require_relative 'abstract_vcs_client'
2
+
3
+ module CircleCI
4
+ module CoverageReporter
5
+ class GitHubClient < AbstractVCSClient
6
+ # @note Implement {AbstractVCSClient#create_comment}
7
+ # @param reports [Array<Report>]
8
+ # @return [void]
9
+ def create_comment(reports)
10
+ Faraday.new(url: 'https://api.github.com').post do |req|
11
+ req.url ['/repos', configuration.project, 'commits', configuration.current_revision, 'comments'].join('/')
12
+ req.headers['Authorization'] = "token #{token}"
13
+ req.headers['Content-Type'] = 'application/json'
14
+ req.body = JSON.generate(body: reports.join("\n"))
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ # @return [Client]
21
+ def configuration
22
+ CoverageReporter.client.configuration
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ require 'circleci/coverage_reporter'
2
+
3
+ namespace :circleci do
4
+ desc 'Report test coverage'
5
+ task :report_coverage do
6
+ abort unless ENV['CIRCLECI']
7
+
8
+ CircleCI::CoverageReporter.configure do |config|
9
+ config.circleci_token = ENV['COVERAGE_REPORTER_CIRCLECI_TOKEN']
10
+ config.vcs_token = ENV['COVERAGE_REPORTER_VCS_TOKEN']
11
+ end
12
+
13
+ CircleCI::CoverageReporter.run
14
+ end
15
+ end
@@ -0,0 +1,72 @@
1
+ module CircleCI
2
+ module CoverageReporter
3
+ class Report
4
+ # @param reporter [AbstractReporter]
5
+ # @param current [AbstractResult]
6
+ # @param base [AbstractResult, nil]
7
+ # @param previous [AbstractResult, nil]
8
+ def initialize(reporter, current:, base:, previous:)
9
+ @reporter = reporter
10
+ @current_result = current
11
+ @base_result = base
12
+ @previous_result = previous
13
+ end
14
+
15
+ # @return [String]
16
+ def to_s
17
+ "#{link}: #{current_result.coverage}%#{emoji}#{progress}"
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :reporter, :current_result, :base_result, :previous_result
23
+
24
+ # @return [String]
25
+ def link
26
+ "[#{reporter.name}](#{current_result.url})"
27
+ end
28
+
29
+ # @return [String, nil]
30
+ def emoji
31
+ return unless base_result
32
+ if current_result.coverage < base_result.coverage
33
+ ' :chart_with_downwards_trend:'
34
+ elsif current_result.coverage > base_result.coverage
35
+ ' :chart_with_upwards_trend:'
36
+ end
37
+ end
38
+
39
+ # @return [String, nil]
40
+ def progress
41
+ elements = [base_progress, branch_progress].compact
42
+ elements.empty? ? nil : " (#{elements.join(', ')})"
43
+ end
44
+
45
+ # @return [String, nil]
46
+ def base_progress
47
+ return unless base_result
48
+ "[master](#{base_result.url}): #{diff(current_result, base_result)}"
49
+ end
50
+
51
+ # @return [String, nil]
52
+ def branch_progress
53
+ return unless previous_result
54
+ "[previous](#{previous_result.url}): #{diff(current_result, previous_result)}"
55
+ end
56
+
57
+ # @param after_result [AbstractResult]
58
+ # @param before_result [AbstractResult]
59
+ # @return [String]
60
+ def diff(after_result, before_result)
61
+ value = (after_result.coverage - before_result.coverage).round(2)
62
+ if value.positive?
63
+ "+#{value}"
64
+ elsif value.negative?
65
+ value.to_s
66
+ else
67
+ '±0'
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,60 @@
1
+ require_relative 'github_client'
2
+
3
+ module CircleCI
4
+ module CoverageReporter
5
+ class Runner
6
+ # @return [void]
7
+ def run
8
+ reports = reporters.map { |reporter| reporter.report(base_build, previous_build) }
9
+ vcs_client.create_comment(reports)
10
+ end
11
+
12
+ private
13
+
14
+ # @return [AbstractVCSClient]
15
+ def vcs_client
16
+ case client.configuration.vcs_type
17
+ when 'github'
18
+ GitHubClient.new(client.configuration.vcs_token)
19
+ else
20
+ raise NotImplementedError
21
+ end
22
+ end
23
+
24
+ # @return [Build]
25
+ def base_build
26
+ @base_build ||= client.single_build(base_build_number)
27
+ end
28
+
29
+ # @return [Build]
30
+ def previous_build
31
+ @previous_build ||= client.single_build(previous_build_number)
32
+ end
33
+
34
+ # @return [Client]
35
+ def client
36
+ CoverageReporter.client
37
+ end
38
+
39
+ # @return [String, nil]
40
+ def base_revision
41
+ client.configuration.base_revision
42
+ end
43
+
44
+ # @return [Integer, nil]
45
+ def previous_build_number
46
+ client.configuration.previous_build_number
47
+ end
48
+
49
+ # @return [Array<AbstractReporter>]
50
+ def reporters
51
+ client.configuration.reporters
52
+ end
53
+
54
+ # @return [Integer, nil]
55
+ def base_build_number
56
+ @base_build_number ||= client.build_number_by_revision(base_revision, branch: 'master')
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,36 @@
1
+ require_relative '../abstract_result'
2
+
3
+ module CircleCI
4
+ module CoverageReporter
5
+ module SimpleCov
6
+ class BuildResult < AbstractResult
7
+ # @param build [Build]
8
+ def initialize(build)
9
+ @build = build
10
+ end
11
+
12
+ # @note Implement {AbstractResult#coverage}
13
+ # @return [Float]
14
+ def coverage
15
+ JSON.parse(find_artifact('.last_run.json').body)['result']['covered_percent']
16
+ end
17
+
18
+ # @note Implement {AbstractResult#url}
19
+ # @return [String]
20
+ def url
21
+ find_artifact('index.html').url
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :build
27
+
28
+ # @param end_with [String]
29
+ # @return [Artifact]
30
+ def find_artifact(end_with)
31
+ build.artifacts.find { |a| a.end_with?(end_with) }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,48 @@
1
+ require_relative '../abstract_result'
2
+
3
+ module CircleCI
4
+ module CoverageReporter
5
+ module SimpleCov
6
+ class CurrentResult < AbstractResult
7
+ # @param path [String] path to coverage directory
8
+ def initialize(path)
9
+ @path = path
10
+ end
11
+
12
+ # @note Implement {AbstractResult#coverage}
13
+ # @return [Float]
14
+ def coverage
15
+ JSON.parse(File.read(join('.last_run.json')))['result']['covered_percent']
16
+ end
17
+
18
+ # @note Implement {AbstractResult#url}
19
+ # @return [String]
20
+ def url
21
+ [
22
+ 'https://circle-artifacts.com/gh',
23
+ configuration.project,
24
+ configuration.current_build_number,
25
+ 'artifacts',
26
+ "0#{configuration.artifacts_dir}",
27
+ path,
28
+ 'index.html'
29
+ ].join('/')
30
+ end
31
+
32
+ private
33
+
34
+ attr_reader :path
35
+
36
+ # @return
37
+ def join(name)
38
+ File.join(configuration.artifacts_dir, path, name)
39
+ end
40
+
41
+ # @return [Client]
42
+ def configuration
43
+ CoverageReporter.client.configuration
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,44 @@
1
+ require 'json'
2
+
3
+ require_relative '../abstract_reporter'
4
+ require_relative 'build_result'
5
+ require_relative 'current_result'
6
+
7
+ module CircleCI
8
+ module CoverageReporter
9
+ module SimpleCov
10
+ class Reporter < AbstractReporter
11
+ DEFAULT_PATH = 'coverage'.freeze
12
+
13
+ # @param path [String] relative path from artifacts dir to coverage directory
14
+ def initialize(path = DEFAULT_PATH)
15
+ @path = path
16
+ end
17
+
18
+ # @note Implement {AbstractReporter#name}
19
+ # @return [String]
20
+ def name
21
+ 'SimpleCov'
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :path
27
+
28
+ # @note Implement {AbstractReporter#create_build_result}
29
+ # @param build [Build, nil]
30
+ # @return [BuildResult, nil]
31
+ def create_build_result(build)
32
+ return unless build
33
+ BuildResult.new(build)
34
+ end
35
+
36
+ # @note Implement {AbstractReporter#create_current_result}
37
+ # @return [CurrentResult]
38
+ def create_current_result
39
+ CurrentResult.new(path)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,13 @@
1
+ module CircleCI
2
+ module CoverageReporter
3
+ module Version
4
+ MAJOR = 0
5
+ MINOR = 1
6
+ PATCH = 0
7
+
8
+ def self.to_s
9
+ [MAJOR, MINOR, PATCH].join('.')
10
+ end
11
+ end
12
+ end
13
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: circleci-coverage_reporter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yuku Takahashi
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-03-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.9'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.12'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.12'
41
+ description: Report test coverage to your GitHub repository
42
+ email:
43
+ - yuku@qiita.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - ".rspec"
50
+ - ".rubocop.yml"
51
+ - CHANGELOG.md
52
+ - Gemfile
53
+ - LICENSE.txt
54
+ - README.md
55
+ - Rakefile
56
+ - bin/setup
57
+ - circle.yml
58
+ - circleci-coverage_reporter.gemspec
59
+ - lib/circleci/coverage_reporter.rb
60
+ - lib/circleci/coverage_reporter/abstract_reporter.rb
61
+ - lib/circleci/coverage_reporter/abstract_result.rb
62
+ - lib/circleci/coverage_reporter/abstract_vcs_client.rb
63
+ - lib/circleci/coverage_reporter/artifact.rb
64
+ - lib/circleci/coverage_reporter/build.rb
65
+ - lib/circleci/coverage_reporter/client.rb
66
+ - lib/circleci/coverage_reporter/configuration.rb
67
+ - lib/circleci/coverage_reporter/github_client.rb
68
+ - lib/circleci/coverage_reporter/rake_task.rb
69
+ - lib/circleci/coverage_reporter/report.rb
70
+ - lib/circleci/coverage_reporter/runner.rb
71
+ - lib/circleci/coverage_reporter/simplecov/build_result.rb
72
+ - lib/circleci/coverage_reporter/simplecov/current_result.rb
73
+ - lib/circleci/coverage_reporter/simplecov/reporter.rb
74
+ - lib/circleci/coverage_reporter/version.rb
75
+ homepage: https://github.com/increments/circleci-coverage_reporter
76
+ licenses:
77
+ - MIT
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.5.1
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Report test coverage to your GitHub repository
99
+ test_files: []