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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 91781d6bb92f7f023f6ab39ea4d0f7f707318bef6d09ef8cced4a9c2810e78c2
4
- data.tar.gz: ff8ad3ff9c1a7c7c2318ab23d53db3a45f629d9b6c2f44104bf7c5d89beccb3b
3
+ metadata.gz: 6733bb77b61c6eeb3d8154eb7dc8e04afdae265464983866b237c7474198612a
4
+ data.tar.gz: 2418be05c9acbf968ac32019ef0d86918b117b68a9f77719d4295e88c074188c
5
5
  SHA512:
6
- metadata.gz: b921af295d7211b7db8d8fd3e3bea3628f64529ccc031a46a02fc88f42fada6b76acc21f4309f80d2faaea2783fa02783519c3503f67a2d44cfe3054b7c5831b
7
- data.tar.gz: fb3836c3e78b7c686f84b559e7344398bc1bed5e6ffca394c6025a4a3389a0b01914f7ab945fbd3a65f697a57b3598da7b8772c919c5b5c20499691c620111f5
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- couve (0.6.0)
4
+ couve (0.8.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
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
- def initialize(coverage)
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
- @coverage[:source_files].reject! { |file| file[:covered_percent] == 100 }
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 problems
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 problems
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 < 33.33
114
+ if percentage < RED_THRESHOLD
96
115
  "bg-danger"
97
- elsif percentage < 66.66
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 < 33.33
124
+ if percentage < RED_THRESHOLD
106
125
  "🔴"
107
- elsif percentage < 66.66
126
+ elsif percentage < GREEN_THRESHOLD
108
127
  "🟡"
109
128
  else
110
129
  "🟢"
data/lib/couve/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Couve
4
- VERSION = "0.6.0"
4
+ VERSION = "0.8.0"
5
5
  end
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 = ARGV[0]
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") do |f|
17
- f.puts report
18
- end
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.6.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-04 00:00:00.000000000 Z
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