Android / Build, or is the channel already serving this? (push) Successful in 3s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Build now, or wait for Android? (push) Successful in 2s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
CI & Build / Web typecheck and unit tests (push) Successful in 12s
CI & Build / Python tests (push) Successful in 23s
Android / Core and FFI clippy and tests (push) Successful in 51s
CI & Build / integration (push) Successful in 1m49s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Successful in 2m20s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 3m6s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 3m46s
Desktop (Tauri) / Update manifest (push) Successful in 3s
Android / Kotlin + Rust (APK) (push) Successful in 8m31s
Android / Build the server image (push) Successful in 1s
#6225 "Comment standard sweep: root, config, CI workflows, docs and packaging", milestone 546 "Bring the repo to the comment standard (rule 32) and compose defaults (rule 198)". - README restructured in newcomer order: what it is, quick start, configuration, setup pitfalls, updating and backups, features, troubleshooting, development, licence. Its quick-start compose carries no restart policy. - Dockerfile and .env.example trimmed to one or two lines per setting. - Workflows, packaging scripts and docs lose issue, run, note, rule and milestone references and their history narration. Comments that still described path filters and "step 6" as future work now state what the workflows do. - ci-requirements.md rewritten against the current workflows. It said the build gated on typecheck and lint only, the integration lane did not gate, a v* tag published :latest, and ci-tauri lacked bsdtar and zstd; none of those is true now (the last checked against run 9630's log). - Echo strings in guard-forward.sh and version.sh drop their note citations; every string a test asserts on is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
72 lines
3.1 KiB
Docker
72 lines
3.1 KiB
Docker
# syntax=docker/dockerfile:1
|
|
|
|
# Stage 1: build the Vue frontend (also type-checks via `vue-tsc` in the build script).
|
|
FROM node:22-alpine AS build-frontend
|
|
WORKDIR /build
|
|
COPY frontend/package.json frontend/package-lock.json* ./
|
|
RUN npm ci --quiet
|
|
COPY frontend/ .
|
|
RUN npm run build
|
|
|
|
# Stage 2: Python runtime.
|
|
FROM python:3.12-slim AS runtime
|
|
WORKDIR /app
|
|
|
|
COPY pyproject.toml .
|
|
COPY src/ src/
|
|
RUN --mount=type=cache,target=/root/.cache/pip \
|
|
pip install .
|
|
|
|
# Bake the built SPA into the package's static dir (served by app.py). PYTHONPATH
|
|
# points at /app/src so the runtime imports this source tree (with static/ present),
|
|
# not the pip-installed copy.
|
|
COPY --from=build-frontend /build/dist/ src/inkwell/static/
|
|
COPY alembic.ini .
|
|
COPY alembic/ alembic/
|
|
|
|
# The clients this server hands out — the APK and all four desktop bundles. CI
|
|
# fetches the newest published build of each into ./client immediately before this
|
|
# runs (packaging/fetch-clients.sh), so both image tags ship a full set and a
|
|
# `docker compose pull` delivers new ones with no file copying by hand.
|
|
#
|
|
# ~104 MB of this image is that set, almost all of it the AppImage.
|
|
#
|
|
# Fetched by the JOB rather than here on purpose: the releases are private, and a
|
|
# token used inside a build ends up in the build context or a layer.
|
|
#
|
|
# LAST of the COPYs, deliberately: this directory changes on every build, so
|
|
# putting it above the `pip install` layer would invalidate that layer every time.
|
|
#
|
|
# The directory is tracked (client/.keep) so this COPY cannot fail on a tree where
|
|
# that step never ran. An image with no clients — or with some and not others — is
|
|
# a supported state: the server advertises what it has and the web UI hides the
|
|
# rest (client_dist.py).
|
|
COPY client/ src/inkwell/client/
|
|
|
|
# The desktop installer, served at /install.sh with this server's own address
|
|
# written into it (installer.py). The SAME script the forge serves raw, copied rather
|
|
# than moved so the forge's raw URL keeps working.
|
|
COPY desktop/packaging/install.sh src/inkwell/install.sh
|
|
|
|
ENV PYTHONPATH=/app/src
|
|
|
|
ARG BUILD_VERSION=dev
|
|
ENV APP_VERSION=$BUILD_VERSION
|
|
|
|
EXPOSE 5000
|
|
# Wait for the database, run migrations, then serve. The DB wait keeps a briefly
|
|
# slow or unready database from crash-looping the container. The schema is built by
|
|
# real migrations, never metadata.create_all.
|
|
#
|
|
# Timeouts, as hypercorn 0.18 implements them:
|
|
# - `--keep-alive 120` is the idle timeout. It is also the header timeout:
|
|
# hypercorn marks a connection busy only once a whole request has arrived, so a
|
|
# client dribbling headers is still "idle" and is cut off at this. 120 stays
|
|
# above Traefik's 90s idle timeout for backend connections, so the proxy never
|
|
# reuses one this server has just closed (a 502).
|
|
# - No `--read-timeout`, on purpose. It bounds every socket read, including the
|
|
# whole time a download is streaming and the client sends nothing, so it would
|
|
# cut off an APK fetched slowly over mobile data. Bodies are capped instead
|
|
# (MAX_CONTENT_LENGTH in app.py).
|
|
CMD ["sh", "-c", "python -m inkwell.dbwait && alembic upgrade head && hypercorn 'inkwell.app:create_app()' --bind 0.0.0.0:5000 --keep-alive 120"]
|