Compare commits

...

2 Commits

Author SHA1 Message Date
Admin
3f436877ee fix: pocketbase healthcheck (add wget) + saveIfAbsent infinite recursion
Some checks failed
Release / Test backend (push) Successful in 1m6s
Release / Check ui (push) Successful in 1m56s
Release / Docker (push) Successful in 8m19s
Release / Deploy to prod (push) Failing after 36s
Release / Gitea Release (push) Successful in 22s
- Add wget to pocketbase Alpine image so the docker-compose healthcheck
  (wget http://localhost:8090/api/health) can actually run
- Fix saveIfAbsent calling itself instead of app.Save(c) — was an
  infinite recursion that would stack-overflow on a fresh install

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 18:05:02 +05:00
Admin
812028e50d ci: add pocketbase image build + automated prod deploy step
Some checks failed
Release / Test backend (push) Successful in 5m39s
Release / Check ui (push) Successful in 2m1s
Release / Docker (push) Successful in 7m46s
Release / Deploy to prod (push) Failing after 1m53s
Release / Gitea Release (push) Successful in 35s
release.yaml:
  - Build and push kalekber/libnovel-pocketbase image on every release tag
  - Add deploy job (runs after docker): copies docker-compose.yml from the
    tagged commit to /opt/libnovel on prod, pulls new images, restarts
    changed services with --remove-orphans (cleans up removed pb-init)

ci.yaml:
  - Validate cmd/pocketbase builds on every branch push

Required new Gitea secrets: PROD_HOST, PROD_USER, PROD_SSH_KEY,
PROD_SSH_KNOWN_HOSTS (see deploy job comments for instructions).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 11:06:27 +05:00
4 changed files with 68 additions and 2 deletions

View File

@@ -41,6 +41,9 @@ jobs:
- name: Build healthcheck
run: go build -o /dev/null ./cmd/healthcheck
- name: Build pocketbase
run: go build -o /dev/null ./cmd/pocketbase
- name: Run tests
run: go test -short -race -count=1 -timeout=60s ./...

View File

@@ -276,6 +276,69 @@ jobs:
cache-from: type=registry,ref=${{ secrets.DOCKER_USER }}/libnovel-caddy:latest
cache-to: type=inline
# ── pocketbase ───────────────────────────────────────────────────────────
- name: Docker meta / pocketbase
id: meta-pocketbase
uses: docker/metadata-action@v5
with:
images: ${{ secrets.DOCKER_USER }}/libnovel-pocketbase
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest
- name: Build and push / pocketbase
uses: docker/build-push-action@v6
with:
context: backend
target: pocketbase
push: true
tags: ${{ steps.meta-pocketbase.outputs.tags }}
labels: ${{ steps.meta-pocketbase.outputs.labels }}
cache-from: type=registry,ref=${{ secrets.DOCKER_USER }}/libnovel-pocketbase:latest
cache-to: type=inline
# ── deploy: sync docker-compose.yml + restart prod ───────────────────────────
# Runs after all images are pushed to Docker Hub.
# Copies the compose file from the tagged commit to the server, pulls the new
# images, and restarts only the services whose image or config changed.
# --remove-orphans cleans up containers no longer defined in the compose file
# (e.g. the now-removed pb-init container).
#
# Required Gitea secrets:
# PROD_HOST — prod server IP or hostname
# PROD_USER — SSH login user (typically root)
# PROD_SSH_KEY — private key whose public half is in authorized_keys
# PROD_SSH_KNOWN_HOSTS — output of: ssh-keyscan -H <PROD_HOST>
deploy:
name: Deploy to prod
runs-on: ubuntu-latest
needs: [docker]
steps:
- uses: actions/checkout@v4
- name: Install SSH key
run: |
mkdir -p ~/.ssh
printf '%s\n' "${{ secrets.PROD_SSH_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
printf '%s\n' "${{ secrets.PROD_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
- name: Copy docker-compose.yml to prod
run: |
scp -i ~/.ssh/deploy_key \
docker-compose.yml \
"${{ secrets.PROD_USER }}@${{ secrets.PROD_HOST }}:/opt/libnovel/docker-compose.yml"
- name: Pull new images and restart changed services
run: |
ssh -i ~/.ssh/deploy_key \
"${{ secrets.PROD_USER }}@${{ secrets.PROD_HOST }}" \
'set -euo pipefail
cd /opt/libnovel
doppler run -- docker compose pull
doppler run -- docker compose up -d --remove-orphans'
# ── Gitea release ─────────────────────────────────────────────────────────────
release:
name: Gitea Release

View File

@@ -48,7 +48,7 @@ ENTRYPOINT ["/backend"]
# On every `serve` startup it applies any pending migrations automatically.
# Data is stored in /pb_data (mounted as a Docker volume in production).
FROM alpine:3.21 AS pocketbase
RUN apk add --no-cache ca-certificates && \
RUN apk add --no-cache ca-certificates wget && \
addgroup -S appgroup && adduser -S appuser -G appgroup
COPY --from=builder /out/pocketbase /pocketbase
RUN mkdir -p /pb_data && chown appuser:appgroup /pb_data

View File

@@ -81,7 +81,7 @@ func saveIfAbsent(app core.App, c *core.Collection) error {
if _, err := app.FindCollectionByNameOrId(c.Name); err == nil {
return nil // already exists — skip
}
return saveIfAbsent(app, c)
return app.Save(c)
}
// ── Collection creators ───────────────────────────────────────────────────────