diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..7fef642 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,114 @@ +# J621 CI — runs on every push (and pull request): Django checks + the full +# backend test suite against MariaDB/Redis, and the frontend type-check, +# lint and production build. +# +# Runner: the "nitro-ci" act_runner with the custom `ubuntu-latest` label. + +name: CI + +on: + push: + branches: ["**"] + tags-ignore: ["**"] + pull_request: + workflow_dispatch: + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + backend: + name: Backend tests + runs-on: ubuntu-latest + services: + mariadb: + image: mariadb:11.4 + env: + MARIADB_ROOT_PASSWORD: root + MARIADB_DATABASE: j621 + MARIADB_USER: j621 + MARIADB_PASSWORD: j621 + options: >- + --health-cmd "healthcheck.sh --connect --innodb_initialized" + --health-interval 5s + --health-timeout 5s + --health-retries 20 + redis: + image: redis:7-alpine + options: >- + --health-cmd "redis-cli ping" + --health-interval 5s + --health-timeout 5s + --health-retries 20 + env: + DB_HOST: mariadb + DB_PORT: "3306" + DB_NAME: j621 + DB_USER: j621 + DB_PASSWORD: j621 + DB_ROOT_PASSWORD: root + REDIS_URL: redis://redis:6379/1 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.14" + cache: pip + cache-dependency-path: backend/requirements.txt + + - name: Install backend dependencies + run: pip install -r backend/requirements.txt + + - name: Install a MariaDB client + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends default-mysql-client + + - name: Grant the test database rights + run: | + for i in $(seq 1 30); do + mysql -h "$DB_HOST" -P "$DB_PORT" -u root -p"$DB_ROOT_PASSWORD" \ + -e "SELECT 1" >/dev/null 2>&1 && break + sleep 2 + done + mysql -h "$DB_HOST" -P "$DB_PORT" -u root -p"$DB_ROOT_PASSWORD" \ + -e "GRANT ALL ON \`test_j621\`.* TO 'j621'@'%'; FLUSH PRIVILEGES;" + + - name: Django system checks + working-directory: backend + run: python manage.py check + + - name: Backend tests + working-directory: backend + run: >- + python manage.py test + apps.core.tests + apps.library.tests + apps.follows.tests + apps.accounts.tests + + frontend: + name: Frontend build & lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "22" + cache: npm + cache-dependency-path: frontend/package-lock.json + + - name: Install frontend dependencies + working-directory: frontend + run: npm ci + + - name: Lint + working-directory: frontend + run: npm run lint + + - name: Type-check & build + working-directory: frontend + run: npm run build diff --git a/.gitea/workflows/publish.yml b/.gitea/workflows/publish.yml new file mode 100644 index 0000000..cefc74d --- /dev/null +++ b/.gitea/workflows/publish.yml @@ -0,0 +1,51 @@ +# J621 image publishing — manual workflow. +# +# Builds the backend (gunicorn + whitenoise, ffmpeg) and frontend (static +# nginx) images for linux/amd64 + linux/arm64 and pushes them to the Gitea +# registry as :latest and :, with the commit baked in as GIT_HASH. +# +# Run it from the Actions tab ("Run workflow"), or: +# curl -X POST .../api/v1/repos/JakeBreath/J621/actions/workflows/publish.yml/dispatches \ +# -d '{"ref":"main"}' +# +# Registry login uses the automatic GITHUB_TOKEN (the repo needs package write +# access for the actor); no extra secrets are required. + +name: Publish images + +on: + workflow_dispatch: + inputs: + platforms: + description: Build platforms (comma separated) + required: false + default: linux/amd64,linux/arm64 + +concurrency: + group: publish + cancel-in-progress: false + +jobs: + publish: + name: Build & push images + runs-on: ubuntu-latest + env: + REGISTRY_USER: ${{ github.actor }} + REGISTRY_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PLATFORMS: ${{ inputs.platforms || 'linux/amd64,linux/arm64' }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Register binfmt (multi-arch builds) + run: docker run --privileged --rm tonistiigi/binfmt --install all + + - name: Build & push both images + run: | + set -euo pipefail + SHA="$(git rev-parse --short HEAD)" + echo "Publishing $SHA for $PLATFORMS" + # Both scripts honour REGISTRY_USER/REGISTRY_TOKEN (see deploy/push_*.sh). + PLATFORMS="$PLATFORMS" ./deploy/push_frontend.sh "$SHA" + PLATFORMS="$PLATFORMS" ./deploy/push_backend.sh "$SHA" diff --git a/deploy/push_backend.sh b/deploy/push_backend.sh index b9d5130..f9a53d0 100755 --- a/deploy/push_backend.sh +++ b/deploy/push_backend.sh @@ -10,10 +10,16 @@ REGISTRY="gitea.rainbow-herring.ts.net/jakebreath/j621-backend" REGISTRY_HOST="$(printf '%s' "$REGISTRY" | cut -d/ -f1)" SHA="${1:-$(git rev-parse --short HEAD)}" BUILDER=multiarch -PLATFORMS="linux/amd64,linux/arm64" +PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}" echo "==> Logging in to $REGISTRY_HOST ..." -docker login "$REGISTRY_HOST" +if [ -n "${REGISTRY_USER:-}" ] && [ -n "${REGISTRY_TOKEN:-}" ]; then + # Non-interactive login for CI (workflow passes GITHUB_TOKEN). + printf '%s' "$REGISTRY_TOKEN" | docker login "$REGISTRY_HOST" \ + -u "$REGISTRY_USER" --password-stdin +else + docker login "$REGISTRY_HOST" +fi if ! docker buildx inspect "$BUILDER" >/dev/null 2>&1; then echo "==> Creating buildx builder '$BUILDER' ..." diff --git a/deploy/push_frontend.sh b/deploy/push_frontend.sh index 97ea80f..10ccd5f 100755 --- a/deploy/push_frontend.sh +++ b/deploy/push_frontend.sh @@ -10,10 +10,16 @@ REGISTRY="gitea.rainbow-herring.ts.net/jakebreath/j621-frontend" REGISTRY_HOST="$(printf '%s' "$REGISTRY" | cut -d/ -f1)" SHA="${1:-$(git rev-parse --short HEAD)}" BUILDER=multiarch -PLATFORMS="linux/amd64,linux/arm64" +PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}" echo "==> Logging in to $REGISTRY_HOST ..." -docker login "$REGISTRY_HOST" +if [ -n "${REGISTRY_USER:-}" ] && [ -n "${REGISTRY_TOKEN:-}" ]; then + # Non-interactive login for CI (workflow passes GITHUB_TOKEN). + printf '%s' "$REGISTRY_TOKEN" | docker login "$REGISTRY_HOST" \ + -u "$REGISTRY_USER" --password-stdin +else + docker login "$REGISTRY_HOST" +fi if ! docker buildx inspect "$BUILDER" >/dev/null 2>&1; then echo "==> Creating buildx builder '$BUILDER' ..."