Merge pull request #121 from bernardladenthin/claude/maven-deps-audit… #194
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # SPDX-FileCopyrightText: 2014-2026 Bernard Ladenthin <bernard.ladenthin@gmail.com> | |
| # | |
| # SPDX-License-Identifier: Apache-2.0 | |
| name: Publish | |
| on: | |
| push: | |
| branches: [main] | |
| tags: ['v*'] | |
| pull_request: | |
| workflow_dispatch: | |
| inputs: | |
| publish_to_central: | |
| description: "Deploy to Maven Central (snapshot if -SNAPSHOT, release if a vX.Y.Z tag)" | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: read | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # Start gate — single cancellable abort window before the pipeline starts. | |
| # The wait duration lives in the `startgate` GitHub Environment (Settings → | |
| # Environments → startgate → Wait timer). | |
| # --------------------------------------------------------------------------- | |
| startgate: | |
| name: Start gate (abort window) | |
| runs-on: ubuntu-latest | |
| environment: startgate | |
| steps: | |
| - run: echo "Start gate elapsed — proceeding with pipeline." | |
| code-style: | |
| name: Code style (spotless) + package graph | |
| needs: startgate | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-java@v5 | |
| with: | |
| java-version: '21' | |
| distribution: temurin | |
| - name: Spotless check (fail fast on format violations) | |
| run: mvn -B --no-transfer-progress spotless:check | |
| - name: SpotBugs check (fail fast on static-analysis findings) | |
| run: mvn -B --no-transfer-progress -DskipTests -Denforcer.skip=true compile spotbugs:check | |
| - name: Print internal package dependency graph (jdeps, informational) | |
| continue-on-error: true | |
| run: | | |
| mvn -B --no-transfer-progress -DskipTests -Denforcer.skip=true compile | |
| echo "=== internal package dependency graph (jdeps, bytecode) ===" | |
| jdeps -verbose:package target/classes | grep 'net.ladenthin.streambuffer' || true | |
| build: | |
| name: Build | |
| needs: startgate | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-java@v5 | |
| with: | |
| java-version: '21' | |
| distribution: temurin | |
| cache: maven | |
| - name: Build | |
| run: mvn --batch-mode --no-transfer-progress -DskipTests package | |
| - uses: actions/upload-artifact@v7 | |
| with: { name: jars, path: target/*.jar } | |
| test: | |
| name: Test (JDK ${{ matrix.java-version }}) | |
| needs: [build] | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| java-version: ['21'] | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-java@v5 | |
| with: | |
| java-version: ${{ matrix.java-version }} | |
| distribution: temurin | |
| cache: maven | |
| - name: Memory before tests | |
| run: free -h | |
| - name: Test | |
| run: mvn -e --batch-mode --no-transfer-progress -P jcstress verify | |
| - uses: actions/upload-artifact@v7 | |
| if: matrix.java-version == '21' | |
| with: | |
| name: jacoco-report | |
| path: target/site/jacoco/jacoco.xml | |
| if-no-files-found: ignore | |
| - name: Memory after tests | |
| if: always() | |
| run: free -h | |
| - name: Upload crash & surefire dumps | |
| if: failure() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: crash-dumps-jdk${{ matrix.java-version }} | |
| path: | | |
| ${{ github.workspace }}/hs_err_pid*.log | |
| ${{ github.workspace }}/*.hprof | |
| ${{ github.workspace }}/target/surefire-reports/*.dump | |
| ${{ github.workspace }}/target/surefire-reports/*.dumpstream | |
| ${{ github.workspace }}/target/surefire-reports/*.txt | |
| ${{ github.workspace }}/target/surefire-reports/TEST-*.xml | |
| if-no-files-found: ignore | |
| vmlens: | |
| name: Test (vmlens interleavings) | |
| needs: [build] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-java@v5 | |
| with: { java-version: '21', distribution: temurin, cache: maven } | |
| - name: Test under vmlens | |
| run: mvn --batch-mode --no-transfer-progress -Pvmlens test | |
| - uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: vmlens-report | |
| path: target/vmlens-report/ | |
| if-no-files-found: ignore | |
| report: | |
| name: Report | |
| needs: [test] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-java@v5 | |
| with: { java-version: '21', distribution: temurin, cache: maven } | |
| - uses: actions/download-artifact@v8 | |
| with: { name: jacoco-report, path: target/site/jacoco/ } | |
| continue-on-error: true | |
| - uses: advanced-security/maven-dependency-submission-action@v5 | |
| - name: Coveralls | |
| uses: coverallsapp/github-action@v2 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| file: target/site/jacoco/jacoco.xml | |
| format: jacoco | |
| continue-on-error: true | |
| - name: Codecov | |
| uses: codecov/codecov-action@v7 | |
| with: | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| files: target/site/jacoco/jacoco.xml | |
| continue-on-error: true | |
| - name: Run PIT mutation tests | |
| run: mvn --batch-mode --no-transfer-progress test-compile org.pitest:pitest-maven:mutationCoverage | |
| - name: Extract PIT survivors | |
| if: always() | |
| run: | | |
| echo "=== PIT Survived Mutations ===" | |
| for html_file in $(find target/pit-reports -name "*.html" -type f | sort); do | |
| if grep -q "SURVIVED" "$html_file"; then | |
| echo "Found survivors in $html_file:" | |
| grep -B 2 -A 3 "SURVIVED" "$html_file" | |
| echo "" | |
| fi | |
| done | |
| - uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: { name: pit-reports, path: target/pit-reports/ } | |
| - name: Run JMH benchmarks | |
| run: > | |
| mvn --batch-mode --no-transfer-progress exec:java | |
| -Dexec.mainClass=org.openjdk.jmh.Main | |
| -Dexec.classpathScope=test | |
| -Dexec.args="StreamBufferThroughputBenchmark -wi 2 -i 3 -f 0 -rf json -rff target/jmh-results.json" | |
| continue-on-error: true | |
| - uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: { name: jmh-results, path: target/jmh-results.json } | |
| check-snapshot: | |
| name: "Check: main branch / SNAPSHOT" | |
| needs: [report] | |
| runs-on: ubuntu-latest | |
| if: >- | |
| (github.event_name == 'push' && github.ref == 'refs/heads/main') || | |
| (github.event_name == 'workflow_dispatch' && !startsWith(github.ref, 'refs/tags/v')) | |
| steps: | |
| - name: Confirm snapshot ref | |
| run: echo "Confirmed on snapshot ref ${{ github.ref }}" | |
| check-tag: | |
| name: "Check: v* tag" | |
| needs: [report] | |
| runs-on: ubuntu-latest | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| steps: | |
| - name: Confirm tag ref | |
| run: echo "Confirmed on tag ${{ github.ref }}" | |
| publish-snapshot: | |
| name: Publish Snapshot to Central | |
| needs: [check-snapshot, code-style] | |
| if: needs.check-snapshot.result == 'success' && inputs.publish_to_central | |
| runs-on: ubuntu-latest | |
| environment: maven-central | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-java@v5 | |
| with: | |
| java-version: '21' | |
| distribution: temurin | |
| cache: maven | |
| server-id: central | |
| server-username: MAVEN_USERNAME | |
| server-password: MAVEN_PASSWORD | |
| gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} | |
| gpg-passphrase: MAVEN_GPG_PASSPHRASE | |
| - name: Guard - require a -SNAPSHOT version | |
| shell: bash | |
| run: | | |
| VERSION=$(mvn -q -DforceStdout help:evaluate -Dexpression=project.version | tail -n1) | |
| echo "Resolved project version: $VERSION" | |
| case "$VERSION" in | |
| *-SNAPSHOT) echo "OK: -SNAPSHOT version, continuing snapshot deploy." ;; | |
| *) echo "::error::Refusing to publish non-SNAPSHOT version '$VERSION' from the snapshot job. Snapshot publishing requires a -SNAPSHOT version; releases go through the v* tag path."; exit 1 ;; | |
| esac | |
| - name: Deploy snapshot | |
| run: mvn --batch-mode --no-transfer-progress -P release deploy -DskipTests | |
| env: | |
| MAVEN_USERNAME: ${{ secrets.CENTRAL_USERNAME }} | |
| MAVEN_PASSWORD: ${{ secrets.CENTRAL_TOKEN }} | |
| MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| - name: Collect signed artifacts | |
| run: | | |
| mkdir -p signed-snapshot-assets | |
| cp target/*.jar signed-snapshot-assets/ 2>/dev/null || true | |
| cp target/*.jar.asc signed-snapshot-assets/ 2>/dev/null || true | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: signed-snapshot-assets | |
| path: signed-snapshot-assets/ | |
| github-snapshot: | |
| name: Update Snapshot Pre-release on GitHub | |
| needs: [publish-snapshot] | |
| if: needs.publish-snapshot.result == 'success' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: signed-snapshot-assets | |
| path: snapshot-assets/ | |
| - name: Update snapshot pre-release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| gh release view snapshot --repo ${{ github.repository }} 2>/dev/null \ | |
| || gh release create snapshot \ | |
| --repo ${{ github.repository }} \ | |
| --prerelease \ | |
| --title "Snapshot (latest)" \ | |
| --notes "Latest snapshot build from the main branch." | |
| gh release upload snapshot snapshot-assets/* \ | |
| --repo ${{ github.repository }} \ | |
| --clobber | |
| publish-release: | |
| name: Publish Release to Central | |
| needs: [check-tag, code-style] | |
| if: needs.check-tag.result == 'success' && inputs.publish_to_central | |
| runs-on: ubuntu-latest | |
| environment: maven-central | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-java@v5 | |
| with: | |
| java-version: '21' | |
| distribution: temurin | |
| cache: maven | |
| server-id: central | |
| server-username: MAVEN_USERNAME | |
| server-password: MAVEN_PASSWORD | |
| gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} | |
| gpg-passphrase: MAVEN_GPG_PASSPHRASE | |
| - name: Deploy release | |
| run: mvn --batch-mode --no-transfer-progress -P release deploy -DskipTests | |
| env: | |
| MAVEN_USERNAME: ${{ secrets.CENTRAL_USERNAME }} | |
| MAVEN_PASSWORD: ${{ secrets.CENTRAL_TOKEN }} | |
| MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| - name: Collect signed artifacts | |
| run: | | |
| mkdir -p signed-release-assets | |
| cp target/*.jar signed-release-assets/ 2>/dev/null || true | |
| cp target/*.jar.asc signed-release-assets/ 2>/dev/null || true | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: signed-release-assets | |
| path: signed-release-assets/ | |
| github-release: | |
| name: Attach Binaries to GitHub Release | |
| needs: [publish-release] | |
| if: needs.publish-release.result == 'success' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: signed-release-assets | |
| path: release-assets/ | |
| - name: Upload release assets | |
| uses: softprops/action-gh-release@v3 | |
| with: | |
| files: release-assets/* |