Add Gitea CI/CD pipeline for beta and prod
This commit is contained in:
@@ -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
|
||||||
@@ -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.
|
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
|
## History endpoints
|
||||||
|
|
||||||
- `GET /requests/{id}/history?limit=10` recent snapshots
|
- `GET /requests/{id}/history?limit=10` recent snapshots
|
||||||
|
|||||||
@@ -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"
|
||||||
@@ -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"
|
||||||
Reference in New Issue
Block a user