# ============================================================================= # Deploy SQLInsight Pro-webstedet (sqlinsight.seosoft.dk) til appserveren ved push til main. # # Samme mønster som deploy-hub.yml: runneren er host-mode, så .env og compose-filen skrives til INSTALL_DIR # via en kortlivet helper-container, og 'docker compose up' køres i docker:cli. # # Påkrævede secrets: HOST_BIND COMMUNITY_PORT COMMUNITY_CONTACT # Valgfri: TRUSTED_KEY_ID + TRUSTED_KEY (offentlig nøgle, som feedet er signeret med, hvis den ikke er indbygget) # ============================================================================= name: deploy community on: push: branches: [main] paths: - "src/**" - "docs/**" - "rules/**" - "deploy/community/**" - "Directory.*.props" - "global.json" - ".forgejo/workflows/deploy-community.yml" workflow_dispatch: concurrency: group: deploy-sqlinsight-community cancel-in-progress: false env: INSTALL_DIR: /opt/sqlinsight-community IMAGE: sqlinsight-community CONTAINER: sqlinsight-community jobs: deploy: runs-on: [self-hosted, appserver] timeout-minutes: 30 steps: - name: Configured? id: check env: COMMUNITY_PORT: ${{ secrets.COMMUNITY_PORT }} run: | # Indtil secrets er sat, springes deploy over i stedet for at fejle hvert push. if [ -n "${COMMUNITY_PORT:-}" ]; then echo "configured=true" >> "$GITHUB_OUTPUT" else echo "::warning::COMMUNITY_PORT er ikke sat; webstedet deployes ikke (se docs/community.md)" echo "configured=false" >> "$GITHUB_OUTPUT" fi - name: Checkout if: steps.check.outputs.configured == 'true' uses: actions/checkout@v4 - name: Build image if: steps.check.outputs.configured == 'true' run: | set -e docker build -f deploy/community/Dockerfile -t "${IMAGE}:latest" -t "${IMAGE}:${{ github.sha }}" . - name: Write .env + docker-compose.yml to INSTALL_DIR if: steps.check.outputs.configured == 'true' env: HOST_BIND: ${{ secrets.HOST_BIND }} COMMUNITY_PORT: ${{ secrets.COMMUNITY_PORT }} COMMUNITY_CONTACT: ${{ secrets.COMMUNITY_CONTACT }} TRUSTED_KEY_ID: ${{ secrets.TRUSTED_KEY_ID }} TRUSTED_KEY: ${{ secrets.TRUSTED_KEY }} run: | set -eu required="HOST_BIND COMMUNITY_PORT COMMUNITY_CONTACT" missing=0 for v in $required; do if [ -z "$(printenv "$v" || true)" ]; then echo "ERROR: required secret $v is not set in repo settings" missing=1 fi done [ "$missing" -eq 0 ] || exit 1 for v in $required TRUSTED_KEY_ID TRUSTED_KEY; do case "$(printenv "$v" || true)" in *"'"*|*";"*) echo "ERROR: secret $v indeholder ' eller ; – ikke understøttet"; exit 1 ;; esac done tmp="$(mktemp -d)" { printf "HOST_BIND='%s'\n" "$HOST_BIND" printf "COMMUNITY_PORT='%s'\n" "$COMMUNITY_PORT" printf "SQLInsight__Community__ContactEmail='%s'\n" "$COMMUNITY_CONTACT" if [ -n "${TRUSTED_KEY_ID:-}" ] && [ -n "${TRUSTED_KEY:-}" ]; then printf "SQLInsight__Community__TrustedKeys__%s='%s'\n" "$TRUSTED_KEY_ID" "$TRUSTED_KEY" fi } > "$tmp/.env" cp deploy/community/docker-compose.prod.yml "$tmp/docker-compose.yml" tar -C "$tmp" -cf - .env docker-compose.yml | docker run --rm -i \ -v "${INSTALL_DIR}:/out" alpine:3 \ sh -c 'tar -C /out -xf - && chown root:root /out/.env /out/docker-compose.yml && chmod 600 /out/.env && chmod 644 /out/docker-compose.yml' rm -rf "$tmp" - name: Deploy (compose up) if: steps.check.outputs.configured == 'true' run: | set -eu docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ -v "${INSTALL_DIR}:${INSTALL_DIR}" \ -w "${INSTALL_DIR}" \ docker:cli \ docker compose --project-name sqlinsight-community up -d --force-recreate --remove-orphans - name: Wait for /health if: steps.check.outputs.configured == 'true' env: HOST_BIND: ${{ secrets.HOST_BIND }} COMMUNITY_PORT: ${{ secrets.COMMUNITY_PORT }} run: | set -eu for i in $(seq 1 30); do if docker run --rm alpine:3 wget -qO- -T 3 "http://${HOST_BIND}:${COMMUNITY_PORT}/health" 2>/dev/null | grep -q '"ok"'; then echo "${CONTAINER} is healthy" exit 0 fi echo "attempt $i: not ready" sleep 5 done echo "${CONTAINER} did not answer /health within 150s — last 100 log lines:" docker logs --tail 100 "${CONTAINER}" || true exit 1 - name: Prune old images if: always() && steps.check.outputs.configured == 'true' run: | docker image prune -f || true docker images "${IMAGE}" --format '{{.Tag}} {{.CreatedAt}}' \ | grep -v '^latest ' | sort -k2 -r | awk 'NR>3 {print $1}' \ | xargs -r -I{} docker image rm "${IMAGE}:{}" || true