renaming from gitTally to Werkator

This commit is contained in:
mhoennig
2026-08-30 18:35:49 +02:00
parent 4d76744721
commit 7f550689dd
169 changed files with 1361 additions and 7504 deletions
+1 -1
View File
@@ -10,7 +10,7 @@
## Context and Problem Statement
GitTally is a greenfield Kotlin/Spring Boot project.
werkator is a greenfield Kotlin/Spring Boot project.
A test framework must be chosen before writing any tests.
The framework shapes how tests are structured, how readable they are, and how well they integrate with the Spring Boot test slice infrastructure.
+1 -1
View File
@@ -10,7 +10,7 @@
## Context and Problem Statement
GitTally is a greenfield Kotlin/Spring Boot project.
werkator is a greenfield Kotlin/Spring Boot project.
A Gradle version must be chosen for the initial setup.
[Gradle 9](https://docs.gradle.org/9.3.0/release-notes.html) (currently 9.5.1) is now stable and available.
@@ -10,7 +10,7 @@
## Context and Problem Statement
GitTally is a greenfield Kotlin/Spring Boot project.
werkator is a greenfield Kotlin/Spring Boot project.
A Spring Boot version must be chosen for the initial setup.
The choice is constrained by the support lifecycle: as of June 2026,
@@ -10,7 +10,7 @@
## Context and Problem Statement
The rewrite of `legacy/gitTally` (bash) as a Kotlin/Spring application (see `docs/plan/`) required several cross-cutting architecture decisions.
The rewrite of `legacy/werkator` (bash) as a Kotlin/Spring application (see `docs/plan/`) required several cross-cutting architecture decisions.
They were proposed in `docs/plan/README.md`, validated step by step during implementation, and are summarized here as one record.
### Technical Background
@@ -26,7 +26,7 @@ Its two structural defects — build status not observable during a build, and a
### Persistence: JSON files behind `BuildResultRepository`
Build results are persisted as a JSON file under `.git/gittally/`, accessed only through the `BuildResultRepository` interface.
Build results are persisted as a JSON file under `.git/werkator/`, accessed only through the `BuildResultRepository` interface.
#### Advantages
@@ -54,7 +54,7 @@ Pages render the full state server-side; one hand-written JavaScript file polls
### Deployment: no managed nginx, systemd user unit instead
nginx/Let's Encrypt container management was not ported; `init --systemd` generates a user unit running `java -jar gittally.jar server`, and `docs/deployment.md` documents the reverse-proxy setup with the host's certbot.
nginx/Let's Encrypt container management was not ported; `init --systemd` generates a user unit running `java -jar werkator.jar server`, and `docs/deployment.md` documents the reverse-proxy setup with the host's certbot.
#### Advantages
@@ -64,7 +64,7 @@ nginx/Let's Encrypt container management was not ported; `init --systemd` genera
#### Disadvantages
- HTTPS setup is a manual, host-specific step outside GitTally's control.
- HTTPS setup is a manual, host-specific step outside werkator's control.
## Decision Outcome
@@ -6,7 +6,7 @@
- rejected: -
- superseded: -
**Decision [accepted]:** GitTally optionally manages an nginx+certbot Docker container for hosts without a usable reverse proxy — revises the "no managed nginx" part of ADR 0004; deployment behind an existing reverse proxy stays the default.
**Decision [accepted]:** werkator optionally manages an nginx+certbot Docker container for hosts without a usable reverse proxy — revises the "no managed nginx" part of ADR 0004; deployment behind an existing reverse proxy stays the default.
## Context and Problem Statement
@@ -15,22 +15,22 @@ That decision was carried over from the rewrite plan without validating it again
### Technical Background
GitTally must run on Hostsharing managed container environments.
These hosts provide Docker but no root access and no host web server that GitTally could sit behind.
Without the managed nginx container, GitTally cannot be served over HTTPS there at all.
werkator must run on Hostsharing managed container environments.
These hosts provide Docker but no root access and no host web server that werkator could sit behind.
Without the managed nginx container, werkator cannot be served over HTTPS there at all.
The legacy script already solved this: it wrote an nginx config, ran an nginx Docker container, and obtained/renewed Let's Encrypt certificates via a certbot container in webroot mode.
## Considered Options
* Keep ADR 0004 as is (host reverse proxy only)
* Re-add the legacy managed nginx+certbot container as an opt-in feature
* External tooling (user-maintained compose stack next to GitTally)
* External tooling (user-maintained compose stack next to werkator)
### Host reverse proxy only
#### Advantages
- No container lifecycle or certificate code in GitTally.
- No container lifecycle or certificate code in werkator.
#### Disadvantages
@@ -38,7 +38,7 @@ The legacy script already solved this: it wrote an nginx config, ran an nginx Do
### Opt-in managed nginx+certbot container
GitTally starts and supervises a labelled nginx container and handles certificate issuance/renewal via certbot, only when explicitly enabled in the config.
werkator starts and supervises a labelled nginx container and handles certificate issuance/renewal via certbot, only when explicitly enabled in the config.
#### Advantages
@@ -48,13 +48,13 @@ GitTally starts and supervises a labelled nginx container and handles certificat
#### Disadvantages
- Re-adds container lifecycle and certificate renewal complexity to GitTally.
- Re-adds container lifecycle and certificate renewal complexity to werkator.
### External compose stack
#### Advantages
- Keeps GitTally itself simple.
- Keeps werkator itself simple.
#### Disadvantages
@@ -6,30 +6,30 @@
- rejected: -
- superseded: -
**Decision [accepted]:** GitTally is distributed for hosts without a Java runtime as a self-contained runtime bundle — a jlink-trimmed JRE plus `gittally.jar` plus a launcher script in one tarball, built by `./gradlew runtimeBundle`.
The JAR stays the primary artifact; a GraalVM native image and a containerized GitTally runtime were rejected.
**Decision [accepted]:** werkator is distributed for hosts without a Java runtime as a self-contained runtime bundle — a jlink-trimmed JRE plus `werkator.jar` plus a launcher script in one tarball, built by `./gradlew runtimeBundle`.
The JAR stays the primary artifact; a GraalVM native image and a containerized werkator runtime were rejected.
## Context and Problem Statement
GitTally must run on Hostsharing container servers (the primary target, see ADR 0005).
werkator must run on Hostsharing container servers (the primary target, see ADR 0005).
These hosts provide git, Docker, make, and systemd user sessions, but no Java runtime, and nothing may be installed system-wide.
`docs/bootstrapping.md` sketched a containerized GitTally runtime as the future answer; that sketch was never validated against the operational details.
`docs/bootstrapping.md` sketched a containerized werkator runtime as the future answer; that sketch was never validated against the operational details.
## Considered Options
* jlink runtime bundle (trimmed JRE + jar + launcher, one tarball)
* GraalVM native image (single executable)
* Containerized GitTally runtime (the original `docs/bootstrapping.md` sketch)
* Containerized werkator runtime (the original `docs/bootstrapping.md` sketch)
### jlink Runtime Bundle
A `jlink`-generated JRE with the pinned module list, the boot jar, and a `bin/gittally` launcher script, packed as `gittally-runtime-linux-x64.tar.gz` (~66 MB) and unpacked to `~/opt/gittally/` on the target host.
A `jlink`-generated JRE with the pinned module list, the boot jar, and a `bin/werkator` launcher script, packed as `werkator-runtime-linux-x64.tar.gz` (~66 MB) and unpacked to `~/opt/werkator/` on the target host.
Good:
- No production-code changes and plain JVM semantics — no new failure modes.
- git and docker CLIs are used from the host; build worktree paths stay host paths.
- `init --systemd` works unchanged: `java.home` and the running-jar path resolve into the bundle, so the generated unit points at `<bundle>/jre/bin/java` and `<bundle>/lib/gittally.jar` (verified).
- `init --systemd` works unchanged: `java.home` and the running-jar path resolve into the bundle, so the generated unit points at `<bundle>/jre/bin/java` and `<bundle>/lib/werkator.jar` (verified).
- Every JDK 21 ships jlink — no new build-toolchain requirement.
Bad:
@@ -44,12 +44,12 @@ Bad:
### GraalVM Native Image
Rejected because Spring AOT evaluates bean conditions at build time, and GitTally's dual-mode wiring cannot be represented in a single AOT arrangement:
Rejected because Spring AOT evaluates bean conditions at build time, and werkator's dual-mode wiring cannot be represented in a single AOT arrangement:
the CLI context runs without web and with `@Profile("!server")` `CliRunner`, while the `server` subcommand starts a second `SpringApplication` with `WebApplicationType.SERVLET` and the `server` profile gating the watcher/metrics/nginx lifecycles.
Whichever profile and web type the AOT processing fixes, the other mode's beans are missing from the binary.
Supporting both would require replacing the profile wiring with runtime guards and collapsing the two context shapes — an invasive rewrite with regression risk for the JVM path, on top of the usual native-image reflection work (Jackson-bound config and persistence classes, picocli).
### Containerized GitTally Runtime
### Containerized werkator Runtime
Rejected for operational complexity: the image must bundle git and docker CLIs; the container needs a same-path `$HOME` mount plus a docker-socket mount and uid/gid mapping so that `DockerBuildRunner`'s `--volume $workspace:$workspace` sibling mounts keep working; and the systemd unit must be hand-edited to a `docker run` invocation.
This remains the documented fallback if the runtime bundle ever becomes unworkable.
@@ -11,7 +11,7 @@
## Context and Problem Statement
GitTally's configuration is branch-centric: `branches.<name>` holds the build settings, and the nightly schedule (`autoBuild`) hangs off the branch.
werkator's configuration is branch-centric: `branches.<name>` holds the build settings, and the nightly schedule (`autoBuild`) hangs off the branch.
v0.9.13 added a per-slot `buildCommand` and `name` to `autoBuild.times[]`, so a nightly slot could run a fuller check recorded in its own result pool.
That worked, but it is a job concept hidden inside a schedule entry: the slot carries a command, an identity, and (implicitly) a branch — everything a job has, in the wrong place.
@@ -73,7 +73,7 @@ A build definition has:
Semantics:
- **Merge order** for the effective settings of one build on one branch: config defaults → `branches.default``branches.<branch>` → the worktree's committed `.gittally.yml` (build keys, pinned keys stripped) → `builds.<name>` overrides. The build definition wins last because it is the job; it comes from the repo install/project config (server-side), never from the worktree.
- **Merge order** for the effective settings of one build on one branch: config defaults → `branches.default``branches.<branch>` → the worktree's committed `.werkator.yml` (build keys, pinned keys stripped) → `builds.<name>` overrides. The build definition wins last because it is the job; it comes from the repo install/project config (server-side), never from the worktree.
- **Pool identity**: the `default` build records under the branch name (URLs, rows, retention as before); every other build records under `<branch>@<build>` (URL-sanitized, e.g. `/branches/master_pitest/…`). Each pool keeps its own retention count, latest status, and permanent latest-green link.
- **Persistence**: the result stores the build's name (`build`, default `default`) next to the branch; the derived pool name keeps keying grouping and display. The v0.9.13 `buildCommandOverride` field is dropped: restart, retry, and startup recovery re-resolve the command from the *current* config by (branch, build) — a job definition in config is the source of truth, so a re-run of an old result uses the job's current command.
- **Triggers in the watcher**: `onPush` uses the existing change detection per pool ("already built" per pool and commit); `atTimes` fires once per day per slot per pool (state file keyed by pool, date, time). The `branches.<name>.requirePullRequest` gate stays a branch property and gates all watcher-triggered builds of that branch, as today.
@@ -119,7 +119,7 @@ Follow-up (2026-08-28): mixing the execution key `maxConcurrent` into the `build
The concurrency limit moved to `executor.maxConcurrent` (a new section for execution settings), without a compatibility alias, so the `builds` section holds build definitions only.
Follow-up (2026-08-29): pinning the whole `builds` section against the branch layer was wrong and is reverted.
A branch's committed `.gittally.yml` describes that branch's CI, and a new `builds` configuration can only be tried out by committing it on a branch — pinned, it was neither effective at build time nor visible to the watcher, so the job silently did not exist.
A branch's committed `.werkator.yml` describes that branch's CI, and a new `builds` configuration can only be tried out by committing it on a branch — pinned, it was neither effective at build time nor visible to the watcher, so the job silently did not exist.
The branch layer now carries `builds` too: the watcher reads each origin branch's committed config (`git show`, cached by head commit) to decide which of *that branch's* builds are due, and a branch's definitions are evaluated for that branch alone, so they can never trigger builds of another branch.
The pinned set is reduced to what does not describe this branch's build: secrets (`git`), the host/repository sections (`server`, `gitea`, `executor`, `watcher`), the sandbox policy (`docker.enabled`/`docker.network`), and the trust gate (`requirePullRequest`).
Letting a branch set its own `buildCommand` through a definition grants no new power — `branches.*.buildCommand` always allowed exactly that — whereas the sandbox and the gate decide whether untrusted branch code runs on the host at all, and therefore stay server-side.