From b00072474b2a9ad13adfca690afb7047b91fcbb8 Mon Sep 17 00:00:00 2001 From: Mike Kell Date: Fri, 22 May 2026 10:09:42 -0400 Subject: [PATCH] feat(ci): add Flutter CI/CD pipeline for Forgejo Actions (Stage 4C) Add Forgejo Actions workflows for automated Flutter validation on PRs: - flutter-analyze.yml: runs dart analyze --fatal-infos on all 8 packages/apps - flutter-test.yml: runs flutter test per package with pass/fail reporting - Aggregate test result summary table in workflow output - Workflows trigger on PRs to main and all non-main branch pushes - Uses ghcr.io/cirruslabs/flutter:stable container image Populate tools/ directory with CI helper scripts: - run_all_tests.sh: local test runner with optional --analyze flag - README.md: documents scripts and CI workflow inventory Validated locally: - dart analyze: all 8 packages/apps clean (no issues) - core: 20/20 tests passed - design_system: 41/41 tests passed - feature_wordpress: 294/294 tests passed - kell_web: 24/24 tests passed - Total: 379/379 tests passed --- .forgejo/workflows/flutter-analyze.yml | 77 +++++++++++ .forgejo/workflows/flutter-test.yml | 127 ++++++++++++++++++ kell_creations_apps/tools/README.md | 44 ++++++ kell_creations_apps/tools/run_all_tests.sh | 147 +++++++++++++++++++++ 4 files changed, 395 insertions(+) create mode 100644 .forgejo/workflows/flutter-analyze.yml create mode 100644 .forgejo/workflows/flutter-test.yml create mode 100644 kell_creations_apps/tools/README.md create mode 100644 kell_creations_apps/tools/run_all_tests.sh diff --git a/.forgejo/workflows/flutter-analyze.yml b/.forgejo/workflows/flutter-analyze.yml new file mode 100644 index 0000000..b57f62d --- /dev/null +++ b/.forgejo/workflows/flutter-analyze.yml @@ -0,0 +1,77 @@ +name: Flutter Analyze + +on: + pull_request: + branches: + - main + push: + branches: + - "**" + - "!main" + +jobs: + analyze: + name: Dart Analyze + runs-on: ubuntu-latest + container: + image: ghcr.io/cirruslabs/flutter:stable + + defaults: + run: + working-directory: kell_creations_apps + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install dependencies — core + run: cd packages/core && flutter pub get + + - name: Install dependencies — design_system + run: cd packages/design_system && flutter pub get + + - name: Install dependencies — feature_wordpress + run: cd packages/feature_wordpress && flutter pub get + + - name: Install dependencies — feature_inventory + run: cd packages/feature_inventory && flutter pub get + + - name: Install dependencies — feature_orders + run: cd packages/feature_orders && flutter pub get + + - name: Install dependencies — feature_policy + run: cd packages/feature_policy && flutter pub get + + - name: Install dependencies — kell_web + run: cd apps/kell_web && flutter pub get + + - name: Install dependencies — kell_mobile + run: cd apps/kell_mobile && flutter pub get + + - name: Analyze — core + run: cd packages/core && dart analyze --fatal-infos + + - name: Analyze — design_system + run: cd packages/design_system && dart analyze --fatal-infos + + - name: Analyze — feature_wordpress + run: cd packages/feature_wordpress && dart analyze --fatal-infos + + - name: Analyze — feature_inventory + run: cd packages/feature_inventory && dart analyze --fatal-infos + + - name: Analyze — feature_orders + run: cd packages/feature_orders && dart analyze --fatal-infos + + - name: Analyze — feature_policy + run: cd packages/feature_policy && dart analyze --fatal-infos + + - name: Analyze — kell_web + run: cd apps/kell_web && dart analyze --fatal-infos + + - name: Analyze — kell_mobile + run: cd apps/kell_mobile && dart analyze --fatal-infos + + - name: Summary + if: always() + run: echo "✅ Dart analyze completed for all packages and apps" diff --git a/.forgejo/workflows/flutter-test.yml b/.forgejo/workflows/flutter-test.yml new file mode 100644 index 0000000..ab31137 --- /dev/null +++ b/.forgejo/workflows/flutter-test.yml @@ -0,0 +1,127 @@ +name: Flutter Test + +on: + pull_request: + branches: + - main + push: + branches: + - "**" + - "!main" + +jobs: + test: + name: Flutter Tests + runs-on: ubuntu-latest + container: + image: ghcr.io/cirruslabs/flutter:stable + + defaults: + run: + working-directory: kell_creations_apps + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install dependencies — core + run: cd packages/core && flutter pub get + + - name: Install dependencies — design_system + run: cd packages/design_system && flutter pub get + + - name: Install dependencies — feature_wordpress + run: cd packages/feature_wordpress && flutter pub get + + - name: Install dependencies — kell_web + run: cd apps/kell_web && flutter pub get + + - name: Test — core + run: | + cd packages/core + flutter test --reporter expanded 2>&1 | tee test_output.txt + echo "" + echo "=== core test summary ===" + TOTAL=$(grep -cE '^\s*✓' test_output.txt || echo "0") + FAILED=$(grep -cE '^\s*✗' test_output.txt || echo "0") + echo " Passed: $TOTAL" + echo " Failed: $FAILED" + # Fail the step if any tests failed + if [ "$FAILED" -gt 0 ]; then exit 1; fi + + - name: Test — design_system + run: | + cd packages/design_system + flutter test --reporter expanded 2>&1 | tee test_output.txt + echo "" + echo "=== design_system test summary ===" + TOTAL=$(grep -cE '^\s*✓' test_output.txt || echo "0") + FAILED=$(grep -cE '^\s*✗' test_output.txt || echo "0") + echo " Passed: $TOTAL" + echo " Failed: $FAILED" + if [ "$FAILED" -gt 0 ]; then exit 1; fi + + - name: Test — feature_wordpress + run: | + cd packages/feature_wordpress + flutter test --reporter expanded 2>&1 | tee test_output.txt + echo "" + echo "=== feature_wordpress test summary ===" + TOTAL=$(grep -cE '^\s*✓' test_output.txt || echo "0") + FAILED=$(grep -cE '^\s*✗' test_output.txt || echo "0") + echo " Passed: $TOTAL" + echo " Failed: $FAILED" + if [ "$FAILED" -gt 0 ]; then exit 1; fi + + - name: Test — kell_web + run: | + cd apps/kell_web + flutter test --reporter expanded 2>&1 | tee test_output.txt + echo "" + echo "=== kell_web test summary ===" + TOTAL=$(grep -cE '^\s*✓' test_output.txt || echo "0") + FAILED=$(grep -cE '^\s*✗' test_output.txt || echo "0") + echo " Passed: $TOTAL" + echo " Failed: $FAILED" + if [ "$FAILED" -gt 0 ]; then exit 1; fi + + - name: Aggregate test report + if: always() + run: | + echo "" + echo "╔══════════════════════════════════════╗" + echo "║ Flutter Test Results Summary ║" + echo "╠══════════════════════════════════════╣" + echo "║ Package Pass Fail ║" + echo "╠══════════════════════════════════════╣" + + TOTAL_PASS=0 + TOTAL_FAIL=0 + + for pkg in packages/core packages/design_system packages/feature_wordpress apps/kell_web; do + NAME=$(basename "$pkg") + OUTPUT="$pkg/test_output.txt" + if [ -f "$OUTPUT" ]; then + PASS=$(grep -cE '^\s*✓' "$OUTPUT" || echo "0") + FAIL=$(grep -cE '^\s*✗' "$OUTPUT" || echo "0") + else + PASS="—" + FAIL="—" + fi + printf "║ %-20s %-7s %-7s ║\n" "$NAME" "$PASS" "$FAIL" + if [ "$PASS" != "—" ]; then TOTAL_PASS=$((TOTAL_PASS + PASS)); fi + if [ "$FAIL" != "—" ]; then TOTAL_FAIL=$((TOTAL_FAIL + FAIL)); fi + done + + echo "╠══════════════════════════════════════╣" + printf "║ %-20s %-7s %-7s ║\n" "TOTAL" "$TOTAL_PASS" "$TOTAL_FAIL" + echo "╚══════════════════════════════════════╝" + + if [ "$TOTAL_FAIL" -gt 0 ]; then + echo "" + echo "❌ Some tests failed. See individual package results above." + exit 1 + else + echo "" + echo "✅ All $TOTAL_PASS tests passed across all packages." + fi diff --git a/kell_creations_apps/tools/README.md b/kell_creations_apps/tools/README.md new file mode 100644 index 0000000..f8a216d --- /dev/null +++ b/kell_creations_apps/tools/README.md @@ -0,0 +1,44 @@ +# Tools + +CI/CD helper scripts for the Kell Creations Flutter monorepo. + +## Scripts + +### `run_all_tests.sh` + +Runs `flutter test` across all testable packages and apps, producing a per-package pass/fail summary. + +**Usage:** + +```bash +# From kell_creations_apps/ directory +./tools/run_all_tests.sh # Run tests only +./tools/run_all_tests.sh --analyze # Run dart analyze + tests +``` + +**What it does:** + +1. Installs dependencies (`flutter pub get`) for all packages and apps. +2. Optionally runs `dart analyze --fatal-infos` on each package/app. +3. Runs `flutter test --reporter expanded` for packages with tests. +4. Prints an aggregate pass/fail summary table. + +**Adding new packages:** + +When a new package gains tests, add its path to the `TESTABLE` array in the script. For packages that should be analyzed but have no tests yet, add to the `ANALYZABLE` array only. + +**Exit codes:** + +- `0` — all tests passed (and analyze clean, if `--analyze` was used) +- `1` — one or more failures detected + +## CI Workflows + +The corresponding Forgejo Actions workflows live in `.forgejo/workflows/`: + +| Workflow | Trigger | Purpose | +| --------------------- | ----------------- | -------------------------------------------- | +| `flutter-analyze.yml` | PRs and branches | Runs `dart analyze` on all packages and apps | +| `flutter-test.yml` | PRs and branches | Runs `flutter test` with result reporting | +| `validate-docs.yml` | Non-main branches | Validates MkDocs documentation build | +| `publish-docs.yml` | Push to main | Publishes documentation to docs host | diff --git a/kell_creations_apps/tools/run_all_tests.sh b/kell_creations_apps/tools/run_all_tests.sh new file mode 100644 index 0000000..0c7206b --- /dev/null +++ b/kell_creations_apps/tools/run_all_tests.sh @@ -0,0 +1,147 @@ +#!/usr/bin/env bash +# ────────────────────────────────────────────────────────────────────── +# run_all_tests.sh — Run flutter test for all testable packages and apps +# +# Usage: +# ./tools/run_all_tests.sh # Run from kell_creations_apps/ +# ./tools/run_all_tests.sh --analyze # Also run dart analyze first +# +# Exit codes: +# 0 — all tests passed (and analyze clean, if requested) +# 1 — one or more failures +# ────────────────────────────────────────────────────────────────────── +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" + +# Packages/apps with tests (add new ones here as they gain tests) +TESTABLE=( + packages/core + packages/design_system + packages/feature_wordpress + apps/kell_web +) + +# All packages/apps to analyze (includes those without tests) +ANALYZABLE=( + packages/core + packages/design_system + packages/feature_wordpress + packages/feature_inventory + packages/feature_orders + packages/feature_policy + apps/kell_web + apps/kell_mobile +) + +RUN_ANALYZE=false +if [[ "${1:-}" == "--analyze" ]]; then + RUN_ANALYZE=true +fi + +OVERALL_EXIT=0 + +# ── Dependency install ─────────────────────────────────────────────── +echo "" +echo "══════════════════════════════════════" +echo " Installing dependencies" +echo "══════════════════════════════════════" + +for pkg in "${ANALYZABLE[@]}"; do + echo " → $pkg" + (cd "$ROOT_DIR/$pkg" && flutter pub get --no-example) > /dev/null 2>&1 +done + +# ── Analyze (optional) ────────────────────────────────────────────── +if $RUN_ANALYZE; then + echo "" + echo "══════════════════════════════════════" + echo " Running dart analyze" + echo "══════════════════════════════════════" + + ANALYZE_FAILURES=() + for pkg in "${ANALYZABLE[@]}"; do + NAME=$(basename "$pkg") + printf " %-25s" "$NAME" + if (cd "$ROOT_DIR/$pkg" && dart analyze --fatal-infos) > /dev/null 2>&1; then + echo "✅ clean" + else + echo "❌ issues found" + ANALYZE_FAILURES+=("$NAME") + OVERALL_EXIT=1 + fi + done + + if [ ${#ANALYZE_FAILURES[@]} -gt 0 ]; then + echo "" + echo " ❌ Analyze failures: ${ANALYZE_FAILURES[*]}" + else + echo "" + echo " ✅ All packages analyze clean" + fi +fi + +# ── Tests ──────────────────────────────────────────────────────────── +echo "" +echo "══════════════════════════════════════" +echo " Running flutter test" +echo "══════════════════════════════════════" + +declare -A RESULTS_PASS +declare -A RESULTS_FAIL +TEST_FAILURES=() + +for pkg in "${TESTABLE[@]}"; do + NAME=$(basename "$pkg") + echo "" + echo " ── $NAME ──" + + TMPFILE=$(mktemp) + if (cd "$ROOT_DIR/$pkg" && flutter test --reporter expanded 2>&1) | tee "$TMPFILE"; then + : # tests passed + else + TEST_FAILURES+=("$NAME") + OVERALL_EXIT=1 + fi + + PASS=$(grep -cE '^\s*✓' "$TMPFILE" 2>/dev/null || echo "0") + FAIL=$(grep -cE '^\s*✗' "$TMPFILE" 2>/dev/null || echo "0") + RESULTS_PASS[$NAME]=$PASS + RESULTS_FAIL[$NAME]=$FAIL + rm -f "$TMPFILE" +done + +# ── Summary ────────────────────────────────────────────────────────── +echo "" +echo "╔══════════════════════════════════════╗" +echo "║ Flutter Test Results Summary ║" +echo "╠══════════════════════════════════════╣" +echo "║ Package Pass Fail ║" +echo "╠══════════════════════════════════════╣" + +TOTAL_PASS=0 +TOTAL_FAIL=0 + +for pkg in "${TESTABLE[@]}"; do + NAME=$(basename "$pkg") + P=${RESULTS_PASS[$NAME]:-0} + F=${RESULTS_FAIL[$NAME]:-0} + printf "║ %-20s %-7s %-7s ║\n" "$NAME" "$P" "$F" + TOTAL_PASS=$((TOTAL_PASS + P)) + TOTAL_FAIL=$((TOTAL_FAIL + F)) +done + +echo "╠══════════════════════════════════════╣" +printf "║ %-20s %-7s %-7s ║\n" "TOTAL" "$TOTAL_PASS" "$TOTAL_FAIL" +echo "╚══════════════════════════════════════╝" + +if [ $OVERALL_EXIT -ne 0 ]; then + echo "" + echo "❌ Failures detected. See details above." +else + echo "" + echo "✅ All $TOTAL_PASS tests passed across all packages." +fi + +exit $OVERALL_EXIT