Skip to content
This repository has been archived by the owner on Jul 4, 2024. It is now read-only.

Commit

Permalink
feat: added --delta flag to delta command to update or merge generate…
Browse files Browse the repository at this point in the history
…d deltas (#38)
  • Loading branch information
astromechza authored Apr 5, 2023
2 parents f084be7 + 437c6e7 commit 26be9e0
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 8 deletions.
2 changes: 2 additions & 0 deletions internal/command/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ var (
appID string
envID string

// deltaID is a cli flag receiver used to support "score-humanitec delta --use foo"
deltaID string
deploy bool
retry bool
verbose bool
Expand Down
27 changes: 19 additions & 8 deletions internal/command/delta.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ The Apache Software Foundation (http://www.apache.org/).
package command

import (
"context"
"encoding/json"
"fmt"
"io"
Expand All @@ -28,6 +27,8 @@ func init() {
deltaCmd.Flags().StringVar(&extensionsFile, "extensions", extensionsFileDefault, "Extensions file")
deltaCmd.Flags().StringVar(&uiUrl, "ui-url", uiUrlDefault, "Humanitec UI")
deltaCmd.Flags().StringVar(&apiUrl, "api-url", apiUrlDefault, "Humanitec API endpoint")
deltaCmd.Flags().StringVar(&deltaID, "delta", "", "The ID of an existing delta in Humanitec into which to merge the generated delta")

deltaCmd.Flags().StringVar(&apiToken, "token", "", "Humanitec API authentication token")
deltaCmd.MarkFlagRequired("token")
deltaCmd.Flags().StringVar(&orgID, "org", "", "Organization ID")
Expand All @@ -46,8 +47,12 @@ func init() {

var deltaCmd = &cobra.Command{
Use: "delta",
Short: "Creates Humanitec deployment delta from the source SCORE file",
RunE: delta,
Short: "Creates or updates a Humanitec deployment delta from the source SCORE file",
Long: `This command will translate the SCORE file into a Humanitec deployment delta and submit it to the Humanitec
environment specified by the --org, --app, and --env flags. If the --delta flag is provided, the generated delta will
be merged with the specified existing delta. The --deploy flag allows the deployment of the delta to be triggered.
`,
RunE: delta,
}

func delta(cmd *cobra.Command, args []string) error {
Expand All @@ -70,14 +75,20 @@ func delta(cmd *cobra.Command, args []string) error {
return fmt.Errorf("preparing new deployment: %w", err)
}

// Create a new deployment delta
//
log.Print("Creating a new deployment delta...\n")
client, err := api.NewClient(apiUrl, apiToken, http.DefaultClient)
if err != nil {
return err
}
res, err := client.CreateDelta(context.Background(), orgID, appID, delta)

var res *ht.DeploymentDelta
if deltaID == "" {
log.Print("Creating a new deployment delta...\n")
res, err = client.CreateDelta(cmd.Context(), orgID, appID, delta)
} else {
log.Printf("Updating existing delta %s in place...\n", deltaID)
updates := []*ht.UpdateDeploymentDeltaRequest{{Modules: delta.Modules, Shared: delta.Shared}}
res, err = client.UpdateDelta(cmd.Context(), orgID, appID, deltaID, updates)
}
if err != nil {
return err
}
Expand All @@ -95,7 +106,7 @@ func delta(cmd *cobra.Command, args []string) error {
//
if deploy {
log.Printf("Starting a new deployment for delta '%s'...\n", res.ID)
_, err := client.StartDeployment(context.Background(), orgID, appID, envID, retry, &ht.StartDeploymentRequest{
_, err := client.StartDeployment(cmd.Context(), orgID, appID, envID, retry, &ht.StartDeploymentRequest{
DeltaID: res.ID,
Comment: "Auto-deployment (SCORE)",
})
Expand Down
39 changes: 39 additions & 0 deletions internal/humanitec_go/client/deltas.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,42 @@ func (api *apiClient) CreateDelta(ctx context.Context, orgID, appID string, delt
return nil, fmt.Errorf("humanitec api: %s %s: HTTP %d - %s", req.Method, req.BaseURL, resp.StatusCode, http.StatusText(resp.StatusCode))
}
}

// UpdateDelta updates an existing Deployment Delta for the orgID and appID with the given deltaID.
// The Deltas in the request will be combined and applied on top of existing Delta to produce a merged result.
func (api *apiClient) UpdateDelta(ctx context.Context, orgID string, appID string, deltaID string, deltas []*humanitec.UpdateDeploymentDeltaRequest) (*humanitec.DeploymentDelta, error) {
data, err := json.Marshal(deltas)
if err != nil {
return nil, fmt.Errorf("marshalling payload into JSON: %w", err)
}

apiPath := fmt.Sprintf("/orgs/%s/apps/%s/deltas/%s", orgID, appID, deltaID)
req := rest.Request{
Method: http.MethodPatch,
BaseURL: api.baseUrl + apiPath,
Headers: map[string]string{
"Authorization": "Bearer " + api.token,
"Content-Type": "application/json",
"Accept": "application/json",
},
Body: data,
}

resp, err := api.client.SendWithContext(ctx, req)
if err != nil {
return nil, fmt.Errorf("humanitec api: %s %s: %w", req.Method, req.BaseURL, err)
}

switch resp.StatusCode {
case http.StatusOK:
{
var res humanitec.DeploymentDelta
if err = json.Unmarshal([]byte(resp.Body), &res); err != nil {
return nil, fmt.Errorf("humanitec api: %s %s: parsing response: %w", req.Method, req.BaseURL, err)
}
return &res, nil
}
default:
return nil, fmt.Errorf("humanitec api: %s %s: HTTP %d - %s", req.Method, req.BaseURL, resp.StatusCode, http.StatusText(resp.StatusCode))
}
}
67 changes: 67 additions & 0 deletions internal/humanitec_go/client/deltas_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,70 @@ func TestCreateDelta(t *testing.T) {
})
}
}

func TestUpdateDelta_success(t *testing.T) {
const (
orgID = "test_org"
appID = "test-app"
deltaID = "0123456789abcdef0123456789abcdef"
apiToken = "qwe...rty"
)

fakeServer := httptest.NewServer(
http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPatch && r.URL.Path == fmt.Sprintf("/orgs/%s/apps/%s/deltas/%s", orgID, appID, deltaID) {
assert.Equal(t, []string{"Bearer " + apiToken}, r.Header["Authorization"])
assert.Equal(t, []string{"application/json"}, r.Header["Accept"])
assert.Equal(t, []string{"application/json"}, r.Header["Content-Type"])
var body []*humanitec.UpdateDeploymentDeltaRequest
var dec = json.NewDecoder(r.Body)
assert.NoError(t, dec.Decode(&body))
assert.NotNil(t, &body)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
assert.NoError(t, json.NewEncoder(w).Encode(&humanitec.DeploymentDelta{
ID: deltaID,
}))
} else {
w.WriteHeader(http.StatusInternalServerError)
}
},
),
)
defer fakeServer.Close()

client, err := NewClient(fakeServer.URL, apiToken, fakeServer.Client())
assert.NoError(t, err)
res, err := client.UpdateDelta(testutil.TestContext(), orgID, appID, deltaID, []*humanitec.UpdateDeploymentDeltaRequest{
{Modules: humanitec.ModuleDeltas{}},
})
assert.NoError(t, err)
assert.NotNil(t, res)
}

func TestUpdateDelta_fail(t *testing.T) {
const (
orgID = "test_org"
appID = "test-app"
deltaID = "0123456789abcdef0123456789abcdef"
apiToken = "qwe...rty"
)

fakeServer := httptest.NewServer(
http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
},
),
)
defer fakeServer.Close()

client, err := NewClient(fakeServer.URL, apiToken, fakeServer.Client())
assert.NoError(t, err)
res, err := client.UpdateDelta(testutil.TestContext(), orgID, appID, deltaID, []*humanitec.UpdateDeploymentDeltaRequest{
{Modules: humanitec.ModuleDeltas{}},
})
assert.Nil(t, res)
assert.ErrorContains(t, err, ": HTTP 404 - Not Found")
}
1 change: 1 addition & 0 deletions internal/humanitec_go/client/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Client interface {
// Deployment Deltas
//
CreateDelta(ctx context.Context, orgID, appID string, delta *humanitec.CreateDeploymentDeltaRequest) (*humanitec.DeploymentDelta, error)
UpdateDelta(ctx context.Context, orgID string, appID string, deltaID string, deltas []*humanitec.UpdateDeploymentDeltaRequest) (*humanitec.DeploymentDelta, error)

// Deployments
//
Expand Down
5 changes: 5 additions & 0 deletions internal/humanitec_go/types/deltas.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ type CreateDeploymentDeltaRequest struct {
Shared []UpdateAction `json:"shared,omitempty"`
}

type UpdateDeploymentDeltaRequest struct {
Modules ModuleDeltas `json:"modules,omitempty"`
Shared []UpdateAction `json:"shared,omitempty"`
}

type DeploymentDelta struct {
ID string `json:"id"`

Expand Down

0 comments on commit 26be9e0

Please sign in to comment.