diff --git a/.github/actions/lint-error/action.yml b/.github/actions/lint-error/action.yml index 95611788c..040aad6ce 100644 --- a/.github/actions/lint-error/action.yml +++ b/.github/actions/lint-error/action.yml @@ -2,10 +2,6 @@ name: "Lint error" description: "Checks for lint errors and posts a helpful comment" inputs: - comment-header: - description: "The header ID for the comment" - required: true - format-command: description: "The command to run to fix lint errors" required: true @@ -47,9 +43,40 @@ runs: if: steps.changes.outputs.diff uses: actions/upload-artifact@v4 with: - name: ${{ steps.changes.outputs.file }} + name: ${{ inputs.format-tool }}-diff path: ${{ steps.changes.outputs.file }} - retention-days: 3 + if-no-files-found: error + + - name: Set summary + id: summary + if: steps.changes.outputs.diff + run: | + code_block="\`\`\`" + + summary=$(cat<> $GITHUB_STEP_SUMMARY + + file="ci_summary.md" + echo "❌🛠️ \`${{ inputs.format-tool }}\`: Lint errors, fix available." >> $file + echo "file=$file" >> $GITHUB_OUTPUT + shell: bash + + - name: Upload CI summary as artifact + if: steps.summary.outputs.file + uses: actions/upload-artifact@v4 + with: + name: summary-${{ inputs.format-tool }} + path: ${{ steps.summary.outputs.file }} if-no-files-found: error - name: Fail if diff exists diff --git a/.github/actions/run-tests-setup/action.yml b/.github/actions/run-tests-setup/action.yml deleted file mode 100644 index 413f3d50a..000000000 --- a/.github/actions/run-tests-setup/action.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: "Run tests (setup)" -description: "Sets up the PR comment for tests" - -runs: - using: "composite" - - steps: - - name: Get workflow URL - id: workflow-url - run: | - repo_url="${{ github.server_url }}/${{ github.repository }}" - echo "url=$repo_url/actions/runs/${{ github.run_id }}" >> $GITHUB_OUTPUT - shell: bash - - - name: Begin PR comment - uses: marocchino/sticky-pull-request-comment@v2 - if: github.event.pull_request.head.repo.full_name == github.repository - with: - header: tests - recreate: true - message: | - ## Test results - See [workflow run](${{ steps.workflow-url.outputs.url }}) for test output. - - # Neccesary since the first comment has an annoying comment. - - name: Append table header - uses: marocchino/sticky-pull-request-comment@v2 - if: github.event.pull_request.head.repo.full_name == github.repository - with: - header: tests - append: true - message: | - | Job name | Unit tests | Integration tests | - | --- | --- | --- | diff --git a/.github/actions/run-tests/action.yml b/.github/actions/run-tests/action.yml index a749c52b1..60086df21 100644 --- a/.github/actions/run-tests/action.yml +++ b/.github/actions/run-tests/action.yml @@ -14,7 +14,13 @@ runs: id: unittests env: QT_QPA_PLATFORM: offscreen - run: ./build/bin/unittests + run: | + ./build/bin/unittests + result=$? + + if [ $result -ne 0 ]; then + echo "Unit tests failed with code: $result" >> $GITHUB_STEP_SUMMARY + fi shell: bash continue-on-error: true @@ -27,7 +33,7 @@ runs: result=$? if [ $result -ne 0 ]; then - echo "::warning ::Integration tests failed with code: $result" + echo "Integration tests failed with code: $result" >> $GITHUB_STEP_SUMMARY fi shell: bash continue-on-error: true @@ -45,14 +51,25 @@ runs: echo "integtests=$integtests" >> $GITHUB_OUTPUT shell: bash - - name: Append to PR comment - uses: marocchino/sticky-pull-request-comment@v2 - if: github.event.pull_request.head.repo.full_name == github.repository + - name: Summary row + id: row + run: | + file="row-${{ inputs.job }}.md" + + row="" + row+="| ${{ inputs.job }} " + row+="| ${{ steps.results.outputs.unittests }} " + row+="| ${{ steps.results.outputs.integtests }} |" + echo "$row" > $file + + echo "file=$file" > $GITHUB_OUTPUT + shell: bash + + - name: Save summary row + uses: actions/upload-artifact@v4 with: - header: tests - append: true - message: | - | ${{ inputs.job }} | ${{ steps.results.outputs.unittests }} | ${{ steps.results.outputs.integtests }} | + name: test-result-${{ inputs.job }} + path: ${{ steps.row.outputs.file }} - name: Check test outcome if: steps.unittests.outcome == 'failure' diff --git a/.github/actions/test-summary/action.yml b/.github/actions/test-summary/action.yml new file mode 100644 index 000000000..a84919382 --- /dev/null +++ b/.github/actions/test-summary/action.yml @@ -0,0 +1,67 @@ +name: "Test Summary" +description: "Creates a markdown table from test results and uploads a summary file" + +runs: + using: "composite" + steps: + - name: Download test result rows + uses: actions/download-artifact@v4 + with: + pattern: test-result-* + merge-multiple: true + path: rows + + - name: Build markdown table + id: markdown-table + run: | + # Builds a markdown table from the row artifacts. + + header=$(cat <> $GITHUB_OUTPUT + shell: bash + + - name: Set step summary + id: summary + run: | + # Sets the step summary and creates a CI summary file. + + table="${{ steps.markdown-table.outputs.markdown }}" + if [ -z "$table" ]; then + echo "No test results found" > $GITHUB_STEP_SUMMARY + exit 1 + else + echo "$table" > $GITHUB_STEP_SUMMARY + fi + + count=$(echo -n "$table" | grep -o "❌" | wc -l || echo 0) + if [ $count -gt 0 ]; then + file="ci-summary.md" + echo "❌🔬 Tests failed: $count" > $file + echo "file=$file" >> $GITHUB_OUTPUT + fi + shell: bash + + - name: Upload CI summary + if: steps.summary.outputs.file + uses: actions/upload-artifact@v4 + with: + name: summary-tests + path: ${{ steps.summary.outputs.file }} + if-no-files-found: error diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 215e195f6..ea7c02ff7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,11 +25,21 @@ env: PACKAGE_BUILD: ${{ !github.event.pull_request.draft }} PACKAGE_UPLOAD: ${{ !github.event.pull_request.draft }} -permissions: - pull-requests: write - jobs: - setup: + # Quality gate to allow PR merge, used in the branch protection rules. + ci-passed: + runs-on: ubuntu-latest + needs: [lint-cmake, lint-clang, windows, macos, linux, unix] + + steps: + - run: echo "CI passed" > $GITHUB_STEP_SUMMARY + + # Summary of test results, combined from test result artifacts. + # Runs even if the tests fail to provide a summary of the failures. + test-results: + needs: [windows, macos, linux] + if: always() + runs-on: ubuntu-latest timeout-minutes: 5 @@ -37,11 +47,32 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Test setup - uses: ./.github/actions/run-tests-setup + - name: Test summary + uses: ./.github/actions/test-summary + + lint-cmake: + if: ${{ github.event_name == 'pull_request' }} + uses: ./.github/workflows/lint-cmake.yml + + lint-clang: + if: ${{ github.event_name == 'pull_request' }} + uses: ./.github/workflows/lint-clang.yml + + analyse-valgrind: + if: ${{ github.event_name == 'pull_request' }} + uses: ./.github/workflows/valgrind-analysis.yml + + analyse-codeql: + if: ${{ github.event_name == 'pull_request' }} + uses: ./.github/workflows/codeql-analysis.yml + + analyse-sonarcloud: + if: ${{ github.event_name == 'pull_request' }} + uses: ./.github/workflows/sonarcloud-analysis.yml + secrets: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} windows: - needs: setup name: ${{ matrix.target.name }} runs-on: ${{ matrix.target.runs-on }} container: ${{ matrix.target.container }} @@ -129,7 +160,6 @@ jobs: package-version: ${{ env.DESKFLOW_VERSION }} macos: - needs: setup name: ${{ matrix.target.name }} runs-on: ${{ matrix.target.os }} timeout-minutes: ${{ matrix.target.timeout }} @@ -230,7 +260,7 @@ jobs: jq-filter: .distro |= map(select(.["runs-on"] | contains("arm64") | not)) linux: - needs: [setup, linux-matrix] + needs: linux-matrix name: linux-${{ matrix.distro.name }} runs-on: ${{ matrix.distro.runs-on }} container: ${{ matrix.distro.container }} @@ -294,7 +324,6 @@ jobs: # Technically, "unix" is a misnomer, but we use it here to mean "Unix-like BSD-derived". unix: - needs: setup name: unix-${{ matrix.distro.name }} runs-on: ${{ vars.CI_UNIX_RUNNER || 'ubuntu-24.04' }} timeout-minutes: 20 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 58b788004..62ec2b1e1 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,12 +2,7 @@ name: "CodeQL Analysis" on: workflow_dispatch: - pull_request: - types: - - opened - - reopened - - synchronize - - ready_for_review + workflow_call: push: branches: [master] diff --git a/.github/workflows/lint-clang.yml b/.github/workflows/lint-clang.yml index 92a8deea6..d8abad286 100644 --- a/.github/workflows/lint-clang.yml +++ b/.github/workflows/lint-clang.yml @@ -2,15 +2,7 @@ name: "Lint Clang" on: workflow_dispatch: - pull_request: - types: - - opened - - reopened - - synchronize - - ready_for_review - -permissions: - pull-requests: write + workflow_call: jobs: lint-clang: @@ -37,4 +29,3 @@ jobs: with: format-command: ./scripts/lint_clang.py -f format-tool: "clang-format" - comment-header: "lint-clang" diff --git a/.github/workflows/lint-cmake.yml b/.github/workflows/lint-cmake.yml index 165638934..5a4679004 100644 --- a/.github/workflows/lint-cmake.yml +++ b/.github/workflows/lint-cmake.yml @@ -2,15 +2,7 @@ name: "Lint CMake" on: workflow_dispatch: - pull_request: - types: - - opened - - reopened - - synchronize - - ready_for_review - -permissions: - pull-requests: write + workflow_call: jobs: lint-cmake: @@ -37,4 +29,3 @@ jobs: with: format-command: ./scripts/lint_cmake.py -f format-tool: "cmake-format" - comment-header: "lint-cmake" diff --git a/.github/workflows/sonarcloud-analysis.yml b/.github/workflows/sonarcloud-analysis.yml index f700f8241..404f9d87d 100644 --- a/.github/workflows/sonarcloud-analysis.yml +++ b/.github/workflows/sonarcloud-analysis.yml @@ -2,12 +2,10 @@ name: "SonarCloud Analysis" on: workflow_dispatch: - pull_request: - types: - - opened - - reopened - - synchronize - - ready_for_review + workflow_call: + secrets: + SONAR_TOKEN: + required: true push: branches: [master] @@ -78,7 +76,6 @@ jobs: QT_QPA_PLATFORM: offscreen run: cmake --build build --target coverage-unittests - # Retry integtests coverae as gcovr intermittently fails to parse .gcda files. - name: Integration tests coverage env: QT_QPA_PLATFORM: offscreen diff --git a/.github/workflows/valgrind-analysis.yml b/.github/workflows/valgrind-analysis.yml index 61089643e..cfa74cb20 100644 --- a/.github/workflows/valgrind-analysis.yml +++ b/.github/workflows/valgrind-analysis.yml @@ -2,15 +2,7 @@ name: "Valgrind Analysis" on: workflow_dispatch: - pull_request: - types: - - opened - - reopened - - synchronize - - ready_for_review - -permissions: - pull-requests: write + workflow_call: jobs: valgrind-analysis: @@ -58,29 +50,22 @@ jobs: with: executable: ./build/bin/integtests - - name: Get workflow URL - id: workflow-url + - name: Set job summary run: | - repo_url="${{ github.server_url }}/${{ github.repository }}" - echo "url=$repo_url/actions/runs/${{ github.run_id }}" >> $GITHUB_OUTPUT - shell: bash + backticks='```' + message=$(cat <> $GITHUB_STEP_SUMMARY