`bwrap` named the mechanism one layer below the tool that actually runs it: since v1.0.0 Werkator does not invoke bwrap at all, it shells out to the werkdock CLI — which made `bwrap.werkdock` a key naming its own executor. The section is `werkdock` now and that key is `werkdock.binary`; BwrapConfig, BwrapOverrides and BwrapBuildRunner follow the name. A file still writing `bwrap` is read as before and warned about once per file, in `renameLegacySandbox` on the raw map of every layer before merging — so nothing downstream knows two names, and the old name is not a way around the pinning either. Renaming rather than refusing, because the section lives in the machine configuration of every webspace instance, which no repository tracks; the hard refusal belongs to the release that sets ConfigVersions.FORMAT_BROKE_IN, where a file declaring no version can be caught by name at all. WERKATOR_SANDBOX in tools/remote follows, and still accepts `bwrap`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: mhoennig <michael@hoennig.de> Reviewed-on: #19
384 lines
26 KiB
HTML
384 lines
26 KiB
HTML
<!doctype html>
|
|
<html xmlns:th="http://www.thymeleaf.org" lang="en">
|
|
<head th:replace="~{fragments :: head(${pageTitle})}"></head>
|
|
<body>
|
|
<main>
|
|
<h1 th:replace="~{fragments :: header(${pageTitle})}"></h1>
|
|
<div th:replace="~{fragments :: nav(${view})}"></div>
|
|
<div class="panel release-notes">
|
|
|
|
<h2>v1.2.0 <span class="muted">— 2026-09-03</span></h2>
|
|
<ul>
|
|
<li>The build sandbox for hosts without Docker is configured as <code>werkdock</code> now,
|
|
not <code>bwrap</code> (PR#19), and its <code>bwrap.werkdock</code> key — which named its
|
|
own executor — is <code>werkdock.binary</code>. The old section is still read, with a
|
|
warning naming the file, so no installation has to be changed before its next
|
|
configuration edit. <code>bwrap</code> named the mechanism one layer below the tool that
|
|
actually runs it: builds have been executed by the werkdock CLI since v1.0.0.</li>
|
|
</ul>
|
|
|
|
<h2>v1.1.2 <span class="muted">— 2026-09-03</span></h2>
|
|
<ul>
|
|
<li>On a Hostsharing Managed Webspace, an <code>instance-update</code> restart no longer looks
|
|
dead while nothing is listening on the port for a moment: the generated
|
|
<code>.htaccess</code> (PR#17) now maps a refused connection to a static
|
|
"Werkator is restarting — please retry in a few minutes" page instead of Apache's default
|
|
error page. Generated only where a <code>server.publicBaseUrl</code> is configured, next to
|
|
the existing <code>.htaccess</code>; nothing changes for a Docker-host deployment.</li>
|
|
</ul>
|
|
|
|
<h2>v1.1.1 <span class="muted">— 2026-09-03</span></h2>
|
|
<ul>
|
|
<li>The system page's disk metric is now quota-aware (PR#16): it shows the tightest of the
|
|
user quota, the group quota, and the volume itself, instead of always the volume. On a
|
|
Hostsharing Managed Webspace that is usually a group quota, far tighter than the shared
|
|
host disk — the info line names the binding source and its hard limit, and the
|
|
warn/critical highlighting now fires against the real budget. A host without a binding
|
|
quota renders exactly as before.</li>
|
|
</ul>
|
|
|
|
<h2>v1.1.0 <span class="muted">— 2026-09-03</span></h2>
|
|
<ul>
|
|
<li>One instance can now serve several repositories (ADR 0009): a <code>~/.werkator.yml</code>
|
|
lists them, and each is worked on through its own <code>RepoContext</code> — checkout,
|
|
results, artifact store, and worktrees never share state across repositories. The watcher
|
|
polls every registered repository in its own guard, and the executor's
|
|
<code>maxConcurrent</code> still applies per <code>(repository, branch)</code>, not just
|
|
per branch.</li>
|
|
<li>Server routes carry the repository as <code>/repos/<name>/…</code> and
|
|
<code>/api/repos/<name>/…</code>; the unscoped routes keep meaning the served
|
|
repository, so a single-repository installation notices nothing. <code>build</code>,
|
|
<code>retry</code>, and <code>status</code> take a <code>--repo</code> option to pick a
|
|
registered repository instead of always acting on the current directory.</li>
|
|
<li>The system page's resource metrics are sampled and reported per repository instead of
|
|
once for the whole instance.</li>
|
|
<li>The page title carries a drop-down next to the heading in place of the plain repository
|
|
name once more than one repository is registered — picking a different one switches
|
|
straight to the same view (<em>Branches</em>, <em>History</em>, …) on it. A single-repository
|
|
installation still shows the plain name, unchanged.</li>
|
|
</ul>
|
|
|
|
<h2>v1.0.1 <span class="muted">— 2026-08-31</span></h2>
|
|
<ul>
|
|
<li>The restart button on the <em>Branches</em> view builds the branch's current head
|
|
instead of repeating the commit its last build ran on, and says so: it reads
|
|
"Build current head" there. A row on that page is a branch, not a past run — and
|
|
repeating an overtaken commit can be worse than useless, because a build gate
|
|
comparing the built commit against origin can never pass on it. The row keeps its
|
|
build definition, and a branch that is gone from origin is refused by name instead
|
|
of quietly falling back to the old commit.</li>
|
|
<li><em>Latest</em> and <em>History</em> are unchanged: a row there is a recorded run,
|
|
and restarting it means that commit.</li>
|
|
</ul>
|
|
|
|
<h2>v1.0.0 <span class="muted">— 2026-08-31</span></h2>
|
|
<ul>
|
|
<li>GitTally is now <strong>Werkator</strong>. The old name already belongs to another
|
|
product in the git space, so the rename is a precaution and nothing more: what the
|
|
build system does, how it is configured, and how it reports to Gitea are unchanged.
|
|
In prose it is Werkator, everywhere a machine reads the name it is
|
|
<code>werkator</code>. The version marks the new name rather than a claim about
|
|
maturity: the release after <code>0.9.21</code> is <code>1.0.0</code>, because a
|
|
product that changes its name is better off counting from one under it.</li>
|
|
<li>The rename reaches the file names an installation depends on. The committed
|
|
configuration is <code>.werkator.yml</code>, the machine-specific one
|
|
<code>.git/werkator/.werkator.yml</code>, and all state — build results, artifacts,
|
|
worktrees, the control token — lives under <code>.git/werkator/</code>.</li>
|
|
<li>The default Gitea check context is <code>werkator</code>. Where the old name is
|
|
pinned in a branch protection rule, the rule has to be updated with it, or a pull
|
|
request waits forever for a check nobody posts any more. Statuses already written
|
|
keep their old context, so a commit built before and after the change shows
|
|
both.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.21 <span class="muted">— 2026-08-30</span></h2>
|
|
<ul>
|
|
<li>An origin the watcher cannot reach is now visible in the web UI: a banner above the
|
|
table says that the list below is not updating, since when, and why. Until now the
|
|
page kept showing its last known state, calm and plausible, while GitTally had not
|
|
been able to fetch for an hour — the failure lived in the log alone. The banner is
|
|
deliberately separate from the live indicator: that one says whether your browser
|
|
reaches the server, this one whether the server reaches origin.</li>
|
|
<li>A lasting fetch failure is logged when its message changes instead of on every poll
|
|
cycle, and the recovery is logged once. One wrong token used to write several hundred
|
|
identical warnings an hour. An invalid <code>atTimes</code> slot is likewise reported
|
|
once per slot.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.20 <span class="muted">— 2026-08-29</span></h2>
|
|
<ul>
|
|
<li>A build definition is now split in two: a <code>trigger</code> block says when the
|
|
build runs and for which branches (<code>onPush</code>, <code>atTimes</code>,
|
|
<code>branches</code>, <code>activeWithin</code>), everything beside it says what
|
|
the build does. Only the second half is inherited from <code>builds.default</code>,
|
|
and making that structural means a selector added later cannot become inheritable
|
|
by accident. A definition still writing those keys flat is refused by name — a
|
|
trigger nobody reads any more is a build that silently stops running.</li>
|
|
<li>A branch pattern prefixed with <code>!</code> excludes instead of selecting, and an
|
|
exclusion wins whatever the order: <code>branches: ["*", "!master"]</code> is every
|
|
branch but master. That lets one branch have a build of its own without being built
|
|
by the default one as well — previously the only way to avoid the double build was
|
|
to give up the second definition's push trigger.</li>
|
|
<li>A build may report under its own Gitea check with <code>statusContext</code>; empty
|
|
keeps the repository-wide <code>gitea.statusContext</code>. Two builds of one commit
|
|
used to overwrite each other's result there, so a second build over the same branch
|
|
— a quick check next to a long one — was not readable in Gitea.</li>
|
|
<li><strong>Fixed:</strong> a branch whose builds all belong to named definitions showed
|
|
an empty row in the branches view, reading as "never built" right next to its actual
|
|
builds.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.19 <span class="muted">— 2026-08-29</span></h2>
|
|
<ul>
|
|
<li>A build definition now describes its build completely: <code>requirePullRequest</code>
|
|
and the whole <code>docker</code> section, the sandbox policy included, live in
|
|
<code>builds.<name></code>. <code>builds.default</code> is the base every other
|
|
definition inherits its settings from — never its trigger, because
|
|
<code>onPush</code>, <code>atTimes</code>, <code>branches</code>, and
|
|
<code>activeWithin</code> say when and where that one build runs.</li>
|
|
<li>The per-branch <code>branches</code> section is thereby superseded and will be
|
|
removed. It is still read, but only while nothing defines a build at all: as soon as
|
|
one real definition exists — a leftover <code>builds.maxConcurrent</code> is not one
|
|
— <code>branches</code> is ignored completely and a warning names it. Either or,
|
|
never both: two half-answers to what a build runs would pull against each other.</li>
|
|
<li><code>requirePullRequest</code>, <code>docker.enabled</code>, and
|
|
<code>docker.network</code> stay pinned to the host, wherever a branch writes them.
|
|
Since the inheritance is applied after all configuration layers are merged, a build
|
|
a branch invents and the host has never heard of still inherits the host's
|
|
<code>builds.default</code> — it cannot reach a native build by defining a new
|
|
job.</li>
|
|
<li><strong>Fixed:</strong> the archived artifact directories came from the plain branch
|
|
settings, so a build definition adding its own <code>artifactDirs</code> — a
|
|
release job storing <code>build/libs</code>, say — never had them stored.</li>
|
|
<li><strong>Fixed:</strong> the build definitions of a branch were cached by its head
|
|
commit alone, so an edited machine or project configuration only took effect once
|
|
that branch moved. On a quiet branch, a new scheduled job never started at all.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.18 <span class="muted">— 2026-08-29</span></h2>
|
|
<ul>
|
|
<li>A configuration file can declare which GitTally it is written for, so a version
|
|
that renames or drops a key says so instead of silently ignoring what it no longer
|
|
understands:
|
|
<code>gitTally: { version: { since: "0.9.18", below: "2.0" } }</code>.
|
|
<code>since</code> is enforced — both against a GitTally that is too old and
|
|
against a file written before the version in which the configuration format last
|
|
changed incompatibly, which GitTally knows about itself. <code>below</code> is a
|
|
release marker and only warns, so an unmaintained value can never stop a build.</li>
|
|
<li>The reach follows the file: the machine and project configuration abort the start
|
|
naming the file and the way back, an incompatible configuration committed on a
|
|
branch fails only that branch's builds. A file that declares nothing keeps working,
|
|
and <code>gittally init</code> writes the current version into the config it
|
|
generates.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.17 <span class="muted">— 2026-08-29</span></h2>
|
|
<ul>
|
|
<li><strong>Fixed:</strong> a page left in the background — a phone tab switched away
|
|
from for an hour — kept showing the state it was left in, with the durations of
|
|
running builds counting up client-side although the builds had long finished.
|
|
A returning page now fetches the current state immediately, whether the browser
|
|
reports the return as a visibility change, a focus, or a restore from its cache.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.16 <span class="muted">— 2026-08-29</span></h2>
|
|
<ul>
|
|
<li>A scheduled build can run hourly: <code>atTimes: ["??:05"]</code> stands for that
|
|
minute of every hour. Each hour is its own slot, so it triggers once per hour —
|
|
mixing it with fixed <code>HH:MM</code> times works, the latest due slot wins.
|
|
Only the hour may be a wildcard; anything else is skipped with a warning.</li>
|
|
<li><strong>Fixed:</strong> the artifact page showed the build command of the plain
|
|
branch configuration — for a build of a named definition, or on a branch whose
|
|
committed <code>.gittally.yml</code> overrides the command, that was a command the
|
|
build never ran. It now shows what this build actually runs, resolved from the
|
|
branch configuration committed at the build's own commit plus its definition.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.15 <span class="muted">— 2026-08-29</span></h2>
|
|
<ul>
|
|
<li>The <code>.gittally.yml</code> committed on a branch now takes precedence for the
|
|
<code>builds</code> section as well — a branch can define its own build definitions
|
|
and override those from the project config. The watcher reads each origin branch's
|
|
committed configuration, so a new build definition takes effect by committing it on
|
|
a branch, without touching any other branch's builds. A branch's definitions apply
|
|
to that branch alone.</li>
|
|
<li>Pinned to the server side are only the keys that do not describe the branch's build:
|
|
secrets (<code>git</code>), the host and repository sections (<code>server</code>,
|
|
<code>gitea</code>, <code>executor</code>, <code>watcher</code>), the container sandbox
|
|
policy (<code>docker.enabled</code>, <code>docker.network</code>), and the
|
|
<code>requirePullRequest</code> gate.</li>
|
|
<li><strong>Changed:</strong> the build concurrency limit moved from
|
|
<code>builds.maxConcurrent</code> to <code>executor.maxConcurrent</code> (default 1,
|
|
no compatibility alias) — the <code>builds</code> section now holds build definitions
|
|
only. A leftover <code>builds.maxConcurrent</code> key is ignored with a warning
|
|
instead of failing the configuration, so an installation keeps running until its
|
|
committed config can be updated.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.14 <span class="muted">— 2026-08-28</span></h2>
|
|
<ul>
|
|
<li>Named build definitions (ADR 0007): the <code>builds</code> section of
|
|
<code>.gittally.yml</code> now defines jobs with <code>onPush</code>/<code>atTimes</code>
|
|
triggers, branch selectors (name globs, <code>activeWithin</code> age filter), and
|
|
overrides of the branch settings — e.g. a nightly <code>pitest</code> build running a
|
|
fuller check than the quick on-push builds. A named build records under its own
|
|
<code><branch>@<build></code> pool with its own branches-view row, retention
|
|
count, and permanent latest-green artifact link.</li>
|
|
<li>Restart, <code>gittally retry</code>, and the startup recovery re-run a build under its
|
|
recorded definition, resolving the settings from the current configuration.</li>
|
|
<li><strong>Changed:</strong> the v0.9.13 per-slot <code>buildCommand</code>/<code>name</code>
|
|
syntax in <code>autoBuild.times</code> is gone again — use a build definition instead.
|
|
<code>branches.*.autoBuild</code> with plain times keeps working but is deprecated.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.13 <span class="muted">— 2026-08-28</span></h2>
|
|
<ul>
|
|
<li>A scheduled auto-build slot (<code>autoBuild.times</code> entry) can carry its own
|
|
<code>buildCommand</code>, so a nightly slot runs a fuller check than the quick
|
|
on-commit builds of the same branch. Restart, retry, and the startup recovery repeat
|
|
a build with the command it originally ran.</li>
|
|
<li>A slot can also carry a <code>name</code> (e.g. <code>master@nightly</code>): its
|
|
builds then get their own row in the branches view, their own history and retention
|
|
pool, and their own permanent latest-green artifact link
|
|
(<code>/branches/master_nightly/…</code>) — the branch's regular builds no longer
|
|
displace the nightly build and its artifacts.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.12 <span class="muted">— 2026-08-26</span></h2>
|
|
<ul>
|
|
<li>A build whose branch is deleted from origin mid-build (the usual fate of a merged
|
|
branch) no longer vanishes from the UI and history while it is still queued or
|
|
running — previously the queue looked stuck although a build was executing.</li>
|
|
<li>Triggering a build that is already queued or running for the same commit no longer
|
|
stacks a duplicate — an impatient double-click on <em>restart</em> now hits the
|
|
existing build. Re-running a finished build is unaffected.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.11 <span class="muted">— 2026-08-14</span></h2>
|
|
<ul>
|
|
<li>At the end of each poll cycle, the local branch refs of the watched repository are
|
|
fast-forwarded to their state on origin, so build steps that compare a branch with its
|
|
origin counterpart no longer fail once origin moved on. Only fast-forwards are applied —
|
|
a branch that diverged from origin or is ahead of it stays untouched. Switched off with
|
|
<code>watcher.fastForwardLocalRefs: false</code>.</li>
|
|
<li>On the artifact index of a failed build, the logs that actually contain the build tool's
|
|
failure line carry a <span class="status status-failed">failed</span> badge — with stdout
|
|
and stderr stored separately, that points straight at the log worth opening. Logs of a
|
|
green build are not scanned.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.10 <span class="muted">— 2026-08-11</span></h2>
|
|
<ul>
|
|
<li>The control token is no longer embedded in the pages — reading them is unauthenticated,
|
|
so anyone could have picked it out of the HTML. Viewing stays public; the first click on
|
|
a restart/cancel/delete button asks for the token once (it is in
|
|
<code>.git/gittally/control-token</code> on the host) and keeps it in the browser.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.9 <span class="muted">— 2026-08-11</span></h2>
|
|
<ul>
|
|
<li><strong>Changed default:</strong> <code>server.bindAddress</code> is now <code>127.0.0.1</code>
|
|
instead of <code>0.0.0.0</code>, because neither the UI nor the API authenticates read access.
|
|
Existing <code>.gittally.yml</code> files keep whatever they set; with the managed nginx
|
|
container, <code>0.0.0.0</code> has to be set explicitly.</li>
|
|
<li>The control token is accepted in the <code>X-GitTally-Token</code> header only — the
|
|
<code>token</code> query parameter is gone, as URLs end up in access logs and browser history.</li>
|
|
<li><code>config:print</code> masks <code>git.token</code>; <code>--show-secrets</code> prints it.</li>
|
|
<li>Files holding secrets (the Gitea token written by <code>init</code>, the control token) are
|
|
created with mode <code>0600</code> right away instead of being <code>chmod</code>-ed afterwards,
|
|
the control token is compared in constant time, and git calls pass <code>--</code> before
|
|
branch names.</li>
|
|
<li>On narrow screens the page title and the repository name are stacked instead of wrapping.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.8 <span class="muted">— 2026-08-10</span></h2>
|
|
<ul>
|
|
<li>The artifact index also links report pages of directories without an <code>index.html</code>.
|
|
A directory holding a single page is linked as a directory, so Gradle's <code>--profile</code>
|
|
report keeps a stable URL although its file name carries the build timestamp.</li>
|
|
<li>The permanent <code>🔗</code> link now appears on the build it resolves to — the branch's
|
|
latest green build — instead of on every build of that branch, and on all build tables.</li>
|
|
<li>The <em>Current</em> tab gave way to a <code>📡</code> link in the artifacts column,
|
|
shown while a build runs.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.7 <span class="muted">— 2026-08-10</span></h2>
|
|
<ul>
|
|
<li><code>init --systemd</code> also installs a nightly Docker cleanup timer
|
|
(<code>gittally-docker-prune.timer</code>, 02:00 host time): stopped containers and unused
|
|
images are pruned before the auto builds — like the legacy host, but the per-repository
|
|
Gradle cache volumes survive.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.6 <span class="muted">— 2026-08-10</span></h2>
|
|
<ul>
|
|
<li>This release-notes page, linked from the version in the footer.</li>
|
|
<li>Mobile: the live indicator collapses to a colored state dot so it no longer squeezes the menu.</li>
|
|
<li>The system page highlights critical utilization: the current value of CPU, RAM, and disk used
|
|
turns <span class="metric-warn">orange from 80%</span> and
|
|
<span class="metric-crit">red from 90%</span> of the respective total.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.5 <span class="muted">— 2026-08-10</span></h2>
|
|
<ul>
|
|
<li>Builds killed by a server shutdown (e.g. a deployment restart) are recorded as
|
|
<span class="status status-interrupted">interrupted</span> instead of
|
|
<span class="status status-failed">failed</span>, publish a <em>pending</em> Gitea status,
|
|
and are re-enqueued when the server starts again.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.4 <span class="muted">— 2026-08-10</span></h2>
|
|
<ul>
|
|
<li>The legacy page names (<code>/index.html</code>, <code>/branches.html</code>, …) answer with
|
|
permanent redirects to the new routes, so pre-rewrite bookmarks and the redirect from the
|
|
old host keep working.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.3 <span class="muted">— 2026-08-10</span></h2>
|
|
<ul>
|
|
<li>The artifact page shows a <span class="status status-failed">n failed</span> badge behind
|
|
links to test reports that contain failures.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.2 <span class="muted">— 2026-08-10</span></h2>
|
|
<ul>
|
|
<li>Cancelling a build also terminates its auxiliary phases (Docker image build, Gradle cache
|
|
volume preparation), so the next queued build starts immediately.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.1 <span class="muted">— 2026-08-10</span></h2>
|
|
<ul>
|
|
<li>Durations no longer flicker while live-updating.</li>
|
|
<li>While a build is running or pending, the artifact link shows an hourglass (logs only,
|
|
so far) instead of the report icon.</li>
|
|
<li>Pending builds show their queue wait time in italics; running and finished builds show
|
|
the pure build time without the wait.</li>
|
|
</ul>
|
|
|
|
<h2>v0.9.0 <span class="muted">— 2026-08-10</span></h2>
|
|
<p>Port of the legacy <em>gitTally</em> bash script to Kotlin/Spring Boot — the first production
|
|
deployment of the rewrite.</p>
|
|
<ul>
|
|
<li>Dual-mode application: CLI (<code>init</code>, <code>status</code>, <code>build</code>,
|
|
<code>retry</code>, <code>config:print</code>) and HTTP server with this web UI and a JSON API.</li>
|
|
<li>Declarative YAML configuration: committed <code>.gittally.yml</code> plus machine-specific
|
|
overrides and secrets under <code>.git/gittally/</code>.</li>
|
|
<li>Builds run detached in git worktrees — the primary checkout is never used for builds.</li>
|
|
<li>Docker build containers with automatic image rebuilds and a per-repository Gradle cache volume;
|
|
works under rootless Docker daemons; git metadata is available read-only inside the container.</li>
|
|
<li>Branch watcher with auto-builds (nightly slots), a pull-request gate, and pruning of results,
|
|
artifacts, and stale worktrees.</li>
|
|
<li>Commit statuses reported to Gitea; artifact store with per-branch retention and permanent
|
|
latest-green links; system metrics page.</li>
|
|
<li>Managed nginx/TLS container (Let's Encrypt) for hosts without a reverse proxy;
|
|
<code>init --systemd</code> generates the service unit.</li>
|
|
<li>Self-contained runtime bundle (jlink-trimmed JRE + jar) for hosts without a Java runtime.</li>
|
|
</ul>
|
|
|
|
</div>
|
|
</main>
|
|
<footer th:replace="~{fragments :: footer}"></footer>
|
|
<script src="/werkator.js"></script>
|
|
</body>
|
|
</html>
|