# 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 lean-build: # ADR-013: prove a per-site build carries only its chosen plugins. # # The split below is SYNTHETIC, and deliberately so. Every plugin in this # repository ships on this line, so there is no "omitted" set to borrow from # a real site - and a job that iterated an empty omitted list would assert # nothing while staying green, which is the exact failure the omission # guarantee exists to catch. So the profile names a genuine SUBSET of the # bundled plugins and the assertions prove the SUBSETTING MECHANISM: what # the profile chooses is staged, and what it leaves out is not. # # Chosen (7): backups computers endpoints machines network notifications # printers # Omitted (5): guides knowledgebase slides tools warranty # # The omitted five are picked because nothing depends on them, so the # closure stays exactly the chosen set. '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. # # Verified by planting a leak, per the standing rule that a green gate may # be vacuous: adding 'guides' to the profile and rebuilding makes both the # GuidesList assertion and the plugins/guides directory assertion fail. 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 (seven-plugin subset) run: | printf '%s' '{ "site": "ci-lean", "plugins": ["backups", "computers", "endpoints", "machines", "network", "notifications", "printers"] }' \ > /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: guides, knowledgebase, slides, # tools, warranty. Each name is proven to exist by the chosen-plugin # loop on a full build, so these are known-good grep targets rather # than strings that would pass by being misspelled. for code in GuidesList KnowledgeBaseDetail SlideManager ToolsIndex \ WarrantiesList; 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 MachineDetail \ NetworkDevicesList NotificationsList PrinterDetail; 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 machines network \ notifications printers; do test -d "/tmp/leansite/plugins/$plugin" || { echo "FAIL: chosen plugin '$plugin' missing from the backend tree" exit 1; } done for plugin in guides knowledgebase slides tools warranty; 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.