All checks were successful
Deploy server-up (dev) / deploy (push) Successful in 1m30s
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
178 lines
6.9 KiB
YAML
178 lines
6.9 KiB
YAML
name: Deploy server-up (prod)
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
tags: ['v*']
|
|
workflow_dispatch:
|
|
|
|
concurrency:
|
|
group: server-up-deploy-prod
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
deploy:
|
|
runs-on: [self-hosted, prod]
|
|
timeout-minutes: 20
|
|
|
|
env:
|
|
DEPLOY_DIR: /opt/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="main"
|
|
fi
|
|
echo "VERSION=${VERSION}" >> "$GITHUB_ENV"
|
|
echo "CHANNEL=${CHANNEL}" >> "$GITHUB_ENV"
|
|
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 --delete \
|
|
--exclude='.git/' \
|
|
--exclude='.forgejo/' \
|
|
--exclude='.env' \
|
|
./ "$DEPLOY_DIR/"
|
|
|
|
- name: Schrijf VERSION-bestand
|
|
run: |
|
|
set -euo pipefail
|
|
# Expliciet cd in plaats van 'working-directory:'; dat laatste wordt
|
|
# niet door elke runner even betrouwbaar toegepast.
|
|
cd "$DEPLOY_DIR"
|
|
echo "${VERSION}" > VERSION
|
|
echo "Werkmap: $(pwd)"
|
|
|
|
- name: Bouwen (en pushen naar de registry)
|
|
run: |
|
|
set -euo pipefail
|
|
cd "$DEPLOY_DIR"
|
|
# SU_TAG vastleggen zodat compose en de "Nu bijwerken"-knop in de app
|
|
# naar hetzelfde image wijzen (zie docs/updates.md).
|
|
#
|
|
# 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
|
|
|
|
# Draait deze server vanaf de registry (SU_IMAGE in .env), dan bouwen
|
|
# we hier én pushen we het resultaat, zodat de in-app updateknop het
|
|
# image kan ophalen. Bouwen en pushen zitten bewust in dezelfde job:
|
|
# een aparte build-workflow zou met deze deploy om de runner strijden.
|
|
export SU_TAG="${VERSION}"
|
|
SU_IMAGE="$(grep -E '^SU_IMAGE=' .env 2>/dev/null | cut -d= -f2- || true)"
|
|
docker compose build --pull
|
|
|
|
if [ -n "$SU_IMAGE" ]; then
|
|
echo "Registry-modus: ${SU_IMAGE}:${VERSION} pushen"
|
|
echo "${{ secrets.PACKAGE_TOKEN }}" \
|
|
| docker login "${{ vars.REGISTRY }}" -u "${{ vars.OWNER }}" --password-stdin
|
|
docker tag "${SU_IMAGE}:${VERSION}" "${SU_IMAGE}:${CHANNEL}" || true
|
|
docker push "${SU_IMAGE}:${VERSION}"
|
|
# Pre-releases krijgen geen 'latest': dat hoort bij stable.
|
|
case "$VERSION" in
|
|
*-*) docker tag "${SU_IMAGE}:${VERSION}" "${SU_IMAGE}:beta"
|
|
docker push "${SU_IMAGE}:beta" ;;
|
|
*) docker tag "${SU_IMAGE}:${VERSION}" "${SU_IMAGE}:latest"
|
|
docker push "${SU_IMAGE}:latest" ;;
|
|
esac
|
|
docker logout "${{ vars.REGISTRY }}" || true
|
|
else
|
|
echo "Lokale bouwmodus (geen SU_IMAGE ingesteld)"
|
|
docker tag "server-up:${VERSION}" "server-up:${CHANNEL}" || true
|
|
fi
|
|
|
|
- name: Deploy
|
|
run: |
|
|
set -euo pipefail
|
|
cd "$DEPLOY_DIR"
|
|
export SU_TAG="${VERSION}"
|
|
docker compose up -d --remove-orphans
|
|
docker compose ps
|
|
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|main) ' \
|
|
| tail -n +6 \
|
|
| awk '{print $2}' \
|
|
| xargs -r docker rmi -f || true
|
|
docker image prune -f
|