server-up/.forgejo/workflows/deploy.yml
Ramon 34a48fb74a
All checks were successful
Deploy server-up (dev) / deploy (push) Successful in 1m30s
ci: deploy mag niet stranden op een .env van een andere gebruiker
De stap "Instellingen en versie klaarzetten" faalde op `touch: cannot touch
'.env': Permission denied`. Het bestand was met sudo aangemaakt en dus van
root, terwijl de runner als een gewone gebruiker draait. Daarmee brak de hele
deploy af op iets dat geen blokkade hoort te zijn.

- SU_TAG wordt nu altijd via de omgeving aan `docker compose` meegegeven
  (export SU_TAG). Het wegschrijven in .env blijft de voorkeur, omdat het een
  handmatige `docker compose up` overleeft, maar het is niet meer nodig om te
  kunnen deployen.
- Is .env niet schrijfbaar, dan meldt de log wie de eigenaar is en welk
  chown-commando dat rechtzet, en loopt de deploy gewoon door.
- Het aanmaken vanuit .env.example faalt niet meer hard.

Positief neveneffect van de vorige fix: de log toont nu "Werkmap:
/opt/docker/server-up", dus de cd landt op de juiste plek.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb
2026-07-27 00:46:30 +02:00

156 lines
No EOL
5.8 KiB
YAML

name: Deploy server-up (dev)
on:
push:
branches: [dev]
workflow_dispatch:
concurrency:
group: server-up-deploy-dev
cancel-in-progress: false
jobs:
deploy:
runs-on: [self-hosted, dev]
timeout-minutes: 20
env:
DEPLOY_DIR: /opt/docker/server-up
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Bepaal versie
id: version
run: |
set -euo pipefail
BASE="$(tr -d '[:space:]' < VERSION 2>/dev/null || echo 0.0.0)"
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
VERSION="${GITHUB_REF_NAME#v}"
CHANNEL="release"
else
VERSION="${BASE}"
CHANNEL="dev"
fi
echo "VERSION=${VERSION}" >> "$GITHUB_ENV"
echo "CHANNEL=${CHANNEL}" >> "$GITHUB_ENV"
# SU_VERSION wordt door docker compose gebruikt als build-arg
echo "SU_VERSION=${VERSION}" >> "$GITHUB_ENV"
echo "Deploying version: ${VERSION} (${CHANNEL})"
- name: Tests draaien
run: |
set -euo pipefail
# In een container in plaats van een venv op de runner: die heeft
# geen python3-venv, en zo draaien de tests bovendien op exact de
# Python-versie waarop de app in productie draait.
# PYTHONDONTWRITEBYTECODE + no:cacheprovider voorkomen dat er
# root-eigen bestanden in de werkmap achterblijven.
docker run --rm \
-v "$PWD:/w" -w /w \
-v su-pip-cache:/root/.cache/pip \
-e PYTHONDONTWRITEBYTECODE=1 \
python:3.12-slim \
sh -c "pip install -q -r server-up/requirements.txt pytest \
&& python -m pytest tests -q -p no:cacheprovider"
- name: Sync code naar deploy-directory
run: |
set -euo pipefail
# .env staat in .gitignore, dus de checkout heeft er geen. Zonder deze
# uitzondering wist --delete de lokale instellingen van de server
# (BIND, SU_IMAGE, PORT) bij elke deploy.
rsync -a --no-group --delete \
--exclude='.git/' \
--exclude='.forgejo/' \
--exclude='.env' \
./ "$DEPLOY_DIR/"
- name: Instellingen en versie klaarzetten
run: |
set -euo pipefail
# Expliciet cd in plaats van 'working-directory:'. Dat laatste wordt
# niet door elke runner-implementatie even betrouwbaar toegepast, en
# als het misgaat belanden VERSION, .env en de container stilletjes in
# de werkmap van de runner in plaats van in de deploy-map.
cd "$DEPLOY_DIR"
echo "Werkmap: $(pwd)"
echo "${VERSION}" > VERSION
# SU_TAG bepaalt welk image compose start. We schrijven dat bij
# voorkeur in .env zodat het een handmatige `docker compose up`
# overleeft, maar dat bestand kan van een andere gebruiker zijn (bv.
# met sudo aangemaakt). Lukt schrijven niet, dan geven we SU_TAG mee
# via de omgeving: compose gebruikt die en de deploy loopt gewoon door.
if [ ! -f .env ] && [ -f .env.example ]; then
cp .env.example .env 2>/dev/null \
&& echo "Nieuwe .env aangemaakt vanuit .env.example" \
|| echo "LET OP: kon geen .env aanmaken in $(pwd)"
fi
if [ -w .env ] || { [ ! -e .env ] && [ -w . ]; }; then
touch .env
sed -i '/^SU_TAG=/d' .env
echo "SU_TAG=${VERSION}" >> .env
echo "Inhoud van $(pwd)/.env:"
grep -vE '^\s*(#|$)' .env | sed 's/^/ /'
else
echo "LET OP: $(pwd)/.env is niet schrijfbaar voor $(id -un)."
echo " Eigenaar: $(stat -c '%U:%G %a' .env 2>/dev/null || echo onbekend)"
echo " Herstel eenmalig met:"
echo " sudo chown $(stat -c '%U:%G' . ) $(pwd)/.env"
echo " SU_TAG wordt nu via de omgeving meegegeven."
fi
- name: Build image
run: |
set -euo pipefail
cd "$DEPLOY_DIR"
export SU_TAG="${VERSION}"
docker compose build --pull
docker tag "server-up:${VERSION}" "server-up:${CHANNEL}" || true
- name: Deploy
run: |
set -euo pipefail
cd "$DEPLOY_DIR"
export SU_TAG="${VERSION}"
docker compose up -d --remove-orphans
docker compose ps
# Waar draait de container vandaan, en op welk adres luistert hij?
echo "Compose-projectmap volgens de container:"
docker inspect server-up \
--format ' {{index .Config.Labels "com.docker.compose.project.working_dir"}}'
echo "Poortbinding:"
docker inspect server-up \
--format ' {{range $p, $c := .NetworkSettings.Ports}}{{$p}} -> {{range $c}}{{.HostIp}}:{{.HostPort}}{{end}}{{"\n"}}{{end}}'
- name: Wachten op healthcheck
run: |
set -euo pipefail
for i in {1..40}; do
status=$(docker inspect --format '{{.State.Health.Status}}' server-up 2>/dev/null || echo "starting")
echo "poll $i: $status"
if [ "$status" = "healthy" ]; then
echo "server-up is healthy als versie ${VERSION}"
exit 0
fi
sleep 3
done
echo "server-up werd niet healthy in tijd — logs:"
cd "$DEPLOY_DIR" && docker compose logs --tail=200
exit 1
- name: Oude images opruimen (behoud laatste 5)
if: success()
run: |
docker images server-up --format '{{.Tag}} {{.ID}}' \
| grep -vE '^(latest|release|dev) ' \
| tail -n +6 \
| awk '{print $2}' \
| xargs -r docker rmi -f || true
docker image prune -f