rspec-circleci-coverage 0.1.93

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d7701549e8db64ecb9f5c7542516bdaff16181b3d7ff439bce08f6d13d5953c4
4
+ data.tar.gz: 289634d878db811312ee09d44a823aea205c420ca5a881454c431407ba28782b
5
+ SHA512:
6
+ metadata.gz: 071a80eaa21b9b8e683a7a2f7e15dc61e1588536d39a9fef90a3ca170fef0536458a0df935cdccacae07bec63f1186e71f9e973ce7c7882b3f766ac83f8d9940
7
+ data.tar.gz: a3b25e6f583bd085cb3508e6c6d8b4440648cd0db7b716aabc61d6d12077716859db719a29d3bb5136eac5b0d90274be47db62555cb6666455a22c70968ae365
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Circle Internet Services, 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 all
13
+ 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 THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # RSpec CircleCI Coverage
2
+
3
+ A RSpec plugin that generates coverage data for
4
+ CircleCI's [Smarter Testing](https://circleci.com/docs/guides/test/smarter-testing/).
5
+
6
+ ## Usage
7
+
8
+ Install the plugin:
9
+
10
+ ```bash
11
+ gem install rspec-circleci-coverage
12
+ ```
13
+
14
+ Add the plugin to your `spec_helper.rb`
15
+
16
+ ```ruby
17
+ require "rspec-circleci-coverage"
18
+ ```
19
+
20
+ To generate coverage, set the `CIRCLECI_COVERAGE` environment variable:
21
+
22
+ ```bash
23
+ CIRCLECI_COVERAGE=coverage.json bundle exec rspec
24
+ ```
25
+
26
+ ## Development
27
+
28
+ Run the integration tests:
29
+
30
+ ```bash
31
+ bundle install
32
+ bundle exec rspec
33
+ ```
34
+
35
+ Generate the testsuite integration test:
36
+
37
+ ```shell
38
+ circleci run testsuite 'integration test' --local --test-analysis=all && cat coverage.json | jq --sort-keys > coveragetmp.json && mv coveragetmp.json coverage.json
39
+ ```
@@ -0,0 +1,151 @@
1
+ require 'coverage'
2
+ require 'json'
3
+ require 'pathname'
4
+
5
+ module RSpec
6
+ module CircleCI
7
+ class Coverage
8
+ class << self
9
+ attr_accessor :instance
10
+ end
11
+
12
+ def self.install
13
+ # Only install if CIRCLECI_COVERAGE environment variable is set
14
+ return unless ENV['CIRCLECI_COVERAGE']
15
+
16
+ self.instance ||= new
17
+ instance.install
18
+ end
19
+
20
+ def initialize
21
+ @coverage_data = Hash.new { |h, k| h[k] = {} }
22
+ @before_coverage = {}
23
+ @installed = false
24
+ end
25
+
26
+ def install
27
+ return if @installed
28
+ @installed = true
29
+
30
+ # Start coverage tracking if not already running
31
+ unless ::Coverage.running?
32
+ ::Coverage.start(lines: true, eval: true)
33
+ end
34
+
35
+ coverage_instance = self
36
+
37
+ # Hook into RSpec lifecycle
38
+ RSpec.configure do |config|
39
+ config.before(:suite) do
40
+ $stdout.write("rspec-circleci-coverage: generating CircleCI coverage JSON...\n")
41
+ end
42
+
43
+ config.before(:each) do |_|
44
+ # Take a snapshot before each test
45
+ coverage_instance.capture_coverage
46
+ end
47
+
48
+ config.after(:each) do |example|
49
+ # Take a snapshot after each test and record coverage
50
+ coverage_instance.record_test_coverage(example)
51
+ end
52
+
53
+ config.after(:suite) do
54
+ # Write coverage data to file
55
+ coverage_instance.write_coverage_data
56
+ end
57
+ end
58
+ end
59
+
60
+ def capture_coverage
61
+ @before_coverage = ::Coverage.peek_result.dup
62
+ end
63
+
64
+ def record_test_coverage(example)
65
+ # Take a snapshot after each test
66
+ after_coverage = ::Coverage.peek_result
67
+
68
+ # Calculate which lines were executed during this test
69
+ test_key = format_test_key(example)
70
+
71
+ after_coverage.each do |file, coverage|
72
+ # Skip files outside project scope, spec files, and rspec gem internals
73
+ next unless in_project_scope?(file)
74
+ next if file.end_with?('_spec.rb')
75
+
76
+ lines = extract_lines(coverage)
77
+ next if lines.nil?
78
+
79
+ before_lines = extract_lines(@before_coverage[file])
80
+
81
+ # Find lines that were executed during this test
82
+ executed_lines = []
83
+ lines.each_with_index do |count, index|
84
+ next if count.nil?
85
+ # Treat a missing before-count as 0 so the first render of an
86
+ # eval'd file (e.g. a compiled template) is attributed to this test.
87
+ before_count = before_lines ? (before_lines[index] || 0) : 0
88
+
89
+ # Line was executed if count increased
90
+ if count > before_count
91
+ executed_lines << (index + 1) # Line numbers are 1-indexed
92
+ end
93
+ end
94
+
95
+ # Only add if lines were executed
96
+ if executed_lines.any?
97
+ relative_file = relative_path(file)
98
+ @coverage_data[relative_file][test_key] = executed_lines
99
+ end
100
+ end
101
+ end
102
+
103
+ def write_coverage_data
104
+ if @coverage_data.empty?
105
+ $stdout.write("rspec-circleci-coverage: warning: no coverage data collected\n")
106
+ end
107
+
108
+ File.write(coverage_file, JSON.pretty_generate(@coverage_data))
109
+ $stdout.write("rspec-circleci-coverage: wrote #{coverage_file}\n")
110
+ end
111
+
112
+ def coverage_file
113
+ ENV['CIRCLECI_COVERAGE']
114
+ end
115
+
116
+ def format_test_key(example)
117
+ file_path = example.metadata[:file_path]
118
+ # Clean path to remove ./ and other redundant components
119
+ file_path = Pathname.new(file_path).cleanpath.to_s if file_path
120
+ description = example.full_description
121
+ "#{file_path}!!#{description}|run"
122
+ end
123
+
124
+ def relative_path(file)
125
+ # Convert absolute path to relative path from current directory
126
+ pathname = Pathname.new(file)
127
+ pathname.absolute? ? pathname.relative_path_from(Dir.pwd).to_s : file
128
+ end
129
+
130
+ def in_project_scope?(file)
131
+ # Check if file is within the project directory
132
+ # Files outside the project (system files, gems, etc.) should be filtered out
133
+ return false unless file.start_with?(Dir.pwd)
134
+
135
+ # Exclude gem files (even if they're in .bundle or vendor directories)
136
+ return false if file.include?('/gems/')
137
+ return false if file.include?('/.bundle/')
138
+ return false if file.include?('/vendor/')
139
+ true
140
+ end
141
+
142
+ def extract_lines(coverage_value)
143
+ case coverage_value
144
+ when Array then coverage_value
145
+ when Hash then coverage_value[:lines]
146
+ else nil
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,4 @@
1
+ require_relative 'rspec/circleci/coverage'
2
+
3
+ # Auto-install when required
4
+ RSpec::CircleCI::Coverage.install
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rspec-circleci-coverage
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.93
5
+ platform: ruby
6
+ authors:
7
+ - CircleCI
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rspec-core
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '3.13'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '3.13'
26
+ executables: []
27
+ extensions: []
28
+ extra_rdoc_files: []
29
+ files:
30
+ - LICENSE
31
+ - README.md
32
+ - lib/rspec-circleci-coverage.rb
33
+ - lib/rspec/circleci/coverage.rb
34
+ homepage: https://github.com/CircleCI-Public/smarter-testing-plugins
35
+ licenses:
36
+ - MIT
37
+ metadata:
38
+ source_code_uri: https://github.com/CircleCI-Public/smarter-testing-plugins
39
+ allowed_push_host: https://rubygems.org
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '3.2'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubygems_version: 4.0.16
55
+ specification_version: 4
56
+ summary: An RSpec plugin that generates coverage data for CircleCI's Smarter Testing
57
+ test_files: []