diff --git a/README.md b/README.md index f3f9b7d..051c37f 100644 --- a/README.md +++ b/README.md @@ -109,10 +109,10 @@ Run the generator after updating `sumup-go`: make generate ``` -[`internal/commands/operations.go`](internal/commands/operations.go) maps CLI -command paths to generated OpenAPI operation IDs. Tests enforce parity between -the pinned SDK, the generated catalog, and the CLI command tree, so an SDK -upgrade fails CI until every new endpoint has a corresponding command. +Each API leaf binds its generated OpenAPI operation ID directly in the command +definition. Tests enforce a one-to-one relationship between the pinned SDK, +the generated catalog, and the CLI command tree, so an SDK upgrade fails CI +until every new endpoint has exactly one corresponding command. ### Developer portal code samples diff --git a/internal/apicommands/apicommands.go b/internal/apicommands/apicommands.go index 76c9b11..b9d1e8a 100644 --- a/internal/apicommands/apicommands.go +++ b/internal/apicommands/apicommands.go @@ -52,8 +52,9 @@ func Lookup(operationID string) (Operation, bool) { return Operation{}, false } -// Bind records which OpenAPI operation a CLI command exposes. -func Bind(command *cli.Command, operationID string) { +// Bind records which OpenAPI operation a CLI command exposes and returns the +// command so the binding can live next to the command definition. +func Bind(operationID string, command *cli.Command) *cli.Command { if command == nil { panic("cannot bind an OpenAPI operation to a nil command") } @@ -64,6 +65,8 @@ func Bind(command *cli.Command, operationID string) { command.Metadata = make(map[string]any) } command.Metadata[operationIDMetadataKey] = operationID + + return command } // OperationID returns the OpenAPI operation ID bound to a CLI command. diff --git a/internal/codesamples/codesamples.go b/internal/codesamples/codesamples.go index a744417..261eb0b 100644 --- a/internal/codesamples/codesamples.go +++ b/internal/codesamples/codesamples.go @@ -69,13 +69,6 @@ type sampleFlag struct { var argumentPattern = regexp.MustCompile(`[<\[]([a-z0-9-]+)[>\]]`) -// canonicalCommandPaths resolves operations exposed through more than one CLI -// command. CreateMerchantMember is also used by the convenience invite flow, -// while the full create command is the canonical portal example. -var canonicalCommandPaths = map[string]string{ - "CreateMerchantMember": "members create", -} - // optionalSampleFlags adds a representative field where an otherwise valid // command would not show what a create or update request changes. var optionalSampleFlags = map[string]map[string]string{ @@ -140,7 +133,7 @@ func Generate(cliVersion string) (*Catalog, error) { commandsByOperation := boundCommandsByOperation(commands.All()) samples := make([]Sample, 0, len(apicommands.Operations)) for _, operation := range apicommands.Operations { - command, err := canonicalCommand(operation.ID, commandsByOperation[operation.ID]) + command, err := commandForOperation(operation.ID, commandsByOperation[operation.ID]) if err != nil { return nil, err } @@ -199,7 +192,7 @@ func boundCommandsByOperation(resourceCommands []*cli.Command) map[string][]boun return result } -func canonicalCommand(operationID string, candidates []boundCommand) (boundCommand, error) { +func commandForOperation(operationID string, candidates []boundCommand) (boundCommand, error) { switch len(candidates) { case 0: return boundCommand{}, fmt.Errorf("OpenAPI operation %q has no CLI command", operationID) @@ -207,21 +200,12 @@ func canonicalCommand(operationID string, candidates []boundCommand) (boundComma return candidates[0], nil } - preferredPath, ok := canonicalCommandPaths[operationID] - if !ok { - paths := make([]string, 0, len(candidates)) - for _, candidate := range candidates { - paths = append(paths, candidate.path) - } - slices.Sort(paths) - return boundCommand{}, fmt.Errorf("OpenAPI operation %q has multiple CLI commands (%s); select a canonical command", operationID, strings.Join(paths, ", ")) - } + paths := make([]string, 0, len(candidates)) for _, candidate := range candidates { - if candidate.path == preferredPath { - return candidate, nil - } + paths = append(paths, candidate.path) } - return boundCommand{}, fmt.Errorf("canonical CLI command %q for OpenAPI operation %q does not exist", preferredPath, operationID) + slices.Sort(paths) + return boundCommand{}, fmt.Errorf("OpenAPI operation %q has multiple CLI commands (%s)", operationID, strings.Join(paths, ", ")) } func renderCommand(bound boundCommand) (string, error) { diff --git a/internal/codesamples/codesamples_test.go b/internal/codesamples/codesamples_test.go index 4fd68f4..75026fc 100644 --- a/internal/codesamples/codesamples_test.go +++ b/internal/codesamples/codesamples_test.go @@ -103,7 +103,7 @@ func TestGeneratedInvocationsReachAPITransport(t *testing.T) { t.Run(operation.ID, func(t *testing.T) { resourceCommands := commands.All() commandsByOperation := boundCommandsByOperation(resourceCommands) - bound, err := canonicalCommand(operation.ID, commandsByOperation[operation.ID]) + bound, err := commandForOperation(operation.ID, commandsByOperation[operation.ID]) require.NoError(t, err) invocation, err := buildInvocation(bound) require.NoError(t, err) @@ -135,12 +135,12 @@ func TestGeneratedInvocationsReachAPITransport(t *testing.T) { } } -func TestCanonicalCommandRequiresExplicitDuplicateSelection(t *testing.T) { +func TestCommandForOperationRejectsDuplicates(t *testing.T) { t.Parallel() - _, err := canonicalCommand("ExampleOperation", []boundCommand{{path: "examples first"}, {path: "examples second"}}) + _, err := commandForOperation("ExampleOperation", []boundCommand{{path: "examples first"}, {path: "examples second"}}) - require.EqualError(t, err, `OpenAPI operation "ExampleOperation" has multiple CLI commands (examples first, examples second); select a canonical command`) + require.EqualError(t, err, `OpenAPI operation "ExampleOperation" has multiple CLI commands (examples first, examples second)`) } func sampleByID(t *testing.T, samples []Sample, id string) Sample { diff --git a/internal/commands/checkouts/checkouts.go b/internal/commands/checkouts/checkouts.go index c90b161..ff6a4b9 100644 --- a/internal/commands/checkouts/checkouts.go +++ b/internal/commands/checkouts/checkouts.go @@ -13,6 +13,7 @@ import ( "github.com/sumup/sumup-go/datetime" "github.com/sumup/sumup-go/nullable" + "github.com/sumup/sumup-cli/internal/apicommands" "github.com/sumup/sumup-cli/internal/app" "github.com/sumup/sumup-cli/internal/commands/util" "github.com/sumup/sumup-cli/internal/currency" @@ -26,7 +27,7 @@ func NewCommand() *cli.Command { Name: "checkouts", Usage: "Commands related to hosted sumup.", Commands: []*cli.Command{ - { + apicommands.Bind("ListCheckouts", &cli.Command{ Name: "list", Usage: "List checkout resources.", Action: listCheckouts, @@ -36,8 +37,8 @@ func NewCommand() *cli.Command { Usage: "Filter results by checkout reference.", }, }, - }, - { + }), + apicommands.Bind("CreateCheckout", &cli.Command{ Name: "create", Usage: "Create a new checkout resource.", Description: `Examples: @@ -94,14 +95,14 @@ func NewCommand() *cli.Command { Usage: "Enable the SumUp-hosted checkout page and return its URL.", }, }, - }, - { + }), + apicommands.Bind("DeactivateCheckout", &cli.Command{ Name: "deactivate", Usage: "Deactivate a checkout by ID.", Action: deactivateCheckout, ArgsUsage: "", - }, - { + }), + apicommands.Bind("CreateApplePaySession", &cli.Command{ Name: "apple-pay-session", Usage: "Create an Apple Pay merchant session for a checkout.", Action: createApplePaySession, @@ -118,14 +119,14 @@ func NewCommand() *cli.Command { Required: true, }, }, - }, - { + }), + apicommands.Bind("GetCheckout", &cli.Command{ Name: "get", Usage: "Get a checkout by ID.", Action: getCheckout, ArgsUsage: "", - }, - { + }), + apicommands.Bind("UpdateCheckout", &cli.Command{ Name: "update", Usage: "Update a checkout by ID.", Description: `Examples: @@ -163,8 +164,8 @@ func NewCommand() *cli.Command { Usage: "Clear the checkout expiration timestamp.", }, }, - }, - { + }), + apicommands.Bind("GetPaymentMethods", &cli.Command{ Name: "payment-methods", Usage: "List available payment methods for a merchant.", Action: listPaymentMethods, @@ -183,8 +184,8 @@ func NewCommand() *cli.Command { Usage: fmt.Sprintf("Optional currency filter. Supported: %s", strings.Join(currency.Supported(), ", ")), }, }, - }, - { + }), + apicommands.Bind("ProcessCheckout", &cli.Command{ Name: "process", Usage: "Process a checkout.", Action: processCheckout, @@ -205,7 +206,7 @@ func NewCommand() *cli.Command { &cli.StringFlag{Name: "tax-id", Usage: "Customer tax ID."}, &cli.StringFlag{Name: "birth-date", Usage: "Customer birth date in YYYY-MM-DD format."}, }, - }, + }), }, } } diff --git a/internal/commands/commands.go b/internal/commands/commands.go index 67597b5..766cc9c 100644 --- a/internal/commands/commands.go +++ b/internal/commands/commands.go @@ -19,7 +19,7 @@ import ( // All returns the list of resource commands exposed by the CLI. func All() []*cli.Command { - return bindOpenAPIOperations([]*cli.Command{ + return []*cli.Command{ checkouts.NewCommand(), context.NewCommand(), customers.NewCommand(), @@ -32,5 +32,5 @@ func All() []*cli.Command { roles.NewCommand(), transactions.NewCommand(), version.NewCommand(), - }) + } } diff --git a/internal/commands/customers/customers.go b/internal/commands/customers/customers.go index f8ebd97..5e5ee31 100644 --- a/internal/commands/customers/customers.go +++ b/internal/commands/customers/customers.go @@ -12,6 +12,7 @@ import ( sumup "github.com/sumup/sumup-go" "github.com/sumup/sumup-go/datetime" + "github.com/sumup/sumup-cli/internal/apicommands" "github.com/sumup/sumup-cli/internal/app" "github.com/sumup/sumup-cli/internal/commands/util" "github.com/sumup/sumup-cli/internal/display" @@ -24,41 +25,41 @@ func NewCommand() *cli.Command { Name: "customers", Usage: "Commands for managing customers.", Commands: []*cli.Command{ - { + apicommands.Bind("CreateCustomer", &cli.Command{ Name: "create", Usage: "Create a customer.", Action: createCustomer, Flags: customerDetailsFlags(), - }, - { + }), + apicommands.Bind("GetCustomer", &cli.Command{ Name: "get", Usage: "Get a customer by ID.", Action: getCustomer, ArgsUsage: "", - }, - { + }), + apicommands.Bind("UpdateCustomer", &cli.Command{ Name: "update", Usage: "Update customer details.", Action: updateCustomer, ArgsUsage: "", Flags: customerDetailsFlags(), - }, + }), { Name: "payment-instruments", Usage: "Manage stored payment instruments for a customer.", Commands: []*cli.Command{ - { + apicommands.Bind("ListPaymentInstruments", &cli.Command{ Name: "list", Usage: "List stored payment instruments for a customer.", Action: listPaymentInstruments, ArgsUsage: "", - }, - { + }), + apicommands.Bind("DeactivatePaymentInstrument", &cli.Command{ Name: "deactivate", Usage: "Deactivate a stored payment instrument.", Action: deactivatePaymentInstrument, ArgsUsage: " ", - }, + }), }, }, }, diff --git a/internal/commands/members/members.go b/internal/commands/members/members.go index ddfd875..4fbb314 100644 --- a/internal/commands/members/members.go +++ b/internal/commands/members/members.go @@ -11,6 +11,7 @@ import ( sumup "github.com/sumup/sumup-go" "github.com/sumup/sumup-go/secret" + "github.com/sumup/sumup-cli/internal/apicommands" "github.com/sumup/sumup-cli/internal/app" "github.com/sumup/sumup-cli/internal/commands/util" "github.com/sumup/sumup-cli/internal/display" @@ -23,7 +24,7 @@ func NewCommand() *cli.Command { Name: "members", Usage: "Commands related to merchant members.", Commands: []*cli.Command{ - { + apicommands.Bind("ListMerchantMembers", &cli.Command{ Name: "list", Usage: "List members attached to a merchant resource.", Action: listMembers, @@ -62,8 +63,8 @@ func NewCommand() *cli.Command { Usage: "Skip counting results to speed up pagination.", }, }, - }, - { + }), + apicommands.Bind("CreateMerchantMember", &cli.Command{ Name: "create", Usage: "Create a merchant member.", Action: createMember, @@ -93,8 +94,8 @@ func NewCommand() *cli.Command { Usage: "Nickname for the member.", }, }, - }, - { + }), + apicommands.Bind("GetMerchantMember", &cli.Command{ Name: "get", Usage: "Get a member from the merchant account.", Action: getMember, @@ -106,8 +107,8 @@ func NewCommand() *cli.Command { Sources: cli.EnvVars("SUMUP_MERCHANT_CODE"), }, }, - }, - { + }), + apicommands.Bind("UpdateMerchantMember", &cli.Command{ Name: "update", Usage: "Update a member in the merchant account.", Action: updateMember, @@ -131,25 +132,8 @@ func NewCommand() *cli.Command { Usage: "Password for managed users.", }, }, - }, - { - Name: "invite", - Usage: "Invite a user to become a member of the merchant account.", - Action: inviteMember, - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "merchant-code", - Usage: "Merchant code to invite member to. Falls back to context.", - Sources: cli.EnvVars("SUMUP_MERCHANT_CODE"), - }, - &cli.StringFlag{ - Name: "email", - Usage: "Email of the user to invite.", - Required: true, - }, - }, - }, - { + }), + apicommands.Bind("DeleteMerchantMember", &cli.Command{ Name: "delete", Usage: "Delete a member from the merchant account.", Action: deleteMember, @@ -161,7 +145,7 @@ func NewCommand() *cli.Command { Sources: cli.EnvVars("SUMUP_MERCHANT_CODE"), }, }, - }, + }), }, } } @@ -277,36 +261,6 @@ func createMember(ctx context.Context, cmd *cli.Command) error { }) } -func inviteMember(ctx context.Context, cmd *cli.Command) error { - appCtx, err := app.GetAppContext(cmd) - if err != nil { - return err - } - - merchantCode, err := app.GetMerchantCode(cmd, "merchant-code") - if err != nil { - return err - } - - body := sumup.MembersCreateParams{ - Email: cmd.String("email"), - Roles: []string{"role_employee"}, - } - - response, err := appCtx.Client.Members.Create(ctx, merchantCode, body) - if err != nil { - return fmt.Errorf("invite member: %w", err) - } - - return display.RenderMutation(appCtx.Output, appCtx.StatusOutput, appCtx.JSONOutput, display.MutationResult{ - JSONValue: response, - SuccessMessage: "Member invited", - Details: []attribute.KeyValue{ - attribute.ID(response.ID), - }, - }) -} - func getMember(ctx context.Context, cmd *cli.Command) error { appCtx, err := app.GetAppContext(cmd) if err != nil { diff --git a/internal/commands/memberships/memberships.go b/internal/commands/memberships/memberships.go index aae7127..7df2dd3 100644 --- a/internal/commands/memberships/memberships.go +++ b/internal/commands/memberships/memberships.go @@ -9,6 +9,7 @@ import ( sumup "github.com/sumup/sumup-go" + "github.com/sumup/sumup-cli/internal/apicommands" "github.com/sumup/sumup-cli/internal/app" "github.com/sumup/sumup-cli/internal/commands/util" "github.com/sumup/sumup-cli/internal/display" @@ -20,7 +21,7 @@ func NewCommand() *cli.Command { Name: "memberships", Usage: "Commands related to sumup.", Commands: []*cli.Command{ - { + apicommands.Bind("ListMemberships", &cli.Command{ Name: "list", Usage: "List memberships for the authenticated user.", Action: listMemberships, @@ -54,7 +55,7 @@ func NewCommand() *cli.Command { Usage: "Filter memberships to sandbox resources only.", }, }, - }, + }), }, } } diff --git a/internal/commands/merchants/merchants.go b/internal/commands/merchants/merchants.go index ae2dca7..83cf65c 100644 --- a/internal/commands/merchants/merchants.go +++ b/internal/commands/merchants/merchants.go @@ -11,6 +11,7 @@ import ( sumup "github.com/sumup/sumup-go" + "github.com/sumup/sumup-cli/internal/apicommands" "github.com/sumup/sumup-cli/internal/app" "github.com/sumup/sumup-cli/internal/commands/util" "github.com/sumup/sumup-cli/internal/display" @@ -22,7 +23,7 @@ func NewCommand() *cli.Command { Name: "merchants", Usage: "Commands related to merchant accounts.", Commands: []*cli.Command{ - { + apicommands.Bind("GetMerchant", &cli.Command{ Name: "get", Usage: "Get merchant information.", Action: getMerchant, @@ -30,12 +31,12 @@ func NewCommand() *cli.Command { merchantCodeFlag("Merchant code to retrieve information for. Falls back to context."), versionFlag(), }, - }, + }), { Name: "persons", Usage: "Commands related to people associated with a merchant.", Commands: []*cli.Command{ - { + apicommands.Bind("ListPersons", &cli.Command{ Name: "list", Usage: "List people associated with a merchant.", Action: listPersons, @@ -43,8 +44,8 @@ func NewCommand() *cli.Command { merchantCodeFlag("Merchant code whose people should be listed. Falls back to context."), versionFlag(), }, - }, - { + }), + apicommands.Bind("GetPerson", &cli.Command{ Name: "get", Usage: "Get a person associated with a merchant.", ArgsUsage: "", @@ -53,7 +54,7 @@ func NewCommand() *cli.Command { merchantCodeFlag("Merchant code associated with the person. Falls back to context."), versionFlag(), }, - }, + }), }, }, }, diff --git a/internal/commands/operations.go b/internal/commands/operations.go deleted file mode 100644 index ac7a914..0000000 --- a/internal/commands/operations.go +++ /dev/null @@ -1,85 +0,0 @@ -package commands - -import ( - "fmt" - "strings" - - "github.com/urfave/cli/v3" - - "github.com/sumup/sumup-cli/internal/apicommands" -) - -// operationBindings is the handwritten CLI naming layer over the generated -// OpenAPI catalog. More than one command may intentionally expose an operation, -// such as the member create and invite flows. -var operationBindings = map[string]string{ - "checkouts apple-pay-session": "CreateApplePaySession", - "checkouts create": "CreateCheckout", - "checkouts deactivate": "DeactivateCheckout", - "checkouts get": "GetCheckout", - "checkouts list": "ListCheckouts", - "checkouts payment-methods": "GetPaymentMethods", - "checkouts process": "ProcessCheckout", - "checkouts update": "UpdateCheckout", - "customers create": "CreateCustomer", - "customers get": "GetCustomer", - "customers payment-instruments deactivate": "DeactivatePaymentInstrument", - "customers payment-instruments list": "ListPaymentInstruments", - "customers update": "UpdateCustomer", - "members create": "CreateMerchantMember", - "members delete": "DeleteMerchantMember", - "members get": "GetMerchantMember", - "members invite": "CreateMerchantMember", - "members list": "ListMerchantMembers", - "members update": "UpdateMerchantMember", - "memberships list": "ListMemberships", - "merchants get": "GetMerchant", - "merchants persons get": "GetPerson", - "merchants persons list": "ListPersons", - "payouts list": "ListPayoutsV1", - "readers add": "CreateReader", - "readers checkout": "CreateReaderCheckout", - "readers delete": "DeleteReader", - "readers get": "GetReader", - "readers list": "ListReaders", - "readers status": "GetReaderStatus", - "readers terminate": "CreateReaderTerminate", - "readers update": "UpdateReader", - "receipts get": "GetReceipt", - "roles create": "CreateMerchantRole", - "roles delete": "DeleteMerchantRole", - "roles get": "GetMerchantRole", - "roles list": "ListMerchantRoles", - "roles update": "UpdateMerchantRole", - "transactions get": "GetTransactionV2.1", - "transactions list": "ListTransactionsV2.1", - "transactions refund": "RefundTransaction", -} - -func bindOpenAPIOperations(commands []*cli.Command) []*cli.Command { - leaves := make(map[string]*cli.Command) - var collect func([]string, *cli.Command) - collect = func(parents []string, command *cli.Command) { - path := append(parents, command.Name) - if len(command.Commands) == 0 { - leaves[strings.Join(path, " ")] = command - return - } - for _, child := range command.Commands { - collect(path, child) - } - } - for _, command := range commands { - collect(nil, command) - } - - for commandPath, operationID := range operationBindings { - command, ok := leaves[commandPath] - if !ok { - panic(fmt.Sprintf("OpenAPI operation binding refers to unknown command %q", commandPath)) - } - apicommands.Bind(command, operationID) - } - - return commands -} diff --git a/internal/commands/operations_test.go b/internal/commands/operations_test.go index bbc8659..283a2a9 100644 --- a/internal/commands/operations_test.go +++ b/internal/commands/operations_test.go @@ -49,7 +49,7 @@ func TestCommandsCoverOpenAPICatalog(t *testing.T) { apiGroups[strings.ToLower(operation.Client)] = struct{}{} } - covered := make(map[string]struct{}) + commandsByOperation := make(map[string][]string) unbound := make([]string, 0) walkLeafCommands(All(), func(path string, command *cli.Command) { group, _, _ := strings.Cut(path, " ") @@ -62,19 +62,30 @@ func TestCommandsCoverOpenAPICatalog(t *testing.T) { unbound = append(unbound, path) return } - covered[operationID] = struct{}{} + commandsByOperation[operationID] = append(commandsByOperation[operationID], path) }) slices.Sort(unbound) missing := make([]string, 0) for _, operation := range apicommands.Operations { - if _, ok := covered[operation.ID]; !ok { + if _, ok := commandsByOperation[operation.ID]; !ok { missing = append(missing, operation.Client+"."+operation.SDKMethod+" ("+operation.ID+")") } } slices.Sort(missing) + duplicates := make([]string, 0) + for operationID, paths := range commandsByOperation { + if len(paths) < 2 { + continue + } + slices.Sort(paths) + duplicates = append(duplicates, operationID+": "+strings.Join(paths, ", ")) + } + slices.Sort(duplicates) + require.Empty(t, unbound, "API commands without an OpenAPI operation binding") + require.Empty(t, duplicates, "OpenAPI operations exposed by more than one CLI command") assert.Empty(t, missing, "SDK operations without a CLI command") } diff --git a/internal/commands/payouts/payouts.go b/internal/commands/payouts/payouts.go index 56518ef..652f83a 100644 --- a/internal/commands/payouts/payouts.go +++ b/internal/commands/payouts/payouts.go @@ -11,6 +11,7 @@ import ( sumup "github.com/sumup/sumup-go" "github.com/sumup/sumup-go/datetime" + "github.com/sumup/sumup-cli/internal/apicommands" "github.com/sumup/sumup-cli/internal/app" "github.com/sumup/sumup-cli/internal/commands/util" "github.com/sumup/sumup-cli/internal/display" @@ -22,7 +23,7 @@ func NewCommand() *cli.Command { Name: "payouts", Usage: "Commands for listing merchant payouts.", Commands: []*cli.Command{ - { + apicommands.Bind("ListPayoutsV1", &cli.Command{ Name: "list", Usage: "List payouts for a merchant.", Action: listPayouts, @@ -51,7 +52,7 @@ func NewCommand() *cli.Command { Usage: "Sort payouts in ascending or descending order (asc, desc).", }, }, - }, + }), }, } } diff --git a/internal/commands/readers/readers.go b/internal/commands/readers/readers.go index 1ac412d..c386051 100644 --- a/internal/commands/readers/readers.go +++ b/internal/commands/readers/readers.go @@ -13,6 +13,7 @@ import ( sumup "github.com/sumup/sumup-go" "github.com/sumup/sumup-go/nullable" + "github.com/sumup/sumup-cli/internal/apicommands" "github.com/sumup/sumup-cli/internal/app" "github.com/sumup/sumup-cli/internal/commands/util" "github.com/sumup/sumup-cli/internal/currency" @@ -26,7 +27,7 @@ func NewCommand() *cli.Command { Name: "readers", Usage: "Commands for managing in-person readers.", Commands: []*cli.Command{ - { + apicommands.Bind("ListReaders", &cli.Command{ Name: "list", Usage: "List paired readers for a merchant.", Action: listReaders, @@ -37,8 +38,8 @@ func NewCommand() *cli.Command { Sources: cli.EnvVars("SUMUP_MERCHANT_CODE"), }, }, - }, - { + }), + apicommands.Bind("CreateReader", &cli.Command{ Name: "add", Usage: "Pair a new reader with the merchant account.", Action: addReader, @@ -59,8 +60,8 @@ func NewCommand() *cli.Command { Required: true, }, }, - }, - { + }), + apicommands.Bind("DeleteReader", &cli.Command{ Name: "delete", Usage: "Delete a paired reader from the merchant account.", Action: deleteReader, @@ -72,8 +73,8 @@ func NewCommand() *cli.Command { Sources: cli.EnvVars("SUMUP_MERCHANT_CODE"), }, }, - }, - { + }), + apicommands.Bind("GetReaderStatus", &cli.Command{ Name: "status", Usage: "Show the last known status of a reader.", Action: readerStatus, @@ -85,8 +86,8 @@ func NewCommand() *cli.Command { Sources: cli.EnvVars("SUMUP_MERCHANT_CODE"), }, }, - }, - { + }), + apicommands.Bind("GetReader", &cli.Command{ Name: "get", Usage: "Get a paired reader.", Action: getReader, @@ -102,8 +103,8 @@ func NewCommand() *cli.Command { Usage: "Optional If-Modified-Since query value.", }, }, - }, - { + }), + apicommands.Bind("UpdateReader", &cli.Command{ Name: "update", Usage: "Update a paired reader.", Action: updateReader, @@ -120,8 +121,8 @@ func NewCommand() *cli.Command { Required: true, }, }, - }, - { + }), + apicommands.Bind("CreateReaderTerminate", &cli.Command{ Name: "terminate", Usage: "Terminate the current reader checkout.", Action: terminateCheckout, @@ -133,8 +134,8 @@ func NewCommand() *cli.Command { Sources: cli.EnvVars("SUMUP_MERCHANT_CODE"), }, }, - }, - { + }), + apicommands.Bind("CreateReaderCheckout", &cli.Command{ Name: "checkout", Usage: "Trigger a checkout on a specific reader device.", Action: readerCheckout, @@ -197,7 +198,7 @@ func NewCommand() *cli.Command { Usage: "Affiliate foreign transaction ID to attribute the transaction.", }, }, - }, + }), }, } } diff --git a/internal/commands/receipts/receipts.go b/internal/commands/receipts/receipts.go index d0209fe..bdbfef1 100644 --- a/internal/commands/receipts/receipts.go +++ b/internal/commands/receipts/receipts.go @@ -10,6 +10,7 @@ import ( sumup "github.com/sumup/sumup-go" + "github.com/sumup/sumup-cli/internal/apicommands" "github.com/sumup/sumup-cli/internal/app" "github.com/sumup/sumup-cli/internal/commands/util" "github.com/sumup/sumup-cli/internal/display" @@ -21,7 +22,7 @@ func NewCommand() *cli.Command { Name: "receipts", Usage: "Commands for retrieving transaction receipts.", Commands: []*cli.Command{ - { + apicommands.Bind("GetReceipt", &cli.Command{ Name: "get", Usage: "Get a receipt by transaction ID.", Action: getReceipt, @@ -37,7 +38,7 @@ func NewCommand() *cli.Command { Usage: "Transaction event ID for refund sumup.", }, }, - }, + }), }, } } diff --git a/internal/commands/roles/roles.go b/internal/commands/roles/roles.go index da580b9..837f1ea 100644 --- a/internal/commands/roles/roles.go +++ b/internal/commands/roles/roles.go @@ -10,6 +10,7 @@ import ( sumup "github.com/sumup/sumup-go" + "github.com/sumup/sumup-cli/internal/apicommands" "github.com/sumup/sumup-cli/internal/app" "github.com/sumup/sumup-cli/internal/commands/util" "github.com/sumup/sumup-cli/internal/display" @@ -22,15 +23,15 @@ func NewCommand() *cli.Command { Name: "roles", Usage: "Commands for managing roles.", Commands: []*cli.Command{ - { + apicommands.Bind("ListMerchantRoles", &cli.Command{ Name: "list", Usage: "List available roles.", Action: listRoles, Flags: []cli.Flag{ merchantCodeFlag("Merchant code whose roles should be listed. Falls back to context."), }, - }, - { + }), + apicommands.Bind("CreateMerchantRole", &cli.Command{ Name: "create", Usage: "Create a custom role.", Action: createRole, @@ -51,8 +52,8 @@ func NewCommand() *cli.Command { Usage: "User-defined role description.", }, }, - }, - { + }), + apicommands.Bind("GetMerchantRole", &cli.Command{ Name: "get", Usage: "Get a custom role by ID.", Action: getRole, @@ -60,8 +61,8 @@ func NewCommand() *cli.Command { Flags: []cli.Flag{ merchantCodeFlag("Merchant code that owns the role. Falls back to context."), }, - }, - { + }), + apicommands.Bind("UpdateMerchantRole", &cli.Command{ Name: "update", Usage: "Update a custom role.", Action: updateRole, @@ -81,8 +82,8 @@ func NewCommand() *cli.Command { Usage: "Updated role description.", }, }, - }, - { + }), + apicommands.Bind("DeleteMerchantRole", &cli.Command{ Name: "delete", Usage: "Delete a custom role.", Action: deleteRole, @@ -90,7 +91,7 @@ func NewCommand() *cli.Command { Flags: []cli.Flag{ merchantCodeFlag("Merchant code that owns the role. Falls back to context."), }, - }, + }), }, } } diff --git a/internal/commands/transactions/transactions.go b/internal/commands/transactions/transactions.go index cecd180..0d6b83a 100644 --- a/internal/commands/transactions/transactions.go +++ b/internal/commands/transactions/transactions.go @@ -10,6 +10,7 @@ import ( sumup "github.com/sumup/sumup-go" + "github.com/sumup/sumup-cli/internal/apicommands" "github.com/sumup/sumup-cli/internal/app" "github.com/sumup/sumup-cli/internal/commands/util" "github.com/sumup/sumup-cli/internal/currency" @@ -22,7 +23,7 @@ func NewCommand() *cli.Command { Name: "transactions", Usage: "Commands for listing, retrieving, and refunding transactions.", Commands: []*cli.Command{ - { + apicommands.Bind("ListTransactionsV2.1", &cli.Command{ Name: "list", Usage: "List transactions for a merchant.", Action: listTransactions, @@ -81,8 +82,8 @@ func NewCommand() *cli.Command { Usage: "Filter by user email. May be specified multiple times.", }, }, - }, - { + }), + apicommands.Bind("GetTransactionV2.1", &cli.Command{ Name: "get", Usage: "Get a specific transaction.", Action: getTransaction, @@ -110,8 +111,8 @@ func NewCommand() *cli.Command { Usage: "Lookup by client transaction ID.", }, }, - }, - { + }), + apicommands.Bind("RefundTransaction", &cli.Command{ Name: "refund", Usage: "Refund a transaction fully or partially.", Action: refundTransaction, @@ -127,7 +128,7 @@ func NewCommand() *cli.Command { Usage: "Optional partial refund amount in major units.", }, }, - }, + }), }, } }