Documentation
¶
Overview ¶
Package cmdutil provides shared helpers used by command packages. Business logic belongs in internal/<domain>/; this package is for command-layer plumbing that would otherwise be copy-pasted.
Index ¶
- func APIErr(err error, subject, notFoundCode, notFoundMsg string, ...) *clierrors.CLIError
- func AddGroup(parent *cobra.Command, title string, cmds ...*cobra.Command)
- func AddJQFlag(cmd *cobra.Command)
- func AddJSONFlag(cmd *cobra.Command, out *bool)
- func AddOrgFlag(cmd *cobra.Command, org *string, opts OrgFlag)
- func AddOutputFlag(cmd *cobra.Command, out *string, what string)
- func AddV0AuthCompatFlags(fs *pflag.FlagSet)
- func AddV0OrgCompatFlags(cmd *cobra.Command, org *string)
- func AppURL(ctx context.Context) (string, error)
- func ApplyCompatFlags(cmd *cobra.Command)
- func CheckTelemetry(ctx context.Context) bool
- func CodeFence(s string) string
- func ConfigPath(cmd *cobra.Command) string
- func ConfirmOrForce(ctx context.Context, streams iostream.Streams, force bool, prompt string, ...) error
- func ContextsURL(appURL, orgSlug string) (string, error)
- func DeployURL(appURL string, proj *apiclient.ProjectInfo) string
- func DisableEverything(cmd *cobra.Command)
- func DisableTelemetry(cmd *cobra.Command)
- func DisableTelemetryForSubcommands(cmd *cobra.Command)
- func GetAgentName(ctx context.Context) string
- func GetConfig(ctx context.Context) *config.Config
- func GetTelemetry(ctx context.Context) *telemetry.Sender
- func GetVersion(ctx context.Context) string
- func GitDetectErr(err error, suggestions ...string) *clierrors.CLIError
- func GitHubAppInstalledURL(appURL string) string
- func GroupRunE(cmd *cobra.Command, args []string) error
- func InferOrgID(ctx context.Context, client *apiclient.Client) string
- func IsEverythingDisabled(cmd *cobra.Command) bool
- func IsSecureStorage(cmd *cobra.Command) bool
- func IsTelemetryDisabled(cmd *cobra.Command) bool
- func JobURL(appURL string, workflowID, jobID uuid.UUID) string
- func KeyringConnectHint(keyringErr error) string
- func LoadClient(ctx context.Context) (*apiclient.Client, error)
- func LoadClientOptionalAuth(ctx context.Context) *apiclient.Client
- func OpenOutput(path string, def io.Writer) (io.Writer, func() error, error)
- func ParseSlug(slug string) (vcs, org, repo string, err error)
- func ProjectURL(appURL, slug string) (string, error)
- func RecordTelemetry(cmd *cobra.Command)
- func RecordTelemetryForSubcommands(cmd *cobra.Command)
- func RecordTelemetryNow(cmd *cobra.Command)
- func RepoSlug(repoURL string) string
- func RequireArgs(args []string, names ...string) error
- func RequireFlag(name string) error
- func ResolveOrgSlug(orgSlug, cmdName string) (string, error)
- func ResolveOrgSlugOrID(ctx context.Context, client *apiclient.Client, ref, cmdName string) (uuid.UUID, error)
- func ResolveProjectID(ctx context.Context, client *apiclient.Client, projectSlug, projectID string) (string, error)
- func ResolveProjectSlug(projectSlug string) (string, error)
- func RunSlugURL(appURL string, slug string) (string, error)
- func RunURL(appURL string, id uuid.UUID) string
- func RunnersURL(appURL, orgSlug string) (string, error)
- func SetTelemetryProp(cmd *cobra.Command, key, value string)
- func VCSSlug(provider string) string
- func WithAgentName(ctx context.Context, name string) context.Context
- func WithConfig(ctx context.Context, cfg *config.Config) context.Context
- func WithTelemetry(ctx context.Context, tc *telemetry.Sender) context.Context
- func WithVersion(ctx context.Context, version string) context.Context
- func WorkflowURL(appURL string, id uuid.UUID) string
- func WriteJSON(w io.Writer, v any) error
- type OrgFlag
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func APIErr ¶
func APIErr(err error, subject, notFoundCode, notFoundMsg string, notFoundSuggestions ...string) *clierrors.CLIError
APIErr converts an apiclient error into a structured CLIError.
notFoundCode and notFoundMsg customise the 404 case for the calling resource (e.g. "run.not_found", "No run found for %q"). notFoundMsg is passed through fmt.Sprintf with subject as the single argument.
Optional notFoundSuggestions are appended to the 404 error (useful for pointing users toward a list command, for example).
func AddJSONFlag ¶
AddJSONFlag registers --json on cmd and binds it to out.
func AddOrgFlag ¶
AddOrgFlag registers the canonical --org flag on cmd, binding it to org and marking it required when opts.Required is set. It is the single source of the flag name and help wording shared by every org-scoped command; pair it with ResolveOrgSlugOrID to turn the value into an org UUID.
func AddOutputFlag ¶
AddOutputFlag registers --output/-o on cmd, binding it to out. The what argument names the content being written, e.g. "the manpage", and is used in the flag description: "Write <what> to this file instead of stdout".
func AddV0AuthCompatFlags ¶ added in v1.0.47091
AddV0AuthCompatFlags registers hidden --host and --token flags on fs, which the 0.1.x CLI accepted and v1 replaced with the CIRCLE_HOST and CIRCLE_TOKEN environment variables. Pass the PersistentFlags of a command group so every subcommand under it inherits them; 0.1.x defined both globally, so a script may attach them to any command in the group it calls.
Published orbs pass these on every invocation — circleci/orb-tools runs `orb validate --host ... --token ...` — and orb versions are pinned in consumers' configs, so rejecting the flags breaks pipelines that the consumer cannot fix by updating the CLI. ApplyCompatFlags folds the values into the env vars that EffectiveHost and EffectiveToken read.
A command needing --host or --token for something else declares its own, which shadows this one and carries no annotation, so ApplyCompatFlags leaves it alone. `runner config --token` and `setup --token` both rely on that.
func AddV0OrgCompatFlags ¶ added in v1.0.47091
AddV0OrgCompatFlags registers hidden --org-id and --org-slug flags that the 0.1.x CLI used before both were folded into --org, which accepts either a slug or a UUID. All three bind to org, so whichever the caller passes lands in the same place the canonical flag would. They are deliberately not marked mutually exclusive: 0.1.x accepted --org-id and --org-slug together, and rejecting that combination would break the pinned orb versions this shim exists to support.
func ApplyCompatFlags ¶ added in v1.0.47091
ApplyCompatFlags copies the value of every compatibility flag on cmd into the environment variable it maps to. Call it before configuration is loaded.
A flag that was passed overwrites the variable, because that is the precedence 0.1.x gave it: an explicit --token beat CIRCLE_TOKEN. orb-tools relies on it — its publish job takes the name of the variable holding the publishing token, so it passes a token that is deliberately not the ambient CIRCLE_TOKEN. Letting the environment win would silently publish as the wrong identity. Visit only reports flags the caller actually set, so an omitted flag never clears anything.
func CheckTelemetry ¶
func CodeFence ¶
CodeFence returns a backtick fence long enough to wrap s verbatim: at least three backticks, and always one more than the longest run of backticks inside s, so a run of backticks in the content cannot prematurely close the block (the CommonMark fencing rule). Use it when embedding arbitrary captured output — step logs, test messages — in a markdown code block.
func ConfigPath ¶
func ConfirmOrForce ¶
func ConfirmOrForce(ctx context.Context, streams iostream.Streams, force bool, prompt string, abortErr, requireForceErr *clierrors.CLIError) error
ConfirmOrForce requires user confirmation of a destructive operation.
- If force is true, returns nil immediately (scripting / non-interactive path).
- In a TTY, shows prompt and returns abortErr if the user declines.
- Outside a TTY, returns requireForceErr with the standard --force suggestion appended so callers don't have to repeat it.
Construct abortErr and requireForceErr with domain-specific codes and messages; the standard suggestion text is added automatically to requireForceErr.
func ContextsURL ¶
ContextsURL returns the CircleCI contexts settings page URL for the given org slug.
func DeployURL ¶
func DeployURL(appURL string, proj *apiclient.ProjectInfo) string
DeployURL returns the CircleCI deploys page URL for the given project.
func DisableEverything ¶
func DisableTelemetry ¶
func GetAgentName ¶
func GetVersion ¶
func GitDetectErr ¶
GitDetectErr wraps a gitremote.Detect error into a structured CLIError.
The standard "run from inside a git repository" suggestion is always included as the first suggestion. Pass additional command-specific suggestions as variadic args (e.g. "Or specify the project with --project gh/org/repo").
func GitHubAppInstalledURL ¶
GitHubAppInstalledURL returns the page to send the browser to once a CircleCI GitHub App install completes. It confirms the install and points the user back at their terminal, where the rest of onboarding happens.
func GroupRunE ¶
GroupRunE is the RunE for group (parent) commands that have no action of their own. It shows help when invoked with no arguments and returns a structured error for unknown subcommands.
func InferOrgID ¶
InferOrgID best-effort resolves the org UUID for the current directory's CircleCI project. Detection follows gitremote.Detect's resolution order — a `circleci project link` binding (.circleci/info.yml) takes precedence over the git remote, so an explicit link wins when the remote is not the right answer (repository renames, forks, standalone projects). When the link recorded the org as a UUID it is used directly; otherwise the resolved project is looked up through the API to recover its owning org.
It is the lenient counterpart to ResolveOrgSlugOrID, for commands where the org is an optional convenience rather than required — e.g. config compilation passes it so private and namespaced orbs resolve without an explicit --org. It returns "" (with no error) whenever the org cannot be determined — not a git checkout, an unrecognised remote, or a failed project lookup — so callers fall back to public-only behaviour instead of failing.
func IsEverythingDisabled ¶
func IsSecureStorage ¶
IsSecureStorage reports whether the API token should be stored in (and read from) the OS keyring rather than the plaintext config file.
It is the single decision point feeding both the load path (root PreRun) and every write path (auth, setting set, setup). Secure storage requires both that the user did not opt out via --insecure-storage and that the keyring backend is actually reachable. The latter check keeps headless/CI Linux hosts — which have no D-Bus session bus — from hitting a confusing `exec: "dbus-launch": executable file not found` failure; instead they transparently fall back to the config file, exactly as --insecure-storage does.
func IsTelemetryDisabled ¶
IsTelemetryDisabled reports whether telemetry has been disabled for this specific command via DisableTelemetry (independent of the user's global telemetry preference).
func KeyringConnectHint ¶
KeyringConnectHint returns a one-line, actionable suggestion when secure storage was requested but the keyring could not be reached for a reason the user can fix. It returns "" when there is nothing actionable to suggest.
The only such case today is a strict snap whose password-manager-service interface is not connected: the session bus exists but the sandbox denies the connection (keyring.ErrAccessDenied). We detect the snap via the SNAP_* environment variables snapd injects, and use the running instance name so the suggested command is correct even for a parallel install.
func LoadClient ¶
LoadClient reads the CLI config, validates that a token is present, and returns an authenticated API client. On failure it returns a structured CLIError ready to be returned directly from a RunE handler. This is the default; see LoadClientOptionalAuth for the anonymous-capable variant.
Honors a --config path set by the root PersistentPreRunE via WithConfigPath.
func LoadClientOptionalAuth ¶ added in v1.0.47027
LoadClientOptionalAuth returns an API client without requiring a token, for commands that work against endpoints CircleCI also serves anonymously. When a token *is* configured it is still sent, so the authenticated behaviour is unchanged; the returned client reports which it is via Authenticated().
Prefer LoadClient everywhere else. Against an endpoint that requires a token, an anonymous client turns the actionable "Authentication required" error into a bare 401 from the API.
func OpenOutput ¶
OpenOutput resolves the destination for a command supporting --output. When path is empty it returns def (the command's normal stdout) with a no-op closer; otherwise it creates the file (along with any missing parent directories) and returns it with its Close method. Callers should always defer the returned closer.
func ProjectURL ¶
ProjectURL returns the CircleCI project page URL for the given project slug.
func RecordTelemetry ¶
func RecordTelemetryNow ¶
func RepoSlug ¶
RepoSlug reduces a repository URL to its "org/repo" form, e.g. "https://github.com/acme/web" → "acme/web". It returns "" for an empty URL and the input unchanged if it cannot be parsed. Used to label cross-project run listings ("my runs" and the run picker's my-runs scope) from each run's repository URL. (When only a project UUID is known, apiclient.GetProjectByID can resolve a name, but the run listings do not currently do so.)
func RequireArgs ¶
RequireArgs returns a structured CLIError if args contains fewer elements than the number of names provided. Each name describes an expected positional argument (e.g. "workflow-id", "resource-class") and appears in the error message as <name>.
Use alongside cobra.MaximumNArgs(N) so that too many args are still rejected by Cobra, while the missing-arg case produces a structured error from RunE.
func RequireFlag ¶
RequireFlag returns a structured CLIError reporting that a required flag was not set. name is the long flag name without the leading dashes (e.g. "org-id").
func ResolveOrgSlug ¶
ResolveOrgSlug returns orgSlug as-is when non-empty. Otherwise it derives the organization slug (vcs/org, e.g. gh/myorg) from the current git remote. It makes no API call — use this for endpoints keyed on an owner slug rather than an org UUID (see ResolveOrgSlugOrID for the UUID case).
cmdName is included in the GitDetectErr suggestion text so users see the exact override flag for the command they invoked, e.g. "circleci context list".
func ResolveOrgSlugOrID ¶
func ResolveOrgSlugOrID(ctx context.Context, client *apiclient.Client, ref, cmdName string) (uuid.UUID, error)
ResolveOrgSlugOrID resolves an organization reference to its UUID. The reference may be:
- an org UUID (e.g. f22b6566-597d-46d5-ba74-99ef5bb3d85c), used as-is;
- an org slug (e.g. gh/myorg), looked up through the API;
- empty, in which case the org is inferred from the current git remote.
cmdName is included in the GitDetectErr suggestion text so users see the exact override flag for the command they invoked, e.g. "circleci runner instance list".
func ResolveProjectID ¶
func ResolveProjectID(ctx context.Context, client *apiclient.Client, projectSlug, projectID string) (string, error)
ResolveProjectID returns projectID as-is when non-empty. Otherwise it resolves the project from the slug (--project flag or git remote) to recover its UUID.
func ResolveProjectSlug ¶
ResolveProjectSlug returns projectSlug as-is when non-empty. Otherwise it detects the slug from the git remote. Unlike ResolveProjectID this does not make an API call and does not return a UUID — use it for endpoints that require a slug in the path (e.g. POST /project/{vcs}/{org}/{repo}/pipeline/run).
func RunnersURL ¶
RunnersURL returns the CircleCI runners inventory page URL for the given org slug.
func SetTelemetryProp ¶
SetTelemetryProp attaches an extra property to cmd that RecordTelemetryNow will include in the command_invocation event.
func VCSSlug ¶
VCSSlug maps API provider strings to the slug prefix used in CircleCI URLs (e.g. "GitHub" → "gh").
func WithConfig ¶
WithConfig returns a copy of ctx carrying the given config file path. The path is read by LoadClient to locate the config file.
Types ¶
type OrgFlag ¶
type OrgFlag struct {
// Purpose, when set, is appended to describe what the organization scopes,
// e.g. "for private orb resolution" or "to claim the namespace for". Omit
// the leading space.
Purpose string
// Required marks --org required and appends "(required)" to its
// description. Use it for commands with no git-remote fallback. It is
// mutually exclusive with DefaultsToGitRemote.
Required bool
// DefaultsToGitRemote appends "; defaults to git remote" to the description.
// Set it for commands that infer the org from the current repository when
// --org is omitted. Ignored when Required is true.
DefaultsToGitRemote bool
}
OrgFlag configures the canonical --org flag added by AddOrgFlag. The flag always accepts an organization slug (e.g. gh/myorg) or a UUID; resolve its value to a UUID with ResolveOrgSlugOrID.