Help us shape the future of Go! Take the 2026 Go Developer Survey

hubcli

package
v0.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 11, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

Documentation

Overview

Package hubcli implements `hub`, the command line client for the hub API.

Every command except the handful that manage configuration is generated from the API catalog, so the CLI gains a command the moment an rpc is added to a .proto - there is no table of endpoints to keep in step. That also makes the surface predictable enough for an AI agent to use without being told: rpc ListUser on UserService is `hub user list-user`, its request fields are its flags, and `hub api list` enumerates the lot as JSON.

Index

Constants

View Source
const DefaultConfigDir = ".hub"

DefaultConfigDir is the directory holding the CLI's configuration, relative to the user's home directory.

Variables

Formats lists the accepted --output values.

Functions

func CommandAliases

func CommandAliases(op apicatalog.Operation) []string

CommandAliases returns the shorthand for the plain CRUD rpcs - "list" for ListUser under `hub user` - and nothing for the rest.

func CommandName

func CommandName(op apicatalog.Operation) string

CommandName is the subcommand for an rpc, the kebab-case of its name. It is deliberately mechanical: an agent that has read the rpc name in the proto or in `hub api list` can predict the command without consulting a mapping table.

func ConfigPath

func ConfigPath() (string, error)

ConfigPath returns the location of the configuration file, honouring HUB_CONFIG so a caller can point the CLI at its own file.

func Execute

func Execute(opts Options) int

Execute runs the CLI and returns the process exit code.

func FlagName

func FlagName(field apicatalog.Field) string

FlagName is the flag for a request field: "group_ids" becomes "group-ids".

func GroupName

func GroupName(op apicatalog.Operation) string

GroupName is the command a service is grouped under: "user.v1.UserService" becomes "user", "system.group.v1.GroupService" becomes "group".

func NewRootCommand

func NewRootCommand(opts Options) *cobra.Command

NewRootCommand builds the `hub` command tree.

func Paginated

func Paginated(op apicatalog.Operation) bool

Paginated reports whether an operation is a list endpoint --all can follow: one that takes a limit and an offset.

func Render

func Render(w io.Writer, format Format, value any) error

Render writes a value in the requested format.

func RenderReference

func RenderReference(catalog *apicatalog.Catalog) string

RenderReference writes the Markdown API reference bundled with the agent skill. It is generated rather than written because a hand-kept reference is exactly the kind of document that quietly goes stale, and an agent following a stale reference produces confidently wrong calls.

func SaveConfig

func SaveConfig(path string, cfg Config) error

SaveConfig writes the configuration file, creating its directory. The file is owner-only because it stores bearer tokens and client secrets.

Types

type APIError

type APIError struct {
	StatusCode int
	Status     string
	Body       json.RawMessage
}

APIError is a non-2xx response from the gateway.

func (*APIError) Error

func (e *APIError) Error() string

type CLI

type CLI struct {
	// contains filtered or unexported fields
}

CLI holds the state shared by every command: the flags parsed off the root, and the settings and client derived from them once flag parsing is done.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client calls the hub REST gateway.

func NewClient

func NewClient(settings Settings) *Client

NewClient returns a client for the resolved settings.

func (*Client) BuildRequest

func (c *Client) BuildRequest(op apicatalog.Operation, values map[string]any) (Request, error)

BuildRequest maps an operation and its argument values onto an HTTP request.

Where each value goes is decided by the operation's google.api.http rule, not by the caller: path fields are substituted into the URL, and the rest become either the JSON body or query parameters depending on whether the rpc declares a body. Values are keyed by protobuf or JSON field name.

func (*Client) Call

func (c *Client) Call(ctx context.Context, op apicatalog.Operation, values map[string]any) (json.RawMessage, error)

Call is BuildRequest followed by Do.

func (*Client) Do

func (c *Client) Do(ctx context.Context, req Request) (json.RawMessage, error)

Do sends a request and returns the decoded response body. A non-2xx status yields an *APIError carrying the gateway's own error payload, which is what tells a caller whether they were denied, throttled or simply wrong.

type Config

type Config struct {
	// Current is the profile used when --profile is not given.
	Current string `yaml:"current,omitempty"`
	// Profiles holds every configured environment by name.
	Profiles map[string]Profile `yaml:"profiles,omitempty"`
}

Config is the on-disk configuration file.

func LoadConfig

func LoadConfig(path string) (Config, error)

LoadConfig reads the configuration file. A missing file is not an error: the CLI is fully usable from flags and environment variables alone, which is how it is normally run in CI and by agents.

func (Config) Profile

func (c Config) Profile(name string) Profile

Profile returns the named profile, or the current one when name is empty.

func (Config) WithProfile

func (c Config) WithProfile(name string, profile Profile) Config

WithProfile returns a copy of c with the named profile replaced. It is a value method so callers cannot accidentally mutate a shared config.

type Format

type Format string

Format is how a command renders its result.

const (
	// FormatJSON is indented JSON. It is the default because the CLI's main
	// consumers - scripts and agents - parse what they read.
	FormatJSON Format = "json"
	// FormatYAML is YAML, for eyeballing large responses.
	FormatYAML Format = "yaml"
	// FormatTable renders a response's list field as columns, falling back to
	// JSON for anything that is not a list of objects.
	FormatTable Format = "table"
)

func ParseFormat

func ParseFormat(value string) (Format, error)

ParseFormat validates an --output value.

type OIDC

type OIDC struct {
	// Issuer is the realm URL, e.g. "http://localhost:8080/realms/hub".
	Issuer string `yaml:"issuer,omitempty"`
	// ClientID is the OIDC client the CLI authenticates as.
	ClientID string `yaml:"client_id,omitempty"`
	// ClientSecret is the client secret, required for confidential clients.
	ClientSecret string `yaml:"client_secret,omitempty"`
}

OIDC holds the OpenID Connect client settings used to obtain a token.

type Options

type Options struct {
	// Catalog is the API surface to build commands from. Defaults to the
	// globally registered descriptors.
	Catalog *apicatalog.Catalog
	// Version is reported by `hub version`.
	Version string
}

Options configures a CLI instance.

type Profile

type Profile struct {
	// Endpoint is the base URL of the hub API, e.g. "http://localhost:9090".
	Endpoint string `yaml:"endpoint,omitempty"`
	// Token is a bearer token. `hub auth login` writes one here.
	Token string `yaml:"token,omitempty"`
	// RefreshToken renews Token without asking for credentials again. Keycloak
	// access tokens last minutes, so without this the CLI would need a fresh
	// `hub auth login` several times an hour.
	RefreshToken string `yaml:"refresh_token,omitempty"`
	// ExpiresAt is when Token stops being accepted. The zero time means
	// unknown, in which case the CLI refreshes only after a call is refused.
	ExpiresAt time.Time `yaml:"expires_at,omitempty"`
	// OIDC describes where `hub auth login` gets a token from.
	OIDC OIDC `yaml:"oidc,omitempty"`
}

Profile is one named set of connection settings.

type Request

type Request struct {
	Method string          `json:"method"`
	URL    string          `json:"url"`
	Body   json.RawMessage `json:"body,omitempty"`
}

Request is a fully resolved HTTP call, kept as data so --dry-run can print exactly what would be sent without sending it.

type Settings

type Settings struct {
	Endpoint     string
	Token        string
	RefreshToken string
	ExpiresAt    time.Time
	OIDC         OIDC
}

Settings is the connection configuration actually used for a command, after flags, environment variables and the config file have been combined.

func Resolve

func Resolve(profile Profile, flags Settings) Settings

Resolve layers the sources in order of increasing precedence: the config file, then the environment, then explicit flags. Anything an agent passes on the command line therefore wins over whatever happens to be on the machine.

type Token

type Token struct {
	AccessToken  string `json:"access_token" yaml:"access_token"`
	RefreshToken string `json:"refresh_token,omitempty" yaml:"refresh_token,omitempty"`
	ExpiresIn    int    `json:"expires_in,omitempty" yaml:"expires_in,omitempty"`
	TokenType    string `json:"token_type,omitempty" yaml:"token_type,omitempty"`
	// contains filtered or unexported fields
}

Token is the subset of an OAuth2 token response the CLI needs.

func (Token) ExpiresAt

func (t Token) ExpiresAt() time.Time

ExpiresAt is when the access token stops being accepted, or the zero time if the provider did not say.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL