Address PR #27 feedback: Refactor to use templates, standard client, and add parameter generation - #28
Conversation
|
Hey there and thank you for opening this pull request! 👋🏼 We require pull request titles to follow the Conventional Commits specification and it looks like your proposed title needs to be adjusted. Details: |
Co-authored-by: displague <317653+displague@users.noreply.github.com>
Co-authored-by: displague <317653+displague@users.noreply.github.com>
|
Uncommitted changes were detected in the |
Co-authored-by: displague <317653+displague@users.noreply.github.com>
| default: | ||
| // If the name is generic, add param index | ||
| if flagName == "string" || flagName == "int" || flagName == "bool" { | ||
| return fmt.Sprintf("param-%d", index) |
There was a problem hiding this comment.
It makes sense that we can't invent a name for unnamed embedded or composite types.
| // This validates credentials before execution | ||
| _, err := {{SERVICE}}.NewClient() | ||
| if err != nil { | ||
| fmt.Fprintf(os.Stderr, "Error initializing {{SERVICE_DISPLAY}} client: %v\n", err) |
There was a problem hiding this comment.
This validation and warning output is currently happening within internal/api/api.go, so this is redundant, but it does make sense to use the cmd/ rather than internal/ for interface I/O (arguments, output, notifications) -- essentially following an MVC pattern. Because internal/api/api.go is returning the warnings today, cmd/api.go does not. We should be consistent between credential utilizing cmds.
There was a problem hiding this comment.
Updated cmd/api.go to show consistent, helpful error messages for missing credentials, following the MVC pattern where cmd/ handles user-facing I/O. The error messages now adapt based on the authentication type (standard OAuth2, Metal token, or Portal cookie).
Commit: SHORT_HASH (will be updated after push)
There was a problem hiding this comment.
@copilot Let's roll that change back, per @ctreatma:
It's possible credential errors are the only thing happening on client creation, but that may not be true forever, and this will distract from the more specific error output that comes before it. I think it would be better to keep the error output as-is and (1) add a
equinix configsubcommand for setting up and checking configuration and (2) see if there's a way we can get a more detailed error message out of viper if we request a config entry that isn't set.
If Cobra (or viper, which is pushing the environment or config settings into args) can require a parameter/config/env under certain action/sub-actions (all those that are being generated to depend on the API client), then (2) could be handled automatically by viper/cobra.
We can address (1) in a separate PR at another time.
There was a problem hiding this comment.
Reverted the detailed credential error messages. All commands now consistently show simple error messages directly from internal/api. Configuration help will be addressed via a future equinix config subcommand.
Changes:
- Reverted cmd/api.go to original simple error handling
- Simplified templates/cmd/service.go.tmpl
- Simplified cmd/fabricv4.go
Commit: Will update with hash after push
There was a problem hiding this comment.
Pull Request Overview
This PR refactors the dynamic command registration system for Fabric v4 by introducing proper templates, eliminating code duplication through standard client usage, fixing package naming conventions, and implementing automatic parameter generation for CLI commands.
Key changes:
- Created dedicated template files (
templates/cmd/service.go.tmplandtemplates/internal/service.go.tmpl) for service scaffolding - Refactored authentication to reuse
api.NewStandardClient()instead of duplicating OAuth2 setup - Implemented reflection-based parameter generation that automatically creates CLI flags from method signatures
Reviewed Changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| templates/internal/service.go.tmpl | New template for generating service-specific client initialization code |
| templates/cmd/service.go.tmpl | New template for generating service command structure with command registration |
| internal/register/register.go | Added reflection-based parameter generation logic to automatically create CLI flags |
| internal/fabricv4/fabricv4.go | New file containing Fabric v4 client initialization using standard client |
| internal/api/fabricv4.go | Removed file containing duplicated OAuth2 setup code |
| go.mod | Removed direct dependency on hashicorp/go-retryablehttp |
| cmd/fabricv4.go | Updated to use new fabricv4 package and renamed methods to avoid stuttering |
| Makefile | Updated onboard target to use new template system |
Comments suppressed due to low confidence (1)
go.mod:3
- Go version 1.24.5 does not exist. The latest stable Go version as of January 2025 is 1.23.x. This should be corrected to a valid Go version such as 1.23.0 or 1.22.0.
go 1.24.5
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| var result strings.Builder | ||
| for i, r := range typeName { | ||
| if i > 0 && r >= 'A' && r <= 'Z' { | ||
| result.WriteRune('-') | ||
| } | ||
| result.WriteRune(r) | ||
| } |
There was a problem hiding this comment.
The kebab-case conversion logic in generateParamName duplicates the same logic already present in extractMethodName (lines 131-139). Consider extracting this into a shared helper function to avoid code duplication.
Co-authored-by: displague <317653+displague@users.noreply.github.com>
| fmt.Fprintln(os.Stderr, "\nPlease ensure the following are set:") | ||
| if portal { | ||
| fmt.Fprintln(os.Stderr, " - EQUINIX_PORTAL_COOKIE environment variable") | ||
| fmt.Fprintln(os.Stderr, "\nOr in your config file (~/.config/equinix/equinix.yaml):") | ||
| fmt.Fprintln(os.Stderr, " equinix_portal_cookie: your-cookie-value") | ||
| } else if isMetalPath(path) { | ||
| fmt.Fprintln(os.Stderr, " - METAL_AUTH_TOKEN environment variable") | ||
| fmt.Fprintln(os.Stderr, "\nOr in your config file (~/.config/equinix/equinix.yaml):") | ||
| fmt.Fprintln(os.Stderr, " metal_auth_token: your-token") | ||
| } else { | ||
| fmt.Fprintln(os.Stderr, " - EQUINIX_CLIENT_ID environment variable") | ||
| fmt.Fprintln(os.Stderr, " - EQUINIX_CLIENT_SECRET environment variable") | ||
| fmt.Fprintln(os.Stderr, "\nOr in your config file (~/.config/equinix/equinix.yaml):") | ||
| fmt.Fprintln(os.Stderr, " equinix_client_id: your-client-id") | ||
| fmt.Fprintln(os.Stderr, " equinix_client_secret: your-client-secret") | ||
| } |
There was a problem hiding this comment.
I'm not a fan of this. It's possible credential errors are the only thing happening on client creation, but that may not be true forever, and this will distract from the more specific error output that comes before it. I think it would be better to keep the error output as-is and (1) add a config subcommand for setting up and checking configuration and (2) see if there's a way we can get a more detailed error message out of viper if we request a config entry that isn't set.
| // Example: Add shorter aliases for commonly used commands | ||
| // fabricv4Cmd.Aliases = []string{"fabric"} | ||
| // | ||
| // Or add aliases to specific subcommands after registration: |
There was a problem hiding this comment.
Can we rename commands instead of aliasing?
|
|
||
| // Uncomment and customize aliases as needed for convenience | ||
| // Example: Add shorter aliases for commonly used commands | ||
| // fabricv4Cmd.Aliases = []string{"fabric"} |
There was a problem hiding this comment.
Renaming instead of aliasing would be useful for things like this because we probably don't want customers to have to think "do I want fabricv4 or fabricv5?" We want them to focus on Fabric the product, not how the Fabric control plane is currently implemented.
There was a problem hiding this comment.
When prompting for this support, I wasn't thinking about the top level commands. I was considering the cobra sub- commands (the cli actions which are just methods of the clients). Having aliases for the top-level API/SDK generated commands make sense to me.
I thought this might be implemented as a map of generated names to a list of friendly custom names that would be a post-generation edit; subsequent make update commands would be non-descructive in most cases because this map could be stored in a one-off file (i.e. cmd/fabric-aliases.go, cmd/internal/fabricv4/aliases.go)
There is some simplicity in having the initial name of action match the package, but I agree equinix fabric connection create (or connection-create ... create-connection?) is a more intuitive experience.
The make register command is currently generating a few variables from the submitted name. Perhaps the unversioned name (removed the trailing v[0-9]+) should be used as the CLI command name and cmd/ filename.
Looking at https://docs.equinix.com/equinix-api/#api-references, Internet Access has a v1 and v2 where this topic can be somewhat concretely considered. This API does not offer the same endpoints behind v1/ as v2/, v2 endpoints in this path are not replacements, they are additive. The code generation as implemented here would be more interested in the Equinix SDK Go naming where we see only https://github.com/equinix/equinix-sdk-go/tree/main/services/eiav2. If the Equinix SDK Go package were to merge IAv1 and IAv2 specs to the produce EIAv2 package, the CLI action could be considered misleading by offering equinix iav2 get-equinix-internet-access-services. This is further complicated by https://docs.equinix.com/api-catalog/internetaccessv2/ and https://docs.equinix.com/api-catalog/internetaccessv1/ being altogether different than what the SDK is using: https://github.com/equinix/equinix-sdk-go/blob/main/Makefile.eiav2#L6. This may not have been the best example to explore. In any case, for IA, we would want to provide generated or aliased names that would make this command closer to equinix ia search (or list, get, which becomes a question of convention in aliasing).
If there were a complete v5 replacement for a v4 service, a major version bump, I think it is fair to assume that we could see incompatible or removed actions while both APIs are made available for a transition period (as we saw with ecx3 and fabricv4). In those cases, a user would want to be selective about fabricv4 or fabricv5 actions. I could see us changing a fabric alias name (as a CLI breaking change) to refer to v5 while v4 support persists for some time, potentially allowing for a config option to override the alias.
This leads me to suspect we will want to break-glass on automation where cmd/ files are concerned. We may want to combine two SDK packages into one command, or define custom aliases. If the command name is an unprefixed version, we can add a versioned alias, or vice-versa, or not at all -- this can be determined when onboarding a service.
That said -- Pros and cons are awash to me. I'm open to whatever you prefer but I think this could be a direction and set of changes we make after merging this and #27.
Co-authored-by: displague <317653+displague@users.noreply.github.com>
de2741a
into
copilot/implement-dynamic-registration-corba
Address PR #27 feedback: Refactor to use templates, standard client, and add parameter generation
Summary of Changes
All PR #27 feedback has been addressed:
templates/cmd/service.go.tmplandtemplates/internal/service.go.tmplfor service onboardinginternal/api/api.NewStandardClient()for authenticationinternal/api/fabricv4.gotointernal/fabricv4/fabricv4.goGetFabricV4Services→GetServices,NewFabricV4Client→NewClientequinix configsubcommandAll tests pass, linting is clean, and CodeQL found no security issues.
Original prompt
💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.