Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.
Merged
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
107 changes: 104 additions & 3 deletions cmd/cli/deployment_create.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package main

import (
"fmt"
"strconv"
"strings"

"github.com/urfave/cli/v2"

"github.com/gitploy-io/gitploy/model/extent"
"github.com/gitploy-io/gitploy/pkg/api"
)

Expand All @@ -26,6 +31,11 @@ var deploymentCreateCommand = &cli.Command{
Usage: "The specific ref. It can be any named branch, tag, or SHA.",
Required: true,
},
&cli.StringSliceFlag{
Name: "field",
Aliases: []string{"f"},
Usage: "The pair of key and value to add to the payload. The format must be <key>=<value>.",
},
Comment on lines +34 to +38
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ex. -f foo=bar -f baz=quz

},
Action: func(cli *cli.Context) error {
ns, n, err := splitFullName(cli.Args().First())
Expand All @@ -34,10 +44,26 @@ var deploymentCreateCommand = &cli.Command{
}

c := buildClient(cli)

config, err := c.Config.Get(cli.Context, ns, n)
if err != nil {
return err
}

// If the 'dynamic_payload' field is enabled,
// it creates a payload and pass it as a parameter.
var payload map[string]interface{}
if env := config.GetEnv(cli.String("env")); env.IsDynamicPayloadEnabled() {
if payload, err = buildDyanmicPayload(cli.StringSlice("field"), env); err != nil {
return err
}
}

d, err := c.Deployment.Create(cli.Context, ns, n, &api.DeploymentCreateRequest{
Type: cli.String("type"),
Ref: cli.String("ref"),
Env: cli.String("env"),
Type: cli.String("type"),
Ref: cli.String("ref"),
Env: cli.String("env"),
DynamicPayload: payload,
})
if err != nil {
return err
Expand All @@ -46,3 +72,78 @@ var deploymentCreateCommand = &cli.Command{
return printJson(cli, d)
},
}

func buildDyanmicPayload(fields []string, env *extent.Env) (map[string]interface{}, error) {
values := make(map[string]string)

for _, f := range fields {
keyAndValue := strings.SplitN(f, "=", 2)
if len(keyAndValue) != 2 {
return nil, fmt.Errorf("The field must be <key>=<value> format")
}

values[keyAndValue[0]] = keyAndValue[1]
}

payload := make(map[string]interface{})

// Build the payload, and use the default value if there is no value.
for key, input := range env.DynamicPayload.Inputs {
val, ok := values[key]
// Set the default value if the value doesn't exist.
if !ok {
if input.Default != nil {
payload[key] = *input.Default
}

continue
}

parsed, err := parseValue(input, val)
if err != nil {
return nil, fmt.Errorf("The value of the '%s' field is not %s", key, input.Type)
}

payload[key] = parsed
}

// Check that the required values are present.
for key, input := range env.DynamicPayload.Inputs {
if !(input.Required != nil && *input.Required) {
continue
}

if _, ok := payload[key]; !ok {
return nil, fmt.Errorf("The value of the '%s' field is required", key)
}
}

return payload, nil
}

func parseValue(input extent.Input, s string) (interface{}, error) {
switch input.Type {
case extent.InputTypeSelect:
return s, nil

case extent.InputTypeString:
return s, nil

case extent.InputTypeNumber:
if val, err := strconv.ParseFloat(s, 64); err != nil {
return nil, err
} else {
return val, nil
}

case extent.InputTypeBoolean:
if val, err := strconv.ParseBool(s); err != nil {
return nil, err
} else {
return val, nil
}

default:
return nil, fmt.Errorf("%s is unsupported type.", input.Type)
}
}
53 changes: 53 additions & 0 deletions cmd/cli/deployment_create_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package main

import (
"reflect"
"testing"

"github.com/gitploy-io/gitploy/model/extent"
)

func Test_buildDyanmicPayload(t *testing.T) {
t.Run("Return an error when syntax is invalid.", func(t *testing.T) {
_, err := buildDyanmicPayload([]string{
"foo",
}, &extent.Env{
DynamicPayload: &extent.DynamicPayload{
Enabled: true,
},
})

if err == nil {
t.Fatalf("buildDyanmicPayload dosen't return an error")
}
})

t.Run("Return a payload with default values.", func(t *testing.T) {
var qux interface{} = "qux"

payload, err := buildDyanmicPayload([]string{}, &extent.Env{
DynamicPayload: &extent.DynamicPayload{
Enabled: true,
Inputs: map[string]extent.Input{
"foo": {
Type: extent.InputTypeString,
},
"baz": {
Type: extent.InputTypeString,
Default: &qux,
},
},
},
})

if err != nil {
t.Fatalf("buildDyanmicPayload returns an error")
}

if expected := map[string]interface{}{
"baz": "qux",
}; !reflect.DeepEqual(payload, expected) {
t.Fatalf("buildDyanmicPayload = %v, wanted %v", payload, expected)
}
})
}
7 changes: 4 additions & 3 deletions pkg/api/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ type (
}

DeploymentCreateRequest struct {
Type string `json:"type"`
Ref string `json:"ref"`
Env string `json:"env"`
Type string `json:"type"`
Ref string `json:"ref"`
Env string `json:"env"`
DynamicPayload map[string]interface{} `json:"dynamic_payload"`
}
)

Expand Down
11 changes: 10 additions & 1 deletion pkg/api/deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"io/ioutil"
"net/http"
"reflect"
"testing"

"github.com/gitploy-io/gitploy/model/ent"
Expand Down Expand Up @@ -61,7 +62,12 @@ func TestDeploymentService_Create(t *testing.T) {
}

// Verify the fields of the body.
return b.Type == "branch" && b.Env == "production" && b.Ref == "main", nil
return b.Type == "branch" &&
b.Env == "production" &&
b.Ref == "main" &&
reflect.DeepEqual(b.DynamicPayload, map[string]interface{}{
"foo": "bar",
}), nil
}).
Reply(201).
JSON(d)
Expand All @@ -72,6 +78,9 @@ func TestDeploymentService_Create(t *testing.T) {
Type: "branch",
Env: "production",
Ref: "main",
DynamicPayload: map[string]interface{}{
"foo": "bar",
},
})
if err != nil {
t.Fatalf("Create returns an error: %s", err)
Expand Down