# CI for shopdb-flask on GitHub Actions. # # Mirrors the internal CI pipeline. Jobs on push + pull_request: # backend - pytest (SQLite via TestingConfig, no DB service needed) # naming - the CONTRIBUTING.md naming/style gate # gates - proves those checks actually RAN rather than skipping # frontend - vitest + Vue build # lean-build - ADR-013: a per-site build carries only its plugins # migrations-mysql - the REAL multi-site deploy path: fresh flask db upgrade # + every plugin's chain on utf8mb4 MySQL 8, idempotent on # a second run. The pytest suite only exercises SQLite # create_all(), so this is what catches an Alembic # regression on MySQL before it ships. name: CI # Action versions are the Node 24 native releases (checkout@v5, setup-node@v5, # setup-python@v6). The v4/v5 generation targets Node 20, which the runners now # force onto Node 24 with a deprecation warning on every job - working today, # a hard failure whenever GitHub drops the shim. # # Jobs run on the org's self-hosted "arc-runner-set" (enterprise # ge-aerospace-runner-group, Linux). GitHub-hosted runners are blocked by the # org IP allow list (hosted Azure runner IPs are not allow-listed -> checkout # 403), so ubuntu-latest cannot be used here. arc-runner-set checks out from an # internal allow-listed IP and, being Linux, still supports service containers. on: push: pull_request: # A second push supersedes the first: the older run answers a question nobody is # asking any more, and it holds a self-hosted runner while doing it. concurrency: group: ci-${{ github.ref }} cancel-in-progress: true jobs: backend: runs-on: arc-runner-set steps: - uses: actions/checkout@v5 - uses: actions/setup-python@v6 with: python-version: '3.14' cache: pip - run: pip install -r requirements-dev.txt - run: python -m pytest -q naming: runs-on: arc-runner-set steps: - uses: actions/checkout@v5 - run: bash scripts/check-naming-and-style.sh gates: # Prove the gates RAN. Several skip themselves when the file they read is # absent, which is correct in this checkout (docs/ becomes the wiki) and was # silently wrong here for months: the modules skipped, CI went green, and an # outside branch added nine routes documented nowhere and passed. # # A gate that stops running is worse than no gate, because nobody looks at # it again. runs-on: arc-runner-set steps: - uses: actions/checkout@v5 - uses: actions/setup-python@v6 with: python-version: '3.14' cache: pip - run: pip install -r requirements-dev.txt - run: bash scripts/check-gates-ran.sh frontend: runs-on: arc-runner-set defaults: run: working-directory: frontend steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v5 with: node-version: '20' cache: npm cache-dependency-path: frontend/package-lock.json - run: npm ci - run: npx vitest run - run: npm run build agent: # Semantic checks on the endpoint agent's pure logic. Until this existed the # agent had no tests at all, so a change to what an endpoint watches - or to # the guard that decides which paths it will execute - was reviewed by # reading alone. # # The project targets net8.0 and links the platform-pure sources rather than # referencing ShopDbEndpointAgent.Core, which is net8.0-windows and cannot # run here. See the csproj header for why, and for what that trades away. # Runs in well under a second; it does not meaningfully add to gate time. runs-on: arc-runner-set steps: - uses: actions/checkout@v5 - uses: actions/setup-dotnet@v4 with: dotnet-version: '8.0.x' - run: dotnet test agent/ShopDbEndpointAgent.Core.Tests/ShopDbEndpointAgent.Core.Tests.csproj --nologo lean-build: # ADR-013 Phase 5: prove a per-site build carries only its chosen plugins. # The profile is the WJ plugin set, so this job proves the build this branch # actually ships, not a two-plugin toy. The omission guarantee is what is # under test, so the assertions below name a component from EVERY omitted # plugin: a set that grows without its check growing is how a leak ships. # # Chosen (12): backups computers endpoints guides knowledgebase machines # network notifications printers slides tools warranty # Omitted (5): employees geenforce measuringtools printedparts usb # 'applications' is manifest-less core and ships in every build (ADR-013). # endpoints hard-depends on computers, which is already chosen, so the # closure adds nothing - if that changes, resolve_plugin_closure.py pulls # the dependency in and the absence assertions below start failing, which is # the signal to update this list rather than to loosen the check. runs-on: arc-runner-set steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v5 with: node-version: '20' cache: npm cache-dependency-path: frontend/package-lock.json - run: cd frontend && npm ci - name: Build lean site (WJ plugin set) run: | printf '%s' '{ "site": "ci-lean", "plugins": ["backups", "computers", "endpoints", "guides", "knowledgebase", "machines", "network", "notifications", "printers", "slides", "tools", "warranty"] }' \ > /tmp/lean-profile.json bash scripts/build-site.sh /tmp/lean-profile.json /tmp/leansite - name: Assert omitted plugin code is absent, chosen present run: | assets=/tmp/leansite/frontend-dist/assets # One component per OMITTED plugin: employees, geenforce, # measuringtools, printedparts, usb. for code in EmployeeDirectory ManifestEditor MeasuringToolsList PartsKiosk USBLabelBatch; do if grep -rqoh "$code" "$assets"/*.js; then echo "FAIL: omitted-plugin code '$code' leaked into the lean bundle" exit 1 fi done # One component per CHOSEN plugin, so a plugin silently dropped from # the bundle fails here instead of on the floor. for code in BackupHistory PCsList EndpointsList GuidesList \ KnowledgeBaseDetail MachineDetail NetworkDevicesList \ NotificationsList PrinterDetail SlideManager ToolsIndex \ WarrantiesList; do grep -rqoh "$code" "$assets"/*.js || { echo "FAIL: chosen-plugin code '$code' missing from the lean bundle" exit 1; } done # Core frontends (no manifest, e.g. applications) must ship in EVERY # build regardless of SITE_PLUGINS, or a lean site loses a core page. grep -rqoh "ApplicationsList" "$assets"/*.js || { echo "FAIL: core page 'ApplicationsList' missing from the lean bundle" exit 1; } for plugin in backups computers endpoints guides knowledgebase \ machines network notifications printers slides tools \ warranty; do test -d "/tmp/leansite/plugins/$plugin" || { echo "FAIL: chosen plugin '$plugin' missing from the backend tree" exit 1; } done for plugin in employees geenforce measuringtools printedparts usb; do test ! -d "/tmp/leansite/plugins/$plugin" || { echo "FAIL: omitted plugin '$plugin' staged into the backend tree" exit 1; } done echo "lean build verified: only chosen plugins present" # NOTE: the MySQL-8 migration/seed job (fresh `flask db upgrade` + every # plugin chain + strict-mode seeders on a real MySQL 8) runs on the internal # CI server, which supports service containers. The org's arc-runner-set is # Kubernetes/ARC without docker-in-docker, so GitHub Actions service # containers ("services: mysql") are unavailable here ("Job Container is # required"). That coverage stays on the internal CI rather than being # duplicated on GitHub.