diff --git a/.github/quality-gates.json b/.github/quality-gates.json new file mode 100644 index 00000000..ad7c3cc5 --- /dev/null +++ b/.github/quality-gates.json @@ -0,0 +1,32 @@ +{ + "qualityGates": [ + { + "metric": "tests-success-rate", + "name": "Tests Success Rate", + "threshold": 100.0, + "criticality": "FAILURE" + }, + { + "metric": "line", + "threshold": 80.0, + "criticality": "UNSTABLE" + }, + { + "metric": "branch", + "threshold": 80.0, + "criticality": "UNSTABLE" + }, + { + "metric": "bugs", + "name": "Potential Bugs", + "threshold": 0.0, + "criticality": "FAILURE" + }, + { + "metric": "style", + "name": "Style Violations", + "threshold": 0.0, + "criticality": "FAILURE" + } + ] +} diff --git a/.github/quality-monitor.json b/.github/quality-monitor.json new file mode 100644 index 00000000..7e675b46 --- /dev/null +++ b/.github/quality-monitor.json @@ -0,0 +1,145 @@ +{ + "tests": { + "name": "Tests", + "tools": [ + { + "id": "junit", + "name": "Unit Tests", + "pattern": "**/target/surefire-reports/TEST*data*.xml" + }, + { + "id": "junit", + "icon": "rocket", + "name": "Integration Tests", + "pattern": "**/target/failsafe-reports/TEST*.xml" + }, + { + "id": "junit", + "icon": "no_entry", + "name": "Architecture Tests", + "pattern": "**/target/surefire-reports/TEST*archunit*.xml" + } + ] + }, + "analysis": [ + { + "name": "Style", + "id": "style", + "tools": [ + { + "id": "checkstyle", + "pattern": "**/target/**checkstyle-result.xml" + }, + { + "id": "pmd", + "pattern": "**/target/pmd-*/pmd.xml" + }, + { + "id": "java", + "icon": "coffee", + "pattern": "**/maven.log" + } + ] + }, + { + "name": "Bugs", + "id": "bugs", + "icon": "bug", + "tools": [ + { + "id": "spotbugs", + "sourcePath": "src/main/java", + "pattern": "**/target/spotbugsXml.xml" + }, + { + "id": "error-prone", + "pattern": "**/maven.log" + } + ] + }, + { + "name": "API Problems", + "id": "api", + "icon": "no_entry_sign", + "tools": [ + { + "id": "revapi", + "sourcePath": "src/main/java", + "pattern": "**/target/revapi-result.json" + } + ] + }, + { + "name": "Vulnerabilities", + "id": "vulnerabilities", + "icon": "shield", + "tools": [ + { + "icon": "shield", + "id": "owasp-dependency-check", + "icon": "shield", + "pattern": "**/target/dependency-check-report.json" + } + ] + } + ], + "coverage": [ + { + "name": "Code Coverage", + "tools": [ + { + "id": "jacoco", + "metric": "line", + "sourcePath": "src/main/java", + "pattern": "**/target/site/jacoco/jacoco.xml" + }, + { + "id": "jacoco", + "metric": "branch", + "sourcePath": "src/main/java", + "pattern": "**/target/site/jacoco/jacoco.xml" + } + ] + } + ], + "metrics": { + "name": "Software Metrics", + "tools": [ + { + "id": "metrics", + "pattern": "**/metrics/pmd.xml", + "metric": "CYCLOMATIC_COMPLEXITY" + }, + { + "id": "metrics", + "pattern": "**/metrics/pmd.xml", + "metric": "COGNITIVE_COMPLEXITY" + }, + { + "id": "metrics", + "pattern": "**/metrics/pmd.xml", + "metric": "NPATH_COMPLEXITY" + }, + { + "id": "metrics", + "pattern": "**/metrics/pmd.xml", + "metric": "LOC" + }, + { + "id": "metrics", + "pattern": "**/metrics/pmd.xml", + "metric": "NCSS" + }, + { + "id": "metrics", + "pattern": "**/metrics/pmd.xml", + "metric": "COHESION" + }, + { + "id": "metrics", + "pattern": "**/metrics/pmd.xml", + "metric": "WEIGHT_OF_CLASS" + } + ] + } +} diff --git a/.github/workflows/quality-monitor-build.yml b/.github/workflows/quality-monitor-build.yml new file mode 100644 index 00000000..c4d695a6 --- /dev/null +++ b/.github/workflows/quality-monitor-build.yml @@ -0,0 +1,59 @@ +name: 'Quality Monitor Build' + +on: + pull_request: + +jobs: + build: + runs-on: [ubuntu-latest] + name: Create quality reports + + steps: + - name: Checkout PR + uses: actions/checkout@v5 + - name: Set up JDK 21 + uses: actions/setup-java@v5 + with: + distribution: 'temurin' + java-version: 21 + check-latest: true + cache: 'maven' + - name: Set up Maven + uses: stCarolas/setup-maven@v5 + with: + maven-version: 3.9.11 + - name: Cache the NVD database + uses: actions/cache@v4 + with: + path: ~/.m2/repository/org/owasp/dependency-check-data + key: dependency-check + - name: Check if quality monitor reports mutation coverage + run: | + FILE='.github/quality-monitor.json' + PATTERN='target/pit-reports/mutations.xml' + if [ -f "$FILE" ]; then + if grep -q "$PATTERN" "$FILE"; then + echo "PIT=-Ppit" >> "$GITHUB_ENV" + fi + fi + - name: Build with Maven + env: + NVD_API_KEY: ${{ secrets.NVD_API_KEY }} + OSS_INDEX_TOKEN: ${{ secrets.OSS_INDEX_TOKEN }} + PIT: ${{ env.PIT }} + BROWSER: chrome-container + run: | + mvn -V --color always -ntp clean verify $PIT -Pci -Powasp | tee maven.log + if [ "${PIPESTATUS[0]}" != "0" ]; then + exit 1; + fi + mv -fv maven.log target/maven.log + - name: Upload Quality Reports + uses: actions/upload-artifact@v4 + with: + name: quality-reports + path: | + **/target/**/*.json + **/target/**/*.xml + **/target/**/*.log + diff --git a/.github/workflows/quality-monitor-comment.yml b/.github/workflows/quality-monitor-comment.yml new file mode 100644 index 00000000..648b197d --- /dev/null +++ b/.github/workflows/quality-monitor-comment.yml @@ -0,0 +1,52 @@ +name: 'Quality Monitor Comment' + +on: + workflow_run: + workflows: [ "Quality Monitor Build" ] + types: [ completed ] + +permissions: + actions: read + contents: read + pull-requests: write + checks: write + +jobs: + comment: + if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request' }} + runs-on: ubuntu-latest + name: Comment on PR + + steps: + - name: Extract PR number and SHA + id: pr + run: | + pr_number='${{ github.event.workflow_run.pull_requests[0].number }}' + echo "number=$pr_number" >> "$GITHUB_OUTPUT" + sha='${{ github.event.workflow_run.head_sha }}' + echo "sha=$sha" >> "$GITHUB_OUTPUT" + - name: Checkout PR + uses: actions/checkout@v5 + with: + ref: ${{ steps.pr.outputs.sha }} + - name: Download PR Quality Reports from Quality Monitor Build workflow + uses: dawidd6/action-download-artifact@v11 + with: + run_id: ${{ github.event.workflow_run.id }} + name: quality-reports + - name: Read Quality Monitor Configuration + id: quality-monitor + run: echo "json=$(jq -c . .github/quality-monitor.json)" >> "$GITHUB_OUTPUT" + - name: Read Quality Gates Configuration + id: quality-gates + run: echo "json=$(jq -c . .github/quality-gates.json)" >> "$GITHUB_OUTPUT" + - name: Run Quality Monitor and Comment on PR + uses: uhafner/quality-monitor@v3 + with: + sha: ${{ steps.pr.outputs.sha }} + config: ${{ steps.quality-monitor.outputs.json }} + quality-gates: ${{ steps.quality-gates.outputs.json }} + pr-number: ${{ steps.pr.outputs.number }} + comments-strategy: REMOVE + show-headers: true + title-metric: none diff --git a/.github/workflows/quality-monitor-jenkins.yml b/.github/workflows/quality-monitor-jenkins.yml deleted file mode 100644 index 5b172143..00000000 --- a/.github/workflows/quality-monitor-jenkins.yml +++ /dev/null @@ -1,180 +0,0 @@ -name: 'Quality Monitor PR' - -on: - pull_request_target: - -jobs: - build: - - runs-on: [ubuntu-latest] - name: Build, test and monitor quality on Ubuntu - - steps: - - name: 'Checkout merge commit' - uses: actions/checkout@v5 - with: - ref: "${{ github.event.pull_request.merge_commit_sha }}" - if: github.event.pull_request.merge_commit_sha != '' - - name: 'Checkout PR head commit' - uses: actions/checkout@v5 - with: - ref: "${{ github.event.pull_request.head.sha }}" - if: github.event.pull_request.merge_commit_sha == '' - - name: Set up JDK 21 - uses: actions/setup-java@v5 - with: - distribution: 'temurin' - java-version: 21 - check-latest: true - cache: 'maven' - - name: Set up Maven - uses: stCarolas/setup-maven@v5 - with: - maven-version: 3.9.11 - - name: Cache the NVD database - uses: actions/cache@v4 - with: - path: ~/.m2/repository/org/owasp/dependency-check-data - key: dependency-check - - name: Build with Maven - env: - BROWSER: chrome-container - NVD_API_KEY: ${{ secrets.NVD_API_KEY }} - run: | - mvn -V --color always -ntp clean verify -Pci -Powasp | tee maven.log - if [ "${PIPESTATUS[0]}" != "0" ]; then - exit 1; - fi - - name: Extract pull request number - uses: jwalton/gh-find-current-pr@v1 - id: pr - - name: Run Quality Monitor - uses: uhafner/quality-monitor@v3 - with: - pr-number: ${{ steps.pr.outputs.number }} - show-headers: true - config: > - { - "tests": { - "name": "Tests", - "tools": [ - { - "id": "junit", - "name": "Unit Tests", - "pattern": "**/target/surefire-reports/TEST*forensics*.xml" - }, - { - "id": "junit", - "icon": "rocket", - "name": "Integration Tests", - "pattern": "**/target/failsafe-reports/TEST*.xml" - }, - { - "id": "junit", - "icon": "no_entry", - "name": "Architecture Tests", - "pattern": "**/target/surefire-reports/TEST*archunit*.xml" - } - ] - }, - "analysis": [ - { - "name": "Style", - "id": "style", - "tools": [ - { - "id": "checkstyle", - "pattern": "**/target/checkstyle-*/checkstyle-result.xml" - }, - { - "id": "pmd", - "pattern": "**/target/pmd-*/pmd.xml" - } - ] - }, - { - "name": "Bugs", - "id": "bugs", - "icon": "bug", - "tools": [ - { - "id": "spotbugs", - "sourcePath": "src/main/java", - "pattern": "**/target/spotbugsXml.xml" - } - ] - }, - { - "name": "Vulnerabilities", - "id": "vulnerabilities", - "icon": "shield", - "tools": [ - { - "id": "owasp-dependency-check", - "icon": "shield", - "pattern": "**/target/dependency-check-report.json" - } - ] - } - ], - "coverage": [ - { - "name": "Code Coverage", - "tools": [ - { - "id": "jacoco", - "metric": "line", - "sourcePath": "src/main/java", - "pattern": "**/target/site/jacoco/jacoco.xml" - }, - { - "id": "jacoco", - "metric": "branch", - "sourcePath": "src/main/java", - "pattern": "**/target/site/jacoco/jacoco.xml" - } - ] - } - ], - "metrics": - { - "name": "Software Metrics", - "tools": [ - { - "id": "metrics", - "pattern": "**/metrics/pmd.xml", - "metric": "CYCLOMATIC_COMPLEXITY" - }, - { - "id": "metrics", - "pattern": "**/metrics/pmd.xml", - "metric": "COGNITIVE_COMPLEXITY" - }, - { - "id": "metrics", - "pattern": "**/metrics/pmd.xml", - "metric": "NPATH_COMPLEXITY" - }, - { - "id": "metrics", - "pattern": "**/metrics/pmd.xml", - "metric": "LOC" - }, - { - "id": "metrics", - "pattern": "**/metrics/pmd.xml", - "metric": "NCSS" - }, - { - "id": "metrics", - "pattern": "**/metrics/pmd.xml", - "metric": "COHESION" - }, - { - "id": "metrics", - "pattern": "**/metrics/pmd.xml", - "metric": "WEIGHT_OF_CLASS" - } - ] - } - }