Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/workflows/jacoco_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ name: JaCoCo report
on:
pull_request:
branches: [ master ]
types: [ opened, edited, synchronize, reopened ]

jobs:
test:
Expand Down Expand Up @@ -51,11 +52,12 @@ jobs:
- name: Build and run tests
run: sbt ++${{matrix.scala}} jacoco

- name: Add coverage to PR
- name: Add JaCoCo Report in PR comments
id: jacoco
uses: madrapps/jacoco-report@50d3aff4548aa991e6753342d9ba291084e63848
uses: MoranaApps/jacoco-report@54bfe284d1119dc917dddba80517c54c5bcf3627
with:
paths: ${{ github.workspace }}/target/scala-${{ matrix.scalaShort }}/jacoco/report/jacoco.xml
paths: |
**/jacoco.xml
token: ${{ secrets.GITHUB_TOKEN }}
min-coverage-overall: ${{ matrix.overall }}
min-coverage-changed-files: ${{ matrix.changed }}
Expand Down
21 changes: 11 additions & 10 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,15 @@ scalafmtFilter.withRank(KeyRanks.Invisible) := fmtFilterExpression
// linting
Global / excludeLintKeys += ThisBuild / name // will be used in publish, todo #3 - confirm if lint ignore is still needed

// JaCoCo code coverage
Test / jacocoReportSettings := JacocoReportSettings(
title = s"spark-data-standardization Jacoco Report - scala:${scalaVersion.value}",
formats = Seq(JacocoReportFormats.HTML, JacocoReportFormats.XML)
)
// JaCoCo Method Filter Plugin
enablePlugins(JacocoFilterPlugin)

// exclude example
Test / jacocoExcludes := Seq(
// "za.co.absa.standardization.udf.UDFBuilder*", // class and related objects
// "za.co.absa.standardization.udf.UDFNames" // class only
)
jacocoReportName := s"spark-data-standardization Jacoco Report - scala:${scalaVersion.value}"
jacocoReportFormats := Set("html", "xml")

// jacocoExcludes := Seq("za/co/absa/standardization/udf/UDFBuilder*", "za/co/absa/standardization/udf/UDFNames")
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @miroslavpojer we also thinking about excluding some tests using the filter method please have a look for a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my proposal. It filter out UDFName vals. You can place it into Project rules part of jmf-rules.txt file.

# UDFNames object — final val string constant accessors
# UDFNames* matches both UDFNames$ (module) and UDFNames (static forwarders)
za.co.absa.standardization.udf.UDFNames*#stdCastErr()           id:udfnames-stdCastErr
za.co.absa.standardization.udf.UDFNames*#stdNullErr()           id:udfnames-stdNullErr
za.co.absa.standardization.udf.UDFNames*#stdSchemaErr()         id:udfnames-stdSchemaErr
za.co.absa.standardization.udf.UDFNames*#arrayDistinctErrors()  id:udfnames-arrayDistinctErrors
za.co.absa.standardization.udf.UDFNames*#cleanErrCol()          id:udfnames-cleanErrCol
za.co.absa.standardization.udf.UDFNames*#errorColumnAppend()    id:udfnames-errorColumnAppend
za.co.absa.standardization.udf.UDFNames*#binaryUnbase64()       id:udfnames-binaryUnbase64


// Command aliases for JaCoCo coverage workflow
addCommandAlias("jacoco", "; jacocoOn; clean; test; jacocoReportAll; jacocoOff")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These can be solved using .sbtrc file.
Just mentioning if avoided on purpose.

addCommandAlias("jacocoOn", "; set every jacocoPluginEnabled := true")
addCommandAlias("jacocoOff", "; set every jacocoPluginEnabled := false")
155 changes: 155 additions & 0 deletions jmf-rules.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# jacoco-method-filter — Default Rules & HowTo (Scala)
# [jmf:1.0.0]
#
# This file defines which methods should be annotated as *Generated so JaCoCo ignores them.
# One rule per line.
#
# ─────────────────────────────────────────────────────────────────────────────
# HOW TO USE (quick)
# 1) Replace YOUR.PACKAGE.ROOT with your project’s package root (e.g., com.example.app).
# 2) Start with the CONSERVATIVE section only.
# 3) If clean, enable STANDARD. Use AGGRESSIVE only inside DTO/auto‑generated packages.
# 4) Keep rules narrow (by package), prefer flags (synthetic/bridge) for compiler artifacts,
# and add `id:` labels so logs are easy to read.
#
# ─────────────────────────────────────────────────────────────────────────────
# ALLOWED SYNTAX (cheat sheet)
#
# General form:
# <FQCN_glob>#<method_glob>(<descriptor_glob>) [FLAGS and PREDICATES...]
#
# FQCN_glob (dot form; $ allowed for inner classes):
# Examples: *.model.*, com.example.*, *
#
# method_glob (glob on method name):
# Examples: copy | $anonfun$* | get* | *_$eq
#
# descriptor_glob (JVM descriptor in (args)ret). You may omit it entirely.
# • Omitting descriptor ⇒ treated as "(*)*" (any args, any return).
# • Short/empty forms "", "()", "(*)" normalize to "(*)*".
# Examples:
# (I)I # takes int, returns int
# (Ljava/lang/String;)V # takes String, returns void
# () or (*) or omitted # any args, any return
#
# FLAGS (optional) — space or comma separated:
# public | protected | private | synthetic | bridge | static | abstract
#
# PREDICATES (optional):
# ret:<glob> # match return type only (e.g., ret:V, ret:I, ret:Lcom/example/*;)
# id:<string> # identifier shown in logs/reports
# name-contains:<s> # method name must contain <s>
# name-starts:<s> # method name must start with <s>
# name-ends:<s> # method name must end with <s>
#
# Notes
# - Always use dot-form (com.example.Foo) for class names.
# - Comments (# …) and blank lines are ignored.
#
# ─────────────────────────────────────────────────────────────────────────────
# QUICK EXAMPLES
#
# Simple wildcards
# *#*(*)
# → Match EVERY method in EVERY class (any package). Useful only for diagnostics.
# "(*)" normalizes to "(*)*" ⇒ any args, any return.
# *.dto.*#*(*)
# → Match every method on any class under any package segment named "dto".
# Good when you treat DTOs as generated/boilerplate.

# Scala case class helpers
# *.model.*#copy(*)
# → Matches Scala case-class `copy` methods under `*.model.*`.
# Hides boilerplate clones with any parameter list and any return.
# *.model.*#productArity()
# → Matches zero-arg `productArity` (case-class/Product API).
# *.model.*#productElement(*)
# → Matches `productElement(int)` (or any descriptor form) on case classes.
# *.model.*#productPrefix()
# → Matches `productPrefix()`; returns the case class' constructor name.

# Companion objects and defaults
# *.model.*$*#apply(*)
# → Matches companion `apply` factories under `*.model.*` (any args).
# BE CAREFUL: can hide real factory logic; keep the package scope narrow.
# *.model.*$*#unapply(*)
# → Matches extractor `unapply` methods in companions under `*.model.*`.
# *#*$default$*(*)
# → Matches Scala-generated default-argument helpers everywhere.
# Safe to keep enabled; they’re compiler-synthesized.

# Anonymous / synthetic / bridge
# *#$anonfun$*
# → Matches any method whose name contains `$anonfun$` (Scala lambdas).
# Consider adding `synthetic` and/or a package scope in real configs.
# *#*(*):synthetic # any synthetic
# → Matches ANY method marked `synthetic` (compiler-generated).
# Powerful; scope by package to avoid hiding intentional glue code.
# *#*(*):bridge # any bridge
# → Matches Java generic bridge methods the compiler inserts.
# Usually safe globally, but scoping is still recommended.

# Setters / fluent APIs
# *.dto.*#*_$eq(*)
# → Matches Scala var setters in DTO packages (e.g., `name_=(...)`).
# Good for excluding trivial field writes.
# *.builder.*#with*(*)
# → Matches builder-style fluent setters (`withXxx(...)`) in builder pkgs.
# Treats chainable configuration as boilerplate.
# *.client.*#with*(*) ret:Lcom/api/client/*
# → Like above but ONLY when the return type matches your client package.
# The `ret:` predicate protects real logic that returns other types.

# Return-type constraints
# *.jobs.*#*(*):ret:V
# → Any method under `*.jobs.*` returning `void` (`V`). Often orchestration.
# *.math.*#*(*):ret:I
# → Any method under `*.math.*` returning primitive int (`I`).
# *.model.*#*(*):ret:Lcom/example/model/*
# → Any method under `*.model.*` that returns a type in `com.example.model`.
# Handy when the *return type* uniquely identifies boilerplate.

# ─────────────────────────────────────────────────────────────────────────────
# GLOBALS RULES
# ─────────────────────────────────────────────────────────────────────────────
# ** all case class boilerplate

# Scala case class helpers
*#canEqual(*) id:case-canequal
*#equals(*) id:case-equals
*#apply(*) id:case-apply
*#unapply(*) id:case-unapply
*#hashCode(*) id:case-hashcode
*#copy(*) id:case-copy
*#copy$default$*(*) id:case-copy-defaults
*#productElement() id:case-prod-element
*#productArity() id:case-prod-arity
*#productPrefix() id:case-prod-prefix
*#productIterator() id:case-prod-iterator
*#tupled() id:case-tupled
*#curried() id:case-curried
*#toString() id:case-tostring
*#name() id:case-name
*#groups() id:case-groups
*#optionalAttributes() id:case-optionalAttributes

# Companion objects, constructors, and static definitions
*$#<init>(*) id:gen-ctor # constructors
*$#<clinit>() id:gen-clinit # static initializer blocks

# Companion objects and defaults
*$*#apply(*) id:comp-apply
*$*#unapply(*) id:comp-unapply
*$*#toString(*) id:comp-tostring
*$*#readResolve(*) id:comp-readresolve

# anonymous class created by a macro expansion
*$macro$*#$anonfun$inst$macro$* id:macro-inst
*$macro$*#inst$macro$* id:macro-inst

# lambda
*#* synthetic name-contains:$anonfun$ id:scala-anonfun

# ─────────────────────────────────────────────────────────────────────────────
# PROJECT RULES
# ─────────────────────────────────────────────────────────────────────────────
10 changes: 2 additions & 8 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,15 @@ addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.7.0")

addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.5")

// sbt-jacoco - workaround related dependencies required to download
// JaCoCo Method Filter sbt Plugin (replaces legacy sbt-jacoco)
addSbtPlugin("io.github.moranaapps" % "jacoco-method-filter-sbt" % "2.0.1")
lazy val ow2Version = "9.5"
lazy val jacocoVersion = "0.8.10-absa.1"

def jacocoUrl(artifactName: String): String = s"https://github.com/AbsaOSS/jacoco/releases/download/$jacocoVersion/org.jacoco.$artifactName-$jacocoVersion.jar"
def ow2Url(artifactName: String): String = s"https://repo1.maven.org/maven2/org/ow2/asm/$artifactName/$ow2Version/$artifactName-$ow2Version.jar"

addSbtPlugin("com.jsuereth" %% "scala-arm" % "2.0" from "https://repo1.maven.org/maven2/com/jsuereth/scala-arm_2.11/2.0/scala-arm_2.11-2.0.jar")
addSbtPlugin("com.jsuereth" %% "scala-arm" % "2.0" from "https://repo1.maven.org/maven2/com/jsuereth/scala-arm_2.12/2.0/scala-arm_2.12-2.0.jar")

addSbtPlugin("za.co.absa.jacoco" % "report" % jacocoVersion from jacocoUrl("report"))
addSbtPlugin("za.co.absa.jacoco" % "core" % jacocoVersion from jacocoUrl("core"))
addSbtPlugin("za.co.absa.jacoco" % "agent" % jacocoVersion from jacocoUrl("agent"))
addSbtPlugin("org.ow2.asm" % "asm" % ow2Version from ow2Url("asm"))
addSbtPlugin("org.ow2.asm" % "asm-commons" % ow2Version from ow2Url("asm-commons"))
addSbtPlugin("org.ow2.asm" % "asm-tree" % ow2Version from ow2Url("asm-tree"))
Comment on lines 25 to 33
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe all these lines can be removed. They were part of previous jacoco sbt plugin solution.


addSbtPlugin("za.co.absa.sbt" % "sbt-jacoco" % "3.4.1-absa.3" from "https://github.com/AbsaOSS/sbt-jacoco/releases/download/3.4.1-absa.3/sbt-jacoco-3.4.1-absa.3.jar")
Loading