diff --git a/.githooks/pre-push b/.githooks/pre-push index 81a3cea7..740e3b75 100755 --- a/.githooks/pre-push +++ b/.githooks/pre-push @@ -73,30 +73,41 @@ else fi echo "" -# 4. Check test coverage threshold (if FoundationUI sources/tests changed) +# 4. Check test coverage threshold (FoundationUI) echo "4️⃣ Checking test coverage threshold..." -MERGE_BASE=$(git merge-base origin/main HEAD 2>/dev/null || echo "HEAD") -if git diff $MERGE_BASE...HEAD --name-only | grep -qE '^FoundationUI/(Sources|Tests)/'; then - echo " FoundationUI code detected in commits, checking coverage..." - if command -v python3 &> /dev/null; then - COVERAGE_THRESHOLD=${ISOINSPECTOR_MIN_TEST_COVERAGE:-0.67} - - # Run coverage analysis with threshold check - if python3 coverage_analysis.py --threshold "$COVERAGE_THRESHOLD" -v >/dev/null 2>&1; then - echo -e "${GREEN}✅ Test coverage check passed${NC}" - echo " Threshold: $COVERAGE_THRESHOLD (67%)" +COVERAGE_THRESHOLD=${ISOINSPECTOR_MIN_TEST_COVERAGE:-0.67} +COVERAGE_TEST_LOG="$LOG_DIR/foundationui-coverage-test-$(date +%Y%m%d-%H%M%S).log" +COVERAGE_REPORT="$LOG_DIR/foundationui-coverage-report-$(date +%Y%m%d-%H%M%S).txt" + +PLATFORM=$(uname -s) +if [[ "$PLATFORM" != "Darwin" ]]; then + echo -e "${YELLOW}⚠️ FoundationUI coverage requires macOS SwiftUI SDKs; skipping on $PLATFORM${NC}" +else + echo " Running FoundationUI tests with coverage..." + if swift test --package-path FoundationUI --enable-code-coverage 2>&1 | tee "$COVERAGE_TEST_LOG"; then + echo -e "${GREEN}✅ FoundationUI tests with coverage passed${NC}" + echo " Log: $COVERAGE_TEST_LOG" + + if command -v python3 &> /dev/null; then + if python3 coverage_analysis.py --threshold "$COVERAGE_THRESHOLD" --report "$COVERAGE_REPORT" -v; then + echo -e "${GREEN}✅ Test coverage check passed${NC}" + echo " Threshold: $COVERAGE_THRESHOLD (67%)" + echo " Report: $COVERAGE_REPORT" + else + echo -e "${RED}❌ Test coverage below threshold${NC}" + echo " Threshold: $COVERAGE_THRESHOLD (67%)" + echo " Report: $COVERAGE_REPORT" + echo " For guidance, see Documentation/ISOInspector.docc/Guides/TestingAndCoverage.md" + FAILED=$((FAILED + 1)) + fi else - echo -e "${RED}❌ Test coverage below threshold${NC}" - echo " Run: python3 coverage_analysis.py --verbose" - echo " For more details on how to improve test coverage, see:" - echo " Documentation/ISOInspector.docc/Guides/TestingAndCoverage.md" - FAILED=$((FAILED + 1)) + echo -e "${YELLOW}⚠️ Python3 not available, skipping coverage check${NC}" fi else - echo -e "${YELLOW}⚠️ Python3 not available, skipping coverage check${NC}" + echo -e "${RED}❌ FoundationUI tests with coverage failed${NC}" + echo " Log: $COVERAGE_TEST_LOG" + FAILED=$((FAILED + 1)) fi -else - echo " No FoundationUI code changes detected, skipping coverage check" fi echo "" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f733a42..6edcb965 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,7 @@ on: paths: - 'Sources/**' - 'Tests/**' + - 'FoundationUI/**' - 'scripts/**' - 'Package.swift' - 'Package.resolved' @@ -21,6 +22,7 @@ on: paths: - 'Sources/**' - 'Tests/**' + - 'FoundationUI/**' - 'scripts/**' - 'Package.swift' - 'Package.resolved' @@ -181,6 +183,40 @@ jobs: if-no-files-found: error retention-days: 14 + coverage-gate: + name: Coverage Gate (FoundationUI) + runs-on: macos-14 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Swift + uses: SwiftyLab/setup-swift@v1 + with: + swift-version: '6.0' + + - name: Create log directory + run: mkdir -p Documentation/Quality + + - name: Run FoundationUI tests with coverage + run: swift test --package-path FoundationUI --enable-code-coverage 2>&1 | tee Documentation/Quality/foundationui-coverage-test.log + + - name: Enforce coverage threshold (67%) + run: | + python3 coverage_analysis.py --threshold 0.67 --report Documentation/Quality/foundationui-coverage-report.txt -v + echo "Coverage report written to Documentation/Quality/foundationui-coverage-report.txt" + + - name: Upload coverage artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: foundationui-coverage + path: | + Documentation/Quality/foundationui-coverage-test.log + Documentation/Quality/foundationui-coverage-report.txt + if-no-files-found: error + retention-days: 14 + docc-archives: name: Generate DocC Archives runs-on: ubuntu-22.04 diff --git a/DOCS/AI/ISOInspector_Execution_Guide/04_TODO_Workplan.md b/DOCS/AI/ISOInspector_Execution_Guide/04_TODO_Workplan.md index 903542b0..73182d6e 100644 --- a/DOCS/AI/ISOInspector_Execution_Guide/04_TODO_Workplan.md +++ b/DOCS/AI/ISOInspector_Execution_Guide/04_TODO_Workplan.md @@ -10,12 +10,12 @@ The following plan decomposes delivery into dependency-aware phases. Each task i | A3 | Set up DocC catalog and documentation publishing workflow. | Medium | 1 | A1 | DocC, SwiftPM | `docc` build succeeds; docs published artifact accessible. (Completed ✅ — generates archives via `scripts/generate_documentation.sh`, DocC catalogs live under `Sources/*/*.docc`, tutorials expanded in `DOCS/TASK_ARCHIVE/35_A3_DocC_Tutorial_Expansion/`, and CI publishing now delivered by the TODO #12-backed `docc-archives` job.) | | A6 | Enforce SwiftFormat-based formatting locally and in CI. | Medium | 0.5 | A2 | swift-format, GitHub Actions | `.pre-commit-config.yaml` runs `swift format --in-place` on staged Swift files; CI step executes `swift format --mode lint` and fails on diff. Documentation updated in `README.md` tooling section. (Completed ✅ — archived in `DOCS/TASK_ARCHIVE/226_A6_Enforce_SwiftFormat_Formatting/`.) | | A7 | Reinstate SwiftLint complexity thresholds across targets. | Medium | 0.75 | A2 | SwiftLint | `.swiftlint.yml` restores `cyclomatic_complexity`, `function_body_length`, `nesting`, and `type_body_length` with agreed limits; pre-commit runs `swiftlint lint --strict`; CI publishes analyzer report artifact. *(Completed ✅ — see `DOCS/INPROGRESS/Summary_of_Work.md`.)* | -| A8 | Gate test coverage using `coverage_analysis.py`. | Medium | 1 | A2 | Python, SwiftPM | `coverage_analysis.py --threshold 0.67` executes in pre-push and GitHub Actions after `swift test --enable-code-coverage`; pushes blocked and workflow fails when ratio drops. Coverage report archived under `Documentation/Quality/` per run. | +| A8 | Gate test coverage using `coverage_analysis.py`. | Medium | 1 | A2 | Python, SwiftPM | `coverage_analysis.py --threshold 0.67` executes in pre-push and GitHub Actions after `swift test --enable-code-coverage`; pushes blocked and workflow fails when ratio drops. Coverage report archived under `Documentation/Quality/` per run. *(Completed ✅ — enforced via pre-push gate and CI `coverage-gate` job with artifacts stored under `Documentation/Quality/`.)* | | A9 | Automate strict concurrency checks for core and tests. | High | 1 | A2 | SwiftPM, GitHub Actions | Pre-push hook and CI workflow run `swift build --strict-concurrency=complete` and `swift test --strict-concurrency=complete`; logs show zero warnings. Results linked to `PRD_SwiftStrictConcurrency_Store.md` rollout checklist. (Completed ✅ — archived in `DOCS/TASK_ARCHIVE/225_A9_Swift6_Concurrency_Cleanup/`; includes post-A9 Swift 6 migration cleanup that removed redundant StrictConcurrency flags and aligned CI to Swift 6.0/Xcode 16.2.) | | A10 | Add Swift duplication detection to CI. | Medium | 1 | A2 | GitHub Actions, Node, `jscpd` | `.github/workflows/swift-duplication.yml` runs `scripts/run_swift_duplication_check.sh` (wrapper for `npx jscpd@3.5.10`) on Swift sources for every PR/push. Workflow fails when duplicated lines exceed 1% or any block >45 lines repeats; artifact uploads console report. Plan + scope: `DOCS/AI/github-workflows/02_swift_duplication_guard/prd.md`. | | A11 | Enable local CI execution on macOS. | Medium | 1.5 | A2 | Bash, Docker (optional) | Scripts in `scripts/local-ci/` replicate GitHub Actions workflows locally, supporting lint, build, test, and coverage jobs. Native and Docker execution modes available. Documentation in `scripts/local-ci/README.md` covers setup, usage, and troubleshooting. *(Completed ✅ — Phase 1 delivered in `DOCS/AI/github-workflows/04_local_ci_macos/`; see `Summary.md` for deliverables and coverage matrix.)* | -> **Current focus:** _BUG #001 Design System Color Token Migration_ archived to `DOCS/TASK_ARCHIVE/227_Bug001_Design_System_Color_Token_Migration/` (2025-11-16). ISOInspectorApp continues to use hardcoded `.accentColor` and manual opacity values in 6 view files instead of FoundationUI design tokens. Blocking FoundationUI Phase 5.2 completion. See archive for full analysis and blockers. Next candidate tasks in automation track: A7 (SwiftLint complexity), A8 (test coverage gate), A10 (duplication detection). Refer to `DOCS/INPROGRESS/next_tasks.md` and `DOCS/INPROGRESS/blocked.md` for day-to-day queue and active blockers. +> **Current focus:** _BUG #001 Design System Color Token Migration_ archived to `DOCS/TASK_ARCHIVE/227_Bug001_Design_System_Color_Token_Migration/` (2025-11-16). ISOInspectorApp continues to use hardcoded `.accentColor` and manual opacity values in 6 view files instead of FoundationUI design tokens. Blocking FoundationUI Phase 5.2 completion. See archive for full analysis and blockers. Next candidate task in automation track: A10 (duplication detection), following completion of A7 (SwiftLint complexity) and A8 (coverage gate). Refer to `DOCS/INPROGRESS/next_tasks.md` and `DOCS/INPROGRESS/blocked.md` for day-to-day queue and active blockers. > > **Bug resolved (2025-11-25):** Bug #235 — Smoke tests blocked by Sendable violations in `WindowSessionController` under strict concurrency. Fixed via sendable annotations + document loading refactor; see `DOCS/INPROGRESS/235_Sendable_SmokeTest_Build_Failure.md` for details and test evidence. > diff --git a/DOCS/INPROGRESS/A8_Test_Coverage_Gate.md b/DOCS/INPROGRESS/A8_Test_Coverage_Gate.md index fa13d9c2..8d144baa 100644 --- a/DOCS/INPROGRESS/A8_Test_Coverage_Gate.md +++ b/DOCS/INPROGRESS/A8_Test_Coverage_Gate.md @@ -26,3 +26,9 @@ Add automated coverage enforcement so pushes and CI runs fail when overall Swift - [`ISOInspector_PRD_TODO.md`](../AI/ISOViewer/ISOInspector_PRD_TODO.md) - [`DOCS/RULES`](../RULES) - Relevant archives in [`DOCS/TASK_ARCHIVE`](../TASK_ARCHIVE) + +## ✅ Resolution Notes — 2025-12-12 + +- **Pre-push enforcement:** `.githooks/pre-push` now runs `swift test --package-path FoundationUI --enable-code-coverage` followed by `coverage_analysis.py --threshold 0.67` (reporting to `Documentation/Quality/`). Pushes fail if either the coverage test run or threshold check fails. Threshold respects `ISOINSPECTOR_MIN_TEST_COVERAGE` when set. +- **CI enforcement:** `.github/workflows/ci.yml` adds a macOS `coverage-gate` job that executes the same FoundationUI coverage test run, invokes the coverage analysis with a 0.67 threshold, and uploads logs/reports from `Documentation/Quality/` as CI artifacts. +- **Artifacts:** Coverage logs and reports are stored under `Documentation/Quality/` for both local hooks and CI, providing a consistent audit trail for regressions. diff --git a/DOCS/INPROGRESS/Summary_of_Work.md b/DOCS/INPROGRESS/Summary_of_Work.md index a06c83b4..50c2c392 100644 --- a/DOCS/INPROGRESS/Summary_of_Work.md +++ b/DOCS/INPROGRESS/Summary_of_Work.md @@ -1,3 +1,18 @@ +## Summary of Work — 2025-12-12 + +### Completed Tasks +- ✅ **Task A8 — Test Coverage Gate** + +### Implementation Highlights +- Added macOS-only FoundationUI coverage enforcement to `.githooks/pre-push`, running `swift test --enable-code-coverage` followed by `coverage_analysis.py --threshold 0.67` with reports under `Documentation/Quality/`. +- Introduced a macOS `coverage-gate` job in `.github/workflows/ci.yml` that mirrors the pre-push coverage gate and uploads coverage logs/reports as CI artifacts. +- Updated task trackers (`todo.md`, `DOCS/AI/ISOInspector_Execution_Guide/04_TODO_Workplan.md`, `DOCS/INPROGRESS/next_tasks.md`, and `DOCS/INPROGRESS/A8_Test_Coverage_Gate.md`) to record the completed coverage gate rollout and artifact locations. + +### Verification +- ⚠️ `swift test --package-path FoundationUI --enable-code-coverage` (fails on Linux due to missing SwiftUI SDK; coverage gate runs on macOS runners in CI and on macOS developer machines.) + +--- + ## Summary of Work — 2025-11-28 ### Completed Tasks diff --git a/DOCS/INPROGRESS/next_tasks.md b/DOCS/INPROGRESS/next_tasks.md index 742f2a73..4b0d0f9b 100644 --- a/DOCS/INPROGRESS/next_tasks.md +++ b/DOCS/INPROGRESS/next_tasks.md @@ -21,10 +21,10 @@ _Last updated: 2025-11-19 (UTC). Maintainers should update this file whenever ta ## 1. Automation & Quality Gates -1. **Task A8 – Test Coverage Gate** _(In Progress — `DOCS/INPROGRESS/A8_Test_Coverage_Gate.md`)_ - - Wire `coverage_analysis.py --threshold 0.67` into `.githooks/pre-push` and `.github/workflows/ci.yml` immediately after `swift test --enable-code-coverage`. - - Publish the HTML or JSON coverage artifacts under `Documentation/Quality/` so regressions have concrete data. - - Update `todo.md` and `DOCS/AI/ISOInspector_Execution_Guide/04_TODO_Workplan.md` once the hook and CI gate are enforced. +1. **Task A8 – Test Coverage Gate** ✅ _(Completed — `DOCS/INPROGRESS/A8_Test_Coverage_Gate.md`)_ + - `coverage_analysis.py --threshold 0.67` now runs in `.githooks/pre-push` after `swift test --enable-code-coverage` (macOS-only due to SwiftUI dependency) and blocks pushes on coverage failures. + - CI `coverage-gate` job executes the same workflow on macOS runners and publishes logs/reports under `Documentation/Quality/`. + - `todo.md` and the Execution Workplan have been updated to reflect the enforced gate and artifact locations. 2. **Task A10 – Swift Duplication Detection** _(Ready)_ - Add `.github/workflows/swift-duplication.yml` that runs `scripts/run_swift_duplication_check.sh` (wrapper around `npx jscpd@3.5.10`). diff --git a/todo.md b/todo.md index d99d020d..b00ee84f 100644 --- a/todo.md +++ b/todo.md @@ -12,7 +12,7 @@ - [x] #A7 Refactor DocumentSessionController to comply with type_body_length threshold — Extracted 7 services: BookmarkService, RecentsService, ParseCoordinationService, SessionPersistenceService, ValidationConfigurationService, ExportService, DocumentOpeningCoordinator. Reduced from 1652 lines to 347 lines (82% reduction). Removed swiftlint:disable directive. (Sources/ISOInspectorApp/State/DocumentSessionController.swift, Sources/ISOInspectorApp/State/Services/) _(Completed 2025-11-28.)_ - [x] #A7 Enable strict mode for main project after refactoring large files — CI and local hooks now run `swiftlint lint --strict` with JSON artifacts published for every run. (`.github/workflows/swiftlint.yml`, `.swiftlint.yml`, `.githooks/pre-commit`) -- [ ] Promote `coverage_analysis.py` to a shared quality gate by wiring it into `.githooks/pre-push` and `.github/workflows/ci.yml` after `swift test --enable-code-coverage`. (Scripts: `.githooks/pre-push`, `coverage_analysis.py`, `.github/workflows/ci.yml`) +- [x] Promote `coverage_analysis.py` to a shared quality gate by wiring it into `.githooks/pre-push` and `.github/workflows/ci.yml` after `swift test --enable-code-coverage`. (Scripts: `.githooks/pre-push`, `coverage_analysis.py`, `.github/workflows/ci.yml`) _(Completed 2025-12-12 — FoundationUI coverage run + threshold enforced locally/CI with artifacts under Documentation/Quality/.)_ - [ ] Add DocC + `missing_docs` enforcement to the lint pipeline so public APIs fail CI without documentation coverage, and capture the suppression playbook in `Documentation/ISOInspector.docc/Guides/DocumentationStyle.md`. (Config: `.swiftlint.yml`, `.github/workflows/documentation.yml`) - [x] Extend `.githooks/pre-push` and `.github/workflows/ci.yml` with `swift build --strict-concurrency=complete`/`swift test --strict-concurrency=complete` runs, publishing logs referenced from `DOCS/AI/PRD_SwiftStrictConcurrency_Store.md`. (Scripts: `.githooks/pre-push`, `.github/workflows/ci.yml`) _(Completed 2025-11-15 — Task A9, archived at `DOCS/TASK_ARCHIVE/225_A9_Swift6_Concurrency_Cleanup/`)_ - [ ] Add `.github/workflows/swift-duplication.yml` that runs `scripts/run_swift_duplication_check.sh` (wrapper around `npx jscpd@3.5.10`) on all Swift targets, fails when duplicates exceed 1% or blocks >45 lines repeat, and uploads a console artifact. (Docs: `DOCS/AI/github-workflows/02_swift_duplication_guard/prd.md` + `TODO.md`)