danger-jacoco-instacart 0.1.15 → 0.1.17
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/.rubocop.yml +1 -1
- data/README.md +6 -0
- data/lib/jacoco/gem_version.rb +1 -1
- data/lib/jacoco/plugin.rb +52 -5
- data/spec/fixtures/output_g.xml +33 -0
- data/spec/jacoco_spec.rb +104 -0
- data/spec/spec_helper.rb +0 -2
- metadata +8 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3b3e380696d9d2e8ce64b52d20baa6c09aa53259133e6b256769929e68b1d32b
|
|
4
|
+
data.tar.gz: b33b2c86616b7f93aeda7a669a3b27882a08b6a38205895636da62ae73e3a022
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2ae620e33819d2e1ce7a13b3e2633071e5564ac3fe01a201b429f32364b47069fae9cb28e736f7f8a23bf94c03552d82171473df4561c070e79ff86cdcb3dd8e
|
|
7
|
+
data.tar.gz: 4e18673c11b8147510fcf5e1456b11145b8632d32de75005fcd3702e71515284ea219389ae41e4e61932d7f472454ee119d9167b4000df88ce18c664407f01ec
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
|
@@ -35,5 +35,11 @@ to your `Dangerfile`
|
|
|
35
35
|
1. Clone this repo
|
|
36
36
|
2. Run `bundle install` to setup dependencies.
|
|
37
37
|
3. Run `bundle exec rake spec` to run the tests.
|
|
38
|
+
4. Run `bundle exec rubocop -A` to fix in-place what's fixable
|
|
38
39
|
4. Use `bundle exec guard` to automatically have tests run as you make changes.
|
|
39
40
|
5. Make your changes.
|
|
41
|
+
|
|
42
|
+
### How to release new version
|
|
43
|
+
1. Bump version in `lib/jacoco/gem_version.rb - X.Y.Z`
|
|
44
|
+
2. `rake build`
|
|
45
|
+
3. `gem push pkg/danger-jacoco-instacart-X.Y.Z.gem`
|
data/lib/jacoco/gem_version.rb
CHANGED
data/lib/jacoco/plugin.rb
CHANGED
|
@@ -105,14 +105,61 @@ module Danger
|
|
|
105
105
|
|
|
106
106
|
def classes(delimiter)
|
|
107
107
|
class_to_file_path_hash = {}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
# Initialize files_extension if it's nil
|
|
109
|
+
@files_extension = ['.kt', '.java'] if @files_extension.nil?
|
|
110
|
+
|
|
111
|
+
filtered_files_to_check.each do |file| # "src/java/com/example/CachedRepository.java"
|
|
112
|
+
# Get the package path
|
|
113
|
+
package_path = file.split('.').first.split(delimiter)[1] # "com/example/CachedRepository"
|
|
114
|
+
next unless package_path
|
|
115
|
+
|
|
116
|
+
# Add the primary class (filename-based class)
|
|
117
|
+
class_to_file_path_hash[package_path] = file
|
|
118
|
+
|
|
119
|
+
# For Kotlin files, we need to look for multiple classes/interfaces in the same file
|
|
120
|
+
add_kotlin_declarations(file, package_path, class_to_file_path_hash) if file.end_with?('.kt')
|
|
121
|
+
end
|
|
113
122
|
class_to_file_path_hash
|
|
114
123
|
end
|
|
115
124
|
|
|
125
|
+
# Returns files that match the configured file extensions
|
|
126
|
+
def filtered_files_to_check
|
|
127
|
+
files_to_check.select { |file| @files_extension.reduce(false) { |state, el| state || file.end_with?(el) } }
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Scans a Kotlin file for additional class/interface declarations and adds them to the hash
|
|
131
|
+
def add_kotlin_declarations(file, package_path, class_to_file_path_hash)
|
|
132
|
+
return unless File.exist?(file)
|
|
133
|
+
|
|
134
|
+
file_content = File.read(file)
|
|
135
|
+
|
|
136
|
+
# Kotlin compiles top-level functions (e.g. @Composable funs) into a `<FileNameKt>` class.
|
|
137
|
+
# Always register it — the SAX parser skips it silently if it's absent from the XML.
|
|
138
|
+
parts = package_path.split('/')
|
|
139
|
+
kt_class_path = (parts[0..-2] + ["#{parts[-1]}Kt"]).join('/')
|
|
140
|
+
class_to_file_path_hash[kt_class_path] = file
|
|
141
|
+
|
|
142
|
+
# Look for class and interface declarations in the file
|
|
143
|
+
# Regex catches class/interface/object declarations with modifiers and generics
|
|
144
|
+
regex = /\b(?:(?:data|sealed|abstract|open|internal|private|protected|public|inline)\s+)*
|
|
145
|
+
(?:class|interface|object)\s+([A-Za-z0-9_]+)(?:<.*?>)?/x
|
|
146
|
+
declarations = file_content.scan(regex).flatten
|
|
147
|
+
|
|
148
|
+
# For each additional class/interface found (excluding the one matching the filename)
|
|
149
|
+
declarations.each do |class_name|
|
|
150
|
+
# Skip if it matches the primary class name (already added)
|
|
151
|
+
next if package_path.end_with?("/#{class_name}")
|
|
152
|
+
|
|
153
|
+
# Create full class path by replacing the last part with the class name
|
|
154
|
+
parts = package_path.split('/')
|
|
155
|
+
parts[-1] = class_name
|
|
156
|
+
additional_class_path = parts.join('/')
|
|
157
|
+
|
|
158
|
+
# Add to hash
|
|
159
|
+
class_to_file_path_hash[additional_class_path] = file
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
116
163
|
# It returns a specific class code coverage and an emoji status as well
|
|
117
164
|
def report_class(jacoco_class, file_path)
|
|
118
165
|
report_result = {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><!DOCTYPE report PUBLIC "-//JACOCO//DTD Report 1.0//EN"
|
|
2
|
+
"report.dtd">
|
|
3
|
+
<report name="test_report">
|
|
4
|
+
<sessioninfo id="test-id" start="1480057517395" dump="1480057526412"/>
|
|
5
|
+
<package name="com/example">
|
|
6
|
+
<class name="com/example/TopLevelFunctionsKt">
|
|
7
|
+
<counter type="INSTRUCTION" missed="5" covered="15"/>
|
|
8
|
+
<counter type="LINE" missed="1" covered="4"/>
|
|
9
|
+
<counter type="COMPLEXITY" missed="1" covered="3"/>
|
|
10
|
+
<counter type="METHOD" missed="1" covered="3"/>
|
|
11
|
+
<counter type="CLASS" missed="0" covered="1"/>
|
|
12
|
+
</class>
|
|
13
|
+
<sourcefile name="TopLevelFunctions.kt">
|
|
14
|
+
<counter type="INSTRUCTION" missed="5" covered="15"/>
|
|
15
|
+
<counter type="LINE" missed="1" covered="4"/>
|
|
16
|
+
<counter type="COMPLEXITY" missed="1" covered="3"/>
|
|
17
|
+
<counter type="METHOD" missed="1" covered="3"/>
|
|
18
|
+
<counter type="CLASS" missed="0" covered="1"/>
|
|
19
|
+
</sourcefile>
|
|
20
|
+
<counter type="INSTRUCTION" missed="5" covered="15"/>
|
|
21
|
+
<counter type="BRANCH" missed="0" covered="0"/>
|
|
22
|
+
<counter type="LINE" missed="1" covered="4"/>
|
|
23
|
+
<counter type="COMPLEXITY" missed="1" covered="3"/>
|
|
24
|
+
<counter type="METHOD" missed="1" covered="3"/>
|
|
25
|
+
<counter type="CLASS" missed="0" covered="1"/>
|
|
26
|
+
</package>
|
|
27
|
+
<counter type="INSTRUCTION" missed="5" covered="15"/>
|
|
28
|
+
<counter type="BRANCH" missed="0" covered="0"/>
|
|
29
|
+
<counter type="LINE" missed="1" covered="4"/>
|
|
30
|
+
<counter type="COMPLEXITY" missed="1" covered="3"/>
|
|
31
|
+
<counter type="METHOD" missed="1" covered="3"/>
|
|
32
|
+
<counter type="CLASS" missed="0" covered="1"/>
|
|
33
|
+
</report>
|
data/spec/jacoco_spec.rb
CHANGED
|
@@ -384,6 +384,110 @@ module Danger
|
|
|
384
384
|
expect(@dangerfile.status_report[:markdowns][0].message).to include('| `com/example/CachedRepository` | 50% | 55% | :warning: |')
|
|
385
385
|
end
|
|
386
386
|
end
|
|
387
|
+
|
|
388
|
+
it 'detects top-level Kotlin functions file via the generated Kt-suffixed class' do
|
|
389
|
+
path_g = "#{File.dirname(__FILE__)}/fixtures/output_g.xml"
|
|
390
|
+
|
|
391
|
+
kotlin_file_path = 'src/kotlin/com/example/TopLevelFunctions.kt'
|
|
392
|
+
kotlin_file_content = <<~KOTLIN
|
|
393
|
+
package com.example
|
|
394
|
+
|
|
395
|
+
@Composable
|
|
396
|
+
fun FirstComposable() {}
|
|
397
|
+
|
|
398
|
+
@Composable
|
|
399
|
+
fun SecondComposable() {}
|
|
400
|
+
KOTLIN
|
|
401
|
+
|
|
402
|
+
allow(File).to receive(:exist?).and_call_original
|
|
403
|
+
allow(File).to receive(:exist?).with(kotlin_file_path).and_return(true)
|
|
404
|
+
allow(File).to receive(:read).and_call_original
|
|
405
|
+
allow(File).to receive(:read).with(kotlin_file_path).and_return(kotlin_file_content)
|
|
406
|
+
|
|
407
|
+
@my_plugin.files_to_check = [kotlin_file_path]
|
|
408
|
+
@my_plugin.minimum_project_coverage_percentage = 0
|
|
409
|
+
@my_plugin.minimum_class_coverage_percentage = 80
|
|
410
|
+
@my_plugin.minimum_composable_class_coverage_percentage = 80
|
|
411
|
+
|
|
412
|
+
class_file_hash = @my_plugin.classes(%r{/kotlin/})
|
|
413
|
+
expect(class_file_hash.keys).to include('com/example/TopLevelFunctionsKt')
|
|
414
|
+
|
|
415
|
+
@my_plugin.report path_g
|
|
416
|
+
|
|
417
|
+
expect(@dangerfile.status_report[:markdowns][0].message).to include('| `com/example/TopLevelFunctionsKt` | 75% | 80% | :warning: |')
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
it 'test with kotlin multiples classes in same file' do
|
|
421
|
+
path_a = "#{File.dirname(__FILE__)}/fixtures/output_a.xml"
|
|
422
|
+
|
|
423
|
+
# Mock the Kotlin file with multiple classes
|
|
424
|
+
kotlin_file_path = 'src/kotlin/com/example/MultiClass.kt'
|
|
425
|
+
kotlin_file_content = <<~KOTLIN
|
|
426
|
+
package com.example
|
|
427
|
+
|
|
428
|
+
class MultiClass {
|
|
429
|
+
// some code
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
data class DataClass(val property: String) {
|
|
433
|
+
// some code
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
sealed class SealedClass {
|
|
437
|
+
// some code
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
private class PrivateClass {
|
|
441
|
+
// some code
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
abstract class AbstractClass {
|
|
445
|
+
// some code
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
class GenericClass<T> {
|
|
449
|
+
// some code
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
interface SomeInterface {
|
|
453
|
+
// some code
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
object SingletonObject {
|
|
457
|
+
// some code
|
|
458
|
+
}
|
|
459
|
+
KOTLIN
|
|
460
|
+
|
|
461
|
+
allow(File).to receive(:exist?).and_call_original
|
|
462
|
+
allow(File).to receive(:exist?).with(kotlin_file_path).and_return(true)
|
|
463
|
+
allow(File).to receive(:read).and_call_original
|
|
464
|
+
allow(File).to receive(:read).with(kotlin_file_path).and_return(kotlin_file_content)
|
|
465
|
+
|
|
466
|
+
@my_plugin.files_to_check = [kotlin_file_path]
|
|
467
|
+
@my_plugin.minimum_project_coverage_percentage = 0 # Avoid project coverage errors
|
|
468
|
+
|
|
469
|
+
# Use a block to capture the key-value pairs passed to classes
|
|
470
|
+
expect { |b| @my_plugin.classes(%r{/kotlin/}).each(&b) }.to yield_control.at_least(8).times
|
|
471
|
+
|
|
472
|
+
# Call report
|
|
473
|
+
@my_plugin.report path_a
|
|
474
|
+
|
|
475
|
+
# Check the class-to-file hash from SAXParser
|
|
476
|
+
class_file_hash = @my_plugin.classes(%r{/kotlin/})
|
|
477
|
+
expect(class_file_hash.keys).to include('com/example/MultiClass')
|
|
478
|
+
expect(class_file_hash.keys).to include('com/example/DataClass')
|
|
479
|
+
expect(class_file_hash.keys).to include('com/example/SealedClass')
|
|
480
|
+
expect(class_file_hash.keys).to include('com/example/PrivateClass')
|
|
481
|
+
expect(class_file_hash.keys).to include('com/example/AbstractClass')
|
|
482
|
+
expect(class_file_hash.keys).to include('com/example/GenericClass')
|
|
483
|
+
expect(class_file_hash.keys).to include('com/example/SomeInterface')
|
|
484
|
+
expect(class_file_hash.keys).to include('com/example/SingletonObject')
|
|
485
|
+
|
|
486
|
+
# All keys should map to the same file path
|
|
487
|
+
class_file_hash.each_value do |file_path|
|
|
488
|
+
expect(file_path).to eq(kotlin_file_path)
|
|
489
|
+
end
|
|
490
|
+
end
|
|
387
491
|
end
|
|
388
492
|
end
|
|
389
493
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -29,7 +29,6 @@ require 'danger_plugin'
|
|
|
29
29
|
# it comes with an extra function `.string` which will
|
|
30
30
|
# strip all ANSI colours from the string.
|
|
31
31
|
|
|
32
|
-
# rubocop:disable Lint/NestedMethodDefinition
|
|
33
32
|
def testing_ui
|
|
34
33
|
@output = StringIO.new
|
|
35
34
|
def @output.winsize
|
|
@@ -42,7 +41,6 @@ def testing_ui
|
|
|
42
41
|
end
|
|
43
42
|
cork
|
|
44
43
|
end
|
|
45
|
-
# rubocop:enable Lint/NestedMethodDefinition
|
|
46
44
|
|
|
47
45
|
# Example environment (ENV) that would come from
|
|
48
46
|
# running a PR on TravisCI
|
metadata
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: danger-jacoco-instacart
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.17
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Anton Malinskiy
|
|
8
8
|
- Alexander Bezverhni
|
|
9
|
-
autorequire:
|
|
9
|
+
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date:
|
|
12
|
+
date: 2026-05-18 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: danger-plugin-api
|
|
@@ -211,13 +211,14 @@ files:
|
|
|
211
211
|
- spec/fixtures/output_d.xml
|
|
212
212
|
- spec/fixtures/output_e.xml
|
|
213
213
|
- spec/fixtures/output_f.xml
|
|
214
|
+
- spec/fixtures/output_g.xml
|
|
214
215
|
- spec/jacoco_spec.rb
|
|
215
216
|
- spec/spec_helper.rb
|
|
216
217
|
homepage: https://github.com/alexanderbezverhni/danger-jacoco
|
|
217
218
|
licenses:
|
|
218
219
|
- MIT
|
|
219
220
|
metadata: {}
|
|
220
|
-
post_install_message:
|
|
221
|
+
post_install_message:
|
|
221
222
|
rdoc_options: []
|
|
222
223
|
require_paths:
|
|
223
224
|
- lib
|
|
@@ -232,8 +233,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
232
233
|
- !ruby/object:Gem::Version
|
|
233
234
|
version: '0'
|
|
234
235
|
requirements: []
|
|
235
|
-
rubygems_version: 3.
|
|
236
|
-
signing_key:
|
|
236
|
+
rubygems_version: 3.5.3
|
|
237
|
+
signing_key:
|
|
237
238
|
specification_version: 4
|
|
238
239
|
summary: A longer description of danger-jacoco.
|
|
239
240
|
test_files:
|
|
@@ -243,5 +244,6 @@ test_files:
|
|
|
243
244
|
- spec/fixtures/output_d.xml
|
|
244
245
|
- spec/fixtures/output_e.xml
|
|
245
246
|
- spec/fixtures/output_f.xml
|
|
247
|
+
- spec/fixtures/output_g.xml
|
|
246
248
|
- spec/jacoco_spec.rb
|
|
247
249
|
- spec/spec_helper.rb
|