Skip to content

Trim the prose: comments, punctuation, docs #267

Trim the prose: comments, punctuation, docs

Trim the prose: comments, punctuation, docs #267

Workflow file for this run

name: CI
on:
pull_request:
branches:
- main
push:
branches:
- main
workflow_dispatch:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
backend:
runs-on: ubuntu-latest
defaults:
run:
working-directory: server
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: server/go.mod
cache-dependency-path: server/go.sum
- name: Test
run: go test ./...
- name: Race test
run: go test -race ./...
- name: Vet
run: go vet ./...
frontend:
runs-on: ubuntu-latest
defaults:
run:
working-directory: frontend
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Clean install
run: npm ci
- name: Lint
run: npm run lint
- name: Test
run: npm test
- name: Build
run: npm run build
# The Docker build regenerates the Swagger docs from the handler annotations,
# so the binary always serves a current spec, but server/docs is also
# committed, and the Pages site publishes that committed copy. Nothing forced
# the two to agree, so annotations could change without a follow-up
# `swag init` and the published reference would drift from the real API with
# no signal. Regenerate here and fail on any diff.
swagger-docs:
runs-on: ubuntu-latest
defaults:
run:
working-directory: server
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: server/go.mod
cache-dependency-path: server/go.sum
# Pinned to the same version server/Dockerfile installs. A different
# version would report drift the real build never produces.
- name: Install swag
run: go install github.com/swaggo/swag/cmd/swag@v1.16.6
- name: Regenerate docs
run: swag init --parseDependency --parseInternal
- name: Committed docs are current
run: |
if ! git diff --exit-code -- docs; then
echo "::error file=server/docs/swagger.json::server/docs is stale. Run 'swag init --parseDependency --parseInternal' in server/ and commit the result."
exit 1
fi
docker-builds:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- name: Build backend image
uses: docker/build-push-action@v6
with:
context: ./server
file: ./server/Dockerfile
push: false
tags: triangle-cms-backend:${{ github.sha }}
cache-from: type=gha,scope=backend
cache-to: type=gha,mode=max,scope=backend
- name: Build frontend image
uses: docker/build-push-action@v6
with:
context: ./frontend
file: ./frontend/Dockerfile
push: false
tags: triangle-cms-frontend:${{ github.sha }}
cache-from: type=gha,scope=frontend
cache-to: type=gha,mode=max,scope=frontend
# The deployment scripts are the least reversible code in the repo, so their
# test suite runs on every PR. It stubs docker/curl/nginx on PATH and needs no
# daemon, database, or privileges.
deploy-scripts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy script tests
run: deploy/scripts/deploy_scripts_test.sh
# The Python in scripts/ was previously untested. A full reseed cannot run
# here: it needs the WordPress export zip, which is not in the repo, and a
# local Docker stack. This covers the parts that can fail silently: the
# scripts compiling at all, the seed generator's id=0 guarantee, and the
# reseed script's refusal to destroy data unattended.
scripts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Compile
run: python -m compileall -q scripts/
- name: Reseed script help
run: python ./scripts/reseed_from_etl.py --help
# The non-TTY guard is the only thing standing between an automated
# context and a destroyed database, so assert it stays a guard: this must
# FAIL to proceed. Without a Docker daemon the run would abort in
# preflight anyway, so accept either refusal. What is not acceptable is
# a clean exit, which would mean it sailed past the confirmation.
- name: Refuses to destroy data unattended
run: |
if python ./scripts/reseed_from_etl.py --skip-etl < /dev/null; then
echo "::error file=scripts/reseed_from_etl.py::reseed script exited 0 without a TTY and without --yes"
exit 1
fi
# articles has a real row with id = 0, which survives a load only under
# NO_AUTO_VALUE_ON_ZERO. Nothing else in CI covers this, and a renumbered
# id=0 orphans every articles_authors and seo row that references it.
- name: Seed generator preserves the id=0 row
run: |
set -euo pipefail
etl=$(mktemp -d); out=$(mktemp -d)
printf "INSERT INTO authors (\`login\`) VALUES ('x');\n" > "$etl/authors.sql"
printf "INSERT INTO articles (\`author_ids\`, \`comment_status\`) VALUES ('x','open');\n" > "$etl/articles.sql"
printf "INSERT INTO articles_authors (\`author_id\`) VALUES (1);\n" > "$etl/articles_authors.sql"
printf "INSERT INTO seo (\`yoast_tag_data\`) VALUES ('{}');\n" > "$etl/seo.sql"
python ./scripts/generate_wordpress_sql.py "$etl" "$out"
if ! head -1 "$out/02-articles.sql" | grep -q 'NO_AUTO_VALUE_ON_ZERO'; then
echo "::error file=scripts/generate_wordpress_sql.py::02-articles.sql lacks the NO_AUTO_VALUE_ON_ZERO preamble; the id=0 article would be renumbered on load"
exit 1
fi
# A mention of the mode in a comment must not be mistaken for setting
# it; that regression would silently skip the preamble.
printf -- "-- NO_AUTO_VALUE_ON_ZERO handled upstream\nINSERT INTO articles (\`author_ids\`, \`comment_status\`) VALUES ('y','open');\n" > "$etl/articles.sql"
python ./scripts/generate_wordpress_sql.py "$etl" "$out"
if ! head -1 "$out/02-articles.sql" | grep -q '^SET sql_mode'; then
echo "::error file=scripts/generate_wordpress_sql.py::a commented mention of NO_AUTO_VALUE_ON_ZERO suppressed the preamble"
exit 1
fi
compose-validation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate Delta Compose config
env:
CMS_IMAGE_TAG: ${{ github.sha }}
DB_NAME: triangle
DB_USER: triangle_user
DB_PASSWORD: ci-placeholder
DB_HOST: db-host-placeholder
DB_PORT: "3306"
OIDC_ISSUER_URL: http://oidc-placeholder.invalid
OIDC_CLIENT_ID: ci-placeholder
OIDC_CLIENT_SECRET: ci-placeholder
FRONTEND_ORIGIN: http://delta-placeholder
OIDC_REDIRECT_URI: http://delta-placeholder/auth/callback
# CMS_EMBEDDINGS_TAG is derived rather than hardcoded, so this also
# checks that the derivation deploy.sh uses still resolves.
run: |
CMS_EMBEDDINGS_TAG="$(git rev-parse HEAD:embeddings)" \
docker compose -f deploy/compose.cms.yml config >/dev/null