# 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 [port] # Example: bash setup-project.sh my-app app.spektr.design 3000 ``` This creates: service user, `/opt/` 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/` directory 3. Install deploy script to `/usr/local/bin/deploy-` 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/` 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//pipelines?page=1&per_page=5 # Get specific pipeline curl -H "Authorization: Bearer $TOKEN" \ https://ci.spektr.design/api/repos//pipelines/ ``` Store token in `.env.local` (gitignored): ``` WOODPECKER_TOKEN= ```