implemented 06-watcher.md: non-blocking poll cycle enqueueing changed/new/auto-build branches via the async executor, startup recovery, retention/worktree pruning, JSON auto-build slot state, watcher.pollInterval config, and watcher health state
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
3c9eeda5da
commit
a1db450bdb
@@ -54,6 +54,8 @@ artifacts:
|
||||
|
||||
# Controls the branch-polling loop.
|
||||
watcher:
|
||||
# delay between poll cycles; suffixes s (seconds), m (minutes), h (hours), d (days)
|
||||
pollInterval: 10s
|
||||
# max commit age for new origin branches to be pulled automatically
|
||||
newBranchMaxAge: 5d
|
||||
|
||||
|
||||
@@ -48,3 +48,41 @@ Update `GitTallyConfig`, `InitCommand` templates, and `docs/configuration.md` to
|
||||
|
||||
- `./gradlew ktlintFormat` then `./gradlew build` is green.
|
||||
- A test proves a poll cycle completes while a (fake) build is running.
|
||||
|
||||
## Execution Notes (done 2026-07-07)
|
||||
|
||||
Implemented as designed in `de.hoennig.gittally.watcher`; build green, 23 new tests
|
||||
(`WatcherTest`, `AutoBuildStateTest`, plus new `DurationParserTest` and `GitServiceTest` cases).
|
||||
Deviations and decisions:
|
||||
|
||||
- The poll loop is a managed single-thread `ScheduledExecutorService` with fixed delay, not Spring `@Scheduled`:
|
||||
scheduling annotations would run during CLI commands and tests.
|
||||
Nothing starts automatically; server/watch mode (step 07) must call `Watcher.start(workingDir)` explicitly,
|
||||
which runs the startup recovery and then polls immediately and on every `watcher.pollInterval`.
|
||||
`ApplicationContextTest` stays green and fast because constructing the beans schedules nothing.
|
||||
- "Changed" is detected against the result repository (`latestFor(branch).commit != origin head`),
|
||||
gated by `hasNewCommits`, instead of resetting local refs like legacy:
|
||||
builds run detached in per-branch worktrees and never move local branch refs,
|
||||
so a legacy-style local-ref comparison would re-enqueue the same commit forever.
|
||||
Consequence: a failed build of a commit is not retried automatically (same as legacy) — step 10 adds the retry command.
|
||||
- Queue-behind vs. cancel-on-new-commit: DEFERRED, keeping queue-behind semantics at watcher granularity.
|
||||
A branch whose latest build is PENDING or RUNNING is skipped; the new commit is picked up on a later cycle
|
||||
once the build finished. Making this per-branch configurable (cancel and rebuild instead) remains open,
|
||||
see also the step 04 amendment.
|
||||
- Enqueue precedence per cycle: changed local branches, then recent new origin branches, then due auto-build slots;
|
||||
each branch at most once (an auto-build slot stays untriggered while its branch is pending/running and fires
|
||||
on a later cycle instead of being lost).
|
||||
- Auto-build state lives in `.git/gittally/auto-builds.json` (`FileAutoBuildState`, replaces `auto-builds.tsv`);
|
||||
entries of past days are dropped on write. Slot matching (`AutoBuildSlots`) picks the latest slot at or before
|
||||
the current UTC time, like legacy `auto_build_check`. Only branches named in the `branches` config
|
||||
(other than `default`) can auto-build; `default.autoBuild.enabled` does not extend to unlisted branches.
|
||||
- Startup recovery re-enqueues branches whose latest result is PENDING or INTERRUPTED and which still exist
|
||||
on origin, after a best-effort fetch (a failing fetch recovers from the last known origin state).
|
||||
A stale latest PENDING entry is marked INTERRUPTED before its replacement build is enqueued,
|
||||
because the executor queue does not survive a restart.
|
||||
- Worktree cleanup deletes `.git/gittally/worktrees/<branchKey>` directories of branches gone from origin
|
||||
(never those of queued or running builds) and then calls `git worktree prune`.
|
||||
- `DurationParser` was extended with `s`/`m` suffixes for `watcher.pollInterval` (it only knew `d`/`h`).
|
||||
- Watcher health is exposed via `Watcher.state(): WatcherState` (running, last poll time, last fetch/poll error,
|
||||
queued branches) for the step 07 status endpoints; no events are published for it.
|
||||
- A UTC `Clock` bean (`WatcherConfiguration`) makes slot matching and poll timestamps testable.
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ Core engine:
|
||||
|
||||
- [x] `04-build-executor.md` — async build execution with logs, cancellation, status transitions
|
||||
- [x] `05-artifact-store.md` — artifact persistence, naming, retention
|
||||
- [ ] `06-watcher.md` — branch watching, scheduling, auto-builds
|
||||
- [x] `06-watcher.md` — branch watching, scheduling, auto-builds
|
||||
|
||||
Server and UI:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user