From ddf0807044b0db81cbc57e921267868d13ced06e Mon Sep 17 00:00:00 2001 From: Quentin Rousseau Date: Wed, 12 Aug 2026 20:19:54 -0700 Subject: [PATCH 1/3] add incident service and type flags --- internal/api/client.go | 16 ++++++++++++++-- internal/api/client_http_test.go | 8 +++++--- internal/api/client_mutations_test.go | 20 +++++++++++++++----- internal/cmd/incidents/cmd_test.go | 8 ++++++++ internal/cmd/incidents/create.go | 14 +++++++++++++- internal/cmd/incidents/update.go | 19 +++++++++++++++++-- 6 files changed, 72 insertions(+), 13 deletions(-) diff --git a/internal/api/client.go b/internal/api/client.go index 82ecd84..2db7920 100644 --- a/internal/api/client.go +++ b/internal/api/client.go @@ -1075,7 +1075,7 @@ func (c *Client) GetIncidentByID(ctx context.Context, id string) (*Incident, err } // CreateIncident creates a new incident using raw HTTP POST. -func (c *Client) CreateIncident(ctx context.Context, title string, opts map[string]string) (*Incident, error) { +func (c *Client) CreateIncident(ctx context.Context, title string, opts map[string]interface{}) (*Incident, error) { // Build JSON:API request body requestBody := map[string]interface{}{ "data": map[string]interface{}{ @@ -1097,6 +1097,12 @@ func (c *Client) CreateIncident(ctx context.Context, title string, opts map[stri if status, ok := opts["status"]; ok { attributes["status"] = status } + if serviceIDs, ok := opts["service_ids"]; ok { + attributes["service_ids"] = serviceIDs + } + if incidentTypeIDs, ok := opts["incident_type_ids"]; ok { + attributes["incident_type_ids"] = incidentTypeIDs + } bodyBytes, err := json.Marshal(requestBody) if err != nil { @@ -1150,7 +1156,7 @@ func (c *Client) CreateIncident(ctx context.Context, title string, opts map[stri } // UpdateIncident updates an incident using raw HTTP PUT. -func (c *Client) UpdateIncident(ctx context.Context, id string, opts map[string]string) (*Incident, error) { +func (c *Client) UpdateIncident(ctx context.Context, id string, opts map[string]interface{}) (*Incident, error) { // Build JSON:API request body with only changed attributes attributes := make(map[string]interface{}) if title, ok := opts["title"]; ok { @@ -1165,6 +1171,12 @@ func (c *Client) UpdateIncident(ctx context.Context, id string, opts map[string] if status, ok := opts["status"]; ok { attributes["status"] = status } + if serviceIDs, ok := opts["service_ids"]; ok { + attributes["service_ids"] = serviceIDs + } + if incidentTypeIDs, ok := opts["incident_type_ids"]; ok { + attributes["incident_type_ids"] = incidentTypeIDs + } requestBody := map[string]interface{}{ "data": map[string]interface{}{ diff --git a/internal/api/client_http_test.go b/internal/api/client_http_test.go index b37153b..bde4c42 100644 --- a/internal/api/client_http_test.go +++ b/internal/api/client_http_test.go @@ -275,9 +275,11 @@ func TestCreateIncident(t *testing.T) { defer server.Close() client := newTestClient(t, server.URL) - inc, err := client.CreateIncident(context.Background(), "New Incident", map[string]string{ - "summary": "Test summary", - "status": "started", + inc, err := client.CreateIncident(context.Background(), "New Incident", map[string]interface{}{ + "summary": "Test summary", + "status": "started", + "service_ids": []string{"api-gateway", "payments"}, + "incident_type_ids": []string{"customer-impacting"}, }) if err != nil { t.Fatalf("CreateIncident returned error: %v", err) diff --git a/internal/api/client_mutations_test.go b/internal/api/client_mutations_test.go index 2d60751..aa4dbfb 100644 --- a/internal/api/client_mutations_test.go +++ b/internal/api/client_mutations_test.go @@ -43,9 +43,11 @@ func TestUpdateIncident(t *testing.T) { defer server.Close() client := newTestClient(t, server.URL) - inc, err := client.UpdateIncident(context.Background(), "inc-1", map[string]string{ - "title": "Updated Title", - "status": "mitigated", + inc, err := client.UpdateIncident(context.Background(), "inc-1", map[string]interface{}{ + "title": "Updated Title", + "status": "mitigated", + "service_ids": []string{"api-gateway", "payments"}, + "incident_type_ids": []string{"customer-impacting"}, }) if err != nil { t.Fatalf("UpdateIncident returned error: %v", err) @@ -70,6 +72,14 @@ func TestUpdateIncident(t *testing.T) { if attrs["status"] != "mitigated" { t.Errorf("request status = %q, want %q", attrs["status"], "mitigated") } + serviceIDs := attrs["service_ids"].([]interface{}) + if len(serviceIDs) != 2 || serviceIDs[0] != "api-gateway" || serviceIDs[1] != "payments" { + t.Errorf("request service_ids = %v, want [api-gateway payments]", serviceIDs) + } + incidentTypeIDs := attrs["incident_type_ids"].([]interface{}) + if len(incidentTypeIDs) != 1 || incidentTypeIDs[0] != "customer-impacting" { + t.Errorf("request incident_type_ids = %v, want [customer-impacting]", incidentTypeIDs) + } } func TestUpdateIncidentNotFound(t *testing.T) { @@ -79,7 +89,7 @@ func TestUpdateIncidentNotFound(t *testing.T) { defer server.Close() client := newTestClient(t, server.URL) - _, err := client.UpdateIncident(context.Background(), "nonexistent", map[string]string{"title": "x"}) + _, err := client.UpdateIncident(context.Background(), "nonexistent", map[string]interface{}{"title": "x"}) if err == nil { t.Fatal("expected error for 404") } @@ -95,7 +105,7 @@ func TestUpdateIncidentForbidden(t *testing.T) { defer server.Close() client := newTestClient(t, server.URL) - _, err := client.UpdateIncident(context.Background(), "inc-1", map[string]string{"title": "x"}) + _, err := client.UpdateIncident(context.Background(), "inc-1", map[string]interface{}{"title": "x"}) if err == nil { t.Fatal("expected error for 403") } diff --git a/internal/cmd/incidents/cmd_test.go b/internal/cmd/incidents/cmd_test.go index ea42d0e..08e86ea 100644 --- a/internal/cmd/incidents/cmd_test.go +++ b/internal/cmd/incidents/cmd_test.go @@ -287,6 +287,8 @@ func TestRunCreateTable(t *testing.T) { cmd.Flags().String("summary", "Test summary", "") cmd.Flags().String("severity", "", "") cmd.Flags().String("status", "started", "") + cmd.Flags().StringSlice("services", []string{"api-gateway", "payments"}, "") + cmd.Flags().StringSlice("types", []string{"customer-impacting"}, "") output := captureStdout(t, func() { err := runCreate(cmd, nil) @@ -315,6 +317,8 @@ func TestRunCreateJSON(t *testing.T) { cmd.Flags().String("summary", "", "") cmd.Flags().String("severity", "", "") cmd.Flags().String("status", "", "") + cmd.Flags().StringSlice("services", nil, "") + cmd.Flags().StringSlice("types", nil, "") output := captureStdout(t, func() { err := runCreate(cmd, nil) @@ -344,6 +348,8 @@ func TestRunUpdateTable(t *testing.T) { cmd.Flags().String("summary", "", "") cmd.Flags().String("severity", "", "") cmd.Flags().String("status", "", "") + cmd.Flags().StringSlice("services", nil, "") + cmd.Flags().StringSlice("types", nil, "") // Simulate the user passing --status=mitigated cmd.Flags().Set("status", "mitigated") @@ -370,6 +376,8 @@ func TestRunUpdateNoFlags(t *testing.T) { cmd.Flags().String("summary", "", "") cmd.Flags().String("severity", "", "") cmd.Flags().String("status", "", "") + cmd.Flags().StringSlice("services", nil, "") + cmd.Flags().StringSlice("types", nil, "") err := runUpdate(cmd, []string{"INC-42"}) if err == nil { diff --git a/internal/cmd/incidents/create.go b/internal/cmd/incidents/create.go index 896de9b..6a6be00 100644 --- a/internal/cmd/incidents/create.go +++ b/internal/cmd/incidents/create.go @@ -22,6 +22,8 @@ var createCmd = &cobra.Command{ --title="API degradation" \ --summary="Response times elevated above 2s p99" \ --severity=sev0 \ + --services=api-gateway,payments \ + --types=customer-impacting \ --status=started # Create and output as JSON @@ -34,6 +36,8 @@ func init() { createCmd.Flags().String("summary", "", "Incident summary/description") createCmd.Flags().String("severity", "", "Severity ID") createCmd.Flags().String("status", "", "Initial status (started, mitigated, resolved)") + createCmd.Flags().StringSlice("services", nil, "Service slugs/IDs, comma-separated") + createCmd.Flags().StringSlice("types", nil, "Incident type slugs/IDs, comma-separated") // Mark title as required _ = createCmd.MarkFlagRequired("title") @@ -54,9 +58,11 @@ func runCreate(cmd *cobra.Command, args []string) error { summary, _ := cmd.Flags().GetString("summary") severity, _ := cmd.Flags().GetString("severity") status, _ := cmd.Flags().GetString("status") + services, _ := cmd.Flags().GetStringSlice("services") + incidentTypes, _ := cmd.Flags().GetStringSlice("types") // Build opts map - only add keys where the flag was provided - opts := make(map[string]string) + opts := make(map[string]interface{}) if summary != "" { opts["summary"] = summary } @@ -66,6 +72,12 @@ func runCreate(cmd *cobra.Command, args []string) error { if status != "" { opts["status"] = status } + if len(services) > 0 { + opts["service_ids"] = services + } + if len(incidentTypes) > 0 { + opts["incident_type_ids"] = incidentTypes + } // Call API incident, err := apiClient.CreateIncident(cmd.Context(), title, opts) diff --git a/internal/cmd/incidents/update.go b/internal/cmd/incidents/update.go index 7b7d530..712872d 100644 --- a/internal/cmd/incidents/update.go +++ b/internal/cmd/incidents/update.go @@ -24,7 +24,12 @@ var updateCmd = &cobra.Command{ --summary="Root cause identified: connection pool exhaustion" # Update severity - rootly incidents update INC-123 --severity=sev1`, + rootly incidents update INC-123 --severity=sev1 + + # Update attached services and incident types + rootly incidents update INC-123 \ + --services=api-gateway,payments \ + --types=customer-impacting`, Args: cobra.ExactArgs(1), RunE: runUpdate, } @@ -34,6 +39,8 @@ func init() { updateCmd.Flags().String("summary", "", "Updated summary") updateCmd.Flags().String("severity", "", "Updated severity ID") updateCmd.Flags().String("status", "", "Updated status (started, mitigated, resolved, closed, cancelled)") + updateCmd.Flags().StringSlice("services", nil, "Updated service slugs/IDs, comma-separated") + updateCmd.Flags().StringSlice("types", nil, "Updated incident type slugs/IDs, comma-separated") // Register with parent command IncidentsCmd.AddCommand(updateCmd) @@ -50,7 +57,7 @@ func runUpdate(cmd *cobra.Command, args []string) error { } // Build opts map using cmd.Flags().Changed() - ONLY include fields the user explicitly set - opts := make(map[string]string) + opts := make(map[string]interface{}) if cmd.Flags().Changed("title") { title, _ := cmd.Flags().GetString("title") opts["title"] = title @@ -67,6 +74,14 @@ func runUpdate(cmd *cobra.Command, args []string) error { status, _ := cmd.Flags().GetString("status") opts["status"] = status } + if cmd.Flags().Changed("services") { + services, _ := cmd.Flags().GetStringSlice("services") + opts["service_ids"] = services + } + if cmd.Flags().Changed("types") { + incidentTypes, _ := cmd.Flags().GetStringSlice("types") + opts["incident_type_ids"] = incidentTypes + } // If opts is empty (no flags changed), return error if len(opts) == 0 { From 8c87dc52fd4a97a37642101692b2b9694e7d8ba1 Mon Sep 17 00:00:00 2001 From: Quentin Rousseau Date: Wed, 12 Aug 2026 20:35:31 -0700 Subject: [PATCH 2/3] add remaining incident association flags --- internal/api/client.go | 18 ++++++++---------- internal/api/client_http_test.go | 24 ++++++++++++++++++++++++ internal/api/client_mutations_test.go | 15 +++++++++++++++ internal/cmd/incidents/cmd_test.go | 16 ++++++++++++++++ internal/cmd/incidents/create.go | 23 +++++++++++++++++++++++ internal/cmd/incidents/update.go | 25 ++++++++++++++++++++++++- 6 files changed, 110 insertions(+), 11 deletions(-) diff --git a/internal/api/client.go b/internal/api/client.go index 2db7920..6c102cf 100644 --- a/internal/api/client.go +++ b/internal/api/client.go @@ -1097,11 +1097,10 @@ func (c *Client) CreateIncident(ctx context.Context, title string, opts map[stri if status, ok := opts["status"]; ok { attributes["status"] = status } - if serviceIDs, ok := opts["service_ids"]; ok { - attributes["service_ids"] = serviceIDs - } - if incidentTypeIDs, ok := opts["incident_type_ids"]; ok { - attributes["incident_type_ids"] = incidentTypeIDs + for _, key := range []string{"service_ids", "incident_type_ids", "functionality_ids", "environment_ids", "group_ids", "cause_ids"} { + if value, ok := opts[key]; ok { + attributes[key] = value + } } bodyBytes, err := json.Marshal(requestBody) @@ -1171,11 +1170,10 @@ func (c *Client) UpdateIncident(ctx context.Context, id string, opts map[string] if status, ok := opts["status"]; ok { attributes["status"] = status } - if serviceIDs, ok := opts["service_ids"]; ok { - attributes["service_ids"] = serviceIDs - } - if incidentTypeIDs, ok := opts["incident_type_ids"]; ok { - attributes["incident_type_ids"] = incidentTypeIDs + for _, key := range []string{"service_ids", "incident_type_ids", "functionality_ids", "environment_ids", "group_ids", "cause_ids"} { + if value, ok := opts[key]; ok { + attributes[key] = value + } } requestBody := map[string]interface{}{ diff --git a/internal/api/client_http_test.go b/internal/api/client_http_test.go index bde4c42..afae8c8 100644 --- a/internal/api/client_http_test.go +++ b/internal/api/client_http_test.go @@ -256,6 +256,26 @@ func TestCreateIncident(t *testing.T) { t.Errorf("expected POST, got %s", r.Method) } + var requestBody map[string]interface{} + if err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil { + t.Fatalf("failed to decode request body: %v", err) + } + data := requestBody["data"].(map[string]interface{}) + attrs := data["attributes"].(map[string]interface{}) + for key, want := range map[string]string{ + "service_ids": "api-gateway", + "incident_type_ids": "customer-impacting", + "functionality_ids": "checkout", + "environment_ids": "production", + "group_ids": "platform", + "cause_ids": "deployment", + } { + values := attrs[key].([]interface{}) + if len(values) == 0 || values[0] != want { + t.Errorf("request %s = %v, want first value %s", key, values, want) + } + } + w.Header().Set("Content-Type", "application/vnd.api+json") w.WriteHeader(http.StatusCreated) resp := map[string]interface{}{ @@ -280,6 +300,10 @@ func TestCreateIncident(t *testing.T) { "status": "started", "service_ids": []string{"api-gateway", "payments"}, "incident_type_ids": []string{"customer-impacting"}, + "functionality_ids": []string{"checkout"}, + "environment_ids": []string{"production"}, + "group_ids": []string{"platform"}, + "cause_ids": []string{"deployment"}, }) if err != nil { t.Fatalf("CreateIncident returned error: %v", err) diff --git a/internal/api/client_mutations_test.go b/internal/api/client_mutations_test.go index aa4dbfb..b6011d9 100644 --- a/internal/api/client_mutations_test.go +++ b/internal/api/client_mutations_test.go @@ -48,6 +48,10 @@ func TestUpdateIncident(t *testing.T) { "status": "mitigated", "service_ids": []string{"api-gateway", "payments"}, "incident_type_ids": []string{"customer-impacting"}, + "functionality_ids": []string{"checkout"}, + "environment_ids": []string{"production"}, + "group_ids": []string{"platform"}, + "cause_ids": []string{"deployment"}, }) if err != nil { t.Fatalf("UpdateIncident returned error: %v", err) @@ -80,6 +84,17 @@ func TestUpdateIncident(t *testing.T) { if len(incidentTypeIDs) != 1 || incidentTypeIDs[0] != "customer-impacting" { t.Errorf("request incident_type_ids = %v, want [customer-impacting]", incidentTypeIDs) } + for key, want := range map[string]string{ + "functionality_ids": "checkout", + "environment_ids": "production", + "group_ids": "platform", + "cause_ids": "deployment", + } { + values := attrs[key].([]interface{}) + if len(values) != 1 || values[0] != want { + t.Errorf("request %s = %v, want [%s]", key, values, want) + } + } } func TestUpdateIncidentNotFound(t *testing.T) { diff --git a/internal/cmd/incidents/cmd_test.go b/internal/cmd/incidents/cmd_test.go index 08e86ea..3f9a12e 100644 --- a/internal/cmd/incidents/cmd_test.go +++ b/internal/cmd/incidents/cmd_test.go @@ -289,6 +289,10 @@ func TestRunCreateTable(t *testing.T) { cmd.Flags().String("status", "started", "") cmd.Flags().StringSlice("services", []string{"api-gateway", "payments"}, "") cmd.Flags().StringSlice("types", []string{"customer-impacting"}, "") + cmd.Flags().StringSlice("functionalities", []string{"checkout"}, "") + cmd.Flags().StringSlice("environments", []string{"production"}, "") + cmd.Flags().StringSlice("teams", []string{"platform"}, "") + cmd.Flags().StringSlice("causes", []string{"deployment"}, "") output := captureStdout(t, func() { err := runCreate(cmd, nil) @@ -319,6 +323,10 @@ func TestRunCreateJSON(t *testing.T) { cmd.Flags().String("status", "", "") cmd.Flags().StringSlice("services", nil, "") cmd.Flags().StringSlice("types", nil, "") + cmd.Flags().StringSlice("functionalities", nil, "") + cmd.Flags().StringSlice("environments", nil, "") + cmd.Flags().StringSlice("teams", nil, "") + cmd.Flags().StringSlice("causes", nil, "") output := captureStdout(t, func() { err := runCreate(cmd, nil) @@ -350,6 +358,10 @@ func TestRunUpdateTable(t *testing.T) { cmd.Flags().String("status", "", "") cmd.Flags().StringSlice("services", nil, "") cmd.Flags().StringSlice("types", nil, "") + cmd.Flags().StringSlice("functionalities", nil, "") + cmd.Flags().StringSlice("environments", nil, "") + cmd.Flags().StringSlice("teams", nil, "") + cmd.Flags().StringSlice("causes", nil, "") // Simulate the user passing --status=mitigated cmd.Flags().Set("status", "mitigated") @@ -378,6 +390,10 @@ func TestRunUpdateNoFlags(t *testing.T) { cmd.Flags().String("status", "", "") cmd.Flags().StringSlice("services", nil, "") cmd.Flags().StringSlice("types", nil, "") + cmd.Flags().StringSlice("functionalities", nil, "") + cmd.Flags().StringSlice("environments", nil, "") + cmd.Flags().StringSlice("teams", nil, "") + cmd.Flags().StringSlice("causes", nil, "") err := runUpdate(cmd, []string{"INC-42"}) if err == nil { diff --git a/internal/cmd/incidents/create.go b/internal/cmd/incidents/create.go index 6a6be00..4251548 100644 --- a/internal/cmd/incidents/create.go +++ b/internal/cmd/incidents/create.go @@ -24,6 +24,9 @@ var createCmd = &cobra.Command{ --severity=sev0 \ --services=api-gateway,payments \ --types=customer-impacting \ + --functionalities=checkout \ + --environments=production \ + --teams=platform \ --status=started # Create and output as JSON @@ -38,6 +41,10 @@ func init() { createCmd.Flags().String("status", "", "Initial status (started, mitigated, resolved)") createCmd.Flags().StringSlice("services", nil, "Service slugs/IDs, comma-separated") createCmd.Flags().StringSlice("types", nil, "Incident type slugs/IDs, comma-separated") + createCmd.Flags().StringSlice("functionalities", nil, "Functionality slugs/IDs, comma-separated") + createCmd.Flags().StringSlice("environments", nil, "Environment slugs/IDs, comma-separated") + createCmd.Flags().StringSlice("teams", nil, "Team slugs/IDs, comma-separated") + createCmd.Flags().StringSlice("causes", nil, "Cause slugs/IDs, comma-separated") // Mark title as required _ = createCmd.MarkFlagRequired("title") @@ -60,6 +67,10 @@ func runCreate(cmd *cobra.Command, args []string) error { status, _ := cmd.Flags().GetString("status") services, _ := cmd.Flags().GetStringSlice("services") incidentTypes, _ := cmd.Flags().GetStringSlice("types") + functionalities, _ := cmd.Flags().GetStringSlice("functionalities") + environments, _ := cmd.Flags().GetStringSlice("environments") + teams, _ := cmd.Flags().GetStringSlice("teams") + causes, _ := cmd.Flags().GetStringSlice("causes") // Build opts map - only add keys where the flag was provided opts := make(map[string]interface{}) @@ -78,6 +89,18 @@ func runCreate(cmd *cobra.Command, args []string) error { if len(incidentTypes) > 0 { opts["incident_type_ids"] = incidentTypes } + if len(functionalities) > 0 { + opts["functionality_ids"] = functionalities + } + if len(environments) > 0 { + opts["environment_ids"] = environments + } + if len(teams) > 0 { + opts["group_ids"] = teams + } + if len(causes) > 0 { + opts["cause_ids"] = causes + } // Call API incident, err := apiClient.CreateIncident(cmd.Context(), title, opts) diff --git a/internal/cmd/incidents/update.go b/internal/cmd/incidents/update.go index 712872d..1c73cd9 100644 --- a/internal/cmd/incidents/update.go +++ b/internal/cmd/incidents/update.go @@ -29,7 +29,10 @@ var updateCmd = &cobra.Command{ # Update attached services and incident types rootly incidents update INC-123 \ --services=api-gateway,payments \ - --types=customer-impacting`, + --types=customer-impacting \ + --functionalities=checkout \ + --environments=production \ + --teams=platform`, Args: cobra.ExactArgs(1), RunE: runUpdate, } @@ -41,6 +44,10 @@ func init() { updateCmd.Flags().String("status", "", "Updated status (started, mitigated, resolved, closed, cancelled)") updateCmd.Flags().StringSlice("services", nil, "Updated service slugs/IDs, comma-separated") updateCmd.Flags().StringSlice("types", nil, "Updated incident type slugs/IDs, comma-separated") + updateCmd.Flags().StringSlice("functionalities", nil, "Updated functionality slugs/IDs, comma-separated") + updateCmd.Flags().StringSlice("environments", nil, "Updated environment slugs/IDs, comma-separated") + updateCmd.Flags().StringSlice("teams", nil, "Updated team slugs/IDs, comma-separated") + updateCmd.Flags().StringSlice("causes", nil, "Updated cause slugs/IDs, comma-separated") // Register with parent command IncidentsCmd.AddCommand(updateCmd) @@ -82,6 +89,22 @@ func runUpdate(cmd *cobra.Command, args []string) error { incidentTypes, _ := cmd.Flags().GetStringSlice("types") opts["incident_type_ids"] = incidentTypes } + if cmd.Flags().Changed("functionalities") { + functionalities, _ := cmd.Flags().GetStringSlice("functionalities") + opts["functionality_ids"] = functionalities + } + if cmd.Flags().Changed("environments") { + environments, _ := cmd.Flags().GetStringSlice("environments") + opts["environment_ids"] = environments + } + if cmd.Flags().Changed("teams") { + teams, _ := cmd.Flags().GetStringSlice("teams") + opts["group_ids"] = teams + } + if cmd.Flags().Changed("causes") { + causes, _ := cmd.Flags().GetStringSlice("causes") + opts["cause_ids"] = causes + } // If opts is empty (no flags changed), return error if len(opts) == 0 { From d635df6186b0eaf32743763a2889c9e005ed188d Mon Sep 17 00:00:00 2001 From: Quentin Rousseau Date: Wed, 12 Aug 2026 20:45:08 -0700 Subject: [PATCH 3/3] test clearing incident associations --- internal/cmd/incidents/cmd_test.go | 43 ++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/internal/cmd/incidents/cmd_test.go b/internal/cmd/incidents/cmd_test.go index 3f9a12e..876c716 100644 --- a/internal/cmd/incidents/cmd_test.go +++ b/internal/cmd/incidents/cmd_test.go @@ -2,6 +2,7 @@ package incidents import ( "context" + "encoding/json" "net/http" "net/http/httptest" "os" @@ -404,6 +405,48 @@ func TestRunUpdateNoFlags(t *testing.T) { } } +func TestRunUpdateCanClearAssociations(t *testing.T) { + var attributes map[string]interface{} + setupTestServer(t, func(w http.ResponseWriter, r *http.Request) { + var requestBody map[string]interface{} + if err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil { + t.Fatalf("failed to decode request body: %v", err) + } + attributes = requestBody["data"].(map[string]interface{})["attributes"].(map[string]interface{}) + w.Header().Set("Content-Type", "application/vnd.api+json") + _, _ = w.Write([]byte(getResponse())) + }) + viper.Set("format", "table") + + cmd := newTestCmd() + cmd.Flags().String("title", "", "") + cmd.Flags().String("summary", "", "") + cmd.Flags().String("severity", "", "") + cmd.Flags().String("status", "", "") + cmd.Flags().StringSlice("services", nil, "") + cmd.Flags().StringSlice("types", nil, "") + cmd.Flags().StringSlice("functionalities", nil, "") + cmd.Flags().StringSlice("environments", nil, "") + cmd.Flags().StringSlice("teams", nil, "") + cmd.Flags().StringSlice("causes", nil, "") + if err := cmd.Flags().Set("services", ""); err != nil { + t.Fatalf("failed to set empty services: %v", err) + } + + captureStdout(t, func() { + if err := runUpdate(cmd, []string{"INC-42"}); err != nil { + t.Fatalf("runUpdate returned error: %v", err) + } + }) + services, ok := attributes["service_ids"].([]interface{}) + if !ok || len(services) != 0 { + t.Errorf("service_ids = %#v, want an explicitly empty array", attributes["service_ids"]) + } + if _, ok := attributes["incident_type_ids"]; ok { + t.Error("incident_type_ids should be absent when --types is omitted") + } +} + func TestRunListNoToken(t *testing.T) { viper.Reset() defer viper.Reset()