implemented 11-docker-build-runtime.md: added optional Docker-based build execution with configuration, per-branch runtime selection, image rebuild on input changes, Gradle cache volume, and ownership repair; updated docs and configuration
This commit is contained in:
@@ -83,6 +83,21 @@ branches:
|
||||
autoBuild:
|
||||
enabled: false # whether to rebuild on schedule
|
||||
times: ["01:00"] # UTC times HH:MM for scheduled builds
|
||||
# Optional Docker build runtime; when enabled, the clean and build commands
|
||||
# run inside a container instead of natively (see notes below).
|
||||
docker:
|
||||
# run clean/build commands in a Docker container
|
||||
enabled: false
|
||||
# image for the build container; required when enabled
|
||||
image: ""
|
||||
# Dockerfile to (re)build the image from when it is missing or stale; empty pulls the image as-is
|
||||
dockerfile: ""
|
||||
# Docker build context used with dockerfile
|
||||
context: "."
|
||||
# Docker network mode for the build container; empty = Docker default
|
||||
network: ""
|
||||
# additional environment variables set inside the build container
|
||||
env: {}
|
||||
|
||||
main:
|
||||
autoBuild:
|
||||
@@ -100,6 +115,16 @@ branches:
|
||||
- "04:00"
|
||||
```
|
||||
|
||||
### Notes on `branches.<name>.docker`
|
||||
|
||||
With `docker.enabled`, GitTally shells out to the `docker` CLI; the `docker` command must be on the `PATH`.
|
||||
When `dockerfile` is set, the image is (re)built whenever the Dockerfile content, its path, or the context path changed.
|
||||
Staleness is tracked via the image label `org.gittally.build-inputs-sha256`.
|
||||
A Gradle cache volume `gittally-gradle-<repo-key>` is created per repository and mounted as `GRADLE_USER_HOME`.
|
||||
The build worktree is bind-mounted into the container; after each command the ownership of `build/` and `.gradle/` is repaired to the host user.
|
||||
The Docker socket is mounted into the container and `DOCKER_HOST`/`TESTCONTAINERS_*` variables are set, so Testcontainers-based builds work inside the container.
|
||||
All GitTally containers carry `org.hoennig.gittally` labels; stale build containers of the repository are removed before the first Docker build after a restart.
|
||||
|
||||
## `.git/gittally/.gittally.yml` (not committed)
|
||||
|
||||
```yaml
|
||||
|
||||
@@ -37,3 +37,39 @@ Update `GitTallyConfig`, `InitCommand` templates, and `docs/configuration.md` to
|
||||
|
||||
- `./gradlew ktlintFormat` then `./gradlew build` is green with Docker absent.
|
||||
- Native execution path (step 04) is unchanged and remains the default.
|
||||
|
||||
## Implementation Notes (2026-07-07)
|
||||
|
||||
Implemented as designed: `DockerBuildRunner` (in `build/`) implements `BuildRunner` and shells out to the `docker` CLI via the generic `GitCommandRunner` process wrapper.
|
||||
The runtime is selected per branch by `DispatchingBuildRunner` (`@Primary`), so `BuildExecutor` keeps a single `BuildRunner` dependency and the native `ProcessBuildRunner` stays the default.
|
||||
No test needs Docker; the main `docker run` argv is asserted exactly through an injectable process launcher, everything else through the mocked command runner.
|
||||
|
||||
Ported from legacy:
|
||||
|
||||
- Image ensure (`ensure_docker_build_image`): rebuild when the image is missing or the `org.gittally.build-inputs-sha256` label no longer matches; all four `org.gittally.*` labels are set.
|
||||
Without a configured `dockerfile`, the image is used as-is and pulled by `docker run` on demand.
|
||||
- Gradle cache volume `gittally-gradle-<repo-key>`, created and chowned to the host uid/gid with the legacy container script.
|
||||
- Build container: workspace bind mount, `branch` env var, configured extra env, network mode, docker socket mount with `DOCKER_HOST`/`TESTCONTAINERS_*` for Testcontainers-based builds, `--add-host host.docker.internal:host-gateway` off host network.
|
||||
- Ownership repair of `build/` and `.gradle/` (`repair_docker_workspace_ownership`).
|
||||
- `org.hoennig.gittally` labels (role `build`) and stale-container cleanup.
|
||||
|
||||
Deviations and decisions:
|
||||
|
||||
- The `BuildRunner` interface gained `repoDir` and `branchConfig` parameters (with defaults), because runner selection and Docker settings are per branch and the per-repo volume/container names need the repository path — a worktree cannot resolve the uncommitted config layer.
|
||||
- The hsadmin-ng-specific legacy options were not ported, as the step suggests: no preflight command, no `JAVA_TOOL_OPTIONS` injection, no `.testcontainers.properties` generation, no `HSADMINNG_*` env passthrough — `TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE`/`TESTCONTAINERS_HOST_OVERRIDE`/`DOCKER_HOST` cover modern Testcontainers; anything else fits `docker.env`.
|
||||
- Ownership repair runs inside the same build container (wrapped around the command, preserving its exit code) instead of a follow-up root container; the separate `prepare_docker_workspace_build_dir` step became unnecessary because the clean command already runs in the container.
|
||||
- Container names are per branch (`gittally-build-<repo-key>-<branch-key>`), not per repository, because builds of different branches may run concurrently.
|
||||
- Containers run with `--init`, so termination signals from build cancellation reach the build process inside the container.
|
||||
- Stale labelled containers are removed before the first Docker build of the process, not at daemon startup, so installations that never build in Docker never invoke docker.
|
||||
- The Gradle volume is prepared once per process and image, not before every build.
|
||||
- A missing unix socket skips the socket mount instead of failing the build (legacy errored); a tcp:// `DOCKER_HOST` also skips it.
|
||||
- `docker.network` defaults to Docker's default network, not to `host` like legacy (host mode was an hsadmin-ng-ism); `network: host` switches the Testcontainers host override to `localhost` exactly like legacy.
|
||||
- Image-input checksums are computed in-process (`DockerImageInputs`), not via `sha256sum`, with the same input format as legacy.
|
||||
|
||||
Manual smoke test (2026-07-07, scratch repo, Rancher Desktop 27.3.1):
|
||||
|
||||
- A scratch repo with `docker.enabled`, a two-line Dockerfile, and a build command writing `id -u` into `build/who.txt`: `gittally build` built the image with all four labels, created the `gittally-gradle-<repo-key>` volume, streamed the container output live, and exited 0 (`success after 0:14`).
|
||||
- A second run reused the image (inputs label matched, no rebuild; `success after 0:04`).
|
||||
- The command ran as uid 0 inside the container while `build/who.txt` ended up owned by the host user — the in-container ownership repair works.
|
||||
- No labelled containers were left behind after the builds.
|
||||
- Caveat found while testing (environmental, not GitTally): with a VM-based Docker (Rancher Desktop/Lima), workspace bind mounts only work for paths shared into the VM (e.g. `$HOME`); a repo under an unshared `/tmp` builds against an empty VM-side directory.
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ Server and UI:
|
||||
Completion:
|
||||
|
||||
- [x] `10-cli-commands.md` — CLI build/status commands
|
||||
- [ ] `11-docker-build-runtime.md` — optional Docker build execution
|
||||
- [x] `11-docker-build-runtime.md` — optional Docker build execution
|
||||
- [ ] `12-deployment.md` — systemd service, migration from legacy, docs
|
||||
|
||||
Steps 01–03 are independent of each other.
|
||||
|
||||
Reference in New Issue
Block a user