Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 0 additions & 62 deletions .github/actions/protected-sonar/action.yml

This file was deleted.

70 changes: 0 additions & 70 deletions .github/actions/protected-sonar/verify-sonar-task.cjs

This file was deleted.

151 changes: 17 additions & 134 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
name: Regression and candidate coverage
name: Quality and Sonar

on:
push:
branches: [main]
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
workflow_dispatch:

permissions:
contents: read
Expand All @@ -14,47 +15,18 @@ concurrency:
cancel-in-progress: true

jobs:
regression:
quality:
name: Regression (test-merge)
runs-on: ubuntu-latest
timeout-minutes: 30
outputs:
diff_base: ${{ steps.diff.outputs.base }}
diff_head: ${{ steps.diff.outputs.head }}

steps:
- name: Check out GitHub test revision
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.sha }}
fetch-depth: 0
persist-credentials: false

- name: Record tested identities
env:
EXPECTED_SHA: ${{ github.sha }}
CANDIDATE_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
CHECK_RUN_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
run: |
set -eu
actual_sha=$(git rev-parse HEAD)
test "$actual_sha" = "$EXPECTED_SHA"
tree=$(git show -s --format=%T HEAD)
{
echo '### Regression identity'
echo
echo "- Event SHA/test revision: \`$EXPECTED_SHA\`"
echo "- Checked-out SHA: \`$actual_sha\`"
echo "- Candidate head SHA: \`$CANDIDATE_SHA\`"
echo "- Check-run head SHA: \`$CHECK_RUN_HEAD_SHA\`"
echo "- Tested tree: \`$tree\`"
} >> "$GITHUB_STEP_SUMMARY"

- name: Resolve and check event-aware diff
id: diff
env:
GITHUB_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
run: sh scripts/ci/check-event-diff.sh

- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
Expand All @@ -67,7 +39,7 @@ jobs:
go-version-file: go.mod
cache-dependency-path: go.sum

- name: Install frontend dependencies without lifecycle scripts
- name: Install frontend dependencies
run: npm ci --ignore-scripts

- name: Run frontend coverage gate
Expand All @@ -92,105 +64,16 @@ jobs:
- name: Check Go formatting
run: sh scripts/check-go-format.sh

- name: Install pinned Actionlint
- name: Run SonarQube Cloud scan
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
uses: SonarSource/sonarqube-scan-action@22918119ff8e1ca75a623e15c8296b6ea4fbe28f # v8.2.1
env:
ACTIONLINT_VERSION: 1.7.12
ACTIONLINT_SHA256: 8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8
run: |
set -eu
archive="$RUNNER_TEMP/actionlint.tar.gz"
curl --fail --location --proto '=https' --tlsv1.2 \
"https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" \
--output "$archive"
printf '%s %s\n' "$ACTIONLINT_SHA256" "$archive" | sha256sum --check --strict
mkdir "$RUNNER_TEMP/actionlint"
tar -xzf "$archive" -C "$RUNNER_TEMP/actionlint" actionlint
"$RUNNER_TEMP/actionlint/actionlint" -version

- name: Lint workflows and shell scripts
run: |
"$RUNNER_TEMP/actionlint/actionlint" .github/workflows/*.yml
shellcheck --version
shellcheck scripts/*.sh scripts/ci/*.sh

- name: Verify immutable action pins
run: node scripts/ci_monitor.cjs check-actions

- name: Run CI control-plane hostile tests
run: |
sh scripts/check-go-checkers.test.sh
sh scripts/ci/test-npm-ignore-scripts.sh
python3 scripts/ci/test_validate_coverage_artifact.py
python3 scripts/ci/test_ci_helpers.py
python3 scripts/ci/test_workflow_structure.py
node scripts/ci/test_validate_workflow_run.cjs
node scripts/ci/test_ci_monitor.cjs

candidate_coverage:
name: Candidate head coverage
needs: regression
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- name: Check out exact candidate head
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 0
persist-credentials: false

- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24.15.0
cache: npm

- name: Set up Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
go-version-file: go.mod
cache-dependency-path: go.sum
args: >-
-Dsonar.organization=${{ vars.SONAR_ORGANIZATION }}
-Dsonar.projectKey=${{ vars.SONAR_PROJECT_KEY }}

- name: Install frontend dependencies without lifecycle scripts
run: npm ci --ignore-scripts

- name: Generate frontend coverage
run: npm run test:coverage:report-only

- name: Generate Go coverage
env:
GO_PACKAGE_COVERAGE_THRESHOLD: '95.0'
GO_TOTAL_COVERAGE_THRESHOLD: '96.4'
GO_COVERAGE_PROFILE: coverage/go.out
run: npm run coverage:go

- name: Fetch verified pull request base
if: github.event_name == 'pull_request'
env:
BASE_REPOSITORY: ${{ github.repository }}
BASE_SHA: ${{ needs.regression.outputs.diff_base }}
run: sh scripts/ci/fetch-verified-base.sh "$BASE_REPOSITORY" "$BASE_SHA"

- name: Create candidate-bound coverage manifest
env:
CANDIDATE_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
CANDIDATE_REPOSITORY: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
CANDIDATE_REF: ${{ github.event.pull_request.head.ref || github.ref_name }}
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number || 0 }}
BASE_SHA: ${{ needs.regression.outputs.diff_base }}
BASE_REF: ${{ github.event.pull_request.base.ref || github.event.repository.default_branch }}
run: node scripts/ci/create-coverage-manifest.cjs

- name: Upload exact candidate coverage bundle
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0
with:
name: candidate-head-coverage-${{ github.event.pull_request.head.sha || github.sha }}
path: |
coverage/lcov.info
coverage/go.out
coverage/manifest.json
if-no-files-found: error
compression-level: 9
retention-days: 7
include-hidden-files: false
- name: Explain skipped Sonar scan
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
run: echo "Sonar scan skipped because GitHub does not expose repository secrets to fork pull requests." >> "$GITHUB_STEP_SUMMARY"
Loading
Loading