Skip to content

Cannot use CLI as library: Run() requires internal SpinnerPrinter #16

@isbecker

Description

@isbecker

What happened?

PR #10 introduced a breaking change that makes public APIs unusable for external consumers.

The SpinnerPrinter parameter was added to public Run() methods across multiple commands (render, validate, etc.), but the SpinnerPrinter interface is defined in github.com/crossplane/cli/v2/internal/terminal, which Go's module system prevents external code from importing.

This creates an impossible situation:

  • The Run() methods are exported (titlecase) and intended to be public APIs
  • External code cannot implement or obtain a SpinnerPrinter because it's in an internal/ package
  • Therefore these public APIs are now completely unusable by external consumers

Example of broken API:

// github.com/crossplane/cli/v2/cmd/crossplane/render/xr
func (c *Cmd) Run(k *kong.Context, log logging.Logger, sp terminal.SpinnerPrinter) error

External code cannot:

  • Import github.com/crossplane/cli/v2/internal/terminal (Go won't allow it)
  • Implement the SpinnerPrinter interface (can't reference the type)
  • Call terminal.NewSpinnerPrinter() (function is in internal package)

How can we reproduce it?

Try to use the CLI as a library from external Go code (commit bc59509 or later):

package main

import (
  "github.com/crossplane/cli/v2/cmd/crossplane/render/xr"
  // Cannot import: github.com/crossplane/cli/v2/internal/terminal
)

func main() {
  cmd := &xr.Cmd{...}
  // Cannot call: cmd.Run(ctx, logger, ???)
  // No way to obtain or create a SpinnerPrinter
}

Compile error:
use of internal package github.com/crossplane/cli/v2/internal/terminal not allowed

Suggested fixes:

  1. Move SpinnerPrinter to a public package (e.g., github.com/crossplane/cli/v2/terminal)
  2. Provide a public constructor for a no-op/disabled spinner (e.g., terminal.NewNoOpSpinner())
  3. Make the parameter optional via an options pattern or accept interface{} that can be nil
  4. Accept io.Writer instead and construct the spinner internally based on whether it's a TTY

What environment did it happen in?

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions