couve 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +1 -1
- data/README.md +37 -0
- data/lib/couve/parser.rb +28 -9
- data/lib/couve/version.rb +1 -1
- data/lib/couve.rb +38 -7
- metadata +2 -3
- data/couve.gemspec +0 -31
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6733bb77b61c6eeb3d8154eb7dc8e04afdae265464983866b237c7474198612a
|
|
4
|
+
data.tar.gz: 2418be05c9acbf968ac32019ef0d86918b117b68a9f77719d4295e88c074188c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 819b2d0c9f768011eb37641ac59a7ac94077222071e867a4a1a50cc51a6ece7bf4028bac072463551e266940e0d12d6b0ce72b15e76070f651a05bef5f4e0257
|
|
7
|
+
data.tar.gz: 9f4cb0dc81003cacd9df9a4702e4d4bc4b4950747d84a1c28ca7c7783241cd3b823e1589a873da0b792123527bf2b8a90c0f08dec66019f6821a6256c8585d42
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.8.0] - 2026-06-05
|
|
4
|
+
|
|
5
|
+
- Add `--fail-on-low-coverage` flag to exit with a non-zero status when any reported file is below 100% coverage.
|
|
6
|
+
|
|
7
|
+
## [0.7.0] - 2026-06-05
|
|
8
|
+
|
|
9
|
+
- Add `--changed-files` to report the coverage status of a given list of files (e.g. a branch's changed files), including fully covered ones, instead of the project-wide below-100% view.
|
|
10
|
+
- Rename the report heading from "Coverage problems" to "Coverage report".
|
|
11
|
+
|
|
3
12
|
## [0.6.0] - 2026-06-04
|
|
4
13
|
|
|
5
14
|
- Add Markdown output format, selected from the output file extension (`.md`). HTML remains the default.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -65,6 +65,43 @@ couve coverage.json coverage.md # post to the PR
|
|
|
65
65
|
gh pr comment "$PR_NUMBER" --body-file coverage.md
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
+
### Reporting only the files you changed
|
|
69
|
+
|
|
70
|
+
By default the report lists every file in the coverage data that is below 100%. With `--changed-files` you flip that around: instead of a project-wide view, you get the coverage status of exactly the files you touched on a branch — including the ones that are fully covered.
|
|
71
|
+
|
|
72
|
+
Pass a file with one repo-relative path per line, or `-` to read the list from standard input:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
git diff --name-only origin/main...HEAD > changed.txt
|
|
76
|
+
couve coverage.json report.md --changed-files changed.txt
|
|
77
|
+
|
|
78
|
+
# or pipe the list straight in:
|
|
79
|
+
git diff --name-only origin/main...HEAD | couve coverage.json report.md --changed-files -
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Only files that appear both in the list and in the coverage data are shown; the rest of the project is left out. Coverage is still reported per file (the whole file's percentage and missed lines), not just the lines in your diff.
|
|
83
|
+
|
|
84
|
+
### Failing the build on low coverage
|
|
85
|
+
|
|
86
|
+
By default couve always exits `0` — it only generates the report. Pass `--fail-on-low-coverage` to make couve exit `1` when any **reported** file is below the green threshold, i.e. rated 🔴 or 🟡 (`< 66.66%`):
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
couve coverage.json report.md --fail-on-low-coverage
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The report is written **before** couve exits, so the offending files stay visible in the report (and in any PR comment built from it). The offending files are also printed to standard error:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
couve: coverage below 66.66% in app/models/foo.rb, app/services/bar.rb
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The threshold is the same fixed band used for the rating indicators; there is nothing to configure. The flag respects `--changed-files` scope: when you only report the files you changed, only those files are evaluated, so a green (or empty) changed-file set passes the build even if untouched files elsewhere are poorly covered.
|
|
99
|
+
|
|
100
|
+
```sh
|
|
101
|
+
# Post the report to the PR, then redden the build if a changed file is under-covered:
|
|
102
|
+
git diff --name-only origin/main...HEAD | couve coverage.json report.md --changed-files - --fail-on-low-coverage
|
|
103
|
+
```
|
|
104
|
+
|
|
68
105
|
## Development
|
|
69
106
|
|
|
70
107
|
To contribute to Couve's development, follow these steps:
|
data/lib/couve/parser.rb
CHANGED
|
@@ -3,10 +3,19 @@
|
|
|
3
3
|
require "json"
|
|
4
4
|
|
|
5
5
|
module Couve
|
|
6
|
-
class Parser
|
|
7
|
-
|
|
6
|
+
class Parser # rubocop:disable Metrics/ClassLength
|
|
7
|
+
RED_THRESHOLD = 33.33
|
|
8
|
+
GREEN_THRESHOLD = 66.66
|
|
9
|
+
|
|
10
|
+
def initialize(coverage, changed_files: nil)
|
|
8
11
|
@coverage = JSON.parse(coverage, symbolize_names: true)
|
|
9
|
-
|
|
12
|
+
|
|
13
|
+
if changed_files
|
|
14
|
+
@coverage[:source_files].select! { |file| changed_files.include?(file[:name]) }
|
|
15
|
+
else
|
|
16
|
+
@coverage[:source_files].reject! { |file| file[:covered_percent] == 100 }
|
|
17
|
+
end
|
|
18
|
+
|
|
10
19
|
@coverage[:source_files].sort_by! { |file| file[:covered_percent] }
|
|
11
20
|
end
|
|
12
21
|
|
|
@@ -16,7 +25,7 @@ module Couve
|
|
|
16
25
|
<body>
|
|
17
26
|
<div class="container mt-5">
|
|
18
27
|
<h1 class="display-5">
|
|
19
|
-
Coverage
|
|
28
|
+
Coverage report
|
|
20
29
|
</h1>
|
|
21
30
|
|
|
22
31
|
<table class="table table-hover mt-5">
|
|
@@ -47,7 +56,7 @@ module Couve
|
|
|
47
56
|
end
|
|
48
57
|
|
|
49
58
|
<<~MARKDOWN
|
|
50
|
-
## Coverage
|
|
59
|
+
## Coverage report
|
|
51
60
|
|
|
52
61
|
| Rating | Coverage | File | Not covered lines |
|
|
53
62
|
| :---: | ---: | :--- | :--- |
|
|
@@ -55,6 +64,16 @@ module Couve
|
|
|
55
64
|
MARKDOWN
|
|
56
65
|
end
|
|
57
66
|
|
|
67
|
+
def low_coverage_files
|
|
68
|
+
@coverage[:source_files]
|
|
69
|
+
.select { |source_file| source_file[:covered_percent].round(2) < GREEN_THRESHOLD }
|
|
70
|
+
.map { |source_file| source_file[:name] }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def low_coverage?
|
|
74
|
+
low_coverage_files.any?
|
|
75
|
+
end
|
|
76
|
+
|
|
58
77
|
private
|
|
59
78
|
|
|
60
79
|
# rubocop:disable Metrics/MethodLength
|
|
@@ -92,9 +111,9 @@ module Couve
|
|
|
92
111
|
# rubocop:enable Metrics/MethodLength
|
|
93
112
|
|
|
94
113
|
def percentage_bar_color(percentage)
|
|
95
|
-
if percentage <
|
|
114
|
+
if percentage < RED_THRESHOLD
|
|
96
115
|
"bg-danger"
|
|
97
|
-
elsif percentage <
|
|
116
|
+
elsif percentage < GREEN_THRESHOLD
|
|
98
117
|
"bg-warning"
|
|
99
118
|
else
|
|
100
119
|
"bg-success"
|
|
@@ -102,9 +121,9 @@ module Couve
|
|
|
102
121
|
end
|
|
103
122
|
|
|
104
123
|
def percentage_indicator(percentage)
|
|
105
|
-
if percentage <
|
|
124
|
+
if percentage < RED_THRESHOLD
|
|
106
125
|
"🔴"
|
|
107
|
-
elsif percentage <
|
|
126
|
+
elsif percentage < GREEN_THRESHOLD
|
|
108
127
|
"🟡"
|
|
109
128
|
else
|
|
110
129
|
"🟢"
|
data/lib/couve/version.rb
CHANGED
data/lib/couve.rb
CHANGED
|
@@ -1,20 +1,51 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "optparse"
|
|
4
|
+
|
|
3
5
|
require_relative "couve/version"
|
|
4
6
|
require_relative "couve/parser"
|
|
5
7
|
|
|
6
8
|
module Couve
|
|
7
|
-
def self.start
|
|
8
|
-
coverage_file =
|
|
9
|
-
output_file = ARGV[1]
|
|
9
|
+
def self.start(argv = ARGV)
|
|
10
|
+
coverage_file, output_file, changed_files_source, fail_on_low_coverage = parse_arguments(argv)
|
|
10
11
|
|
|
11
12
|
coverage = File.read(coverage_file)
|
|
12
|
-
parser = Couve::Parser.new(coverage)
|
|
13
|
+
parser = Couve::Parser.new(coverage, changed_files: changed_files(changed_files_source))
|
|
13
14
|
|
|
14
15
|
report = output_file.end_with?(".md") ? parser.to_markdown : parser.to_html
|
|
15
16
|
|
|
16
|
-
File.open(output_file, "w")
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
File.open(output_file, "w") { |f| f.puts report }
|
|
18
|
+
|
|
19
|
+
return unless fail_on_low_coverage && parser.low_coverage?
|
|
20
|
+
|
|
21
|
+
warn "couve: coverage below #{Couve::Parser::GREEN_THRESHOLD}% in #{parser.low_coverage_files.join(", ")}"
|
|
22
|
+
exit 1
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.parse_arguments(argv) # rubocop:disable Metrics/MethodLength
|
|
26
|
+
argv = argv.dup
|
|
27
|
+
changed_files_source = nil
|
|
28
|
+
fail_on_low_coverage = false
|
|
29
|
+
|
|
30
|
+
OptionParser.new do |opts|
|
|
31
|
+
opts.on("--changed-files PATH", "Only report the files listed in PATH (use - for stdin)") do |path|
|
|
32
|
+
changed_files_source = path
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
opts.on("--fail-on-low-coverage",
|
|
36
|
+
"Exit 1 if any reported file is below #{Couve::Parser::GREEN_THRESHOLD}% coverage") do
|
|
37
|
+
fail_on_low_coverage = true
|
|
38
|
+
end
|
|
39
|
+
end.parse!(argv)
|
|
40
|
+
|
|
41
|
+
[argv[0], argv[1], changed_files_source, fail_on_low_coverage]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.changed_files(source)
|
|
45
|
+
return nil unless source
|
|
46
|
+
|
|
47
|
+
contents = source == "-" ? $stdin.read : File.read(source)
|
|
48
|
+
|
|
49
|
+
contents.lines.map { |line| line.strip.delete_prefix("./") }.reject(&:empty?)
|
|
19
50
|
end
|
|
20
51
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: couve
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Cezinha
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description:
|
|
14
14
|
email:
|
|
@@ -32,7 +32,6 @@ files:
|
|
|
32
32
|
- bin/guard
|
|
33
33
|
- bin/rubocop
|
|
34
34
|
- bin/setup
|
|
35
|
-
- couve.gemspec
|
|
36
35
|
- exe/couve
|
|
37
36
|
- lib/couve.rb
|
|
38
37
|
- lib/couve/parser.rb
|
data/couve.gemspec
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "lib/couve/version"
|
|
4
|
-
|
|
5
|
-
Gem::Specification.new do |spec|
|
|
6
|
-
spec.name = "couve"
|
|
7
|
-
spec.version = Couve::VERSION
|
|
8
|
-
spec.authors = ["Cezinha"]
|
|
9
|
-
spec.email = ["cesar@asseinfo.com.br"]
|
|
10
|
-
spec.metadata = { "rubygems_mfa_required" => "true" }
|
|
11
|
-
|
|
12
|
-
spec.summary = "Generate a human readable report for CodeClimate test-reporter gem."
|
|
13
|
-
|
|
14
|
-
# Specify which files should be added to the gem when it is released.
|
|
15
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
16
|
-
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
17
|
-
`git ls-files -z`.split("\x0").reject do |f|
|
|
18
|
-
(f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
spec.bindir = "exe"
|
|
22
|
-
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
23
|
-
spec.require_paths = ["lib", "lib/couve"]
|
|
24
|
-
spec.required_ruby_version = ">= 3"
|
|
25
|
-
|
|
26
|
-
# Uncomment to register a new dependency of your gem
|
|
27
|
-
# spec.add_dependency "example-gem", "~> 1.0"
|
|
28
|
-
|
|
29
|
-
# For more information and examples about making a new gem, checkout our
|
|
30
|
-
# guide at: https://bundler.io/guides/creating_gem.html
|
|
31
|
-
end
|