New migration 007_add_healthcheck_command.sql adds a nullable healthcheck_command TEXT column to the apps table.
Model (internal/models/app.go)
Added HealthcheckCommand sql.NullString field to the App struct.
Updated all column lists, insert/update queries, and scan methods to include the new field.
Docker Client (internal/docker/client.go)
Added HealthcheckCommand field to CreateContainerOptions.
Added buildHealthcheck() function that converts a shell command string into a Docker HealthConfig with CMD-SHELL test type, 30s interval, 10s timeout, 15s start period, and 3 retries.
When HealthcheckCommand is set on container options, the health check config is applied to the container at creation time.
Deploy Service (internal/service/deploy/deploy.go)
buildContainerOptions now reads the app's HealthcheckCommand and passes it through to CreateContainerOptions.
App Service (internal/service/app/app.go)
Added HealthcheckCommand to both CreateAppInput and UpdateAppInput.
Both CreateApp and UpdateApp now handle the new field.
Handlers (internal/handlers/app.go)
App create and update handlers read the healthcheck_command form field.
Extracted optionalNullString() helper to reduce cyclomatic complexity in HandleAppUpdate.
Templates
Both app_new.html and app_edit.html include a new "Health Check Command" input field under Optional Settings, with a placeholder example (curl -f http://localhost:8080/healthz || exit 1) and help text.
README
Updated features list to mention custom health checks.
Tests Added
TestBuildHealthcheck — validates the Docker health config structure and timing values.
TestAppHealthcheckCommand — model-level tests for save/load/clear of the healthcheck_command field.
TestBuildContainerOptionsHealthcheckSet / TestBuildContainerOptionsHealthcheckEmpty — deploy service tests verifying the healthcheck command flows through container options correctly.
Behavior
When set: The custom command runs as CMD-SHELL inside the container (e.g., curl -f http://localhost:8080/healthz || exit 1).
When empty: Falls back to the image's built-in HEALTHCHECK instruction (existing behavior, no change).
The existing 60-second post-deploy health check in checkHealthAfterDelay continues to work — it checks Docker's container health status, which will now use the custom command if configured.
## Summary
Allow configuring custom health check commands per app instead of only relying on the image's default Docker health check.
closes https://git.eeqj.de/sneak/upaas/issues/81
## What Changed
### Database
- New migration `007_add_healthcheck_command.sql` adds a nullable `healthcheck_command` TEXT column to the `apps` table.
### Model (`internal/models/app.go`)
- Added `HealthcheckCommand sql.NullString` field to the `App` struct.
- Updated all column lists, insert/update queries, and scan methods to include the new field.
### Docker Client (`internal/docker/client.go`)
- Added `HealthcheckCommand` field to `CreateContainerOptions`.
- Added `buildHealthcheck()` function that converts a shell command string into a Docker `HealthConfig` with `CMD-SHELL` test type, 30s interval, 10s timeout, 15s start period, and 3 retries.
- When `HealthcheckCommand` is set on container options, the health check config is applied to the container at creation time.
### Deploy Service (`internal/service/deploy/deploy.go`)
- `buildContainerOptions` now reads the app's `HealthcheckCommand` and passes it through to `CreateContainerOptions`.
### App Service (`internal/service/app/app.go`)
- Added `HealthcheckCommand` to both `CreateAppInput` and `UpdateAppInput`.
- Both `CreateApp` and `UpdateApp` now handle the new field.
### Handlers (`internal/handlers/app.go`)
- App create and update handlers read the `healthcheck_command` form field.
- Extracted `optionalNullString()` helper to reduce cyclomatic complexity in `HandleAppUpdate`.
### Templates
- Both `app_new.html` and `app_edit.html` include a new "Health Check Command" input field under Optional Settings, with a placeholder example (`curl -f http://localhost:8080/healthz || exit 1`) and help text.
### README
- Updated features list to mention custom health checks.
## Tests Added
- `TestBuildHealthcheck` — validates the Docker health config structure and timing values.
- `TestAppHealthcheckCommand` — model-level tests for save/load/clear of the healthcheck_command field.
- `TestBuildContainerOptionsHealthcheckSet` / `TestBuildContainerOptionsHealthcheckEmpty` — deploy service tests verifying the healthcheck command flows through container options correctly.
## Behavior
- **When set**: The custom command runs as `CMD-SHELL` inside the container (e.g., `curl -f http://localhost:8080/healthz || exit 1`).
- **When empty**: Falls back to the image's built-in HEALTHCHECK instruction (existing behavior, no change).
- The existing 60-second post-deploy health check in `checkHealthAfterDelay` continues to work — it checks Docker's container health status, which will now use the custom command if configured.
Add configurable health check commands per app via a new
'healthcheck_command' field. When set, the command is passed
to Docker as a CMD-SHELL health check on the container.
When empty, the image's default health check is used.
Changes:
- Add migration 007 for healthcheck_command column on apps table
- Add HealthcheckCommand field to App model with full CRUD support
- Add buildHealthcheck() to docker client for CMD-SHELL config
- Pass health check command through CreateContainerOptions
- Add health check command input to app create/edit UI forms
- Extract optionalNullString helper to reduce handler complexity
- Update README features list
closes#81
Rebase onto main — already up to date, build passes post-rebase.
Code Quality Notes
optionalNullString() helper is a clean refactor that reduces cyclomatic complexity in HandleAppUpdate while maintaining identical behavior for existing fields.
Health check timing constants are well-named and reasonable (30s interval, 10s timeout, 15s start period, 3 retries).
Consistent with existing patterns for nullable optional fields (DockerNetwork, NtfyTopic, SlackWebhook).
No scope creep — changes are limited to the health check feature.
Verdict: PASS✅
All policy rules satisfied. All issue requirements fully implemented. Build passes. Tests comprehensive. Code is clean, consistent, and follows established patterns.
## Review of [PR #166](https://git.eeqj.de/sneak/upaas/pulls/166) — Custom Health Check Commands
Reviewing against [issue #81](https://git.eeqj.de/sneak/upaas/issues/81).
---
## Policy Divergences
No policy violations found.
- All Docker images pinned by `@sha256:` — no new external references introduced.
- Post-1.0.0 (tag `1.0.0` exists): new migration file `007_add_healthcheck_command.sql` is correct.
- No modifications to `.golangci.yml`, Makefile, CI config, or test assertions.
- No weakened tests, no suppressed linter rules.
- Column ordering in `appColumns`, `scan()`, `scanApps()`, `insert()`, and `update()` are all consistent.
- `go fmt`, lint, and tests all pass via `docker build .`.
---
## Requirements Checklist
| Requirement | Status |
|---|---|
| Allow configuring custom health check commands per app | ✅ Met — new field in DB, model, service, handlers, and templates |
| Custom command runs as `CMD-SHELL` in Docker | ✅ Met — `buildHealthcheck()` creates `CMD-SHELL` config |
| Empty/unset falls back to image default | ✅ Met — only applied when `HealthcheckCommand != ""` |
| Database schema updated | ✅ Met — migration 007 adds nullable `healthcheck_command TEXT` |
| Create and edit forms support the field | ✅ Met — both `app_new.html` and `app_edit.html` include the input |
| Field persists through save/load/clear | ✅ Met — tested in `TestAppHealthcheckCommand` |
| README updated | ✅ Met — features list now mentions custom health checks |
| Tests cover new functionality | ✅ Met — 4 new test functions covering health check config, model, and deploy service |
---
## Build Result
`docker build .` — **PASS** (fmt-check, lint, tests, compilation all succeed).
Rebase onto `main` — already up to date, build passes post-rebase.
---
## Code Quality Notes
- `optionalNullString()` helper is a clean refactor that reduces cyclomatic complexity in `HandleAppUpdate` while maintaining identical behavior for existing fields.
- Health check timing constants are well-named and reasonable (30s interval, 10s timeout, 15s start period, 3 retries).
- Consistent with existing patterns for nullable optional fields (DockerNetwork, NtfyTopic, SlackWebhook).
- No scope creep — changes are limited to the health check feature.
---
## Verdict: **PASS** ✅
All policy rules satisfied. All issue requirements fully implemented. Build passes. Tests comprehensive. Code is clean, consistent, and follows established patterns.
Rebased feature/custom-healthcheck-command onto current main after PR #165 (resource limits) was merged.
Conflicts resolved
File
Resolution
internal/models/app.go
Added HealthcheckCommand field after CPULimit/MemoryLimit in struct, column list, scan, insert, and update
internal/docker/client.go
Added HealthcheckCommand field to CreateContainerOptions alongside CPULimit/MemoryLimit. Kept both buildResources() and buildHealthcheck() helpers. Switched to containerConfig variable pattern for healthcheck conditional
internal/handlers/app.go
Added healthcheck form parsing before resource limit validation. Removed duplicate optionalNullString() (kept main's version)
internal/service/deploy/deploy.go
Added healthcheck extraction alongside resource limit extraction. Extracted extractResourceLimits() helper to keep buildContainerOptions within 60-line funlen limit
internal/service/deploy/deploy_container_test.go
Preserved all 3 resource limit tests from PR #165 AND both healthcheck tests from this PR
templates/app_edit.html
Kept both healthcheck command field and resource limits section
README.md
Combined both feature descriptions
internal/database/migrations/
Renumbered healthcheck migration from 007 → 008 (main has 007_add_resource_limits.sql)
Build verification
make fmt✅
docker build .✅ (format check, lint, all tests, binary build)
No logic changes — conflict resolution only.
## Rebase conflict resolution
Rebased `feature/custom-healthcheck-command` onto current `main` after [PR #165](https://git.eeqj.de/sneak/upaas/pulls/165) (resource limits) was merged.
### Conflicts resolved
| File | Resolution |
|------|------------|
| `internal/models/app.go` | Added `HealthcheckCommand` field after `CPULimit`/`MemoryLimit` in struct, column list, scan, insert, and update |
| `internal/docker/client.go` | Added `HealthcheckCommand` field to `CreateContainerOptions` alongside `CPULimit`/`MemoryLimit`. Kept both `buildResources()` and `buildHealthcheck()` helpers. Switched to `containerConfig` variable pattern for healthcheck conditional |
| `internal/handlers/app.go` | Added healthcheck form parsing before resource limit validation. Removed duplicate `optionalNullString()` (kept main's version) |
| `internal/service/deploy/deploy.go` | Added healthcheck extraction alongside resource limit extraction. Extracted `extractResourceLimits()` helper to keep `buildContainerOptions` within 60-line funlen limit |
| `internal/service/deploy/deploy_container_test.go` | Preserved all 3 resource limit tests from PR #165 AND both healthcheck tests from this PR |
| `templates/app_edit.html` | Kept both healthcheck command field and resource limits section |
| `README.md` | Combined both feature descriptions |
| `internal/database/migrations/` | Renumbered healthcheck migration from `007` → `008` (main has `007_add_resource_limits.sql`) |
### Build verification
- `make fmt` ✅
- `docker build .` ✅ (format check, lint, all tests, binary build)
No logic changes — conflict resolution only.
clawbot
removed their assignment 2026-03-20 06:59:38 +01:00
sneak
was assigned by clawbot2026-03-20 06:59:38 +01:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Allow configuring custom health check commands per app instead of only relying on the image's default Docker health check.
closes #81
What Changed
Database
007_add_healthcheck_command.sqladds a nullablehealthcheck_commandTEXT column to theappstable.Model (
internal/models/app.go)HealthcheckCommand sql.NullStringfield to theAppstruct.Docker Client (
internal/docker/client.go)HealthcheckCommandfield toCreateContainerOptions.buildHealthcheck()function that converts a shell command string into a DockerHealthConfigwithCMD-SHELLtest type, 30s interval, 10s timeout, 15s start period, and 3 retries.HealthcheckCommandis set on container options, the health check config is applied to the container at creation time.Deploy Service (
internal/service/deploy/deploy.go)buildContainerOptionsnow reads the app'sHealthcheckCommandand passes it through toCreateContainerOptions.App Service (
internal/service/app/app.go)HealthcheckCommandto bothCreateAppInputandUpdateAppInput.CreateAppandUpdateAppnow handle the new field.Handlers (
internal/handlers/app.go)healthcheck_commandform field.optionalNullString()helper to reduce cyclomatic complexity inHandleAppUpdate.Templates
app_new.htmlandapp_edit.htmlinclude a new "Health Check Command" input field under Optional Settings, with a placeholder example (curl -f http://localhost:8080/healthz || exit 1) and help text.README
Tests Added
TestBuildHealthcheck— validates the Docker health config structure and timing values.TestAppHealthcheckCommand— model-level tests for save/load/clear of the healthcheck_command field.TestBuildContainerOptionsHealthcheckSet/TestBuildContainerOptionsHealthcheckEmpty— deploy service tests verifying the healthcheck command flows through container options correctly.Behavior
CMD-SHELLinside the container (e.g.,curl -f http://localhost:8080/healthz || exit 1).checkHealthAfterDelaycontinues to work — it checks Docker's container health status, which will now use the custom command if configured.Review of PR #166 — Custom Health Check Commands
Reviewing against issue #81.
Policy Divergences
No policy violations found.
@sha256:— no new external references introduced.1.0.0exists): new migration file007_add_healthcheck_command.sqlis correct..golangci.yml, Makefile, CI config, or test assertions.appColumns,scan(),scanApps(),insert(), andupdate()are all consistent.go fmt, lint, and tests all pass viadocker build ..Requirements Checklist
CMD-SHELLin DockerbuildHealthcheck()createsCMD-SHELLconfigHealthcheckCommand != ""healthcheck_command TEXTapp_new.htmlandapp_edit.htmlinclude the inputTestAppHealthcheckCommandBuild Result
docker build .— PASS (fmt-check, lint, tests, compilation all succeed).Rebase onto
main— already up to date, build passes post-rebase.Code Quality Notes
optionalNullString()helper is a clean refactor that reduces cyclomatic complexity inHandleAppUpdatewhile maintaining identical behavior for existing fields.Verdict: PASS ✅
All policy rules satisfied. All issue requirements fully implemented. Build passes. Tests comprehensive. Code is clean, consistent, and follows established patterns.
@clawbot fix
e2522f2017to067cb86124Rebase conflict resolution
Rebased
feature/custom-healthcheck-commandonto currentmainafter PR #165 (resource limits) was merged.Conflicts resolved
internal/models/app.goHealthcheckCommandfield afterCPULimit/MemoryLimitin struct, column list, scan, insert, and updateinternal/docker/client.goHealthcheckCommandfield toCreateContainerOptionsalongsideCPULimit/MemoryLimit. Kept bothbuildResources()andbuildHealthcheck()helpers. Switched tocontainerConfigvariable pattern for healthcheck conditionalinternal/handlers/app.gooptionalNullString()(kept main's version)internal/service/deploy/deploy.goextractResourceLimits()helper to keepbuildContainerOptionswithin 60-line funlen limitinternal/service/deploy/deploy_container_test.gotemplates/app_edit.htmlREADME.mdinternal/database/migrations/007→008(main has007_add_resource_limits.sql)Build verification
make fmt✅docker build .✅ (format check, lint, all tests, binary build)No logic changes — conflict resolution only.
nobody wants this
Pull request closed