CI/CD & Versioning for dicechess-analytics-ui

Background

Currently dicechess-analytics-ui has minimal infrastructure:

  • mise.toml with basic tasks (setup, dev, build, check)
  • ✅ Docker build + push to GHCR (deploy.yml)
  • ✅ CodeRabbit PR reviews (.coderabbit.yaml)
  • ❌ No CI pipeline (lint, type-check, test)
  • ❌ No linter/formatter installed (ESLint, Prettier missing despite CodeRabbit referencing them)
  • ❌ No testing framework
  • ❌ No automated versioning or changelog
  • ❌ No PR labeler or stale bot
  • ❌ No pre-commit hooks
  • ❌ No mise run format (required by AGENTS.md)

Reference Repositories Comparison

Featuredicechess-labdicechess-engine-scalaanalytics-ui now
CI pipeline✅ Backend + Frontend CI✅ sbt build+test❌ None
Versioning✅ Manual Ops: Release + git tags✅ Release Please (simple)❌ Static 0.1.0
Deploy chain✅ Release → Staging → E2E → Prod✅ —✅ Docker only
PR labeler
Stale bot
Pre-commit hooks✅ 7 hooks
Linting✅ Ruff + Svelte-check✅ scalafmt❌ Svelte-check only
Formatting✅ Ruff + Prettier✅ scalafmt❌ None
Unit testing✅ pytest + Vitest✅ MUnit❌ None
E2E testing✅ Playwright
Type checking✅ ty + mypy + svelte-check✅ scalac✅ svelte-check + tsc
Dependabot✅ 7 ecosystems
Code review bot✅ CodeRabbit
Docs site✅ MkDocs → GH Pages✅ Docusaurus → GH Pages

User Review Required

> Versioning strategy choice: dicechess-lab uses a manual Ops: Release workflow (trigger → bump tag → GitHub Release), while dicechess-engine-scala uses Release Please (auto-generates PRs from Conventional Commits). Which approach do you prefer for analytics-ui?

> Deployment model: Currently the Docker image is pushed to GHCR on every push to main. Should we add a staging/production deployment chain similar to dicechess-lab (with self-hosted runners on RPi), or keep the simple Docker-push model?

> SvelteKit migration consideration: The current project uses plain Svelte 5 + Vite (not SvelteKit). This is fine for a SPA but means we don't have SvelteKit's built-in adapter-static for GitHub Pages. Should we keep the current architecture?

Open Questions

  1. Do you want Playwright E2E tests in Phase 2, or is unit testing with Vitest sufficient for now?
  2. Should we add Dependabot (like dicechess-lab with weekly schedules per ecosystem)?
  3. Documentation site — is this needed for analytics-ui, or is README sufficient?
  4. Telegram notifications — should we add deployment notifications (like dicechess-lab)?

Proposed Changes

Phase 1 — Code Quality Foundation

[NEW] .github/workflows/ci.yml

CI pipeline triggered on push/PR to main:

  1. Lint — ESLint check
  2. Format — Prettier check
  3. Type-checksvelte-check + tsc
  4. Buildvite build (ensures the project compiles)
name: CI
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs:
  ci:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: jdx/mise-action@v2
      - run: npm ci
      - run: npm run lint
      - run: npm run format:check
      - run: npm run check
      - run: npm run build

[MODIFY] package.json

Add missing dev dependencies and scripts:

  • Install: eslint, @eslint/js, typescript-eslint, eslint-plugin-svelte, prettier, prettier-plugin-svelte
  • Add scripts: lint, format, format:check
 "scripts": {
   "dev": "vite",
   "build": "vite build",
   "preview": "vite preview",
-  "check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json"
+  "check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json",
+  "lint": "eslint .",
+  "format": "prettier --write .",
+  "format:check": "prettier --check ."
 }

[NEW] eslint.config.js

Flat config with eslint-plugin-svelte + typescript-eslint, matching dicechess-lab frontend patterns.

[NEW] .prettierrc

{
  "useTabs": true,
  "singleQuote": true,
  "trailingComma": "all",
  "printWidth": 100,
  "plugins": ["prettier-plugin-svelte"],
  "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}

[NEW] .prettierignore

package-lock.json
dist/
node_modules/
public/

[MODIFY] mise.toml

Add format and lint tasks to satisfy AGENTS.md requirement:

[tasks.format]
description = "🎨 Format code with Prettier"
run = "npm run format"
 
[tasks.lint]
description = "🔍 Run ESLint checks"
run = "npm run lint"
 
[tasks.check]
description = "✅ Run all quality checks (lint + format + types)"
run = ["npm run lint", "npm run format:check", "npm run check"]

Phase 2 — Versioning & Release Automation

Option A: Release Please (like dicechess-engine-scala)

[NEW] .github/workflows/release.yml

name: Release Please
on:
  push:
    branches: [main]
permissions:
  contents: write
  pull-requests: write
jobs:
  release-please:
    runs-on: ubuntu-latest
    steps:
      - uses: googleapis/release-please-action@v4
        with:
          config-file: release-please-config.json
          manifest-file: .release-please-manifest.json

[NEW] release-please-config.json

{
  "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
  "packages": {
    ".": {
      "release-type": "node",
      "changelog-path": "CHANGELOG.md"
    }
  }
}

[NEW] .release-please-manifest.json

{
  ".": "0.1.0"
}

Option B: Manual Ops: Release (like dicechess-lab)

Similar to dicechess-lab’s release.yaml with manual workflow_dispatch and patch/minor/major input.


Phase 3 — GitHub Automation

[NEW] .github/workflows/labeler.yml

Auto-label PRs based on changed paths:

LabelPaths
frontendsrc/**
ci.github/workflows/**
dependenciespackage.json, package-lock.json
documentation*.md, docs/**
dockerDockerfile, nginx.conf, .dockerignore

[NEW] .github/labeler.yml

Label definitions for the labeler action.

[NEW] .github/workflows/stale.yml

Stale bot matching dicechess-engine-scala pattern:

  • Issues: stale after 60 days, close after 14
  • PRs: stale after 30 days, close after 10
  • Exempt labels: pinned, security, enhancement

Phase 4 — Testing Infrastructure

Install Vitest

npm install -D vitest @testing-library/svelte @testing-library/jest-dom jsdom

[MODIFY] vite.config.ts

Add Vitest configuration:

/// <reference types="vitest/config" />
import { defineConfig } from "vite"
 
export default defineConfig({
  // ... existing config
  test: {
    environment: "jsdom",
    include: ["src/**/*.test.ts"],
    coverage: {
      provider: "v8",
      reporter: ["text", "json-summary"],
    },
  },
})

[MODIFY] package.json

+"test": "vitest run",
+"test:watch": "vitest",
+"test:coverage": "vitest run --coverage"

[MODIFY] mise.toml

[tasks.test]
description = "🧪 Run unit tests"
run = "npm run test"

Phase 5 — Optional Enhancements

Dependabot

[NEW] .github/dependabot.yml — weekly updates for npm and github-actions ecosystems.

Pre-commit Hooks

Based on dicechess-lab pattern:

  • trailing-whitespace, end-of-file-fixer
  • gitleaks (secret scanning)
  • ESLint + Prettier
  • svelte-check
  • actionlint

Docker Deploy Enhancement

Modify existing deploy.yml to add version tagging from git tags (not just latest + SHA).


Verification Plan

Automated Tests

# After Phase 1
mise run check        # Should run lint + format:check + svelte-check + tsc
mise run format       # Should format all files with Prettier
 
# After Phase 4
mise run test         # Should run Vitest suite

CI Validation

  • Push a test branch → verify CI workflow runs lint + format + type-check + build
  • Merge a conventional commit → verify Release Please creates a release PR

Manual Verification

  • Confirm mise run format and mise run check work locally
  • Verify GitHub Actions workflows appear and run correctly
  • Check that PR labeler correctly assigns labels