Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ func Run(args []string) int {
return 1
}

if shouldShowTopLevelHelp(execArgs) {
commands.RenderTopLevelHelp(d)
return 0
}

err = d.Execute(execArgs)
if err != nil {
if errors.Is(err, context.Canceled) {
Expand All @@ -66,6 +71,22 @@ func Run(args []string) int {
return 0
}

// shouldShowTopLevelHelp returns true when the args indicate we should render
// top-level help (no args, or just -h/--help with no command).
func shouldShowTopLevelHelp(args []string) bool {
if len(args) == 0 {
return true
}
// Only help flags, no command words
for _, arg := range args {
if arg == "-h" || arg == "--help" {
continue
}
return false
}
return true
}

// printError renders an error to stderr. If the error implements
// ui.TerminalError, it gets colorized multi-line output; otherwise
// it falls back to a plain "ERROR: ..." line.
Expand Down
46 changes: 28 additions & 18 deletions cli/commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
func RegisterAll(d *mflags.Dispatcher) {
// Core commands
d.Dispatch("version", Infer("version", "Print the version", Version,
WithGroup(GroupClient),
WithExample(mflags.Example{
Name: "Print version",
Body: "miren version",
Expand All @@ -18,6 +19,7 @@ func RegisterAll(d *mflags.Dispatcher) {
}),
))
d.Dispatch("login", Infer("login", "Authenticate with miren.cloud", Login,
WithGroup(GroupClient),
WithExample(mflags.Example{
Name: "Login",
Body: "miren login",
Expand All @@ -28,12 +30,14 @@ func RegisterAll(d *mflags.Dispatcher) {
}),
))
d.Dispatch("logout", Infer("logout", "Remove local authentication credentials", Logout,
WithGroup(GroupClient),
WithExample(mflags.Example{
Name: "Logout",
Body: "miren logout",
}),
))
d.Dispatch("whoami", Infer("whoami", "Display information about the current authenticated user", Whoami,
WithGroup(GroupClient),
WithExample(mflags.Example{
Name: "Show current user",
Body: "miren whoami",
Expand All @@ -46,6 +50,7 @@ func RegisterAll(d *mflags.Dispatcher) {

// Doctor commands
d.Dispatch("doctor", Infer("doctor", "Diagnose miren environment and connectivity", Doctor,
WithGroup(GroupClient),
WithExample(mflags.Example{
Name: "Run all diagnostics",
Body: "miren doctor",
Expand All @@ -72,6 +77,7 @@ func RegisterAll(d *mflags.Dispatcher) {

// App lifecycle commands
d.Dispatch("init", Infer("init", "Initialize a new application", Init,
WithGroup(GroupGettingStarted),
WithExample(mflags.Example{
Name: "Initialize in current directory",
Body: "miren init",
Expand All @@ -82,6 +88,7 @@ func RegisterAll(d *mflags.Dispatcher) {
}),
))
d.Dispatch("deploy", Infer("deploy", "Deploy an application", Deploy,
WithGroup(GroupGettingStarted),
WithExample(mflags.Example{
Name: "Basic",
Body: "miren deploy",
Expand Down Expand Up @@ -114,6 +121,7 @@ miren deploy --analyze
}),
))
d.Dispatch("rollback", Infer("rollback", "Roll back to a previous version", Rollback,
WithGroup(GroupGettingStarted),
WithExample(mflags.Example{
Name: "Rollback the app in the current directory",
Body: "miren rollback",
Expand All @@ -124,6 +132,7 @@ miren deploy --analyze
}),
))
d.Dispatch("logs", Infer("logs", "View logs (defaults to app logs)", LogsApp,
WithGroup(GroupMonitoring),
WithDescription(logsDescription),
WithExample(mflags.Example{
Name: "View logs for the current app",
Expand Down Expand Up @@ -190,6 +199,7 @@ miren deploy --analyze

// App management commands
d.Dispatch("app", Infer("app", "Get information about an application", App,
WithGroup(GroupMonitoring),
WithExample(mflags.Example{
Name: "Show app info for the current directory",
Body: "miren app",
Expand Down Expand Up @@ -287,14 +297,15 @@ miren deploy --analyze
}),
))
d.Dispatch("apps", Infer("apps", "List all applications (alias for 'app list')", AppList,
WithGroup(GroupMonitoring),
WithExample(mflags.Example{
Name: "List all apps",
Body: "miren apps",
}),
))

// Sandbox commands
d.Dispatch("sandbox", Section("sandbox", "Sandbox management commands", "", WithSectionDescription(sandboxSectionDescription)))
d.Dispatch("sandbox", Section("sandbox", "Sandbox management commands", "", WithSectionDescription(sandboxSectionDescription), WithSectionGroup(GroupMonitoring)))
d.Dispatch("sandbox list", Infer("sandbox list", "List sandboxes (excludes dead by default)", SandboxList,
WithExample(mflags.Example{
Name: "List running sandboxes",
Expand Down Expand Up @@ -338,7 +349,7 @@ miren deploy --analyze
))

// Sandbox pool commands
d.Dispatch("sandbox-pool", Section("sandbox-pool", "Sandbox pool management commands", ""))
d.Dispatch("sandbox-pool", Section("sandbox-pool", "Sandbox pool management commands", "", WithSectionGroup(GroupMonitoring)))
d.Dispatch("sandbox-pool list", Infer("sandbox-pool list", "List all sandbox pools", SandboxPoolList,
WithExample(mflags.Example{
Name: "List all pools",
Expand All @@ -353,7 +364,7 @@ miren deploy --analyze
))

// Environment variable commands
d.Dispatch("env", Section("env", "Environment variable management commands", ""))
d.Dispatch("env", Section("env", "Environment variable management commands", "", WithSectionGroup(GroupConfiguring)))
d.Dispatch("env set", Infer("env set", "Set environment variables for an application", EnvSet,
WithExample(mflags.Example{
Name: "Set an environment variable",
Expand Down Expand Up @@ -409,7 +420,7 @@ miren deploy --analyze

// Addon commands (gated behind labs flag)
if labs.Addons() {
d.Dispatch("addon", Section("addon", "Addon management commands", ""))
d.Dispatch("addon", Section("addon", "Addon management commands", "", WithSectionGroup(GroupConfiguring)))
d.Dispatch("addon list-available", Infer("addon list-available", "List available addons", AddonListAvailable,
WithLabsFeature(labs.FeatureAddons),
WithExample(mflags.Example{
Expand Down Expand Up @@ -457,6 +468,7 @@ miren deploy --analyze

// Route commands
d.Dispatch("route", Infer("route", "List all HTTP routes", Route,
WithGroup(GroupConfiguring),
WithExample(mflags.Example{
Name: "List all routes",
Body: "miren route",
Expand Down Expand Up @@ -544,7 +556,7 @@ miren deploy --analyze
}

// Config commands
d.Dispatch("config", Section("config", "Configuration file management", ""))
d.Dispatch("config", Section("config", "Configuration file management", "", WithSectionGroup(GroupClient)))
d.Dispatch("config info", Infer("config info", "Show configuration file locations and format", ConfigInfo,
WithExample(mflags.Example{
Name: "Show config info",
Expand All @@ -564,6 +576,7 @@ miren deploy --analyze

// Cluster commands
d.Dispatch("cluster", Infer("cluster", "List configured clusters", Cluster,
WithGroup(GroupClient),
WithExample(mflags.Example{
Name: "List clusters",
Body: "miren cluster",
Expand Down Expand Up @@ -622,7 +635,7 @@ miren deploy --analyze

// Runner commands (distributed runners) - behind feature flag
if labs.DistributedRunners() {
d.Dispatch("runner", Section("runner", "Runner management commands", ""))
d.Dispatch("runner", Section("runner", "Runner management commands", "", WithSectionGroup(GroupServer)))
d.Dispatch("runner token", Section("runner token", "Manage join tokens", ""))
d.Dispatch("runner token create", Infer("runner token create", "Create a join token for a runner", RunnerTokenCreate,
WithLabsFeature(labs.FeatureDistributedRunners),
Expand Down Expand Up @@ -755,6 +768,7 @@ miren deploy --analyze

// Server commands
d.Dispatch("server", Infer("server", "Start the miren server", Server,
WithGroup(GroupServer),
WithExample(mflags.Example{
Name: "Start in standalone mode",
Body: "miren server --mode standalone",
Expand Down Expand Up @@ -834,14 +848,15 @@ miren deploy --analyze
))

// CLI management commands
d.Dispatch("download", Section("download", "Download management commands", ""))
d.Dispatch("download", Section("download", "Download management commands", "", WithSectionGroup(GroupServer)))
d.Dispatch("download release", Infer("download release", "Download and extract miren release", DownloadRelease,
WithExample(mflags.Example{
Name: "Download the latest release",
Body: "miren download release",
}),
))
d.Dispatch("upgrade", Infer("upgrade", "Upgrade miren CLI to latest version", Upgrade,
WithGroup(GroupClient),
WithExample(mflags.Example{
Name: "Upgrade to latest",
Body: "miren upgrade",
Expand All @@ -857,7 +872,7 @@ miren deploy --analyze
))

// Auth commands
d.Dispatch("auth", Section("auth", "Authentication commands", ""))
d.Dispatch("auth", Section("auth", "Authentication commands", "", WithSectionGroup(GroupConfiguring)))
d.Dispatch("auth generate", Infer("auth generate", "Generate authentication config file", AuthGenerate,
WithExample(mflags.Example{
Name: "Generate auth config",
Expand Down Expand Up @@ -895,6 +910,7 @@ miren deploy --analyze

// Admin commands
d.Dispatch("admin", Infer("admin", "Call an admin method on an application", Admin,
WithGroup(GroupConfiguring),
WithDescription(adminDescription),
WithExample(mflags.Example{
Name: "List available admin methods",
Expand All @@ -920,7 +936,7 @@ Use these commands to help diagnose issues with the miren runtime.

Warning: These commands are intended for advanced users and developers. They may change or be removed without notice.

`))
`, WithSectionGroup(GroupServer)))
d.Dispatch("debug connection", Infer("debug connection", "Test connectivity and authentication with a server", DebugConnection))
d.Dispatch("debug advertise", Infer("debug advertise", "Show which addresses the server would advertise and why", DebugAdvertise))
d.Dispatch("debug reindex", Infer("debug reindex", "Rebuild all entity indexes from scratch", DebugReindex))
Expand Down Expand Up @@ -949,6 +965,7 @@ Warning: These commands are intended for advanced users and developers. They may
d.Dispatch("debug entity ensure", Infer("debug entity ensure", "Ensure an entity exists", EntityEnsure))

// Disk commands
d.Dispatch("disk", Section("disk", "Disk backup and recovery", "", WithSectionGroup(GroupServer)))
d.Dispatch("disk backup", Infer("disk backup", "Backup a disk to a snapshot file", DiskBackup))
d.Dispatch("disk restore", Infer("disk restore", "Restore a disk from a snapshot file", DiskRestore))
d.Dispatch("disk undelete", Infer("disk undelete", "Restore a recently deleted disk", DiskUndelete))
Expand Down Expand Up @@ -980,21 +997,14 @@ Warning: These commands are intended for advanced users and developers. They may
d.Dispatch("debug netdb gc", Infer("debug netdb gc", "Find and release orphaned IP leases", DebugNetDBGC))

// Internal commands (hidden from help, used by miren internals)
d.Dispatch("internal", Section("internal", "Internal commands used by miren components", ""))
d.Dispatch("internal", Section("internal", "Internal commands used by miren components", "", WithSectionGroup(GroupHidden)))

// Alias commands
d.Dispatch("alias", Section("alias", "CLI alias management", "", WithSectionGroup(GroupClient)))
d.Dispatch("alias list", Infer("alias list", "List configured CLI aliases", AliasList))

// Help command (registered last so it can reference all other commands)
d.Dispatch("help", NewHelpCommand(d))
d.Dispatch("help alias", Infer("help alias", "Learn how to define and use CLI aliases", HelpAlias))

addCommands(d)
}

func HiddenCommands() []string {
return []string{
"internal",
"debug",
}
}
13 changes: 13 additions & 0 deletions cli/commands/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type section struct {
help string
desc string
description string
group string
fs *mflags.FlagSet
}

Expand All @@ -25,6 +26,13 @@ func WithSectionDescription(desc string) SectionOption {
}
}

// WithSectionGroup assigns this section to a named group for help rendering.
func WithSectionGroup(group string) SectionOption {
return func(s *section) {
s.group = group
}
}

func Section(name, desc, help string, opts ...SectionOption) mflags.Command {
help = strings.TrimSpace(help)

Expand Down Expand Up @@ -77,3 +85,8 @@ func (s *section) Synopsis() string {
func (s *section) Description() string {
return s.description
}

// CommandGroup implements mflags.CommandGroupProvider.
func (s *section) CommandGroup() string {
return s.group
}
88 changes: 0 additions & 88 deletions cli/commands/help_alias.go

This file was deleted.

Loading
Loading