Expose remaining hypeman-go SDK surface in the CLI#56
Conversation
Closes the gap between the SDK's published methods/params and what the CLI exposed. The CLI previously called 50 of 52 SDK methods and left several params (health-check, restart-policy, multi-rule ingress) reachable only via compose. - add `update health-check` and `update restart-policy` subcommands - add `run --health-* / --restart-*` flags for imperative parity with compose - share one health-check/restart-policy mapping path across compose, run, and update (new lib/compose/policy.go) so the logic can't drift - add `volume create --from-archive <path|->` (Volumes.NewFromArchive) - add repeatable `ingress create --rule` for multi-rule ingresses - add top-level `health` command (Health.Check) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
bugbot run |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Autofix Details
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: HTTP probe allows zero port
- Health-check parsing now errors when HTTP metadata flags are used without --http-port, preventing generation of an HTTP probe with port 0.
- ✅ Fixed: Update ignores unlimited restarts
- Update restart-policy now explicitly sets max_attempts whenever --max-attempts is provided, so a value of 0 correctly clears the limit to unlimited.
Or push these changes by commenting:
@cursor push 9526924db2
Preview (9526924db2)
diff --git a/pkg/cmd/policyflags.go b/pkg/cmd/policyflags.go
--- a/pkg/cmd/policyflags.go
+++ b/pkg/cmd/policyflags.go
@@ -1,6 +1,8 @@
package cmd
import (
+ "fmt"
+
"github.com/kernel/hypeman-cli/lib/compose"
"github.com/urfave/cli/v3"
)
@@ -83,7 +85,7 @@
}
}
-func parseHealthCheckInput(cmd *cli.Command, prefix string) (compose.HealthCheckInput, bool) {
+func parseHealthCheckInput(cmd *cli.Command, prefix string) (compose.HealthCheckInput, bool, error) {
typeFlag := prefix + "type"
intervalFlag := prefix + "interval"
timeoutFlag := prefix + "timeout"
@@ -98,7 +100,15 @@
execFlag := prefix + "exec"
execWorkingDirFlag := prefix + "exec-working-dir"
- httpSet := cmd.IsSet(httpPortFlag) || cmd.IsSet(httpPathFlag) || cmd.IsSet(httpSchemeFlag) || cmd.IsSet(httpExpectedStatusFlag)
+ httpPortSet := cmd.IsSet(httpPortFlag)
+ httpMetadataSet := cmd.IsSet(httpPathFlag) || cmd.IsSet(httpSchemeFlag) || cmd.IsSet(httpExpectedStatusFlag)
+ if httpMetadataSet && !httpPortSet {
+ return compose.HealthCheckInput{}, false, fmt.Errorf(
+ "--%s is required when using --%s, --%s, or --%s",
+ httpPortFlag, httpPathFlag, httpSchemeFlag, httpExpectedStatusFlag,
+ )
+ }
+ httpSet := httpPortSet
tcpSet := cmd.IsSet(tcpPortFlag)
// Gate the exec block on --exec only: HealthCheckExecParam.Command is required,
// so building it from a lone --exec-working-dir would send an empty command.
@@ -106,9 +116,9 @@
set := cmd.IsSet(typeFlag) || cmd.IsSet(intervalFlag) || cmd.IsSet(timeoutFlag) ||
cmd.IsSet(startPeriodFlag) || cmd.IsSet(failureThresholdFlag) || cmd.IsSet(successThresholdFlag) ||
- httpSet || tcpSet || execSet
+ httpSet || httpMetadataSet || tcpSet || execSet
if !set {
- return compose.HealthCheckInput{}, false
+ return compose.HealthCheckInput{}, false, nil
}
in := compose.HealthCheckInput{
@@ -136,7 +146,7 @@
WorkingDir: cmd.String(execWorkingDirFlag),
}
}
- return in, true
+ return in, true, nil
}
func parseRestartPolicyInput(cmd *cli.Command, prefix string) (compose.RestartPolicyInput, bool) {
diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go
--- a/pkg/cmd/run.go
+++ b/pkg/cmd/run.go
@@ -273,7 +273,11 @@
if autoStandbySet {
params.AutoStandby = autoStandbyPolicy
}
- if healthInput, ok := parseHealthCheckInput(cmd, "health-"); ok {
+ healthInput, healthSet, err := parseHealthCheckInput(cmd, "health-")
+ if err != nil {
+ return err
+ }
+ if healthSet {
params.HealthCheck = compose.BuildHealthCheckParam(healthInput)
}
if restartInput, ok := parseRestartPolicyInput(cmd, "restart-"); ok {
diff --git a/pkg/cmd/update.go b/pkg/cmd/update.go
--- a/pkg/cmd/update.go
+++ b/pkg/cmd/update.go
@@ -149,7 +149,10 @@
return fmt.Errorf("instance ID or name required\nUsage: hypeman update health-check <instance> [flags]")
}
- input, set := parseHealthCheckInput(cmd, "")
+ input, set, err := parseHealthCheckInput(cmd, "")
+ if err != nil {
+ return err
+ }
if !set {
return fmt.Errorf("at least one health-check flag is required")
}
@@ -210,8 +213,13 @@
return err
}
+ restartPolicy := compose.BuildRestartPolicyParam(input)
+ if cmd.IsSet("max-attempts") {
+ restartPolicy.MaxAttempts = hypeman.Int(input.MaxAttempts)
+ }
+
params := hypeman.InstanceUpdateParams{
- RestartPolicy: compose.BuildRestartPolicyParam(input),
+ RestartPolicy: restartPolicy,
}
var opts []option.RequestOptionYou can send follow-ups to the cloud agent here.
- require --http-port (and --exec) before engaging the HTTP/exec health probe, so a secondary flag alone (--http-path/-scheme/-expected-status, --exec-working-dir) can't build a probe with a zero/empty api:"required" field - send restart max_attempts only when explicitly set, so `--max-attempts 0` (documented as unlimited) clears the limit on a PATCH instead of being omitted as a no-op; compose's omit-when-zero behavior is preserved - add policyflags tests for both Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit f713a72. Configure here.
|
Created a monitoring plan for this PR. What this PR does: Gives CLI users direct imperative access to workload health checks, restart policies, multi-rule ingress, and volume seeding from an archive — features that were previously only reachable through Intended effect: No production telemetry signal exists for this change — Risks:
Status updates will be posted automatically on this PR as monitoring progresses. |

Summary
The CLI called 50 of the SDK's 52 methods, and a few useful params (workload health check, restart policy, multi-rule ingress) were only reachable through
compose. This brings the CLI to full coverage of the published SDK surface.update health-check/update restart-policy— new subcommands that PATCHInstances.Update(previously theseInstanceUpdateParamsfields were never set by the CLI).run --health-* / --restart-*flags — imperative parity with whatcomposecould already declare, including HTTP scheme, expected-status, and exec working-dir.compose,run, and the newupdatesubcommands now buildHealthCheckParam/RestartPolicyParamthrough one set of builders (lib/compose/policy.go) so the logic can't drift.composebehavior is unchanged.volume create --from-archive <path|->— routes toVolumes.NewFromArchive(gzip body;-reads stdin). Was entirely unused.ingress create --rule(repeatable) —hostname[:host-port]=instance:port[,tls][,redirect-http], exposing theRulesarray the SDK supports. When any--ruleis given the single-rule shorthand flags are rejected (unambiguous precedence); a rule that omits the instance falls back to the positional<instance>.health— top-level command callingHealth.Check(GET /health, distinct fromresources).Test plan
go build ./...,go vet ./...,gofmt -lcleango test ./...passes, including a newTestParseIngressRuleSpec(8 cases) and the existingcomposetests (confirming the shared-builder refactor preserves behavior)update health-check,run --health-*,volume create --from-archive,ingress create --rule,health)🤖 Generated with Claude Code
Note
Medium Risk
Changes affect instance create/update (health/restart), ingress routing, and volume creation from archives; shared builders reduce mapping drift but incorrect flags could still send wrong API payloads.
Overview
Brings the CLI in line with the published hypeman-go SDK by wiring previously unused APIs and params that were only reachable through compose.
Shared policy builders — Health check and restart policy mapping moves into
lib/compose/policy.go(BuildHealthCheckParam/BuildRestartPolicyParam). Compose,run, and the new update flows all use the same path so behavior stays aligned; compose still only setsMaxAttemptswhen> 0, while CLI update can send explicit0for unlimited.Instance lifecycle —
rungains--health-*and--restart-*flags. Newupdate health-checkandupdate restart-policysubcommands PATCHInstances.Update. Reusable flag parsing lives inpolicyflags.gowith validation (e.g. HTTP probe requires--http-port).Ingress —
ingress createsupports repeatable--rule(hostname[:host-port]=instance:port[,tls][,redirect-http]); shorthand--hostname/--portflags are mutually exclusive with--rule. Single-rule mode now validates required flags at runtime instead of viaRequiredon the flag.Volumes & API health —
volume create --from-archivestreams a tar.gz (file or-stdin) toVolumes.NewFromArchive. Top-levelhealthcallsHealth.Check(server liveness, separate fromresources).Reviewed by Cursor Bugbot for commit f713a72. Bugbot is set up for automated code reviews on this repo. Configure here.