From 2cf7615e8f064766ff0d9a2935da3ef455efa928 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 10:55:38 +0000 Subject: [PATCH 1/5] Add GitHub Actions CI with JaCoCo coverage badges Mirrors the CI setup from simple-websocket-service: - CI workflow runs ./mvnw clean test on JDK 25 (Temurin) for pushes and PRs to main, generates JaCoCo coverage/branch badges and commits them on pushes to main - Dependabot keeps GitHub Actions versions up to date weekly - JaCoCo 0.8.15 (Java 25 class files need 0.8.14+) wired into the test phase - CI and coverage badges in README Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_012MLyPXGHeCc1fvTeB8JnT2 --- .github/dependabot.yml | 6 ++++++ .github/workflows/ci.yml | 40 ++++++++++++++++++++++++++++++++++++++++ README.md | 4 ++++ pom.xml | 20 ++++++++++++++++++++ 4 files changed, 70 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/ci.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..5ace460 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..00b950d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,40 @@ +name: CI + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +permissions: + contents: write + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + + - name: Set up JDK 25 + uses: actions/setup-java@v5 + with: + java-version: '25' + distribution: 'temurin' + cache: 'maven' + + - name: Run tests with coverage + run: ./mvnw -B clean test + + - name: Generate JaCoCo badge + uses: cicirello/jacoco-badge-generator@72266185b7ee48a6fd74eaf0238395cc8b14fef8 # v2.12.1 + with: + generate-branches-badge: true + jacoco-csv-file: target/site/jacoco/jacoco.csv + badges-directory: .github/badges + + - name: Commit updated badges + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + uses: stefanzweifel/git-auto-commit-action@4a55954c782fc1ea30b9056cd3e7a2b40ca8887d # v7.2.0 + with: + commit_message: "chore: update JaCoCo coverage badges" + file_pattern: '.github/badges/*.svg' diff --git a/README.md b/README.md index 8a62a2d..a892b73 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ # java-spring-rest +![CI](https://github.com/andreasarf/java-spring-rest/actions/workflows/ci.yml/badge.svg) +![Coverage](.github/badges/jacoco.svg) +![Branches](.github/badges/branches.svg) + Example for implementation Rest API using Spring Boot. ## Requirement diff --git a/pom.xml b/pom.xml index d5ad0d5..fc4f76d 100755 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,7 @@ 25 2.2.55 + 0.8.15 @@ -98,6 +99,25 @@ + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + + prepare-agent + + + + report + test + + report + + + + From 0d84904c189f833573d135063c070bdc17a1b84c Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 11:04:26 +0000 Subject: [PATCH 2/5] Exclude Lombok-generated code from coverage; scope CI badge to main - lombok.config marks generated methods with @lombok.Generated so JaCoCo ignores @Data equals/hashCode/toString (same as simple-websocket-service) - CI badge shows the status of main instead of the latest run on any branch Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_012MLyPXGHeCc1fvTeB8JnT2 --- README.md | 2 +- lombok.config | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 lombok.config diff --git a/README.md b/README.md index a892b73..af60ac0 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # java-spring-rest -![CI](https://github.com/andreasarf/java-spring-rest/actions/workflows/ci.yml/badge.svg) +![CI](https://github.com/andreasarf/java-spring-rest/actions/workflows/ci.yml/badge.svg?branch=main) ![Coverage](.github/badges/jacoco.svg) ![Branches](.github/badges/branches.svg) diff --git a/lombok.config b/lombok.config new file mode 100644 index 0000000..df71bb6 --- /dev/null +++ b/lombok.config @@ -0,0 +1,2 @@ +config.stopBubbling = true +lombok.addLombokGeneratedAnnotation = true From ea1909c3842902f32f785060cfd640043f27fa10 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 11:44:16 +0000 Subject: [PATCH 3/5] Harden CI workflow - Default the workflow token to contents: read; only a separate badges job, which runs on pushes to main, gets contents: write - Badges job checks out the tip of main and is serialized with a concurrency group so the auto-commit fast-forwards - Skip badge generation on pull requests - Pin actions/checkout and actions/setup-java to commit SHAs like the other actions (setup-java bumped to v6.1.0) - Let Dependabot also update Maven dependencies Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_012MLyPXGHeCc1fvTeB8JnT2 --- .github/dependabot.yml | 4 ++++ .github/workflows/ci.yml | 37 +++++++++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5ace460..c9b2105 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,3 +4,7 @@ updates: directory: "/" schedule: interval: "weekly" + - package-ecosystem: "maven" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 00b950d..dafaa49 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,16 +7,16 @@ on: branches: [ main ] permissions: - contents: write + contents: read jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up JDK 25 - uses: actions/setup-java@v5 + uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0 with: java-version: '25' distribution: 'temurin' @@ -25,6 +25,36 @@ jobs: - name: Run tests with coverage run: ./mvnw -B clean test + - name: Upload coverage report + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: jacoco-report + path: target/site/jacoco/jacoco.csv + if-no-files-found: error + + # Only this job gets a write token, and only for pushes to main + badges: + needs: test + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + permissions: + contents: write + concurrency: + group: coverage-badges + cancel-in-progress: false + steps: + # Check out the branch tip (not the triggering SHA) so the badge commit fast-forwards + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: main + + - name: Download coverage report + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + name: jacoco-report + path: target/site/jacoco + - name: Generate JaCoCo badge uses: cicirello/jacoco-badge-generator@72266185b7ee48a6fd74eaf0238395cc8b14fef8 # v2.12.1 with: @@ -33,7 +63,6 @@ jobs: badges-directory: .github/badges - name: Commit updated badges - if: github.event_name == 'push' && github.ref == 'refs/heads/main' uses: stefanzweifel/git-auto-commit-action@4a55954c782fc1ea30b9056cd3e7a2b40ca8887d # v7.2.0 with: commit_message: "chore: update JaCoCo coverage badges" From 65dc65b535a68447bb63bf36b81a4bc715ecabba Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 11:45:29 +0000 Subject: [PATCH 4/5] CI: ordered concurrency, timeouts, manual trigger, grouped Maven updates - Workflow-level concurrency cancels superseded PR runs and runs main pushes one at a time, so an older run can't overwrite newer badges - timeout-minutes on both jobs - workflow_dispatch to regenerate badges without a commit - Don't persist the checkout token in the test job - Group Dependabot Maven minor/patch updates into one PR Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_012MLyPXGHeCc1fvTeB8JnT2 --- .github/dependabot.yml | 3 +++ .github/workflows/ci.yml | 19 +++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c9b2105..370ea48 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,3 +8,6 @@ updates: directory: "/" schedule: interval: "weekly" + groups: + maven-minor-and-patch: + update-types: [ "minor", "patch" ] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dafaa49..aed9e24 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,15 +5,24 @@ on: branches: [ main ] pull_request: branches: [ main ] + workflow_dispatch: permissions: contents: read +# Supersede outdated PR runs; queue runs on main in order so badges never regress +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: test: runs-on: ubuntu-latest + timeout-minutes: 20 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Set up JDK 25 uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0 @@ -26,23 +35,21 @@ jobs: run: ./mvnw -B clean test - name: Upload coverage report - if: github.event_name == 'push' && github.ref == 'refs/heads/main' + if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: jacoco-report path: target/site/jacoco/jacoco.csv if-no-files-found: error - # Only this job gets a write token, and only for pushes to main + # Only this job gets a write token, and only on main badges: needs: test - if: github.event_name == 'push' && github.ref == 'refs/heads/main' + if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' runs-on: ubuntu-latest + timeout-minutes: 10 permissions: contents: write - concurrency: - group: coverage-badges - cancel-in-progress: false steps: # Check out the branch tip (not the triggering SHA) so the badge commit fast-forwards - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 From 00d50cdb640ccdcf3c612537d415895c55813fe9 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 11:51:37 +0000 Subject: [PATCH 5/5] CI: don't let re-runs of older commits regress the badges - Badges job skips the commit unless the run's commit is still the latest non-badge commit on main - Single ref condition for the main-only steps - Keep the coverage artifact for 1 day; it is only handed to the next job Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_012MLyPXGHeCc1fvTeB8JnT2 --- .github/workflows/ci.yml | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aed9e24..cac1f27 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,17 +35,18 @@ jobs: run: ./mvnw -B clean test - name: Upload coverage report - if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' + if: github.ref == 'refs/heads/main' uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: jacoco-report path: target/site/jacoco/jacoco.csv if-no-files-found: error + retention-days: 1 # Only this job gets a write token, and only on main badges: needs: test - if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest timeout-minutes: 10 permissions: @@ -55,14 +56,29 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: main + fetch-depth: 50 + + # A re-run of an older commit must not replace the badges of newer code + - name: Check commit is still the latest on main + id: latest + run: | + if ! git merge-base --is-ancestor "$GITHUB_SHA" HEAD; then + echo "is_latest=false" >> "$GITHUB_OUTPUT" + elif git log --format=%s "$GITHUB_SHA"..HEAD | grep -qvx 'chore: update JaCoCo coverage badges'; then + echo "is_latest=false" >> "$GITHUB_OUTPUT" + else + echo "is_latest=true" >> "$GITHUB_OUTPUT" + fi - name: Download coverage report + if: steps.latest.outputs.is_latest == 'true' uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: jacoco-report path: target/site/jacoco - name: Generate JaCoCo badge + if: steps.latest.outputs.is_latest == 'true' uses: cicirello/jacoco-badge-generator@72266185b7ee48a6fd74eaf0238395cc8b14fef8 # v2.12.1 with: generate-branches-badge: true @@ -70,6 +86,7 @@ jobs: badges-directory: .github/badges - name: Commit updated badges + if: steps.latest.outputs.is_latest == 'true' uses: stefanzweifel/git-auto-commit-action@4a55954c782fc1ea30b9056cd3e7a2b40ca8887d # v7.2.0 with: commit_message: "chore: update JaCoCo coverage badges"