Skip to content
Closed
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
26 changes: 25 additions & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ StatusBoard is a real-time monitoring platform for tracking service health statu
- **Database**: AWS DynamoDB for persistence
- **Testing**: ZIO Test framework
- **Code Coverage**: Jacoco
- Compiler warnings treated as errors where configured; coverage ≥ 80% via JMF-enabled JaCoCo (excluding methods listed in `jmf-rules.txt`).

### Frontend (TypeScript)
- **Framework**: Angular 19
Expand Down Expand Up @@ -166,6 +167,29 @@ The checker system uses a polymorphic design:
- E2E tests: `npm run e2e` (Cypress via `cypress.json`)
- Test coverage: `npm run test:coverage`

## Coverage Filtering (JMF)

### When a unit test adds value — write one
- The method has any logic of its own.

### When to add to `jmf-rules.txt` instead of writing a unit test
- The body is a single call with no own logic: it forwards to another overload, calls its non-deprecated replacement, returns a field, or wraps a constructor with no transformation.
- **Litmus test**: "Does this method have any logic of its own?" — No → add a JMF rule instead of a test.

### Global rule collision check (CRITICAL)
- When adding any new method, check whether its name matches a pattern in the `# GLOBAL RULES` section of `jmf-rules.txt`.
- If a method name matches a global rule AND the method contains domain logic: immediately add an INCLUDE rescue rule (`+FQCN#method(*)`) in the `# INCLUDE RULES` section of `jmf-rules.txt`.
- High-risk method names (most common collisions): `apply()`, `toString()`, `equals()`, `copy()`, `name()`, `groups()`, `optionalAttributes()`. See the `# GLOBAL RULES` section of `jmf-rules.txt` for the full list.
- Rationale: broad global rules are designed for compiler-generated boilerplate and can silently suppress coverage for domain methods. INCLUDE rules rescue specific methods from broad exclusions.
- Example: if adding `def apply(id: String): Record`, add `+*Record$#apply(*) id:keep-record-factory` to the `# INCLUDE RULES` section to rescue it from the `*$*#apply(*)` global rule.

### JMF drift check (review rule)
- When modifying a method that already appears in `jmf-rules.txt`, verify its body still qualifies for exclusion.
- If own logic has been added since the rule was created, remove the JMF rule and write a unit test instead.

### Cannot add JMF rules for
- Methods with branching logic, error handling, or non-trivial transformations — write a unit test instead.

## Configuration
- Main config: `config. conf` (HOCON format)
- Environment-specific configurations for different deployments
Expand Down Expand Up @@ -279,4 +303,4 @@ npm run sync-version # Sync VERSION file to package.json
## Additional Resources
- [Wiki - REST API](https://github.com/AbsaOSS/StatusBoard/wiki/REST-API)
- [Wiki - Architecture](https://github.com/AbsaOSS/StatusBoard/wiki/Architecture)
- [Wiki - Supported Checkers](https://github.com/AbsaOSS/StatusBoard/wiki/Supported-checkers)
- [Wiki - Supported Checkers](https://github.com/AbsaOSS/StatusBoard/wiki/Supported-checkers)
65 changes: 48 additions & 17 deletions .github/workflows/ci-check-jacoco.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,48 @@
name: JaCoCo Report
name: CI Check JaCoCo code-coverage

on:
pull_request:
branches: [ master ]
types: [ opened, edited, synchronize, reopened ]

env:
scalaLong: 2.13.11
scalaShort: "2.13"
coverage-overall: 80.0
coverage-changed-files: 80.0
coverage-per-changed-file: 0.0
check-overall-coverages: true
REPORT_GROUPS: |
- name: statusboard
paths:
- '**/target/**/jacoco-report/jacoco.xml'
thresholds: '77*80*60'

jobs:
jacoco-report:
name: JaCoCo Report
detect:
name: Detect Changed Files
runs-on: ubuntu-latest
timeout-minutes: 2
outputs:
scala_changed: ${{ steps.filter.outputs.scala }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10
with:
persist-credentials: false
fetch-depth: 0
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d
id: filter
with:
token: ""
filters: |
scala:
- '**/*.scala'
- '!project/**'

build-test-and-measure:
name: Build, Test and Measure
needs: detect
if: needs.detect.outputs.scala_changed == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
pull-requests: write
services:
dynamodb-local:
image: "amazon/dynamodb-local:latest"
Expand Down Expand Up @@ -51,16 +77,21 @@ jobs:
with:
python-version: '3.14'

- name: Publish JaCoCo Report in PR comments
- name: Check coverage thresholds and add reports in PR comments
id: jacoco
uses: MoranaApps/jacoco-report@69351d88d18f7697c416e1bc2020ed05606d8120
with:
token: '${{ secrets.GITHUB_TOKEN }}'
paths: |
**/target/**/jacoco/report/jacoco.xml
sensitivity: "detail"
comment-mode: 'single'
min-coverage-overall: ${{ env.coverage-overall }}
min-coverage-changed-files: ${{ env.coverage-changed-files }}
min-coverage-per-changed-file: ${{ env.coverage-per-changed-file }}
skip-unchanged: false
global-thresholds: '77*80'
report-thresholds-default: '0*0*0'
skip-unchanged: 'true'
evaluate-unchanged: 'false'
report-groups: ${{ env.REPORT_GROUPS }}

noop:
name: No Operation
needs: detect
if: needs.detect.outputs.scala_changed != 'true'
runs-on: ubuntu-latest
steps:
- run: echo "No changes in src/**/*.scala — passing."
4 changes: 3 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ lazy val root = (project in file("."))
Test / parallelExecution := false,
(assembly / test) := {},
publish := {},
jmfReportFile := Some(target.value / "jmf-report.json"),
jmfReportFormat := "json",
)
.enablePlugins(AutomateHeaderPlugin)
.enablePlugins(AssemblyPlugin)
.enablePlugins(FilteredJacocoAgentPlugin)
.enablePlugins(JacocoFilterPlugin)
Loading
Loading