name: Release on: push: tags: - "v*" # e.g. v1.0.0, v1.2.3 concurrency: group: ${{ gitea.workflow }}-${{ gitea.ref }} cancel-in-progress: true jobs: # ── backend: vet & test ─────────────────────────────────────────────────────── test-backend: name: Test backend runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version-file: backend/go.mod cache-dependency-path: backend/go.sum - name: go vet working-directory: backend run: go vet ./... - name: Run tests working-directory: backend run: go test -short -race -count=1 -timeout=60s ./... # ── ui: type-check & build ──────────────────────────────────────────────────── check-ui: name: Check ui runs-on: ubuntu-latest defaults: run: working-directory: ui steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: "22" cache: npm cache-dependency-path: ui/package-lock.json - name: Install dependencies run: npm ci - name: Type check run: npm run check - name: Build run: npm run build # ── docker: backend ─────────────────────────────────────────────────────────── docker-backend: name: Docker / backend runs-on: ubuntu-latest needs: [test-backend] 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-backend 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: backend target: backend push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} 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: name: Docker / runner runs-on: ubuntu-latest needs: [test-backend] 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-runner 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: backend target: runner push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} 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 # ── ui: source map upload ───────────────────────────────────────────────────── # Commented out: GlitchTip project/auth token needs to be recreated after # the GlitchTip DB wipe. Re-enable once GLITCHTIP_AUTH_TOKEN is updated. # upload-sourcemaps: # name: Upload source maps # runs-on: ubuntu-latest # needs: [check-ui] # defaults: # run: # working-directory: ui # steps: # - uses: actions/checkout@v4 # # - uses: actions/setup-node@v4 # with: # node-version: "22" # cache: npm # cache-dependency-path: ui/package-lock.json # # - name: Install dependencies # run: npm ci # # - name: Build with source maps # run: npm run build # # - name: Download glitchtip-cli # run: | # curl -L "https://gitlab.com/glitchtip/glitchtip-cli/-/jobs/artifacts/v0.1.0/raw/artifacts/glitchtip-cli-linux-x86_64?job=build-linux-x86_64" \ # -o /usr/local/bin/glitchtip-cli # chmod +x /usr/local/bin/glitchtip-cli # # - name: Inject debug IDs into build artifacts # run: glitchtip-cli sourcemaps inject ./build # env: # SENTRY_URL: https://errors.libnovel.cc/ # SENTRY_AUTH_TOKEN: ${{ secrets.GLITCHTIP_AUTH_TOKEN }} # SENTRY_ORG: libnovel # SENTRY_PROJECT: libnovel-ui # # - name: Upload source maps to GlitchTip # run: glitchtip-cli sourcemaps upload ./build --release ${{ gitea.ref_name }} # env: # SENTRY_URL: https://errors.libnovel.cc/ # SENTRY_AUTH_TOKEN: ${{ secrets.GLITCHTIP_AUTH_TOKEN }} # SENTRY_ORG: libnovel # SENTRY_PROJECT: libnovel-ui # ── docker: ui ──────────────────────────────────────────────────────────────── docker-ui: name: Docker / ui runs-on: ubuntu-latest needs: [check-ui] steps: - uses: actions/checkout@v4 - name: Fetch releases from Gitea API run: | set -euo pipefail RESPONSE=$(curl -sfL \ -H "Accept: application/json" \ "http://gitea.kalekber.cc/api/v1/repos/kamil/libnovel/releases?limit=50&page=1") # Validate JSON before writing — fails hard if response is not a JSON array COUNT=$(echo "$RESPONSE" | jq 'if type == "array" then length else error("expected array, got \(type)") end') echo "$RESPONSE" > ui/static/releases.json echo "Fetched $COUNT releases" - 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-ui 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: 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 }} BUILD_TIME=${{ gitea.event.head_commit.timestamp }} 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, docker-caddy] steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Create release uses: https://gitea.com/actions/gitea-release-action@v1 with: token: ${{ secrets.GITEA_TOKEN }} generate_release_notes: true