Skip to content

Commit 82b7ddb

Browse files
Remove jacoco forks (#136)
- Jacoco Agent used for jacoco measuring instead of sbt-jacoco plugin. - Introduced jacoco method filtration library.
1 parent d1e890a commit 82b7ddb

File tree

7 files changed

+545
-50
lines changed

7 files changed

+545
-50
lines changed

.github/workflows/jacoco_check.yml

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,29 +34,23 @@ jobs:
3434
steps:
3535
- name: Checkout code
3636
uses: actions/checkout@v2
37+
with:
38+
persist-credentials: false
39+
fetch-depth: 0
3740
- name: Setup Scala
3841
uses: olafurpg/setup-scala@v10
3942
with:
4043
java-version: "[email protected]"
4144
- name: Build and run tests
4245
run: sbt ++${{matrix.scala}} jacoco
43-
- name: Add coverage to PR
44-
id: jacoco
45-
uses: madrapps/[email protected]
46-
with:
47-
paths: ${{ github.workspace }}/api/target/scala-${{ matrix.scala_short }}/jacoco/report/jacoco.xml
48-
token: ${{ secrets.GITHUB_TOKEN }}
49-
min-coverage-overall: ${{ matrix.overall }}
50-
min-coverage-changed-files: ${{ matrix.changed }}
51-
title: JaCoCo code coverage report - scala:${{ matrix.scala }}
52-
update-comment: true
53-
- name: Get the Coverage info
54-
run: |
55-
echo "Total coverage ${{ steps.jacoco.outputs.coverage-overall }}"
56-
echo "Changed Files coverage ${{ steps.jacoco.outputs.coverage-changed-files }}"
57-
- name: Fail PR if changed files coverage is less than ${{ matrix.changed }}%
58-
if: ${{ steps.jacoco.outputs.coverage-changed-files < 80.0 }}
59-
uses: actions/github-script@v6
46+
- name: Add JaCoCo Report in PR comments
47+
uses: MoranaApps/jacoco-report@v2
6048
with:
61-
script: |
62-
core.setFailed('Changed files coverage is less than ${{ matrix.changed }}%!')
49+
token: '${{ secrets.GITHUB_TOKEN }}'
50+
paths: |
51+
**/target/jacoco/report/jacoco.xml
52+
min-coverage-overall: 43.0
53+
min-coverage-changed-files: 70.0
54+
sensitivity: "detail"
55+
comment-mode: 'multi'
56+
skip-unchanged: 'true'

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ sbt jacoco
389389
```
390390
Code coverage will be generated on path:
391391
```
392-
{project-root}/{module}/target/scala-{scala_version}/jacoco/report/html
392+
{project-root}/{module}/target/jacoco/report/index.html
393393
```
394394
## Health check endpoint
395395
Springboot Actuator is enabled for this project. This provides the user with an endpoint (readable via HTTP or JMX)
@@ -459,4 +459,4 @@ This requires Git to be installed and available on the host.
459459
The example `git.properties` file provided may be edited manually if the git generation is functioning incorrectly.
460460
461461
## Client Library
462-
See Readme in [clientLibrary](clientLibrary/README.md) module.
462+
See Readme in [clientLibrary](clientLibrary/README.md) module.

build.sbt

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
*/
1515

1616
import Dependencies._
17-
import com.github.sbt.jacoco.report.JacocoReportSettings
1817

1918
ThisBuild / organization := "za.co.absa"
2019

@@ -24,23 +23,24 @@ lazy val scala213 = "2.13.12"
2423
ThisBuild / scalaVersion := scala212
2524
ThisBuild / versionScheme := Some("early-semver")
2625

27-
lazy val commonJacocoReportSettings: JacocoReportSettings = JacocoReportSettings(
28-
formats = Seq(JacocoReportFormats.HTML, JacocoReportFormats.XML)
29-
)
30-
3126
lazy val commonJacocoExcludes: Seq[String] = Seq(
3227
"za.co.absa.loginsvc.rest.Application*"
33-
// "za.co.absa.loginsvc.rest.config.BaseConfig" // class only
28+
// "za.co.absa.loginsvc.rest.config.BaseConfig" // class only
3429
)
3530

3631
lazy val commonJavacOptions = Seq("-source", "1.8", "-target", "1.8", "-Xlint") // deliberately making backwards compatible with J8
3732

3833
lazy val parent = (project in file("."))
3934
.aggregate(api, clientLibrary, examples)
35+
.enablePlugins(FilteredJacocoAgentPlugin)
4036
.settings(
4137
name := "login-service",
4238
javacOptions ++= commonJavacOptions,
43-
publish / skip := true
39+
publish / skip := true,
40+
// Global defaults (override per-module below if you wish)
41+
FilteredJacocoAgentPlugin.autoImport.jacocoIncludes := Seq("za.co.absa.*"),
42+
FilteredJacocoAgentPlugin.autoImport.jacocoExcludes ++= commonJacocoExcludes,
43+
FilteredJacocoAgentPlugin.autoImport.jacocoFailOnMissingExec := false
4444
)
4545

4646
lazy val api = project // no need to define file, because path is same as val name
@@ -50,11 +50,10 @@ lazy val api = project // no need to define file, because path is same as val na
5050
webappWebInfClasses := true,
5151
inheritJarManifest := true,
5252
javacOptions ++= commonJavacOptions,
53-
jacocoReportSettings := commonJacocoReportSettings.withTitle(s"login-service:service Jacoco Report - scala:${scalaVersion.value}"),
54-
jacocoExcludes := commonJacocoExcludes,
5553
publish / skip := true
5654
).enablePlugins(TomcatPlugin)
5755
.enablePlugins(AutomateHeaderPlugin)
56+
.enablePlugins(FilteredJacocoAgentPlugin)
5857

5958
lazy val clientLibrary = project // no need to define file, because path is same as val name
6059
.settings(
@@ -63,6 +62,7 @@ lazy val clientLibrary = project // no need to define file, because path is same
6362
javacOptions ++= commonJavacOptions,
6463
crossScalaVersions := Seq(scala212, scala213)
6564
).enablePlugins(AutomateHeaderPlugin)
65+
.enablePlugins(FilteredJacocoAgentPlugin)
6666

6767
lazy val examples = project // no need to define file, because path is same as val name
6868
.settings(
@@ -71,4 +71,9 @@ lazy val examples = project // no need to define file, because path is same as v
7171
javacOptions ++= commonJavacOptions,
7272
publish / skip := true
7373
).enablePlugins(AutomateHeaderPlugin)
74-
.dependsOn(clientLibrary)
74+
.dependsOn(clientLibrary)
75+
76+
// Run activate jacoco + clean + test + per-module reports across the whole build + deactivate jacoco
77+
addCommandAlias("jacoco", "; jacocoOn; clean; test; jacocoReportAll; jacocoOff")
78+
addCommandAlias("jacocoOff", "; set every jacocoPluginEnabled := false")
79+
addCommandAlias("jacocoOn", "; set every jacocoPluginEnabled := true")

jmf-rules.txt

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# jacoco-method-filter — Default Rules & HowTo (Scala + Java)
2+
#
3+
# This file defines which methods should be annotated as *Generated so JaCoCo ignores them.
4+
# One rule per line.
5+
#
6+
# ─────────────────────────────────────────────────────────────────────────────
7+
# HOW TO USE (quick)
8+
# 1) Replace YOUR.PACKAGE.ROOT with your project’s package root (e.g., com.example.app).
9+
# 2) Start with the CONSERVATIVE section only.
10+
# 3) If clean, enable STANDARD. Use AGGRESSIVE only inside DTO/auto‑generated packages.
11+
# 4) Keep rules narrow (by package), prefer flags (synthetic/bridge) for compiler artifacts,
12+
# and add `id:` labels so logs are easy to read.
13+
#
14+
# ─────────────────────────────────────────────────────────────────────────────
15+
# ALLOWED SYNTAX (cheat sheet)
16+
#
17+
# General form:
18+
# <FQCN_glob>#<method_glob>(<descriptor_glob>) [FLAGS and PREDICATES...]
19+
#
20+
# FQCN_glob (dot form; $ allowed for inner classes):
21+
# Examples: *.model.*, com.example.*, *
22+
#
23+
# method_glob (glob on method name):
24+
# Examples: copy | $anonfun$* | get* | *_$eq
25+
#
26+
# descriptor_glob (JVM descriptor in (args)ret). You may omit it entirely.
27+
# • Omitting descriptor ⇒ treated as "(*)*" (any args, any return).
28+
# • Short/empty forms "", "()", "(*)" normalize to "(*)*".
29+
# Examples:
30+
# (I)I # takes int, returns int
31+
# (Ljava/lang/String;)V # takes String, returns void
32+
# () or (*) or omitted # any args, any return
33+
#
34+
# FLAGS (optional) — space or comma separated:
35+
# public | protected | private | synthetic | bridge | static | abstract
36+
#
37+
# PREDICATES (optional):
38+
# ret:<glob> # match return type only (e.g., ret:V, ret:I, ret:Lcom/example/*;)
39+
# id:<string> # identifier shown in logs/reports
40+
# name-contains:<s> # method name must contain <s>
41+
# name-starts:<s> # method name must start with <s>
42+
# name-ends:<s> # method name must end with <s>
43+
#
44+
# Notes
45+
# - Always use dot-form (com.example.Foo) for class names.
46+
# - Comments (# …) and blank lines are ignored.
47+
#
48+
# ─────────────────────────────────────────────────────────────────────────────
49+
# QUICK EXAMPLES
50+
#
51+
# Simple wildcards
52+
# *#*(*)
53+
# → Match EVERY method in EVERY class (any package). Useful only for diagnostics.
54+
# "(*)" normalizes to "(*)*" ⇒ any args, any return.
55+
# *.dto.*#*(*)
56+
# → Match every method on any class under any package segment named "dto".
57+
# Good when you treat DTOs as generated/boilerplate.
58+
59+
# Scala case class helpers
60+
# *.model.*#copy(*)
61+
# → Matches Scala case-class `copy` methods under `*.model.*`.
62+
# Hides boilerplate clones with any parameter list and any return.
63+
# *.model.*#productArity()
64+
# → Matches zero-arg `productArity` (case-class/Product API).
65+
# *.model.*#productElement(*)
66+
# → Matches `productElement(int)` (or any descriptor form) on case classes.
67+
# *.model.*#productPrefix()
68+
# → Matches `productPrefix()`; returns the case class' constructor name.
69+
70+
# Companion objects and defaults
71+
# *.model.*$*#apply(*)
72+
# → Matches companion `apply` factories under `*.model.*` (any args).
73+
# BE CAREFUL: can hide real factory logic; keep the package scope narrow.
74+
# *.model.*$*#unapply(*)
75+
# → Matches extractor `unapply` methods in companions under `*.model.*`.
76+
# *#*$default$*(*)
77+
# → Matches Scala-generated default-argument helpers everywhere.
78+
# Safe to keep enabled; they’re compiler-synthesized.
79+
80+
# Anonymous / synthetic / bridge
81+
# *#$anonfun$*
82+
# → Matches any method whose name contains `$anonfun$` (Scala lambdas).
83+
# Consider adding `synthetic` and/or a package scope in real configs.
84+
# *#*(*):synthetic # any synthetic
85+
# → Matches ANY method marked `synthetic` (compiler-generated).
86+
# Powerful; scope by package to avoid hiding intentional glue code.
87+
# *#*(*):bridge # any bridge
88+
# → Matches Java generic bridge methods the compiler inserts.
89+
# Usually safe globally, but scoping is still recommended.
90+
91+
# Setters / fluent APIs
92+
# *.dto.*#*_$eq(*)
93+
# → Matches Scala var setters in DTO packages (e.g., `name_=(...)`).
94+
# Good for excluding trivial field writes.
95+
# *.builder.*#with*(*)
96+
# → Matches builder-style fluent setters (`withXxx(...)`) in builder pkgs.
97+
# Treats chainable configuration as boilerplate.
98+
# *.client.*#with*(*) ret:Lcom/api/client/*
99+
# → Like above but ONLY when the return type matches your client package.
100+
# The `ret:` predicate protects real logic that returns other types.
101+
102+
# Return-type constraints
103+
# *.jobs.*#*(*):ret:V
104+
# → Any method under `*.jobs.*` returning `void` (`V`). Often orchestration.
105+
# *.math.*#*(*):ret:I
106+
# → Any method under `*.math.*` returning primitive int (`I`).
107+
# *.model.*#*(*):ret:Lcom/example/model/*
108+
# → Any method under `*.model.*` that returns a type in `com.example.model`.
109+
# Handy when the *return type* uniquely identifies boilerplate.
110+
111+
# ─────────────────────────────────────────────────────────────────────────────
112+
# GLOBALS RULES
113+
# ─────────────────────────────────────────────────────────────────────────────
114+
# ** all case class boilerplate
115+
116+
# Scala case class helpers
117+
*#canEqual(*) id:case-canequal
118+
*#equals(*) id:case-equals
119+
*#apply(*) id:case-apply
120+
*#unapply(*) id:case-unapply
121+
*#hashCode(*) id:case-hashcode
122+
*#copy(*) id:case-copy
123+
*#copy$default$*(*) id:case-copy-defaults
124+
*#productElement() id:case-prod-element
125+
*#productArity() id:case-prod-arity
126+
*#productPrefix() id:case-prod-prefix
127+
*#productIterator() id:case-prod-iterator
128+
*#tupled() id:case-tupled
129+
*#curried() id:case-curried
130+
*#toString() id:case-tostring
131+
*#name() id:case-name
132+
*#groups() id:case-groups
133+
*#optionalAttributes() id:case-optionalAttributes
134+
135+
# Companion objects, constructors, and static definitions
136+
*$#<init>(*) id:gen-ctor # constructors
137+
*$#<clinit>() id:gen-clinit # static initializer blocks
138+
139+
# Companion objects and defaults
140+
*$*#apply(*) id:comp-apply
141+
*$*#unapply(*) id:comp-unapply
142+
*$*#toString(*) id:comp-tostring
143+
*$*#readResolve(*) id:comp-readresolve
144+
145+
# anonymous class created by a macro expansion
146+
*$macro$*#$anonfun$inst$macro$* id:macro-inst
147+
*$macro$*#inst$macro$* id:macro-inst
148+
149+
# lambda
150+
*#* synthetic name-contains:$anonfun$ id:scala-anonfun
151+
152+
# ─────────────────────────────────────────────────────────────────────────────
153+
# DIRECT RULES
154+
# ─────────────────────────────────────────────────────────────────────────────

0 commit comments

Comments
 (0)