diff --git a/go.mod b/go.mod index 5a423af..6a94a6f 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 github.com/tidwall/pretty v1.2.1 - github.com/trycourier/courier-go/v4 v4.18.1 + github.com/trycourier/courier-go/v4 v4.20.0 github.com/urfave/cli-docs/v3 v3.0.0-alpha6 github.com/urfave/cli/v3 v3.3.2 golang.org/x/sys v0.38.0 diff --git a/go.sum b/go.sum index 915a391..9cdb700 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,8 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= -github.com/trycourier/courier-go/v4 v4.18.1 h1:YcLkq6cs9Ae99Jo3zE5560HdCb2AA3cVafqeZMLQgi0= -github.com/trycourier/courier-go/v4 v4.18.1/go.mod h1:0ZQyZUNupRxUytcf9bLyIjCyssOKl0vT+wqjjaMaw6k= +github.com/trycourier/courier-go/v4 v4.20.0 h1:SF7OtspsTyAtsdhMrzjyz2C1s1OgsL+0hVzXgYtRSWk= +github.com/trycourier/courier-go/v4 v4.20.0/go.mod h1:0ZQyZUNupRxUytcf9bLyIjCyssOKl0vT+wqjjaMaw6k= github.com/urfave/cli-docs/v3 v3.0.0-alpha6 h1:w/l/N0xw1rO/aHRIGXJ0lDwwYFOzilup1qGvIytP3BI= github.com/urfave/cli-docs/v3 v3.0.0-alpha6/go.mod h1:p7Z4lg8FSTrPB9GTaNyTrK3ygffHZcK3w0cU2VE+mzU= github.com/urfave/cli/v3 v3.3.2 h1:BYFVnhhZ8RqT38DxEYVFPPmGFTEf7tJwySTXsVRrS/o= diff --git a/pkg/cmd/bulk.go b/pkg/cmd/bulk.go deleted file mode 100644 index 2fd110c..0000000 --- a/pkg/cmd/bulk.go +++ /dev/null @@ -1,350 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -package cmd - -import ( - "context" - "fmt" - - "github.com/tidwall/gjson" - "github.com/trycourier/courier-cli/v3/internal/apiquery" - "github.com/trycourier/courier-cli/v3/internal/requestflag" - "github.com/trycourier/courier-go/v4" - "github.com/trycourier/courier-go/v4/option" - "github.com/urfave/cli/v3" -) - -var bulkAddUsers = requestflag.WithInnerFlags(cli.Command{ - Name: "add-users", - Usage: "Ingest user data into a Bulk Job.", - Suggest: true, - Flags: []cli.Flag{ - &requestflag.Flag[string]{ - Name: "job-id", - Required: true, - PathParam: "job_id", - }, - &requestflag.Flag[[]map[string]any]{ - Name: "user", - Required: true, - BodyPath: "users", - }, - }, - Action: handleBulkAddUsers, - HideHelpCommand: true, -}, map[string][]requestflag.HasOuterFlag{ - "user": { - &requestflag.InnerFlag[any]{ - Name: "user.data", - Usage: "User-specific data that will be merged with message.data", - InnerField: "data", - }, - &requestflag.InnerFlag[map[string]any]{ - Name: "user.preferences", - InnerField: "preferences", - }, - &requestflag.InnerFlag[map[string]any]{ - Name: "user.profile", - Usage: "User profile information. For email-based bulk jobs, `profile.email` is required \nfor provider routing to determine if the message can be delivered. The email \naddress should be provided here rather than in `to.email`.\n", - InnerField: "profile", - }, - &requestflag.InnerFlag[*string]{ - Name: "user.recipient", - Usage: "User ID (legacy field, use profile or to.user_id instead)", - InnerField: "recipient", - }, - &requestflag.InnerFlag[map[string]any]{ - Name: "user.to", - InnerField: "to", - }, - }, -}) - -var bulkCreateJob = requestflag.WithInnerFlags(cli.Command{ - Name: "create-job", - Usage: "Creates a new bulk job for sending messages to multiple recipients.", - Suggest: true, - Flags: []cli.Flag{ - &requestflag.Flag[map[string]any]{ - Name: "message", - Usage: "Bulk message definition. Supports two formats:\n- V1 format: Requires `event` field (event ID or notification ID)\n- V2 format: Optionally use `template` (notification ID) or `content` (Elemental content) in addition to `event`\n", - Required: true, - BodyPath: "message", - }, - }, - Action: handleBulkCreateJob, - HideHelpCommand: true, -}, map[string][]requestflag.HasOuterFlag{ - "message": { - &requestflag.InnerFlag[string]{ - Name: "message.event", - Usage: "Event ID or Notification ID (required). Can be either a \nNotification ID (e.g., \"FRH3QXM9E34W4RKP7MRC8NZ1T8V8\") or a custom Event ID \n(e.g., \"welcome-email\") mapped to a notification.\n", - InnerField: "event", - }, - &requestflag.InnerFlag[*string]{ - Name: "message.brand", - InnerField: "brand", - }, - &requestflag.InnerFlag[map[string]any]{ - Name: "message.content", - Usage: "Elemental content (optional, for V2 format). When provided, this will be used \ninstead of the notification associated with the `event` field.\n", - InnerField: "content", - }, - &requestflag.InnerFlag[map[string]any]{ - Name: "message.data", - InnerField: "data", - }, - &requestflag.InnerFlag[map[string]any]{ - Name: "message.locale", - InnerField: "locale", - }, - &requestflag.InnerFlag[map[string]any]{ - Name: "message.override", - InnerField: "override", - }, - &requestflag.InnerFlag[*string]{ - Name: "message.template", - Usage: "Notification ID or template ID (optional, for V2 format). When provided, \nthis will be used instead of the notification associated with the `event` field.\n", - InnerField: "template", - }, - }, -}) - -var bulkListUsers = cli.Command{ - Name: "list-users", - Usage: "Get Bulk Job Users", - Suggest: true, - Flags: []cli.Flag{ - &requestflag.Flag[string]{ - Name: "job-id", - Required: true, - PathParam: "job_id", - }, - &requestflag.Flag[*string]{ - Name: "cursor", - Usage: "A unique identifier that allows for fetching the next set of users added to the bulk job", - QueryPath: "cursor", - }, - }, - Action: handleBulkListUsers, - HideHelpCommand: true, -} - -var bulkRetrieveJob = cli.Command{ - Name: "retrieve-job", - Usage: "Get a bulk job", - Suggest: true, - Flags: []cli.Flag{ - &requestflag.Flag[string]{ - Name: "job-id", - Required: true, - PathParam: "job_id", - }, - }, - Action: handleBulkRetrieveJob, - HideHelpCommand: true, -} - -var bulkRunJob = cli.Command{ - Name: "run-job", - Usage: "Run a bulk job", - Suggest: true, - Flags: []cli.Flag{ - &requestflag.Flag[string]{ - Name: "job-id", - Required: true, - PathParam: "job_id", - }, - }, - Action: handleBulkRunJob, - HideHelpCommand: true, -} - -func handleBulkAddUsers(ctx context.Context, cmd *cli.Command) error { - client := courier.NewClient(getDefaultRequestOptions(cmd)...) - unusedArgs := cmd.Args().Slice() - if !cmd.IsSet("job-id") && len(unusedArgs) > 0 { - cmd.Set("job-id", unusedArgs[0]) - unusedArgs = unusedArgs[1:] - } - if len(unusedArgs) > 0 { - return fmt.Errorf("Unexpected extra arguments: %v", unusedArgs) - } - - options, err := flagOptions( - cmd, - apiquery.NestedQueryFormatBrackets, - apiquery.ArrayQueryFormatComma, - ApplicationJSON, - false, - ) - if err != nil { - return err - } - - params := courier.BulkAddUsersParams{} - - return client.Bulk.AddUsers( - ctx, - cmd.Value("job-id").(string), - params, - options..., - ) -} - -func handleBulkCreateJob(ctx context.Context, cmd *cli.Command) error { - client := courier.NewClient(getDefaultRequestOptions(cmd)...) - unusedArgs := cmd.Args().Slice() - - if len(unusedArgs) > 0 { - return fmt.Errorf("Unexpected extra arguments: %v", unusedArgs) - } - - options, err := flagOptions( - cmd, - apiquery.NestedQueryFormatBrackets, - apiquery.ArrayQueryFormatComma, - ApplicationJSON, - false, - ) - if err != nil { - return err - } - - params := courier.BulkNewJobParams{} - - var res []byte - options = append(options, option.WithResponseBodyInto(&res)) - _, err = client.Bulk.NewJob(ctx, params, options...) - if err != nil { - return err - } - - obj := gjson.ParseBytes(res) - format := cmd.Root().String("format") - explicitFormat := cmd.Root().IsSet("format") - transform := cmd.Root().String("transform") - return ShowJSON(obj, ShowJSONOpts{ - ExplicitFormat: explicitFormat, - Format: format, - RawOutput: cmd.Root().Bool("raw-output"), - Title: "bulk create-job", - Transform: transform, - }) -} - -func handleBulkListUsers(ctx context.Context, cmd *cli.Command) error { - client := courier.NewClient(getDefaultRequestOptions(cmd)...) - unusedArgs := cmd.Args().Slice() - if !cmd.IsSet("job-id") && len(unusedArgs) > 0 { - cmd.Set("job-id", unusedArgs[0]) - unusedArgs = unusedArgs[1:] - } - if len(unusedArgs) > 0 { - return fmt.Errorf("Unexpected extra arguments: %v", unusedArgs) - } - - options, err := flagOptions( - cmd, - apiquery.NestedQueryFormatBrackets, - apiquery.ArrayQueryFormatComma, - EmptyBody, - false, - ) - if err != nil { - return err - } - - params := courier.BulkListUsersParams{} - - var res []byte - options = append(options, option.WithResponseBodyInto(&res)) - _, err = client.Bulk.ListUsers( - ctx, - cmd.Value("job-id").(string), - params, - options..., - ) - if err != nil { - return err - } - - obj := gjson.ParseBytes(res) - format := cmd.Root().String("format") - explicitFormat := cmd.Root().IsSet("format") - transform := cmd.Root().String("transform") - return ShowJSON(obj, ShowJSONOpts{ - ExplicitFormat: explicitFormat, - Format: format, - RawOutput: cmd.Root().Bool("raw-output"), - Title: "bulk list-users", - Transform: transform, - }) -} - -func handleBulkRetrieveJob(ctx context.Context, cmd *cli.Command) error { - client := courier.NewClient(getDefaultRequestOptions(cmd)...) - unusedArgs := cmd.Args().Slice() - if !cmd.IsSet("job-id") && len(unusedArgs) > 0 { - cmd.Set("job-id", unusedArgs[0]) - unusedArgs = unusedArgs[1:] - } - if len(unusedArgs) > 0 { - return fmt.Errorf("Unexpected extra arguments: %v", unusedArgs) - } - - options, err := flagOptions( - cmd, - apiquery.NestedQueryFormatBrackets, - apiquery.ArrayQueryFormatComma, - EmptyBody, - false, - ) - if err != nil { - return err - } - - var res []byte - options = append(options, option.WithResponseBodyInto(&res)) - _, err = client.Bulk.GetJob(ctx, cmd.Value("job-id").(string), options...) - if err != nil { - return err - } - - obj := gjson.ParseBytes(res) - format := cmd.Root().String("format") - explicitFormat := cmd.Root().IsSet("format") - transform := cmd.Root().String("transform") - return ShowJSON(obj, ShowJSONOpts{ - ExplicitFormat: explicitFormat, - Format: format, - RawOutput: cmd.Root().Bool("raw-output"), - Title: "bulk retrieve-job", - Transform: transform, - }) -} - -func handleBulkRunJob(ctx context.Context, cmd *cli.Command) error { - client := courier.NewClient(getDefaultRequestOptions(cmd)...) - unusedArgs := cmd.Args().Slice() - if !cmd.IsSet("job-id") && len(unusedArgs) > 0 { - cmd.Set("job-id", unusedArgs[0]) - unusedArgs = unusedArgs[1:] - } - if len(unusedArgs) > 0 { - return fmt.Errorf("Unexpected extra arguments: %v", unusedArgs) - } - - options, err := flagOptions( - cmd, - apiquery.NestedQueryFormatBrackets, - apiquery.ArrayQueryFormatComma, - EmptyBody, - false, - ) - if err != nil { - return err - } - - return client.Bulk.RunJob(ctx, cmd.Value("job-id").(string), options...) -} diff --git a/pkg/cmd/bulk_test.go b/pkg/cmd/bulk_test.go deleted file mode 100644 index 66b441f..0000000 --- a/pkg/cmd/bulk_test.go +++ /dev/null @@ -1,198 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -package cmd - -import ( - "testing" - - "github.com/trycourier/courier-cli/v3/internal/mocktest" - "github.com/trycourier/courier-cli/v3/internal/requestflag" -) - -func TestBulkAddUsers(t *testing.T) { - t.Skip("Mock server tests are disabled") - t.Run("regular flags", func(t *testing.T) { - mocktest.TestRunMockTestWithFlags( - t, - "--api-key", "string", - "bulk", "add-users", - "--job-id", "job_id", - "--user", "{data: {}, preferences: {categories: {foo: {status: OPTED_IN, channel_preferences: [{channel: direct_message}], rules: [{until: until, start: start}]}}, notifications: {foo: {status: OPTED_IN, channel_preferences: [{channel: direct_message}], rules: [{until: until, start: start}]}}}, profile: {foo: bar}, recipient: recipient, to: {account_id: account_id, context: {tenant_id: tenant_id}, data: {foo: bar}, email: email, list_id: list_id, locale: locale, phone_number: phone_number, preferences: {notifications: {foo: {status: OPTED_IN, channel_preferences: [{channel: direct_message}], rules: [{until: until, start: start}], source: subscription}}, categories: {foo: {status: OPTED_IN, channel_preferences: [{channel: direct_message}], rules: [{until: until, start: start}], source: subscription}}, templateId: templateId}, tenant_id: tenant_id, user_id: user_id}}", - ) - }) - - t.Run("inner flags", func(t *testing.T) { - // Check that inner flags have been set up correctly - requestflag.CheckInnerFlags(bulkAddUsers) - - // Alternative argument passing style using inner flags - mocktest.TestRunMockTestWithFlags( - t, - "--api-key", "string", - "bulk", "add-users", - "--job-id", "job_id", - "--user.data", "{}", - "--user.preferences", "{categories: {foo: {status: OPTED_IN, channel_preferences: [{channel: direct_message}], rules: [{until: until, start: start}]}}, notifications: {foo: {status: OPTED_IN, channel_preferences: [{channel: direct_message}], rules: [{until: until, start: start}]}}}", - "--user.profile", "{foo: bar}", - "--user.recipient", "recipient", - "--user.to", "{account_id: account_id, context: {tenant_id: tenant_id}, data: {foo: bar}, email: email, list_id: list_id, locale: locale, phone_number: phone_number, preferences: {notifications: {foo: {status: OPTED_IN, channel_preferences: [{channel: direct_message}], rules: [{until: until, start: start}], source: subscription}}, categories: {foo: {status: OPTED_IN, channel_preferences: [{channel: direct_message}], rules: [{until: until, start: start}], source: subscription}}, templateId: templateId}, tenant_id: tenant_id, user_id: user_id}", - ) - }) - - t.Run("piping data", func(t *testing.T) { - // Test piping YAML data over stdin - pipeData := []byte("" + - "users:\n" + - " - data: {}\n" + - " preferences:\n" + - " categories:\n" + - " foo:\n" + - " status: OPTED_IN\n" + - " channel_preferences:\n" + - " - channel: direct_message\n" + - " rules:\n" + - " - until: until\n" + - " start: start\n" + - " notifications:\n" + - " foo:\n" + - " status: OPTED_IN\n" + - " channel_preferences:\n" + - " - channel: direct_message\n" + - " rules:\n" + - " - until: until\n" + - " start: start\n" + - " profile:\n" + - " foo: bar\n" + - " recipient: recipient\n" + - " to:\n" + - " account_id: account_id\n" + - " context:\n" + - " tenant_id: tenant_id\n" + - " data:\n" + - " foo: bar\n" + - " email: email\n" + - " list_id: list_id\n" + - " locale: locale\n" + - " phone_number: phone_number\n" + - " preferences:\n" + - " notifications:\n" + - " foo:\n" + - " status: OPTED_IN\n" + - " channel_preferences:\n" + - " - channel: direct_message\n" + - " rules:\n" + - " - until: until\n" + - " start: start\n" + - " source: subscription\n" + - " categories:\n" + - " foo:\n" + - " status: OPTED_IN\n" + - " channel_preferences:\n" + - " - channel: direct_message\n" + - " rules:\n" + - " - until: until\n" + - " start: start\n" + - " source: subscription\n" + - " templateId: templateId\n" + - " tenant_id: tenant_id\n" + - " user_id: user_id\n") - mocktest.TestRunMockTestWithPipeAndFlags( - t, pipeData, - "--api-key", "string", - "bulk", "add-users", - "--job-id", "job_id", - ) - }) -} - -func TestBulkCreateJob(t *testing.T) { - t.Skip("Mock server tests are disabled") - t.Run("regular flags", func(t *testing.T) { - mocktest.TestRunMockTestWithFlags( - t, - "--api-key", "string", - "bulk", "create-job", - "--message", "{event: event, brand: brand, content: {body: body, title: title}, data: {foo: bar}, locale: {foo: {foo: bar}}, override: {foo: bar}, template: template}", - ) - }) - - t.Run("inner flags", func(t *testing.T) { - // Check that inner flags have been set up correctly - requestflag.CheckInnerFlags(bulkCreateJob) - - // Alternative argument passing style using inner flags - mocktest.TestRunMockTestWithFlags( - t, - "--api-key", "string", - "bulk", "create-job", - "--message.event", "event", - "--message.brand", "brand", - "--message.content", "{body: body, title: title}", - "--message.data", "{foo: bar}", - "--message.locale", "{foo: {foo: bar}}", - "--message.override", "{foo: bar}", - "--message.template", "template", - ) - }) - - t.Run("piping data", func(t *testing.T) { - // Test piping YAML data over stdin - pipeData := []byte("" + - "message:\n" + - " event: event\n" + - " brand: brand\n" + - " content:\n" + - " body: body\n" + - " title: title\n" + - " data:\n" + - " foo: bar\n" + - " locale:\n" + - " foo:\n" + - " foo: bar\n" + - " override:\n" + - " foo: bar\n" + - " template: template\n") - mocktest.TestRunMockTestWithPipeAndFlags( - t, pipeData, - "--api-key", "string", - "bulk", "create-job", - ) - }) -} - -func TestBulkListUsers(t *testing.T) { - t.Skip("Mock server tests are disabled") - t.Run("regular flags", func(t *testing.T) { - mocktest.TestRunMockTestWithFlags( - t, - "--api-key", "string", - "bulk", "list-users", - "--job-id", "job_id", - "--cursor", "cursor", - ) - }) -} - -func TestBulkRetrieveJob(t *testing.T) { - t.Skip("Mock server tests are disabled") - t.Run("regular flags", func(t *testing.T) { - mocktest.TestRunMockTestWithFlags( - t, - "--api-key", "string", - "bulk", "retrieve-job", - "--job-id", "job_id", - ) - }) -} - -func TestBulkRunJob(t *testing.T) { - t.Skip("Mock server tests are disabled") - t.Run("regular flags", func(t *testing.T) { - mocktest.TestRunMockTestWithFlags( - t, - "--api-key", "string", - "bulk", "run-job", - "--job-id", "job_id", - ) - }) -} diff --git a/pkg/cmd/cmd.go b/pkg/cmd/cmd.go index fbbf72c..0bba44d 100644 --- a/pkg/cmd/cmd.go +++ b/pkg/cmd/cmd.go @@ -203,18 +203,6 @@ func init() { &brandsDelete, }, }, - { - Name: "bulk", - Category: "API RESOURCE", - Suggest: true, - Commands: []*cli.Command{ - &bulkAddUsers, - &bulkCreateJob, - &bulkListUsers, - &bulkRetrieveJob, - &bulkRunJob, - }, - }, { Name: "digests:schedules", Category: "API RESOURCE",