Skip to content

Development Setup

Terminal window
gh auth login

The engine artifact resolves from GitHub Packages, which requires authentication even for public packages; build.sbt reads the token via gh auth token. If you skip this, the failure looks like a broken build rather than a missing credential:

unresolved dependency: lv.id.jc#dicechess-engine-scala...

That signature always means auth, never a broken build.

Tools are pinned in mise.toml: Java temurin-25, native scalafmt, lefthook, betterleaks, actionlint, gh, jq. Install everything and register the Git hooks with:

Terminal window
mise run setup

Docker is needed only by the four Postgres suites. On Rancher Desktop, export DOCKER_HOST=unix://$HOME/.rd/docker.sock and TESTCONTAINERS_RYUK_DISABLED=true first — without them the test run hangs at container startup rather than failing.

Command What it does
mise run compile sbt compile Test/compile
mise run test sbt "testOnly *" (full suite, needs Docker for four suites)
mise run check The CI mirror: shutdown, disposable cache, scalafmtCheckAll, clean, coverage, testOnly *, coverageReport
mise run format sbt scalafmtAll
mise run run Start the server on :8080
mise run contrib-docs:dev This site, locally
mise run contrib-docs:schema Regenerate the schema reference from the migrations
mise run docs:dev The Bot API site, locally

For a targeted, Docker-free run: sbt "testOnly dicechess.play.server.*".

  • Scala 3 “fewer braces” throughout: colon syntax for template bodies and lambdas, no end markers. Formatting is law — scalafmt decides, maxColumn is 120.
  • -Werror -Wunused:all -deprecation -feature -explain. One unused import fails the build.
  • Pure Typelevel FP in cats-effect IO. No nulls, no exceptions for control flow.
  • Comments explain why, not what. There are zero TODO/FIXME comments in src/ — keep it that way; encode the decision as a rationale comment instead.
  • Two-space indent, per .editorconfig.
  • mise run check passes locally. It mirrors CI exactly.
  • Backend CI is path-filtered to src/**, build.sbt, project/**, .scalafmt.conf, and its own workflow file. A documentation-only pull request gets zero checks — that is normal, not a stuck pipeline. A pull request touching only other workflow files likewise gets no run; validate those with gh workflow run.
  • SonarCloud imports the scoverage report. No coverage minimum is enforced — which is not a licence to skip tests.
  • Branch naming and Closes #n linking are validated automatically; external contributors must sign the CLA.

Warm-cache formatting. On a warm target/, sbt-scalafmt’s incremental cache can skip a genuinely misformatted file, so a local check passes while CI — a fresh checkout — fails. Check after a clean, or confirm with the native scalafmt --test <files>.

Untracked Scala files. sbt scalafmtAll skips them. git add a new .scala file before running the formatter, or the native pre-commit hook rejects the commit.

Three scalafmt toolchains. .scalafmt.conf, the native CLI pinned in mise.toml (used by the hooks; it does not auto-dispatch by version), and sbt-scalafmt must be bumped together.

Never pipe test output through grep or head — it masks the exit code.

  • Force-bumps testcontainers-java / docker-java and sets -Dapi.version=1.43: the wrapper’s pinned docker-java speaks an API version modern daemons reject.
  • ThisBuild/version is frozen at 0.1.0-SNAPSHOT. Real versions come only from git tags via the CD workflow. Do not bump it.
  • The Dockerfile pins eclipse-temurin:25-*-noble; the unsuffixed tag drifted to a base image whose coreutils break the launcher. The JAVA_OPTS flags in Dockerfile and compose are required by cats-effect on Java 25.
  • Docker builds pass the GitHub token as a BuildKit secret so it never lands in a layer — never convert it to a build argument.

Branch as <type>/<short-desc> or <type>/<id>-<short-desc>, where type is one of task, feat, bug, refactor, chore, docs, ci, test, perf. Run git status before editing so unrelated work does not bleed into your commit, and stage files by name — git add -A is forbidden. Commits, pull request descriptions, and review replies are English only. Split large work into small, reviewable pull requests.

Releases, production promotion, schema migrations against shared databases, data repair, and secret rotation are operator actions: prepare and propose them, never execute them.