Skip to content

Add three build guardrails: Error Prone Class.forName ban, @since validation, Vale version-name block#5044

Merged
shai-almog merged 3 commits into
masterfrom
add-build-guardrails
May 26, 2026
Merged

Add three build guardrails: Error Prone Class.forName ban, @since validation, Vale version-name block#5044
shai-almog merged 3 commits into
masterfrom
add-build-guardrails

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

Summary

Adds three independent checks that catch documentation and build hygiene issues that have slipped into the framework repeatedly. Each check fires on existing code, which is intentional — the violations they catch are real bugs.

  • Error Prone BanClassForName — new maven/errorprone-checks module + custom BugChecker that refuses any Class.forName(...) call under CodenameOne/src. ParparVM (iOS) cannot resolve classes by string name at runtime, so these calls silently break on iOS. Wired into core via an opt-in errorprone Maven profile (Error Prone needs JDK 11+; the primary build runs on JDK 8). Other Error Prone rules are disabled with -XepDisableAllChecks so only this one rule fires. Currently catches 3 real usages in NativeLookup, GeofenceManager, and DeviceRunner.
  • scripts/check-since-tags.sh — scans @since X.Y.Z references in framework sources and fails the build when the referenced version has no matching git tag (with or without a leading v). Currently flags 30 @since 7.0.245 / @since 3.7.2 references that point at versions that never shipped.
  • Vale CodenameOneRules.NonexistentVersions — blocks prose like "Codename One 8", "Codename One 9", "Codename One 7.1" in the developer guide while still allowing the live release line (Codename One 7 / 7.0.x) and historical releases (Codename One 3.4). Needs vocab: false to escape Vale's vocab-pre-filtering, which would otherwise silently swallow every match because Codename is in accept.txt. Catches a real preexisting hit at The-Components-Of-Codename-One.asciidoc:2568.

Notes on integration

  • The Error Prone profile is opt-in (mvn -Perrorprone install) and runs on its own CI job (.github/workflows/errorprone.yml, JDK 17). The default JDK 8 build is untouched.
  • The @since check has its own workflow (.github/workflows/check-since-tags.yml). It uses actions/checkout with fetch-tags: true so git tag --list sees the full release history.
  • The Vale rule slots into the existing developer-guide-docs.yml workflow (no changes needed there).
  • Style directory needed a .gitignore whitelist (!styles/CodenameOneRules/) because Vale syncs upstream style packages under styles/* which is otherwise excluded.

Test plan

  • mvn -Perrorprone -pl core -am install -DskipTests fails with [BanClassForName] errors on the three known usages
  • scripts/check-since-tags.sh exits non-zero and prints the 30 unresolved @since versions
  • vale --filter='.Name == "CodenameOneRules.NonexistentVersions"' docs/developer-guide/*.asciidoc docs/developer-guide/*.adoc flags The-Components-Of-Codename-One.asciidoc:2568 and nothing else
  • Default mvn install on JDK 8 still works (the errorprone-checks module is gated behind the errorprone profile)
  • The three flagged Vale/@since/Error Prone hits are addressed in follow-up PRs (this PR is the guardrail, not the cleanup)

🤖 Generated with Claude Code

Introduce checks that catch documentation/build hygiene issues that have
slipped in repeatedly:

- Error Prone BanClassForName: forbids Class.forName(...) anywhere under
  CodenameOne/src because ParparVM (iOS) cannot resolve classes by string
  name at runtime. Lives in a new maven/errorprone-checks module wired
  into core via an opt-in `errorprone` profile (Error Prone needs JDK 11+;
  the primary build runs on JDK 8). CI workflow runs `mvn -Perrorprone`
  on JDK 17.

- scripts/check-since-tags.sh: fails the build when any @SInCE javadoc
  tag references a version with no matching git tag. Wired up via a
  dedicated GitHub Actions workflow that fetches tags and runs the check.

- Vale rule CodenameOneRules.NonexistentVersions: blocks prose like
  "Codename One 8", "Codename One 9", "Codename One 7.1" in the
  developer guide, while still allowing the live release line
  (Codename One 7 / 7.0.x) and historical releases. The rule needs
  `vocab: false` because the Codename entry in accept.txt would
  otherwise swallow every match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog shai-almog closed this May 26, 2026
@shai-almog shai-almog reopened this May 26, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 26, 2026

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 26, 2026

Compared 20 screenshots: 20 matched.
✅ JavaScript-port screenshot tests passed.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 26, 2026

Developer Guide build artifacts are available for download from this workflow run:

Developer Guide quality checks:

  • AsciiDoc linter: No issues found (report)
  • Vale: No alerts found (report)
  • Paragraph capitalization: No paragraph capitalization issues (report)
  • LanguageTool: No grammar matches (report)
  • Image references: No unused images detected (report)

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 26, 2026

Compared 110 screenshots: 110 matched.

Native Android coverage

  • 📊 Line coverage: 11.82% (6794/57481 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 9.62% (34125/354909), branch 4.14% (1398/33740), complexity 5.18% (1677/32374), method 8.99% (1362/15146), class 14.44% (303/2099)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 11.82% (6794/57481 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 9.62% (34125/354909), branch 4.14% (1398/33740), complexity 5.18% (1677/32374), method 8.99% (1362/15146), class 14.44% (303/2099)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 940.000 ms
Base64 CN1 encode 92.000 ms
Base64 encode ratio (CN1/native) 0.098x (90.2% faster)
Base64 native decode 992.000 ms
Base64 CN1 decode 435.000 ms
Base64 decode ratio (CN1/native) 0.439x (56.1% faster)
Image encode benchmark status skipped (SIMD unsupported)

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 26, 2026

Compared 110 screenshots: 110 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 271 seconds

Build and Run Timing

Metric Duration
Simulator Boot 100000 ms
Simulator Boot (Run) 1000 ms
App Install 16000 ms
App Launch 5000 ms
Test Execution 259000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 437.000 ms
Base64 CN1 encode 1164.000 ms
Base64 encode ratio (CN1/native) 2.664x (166.4% slower)
Base64 native decode 266.000 ms
Base64 CN1 decode 850.000 ms
Base64 decode ratio (CN1/native) 3.195x (219.5% slower)
Base64 SIMD encode 384.000 ms
Base64 encode ratio (SIMD/native) 0.879x (12.1% faster)
Base64 encode ratio (SIMD/CN1) 0.330x (67.0% faster)
Base64 SIMD decode 361.000 ms
Base64 decode ratio (SIMD/native) 1.357x (35.7% slower)
Base64 decode ratio (SIMD/CN1) 0.425x (57.5% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 53.000 ms
Image createMask (SIMD on) 8.000 ms
Image createMask ratio (SIMD on/off) 0.151x (84.9% faster)
Image applyMask (SIMD off) 123.000 ms
Image applyMask (SIMD on) 55.000 ms
Image applyMask ratio (SIMD on/off) 0.447x (55.3% faster)
Image modifyAlpha (SIMD off) 103.000 ms
Image modifyAlpha (SIMD on) 56.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.544x (45.6% faster)
Image modifyAlpha removeColor (SIMD off) 134.000 ms
Image modifyAlpha removeColor (SIMD on) 73.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.545x (45.5% faster)
Image PNG encode (SIMD off) 1088.000 ms
Image PNG encode (SIMD on) 833.000 ms
Image PNG encode ratio (SIMD on/off) 0.766x (23.4% faster)
Image JPEG encode 623.000 ms

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 26, 2026

Compared 110 screenshots: 110 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 261 seconds

Build and Run Timing

Metric Duration
Simulator Boot 93000 ms
Simulator Boot (Run) 1000 ms
App Install 14000 ms
App Launch 8000 ms
Test Execution 326000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 838.000 ms
Base64 CN1 encode 1294.000 ms
Base64 encode ratio (CN1/native) 1.544x (54.4% slower)
Base64 native decode 440.000 ms
Base64 CN1 decode 1050.000 ms
Base64 decode ratio (CN1/native) 2.386x (138.6% slower)
Base64 SIMD encode 508.000 ms
Base64 encode ratio (SIMD/native) 0.606x (39.4% faster)
Base64 encode ratio (SIMD/CN1) 0.393x (60.7% faster)
Base64 SIMD decode 393.000 ms
Base64 decode ratio (SIMD/native) 0.893x (10.7% faster)
Base64 decode ratio (SIMD/CN1) 0.374x (62.6% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 59.000 ms
Image createMask (SIMD on) 10.000 ms
Image createMask ratio (SIMD on/off) 0.169x (83.1% faster)
Image applyMask (SIMD off) 135.000 ms
Image applyMask (SIMD on) 88.000 ms
Image applyMask ratio (SIMD on/off) 0.652x (34.8% faster)
Image modifyAlpha (SIMD off) 143.000 ms
Image modifyAlpha (SIMD on) 72.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.503x (49.7% faster)
Image modifyAlpha removeColor (SIMD off) 193.000 ms
Image modifyAlpha removeColor (SIMD on) 95.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.492x (50.8% faster)
Image PNG encode (SIMD off) 1082.000 ms
Image PNG encode (SIMD on) 789.000 ms
Image PNG encode ratio (SIMD on/off) 0.729x (27.1% faster)
Image JPEG encode 496.000 ms

shai-almog and others added 2 commits May 26, 2026 19:15
- check-since-tags: also accept the *next patch* of every X.Y.Z release
  line, since @SInCE markers are necessarily written before the release
  is tagged. With the highest 7.0.x tag at v7.0.244, the existing
  @SInCE 7.0.245 entries are now valid. Next-minor/next-major bumps
  still require an explicit prior tag because those are the values
  Claude hallucinates most often.
- check-since-tags: only scan javadoc-style @SInCE (lines containing
  `*` or `///` before the tag), so plain `//` comments — which in
  vendored MiG Layout code reference the upstream library's changelog,
  not a Codename One release — no longer trigger the check.
- errorprone CI: explicitly add errorprone-checks to -pl. The custom
  checker is wired in via annotationProcessorPaths, which Maven's -am
  does not recognise as a build-time dependency.
- Suppress BanClassForName at the three deliberate framework-internal
  reflective lookups (NativeLookup.create, GeofenceManager.getListenerClass,
  DeviceRunner.runTest) with @SuppressWarnings and a justifying comment.
- Drop the "From Codename One 9.0," prefix from the ImageViewer prose
  in the developer guide — a real preexisting false advertisement of
  an unreleased version that the new Vale rule correctly flagged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Maven's reactor schedules modules by declared dependencies. `core`
references `errorprone-checks` only via the maven-compiler-plugin's
`annotationProcessorPaths`, which Maven does not treat as a build-time
dependency, so the reactor scheduled core first and failed to resolve
com.codenameone:errorprone-checks:8.0-SNAPSHOT.

Fix by splitting the CI command into two invocations: first install
errorprone-checks to the local repo, then compile core with the
errorprone profile active.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog shai-almog merged commit 6490db8 into master May 26, 2026
22 of 24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant