2.8 KiB
2.8 KiB
Step 01: Build State Domain and Repository
Prerequisites: none.
Read README.md and 00-legacy-analysis.md first.
Goal
A tested domain model for build results plus a persistent repository, replacing the legacy build-results.tsv.
Design
Create package de.hoennig.gittally.build:
BuildStatusenum:PENDING,RUNNING,SUCCESS,FAILED,INTERRUPTED,CANCELLED. AddisTerminal,isRestartable(pending/running/interrupted) properties.BuildResultdata class: branch, commit SHA, status, startedAt, duration, artifactKey. Usejava.time.Instant/Duration; format only at the edges.BuildResultRepositoryinterface: append, update status of latest entry for a branch, query latest per branch, query history, delete entry, prune.FileBuildResultRepository: JSON file at.git/gittally/build-results.json. Write atomically (write temp file, thenFiles.movewithATOMIC_MOVE). Reuse the Jackson YAML/JSON setup style fromConfigLoader.
Business logic to include (port from legacy, see analysis):
markStaleRunningAsInterrupted()— called at startup; running → interrupted, superseded pending → interrupted.- Retention pruning: keep N builds per branch (
artifacts.retentionPerBranch); drop entries for branches no longer on origin (branch list passed in as a parameter, no git dependency here).
Out of Scope
- No git access, no Gitea, no execution — pure domain and file I/O.
- Artifact directory pruning (step 05 consumes the pruning result).
- Age-based retention (legacy supported
h/dsuffixes); count-based only, extend later if needed.
Config
Uses existing artifacts.retentionPerBranch.
No new keys expected.
Tests
Kotest FunSpec, no Spring context needed.
- Round-trip persistence, atomicity (temp file cleaned up).
- Status transition helpers and
markStaleRunningAsInterruptededge cases. - Retention pruning: per-branch count, removed branches, ordering by timestamp.
- Corrupt/missing file → empty repository, no crash (legacy failed silently; we log a warning).
Acceptance Criteria
./gradlew ktlintFormatthen./gradlew buildis green.- New code has no dependency on picocli or web classes.
Execution Notes (done 2026-07-07)
Implemented as specified in de.hoennig.gittally.build; build green, 19 new tests.
Deviations and details:
- Added
jackson-datatype-jsr310tobuild.gradle.ktsforInstant/DurationJSON support (ISO-8601 strings). FileBuildResultRepositoryis a plain class, not a Spring bean; the file path depends on the runtime repo location, so wiring happens in step 04/06 via a factory or configuration.prune(...)andmarkStaleRunningAsInterrupted()return the removed/changed entries so step 05 can prune artifact directories and callers can log.- Timestamp ties in
updateLatest/latestForresolve to the later appended entry.