feat(cd): add continuous deployment on push to master
Some checks failed
CI / ruff (push) Successful in 8s
CI / pytest (push) Successful in 36m19s
CI / architecture (push) Successful in 11s
CI / dependency-scanning (push) Successful in 27s
CI / audit (push) Successful in 9s
CI / docs (push) Failing after 59s
CI / deploy (push) Failing after 3s
Some checks failed
CI / ruff (push) Successful in 8s
CI / pytest (push) Successful in 36m19s
CI / architecture (push) Successful in 11s
CI / dependency-scanning (push) Successful in 27s
CI / audit (push) Successful in 9s
CI / docs (push) Failing after 59s
CI / deploy (push) Failing after 3s
Deploy job SSHes to production after ruff/pytest/architecture pass, running scripts/deploy.sh (stash, pull, docker rebuild, migrate, health check). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -205,10 +205,10 @@ Configure these in your Gitea repository under **Settings > Actions > Secrets**:
|
||||
|
||||
| Secret | Description | Used by |
|
||||
|--------|-------------|---------|
|
||||
| `SSH_PRIVATE_KEY` | Private key for deployment server | Deploy job (if added) |
|
||||
| `SERVER_HOST` | Production server IP/hostname | Deploy job |
|
||||
| `SERVER_USER` | SSH user on production server | Deploy job |
|
||||
| `SERVER_PATH` | App directory on server | Deploy job |
|
||||
| `DEPLOY_SSH_KEY` | Ed25519 private key for deployment | Deploy job |
|
||||
| `DEPLOY_HOST` | Production server IP (e.g. `127.0.0.1`) | Deploy job |
|
||||
| `DEPLOY_USER` | SSH user on production server (e.g. `samir`) | Deploy job |
|
||||
| `DEPLOY_PATH` | App directory on server (e.g. `/home/samir/apps/orion`) | Deploy job |
|
||||
|
||||
---
|
||||
|
||||
@@ -223,16 +223,17 @@ push/PR to master
|
||||
├── architecture (architecture validation)
|
||||
├── dependency-scanning (pip-audit, non-blocking)
|
||||
├── audit (custom audit, non-blocking)
|
||||
└── docs (mkdocs build, master-only, after lint+test pass)
|
||||
├── docs (mkdocs build, master-only, after lint+test pass)
|
||||
└── deploy (SSH deploy, master-only, after lint+test+arch pass)
|
||||
```
|
||||
|
||||
All jobs run in parallel except `docs`, which waits for `ruff`, `pytest`, and `architecture` to pass.
|
||||
All jobs run in parallel except `docs` and `deploy`, which wait for `ruff`, `pytest`, and `architecture` to pass. The `deploy` job only runs on push (not PRs).
|
||||
|
||||
---
|
||||
|
||||
## 9. Adding a Deploy Job (Optional)
|
||||
## 9. Deploy Job (Continuous Deployment)
|
||||
|
||||
To add automated deployment via SSH (similar to the GitLab deploy stage), add this job to `.gitea/workflows/ci.yml`:
|
||||
The CI pipeline includes an automated deploy job that runs on every successful push to master. It SSHes to the production server and runs a version-controlled deploy script:
|
||||
|
||||
```yaml
|
||||
deploy:
|
||||
@@ -240,23 +241,28 @@ To add automated deployment via SSH (similar to the GitLab deploy stage), add th
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
needs: [ruff, pytest, architecture]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Deploy via SSH
|
||||
- name: Deploy to production
|
||||
uses: appleboy/ssh-action@v1
|
||||
with:
|
||||
host: ${{ secrets.SERVER_HOST }}
|
||||
username: ${{ secrets.SERVER_USER }}
|
||||
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
script: |
|
||||
cd ${{ secrets.SERVER_PATH }}
|
||||
git pull origin master
|
||||
source .venv/bin/activate
|
||||
uv sync --frozen
|
||||
python -m alembic upgrade head
|
||||
sudo systemctl restart wizamart
|
||||
host: ${{ secrets.DEPLOY_HOST }}
|
||||
username: ${{ secrets.DEPLOY_USER }}
|
||||
key: ${{ secrets.DEPLOY_SSH_KEY }}
|
||||
port: 22
|
||||
command_timeout: 10m
|
||||
script: cd ${{ secrets.DEPLOY_PATH }} && bash scripts/deploy.sh
|
||||
```
|
||||
|
||||
The `scripts/deploy.sh` script handles the full deploy lifecycle:
|
||||
|
||||
1. Stash local changes (preserves `.env` and other server-side edits)
|
||||
2. Pull latest code (`--ff-only`)
|
||||
3. Pop stash to restore local changes
|
||||
4. Rebuild and restart Docker containers (`docker compose --profile full up -d --build`)
|
||||
5. Run database migrations (`alembic upgrade heads`)
|
||||
6. Health check `http://localhost:8001/health` with retries
|
||||
|
||||
See [Hetzner Server Setup — Step 16](hetzner-server-setup.md#step-16-continuous-deployment) for the full setup guide including SSH key generation and Gitea secrets configuration.
|
||||
|
||||
---
|
||||
|
||||
## 10. Firewall Configuration
|
||||
|
||||
Reference in New Issue
Block a user