./gradlew runtimeBundle packs a jlink-trimmed JRE, gittally.jar, and a launcher script into one tarball, unpacked to ~/opt/gittally on the target host; init --systemd works from the bundle unchanged because java.home and the running-jar path resolve into it. Chosen over a GraalVM native image (Spring AOT evaluates bean conditions at build time, which cannot represent the dual-context CLI/server wiring) and over a containerized runtime — see ADR 0006 and docs/plan/15-runtime-bundle-distribution.md, which also records the full vm2176-to-vm4006 migration walkthrough. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
58 lines
3.6 KiB
Markdown
58 lines
3.6 KiB
Markdown
# Self-Contained Runtime Bundle Distribution
|
|
|
|
**Status:**
|
|
- proposed: 2026-08-10
|
|
- accepted: 2026-08-10
|
|
- rejected: -
|
|
- superseded: -
|
|
|
|
**Decision [accepted]:** GitTally is distributed for hosts without a Java runtime as a self-contained runtime bundle — a jlink-trimmed JRE plus `gittally.jar` plus a launcher script in one tarball, built by `./gradlew runtimeBundle`.
|
|
The JAR stays the primary artifact; a GraalVM native image and a containerized GitTally runtime were rejected.
|
|
|
|
## Context and Problem Statement
|
|
|
|
GitTally must run on Hostsharing container servers (the primary target, see ADR 0005).
|
|
These hosts provide git, Docker, make, and systemd user sessions, but no Java runtime, and nothing may be installed system-wide.
|
|
`docs/bootstrapping.md` sketched a containerized GitTally runtime as the future answer; that sketch was never validated against the operational details.
|
|
|
|
## Considered Options
|
|
|
|
* jlink runtime bundle (trimmed JRE + jar + launcher, one tarball)
|
|
* GraalVM native image (single executable)
|
|
* Containerized GitTally runtime (the original `docs/bootstrapping.md` sketch)
|
|
|
|
### jlink Runtime Bundle
|
|
|
|
A `jlink`-generated JRE with the pinned module list, the boot jar, and a `bin/gittally` launcher script, packed as `gittally-runtime-linux-x64.tar.gz` (~66 MB) and unpacked to `~/opt/gittally/` on the target host.
|
|
|
|
Good:
|
|
|
|
- No production-code changes and plain JVM semantics — no new failure modes.
|
|
- git and docker CLIs are used from the host; build worktree paths stay host paths.
|
|
- `init --systemd` works unchanged: `java.home` and the running-jar path resolve into the bundle, so the generated unit points at `<bundle>/jre/bin/java` and `<bundle>/lib/gittally.jar` (verified).
|
|
- Every JDK 21 ships jlink — no new build-toolchain requirement.
|
|
|
|
Bad:
|
|
|
|
- A directory tree, not a single file (still one tarball to copy).
|
|
- JVM startup (~1-2 s) instead of native-image startup — irrelevant for a long-running server.
|
|
- The jlink image links glibc dynamically: build on glibc ≤ target (Ubuntu 24.04 dev machine: 2.39; vm4006 Debian 13: 2.41 — compatible), same architecture.
|
|
|
|
### GraalVM Native Image
|
|
|
|
Rejected because Spring AOT evaluates bean conditions at build time, and GitTally's dual-mode wiring cannot be represented in a single AOT arrangement:
|
|
the CLI context runs without web and with `@Profile("!server")` `CliRunner`, while the `server` subcommand starts a second `SpringApplication` with `WebApplicationType.SERVLET` and the `server` profile gating the watcher/metrics/nginx lifecycles.
|
|
Whichever profile and web type the AOT processing fixes, the other mode's beans are missing from the binary.
|
|
Supporting both would require replacing the profile wiring with runtime guards and collapsing the two context shapes — an invasive rewrite with regression risk for the JVM path, on top of the usual native-image reflection work (Jackson-bound config and persistence classes, picocli).
|
|
|
|
### Containerized GitTally Runtime
|
|
|
|
Rejected for operational complexity: the image must bundle git and docker CLIs; the container needs a same-path `$HOME` mount plus a docker-socket mount and uid/gid mapping so that `DockerBuildRunner`'s `--volume $workspace:$workspace` sibling mounts keep working; and the systemd unit must be hand-edited to a `docker run` invocation.
|
|
This remains the documented fallback if the runtime bundle ever becomes unworkable.
|
|
|
|
## Consequences
|
|
|
|
- `docs/deployment.md` documents the bundle path; the "Future: Docker-based Deployment" section in `docs/bootstrapping.md` is replaced.
|
|
- The pinned JDK module list in `build.gradle.kts` must be re-checked (via the documented jdeps command) when dependencies change.
|
|
- Deployment and migration for vm4006 follow plan step 15.
|