feat(renovate): add Gitea update automation
Run Renovate in Kubernetes to create reviewed image update PRs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
1 parent
6715f9e9af
commit
7288058df6
11 files changed
+331
No files matched your search
@@ -0,0 +1,45 @@
|
||||
name: renovate-ci
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
validate-renovate:
|
||||
runs-on: [self-hosted, linux, arch, homelab]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Validate Renovate Compose draft
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
trap 'rm -f renovate/.env' EXIT
|
||||
printf '%s\n' \
|
||||
'RENOVATE_ENDPOINT=https://gitea.example/api/v1' \
|
||||
'RENOVATE_TOKEN=test-token' \
|
||||
'RENOVATE_REPOSITORIES=forust/homelab' \
|
||||
> renovate/.env
|
||||
docker compose -f renovate/renovate-compose.yaml config --quiet
|
||||
|
||||
- name: Validate Kubernetes manifests
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
for manifest in renovate/k8s/namespace.yaml renovate/k8s/configmap.yaml renovate/k8s/cronjob.yaml; do
|
||||
kubectl apply --dry-run=client --validate=false -f "$manifest" >/dev/null
|
||||
done
|
||||
|
||||
- name: Validate Renovate repository config
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
docker run --rm \
|
||||
-v "$PWD:/work" \
|
||||
-w /work \
|
||||
renovate/renovate:44.83.2 \
|
||||
renovate-config-validator renovate.json
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:recommended"
|
||||
],
|
||||
"enabledManagers": [
|
||||
"docker-compose",
|
||||
"kubernetes"
|
||||
],
|
||||
"kubernetes": {
|
||||
"managerFilePatterns": [
|
||||
"/k8s/.+\\.ya?ml$/"
|
||||
]
|
||||
},
|
||||
"packageRules": [
|
||||
{
|
||||
"description": "Keep private homelab images unchanged",
|
||||
"matchDatasources": [
|
||||
"docker"
|
||||
],
|
||||
"matchPackageNames": [
|
||||
"/gcr\\.forust\\.xyz\\/forust\\/.+/"
|
||||
],
|
||||
"enabled": false
|
||||
},
|
||||
{
|
||||
"description": "Require approval for major upgrades",
|
||||
"matchUpdateTypes": [
|
||||
"major"
|
||||
],
|
||||
"dependencyDashboardApproval": true,
|
||||
"automerge": false
|
||||
},
|
||||
{
|
||||
"description": "Group container patch updates",
|
||||
"matchDatasources": [
|
||||
"docker"
|
||||
],
|
||||
"matchUpdateTypes": [
|
||||
"patch"
|
||||
],
|
||||
"groupName": "container patch updates"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
RENOVATE_ENDPOINT=https://gitea.forust.xyz/api/v1
|
||||
RENOVATE_TOKEN=
|
||||
RENOVATE_REPOSITORIES=forust/homelab
|
||||
LOG_LEVEL=info
|
||||
@@ -0,0 +1,59 @@
|
||||
# Renovate for Gitea
|
||||
|
||||
Renovate runs as a Kubernetes CronJob and creates container image update pull
|
||||
requests in Gitea. It does not deploy changes itself.
|
||||
|
||||
## Kubernetes
|
||||
|
||||
Create a dedicated Gitea user named `renovate-bot`, create a repository access
|
||||
token, and grant it repository read/write plus issue read/write permissions.
|
||||
Add `read:packages` if Renovate must inspect private Gitea registry images.
|
||||
|
||||
Create the ignored Secret locally; never commit the PAT:
|
||||
|
||||
```sh
|
||||
cp renovate/k8s/secrets.yaml.example renovate/k8s/secrets.yaml
|
||||
$EDITOR renovate/k8s/secrets.yaml
|
||||
kubectl apply -f renovate/k8s/namespace.yaml
|
||||
kubectl apply -f renovate/k8s/secrets.yaml
|
||||
kubectl apply -f renovate/k8s/configmap.yaml
|
||||
kubectl apply -f renovate/k8s/cronjob.yaml
|
||||
```
|
||||
|
||||
The `renovate/k8s/active` marker makes the normal deployment workflow include
|
||||
the namespace, ConfigMap, and CronJob. The Secret is intentionally excluded
|
||||
from Git and must be applied separately after every new cluster.
|
||||
|
||||
Run it immediately instead of waiting for the six-hour schedule:
|
||||
|
||||
```sh
|
||||
kubectl create job --from=cronjob/renovate renovate-manual-$(date +%s) -n renovate
|
||||
```
|
||||
|
||||
Inspect runs with:
|
||||
|
||||
```sh
|
||||
kubectl get cronjob,jobs,pods -n renovate
|
||||
kubectl logs -n renovate job/<job-name>
|
||||
```
|
||||
|
||||
`RENOVATE_GITHUB_COM_TOKEN` is optional but recommended for changelogs and
|
||||
GitHub API rate limits. Set it in the Kubernetes Secret if available.
|
||||
|
||||
## Compose
|
||||
|
||||
Copy `.env.example` to `.env`, set the PAT, and run:
|
||||
|
||||
```sh
|
||||
docker compose -f renovate-compose.yaml run --rm renovate
|
||||
```
|
||||
|
||||
The Compose file is intentionally named `renovate-compose.yaml`, so the
|
||||
repository's automatic deployment discovery does not start it accidentally.
|
||||
|
||||
## How updates flow
|
||||
|
||||
Renovate scans both `compose.yaml` files and Kubernetes manifests, opens a
|
||||
branch and PR with image tag changes, and waits for CI. After merge, the
|
||||
existing deployment workflow applies Kubernetes changes or redeploys Compose
|
||||
stacks. Renovate never updates running workloads directly.
|
||||
@@ -0,0 +1,41 @@
|
||||
module.exports = {
|
||||
platform: 'gitea',
|
||||
endpoint: process.env.RENOVATE_ENDPOINT,
|
||||
enabledManagers: ['docker-compose', 'kubernetes'],
|
||||
kubernetes: {
|
||||
managerFilePatterns: ['/k8s/.+\\.ya?ml$/'],
|
||||
},
|
||||
repositories: (process.env.RENOVATE_REPOSITORIES || '')
|
||||
.split(',')
|
||||
.map((repository) => repository.trim())
|
||||
.filter(Boolean),
|
||||
onboarding: false,
|
||||
requireConfig: 'optional',
|
||||
autodiscover: false,
|
||||
dependencyDashboard: true,
|
||||
prCreation: 'immediate',
|
||||
labels: ['dependencies', 'automated'],
|
||||
extends: [
|
||||
'config:recommended',
|
||||
':dependencyDashboard',
|
||||
],
|
||||
packageRules: [
|
||||
{
|
||||
description: 'Do not update private homelab images',
|
||||
matchDatasources: ['docker'],
|
||||
matchPackageNames: ['/gcr\\.forust\\.xyz\\/forust\\/.+/'],
|
||||
enabled: false,
|
||||
},
|
||||
{
|
||||
description: 'Keep major upgrades manual',
|
||||
matchUpdateTypes: ['major'],
|
||||
dependencyDashboardApproval: true,
|
||||
automerge: false,
|
||||
},
|
||||
{
|
||||
description: 'Group patch updates',
|
||||
matchUpdateTypes: ['patch'],
|
||||
groupName: 'container patch updates',
|
||||
},
|
||||
],
|
||||
};
|
||||
Whitespace-only changes.
@@ -0,0 +1,45 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: renovate-config
|
||||
namespace: renovate
|
||||
data:
|
||||
config.js: |
|
||||
module.exports = {
|
||||
platform: 'gitea',
|
||||
endpoint: process.env.RENOVATE_ENDPOINT,
|
||||
enabledManagers: ['docker-compose', 'kubernetes'],
|
||||
kubernetes: {
|
||||
managerFilePatterns: ['/k8s/.+\\.ya?ml$/'],
|
||||
},
|
||||
repositories: (process.env.RENOVATE_REPOSITORIES || '')
|
||||
.split(',')
|
||||
.map((repository) => repository.trim())
|
||||
.filter(Boolean),
|
||||
onboarding: false,
|
||||
requireConfig: 'optional',
|
||||
autodiscover: false,
|
||||
dependencyDashboard: true,
|
||||
prCreation: 'immediate',
|
||||
labels: ['dependencies', 'automated'],
|
||||
extends: ['config:recommended', ':dependencyDashboard'],
|
||||
packageRules: [
|
||||
{
|
||||
description: 'Do not update private homelab images',
|
||||
matchDatasources: ['docker'],
|
||||
matchPackageNames: ['/gcr\\.forust\\.xyz\\/forust\\/.+/'],
|
||||
enabled: false,
|
||||
},
|
||||
{
|
||||
description: 'Keep major upgrades manual',
|
||||
matchUpdateTypes: ['major'],
|
||||
dependencyDashboardApproval: true,
|
||||
automerge: false,
|
||||
},
|
||||
{
|
||||
description: 'Group patch updates',
|
||||
matchUpdateTypes: ['patch'],
|
||||
groupName: 'container patch updates',
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: renovate
|
||||
namespace: renovate
|
||||
spec:
|
||||
schedule: "17 */6 * * *"
|
||||
concurrencyPolicy: Forbid
|
||||
successfulJobsHistoryLimit: 2
|
||||
failedJobsHistoryLimit: 3
|
||||
jobTemplate:
|
||||
spec:
|
||||
backoffLimit: 1
|
||||
template:
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: renovate
|
||||
image: renovate/renovate:44.83.2
|
||||
env:
|
||||
- name: RENOVATE_PLATFORM
|
||||
value: gitea
|
||||
- name: RENOVATE_ENDPOINT
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: renovate-secrets
|
||||
key: RENOVATE_ENDPOINT
|
||||
- name: RENOVATE_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: renovate-secrets
|
||||
key: RENOVATE_TOKEN
|
||||
- name: RENOVATE_REPOSITORIES
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: renovate-secrets
|
||||
key: RENOVATE_REPOSITORIES
|
||||
- name: RENOVATE_CONFIG_FILE
|
||||
value: /opt/renovate/config.js
|
||||
- name: RENOVATE_BASE_DIR
|
||||
value: /tmp/renovate
|
||||
- name: RENOVATE_GITHUB_COM_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: renovate-secrets
|
||||
key: RENOVATE_GITHUB_COM_TOKEN
|
||||
optional: true
|
||||
- name: LOG_LEVEL
|
||||
value: info
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /opt/renovate/config.js
|
||||
subPath: config.js
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: renovate-config
|
||||
@@ -0,0 +1,6 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: renovate
|
||||
labels:
|
||||
app.kubernetes.io/part-of: renovate
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: renovate-secrets
|
||||
namespace: renovate
|
||||
type: Opaque
|
||||
stringData:
|
||||
RENOVATE_TOKEN: ""
|
||||
RENOVATE_ENDPOINT: "https://gitea.forust.xyz/api/v1"
|
||||
RENOVATE_REPOSITORIES: "forust/homelab"
|
||||
RENOVATE_GITHUB_COM_TOKEN: ""
|
||||
@@ -0,0 +1,17 @@
|
||||
services:
|
||||
renovate:
|
||||
image: renovate/renovate:44.83.2
|
||||
container_name: renovate
|
||||
restart: "no"
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
RENOVATE_PLATFORM: gitea
|
||||
RENOVATE_ENDPOINT: ${RENOVATE_ENDPOINT:?set RENOVATE_ENDPOINT}
|
||||
RENOVATE_TOKEN: ${RENOVATE_TOKEN:?set RENOVATE_TOKEN}
|
||||
RENOVATE_REPOSITORIES: ${RENOVATE_REPOSITORIES:?set RENOVATE_REPOSITORIES}
|
||||
RENOVATE_CONFIG_FILE: /opt/renovate/config.js
|
||||
RENOVATE_BASE_DIR: /tmp/renovate
|
||||
LOG_LEVEL: ${LOG_LEVEL:-info}
|
||||
volumes:
|
||||
- ./config.js:/opt/renovate/config.js:ro
|
||||
Reference in new issue
Block a user