diff --git a/.gitea/workflows/ci-v3.yaml b/.gitea/workflows/ci-v3.yaml index 9ea014f..12a4817 100644 --- a/.gitea/workflows/ci-v3.yaml +++ b/.gitea/workflows/ci-v3.yaml @@ -4,12 +4,18 @@ on: push: branches: ["main", "master"] paths: - - "v3/**" + - "backend/**" + - "ui/**" + - "caddy/**" + - "docker-compose.yml" - ".gitea/workflows/ci-v3.yaml" pull_request: branches: ["main", "master"] paths: - - "v3/**" + - "backend/**" + - "ui/**" + - "caddy/**" + - "docker-compose.yml" - ".gitea/workflows/ci-v3.yaml" concurrency: @@ -17,7 +23,7 @@ concurrency: cancel-in-progress: true jobs: - # ── backend: lint & test ───────────────────────────────────────────────────── + # ── backend: vet & test ─────────────────────────────────────────────────────── test-backend: name: Test backend runs-on: ubuntu-latest @@ -26,24 +32,24 @@ jobs: - uses: actions/setup-go@v5 with: - go-version-file: v3/backend/go.mod - cache-dependency-path: v3/backend/go.sum + go-version-file: backend/go.mod + cache-dependency-path: backend/go.sum - name: go vet - working-directory: v3/backend + working-directory: backend run: go vet ./... - name: Run tests - working-directory: v3/backend + working-directory: backend run: go test -short -race -count=1 -timeout=60s ./... - # ── ui: type-check ─────────────────────────────────────────────────────────── + # ── ui: type-check & build ──────────────────────────────────────────────────── check-ui: name: Check ui runs-on: ubuntu-latest defaults: run: - working-directory: v3/ui + working-directory: ui steps: - uses: actions/checkout@v4 @@ -51,7 +57,7 @@ jobs: with: node-version: "22" cache: npm - cache-dependency-path: v3/ui/package-lock.json + cache-dependency-path: ui/package-lock.json - name: Install dependencies run: npm ci @@ -62,7 +68,7 @@ jobs: - name: Build run: npm run build - # ── docker: backend (push to Docker Hub on branch push only) ───────────────── + # ── docker: backend ─────────────────────────────────────────────────────────── docker-backend: name: Docker / backend runs-on: ubuntu-latest @@ -71,6 +77,8 @@ jobs: steps: - uses: actions/checkout@v4 + - uses: docker/setup-buildx-action@v3 + - name: Log in to Docker Hub uses: docker/login-action@v3 with: @@ -80,15 +88,17 @@ jobs: - name: Build and push uses: docker/build-push-action@v6 with: - context: v3/backend + context: backend target: backend push: true tags: | - ${{ secrets.DOCKER_USER }}/libnovel-v3-backend:latest - ${{ secrets.DOCKER_USER }}/libnovel-v3-backend:${{ gitea.sha }} + ${{ secrets.DOCKER_USER }}/libnovel-backend:latest + ${{ secrets.DOCKER_USER }}/libnovel-backend:${{ gitea.sha }} build-args: | VERSION=${{ gitea.sha }} COMMIT=${{ gitea.sha }} + cache-from: type=registry,ref=${{ secrets.DOCKER_USER }}/libnovel-backend:latest + cache-to: type=inline # ── docker: runner ──────────────────────────────────────────────────────────── docker-runner: @@ -99,6 +109,8 @@ jobs: steps: - uses: actions/checkout@v4 + - uses: docker/setup-buildx-action@v3 + - name: Log in to Docker Hub uses: docker/login-action@v3 with: @@ -108,15 +120,17 @@ jobs: - name: Build and push uses: docker/build-push-action@v6 with: - context: v3/backend + context: backend target: runner push: true tags: | - ${{ secrets.DOCKER_USER }}/libnovel-v3-runner:latest - ${{ secrets.DOCKER_USER }}/libnovel-v3-runner:${{ gitea.sha }} + ${{ secrets.DOCKER_USER }}/libnovel-runner:latest + ${{ secrets.DOCKER_USER }}/libnovel-runner:${{ gitea.sha }} build-args: | VERSION=${{ gitea.sha }} COMMIT=${{ gitea.sha }} + cache-from: type=registry,ref=${{ secrets.DOCKER_USER }}/libnovel-runner:latest + cache-to: type=inline # ── docker: ui ──────────────────────────────────────────────────────────────── docker-ui: @@ -127,6 +141,8 @@ jobs: steps: - uses: actions/checkout@v4 + - uses: docker/setup-buildx-action@v3 + - name: Log in to Docker Hub uses: docker/login-action@v3 with: @@ -136,11 +152,40 @@ jobs: - name: Build and push uses: docker/build-push-action@v6 with: - context: v3/ui + context: ui push: true tags: | - ${{ secrets.DOCKER_USER }}/libnovel-v3-ui:latest - ${{ secrets.DOCKER_USER }}/libnovel-v3-ui:${{ gitea.sha }} + ${{ secrets.DOCKER_USER }}/libnovel-ui:latest + ${{ secrets.DOCKER_USER }}/libnovel-ui:${{ gitea.sha }} build-args: | BUILD_VERSION=${{ gitea.sha }} BUILD_COMMIT=${{ gitea.sha }} + cache-from: type=registry,ref=${{ secrets.DOCKER_USER }}/libnovel-ui:latest + cache-to: type=inline + + # ── docker: caddy ───────────────────────────────────────────────────────────── + docker-caddy: + name: Docker / caddy + runs-on: ubuntu-latest + if: gitea.event_name == 'push' + steps: + - uses: actions/checkout@v4 + + - uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USER }} + password: ${{ secrets.DOCKER_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: caddy + push: true + tags: | + ${{ secrets.DOCKER_USER }}/libnovel-caddy:latest + ${{ secrets.DOCKER_USER }}/libnovel-caddy:${{ gitea.sha }} + cache-from: type=registry,ref=${{ secrets.DOCKER_USER }}/libnovel-caddy:latest + cache-to: type=inline diff --git a/.gitea/workflows/release-v3.yaml b/.gitea/workflows/release-v3.yaml index 5e733b0..f126719 100644 --- a/.gitea/workflows/release-v3.yaml +++ b/.gitea/workflows/release-v3.yaml @@ -3,15 +3,14 @@ name: Release / v3 on: push: tags: - - "v3/*" # e.g. v3/1.0.0, v3/1.2.3 - - "v3-*" # e.g. v3-1.0.0 (alternative convention) + - "v*" # e.g. v1.0.0, v1.2.3 concurrency: group: ${{ gitea.workflow }}-${{ gitea.ref }} cancel-in-progress: true jobs: - # ── backend: lint & test ───────────────────────────────────────────────────── + # ── backend: vet & test ─────────────────────────────────────────────────────── test-backend: name: Test backend runs-on: ubuntu-latest @@ -20,24 +19,24 @@ jobs: - uses: actions/setup-go@v5 with: - go-version-file: v3/backend/go.mod - cache-dependency-path: v3/backend/go.sum + go-version-file: backend/go.mod + cache-dependency-path: backend/go.sum - name: go vet - working-directory: v3/backend + working-directory: backend run: go vet ./... - name: Run tests - working-directory: v3/backend + working-directory: backend run: go test -short -race -count=1 -timeout=60s ./... - # ── ui: type-check & build ─────────────────────────────────────────────────── + # ── ui: type-check & build ──────────────────────────────────────────────────── check-ui: name: Check ui runs-on: ubuntu-latest defaults: run: - working-directory: v3/ui + working-directory: ui steps: - uses: actions/checkout@v4 @@ -45,7 +44,7 @@ jobs: with: node-version: "22" cache: npm - cache-dependency-path: v3/ui/package-lock.json + cache-dependency-path: ui/package-lock.json - name: Install dependencies run: npm ci @@ -64,6 +63,8 @@ jobs: steps: - uses: actions/checkout@v4 + - uses: docker/setup-buildx-action@v3 + - name: Log in to Docker Hub uses: docker/login-action@v3 with: @@ -74,15 +75,16 @@ jobs: id: meta uses: docker/metadata-action@v5 with: - images: ${{ secrets.DOCKER_USER }}/libnovel-v3-backend + images: ${{ secrets.DOCKER_USER }}/libnovel-backend tags: | - type=match,pattern=v3/(.*),group=1 + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} type=raw,value=latest - name: Build and push uses: docker/build-push-action@v6 with: - context: v3/backend + context: backend target: backend push: true tags: ${{ steps.meta.outputs.tags }} @@ -90,6 +92,8 @@ jobs: build-args: | VERSION=${{ steps.meta.outputs.version }} COMMIT=${{ gitea.sha }} + cache-from: type=registry,ref=${{ secrets.DOCKER_USER }}/libnovel-backend:latest + cache-to: type=inline # ── docker: runner ──────────────────────────────────────────────────────────── docker-runner: @@ -99,6 +103,8 @@ jobs: steps: - uses: actions/checkout@v4 + - uses: docker/setup-buildx-action@v3 + - name: Log in to Docker Hub uses: docker/login-action@v3 with: @@ -109,15 +115,16 @@ jobs: id: meta uses: docker/metadata-action@v5 with: - images: ${{ secrets.DOCKER_USER }}/libnovel-v3-runner + images: ${{ secrets.DOCKER_USER }}/libnovel-runner tags: | - type=match,pattern=v3/(.*),group=1 + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} type=raw,value=latest - name: Build and push uses: docker/build-push-action@v6 with: - context: v3/backend + context: backend target: runner push: true tags: ${{ steps.meta.outputs.tags }} @@ -125,6 +132,8 @@ jobs: build-args: | VERSION=${{ steps.meta.outputs.version }} COMMIT=${{ gitea.sha }} + cache-from: type=registry,ref=${{ secrets.DOCKER_USER }}/libnovel-runner:latest + cache-to: type=inline # ── docker: ui ──────────────────────────────────────────────────────────────── docker-ui: @@ -134,6 +143,8 @@ jobs: steps: - uses: actions/checkout@v4 + - uses: docker/setup-buildx-action@v3 + - name: Log in to Docker Hub uses: docker/login-action@v3 with: @@ -144,27 +155,65 @@ jobs: id: meta uses: docker/metadata-action@v5 with: - images: ${{ secrets.DOCKER_USER }}/libnovel-v3-ui + images: ${{ secrets.DOCKER_USER }}/libnovel-ui tags: | - type=match,pattern=v3/(.*),group=1 + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} type=raw,value=latest - name: Build and push uses: docker/build-push-action@v6 with: - context: v3/ui + context: ui push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-args: | BUILD_VERSION=${{ steps.meta.outputs.version }} BUILD_COMMIT=${{ gitea.sha }} + cache-from: type=registry,ref=${{ secrets.DOCKER_USER }}/libnovel-ui:latest + cache-to: type=inline + + # ── docker: caddy ───────────────────────────────────────────────────────────── + docker-caddy: + name: Docker / caddy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USER }} + password: ${{ secrets.DOCKER_TOKEN }} + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ secrets.DOCKER_USER }}/libnovel-caddy + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=latest + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: caddy + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=${{ secrets.DOCKER_USER }}/libnovel-caddy:latest + cache-to: type=inline # ── Gitea release ───────────────────────────────────────────────────────────── release: name: Gitea Release runs-on: ubuntu-latest - needs: [docker-backend, docker-runner, docker-ui] + needs: [docker-backend, docker-runner, docker-ui, docker-caddy] steps: - uses: actions/checkout@v4 with: diff --git a/docker-compose.yml b/docker-compose.yml index bb258a6..61c514f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -128,6 +128,7 @@ services: # ─── Backend API ────────────────────────────────────────────────────────────── backend: + image: kalekber/libnovel-backend:${GIT_TAG:-latest} build: context: ./backend dockerfile: Dockerfile @@ -167,6 +168,7 @@ services: # ─── Runner (background task worker) ───────────────────────────────────────── runner: + image: kalekber/libnovel-runner:${GIT_TAG:-latest} build: context: ./backend dockerfile: Dockerfile @@ -219,6 +221,7 @@ services: # ─── SvelteKit UI ───────────────────────────────────────────────────────────── ui: + image: kalekber/libnovel-ui:${GIT_TAG:-latest} build: context: ./ui dockerfile: Dockerfile @@ -318,6 +321,7 @@ services: # Custom build includes github.com/mholt/caddy-ratelimit and # github.com/hslatman/caddy-crowdsec-bouncer/http. caddy: + image: kalekber/libnovel-caddy:${GIT_TAG:-latest} build: context: ./caddy dockerfile: Dockerfile diff --git a/justfile b/justfile index 9bfeb83..aa57f1f 100644 --- a/justfile +++ b/justfile @@ -44,9 +44,9 @@ down-volumes: ps: {{doppler}} docker compose ps -# ── Build ───────────────────────────────────────────────────────────────────── +# ── Build & publish ─────────────────────────────────────────────────────────── -# Build (or rebuild) all images +# Build (or rebuild) all custom images locally build: {{doppler}} docker compose build @@ -54,9 +54,20 @@ build: build-svc svc: {{doppler}} docker compose build {{svc}} -# Pull latest base images -pull: - {{doppler}} docker compose pull +# Push all custom images to Docker Hub (requires docker login) +push: + {{doppler}} docker compose push backend runner ui caddy + +# Build then push all custom images +build-push: build push + +# Pull all images from Docker Hub (uses GIT_TAG from Doppler) +pull-images: + {{doppler}} docker compose pull backend runner ui caddy + +# Pull all third-party base images (minio, pocketbase, etc.) +pull-infra: + {{doppler}} docker compose pull minio pocketbase meilisearch valkey postgres crowdsec watchtower # ── Logs ─────────────────────────────────────────────────────────────────────