From 40db6f5f4feaf2b026007b55d7deb96d88ff0e27 Mon Sep 17 00:00:00 2001 From: JeffreyChen Date: Mon, 3 Aug 2026 03:01:16 +0800 Subject: [PATCH 1/2] State that CLAUDE.md is the only home for project rules A rule kept in a side document is a rule nobody reads, which is how the architecture tree in this file drifted out of date. Reference material that is not a rule keeps its own file and is linked from here. --- CLAUDE.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 4c3817d..fca3f1c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,6 +2,8 @@ Automation-first Python IDE built on PySide6 + JEditor, integrating Web/API/GUI/Load testing into a single environment. +**This file is the only home for project rules.** Anything that constrains how work is done here — conventions, security requirements, quality gates, commit policy — belongs in this file. Do not start a `progress.md`, a scratch notes file, or any other side document to hold rules: a rule kept somewhere else is a rule nobody reads. Reference material that is not a rule (the architecture map, the plugin API) lives in its own file and is linked from here. + ## Architecture ``` From 4a9beb030128cfdf180c1bfb09526d0040ceeef8 Mon Sep 17 00:00:00 2001 From: JeffreyChen Date: Mon, 3 Aug 2026 03:29:49 +0800 Subject: [PATCH 2/2] Feed real coverage to SonarCloud and stop scanning what cannot be read Two things the migration to CI-based analysis surfaced. The quality gate on main fails on one condition: new code is scored at 0% coverage against a threshold of 80, because no coverage report has ever been uploaded. The 3.12 matrix leg now runs pytest under coverage and hands the report to the scanner as an artifact. .coveragerc sets relative_files because the report is produced on Windows and read by a Linux scanner, so it must not carry an absolute source root. Real coverage is 57% overall -- utils and tools_gui sit at 95-100%, the UI layer between 20% and 45% -- so this reports an honest number rather than necessarily clearing the gate. SonarCloud's plan for this organization exposes results for main and for pull requests only. An analysis pushed for dev is accepted and its compute-engine task succeeds, but every read of it returns 403, and no project in the organization has a branch other than main. Scanning each push to dev therefore spent CI time producing numbers nobody can see, so dev.yml now scans pull requests only; stable.yml still scans pushes to main. --- .coveragerc | 14 ++++++++++++++ .github/workflows/dev.yml | 30 ++++++++++++++++++++++-------- .github/workflows/stable.yml | 24 +++++++++++++++++++----- CLAUDE.md | 4 +++- architecture_explore.md | 6 ++++-- sonar-project.properties | 4 ++++ 6 files changed, 66 insertions(+), 16 deletions(-) create mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..e2f9790 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,14 @@ +# Coverage is measured on Windows and consumed by the SonarQube scanner running +# on Linux, so the report must not carry machine-specific paths. relative_files +# makes coverage emit repo-root-relative names (pybreeze/utils/... rather than an +# absolute plus a package-relative filename), which is what the scanner +# resolves against. +[run] +relative_files = True +source = pybreeze +branch = True + +[report] +exclude_also = + if TYPE_CHECKING: + if __name__ == .__main__.: diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 20d4cb0..15f0f62 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -30,9 +30,17 @@ jobs: - name: Install dev dependencies run: python -m pip install -r dev_requirements.txt - name: Install test tooling - run: python -m pip install pytest hypothesis + run: python -m pip install pytest pytest-cov hypothesis - name: Run unit tests (pytest) - run: python -m pytest test/test_utils/ -v --tb=short + run: python -m pytest test/test_utils/ -v --tb=short --cov=pybreeze --cov-branch --cov-report=xml + - name: Upload coverage for analysis + # One leg is enough; the scanner only consumes a single report. + if: matrix.python-version == '3.12' + uses: actions/upload-artifact@v4 + with: + name: coverage-xml + path: coverage.xml + if-no-files-found: error - name: Run AutomationEditor With Debug Mode run: python ./test/unit_test/start_automation/start_automation_test.py env: @@ -43,19 +51,25 @@ jobs: PYTHONPATH: . sonarcloud: - # Automatic Analysis is off, so branch and pull-request analysis both come - # from here. Skipped on the nightly schedule, where re-scanning an unchanged - # commit adds nothing, and on fork pull requests, which cannot read the token. + # Pull requests only. SonarCloud's plan for this organization exposes results + # for the main branch and for pull requests; an analysis pushed for `dev` + # succeeds but its results are not readable, so scanning every push here + # would spend CI time on numbers nobody can see. Fork pull requests are + # skipped because they cannot read the token. if: >- - github.event_name != 'schedule' && - (github.event_name != 'pull_request' || - github.event.pull_request.head.repo.full_name == github.repository) + github.event_name == 'pull_request' && + github.event.pull_request.head.repo.full_name == github.repository + needs: unit-tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: # Sonar needs the full history to attribute new code to the right commits. fetch-depth: 0 + - name: Download coverage + uses: actions/download-artifact@v4 + with: + name: coverage-xml - name: SonarQube Cloud scan uses: SonarSource/sonarqube-scan-action@v8.2.1 env: diff --git a/.github/workflows/stable.yml b/.github/workflows/stable.yml index 3a64059..00c0997 100644 --- a/.github/workflows/stable.yml +++ b/.github/workflows/stable.yml @@ -30,9 +30,17 @@ jobs: - name: Install dependencies run: python -m pip install -r requirements.txt - name: Install test tooling - run: python -m pip install pytest hypothesis + run: python -m pip install pytest pytest-cov hypothesis - name: Run unit tests (pytest) - run: python -m pytest test/test_utils/ -v --tb=short + run: python -m pytest test/test_utils/ -v --tb=short --cov=pybreeze --cov-branch --cov-report=xml + - name: Upload coverage for analysis + # One leg is enough; the scanner only consumes a single report. + if: matrix.python-version == '3.12' + uses: actions/upload-artifact@v4 + with: + name: coverage-xml + path: coverage.xml + if-no-files-found: error - name: Run AutomationEditor With Debug Mode run: python ./test/unit_test/start_automation/start_automation_test.py env: @@ -43,19 +51,25 @@ jobs: PYTHONPATH: . sonarcloud: - # Automatic Analysis is off, so branch and pull-request analysis both come - # from here. Skipped on the nightly schedule, where re-scanning an unchanged - # commit adds nothing, and on fork pull requests, which cannot read the token. + # Automatic Analysis is off, so main-branch and pull-request analysis both + # come from here. Skipped on the nightly schedule, where re-scanning an + # unchanged commit adds nothing, and on fork pull requests, which cannot + # read the token. if: >- github.event_name != 'schedule' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) + needs: unit-tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: # Sonar needs the full history to attribute new code to the right commits. fetch-depth: 0 + - name: Download coverage + uses: actions/download-artifact@v4 + with: + name: coverage-xml - name: SonarQube Cloud scan uses: SonarSource/sonarqube-scan-action@v8.2.1 env: diff --git a/CLAUDE.md b/CLAUDE.md index fca3f1c..4823b03 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -61,7 +61,9 @@ pybreeze/ - `main`: stable, publishes `pybreeze` · `dev`: development, publishes `pybreeze_dev` - Version config: `pyproject.toml` (stable), `dev.toml` (dev) — keep both in sync when bumping - `unit-tests` job: GitHub Actions on Windows, Python 3.10–3.14 — install deps → pytest `test/test_utils/` → `start_automation_test` → `extend_automation_test` -- `sonarcloud` job: CI-based SonarQube Cloud analysis (`sonar-project.properties`), skipped on the nightly schedule and on fork PRs. Automatic Analysis is off — it only covers main and PRs, so `dev` went unanalysed; the two modes are mutually exclusive, so do not re-enable it +- `sonarcloud` job: CI-based SonarQube Cloud analysis (`sonar-project.properties`), `needs: unit-tests` so it can consume the `coverage-xml` artifact that leg uploads. Automatic Analysis is off and must stay off — the two modes are mutually exclusive and the scanner refuses to run alongside it +- SonarCloud's plan for this organization exposes results for `main` and for pull requests only. An analysis pushed for another branch succeeds but its results read back 403, so `dev.yml` scans on pull requests only; `stable.yml` also scans pushes to `main`. Do not "fix" this by scanning every `dev` push — the numbers are not readable +- Coverage comes from the 3.12 matrix leg (`pytest --cov`), configured by `.coveragerc`. `relative_files = True` is required: the report is produced on Windows and consumed by a Linux scanner, so it must not carry machine-specific paths ## Development diff --git a/architecture_explore.md b/architecture_explore.md index 3e204bd..a5a2d8f 100644 --- a/architecture_explore.md +++ b/architecture_explore.md @@ -398,8 +398,10 @@ extend_ai_gui/ - **單元測試** `test/test_utils/` — 60 個 `test_*.py`。純邏輯 + headless Qt widget 測試(`QT_QPA_PLATFORM=offscreen`)。涵蓋 curl/HAR 解析、SSRF 驗證、SSH 安全、process reader EOF、queue pump、語言對齊、mermaid parser、diagram 序列化、prthinker 設定等。有 hypothesis fuzz 測試(`test_fuzz_pure_logic.py`)。 - **整合測試** `test/unit_test/start_automation/` — 以 `debug_mode=True` 啟動 IDE,10 秒後自動關閉,驗證啟動流程與 extend tab -- **CI** `.github/workflows/{dev,stable}.yml` — `unit-tests` job 跑 Windows runner、Python 3.10–3.14 矩陣;`sonarcloud` job 跑 ubuntu,排程與 fork PR 會跳過。每日 02:00 排程 + push/PR 觸發。`stable.yml` 另有 `publish` job 負責版號遞增與 PyPI 發布 -- **靜態分析** SonarCloud(`sonar-project.properties`,由兩個 workflow 的 `sonarcloud` job 執行 CI-based analysis;Automatic Analysis 已關閉,因為它只看 main 與 PR,`dev` 完全不會被分析)+ Codacy(`.codacy.yml`)+ Bandit(`pyproject.toml` 中排除 test、skip B101/B404) +- **CI** `.github/workflows/{dev,stable}.yml` — `unit-tests` job 跑 Windows runner、Python 3.10–3.14 矩陣,3.12 那一腳額外上傳 `coverage-xml` artifact;`sonarcloud` job 跑 ubuntu、`needs: unit-tests`。每日 02:00 排程 + push/PR 觸發。`stable.yml` 另有 `publish` job 負責版號遞增與 PyPI 發布 +- **覆蓋率** `.coveragerc` — `relative_files = True` 是必要的:報告在 Windows 產生、由 Linux 上的 scanner 讀取,路徑不能帶機器資訊。目前整體 57%(`utils/` 與 `tools_gui` 95–100%,UI 層 20–45% 拉低) +- **靜態分析** SonarCloud(`sonar-project.properties`,CI-based analysis;Automatic Analysis 已關閉且必須維持關閉,兩種模式互斥)+ Codacy(`.codacy.yml`)+ Bandit(`pyproject.toml` 中排除 test、skip B101/B404) +- **SonarCloud 方案限制** 該組織的方案只開放 `main` 與 PR 的分析結果。非 main 分支的分析送得出去、CE 任務也會成功,但結果讀回來是 403(組織內每個專案都只有 `main` 一條分支)。因此 `dev.yml` 只在 PR 時掃描,`stable.yml` 另外掃 push to `main` --- diff --git a/sonar-project.properties b/sonar-project.properties index 7040869..009b45e 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -9,3 +9,7 @@ sonar.organization=integration-automation sonar.sources=pybreeze sonar.tests=test sonar.python.version=3.10, 3.11, 3.12, 3.13, 3.14 + +# Produced by the test matrix and handed to the scanner as an artifact. Without +# it the quality gate scores new code at 0% coverage and fails on that alone. +sonar.python.coverage.reportPaths=coverage.xml