Files
AI_template/docs/ci-cd.md
olekhondera 425227c6b8 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>
2026-02-20 23:24:41 +02:00

3.6 KiB

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, varconst, =====, 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)

# 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:

# 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>