feat: add Woodpecker CI + Gitea deployment templates
- .woodpecker.yml: full pipeline template (install → lint-fix → lint → test → deploy) - scripts/setup-project.sh: one-command VPS setup (user, dir, deploy, sudoers, systemd, nginx) - scripts/deploy.sh: deploy script template (rsync + npm ci + systemctl + health check) - scripts/ci-lint-fix.sh: ESLint auto-fix with [CI SKIP] commit-back - docs/ci-cd.md: complete CI/CD documentation and troubleshooting - .env.example: added WOODPECKER_TOKEN - DOCS.md: added CI/CD section Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
114
docs/ci-cd.md
Normal file
114
docs/ci-cd.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# CI/CD — Woodpecker + Gitea
|
||||
|
||||
## Overview
|
||||
|
||||
Pipeline runs on Woodpecker CI with **local backend** (no Docker) on the same VPS.
|
||||
Triggered by push to `main` branch via Gitea webhook.
|
||||
|
||||
## Pipeline Flow
|
||||
|
||||
```
|
||||
push to main → install → lint-fix (optional) → lint + test → deploy
|
||||
```
|
||||
|
||||
### Steps
|
||||
|
||||
| Step | What it does |
|
||||
|------|-------------|
|
||||
| **install** | `npm ci` — clean install dependencies |
|
||||
| **lint-fix** | ESLint `--fix`, auto-commits back with `[CI SKIP]` |
|
||||
| **lint** | ESLint check — fails pipeline on errors |
|
||||
| **test** | `npm test` — fails pipeline on test failures |
|
||||
| **deploy** | Runs deploy script via sudo on the VPS |
|
||||
|
||||
### lint-fix auto-commit
|
||||
|
||||
When ESLint can auto-fix issues (formatting, `var` → `const`, `==` → `===`, etc.),
|
||||
the pipeline commits the fix back to Gitea with `[CI SKIP]` in the message.
|
||||
Woodpecker natively skips pipelines for commits containing `[CI SKIP]`.
|
||||
|
||||
Requires `gitea_token` secret — a Gitea access token with repo write permission.
|
||||
|
||||
## Configuration
|
||||
|
||||
### `.woodpecker.yml`
|
||||
|
||||
Located at project root. Uses `image: bash` for local backend (specifies shell, not Docker image).
|
||||
|
||||
### Secrets (Woodpecker UI)
|
||||
|
||||
| Secret | Where | Purpose |
|
||||
|--------|-------|---------|
|
||||
| `gitea_token` | Global or repo | Gitea access token for lint-fix auto-commit |
|
||||
|
||||
Add secrets in Woodpecker UI → Settings → Secrets (repo level) or global level.
|
||||
|
||||
## Deploy Setup (one-time on VPS)
|
||||
|
||||
### Automated setup (recommended)
|
||||
|
||||
```bash
|
||||
# On VPS as root:
|
||||
bash setup-project.sh <project-name> <domain> [port]
|
||||
|
||||
# Example:
|
||||
bash setup-project.sh my-app app.spektr.design 3000
|
||||
```
|
||||
|
||||
This creates: service user, `/opt/<project>` directory, deploy script, sudoers rule, systemd service, nginx config.
|
||||
|
||||
After running, create `.env` and push code to Gitea.
|
||||
|
||||
### Manual setup
|
||||
|
||||
If you need more control, see `scripts/setup-project.sh` for individual steps:
|
||||
1. Create service user (`useradd -r -s /sbin/nologin`)
|
||||
2. Create `/opt/<project>` directory
|
||||
3. Install deploy script to `/usr/local/bin/deploy-<project>`
|
||||
4. Add sudoers rule for Woodpecker agent user
|
||||
5. Create systemd service
|
||||
6. Create nginx config
|
||||
|
||||
### Deploy script details
|
||||
|
||||
`scripts/deploy.sh` does:
|
||||
1. rsync files (excludes node_modules, .env, .git)
|
||||
2. `npm ci --omit=dev` as service user (with `HOME=` set to avoid npm cache errors)
|
||||
3. `systemctl restart` + health check
|
||||
|
||||
The script runs as root via sudo. Only this specific script is allowed in sudoers.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Problem | Cause | Fix |
|
||||
|---------|-------|-----|
|
||||
| `secret "X" not found` | Secret not added in Woodpecker | Add in UI → Settings → Secrets |
|
||||
| `Invalid or missing image` | Missing `image:` field | Use `image: bash` for local backend |
|
||||
| `Permission denied` on deploy | Sudoers not configured | Follow deploy setup above |
|
||||
| `command not found` for deploy script | Script not at `/usr/local/bin/` | Copy and chmod 755 |
|
||||
| npm `EACCES mkdir /home/user` | Service user has no home dir | Set `HOME=/opt/<project>` in deploy script |
|
||||
| Pipeline not triggered | Webhook issue or `[CI SKIP]` in message | Check Gitea webhook settings |
|
||||
|
||||
## Gitea Access Token
|
||||
|
||||
Create in Gitea: Settings → Applications → Generate New Token.
|
||||
Permissions needed: `repo` (read/write).
|
||||
|
||||
## Woodpecker API
|
||||
|
||||
Check pipeline status programmatically:
|
||||
|
||||
```bash
|
||||
# List recent pipelines
|
||||
curl -H "Authorization: Bearer $TOKEN" \
|
||||
https://ci.spektr.design/api/repos/<REPO_ID>/pipelines?page=1&per_page=5
|
||||
|
||||
# Get specific pipeline
|
||||
curl -H "Authorization: Bearer $TOKEN" \
|
||||
https://ci.spektr.design/api/repos/<REPO_ID>/pipelines/<NUMBER>
|
||||
```
|
||||
|
||||
Store token in `.env.local` (gitignored):
|
||||
```
|
||||
WOODPECKER_TOKEN=<your-token>
|
||||
```
|
||||
Reference in New Issue
Block a user