feat(extension): implicit plugin mechanism via circleci-<name> PATH lookup#1277
Draft
michael-webster wants to merge 3 commits intonextfrom
Draft
feat(extension): implicit plugin mechanism via circleci-<name> PATH lookup#1277michael-webster wants to merge 3 commits intonextfrom
michael-webster wants to merge 3 commits intonextfrom
Conversation
…ookup Unknown top-level commands transparently exec a matching circleci-<name> binary from PATH, following git's plugin convention. The extension receives CIRCLE_TOKEN, CIRCLE_URL, and best-effort project metadata (VCS type, org, repo) via environment variables so it can call the CircleCI API without reimplementing auth. Only top-level unknown commands are intercepted — unknown subcommands within a group (e.g. "circleci pipeline foo") still produce the normal cobra error. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ndling - acceptance/extension_test.go: acceptance tests for extension dispatch, CIRCLE_TOKEN injection, unknown-command fallthrough, and exit code propagation - buildEnv: replace duplicate env keys in-place instead of appending, so the injected token wins over any pre-existing CIRCLE_TOKEN in the shell env - Run: use clierrors.New instead of fmt.Errorf for structured error output - rootUnknownCommand: accept rootName param so binary renames (e.g. cci) work - main.go: format CLIError from extension via the normal error formatter Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
70d7b19 to
0bac55c
Compare
- Replace brittle Cobra error-string matching and hand-maintained globalFlagsWithValues allowlist with rootCmd.Find() + Flags().Args(), so extension dispatch is robust to new flags and Cobra version changes - Return ErrExited from Run instead of calling os.Exit directly, so deferred cleanup runs and Run is testable - Rename injected env vars CIRCLE_TOKEN/CIRCLE_URL → CIRCLECI_TOKEN/CIRCLECI_HOST (and VCS/project vars) to match the project's documented CIRCLECI_ prefix - Extract skipUnlessShell helper in acceptance tests to consolidate the Windows skip guard in one place Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
0bac55c to
feadafc
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
circleci-<name>binary in PATH is transparently invoked ascircleci <name>, following git's plugin conventioninternal/extensionpackage handles PATH lookup, environment injection, and exit code propagationHow it works
When Cobra returns an
unknown command "X" for "circleci"error,main.gointercepts it before printing and attempts toexec.LookPath("circleci-X"). If found, the binary is executed with:CIRCLECI_TOKENandCIRCLECI_HOSTinjected from the config file / env varsCIRCLECI_VCS_TYPE,CIRCLECI_PROJECT_USERNAME,CIRCLECI_PROJECT_REPONAMEinjected from git remote (best-effort, silent on failure)os.Environ()inherited so the extension gets everything the user hadIf no matching binary exists, the original cobra error is shown unchanged.
Test plan
task test— all 464 tests passtask check— lint clean (pre-existing license failure incmd/.circleci/update_check.ymlunrelated to this change)circleci-helloextension: args,CIRCLECI_TOKEN, andCIRCLECI_HOSTall injected correctlycircleci testsuite "ci tests"— dispatches tocircleci-testsuitecorrectly, exit code propagatedcircleci pipeline foo) are not interceptedExample running this:

🤖 Generated with Claude Code