Add Gitea Actions workflows, CI config, and docs
Some checks failed
Docker / docker (push) Successful in 6s
Security / security (push) Successful in 6s
Deploy / deploy-local-runner (push) Has been cancelled
CI / ci (push) Successful in 1m42s
Deploy / deploy-ssh (push) Successful in 7s

This commit is contained in:
2026-02-28 20:40:14 +01:00
parent 3b48b39561
commit 8cadb2d216
35 changed files with 3216 additions and 0 deletions

108
docs/AI.md Normal file
View File

@@ -0,0 +1,108 @@
# AI Workflows — ${REPO_NAME}
## Overview
This template includes five AI-powered workflows that use the
[OpenRabbit](https://git.hiddenden.cafe/Hiddenden/openrabbit) tooling
to provide automated code review, issue triage, and interactive chat
via a bot (default: `@codebot` / user `Bartender`).
All AI workflows check out the central `Hiddenden/openrabbit` repo at runtime
and execute its Python-based tools. No AI code lives in your repository.
## Workflows
### 1. Enterprise AI Code Review (`enterprise-ai-review.yml`)
- **Trigger**: Pull request opened or updated
- **What it does**: Automatically reviews PR diffs for code quality, bugs,
security issues, and style. Posts findings as PR comments.
- **Severity gating**: If the review finds HIGH severity issues, CI fails
(optional — see the `Check Review Result` step).
### 2. AI Issue Triage (`ai-issue-triage.yml`)
- **Trigger**: Comment containing `@codebot triage` on any issue
- **What it does**: Analyzes the issue content and applies appropriate labels,
priority, and category suggestions.
### 3. AI Comment Reply (`ai-comment-reply.yml`)
- **Trigger**: Comment containing a specific `@codebot` command
- **Supported commands**:
- `@codebot help` — show available commands
- `@codebot explain` — explain code or issue context
- `@codebot suggest` — suggest improvements
- `@codebot security` — security-focused analysis
- `@codebot summarize` — summarize a thread
- `@codebot changelog` — generate changelog entries
- `@codebot explain-diff` — explain PR diff
- `@codebot review-again` — re-run review
- `@codebot setup-labels` — configure repo labels
- **PR vs Issue**: Automatically detects whether the comment is on a PR or issue
and dispatches accordingly.
### 4. AI Chat (`ai-chat.yml`)
- **Trigger**: Comment mentioning `@codebot` that is NOT a known command
- **What it does**: Free-form AI chat. Ask the bot any question and it will
respond using the codebase context and optional web search (SearXNG).
- **Routing**: This is the fallback — only fires when no specific command matches.
### 5. AI Codebase Quality Review (`ai-codebase-review.yml`)
- **Trigger**: Manual (workflow_dispatch) or scheduled (weekly, commented out)
- **What it does**: Full codebase analysis generating a quality report.
- **Report types**: `full`, `security`, `quick` (selectable on manual trigger).
## Required Secrets
All AI workflows require these secrets in your repository
(Settings → Actions → Secrets):
| Secret | Required | Description |
|--------|----------|-------------|
| `AI_REVIEW_TOKEN` | Yes | Gitea PAT with repo access (to check out OpenRabbit and post comments) |
| `OPENAI_API_KEY` | Conditional | OpenAI API key (if using OpenAI models) |
| `OPENROUTER_API_KEY` | Conditional | OpenRouter API key (if using OpenRouter) |
| `OLLAMA_HOST` | Conditional | Ollama server URL (if using self-hosted models) |
| `SEARXNG_URL` | Optional | SearXNG instance URL for web search in AI chat |
At least one AI provider key (`OPENAI_API_KEY`, `OPENROUTER_API_KEY`, or
`OLLAMA_HOST`) must be set.
## Customization
### Changing the Bot Name
The default bot is `@codebot` (Gitea user: `Bartender`). To change it:
1. Update the `if:` conditions in all AI workflows to match your bot's mention prefix.
2. Update the `github.event.comment.user.login != 'Bartender'` check to your bot's username.
3. Update `config.yml` in the OpenRabbit tooling if applicable.
### Loop Prevention
All AI workflows check `github.event.comment.user.login != 'Bartender'` to
prevent the bot from responding to its own comments. This is critical —
without it, the bot can trigger infinite loops.
### Workflow Routing
The three comment-triggered workflows are carefully routed to avoid duplicates:
```
Issue comment with @codebot
├── Contains "triage"? → ai-issue-triage.yml
├── Contains known command? → ai-comment-reply.yml
└── Free-form mention? → ai-chat.yml (fallback)
```
## Enabling / Disabling
To disable AI workflows without deleting them, either:
- Remove the workflow files from `.gitea/workflows/`
- Or comment out the `on:` triggers in each file
To enable the scheduled codebase review, uncomment the `schedule` trigger
in `ai-codebase-review.yml`.

52
docs/CI.md Normal file
View File

@@ -0,0 +1,52 @@
# CI Pipeline — ${REPO_NAME}
## Overview
The CI workflow (`.gitea/workflows/ci.yml`) runs on every push and pull request.
It auto-detects the project type and runs the appropriate tools.
## Detection Logic
The workflow checks for project files in this order:
### Python Detection
- **Trigger**: `requirements.txt`, `setup.py`, or `pyproject.toml` exists
- **Actions**:
1. Set up Python 3.x
2. `pip install -r requirements.txt` (if present)
3. Install dev tools: ruff, black, flake8, pytest
4. **Lint**: Run ruff, black --check, and flake8 (each skipped if not installed)
5. **Test**: Run pytest (only if `tests/` dir or pytest config detected)
### Node.js Detection
- **Trigger**: `package.json` exists
- **Actions**:
1. Set up Node.js (LTS)
2. `npm ci`
3. **Lint**: `npm run lint` (only if "lint" script exists in package.json)
4. **Test**: `npm test` (only if "test" script exists)
5. **Build**: `npm run build` (only if "build" script exists)
### No Project Detected
- If neither Python nor Node.js files are found, the workflow prints a message
and exits successfully. **It never fails due to missing language detection.**
## Strict Mode
Controlled by `CI_STRICT` in `.ci/config.env`:
| CI_STRICT | Behavior |
|-----------|----------|
| `true` (default) | Lint/test failures cause the workflow to fail |
| `false` | Failures are logged as warnings; workflow succeeds |
Use `CI_STRICT=false` during early development when you want visibility
into issues without blocking merges.
## Adding Support for Other Languages
To add support for another language (Go, Rust, etc.):
1. Add a detection step similar to the Python/Node checks.
2. Add setup, lint, and test steps conditional on detection.
3. Follow the same CI_STRICT pattern for error handling.

100
docs/CONFIG.md Normal file
View File

@@ -0,0 +1,100 @@
# Configuration Reference — ${REPO_NAME}
All settings live in **`.ci/config.env`** and are loaded by every workflow at runtime.
## CI Settings
| Variable | Default | Description |
|----------|---------|-------------|
| `ENABLE_CI` | `true` | Master switch. If `false`, the CI workflow exits immediately. |
| `CI_STRICT` | `true` | If `true`, lint/test failures cause the workflow to fail. If `false`, they are logged as warnings only. |
| `DEFAULT_BRANCH` | `main` | The primary branch. Used by Docker and other workflows to determine branch-push behavior. |
## Docker Settings
| Variable | Default | Description |
|----------|---------|-------------|
| `ENABLE_DOCKER` | `true` | Master switch for Docker build steps. |
| `DOCKER_PUSH` | `false` | Whether to push images to the registry. **Safe default: off.** |
| `DOCKER_PUSH_ON_BRANCH` | `true` | Push when a commit lands on `DEFAULT_BRANCH`. Only effective if `DOCKER_PUSH=true`. |
| `DOCKER_PUSH_ON_TAG` | `true` | Push when a semver tag (`v*`) is pushed. Only effective if `DOCKER_PUSH=true`. |
| `REGISTRY_HOST` | `git.hiddenden.cafe` | Hostname of the container registry. |
| `IMAGE_OWNER` | `auto` | Image owner (org/user). `auto` = derived from repository context at runtime. |
| `IMAGE_NAME` | `auto` | Image name. `auto` = derived from repository name at runtime. |
| `DOCKER_TAG_STRATEGY` | `semver+latest` | Controls tagging. Options: `semver+latest`, `semver`, `branch`. |
### Tag Strategy Details
| Trigger | `semver+latest` | `semver` | `branch` |
|---------|-----------------|----------|----------|
| `v1.2.3` tag | `:1.2.3` + `:latest` | `:1.2.3` | — |
| Push to `main` | `:main` | `:main` | `:main` |
| Pull request | `:pr-<N>` (local only) | `:pr-<N>` (local only) | `:pr-<N>` (local only) |
## Security Settings
| Variable | Default | Description |
|----------|---------|-------------|
| `ENABLE_SECURITY` | `false` | Master switch. Enables gitleaks, osv-scanner, and Trivy. |
| `STRICT_SECURITY` | `false` | If `true`, any finding fails the workflow. If `false`, findings are warnings. |
## Renovate Settings
| Variable | Default | Description |
|----------|---------|-------------|
| `ENABLE_RENOVATE` | `false` | Master switch for Renovate dependency updates. |
| `RENOVATE_SCHEDULE` | `weekly` | How often Renovate runs. |
| `RENOVATE_PR_LIMIT` | `5` | Max open PRs Renovate can create. |
## Deploy Settings
| Variable | Default | Description |
|----------|---------|-------------|
| `ENABLE_DEPLOY` | `false` | Master switch. Deploy never runs unless `true`. |
| `DEPLOY_MODE` | `local-runner` | How to reach the VPS: `local-runner` (runs on VPS directly) or `ssh` (SSH from any runner). |
| `DEPLOY_RUNNER_LABEL` | `deploy-ovh` | Runner label for local-runner mode. Must match the act_runner's registered label. |
| `DEPLOY_WORKDIR` | `/opt/${REPO_NAME}` | Working directory on the VPS where your project lives. |
| `DEPLOY_STRATEGY` | `compose` | What to do on deploy: `compose` (docker compose up), `systemd` (restart service), or `script` (run custom script). |
| `DEPLOY_COMPOSE_FILE` | `docker-compose.yml` | Compose file path relative to `DEPLOY_WORKDIR`. Used with `compose` strategy. |
| `DEPLOY_SYSTEMD_SERVICE` | _(empty)_ | Systemd service name. Required if `DEPLOY_STRATEGY=systemd`. |
| `DEPLOY_SCRIPT` | `scripts/deploy.sh` | Custom deploy script path relative to repo root. Used with `script` strategy. |
| `DEPLOY_ON_TAG` | `false` | Also deploy when a `v*` tag is pushed. |
### Deploy Mode Comparison
| | `local-runner` | `ssh` |
|---|---|---|
| Secrets needed | None | `DEPLOY_SSH_KEY`, `DEPLOY_HOST`, `DEPLOY_USER` |
| Runner location | On the VPS | Any runner (e.g., shared) |
| Setup effort | Install act_runner on VPS | Create SSH key + add secrets |
| Network exposure | None | SSH port must be reachable |
See [docs/DEPLOY.md](DEPLOY.md) for full setup instructions.
## Recommended Defaults
For a **new public project**:
```env
ENABLE_CI=true
CI_STRICT=true
ENABLE_DOCKER=true
DOCKER_PUSH=false # Enable when ready to publish
ENABLE_SECURITY=false # Enable after initial development
ENABLE_RENOVATE=false # Enable after first release
ENABLE_DEPLOY=false # Enable when VPS runner is set up
```
For a **production project**:
```env
ENABLE_CI=true
CI_STRICT=true
ENABLE_DOCKER=true
DOCKER_PUSH=true
DOCKER_PUSH_ON_TAG=true
ENABLE_SECURITY=true
STRICT_SECURITY=true
ENABLE_RENOVATE=true
ENABLE_DEPLOY=true
DEPLOY_MODE=local-runner
DEPLOY_STRATEGY=compose
```

295
docs/DEPLOY.md Normal file
View File

@@ -0,0 +1,295 @@
# Deploy Workflow — ${REPO_NAME}
## Overview
The deploy workflow (`.gitea/workflows/deploy.yml`) automates deployment to a
VPS after a push to the default branch. It supports two modes and three
deployment strategies.
**Disabled by default.** Set `ENABLE_DEPLOY=true` in `.ci/config.env` to enable.
## Deployment Modes
### Mode A: Local Runner (Recommended)
The deploy job runs **directly on the VPS** via a self-hosted `act_runner`.
No SSH keys or network credentials needed — the runner already has local access.
```
┌──────────┐ push ┌──────────┐ runs-on: deploy-ovh ┌───────────┐
│ Developer │ ────────────► │ Gitea │ ────────────────────────► │ VPS │
│ │ │ Server │ │ act_runner│
└──────────┘ └──────────┘ │ (local) │
└───────────┘
```
**Pros:**
- No SSH secrets to manage
- No network exposure (runner is already on the VPS)
- Simpler setup, fewer moving parts
- Runner can access local Docker socket, systemd, files directly
**Cons:**
- Requires installing `act_runner` on the VPS
- One runner per VPS (or one runner with multiple labels)
### Mode B: SSH (Fallback)
The deploy job runs on **any runner** (e.g., shared ubuntu-latest) and SSHs
into the VPS to execute deploy commands remotely.
```
┌──────────┐ push ┌──────────┐ runs job ┌────────┐ SSH ┌─────┐
│ Developer │ ────────────► │ Gitea │ ──────────────► │ Runner │ ────────► │ VPS │
└──────────┘ └──────────┘ │(shared)│ └─────┘
└────────┘
```
**Pros:**
- Works without installing anything on the VPS
- Can deploy to VPSes you don't fully control
**Cons:**
- Requires SSH secrets (private key, host, user)
- VPS SSH port must be reachable from the runner
- More moving parts, more to go wrong
## Deploy Strategies
Regardless of mode, the workflow supports three strategies for what actually
happens on the VPS:
### `compose` (default)
```bash
cd /opt/myapp
docker compose -f docker-compose.yml pull
docker compose -f docker-compose.yml up -d
```
Best for: Docker Compose-based projects. Pulls latest images and recreates
containers with zero-downtime (depends on your compose config).
### `systemd`
```bash
sudo systemctl restart my-service
```
Best for: Applications managed as systemd services (e.g., a Go binary,
Python app with gunicorn, etc.).
### `script`
```bash
./scripts/deploy.sh /opt/myapp
```
Best for: Custom deploy logic that doesn't fit compose or systemd.
The script receives `DEPLOY_WORKDIR` as `$1`.
## Setup Guide
### Local Runner Mode
#### Step 1: Install act_runner on the VPS
```bash
# Download the latest act_runner binary
wget https://gitea.com/gitea/act_runner/releases/latest/download/act_runner-linux-amd64
chmod +x act_runner-linux-amd64
sudo mv act_runner-linux-amd64 /usr/local/bin/act_runner
```
#### Step 2: Register the runner with your label
```bash
# Register with Gitea (get the token from: Site Admin → Runners → Create)
act_runner register \
--instance https://git.hiddenden.cafe \
--token YOUR_RUNNER_TOKEN \
--labels deploy-ovh
# Or for repo-level: Repository Settings → Actions → Runners → Create
```
#### Step 3: Configure runner labels
The runner config file (usually `~/.config/act_runner/config.yaml` or next to
the binary) contains the labels:
```yaml
runner:
labels:
- "deploy-ovh:host"
```
The `:host` suffix means the job runs directly on the host (not in a container).
This is important for accessing Docker, systemd, and local files.
**After changing labels, restart the runner:**
```bash
sudo systemctl restart act_runner
```
#### Step 4: Update workflow runs-on
In `.gitea/workflows/deploy.yml`, the `deploy-local-runner` job has:
```yaml
runs-on: deploy-ovh
```
If you changed `DEPLOY_RUNNER_LABEL` in config.env, you **must also** update
this `runs-on` value in the workflow file to match. Gitea Actions does not
support dynamic `runs-on` from environment variables.
#### Step 5: Enable deploy
In `.ci/config.env`:
```env
ENABLE_DEPLOY=true
DEPLOY_MODE=local-runner
DEPLOY_RUNNER_LABEL=deploy-ovh
DEPLOY_WORKDIR=/opt/myapp
DEPLOY_STRATEGY=compose
```
#### Step 6: Verify VPS prerequisites
For `compose` strategy:
```bash
# Docker and compose plugin must be installed
docker --version
docker compose version
# The deploy workdir must exist with a docker-compose.yml
ls /opt/myapp/docker-compose.yml
```
For `systemd` strategy:
```bash
# The service must exist
systemctl cat my-service
```
For `script` strategy:
```bash
# The script must be in the repo and executable
```
### SSH Mode
#### Step 1: Create an SSH key
```bash
ssh-keygen -t ed25519 -C "deploy@gitea" -f deploy_key -N ""
```
#### Step 2: Add the public key to the VPS
```bash
ssh-copy-id -i deploy_key.pub user@your-vps
```
#### Step 3: Add secrets to Gitea
Go to **Repository Settings → Actions → Secrets** and add:
| Secret | Value |
|--------|-------|
| `DEPLOY_SSH_KEY` | Contents of `deploy_key` (private key) |
| `DEPLOY_HOST` | VPS IP or hostname |
| `DEPLOY_USER` | SSH username |
| `DEPLOY_KNOWN_HOSTS` | Output of `ssh-keyscan your-vps` (recommended) |
#### Step 4: Enable deploy
In `.ci/config.env`:
```env
ENABLE_DEPLOY=true
DEPLOY_MODE=ssh
DEPLOY_WORKDIR=/opt/myapp
DEPLOY_STRATEGY=compose
```
## Configuration Reference
| Variable | Default | Description |
|----------|---------|-------------|
| `ENABLE_DEPLOY` | `false` | Master switch. Deploy never runs unless `true`. |
| `DEPLOY_MODE` | `local-runner` | `local-runner` or `ssh` |
| `DEPLOY_RUNNER_LABEL` | `deploy-ovh` | Runner label for local-runner mode |
| `DEPLOY_WORKDIR` | `/opt/${REPO_NAME}` | Working directory on the VPS |
| `DEPLOY_STRATEGY` | `compose` | `compose`, `systemd`, or `script` |
| `DEPLOY_COMPOSE_FILE` | `docker-compose.yml` | Compose file path (relative to workdir) |
| `DEPLOY_SYSTEMD_SERVICE` | _(empty)_ | Systemd service name (required for systemd strategy) |
| `DEPLOY_SCRIPT` | `scripts/deploy.sh` | Deploy script path (relative to repo root) |
| `DEPLOY_ON_TAG` | `false` | Also deploy on `v*` tag pushes |
## Safety
### Branch Protection
The workflow only deploys from the `DEFAULT_BRANCH` (main). This is enforced
in two places:
1. **Trigger filter**: `on.push.branches: [main]`
2. **Branch guard step**: Runtime check comparing the actual ref to `DEFAULT_BRANCH`
### Never on Pull Requests
The `pull_request` event is intentionally absent from the trigger list.
Deploy cannot run on PRs.
### Protected Branches
For maximum safety, enable **branch protection** on `main` in Gitea:
1. Go to **Repository Settings → Branches → Branch Protection**
2. Enable for `main`
3. Require: status checks to pass, review approval, no force push
4. This ensures only reviewed, passing code reaches main → gets deployed
### Secrets
- **Local-runner mode**: No secrets needed. The runner has local access.
- **SSH mode**: Private key is written to a temp file, used once, then deleted.
It is never echoed to logs.
## Runner Label Examples
| Label | Description |
|-------|-------------|
| `deploy-ovh` | OVH VPS runner |
| `vps-prod` | Production VPS |
| `deploy-hetzner` | Hetzner VPS runner |
| `staging-runner` | Staging environment |
## Troubleshooting
### Local Runner Mode
- [ ] **Runner registered?** Check Gitea Admin → Runners or Repo Settings → Runners
- [ ] **Label matches?** `runs-on` in workflow must match the runner's label exactly
- [ ] **Runner online?** Check runner status in Gitea; restart if offline
- [ ] **Label suffix correct?** Use `:host` for direct host execution (not container)
- [ ] **Docker accessible?** Runner user must be in the `docker` group
- [ ] **Workdir exists?** `DEPLOY_WORKDIR` must exist and be readable
- [ ] **Compose file present?** Check `docker-compose.yml` exists in the workdir
- [ ] **Permissions?** For systemd: runner user needs sudo for systemctl
### SSH Mode
- [ ] **Secrets set?** Check all four secrets are in repo settings
- [ ] **Key format?** Private key must include `-----BEGIN` header
- [ ] **SSH port open?** VPS firewall must allow port 22 (or custom port) from runner
- [ ] **User permissions?** SSH user needs access to Docker/systemd/workdir
- [ ] **Known hosts?** Set `DEPLOY_KNOWN_HOSTS` for production (avoids MITM risk)
- [ ] **Key not passphrase-protected?** CI keys must have no passphrase
### General
- [ ] **ENABLE_DEPLOY=true?** Check `.ci/config.env`
- [ ] **Pushing to main?** Deploy only triggers on `DEFAULT_BRANCH`
- [ ] **Workflow file correct?** YAML syntax errors prevent the workflow from running
- [ ] **Check Actions tab** in Gitea for workflow run logs

104
docs/DOCKER.md Normal file
View File

@@ -0,0 +1,104 @@
# Docker Build & Registry — ${REPO_NAME}
## Overview
The Docker workflow (`.gitea/workflows/docker.yml`) builds Docker images and
optionally pushes them to the Gitea Container Registry.
## Gitea Container Registry Naming Convention
Gitea's registry follows this pattern:
```
{REGISTRY_HOST}/{OWNER}/{IMAGE}:{TAG}
```
Example:
```
git.hiddenden.cafe/myorg/myapp:1.2.3
```
This is different from Docker Hub (`docker.io/library/myapp:latest`).
The workflow enforces this format automatically.
## Dynamic Owner/Repo Derivation
The workflow dynamically determines the image owner and name so it works
for both user repos and organization repos without hardcoding.
**Logic:**
1. Determine `FULL_REPO` from (in priority order):
- `$GITEA_REPOSITORY` (Gitea native environment variable)
- `${{ github.repository }}` (Gitea Actions compatibility layer)
2. Split into `OWNER` (before `/`) and `REPO` (after `/`).
3. If `IMAGE_OWNER=auto` in config → use `OWNER`; else use the config value.
4. If `IMAGE_NAME=auto` in config → use `REPO`; else use the config value.
This means you rarely need to change `IMAGE_OWNER` or `IMAGE_NAME`.
## Triggers & Push Behavior
| Event | Build? | Push? | Condition |
|-------|--------|-------|-----------|
| Pull Request | Yes | **No** | Never pushes on PRs |
| Push to `main` | Yes | Conditional | `DOCKER_PUSH=true` AND `DOCKER_PUSH_ON_BRANCH=true` |
| Tag `v1.2.3` | Yes | Conditional | `DOCKER_PUSH=true` AND `DOCKER_PUSH_ON_TAG=true` |
**Safe default**: `DOCKER_PUSH=false` — images are built but never pushed.
## Tag Strategy
Controlled by `DOCKER_TAG_STRATEGY` in `.ci/config.env`:
### `semver+latest` (default)
- Tag `v1.2.3` → pushes `:1.2.3` and `:latest`
- Push to `main` → pushes `:main`
### `semver`
- Tag `v1.2.3` → pushes `:1.2.3` only
- Push to `main` → pushes `:main`
### `branch`
- Branch pushes only, tagged as `:branchname`
## Required Secrets
To push images, set these secrets in your Gitea repository
(Settings → Actions → Secrets):
| Secret | Description |
|--------|-------------|
| `REGISTRY_USERNAME` | Gitea username or bot account name |
| `REGISTRY_TOKEN` | Personal Access Token with `package:write` scope |
### Creating a PAT
1. Go to **Settings → Applications → Generate New Token**
2. Name: e.g., `ci-docker-push`
3. Scopes: select **`package`** (read + write)
4. Copy the token and add it as `REGISTRY_TOKEN` in repo secrets
**Why PAT instead of job token?**
Gitea Actions job tokens may not have sufficient permissions for the
container registry in all configurations. PATs are the recommended approach.
## Detection
The workflow auto-detects how to build:
1. **Dockerfile**`docker build -t <image>:<tag> .`
2. **docker-compose.yml**`docker compose build`
3. **Neither** → exits 0 with a message (graceful skip)
## Enabling Docker Push
1. Set `DOCKER_PUSH=true` in `.ci/config.env`
2. Add `REGISTRY_USERNAME` and `REGISTRY_TOKEN` secrets
3. Push a commit or tag — the workflow will build and push
## Pulling Images
After pushing, pull images with:
```bash
docker pull git.hiddenden.cafe/<owner>/<repo>:latest
```

101
docs/RENOVATE.md Normal file
View File

@@ -0,0 +1,101 @@
# Renovate — Automated Dependency Updates — ${REPO_NAME}
## Overview
[Renovate](https://docs.renovatebot.com/) automatically detects outdated
dependencies and opens PRs to update them. This keeps your project secure
and up-to-date with minimal manual effort.
**Disabled by default.** Set `ENABLE_RENOVATE=true` in `.ci/config.env` to enable.
## How It Works
1. The workflow (`.gitea/workflows/renovate.yml`) runs on a schedule (default: weekly).
2. Renovate scans your lockfiles and config for outdated packages.
3. It opens PRs with updates, grouped by minor/patch to reduce noise.
4. You review and merge the PRs.
## Setup
### Step 1: Create a Bot PAT
1. Create a dedicated Gitea user (e.g., `renovate-bot`) or use your own account.
2. Generate a PAT: **Settings → Applications → Generate New Token**
3. Scopes: `repo` (full repository access)
4. Copy the token.
### Step 2: Add the Secret
1. Go to **Repository Settings → Actions → Secrets**
2. Add secret: `RENOVATE_TOKEN` = the PAT from step 1
### Step 3: Enable in Config
In `.ci/config.env`:
```env
ENABLE_RENOVATE=true
RENOVATE_SCHEDULE=weekly
RENOVATE_PR_LIMIT=5
```
### Step 4: Commit and Push
Renovate will run on the next scheduled time, or you can trigger it manually
via the Actions tab → "Renovate" → "Run workflow".
## Configuration
### Workflow Config (.ci/config.env)
| Variable | Default | Description |
|----------|---------|-------------|
| `ENABLE_RENOVATE` | `false` | Master switch |
| `RENOVATE_SCHEDULE` | `weekly` | How often to run |
| `RENOVATE_PR_LIMIT` | `5` | Max open PRs at once |
### Renovate Config (renovate.json)
The `renovate.json` file in the repo root controls Renovate's behavior:
- **Grouping**: Minor and patch updates are grouped into a single PR.
- **Docker**: Base image updates (`FROM ...`) are enabled.
- **Labels**: PRs get the `dependencies` label.
- **Schedule**: Runs before 6am on Mondays.
Customize `renovate.json` to:
- Pin specific dependencies
- Exclude packages
- Change grouping strategy
- Add automerge for low-risk updates
### Docker Base Image Updates
Renovate will detect `FROM` lines in your Dockerfile and open PRs when
newer base images are available. This is enabled by default in `renovate.json`.
## Noise Control
To reduce PR spam:
1. **Group updates**: Already configured — minor/patch grouped together.
2. **Limit PRs**: `RENOVATE_PR_LIMIT=5` (adjust as needed).
3. **Schedule**: Runs weekly by default, not on every push.
4. **Automerge**: Add to `renovate.json` for trusted updates:
```json
{
"packageRules": [
{
"matchUpdateTypes": ["patch"],
"automerge": true
}
]
}
```
## Expected Behavior
After enabling, expect:
- An initial burst of PRs for all outdated dependencies
- Weekly batches of 1-5 PRs (depending on updates available)
- PRs labeled `dependencies` for easy filtering
- Each PR includes a changelog and compatibility notes