Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 22 additions & 48 deletions cmd/deploy_destination.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package cmd

import (
"context"
"errors"
"reflect"

"github.com/amp-labs/cli/flags"
"github.com/amp-labs/cli/logger"
Expand All @@ -14,10 +12,9 @@ import (
)

var deployDestinationCmd = &cobra.Command{ //nolint:gochecknoglobals
Use: "deploy:destination -i <input file path> [-o <output file path>] [-f <format>]",
Short: "Deploy a destination",
Long: "Deploy a destination",
Hidden: true,
Use: "deploy:destination -i <input file path> [-o <output file path>] [-f <format>]",
Short: "Deploy a destination",
Long: "Create or update a destination from a JSON or YAML file.",
Run: func(cmd *cobra.Command, args []string) {
projectId := flags.GetProjectOrFail()
apiKey := flags.GetAPIKey()
Expand All @@ -37,6 +34,11 @@ var deployDestinationCmd = &cobra.Command{ //nolint:gochecknoglobals
client := request.NewAPIClient(projectId, &apiKey)
oldDest := getOldDest(cmd.Context(), client, &dest)

format, err := cmd.Flags().GetString("format")
if err != nil {
logger.FatalErr("Unable to read output format", err)
}

var output *request.Destination

if oldDest == nil {
Expand All @@ -45,7 +47,7 @@ var deployDestinationCmd = &cobra.Command{ //nolint:gochecknoglobals
patch := generatePatch(oldDest, &dest)
if len(patch.UpdateMask) == 0 {
err := utils.WriteStructToFile(viper.GetString("output"),
flags.GetOutputFormat(), oldDest)
utils.Format(format), oldDest)
if err != nil {
logger.FatalErr("Unable to write destination file", err)
}
Expand All @@ -61,7 +63,7 @@ var deployDestinationCmd = &cobra.Command{ //nolint:gochecknoglobals
}

err = utils.WriteStructToFile(viper.GetString("output"),
flags.GetOutputFormat(), output)
utils.Format(format), output)
if err != nil {
logger.FatalErr("Unable to write destination file", err)
}
Expand All @@ -83,59 +85,31 @@ func generatePatch(oldDest *request.Destination, newDest *request.Destination) *
patch.UpdateMask = append(patch.UpdateMask, "type")
}

if oldDest.Metadata != nil { //nolint:nestif
if newDest.Metadata == nil {
patch.Destination["metadata"] = nil
patch.UpdateMask = append(patch.UpdateMask, "metadata")
} else if !reflect.DeepEqual(oldDest.Metadata, newDest.Metadata) {
patch.Destination["metadata"] = newDest.Metadata
patch.UpdateMask = append(patch.UpdateMask, "metadata")
}
} else {
if newDest.Metadata != nil {
patch.Destination["metadata"] = newDest.Metadata
patch.UpdateMask = append(patch.UpdateMask, "metadata")
}
if newDest.Metadata != nil && (oldDest.Metadata == nil || oldDest.Metadata.URL != newDest.Metadata.URL) {
patch.Destination["metadata"] = map[string]any{"url": newDest.Metadata.URL}
patch.UpdateMask = append(patch.UpdateMask, "metadata.url")
}

return patch
}

func getOldDest(ctx context.Context, client *request.APIClient, dest *request.Destination) *request.Destination {
id := findDestId(ctx, client, dest)
if id == "" {
return nil
}

dst, err := client.GetDestination(ctx, id)
if err != nil {
if errors.Is(err, request.ErrNotFound) {
return nil
} else {
logger.FatalErr("Unable to get destination", err)
}
}

return dst
}

func findDestId(ctx context.Context, client *request.APIClient, dest *request.Destination) string {
if dest.Id != "" {
return dest.Id
}

dests, err := client.ListDestinations(ctx)
destinations, err := client.ListDestinations(ctx)
if err != nil {
logger.FatalErr("Unable to list destinations", err)
}

for _, d := range dests {
if d.Name == dest.Name {
return d.Id
for _, existing := range destinations {
if dest.Id != "" && existing.Id == dest.Id {
return existing
}

if dest.Id == "" && existing.Name == dest.Name {
return existing
}
}

return ""
return nil
}

func init() {
Expand Down
69 changes: 69 additions & 0 deletions cmd/deploy_destination_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package cmd

import (
"net/http"
"net/http/httptest"
"reflect"
"testing"

"github.com/amp-labs/cli/request"
)

func TestGeneratePatchUpdatesOnlyDestinationURL(t *testing.T) {
t.Parallel()

oldDestination := &request.Destination{
Metadata: &request.WebhookMetadata{
URL: "https://old.example.com/webhook",
Headers: map[string]string{"Authorization": "secret"},
SvixAppId: "svix-app-id",
SvixEndpointId: "svix-endpoint-id",
},
}
newDestination := &request.Destination{
Metadata: &request.WebhookMetadata{URL: "https://new.example.com/webhook"},
}

patch := generatePatch(oldDestination, newDestination)

wantDestination := map[string]any{
"metadata": map[string]any{"url": "https://new.example.com/webhook"},
}
if !reflect.DeepEqual(patch.Destination, wantDestination) {
t.Fatalf("patch destination = %#v, want %#v", patch.Destination, wantDestination)
}

wantUpdateMask := []string{"metadata.url"}
if !reflect.DeepEqual(patch.UpdateMask, wantUpdateMask) {
t.Fatalf("patch update mask = %#v, want %#v", patch.UpdateMask, wantUpdateMask)
}
}

func TestGetOldDestFindsExistingDestinationByName(t *testing.T) {
t.Parallel()

server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, req *http.Request) {
if req.Method != http.MethodGet || req.URL.Path != "/v1/projects/test-project/destinations" {
http.NotFound(writer, req)

return
}

writer.Header().Set("Content-Type", "application/json")
_, _ = writer.Write([]byte(`[{"id":"destination-id","name":"local-webhook","type":"webhook"}]`))
}))
t.Cleanup(server.Close)

apiKey := "test-key"
client := &request.APIClient{
Root: server.URL + "/v1",
ProjectId: "test-project",
APIKey: &apiKey,
Client: request.NewRequestClient(),
}

destination := getOldDest(t.Context(), client, &request.Destination{Name: "local-webhook"})
if destination == nil || destination.Id != "destination-id" {
t.Fatalf("getOldDest() = %#v, want existing destination", destination)
}
}
Loading