From a8aa8e38e258d86c74b0040fcd7d96c21d8b09ad Mon Sep 17 00:00:00 2001 From: Rephl3x Date: Sun, 24 May 2026 17:07:27 +1200 Subject: [PATCH] Add Gitea CI/CD pipeline for beta and prod --- .gitea/workflows/ci-cd.yml | 73 ++++++++++++++++++++++++++++++ README.md | 20 ++++++++ scripts/ci_backend_quality_gate.sh | 18 ++++++++ scripts/deploy_ams_dev01.sh | 51 +++++++++++++++++++++ 4 files changed, 162 insertions(+) create mode 100644 .gitea/workflows/ci-cd.yml create mode 100644 scripts/ci_backend_quality_gate.sh create mode 100644 scripts/deploy_ams_dev01.sh diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml new file mode 100644 index 0000000..839cf8d --- /dev/null +++ b/.gitea/workflows/ci-cd.yml @@ -0,0 +1,73 @@ +name: Magent CI/CD + +on: + push: + branches: + - beta + - prod + workflow_dispatch: + +concurrency: + group: magent-${{ github.ref }} + cancel-in-progress: true + +jobs: + verify: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: "24" + cache: npm + cache-dependency-path: frontend/package-lock.json + + - name: Install frontend dependencies + working-directory: frontend + run: npm ci + + - name: Run backend quality gate + run: bash scripts/ci_backend_quality_gate.sh + + - name: Build frontend + working-directory: frontend + run: npm run build + + deploy-prod: + if: github.ref_name == 'prod' + needs: verify + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Configure SSH key + env: + PROD_SSH_PRIVATE_KEY: ${{ secrets.PROD_SSH_PRIVATE_KEY }} + PROD_SSH_KNOWN_HOSTS: ${{ secrets.PROD_SSH_KNOWN_HOSTS }} + run: | + set -euo pipefail + mkdir -p ~/.ssh + chmod 700 ~/.ssh + printf '%s' "$PROD_SSH_PRIVATE_KEY" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + if [ -n "${PROD_SSH_KNOWN_HOSTS:-}" ]; then + printf '%s\n' "$PROD_SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts + chmod 644 ~/.ssh/known_hosts + fi + + - name: Deploy to AMS-DEV01 + env: + DEPLOY_HOST: ${{ secrets.PROD_SSH_HOST }} + DEPLOY_USER: ${{ secrets.PROD_SSH_USER }} + DEPLOY_PATH: ${{ secrets.PROD_DEPLOY_PATH }} + DEPLOY_SSH_OPTS: -o StrictHostKeyChecking=accept-new + run: bash scripts/deploy_ams_dev01.sh diff --git a/README.md b/README.md index c59f17d..7671587 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,26 @@ The frontend proxies `/api/*` to the backend container. Set: If you prefer the browser to call the backend directly, set `NEXT_PUBLIC_API_BASE` to your public backend URL and ensure CORS is configured. +## Gitea CI/CD + +This repo now includes a Gitea Actions workflow at `.gitea/workflows/ci-cd.yml`. + +- Push to `beta`: runs the backend unit-test quality gate and a production frontend build. +- Push to `prod`: runs the same verification, then deploys to Docker on `AMS-DEV01`. + +The deploy step ships tracked repository files over SSH, preserves the server's `.env` and `data/`, rebuilds with `docker compose up -d --build`, and smoke-tests: + +- `http://127.0.0.1:8000/health` +- `http://127.0.0.1:3000/login` + +Configure these Gitea Actions secrets before enabling the deploy job: + +- `PROD_SSH_PRIVATE_KEY`: private key for the deployment account. +- `PROD_SSH_HOST`: target host, for example `AMS-DEV01`. +- `PROD_SSH_USER`: target user, for example `zak`. +- `PROD_DEPLOY_PATH`: target app path, for example `/home/zak/magent`. +- `PROD_SSH_KNOWN_HOSTS`: optional pinned `known_hosts` entry for stricter host verification. + ## History endpoints - `GET /requests/{id}/history?limit=10` recent snapshots diff --git a/scripts/ci_backend_quality_gate.sh b/scripts/ci_backend_quality_gate.sh new file mode 100644 index 0000000..3b0a1ce --- /dev/null +++ b/scripts/ci_backend_quality_gate.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$repo_root" + +python_bin="${PYTHON_BIN:-python3}" + +echo "Installing backend Python requirements" +"$python_bin" -m pip install -r backend/requirements.txt + +echo "Running Python dependency integrity check" +"$python_bin" -m pip check + +echo "Running backend unit tests" +"$python_bin" -m unittest discover -s backend/tests -p "test_*.py" -v + +echo "Backend quality gate passed" diff --git a/scripts/deploy_ams_dev01.sh b/scripts/deploy_ams_dev01.sh new file mode 100644 index 0000000..ea52e0f --- /dev/null +++ b/scripts/deploy_ams_dev01.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$repo_root" + +deploy_host="${DEPLOY_HOST:-AMS-DEV01}" +deploy_user="${DEPLOY_USER:-zak}" +deploy_path="${DEPLOY_PATH:-/home/${deploy_user}/magent}" +ssh_opts="${DEPLOY_SSH_OPTS:-"-o StrictHostKeyChecking=accept-new"}" +timestamp="$(date -u +%Y%m%dT%H%M%SZ)" + +remote="${deploy_user}@${deploy_host}" + +echo "Deploying tracked repository contents to ${remote}:${deploy_path}" + +git archive --format=tar HEAD | ssh ${ssh_opts} "${remote}" " + set -e + mkdir -p '${deploy_path}' + backup_root=\"\${HOME}/magent-backups/${timestamp}\" + mkdir -p \"\${backup_root}\" + cd '${deploy_path}' + for path in backend frontend docker-compose.yml docker-compose.hub.yml Dockerfile README.md docker scripts .build_number .gitattributes .gitignore; do + if [ -e \"\$path\" ]; then + cp -a \"\$path\" \"\${backup_root}/\" + fi + done + tar -xf - -C '${deploy_path}' + docker compose up -d --build +" + +echo "Running remote smoke checks" +ssh ${ssh_opts} "${remote}" " + set -e + python3 - <<'PY' +from urllib import request + +checks = [ + ('http://127.0.0.1:8000/health', 200), + ('http://127.0.0.1:3000/login', 200), +] + +for url, expected in checks: + with request.urlopen(url, timeout=20) as response: + if response.status != expected: + raise SystemExit(f'{url} returned {response.status}, expected {expected}') + print(url, response.status) +PY +" + +echo "Deployment completed successfully"