`gitTally` is the name of another product in the git space, so the rename is a precaution; nothing about what the build system does changes. The name follows one rule: `Werkator` where it is prose, capitalized where it is a Kotlin type and its file, lowercase everywhere a machine reads it — the command, packages, paths, configuration keys and values, the Gitea check context. Environment variables keep their convention and are uppercase throughout. Every configuration file is still found under its pre-rename name (`ConfigFiles`): `.gittally.yml` at the repository root, in a build worktree and as committed on a branch, `.git/gittally/.gittally.yml` for the machine layer. The current name wins where both exist, and the old file is then ignored rather than merged — two files side by side are a half-done rename, not a layering. Without the fallback an installation that updated without renaming would not fail: a configuration that is not found leaves every setting at its default, so it would come up looking healthy while having forgotten its credentials and its builds. `docs/werkator-migrationsplan.md` lists what the fallback does not cover and has to be moved by hand — above all the state directory `.git/werkator/`, which holds the build history, the control token and the worktrees, and has no fallback of its own. `docs/migration-from-legacy.md` is deleted with this: it mapped the legacy script's environment variables, and every host it addressed has long since moved to the YAML configuration. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5.3 KiB
Step 12: Deployment and Legacy Migration
Prerequisites: steps 07, 08, 10.
Read README.md and 00-legacy-analysis.md first.
Goal
Make the new Werkator deployable as a service and retire the legacy script.
Design
Deployment (documentation plus a small generator, no self-install):
- Extend
init(or addinit --systemd) to generate a systemd user unit runningjava -jar werkator.jar serverwithWorkingDirectoryset to the repo,Restart=always, and anEnvironmentFilefor overrides — port the shape of the legacy unit, drop the self-copy/update machinery. - Write
docs/deployment.md: JRE requirement, jar location convention, systemd enable/start/log commands, and reverse-proxy guidance (example nginxserverblock proxying toserver.port; TLS via the host's existing certbot — replaces the legacy managed nginx container).
Migration:
- Write
docs/migration-from-legacy.md: mapping table legacy env vars → YAML keys (source:00-legacy-analysis.mdand legacy--envoutput), what is intentionally not ported, and the manual steps (stop legacy service, runinit, fill in token, install new service). - Decide and document: no automatic import of
build-results.tsv(history starts fresh) unless trivially cheap.
Housekeeping:
- Mark
legacy/werkatoras deprecated in its header comment and inREADME.md. - Review
../Werkator-Konzept.mdagainst what was actually built; update or note deviations. - Add an ADR summarizing the architecture decisions that emerged during the rewrite (persistence choice, polling UI, no nginx management).
Tests
- Unit test for the systemd unit generator (content assertions, no systemd interaction).
- Docs have no test, but verify every command in them by running it once.
Acceptance Criteria
./gradlew ktlintFormatthen./gradlew buildis green.- A fresh clone can follow
docs/deployment.mdto a running service (manual walkthrough; document the result in this file).
Implementation Notes (2026-07-07)
Implemented as designed: init --systemd (an option on init, not a separate subcommand) generates the unit and its EnvironmentFile under .git/werkator/, prints the install commands, and never touches ~/.config/systemd itself (no self-install).
SystemdServiceFiles builds the file contents and is unit-tested by content assertions, including the legacy % escaping and ExecStart quoting.
docs/deployment.md and docs/migration-from-legacy.md were written; README.md, docs/bootstrapping.md, ../Werkator-Konzept.md, and CLAUDE.md were updated to reference them.
docs/migration-from-legacy.md was deleted again on 2026-08-30 with the rename to Werkator: every host it addressed had long since moved to the YAML configuration.
Deviations and decisions:
- The unit is named per repository (
werkator-<repo-name>.service) instead of the global legacywerkator.service, because one instance serves one repository and several repositories can share a host. ExecStartuses thejavabinary and the jar path of the JVM that raninit --systemd, so the unit points at the jar in place (legacy copied the script to an install dir); systemd expands$JAVA_OPTSfrom theEnvironmentFileinto the command line. When not started viajava -jar(e.g. from Gradle),init --systemdprints an error instead of generating a broken unit.- The
EnvironmentFileonly tunes the JVM (JAVA_OPTS); the legacy env file carried username/token, which now live in.git/werkator/.werkator.yml. An existingwerkator.envis kept; the unit file is regenerated on every run (same as legacy). - The legacy
--nginx --dockerExecStartflags were dropped (runtime selection is per-branch config now); theAfter=… docker.serviceordering was kept. - Legacy build history (
build-results.tsv) is not imported — decided and documented indocs/migration-from-legacy.md(formats differ substantially; retention would prune imported rows quickly). - ADR 0004 records the rewrite architecture decisions (JSON-file persistence behind a repository interface, polling UI, no managed nginx).
../Werkator-Konzept.mdreview: only one real deviation found — "Builds laufen in Docker" became "nativ oder optional in Docker (pro Branch konfigurierbar)"; CLI capability lists gained build/retry; deployment links added.
Manual walkthrough (2026-07-07, fresh clone under ~/.cache):
- Followed
docs/deployment.mdend to end: built the jar, copied it to a stable path, cloned the repository freshly, raninitandinit --systemd, linked the generated unit,daemon-reload, started the service. - The clone already contained the committed
.werkator.yml, so only the machine config was created;server.portwas overridden to a free port via.git/werkator/.werkator.ymlto avoid clashing with a locally running instance. - Result: unit
active (running),GET /returned 200,/api/watchershowed a successful poll,journalctl --user -u …showed the startup log,restartandstopworked; the unit link and the scratch clone were removed afterwards. - Not machine-verified:
systemctl --user enableandloginctl enable-linger(the walkthrough used a transientstartto leave no persistent service behind) and the nginx/certbot section (no public host available); those commands were reviewed against the systemd/certbot documentation instead.