CircleCI CLI

repository·main·Indexed 19 days ago

https://github.com/circleci-public/circleci-cli

A Go-based command-line interface for interacting with CircleCI. Features include pipeline run management via `circleci run`, workflow and pipeline inspection, environment variable management, and Model Context Protocol (MCP) support for AI-powered editors. The CLI provides machine-readable JSON output with built-in JQ integration and a `circleci api` command for making authenticated requests to the CircleCI REST API.

Tokens
19.6K
Snippets
85
Records
104
Agent score
65%

What's inside circleci-cli

  1. Overview of new CircleCI CLI v1.x commands

    main

    The v1.x preview release introduces several new command groups for managing CI/CD workflows directly from the terminal:

    • circleci run: Full pipeline run management. Includes list, get, trigger, cancel, and watch. The run watch command blocks until a run completes and exits with a status code reflecting the result, useful for CI gating scripts.
    • circleci deploy: View deployed components and versions across environments; initializes CircleCI Deploys.
    • circleci dlc purge: Invalidates Docker layer caching for a project to force fresh image builds.
    • circleci workflow: List, inspect, cancel, and rerun individual workflows.
    • circleci pipeline: List and inspect pipelines.
    • circleci envvar: Manage project environment variables.
    • --json flag: Supported by every data-returning command for machine-readable, scriptable output.
    • circleci completion: Provides Bash and Zsh shell completions.
  2. Configure Environment Variables in the Command Layer

    main

    To keep business logic pure and testable, environment variable resolution must be hoisted to the cmd/ layer.

    • Do not read os.Getenv inside business logic New() functions.
    • Do resolve environment variables in the cmd/ layer and pass the resulting values as arguments to business logic constructors or functions.
    • Documentation: Ensure help text explicitly documents the same environment variable names that the code reads.
    // Prefer this pattern:
    // internal/cmd/sandboxes.go
    token := os.Getenv("CIRCLE_TOKEN")
    if token == "" {
        return usererr.New("Set CIRCLE_TOKEN to authenticate.", fmt.Errorf("missing CIRCLE_TOKEN"))
    }
    client := circleci.NewClient(token)
  3. Understand the circleci-cli interactivity policy

    main

    The circleci CLI is designed to behave correctly in non-TTY (automated/agent) contexts:

    • No Pager: It automatically skips the pager in non-interactive environments. You do not need to pass --no-pager (this flag does not exist).
    • No Prompts: Instead of prompting for input, it will error out quickly with a helpful message (e.g., must provide --title and --body when not running interactively).
    • Color: It automatically strips ANSI color codes in non-TTY contexts.

    Note: The CLI still honors the PAGER and NO_COLOR environment variables.

  4. Follow Architectural Layering and Boundaries

    main

    The project enforces a strict downward dependency flow to maintain modularity. Violating these boundaries is considered a required fix:

    Dependency Flow: main.go $\rightarrow$ internal/cmd/ $\rightarrow$ internal/{business packages} $\rightarrow$ internal/httpcl/.

    Key Rules:

    • No Upward Imports: Leaf packages (like business logic) must never import from internal/cmd/.
    • Separation of Concerns: Business logic packages must not contain UI output (colors, spinners, formatting). UI logic belongs in cmd/ or internal/ui/.
    • Pure Business Logic: Business logic functions should return data and errors; they must not call os.Stdout or fmt.Print directly.
    • HTTP Client Isolation: internal/httpcl/ must not import anything from other internal/ packages.
  5. Target specific projects and organizations

    main

    The circleci CLI automatically infers the current project by inspecting the git remotes in the current working directory (CWD).

    To override this automatic detection and target a specific organization, use the --org <VCS>/<ORG> flag. The <VCS> component must be one of gh, bb, or circleci.

    # Override the detected project to target a specific org
    circleci <command> --org gh/my-organization
  6. Handle Errors and Resources Correctly

    main

    Follow these patterns for robust error handling and resource management:

    • Wrap Errors with Context: Use fmt.Errorf("context: %w", err) to provide trace information rather than returning bare errors.
    • User-Facing Errors: Use usererr.New(message, err) for errors intended for the end-user. Avoid using fmt.Errorf with user-facing text.
    • No Panics in Libraries: Library code must never use log.Fatal, os.Exit, or panic. Always return errors to the caller.
    • Safe Resource Closing: When deferring a close on a fallible resource, use the closer.ErrorHandler(resource, &err) pattern to ensure close errors are captured in a named return error.
    f, err := os.Create(path)
    if err != nil {
        return fmt.Errorf("create %s: %w", path, err)
    }
    defer closer.ErrorHandler(f, &err)
  7. Access the CircleCI REST API via the CLI

    main

    If a specific piece of data is not exposed by the standard typed CLI commands, you can use the circleci api command to interact with the REST API directly.

    When running from within a repository, the CLI can automatically fill in {project-id} placeholders in certain paths. For deterministic behavior, you can pass the project ID literally.

    # Access project details via REST shortcut
    circleci api 'projects/{project-id}'
    
    # Access runs for a specific project
    circleci api 'runs?filter[project_id]={project-id}'
  8. Retrieve job attributes and step outputs

    main

    Use the following commands to inspect job details and logs. All commands support --json for structured data and provide ANSI-stripped output for logs.

    Get recent runs for a branch

    Use circleci run get --json --branch <branch> to retrieve the most recent run for a specific branch.

    Get job attributes and all step outputs

    Use circleci job output list <job-id> --json to get all job attributes and the output for every step.

    Get job attributes without step output

    If you only need metadata, use circleci job get <job-id> --json to get job attributes and step information without the actual log output.

    Get output for a specific step

    Use circleci job output get <job-id> --json --step-num <step-id> to retrieve the ANSI-stripped output for a single specific step.

    # Get the most recent run for a branch
    circleci run get --json --branch main
    
    # Get all job attributes and step outputs
    circleci job output list <job-id> --json
    
    # Get attributes for a specific step
    circleci job output get <job-id> --json --step-num 1
  9. Enable Model Context Protocol (MCP) support

    main

    The CircleCI CLI supports the Model Context Protocol (MCP), allowing you to register the CLI as an MCP server in AI-powered editors and agents.

    Claude Desktop

    To enable in Claude desktop and add it with the current user scope:

    circleci mcp claude enable
    claude mcp add-from-claude-desktop -s user

    Cursor

    circleci mcp cursor enable

    VS Code

    circleci mcp vscode enable
    circleci mcp cursor enable
  10. Use Fakes instead of Mocks for Testing

    main

    The project prioritizes integration testing and real behavior over mock generation:

    • Prefer Fakes/Stubs: Use real HTTP servers via httptest.NewServer or temporary directories via t.TempDir() instead of mock generators (like gomock).
    • I/O Testing: Test I/O by providing iostream.Streams{Out: &buf, Err: &errBuf} rather than capturing os.Stdout.
    • Avoid Interface Over-abstraction: Do not create interfaces for single implementations. Prefer passing concrete types or function parameters for dependency injection.
    • Race Detection: Always run tests with the -race detector.
    • Acceptance Tests: Run the actual compiled binary for acceptance tests, not internal functions.
    func TestListSandboxes(t *testing.T) {
        srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            json.NewEncoder(w).Encode([]Sandbox{{ID: "sb-1"}})
        }))
        t.Cleanup(srv.Close)
    
        client := circleci.NewClient("test-token")
        client.BaseURL = srv.URL
        got, err := sandbox.List(context.Background(), client, "org-1")
        assert.NilError(t, err)
        assert.Equal(t, len(got), 1)
        assert.Equal(t, got[0].ID, "sb-1")
    }
  11. Handle structured data and JSON output with circleci-cli

    main

    By default, circleci outputs markdown-formatted text intended for humans. To use the CLI in automated environments or with agents, use the --json flag to obtain structured data.

    To filter or extract specific fields without needing an external jq installation, use the built-in --jq '<expr>' flag.

    # Get structured output
    circleci <command> --json
    
    # Filter structured output directly using the built-in jq flag
    circleci <command> --json --jq '.some.key'