`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.6 KiB
Legacy Werkator Analysis
Condensed analysis of legacy/werkator (bash, ~6000 lines) as input for the rewrite.
Line numbers refer to the legacy script at the time of analysis (version 0.7.8).
What the Legacy System Does
A single bash daemon per repository that:
- Polls
originfor changed local branches and recent new origin branches. - Checks out and builds each changed branch (natively or in Docker), one at a time.
- Records results and publishes commit statuses to Gitea.
- Archives build logs and report directories as browsable artifacts.
- Serves a static-HTML web UI via an embedded Python HTTP server.
- Optionally manages an nginx+certbot Docker container for HTTPS.
- Installs itself as a systemd user service.
Persistent State (formats to replace)
All state lives in files; there is no database.
| File | Format | Content |
|---|---|---|
.git/git-watch-origin-and-test/build-results.tsv |
TSV | branch, commit, status, timestamp, duration(MM:SS), artifact_key |
.git/git-watch-origin-and-test/auto-builds.tsv |
TSV | branch, date, time_slot — prevents double auto-builds |
.git/git-watch-origin-and-test/build.lock |
flock file | build mutex, holder found via fuser/lsof |
.git/git-watch-origin-and-test/cancel-* |
touch/token files | cancellation request/token/accepted handshake |
$TMPDIR/git-watch-origin-and-test/<repo_key>/ |
HTML + files | artifact root: generated pages, per-build artifact dirs |
<artifact_root>/system.json + system_state.dat |
JSON + text | system metrics snapshot and aggregation state |
Build statuses: pending, running, success, failed, interrupted, cancelled (legacy alias passed → success).
Artifact key naming: sanitized branch + 12-char SHA256 prefix, plus sanitized timestamp + hash for per-build dirs.
External Interactions
Git (always via CLI): rev-parse, for-each-ref, fetch, switch, reset --hard, show -s --format=%cI, rev-list.
HTTPS git auth uses a generated GIT_ASKPASS script feeding username + Gitea token.
Gitea API:
POST /api/v1/repos/{owner}/{repo}/statuses/{sha}— publish status; payloadstate,context,description,target_url.GET /api/v1/repos/{owner}/{repo}/commits/{sha}/statuses?sort=recentupdate— read statuses, filtered bycontext.GET /api/v1/user— resolve username from token.- State mapping: success→success; failed/interrupted/cancelled→failure; pending/running→pending.
Web control endpoints (Python handler):
GET /control/status?commit=<sha>&local_status=<s>— proxy Gitea status for a commit.POST /control/cancel— cancel running build (CSRF-token protected).POST /control/restart— append a new pending result row.POST /control/delete— remove a result row and patch HTML files via regex.
Root Causes of the Known Bugs
Stuck loading animation (UI):
- Status cells start as
status-loadingand each row fetches/control/statuswith a 15s timeout; failures leave the spinner forever (no error state). - Page auto-refresh re-fetches the page HTML and diffs
#build-rows; HTML is regenerated server-side by regex-patching files, which fails silently when structure drifts. - "Current" and "System" nav views exist, but the page generator only implements
latest/branches/history, so some views fall through.
No status changes observable during a build (control loop):
- The main loop (lines ~4944–4966) is synchronous:
checkout_and_buildblocks until the build ends; only then is origin re-scanned. retry_origin_change_check()is an uninterruptible internal retry loop with 10s sleeps.- The console spinner is cosmetic and runs independently of actual progress.
Behavior Worth Preserving
- Startup recovery: mark stale
runningbuilds asinterrupted; restart restartable builds; optional retry of failed builds. - New-branch age filter (
newBranchMaxAge) to avoid building stale branches. - Auto-build time slots (UTC HH:MM) per branch with per-day/slot dedup.
- Retention per branch by count or age, pruning both results and artifact dirs.
- Per-branch build/clean command, artifact dirs, and log file names (now via
branches:YAML config). - Cancellation with token handshake; process-tree termination (TERM, wait, KILL).
- Build log capture: stdout/stderr to files plus a live "current build" log.
- Gitea status published on every transition with
target_urlpointing at the artifact page.
Not Ported (decided)
- nginx + certbot/Let's Encrypt container management — replaced by deployment documentation (step 12). Revised by ADR 0005: it IS needed for Hostsharing container hosts and returns as an opt-in feature (step 13).
- Self-install (
--install), self-update script generation — replaced by jar deployment plus systemd docs (step 12). - Legacy
HSADMIN_NG_*environment fallbacks and env-file config — replaced by YAML config (done). - Regex-based in-place HTML patching — replaced by server-rendered pages/JSON endpoints.
- Static HTML artifact index generation with embedded 900-line JavaScript — replaced by templates.
.aliasessourcing (line 731), impressum footer link handling stays optional/simple.
Orphaned or Dubious Legacy Config
Verify need before porting any of these:
WERKATOR_BUILD_DOCKER_PREFLIGHT_COMMAND,WERKATOR_BUILD_DOCKER_JAVA_TOOL_OPTIONS— highly hsadmin-ng-specific defaults.WERKATOR_ARTIFACT_NGINX_*,WERKATOR_ARTIFACT_LETSENCRYPT_EMAIL— dropped with nginx management; revived asserver.nginx.*by step 13 (ADR 0005).WERKATOR_IMPRESSUM_URL— keep as optional simple footer link if wanted.WERKATOR_INSTALL_DIR— dropped with self-install.