Signage moves from the legacy module contract to Ekklesia 0.2.0's, with no behaviour or schema
change:
- manifest version 8, `database: { abi: 1 }`, compatibility ^0.2.0 for platform and module SDK;
the runtime declares the same ABI, as Core requires;
- every store reaches PostgreSQL through the platform's Module Database ABI v1 executor, with
Signage's own Drizzle tables and the module-side adapter (`moduleDrizzle`) from
@ekklesia/module-database. createSignageStore takes the executor, so no call site changes;
- the schema entrypoint exports only plain ABI v1 metadata (table names and foreign-key targets),
derived from tables.ts with moduleDrizzleSchemaMetadata; no Drizzle object reaches Core;
- duplicate-image detection reads SQLSTATE 23505 from the stable Ekklesia database error, found
with findEkklesiaDatabaseError through Drizzle's DrizzleQueryError wrapping. The old
`error.code === "23505"` check never matched a wrapped error, so a duplicate-upload race
surfaced as a 500 instead of the content-hash conflict.
tables.ts declarations, the migration, and its pinned checksum are unchanged.
Tests: an ABI v1 executor double that enforces Core's scope, parameter, and abort rules drives all
13 store transactions, their rollbacks, raw int8/timestamptz/jsonb decoding, and the 23505
regression, including generic and driver-shaped errors that must not count as duplicates.
CI, temporarily: the platform pin moves to v0.2.0 (1788d17) with a regenerated ci/pnpm-lock.yaml.
The integration job is disabled: from 0.2.0 the platform image is generic (ADR 0048) and installs
modules only as Module Packages, which Signage cannot be until its sharp dependency goes through
the native package flow. The job and ci/integration.sh stay, and the job returns in that change.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
229 lines
8.8 KiB
YAML
229 lines
8.8 KiB
YAML
name: CI
|
|
|
|
# Signage builds, tests, and runs only inside an Ekklesia workspace, so every job first assembles it
|
|
# into the platform commit pinned in ci/platform.env (ci/assemble.sh) and installs that workspace
|
|
# with --frozen-lockfile from ci/pnpm-lock.yaml.
|
|
#
|
|
# The same trust rules as the platform's own CI (docs/development/security.md there):
|
|
# * every action is pinned by a full commit SHA;
|
|
# * every checkout sets `persist-credentials: false`, and nothing in this workflow pushes;
|
|
# * no repository, organization, or instance secret is referenced;
|
|
# * there is no `pull_request_target`;
|
|
# * the self-hosted runner executes trusted, reviewed code only.
|
|
#
|
|
# The server is Gitea 1.24, which ignores `permissions`, `concurrency`, and `timeout-minutes`
|
|
# (https://docs.gitea.com/1.24/usage/actions/comparison). They are declared so the workflow is already
|
|
# correct on a release that honours them; on 1.24 they bound nothing, and `permissions` does not
|
|
# restrict the job token.
|
|
|
|
on:
|
|
pull_request:
|
|
push:
|
|
branches:
|
|
- main
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
concurrency:
|
|
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
lint:
|
|
name: lint
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
steps:
|
|
- name: Check out repository
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
# Nothing here pushes, so the job token is never needed after checkout and must not be left
|
|
# in .git/config for a later step to read.
|
|
persist-credentials: false
|
|
|
|
- name: Assemble Signage into the pinned platform
|
|
run: bash ci/assemble.sh
|
|
|
|
- name: Set up Node.js at the platform's version
|
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
with:
|
|
node-version-file: build/workspace/.node-version
|
|
|
|
- name: Install the assembled workspace (frozen lockfile)
|
|
working-directory: build/workspace
|
|
run: |
|
|
corepack enable
|
|
corepack install
|
|
pnpm install --frozen-lockfile
|
|
|
|
- name: Lint
|
|
working-directory: build/workspace
|
|
run: pnpm --filter @ekklesia/signage lint
|
|
|
|
- name: Check that CI cleans up every stack it starts
|
|
run: bash ci/check-cleanup.sh
|
|
|
|
typecheck:
|
|
name: typecheck
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
steps:
|
|
- name: Check out repository
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
# Nothing here pushes, so the job token is never needed after checkout and must not be left
|
|
# in .git/config for a later step to read.
|
|
persist-credentials: false
|
|
|
|
- name: Assemble Signage into the pinned platform
|
|
run: bash ci/assemble.sh
|
|
|
|
- name: Set up Node.js at the platform's version
|
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
with:
|
|
node-version-file: build/workspace/.node-version
|
|
|
|
- name: Install the assembled workspace (frozen lockfile)
|
|
working-directory: build/workspace
|
|
run: |
|
|
corepack enable
|
|
corepack install
|
|
pnpm install --frozen-lockfile
|
|
|
|
- name: Build the platform packages Signage depends on
|
|
working-directory: build/workspace
|
|
run: pnpm exec turbo run build --filter='@ekklesia/signage^...'
|
|
|
|
- name: Typecheck the server, browser, and browser-test projects
|
|
working-directory: build/workspace
|
|
run: pnpm --filter @ekklesia/signage typecheck
|
|
|
|
test:
|
|
name: test
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
steps:
|
|
- name: Check out repository
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
# Nothing here pushes, so the job token is never needed after checkout and must not be left
|
|
# in .git/config for a later step to read.
|
|
persist-credentials: false
|
|
|
|
- name: Assemble Signage into the pinned platform
|
|
run: bash ci/assemble.sh
|
|
|
|
- name: Set up Node.js at the platform's version
|
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
with:
|
|
node-version-file: build/workspace/.node-version
|
|
|
|
- name: Install the assembled workspace (frozen lockfile)
|
|
working-directory: build/workspace
|
|
run: |
|
|
corepack enable
|
|
corepack install
|
|
pnpm install --frozen-lockfile
|
|
|
|
- name: Build the platform packages Signage depends on
|
|
working-directory: build/workspace
|
|
run: pnpm exec turbo run build --filter='@ekklesia/signage^...'
|
|
|
|
- name: Unit, browser, and display contract tests
|
|
working-directory: build/workspace
|
|
run: pnpm --filter @ekklesia/signage test
|
|
|
|
build:
|
|
name: build
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 20
|
|
steps:
|
|
- name: Check out repository
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
# Nothing here pushes, so the job token is never needed after checkout and must not be left
|
|
# in .git/config for a later step to read.
|
|
persist-credentials: false
|
|
|
|
- name: Assemble Signage into the pinned platform
|
|
run: bash ci/assemble.sh
|
|
|
|
- name: Set up Node.js at the platform's version
|
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
with:
|
|
node-version-file: build/workspace/.node-version
|
|
|
|
- name: Install the assembled workspace (frozen lockfile)
|
|
working-directory: build/workspace
|
|
run: |
|
|
corepack enable
|
|
corepack install
|
|
pnpm install --frozen-lockfile
|
|
|
|
# The same gates the platform's image build runs against exactly this module set: its boundary
|
|
# rules (which apply to modules), the manifest, and the migrations.
|
|
- name: Platform gates (boundaries, module manifest, migrations)
|
|
working-directory: build/workspace
|
|
run: |
|
|
pnpm boundaries
|
|
pnpm modules:validate
|
|
pnpm migrations:validate
|
|
|
|
- name: Build Signage and the platform it depends on
|
|
working-directory: build/workspace
|
|
run: pnpm exec turbo run build --filter='@ekklesia/signage...'
|
|
|
|
# Signage inside Ekklesia, end to end, in a real browser: the platform's own Dockerfile builds the
|
|
# deployment image with Signage in it, and the platform's split-topology deployment smoke runs
|
|
# against it, pairing a kiosk display and running the scenarios in ci/display-scenarios. A
|
|
# disposable database and object store with generated secrets; nothing is pushed or logged in to.
|
|
#
|
|
# DISABLED while Signage is pinned to Ekklesia 0.2.0. From that release on, the platform's image is
|
|
# the one generic image (platform ADR 0048): deploy/Dockerfile keeps `modules/` out of its build
|
|
# context and refuses one that has it, and the deployment smoke installs modules only as canonical
|
|
# Module Packages (ADR 0049). Signage is not one yet: its static sharp dependency needs the native
|
|
# linux-x64-glibc package flow, which is deliberately not part of the 0.2.0 compatibility change.
|
|
# Run against 0.2.0, this job would build an image without Signage and drive the module template's
|
|
# display instead, so it is switched off rather than left reporting on something else. The job and
|
|
# ci/integration.sh stay as they are; the job returns once Signage is built as a Module Package and
|
|
# installed into the generic image, and `if: false` is removed in that change.
|
|
integration:
|
|
name: integration
|
|
if: false
|
|
needs:
|
|
- test
|
|
- build
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 45
|
|
env:
|
|
DOCKER_BUILDKIT: "1"
|
|
# Names this job's stacks, so its final step removes exactly these (the platform's
|
|
# scripts/lib/ci-project.sh).
|
|
EKKLESIA_CI_JOB_KEY: signage-integration
|
|
steps:
|
|
- name: Check out repository
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Assemble Signage into the pinned platform
|
|
run: bash ci/assemble.sh
|
|
|
|
# A job the runner killed (cancelled, or past the runner's own time limit) never ran its
|
|
# cleanup. Anything a CI job left on this shared daemon more than three hours ago goes first.
|
|
- name: Sweep stale CI stacks from the runner
|
|
run: bash build/workspace/scripts/ci-sweep.sh --stale
|
|
|
|
- name: Build the image and run the display scenarios
|
|
run: bash ci/integration.sh
|
|
|
|
# Whatever happened above, this job's own stacks do not outlive it. If assembly failed, nothing
|
|
# was started.
|
|
- name: Remove this job's CI stacks
|
|
if: always()
|
|
run: |
|
|
if [ -f build/workspace/scripts/ci-sweep.sh ]; then
|
|
bash build/workspace/scripts/ci-sweep.sh --job
|
|
fi
|