Skip to content
Open
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
5 changes: 5 additions & 0 deletions .github/actions/post-clang-tidy-results/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ inputs:
required: false
default: "false"

outputs:
has_content:
description: "Whether any clang-tidy artifacts with reportable content were found"
value: ${{ steps.check.outputs.has_summary_content }}

runs:
using: "composite"
steps:
Expand Down
15 changes: 15 additions & 0 deletions .github/workflows/clang-tidy-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,23 @@ jobs:
issues: write
steps:
- name: Post Clang-Tidy results
id: post_results
uses: Framework-R-D/phlex/.github/actions/post-clang-tidy-results@main
with:
build-path: ${{ needs.setup.outputs.build_path }}
pr-number: ${{ needs.setup.outputs.pr_number }}
post-summary: "true"

- name: Post no-issues comment
if: >-
always() && github.event_name == 'issue_comment' && needs.clang-tidy-check.result == 'success' &&
steps.post_results.outputs.has_content != 'true' && needs.setup.outputs.pr_number != ''
uses: thollander/actions-comment-pull-request@24bffb9b452ba05a4f3f77933840a6a841d1b32b # v3.0.1
with:
message: "No clang-tidy issues found."

- name: Update PR comment reactions
if: always() && github.event_name == 'issue_comment'
uses: Framework-R-D/phlex/.github/actions/complete-pr-comment@main
with:
status: ${{ needs.clang-tidy-check.result }}
7 changes: 7 additions & 0 deletions .github/workflows/cmake-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
pull-requests: write
issues: write

steps:
- name: Comment on build completion
Expand All @@ -319,3 +320,9 @@ jobs:

See the [workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for detailed results.
# yamllint enable

- name: Update PR comment reactions
if: always()
uses: Framework-R-D/phlex/.github/actions/complete-pr-comment@main
with:
status: ${{ needs.build.result }}
31 changes: 30 additions & 1 deletion .github/workflows/coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ jobs:
has_coverage_xml: ${{ steps.coverage_outputs.outputs.has_coverage_xml }}
has_coverage_html: ${{ steps.coverage_outputs.outputs.has_coverage_html }}
has_coverage_llvm_info: ${{ steps.coverage_outputs.outputs.has_coverage_llvm_info }}
has_coverage_python_xml: ${{ steps.coverage_outputs.outputs.has_coverage_python_xml }}
artifact_upload_available: ${{ steps.artifact_runtime.outputs.available }}

steps:
Expand Down Expand Up @@ -271,7 +272,6 @@ jobs:
--cov=scripts \
--cov-report=xml:"$BUILD_DIR/coverage-scripts.xml" \
--cov-report=term-missing \
--omit="scripts/test/*" \
-q; then
echo "✅ Scripts coverage report generation succeeded."
else
Expand Down Expand Up @@ -454,3 +454,32 @@ jobs:
path: coverage-artifacts/coverage-html/
if-no-files-found: warn
retention-days: 30

coverage-complete:
needs: [setup, coverage, coverage-upload]
if: always() && github.event_name == 'issue_comment' && needs.setup.result == 'success'
runs-on: ubuntu-latest
permissions:
pull-requests: write
issues: write

steps:
- name: Comment on coverage completion
uses: thollander/actions-comment-pull-request@24bffb9b452ba05a4f3f77933840a6a841d1b32b # v3.0.1
with:
message: |
Coverage workflow completed.

**Result:** ${{ needs.coverage.result == 'success' && '✅ Coverage analysis passed.'
|| needs.coverage.result == 'failure' && '❌ Coverage analysis failed.'
|| needs.coverage.result == 'cancelled' && '⚠️ Coverage analysis was cancelled.'
|| needs.coverage.result == 'skipped' && 'ℹ️ No relevant changes detected; coverage skipped.'
|| format('ℹ️ Coverage completed with status: {0}.', needs.coverage.result) }}

See the [workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for detailed results.

- name: Update PR comment reactions
if: always()
uses: Framework-R-D/phlex/.github/actions/complete-pr-comment@main
with:
status: ${{ needs.coverage.result }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,4 @@ docs/build/
.act-artifacts/
.secrets
actionlint
.coverage
25 changes: 25 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,33 @@ extend-ignore = [
"E203", # whitespace before ':'
]

[tool.ruff.lint.isort]
# Scripts are treated as first-party so that `import clang_tidy_check_summary`
# and similar local imports are grouped correctly relative to third-party ones
# (e.g. pytest), avoiding false I001 violations in scripts/test/.
known-first-party = [
"check_codeql_alerts",
"clang_tidy_check_summary",
"clang_tidy_diff_issues",
"clang_tidy_fixes_to_problems",
"codeql_reset_dismissed_alerts",
"create_coverage_symlinks",
"export_llvm_lcov",
"fix_header_guards",
"normalize_coverage_lcov",
"normalize_coverage_xml",
"sarif_alerts",
]

[tool.ruff.lint.pydocstyle]
convention = "google"

[tool.ruff.format]
quote-style = "double"

[tool.coverage.run]
# Exclude the test helpers from coverage measurement. pytest-cov resolves
# this glob relative to the measurement source root (scripts/), so the pattern
# works whether pytest is invoked from the repo root or a build directory that
# sets --cov=scripts.
omit = ["scripts/test/*"]
52 changes: 52 additions & 0 deletions scripts/QUICK_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,58 @@ Quick coverage workflow:

See `scripts/README.md` for detailed coverage documentation.

## Developer Tools (Quick Reference)

Three local-only utility scripts for post-processing clang-tidy output and
managing GitHub CodeQL alerts. None of these are invoked by CI.

### clang-tidy Checklist

After running `run-clang-tidy -export-fixes build/fixes.yaml ...`, generate a
markdown task list of checks with occurrence counts:

```bash
# Plain list to stdout
python3 scripts/clang_tidy_check_summary.py build/fixes.yaml

# With documentation hyperlinks, written to a file
python3 scripts/clang_tidy_check_summary.py build/fixes.yaml --links \
-o summary.md
```

### clang-tidy → VS Code Problem Links

Convert the same YAML to gcc-style `file:line:col: severity: message [check]`
lines that VS Code's `$gcc` problem matcher turns into clickable source links:

```bash
# Diagnostics to stdout (clickable in VS Code terminal)
python3 scripts/clang_tidy_fixes_to_problems.py build/fixes.yaml

# Translate CI runner paths to local paths
python3 scripts/clang_tidy_fixes_to_problems.py build/fixes.yaml \
--path-map /__w/phlex/phlex/phlex-src=/your/local/checkout \
-o build/problems.txt
```

### Reset Dismissed CodeQL Alerts

Reopen all dismissed CodeQL alerts so the next scan re-evaluates them:

```bash
# Preview (no changes)
GITHUB_TOKEN=$(gh auth token) \
python3 scripts/codeql_reset_dismissed_alerts.py \
--owner Framework-R-D --repo phlex --dry-run

# Live run
GITHUB_TOKEN=$(gh auth token) \
python3 scripts/codeql_reset_dismissed_alerts.py \
--owner Framework-R-D --repo phlex
```

See `scripts/README.md` for full documentation on all three tools.

## Getting Help

- Script documentation: `scripts/README.md`
Expand Down
165 changes: 165 additions & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,171 @@ cd build && ctest -R test_name
./scripts/coverage.sh clean test summary
```

## Developer Tools

These scripts are **not** invoked by CI — they are local developer utilities
for post-processing clang-tidy output and managing GitHub code-scanning alerts.

### `clang_tidy_check_summary.py`

Reads a `clang-tidy-fixes.yaml` file (produced by `run-clang-tidy
-export-fixes`) and writes a compact markdown task list — one line per check
name with its unique occurrence count — suitable for pasting into a GitHub
issue or PR description to track remediation progress.

#### Usage (`clang_tidy_check_summary.py`)

```bash
# Print checklist to stdout
python3 scripts/clang_tidy_check_summary.py build/clang-tidy-fixes.yaml

# Write to a file
python3 scripts/clang_tidy_check_summary.py build/clang-tidy-fixes.yaml \
-o summary.md

# Add documentation hyperlinks for each check name
python3 scripts/clang_tidy_check_summary.py build/clang-tidy-fixes.yaml \
--links -o summary.md
```

#### Output format (`clang_tidy_check_summary.py`)

```markdown
- [ ] cert-err34-c (3)
- [ ] modernize-use-nullptr (12)
- [ ] readability-identifier-naming (47)
```

With `--links` each check name becomes a hyperlink to its clang-tidy
documentation page.

#### Typical workflow

```bash
# 1. Run clang-tidy and collect fixes (from repo root)
run-clang-tidy -p build -export-fixes build/fixes.yaml phlex/ form/ plugins/

# 2. Generate a summary for a GitHub issue
python3 scripts/clang_tidy_check_summary.py build/fixes.yaml --links \
-o summary.md

# 3. Paste summary.md into the issue body
```

#### Uniqueness counting

Two entries are collapsed into a single occurrence when they share the same
`(DiagnosticName, FilePath, FileOffset)` triplet — this avoids inflating
counts when the same location is reported by multiple translation units.

---

### `clang_tidy_fixes_to_problems.py`

Converts a `clang-tidy-fixes.yaml` file into gcc/clang compiler-style
diagnostic lines:

```text
/abs/path/file.cpp:line:col: warning: message [check-name]
```

VS Code's built-in `$gcc` problem matcher recognises this format and turns
each line into a clickable source link in the terminal panel. The script also
handles CI-to-local path translation via `--path-map`.

#### Usage (`clang_tidy_fixes_to_problems.py`)

```bash
# Print diagnostics to stdout (opens as clickable links in VS Code terminal)
python3 scripts/clang_tidy_fixes_to_problems.py build/clang-tidy-fixes.yaml

# Write to a file
python3 scripts/clang_tidy_fixes_to_problems.py build/fixes.yaml \
-o build/problems.txt

# Translate CI runner paths to local paths
python3 scripts/clang_tidy_fixes_to_problems.py build/fixes.yaml \
--path-map /__w/phlex/phlex/phlex-src=/home/user/phlex \
--workspace-root /home/user/phlex \
-o build/problems.txt
```

#### Path mapping

clang-tidy embeds absolute paths as seen on the machine that ran the build.
When you download a `clang-tidy-fixes.yaml` artifact from CI you need to
translate the runner paths to your local checkout.

Use `--path-map OLD=NEW` (repeatable). Two default mappings for the standard
Phlex CI layout are applied automatically after any explicit `--path-map`
entries:

| CI path prefix | Local path |
| :--- | :--- |
| `/__w/phlex/phlex/phlex-src` | `<workspace-root>` |
| `/__w/phlex/phlex/phlex-build` | `<workspace-root>/build` |

#### External-header handling

When a diagnostic's primary location is inside a system or third-party header
that is absent locally, the script searches the attached clang-tidy notes for
a trace back to workspace source code and redirects the reported location
there. The original external location is preserved in the message text.

---

### `codeql_reset_dismissed_alerts.py`

Reopens every dismissed CodeQL code-scanning alert for a repository via the
GitHub REST API. Useful before an audit or after a large refactor to ensure
the alert list reflects the current code rather than past dismissals.

#### Authentication

Set a GitHub personal access token (PAT) with the `security_events` scope
before running:

```bash
export GITHUB_TOKEN=ghp_your_token_here

# Or reuse the token from the GitHub CLI
export GH_TOKEN=$(gh auth token)
```

#### Usage (`codeql_reset_dismissed_alerts.py`)

```bash
# Preview what would be reopened (no changes made)
GITHUB_TOKEN=ghp_... python3 scripts/codeql_reset_dismissed_alerts.py \
--owner Framework-R-D --repo phlex --dry-run

# Reopen all dismissed alerts
GITHUB_TOKEN=ghp_... python3 scripts/codeql_reset_dismissed_alerts.py \
--owner Framework-R-D --repo phlex
```

#### What it does

1. Pages through all alerts with `state=dismissed` in batches of 100.
2. Prints the alert number, rule ID, and dismissal reason for each one.
3. Issues a `PATCH` request per alert to set `state=open`.

After running, the next scheduled or triggered CodeQL analysis will
re-evaluate every reopened alert and either confirm it as still present or
close it as fixed.

#### Rate limits

Each alert requires one PATCH request. The GitHub API allows 5 000
authenticated requests per hour; for repositories with large numbers of
dismissed alerts, check your remaining quota first:

```bash
gh api /rate_limit
```

---

## Additional Notes

- All scripts should be run from the repository root or scripts directory
Expand Down
Loading
Loading