Skip to content

Commit

Permalink
fix: toggle flag aliases (#269)
Browse files Browse the repository at this point in the history
Add flags toggle-on/toggle-off commands
  • Loading branch information
dbolson authored May 10, 2024
1 parent 468b41e commit 76de2a5
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 3 deletions.
104 changes: 104 additions & 0 deletions cmd/flags/toggle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package flags

import (
"fmt"

"github.com/spf13/cobra"
"github.com/spf13/viper"

"ldcli/cmd/cliflags"
resourcescmd "ldcli/cmd/resources"
"ldcli/cmd/validators"
"ldcli/internal/errors"
"ldcli/internal/output"
"ldcli/internal/resources"
)

func NewToggleOnCmd(client resources.Client) *cobra.Command {
cmd := &cobra.Command{
Args: validators.Validate(),
Long: "Turn a feature flag on",
RunE: runE(client),
Short: "Turn a feature flag on",
Use: "toggle-on",
}

cmd.SetUsageTemplate(resourcescmd.OperationUsageTemplate())
initFlags(cmd)

return cmd
}

func NewToggleOffCmd(client resources.Client) *cobra.Command {
cmd := &cobra.Command{
Args: validators.Validate(),
Long: "Turn a feature flag off",
RunE: runE(client),
Short: "Turn a feature flag off",
Use: "toggle-off",
}

initFlags(cmd)

return cmd
}

func runE(client resources.Client) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {
var toggleOn bool
switch cmd.CalledAs() {
case "toggle-on":
toggleOn = true
case "toggle-off":
toggleOn = false
}

path := fmt.Sprintf(
"%s/api/v2/flags/%s/%s",
viper.GetString(cliflags.BaseURIFlag),
viper.GetString(cliflags.ProjectFlag),
viper.GetString(cliflags.FlagFlag),
)
res, err := client.MakeRequest(
viper.GetString(cliflags.AccessTokenFlag),
"PATCH",
path,
"application/json",
nil,
[]byte(buildPatch(viper.GetString("environment"), toggleOn)),
)
if err != nil {
return errors.NewError(output.CmdOutputError(viper.GetString(cliflags.OutputFlag), err))
}

output, err := output.CmdOutput("update", viper.GetString(cliflags.OutputFlag), res)
if err != nil {
return errors.NewError(err.Error())
}

fmt.Fprintf(cmd.OutOrStdout(), output+"\n")

return nil
}
}

func initFlags(cmd *cobra.Command) {
cmd.Flags().String(cliflags.EnvironmentFlag, "", "The environment key")
_ = cmd.MarkFlagRequired(cliflags.EnvironmentFlag)
_ = cmd.Flags().SetAnnotation(cliflags.EnvironmentFlag, "required", []string{"true"})
_ = viper.BindPFlag(cliflags.EnvironmentFlag, cmd.Flags().Lookup(cliflags.EnvironmentFlag))

cmd.Flags().String(cliflags.FlagFlag, "", "The feature flag key")
_ = cmd.MarkFlagRequired(cliflags.FlagFlag)
_ = cmd.Flags().SetAnnotation(cliflags.FlagFlag, "required", []string{"true"})
_ = viper.BindPFlag(cliflags.FlagFlag, cmd.Flags().Lookup(cliflags.FlagFlag))

cmd.Flags().String(cliflags.ProjectFlag, "", "The project key")
_ = cmd.MarkFlagRequired(cliflags.ProjectFlag)
_ = cmd.Flags().SetAnnotation(cliflags.ProjectFlag, "required", []string{"true"})
_ = viper.BindPFlag(cliflags.ProjectFlag, cmd.Flags().Lookup(cliflags.ProjectFlag))
}

func buildPatch(envKey string, toggleValue bool) string {
return fmt.Sprintf(`[{"op": "replace", "path": "/environments/%s/on", "value": %t}]`, envKey, toggleValue)
}
40 changes: 40 additions & 0 deletions cmd/flags/toggle_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package flags_test

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"ldcli/cmd"
"ldcli/internal/analytics"
"ldcli/internal/resources"
)

func TestToggleOn(t *testing.T) {
mockClient := &resources.MockClient{
Response: []byte(`{
"key": "test-flag",
"name": "test flag"
}`),
}
args := []string{
"flags", "toggle-on",
"--access-token", "abcd1234",
"--environment", "test-env",
"--flag", "test-flag",
"--project", "test-proj",
}
output, err := cmd.CallCmd(
t,
cmd.APIClients{
ResourcesClient: mockClient,
},
analytics.NoopClientFn{}.Tracker(),
args,
)

require.NoError(t, err)
assert.Equal(t, `[{"op": "replace", "path": "/environments/test-env/on", "value": true}]`, string(mockClient.Input))
assert.Equal(t, "Successfully updated test flag (test-flag)\n", string(output))
}
7 changes: 4 additions & 3 deletions cmd/resources/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ func NewOperationCmd(parentCmd *cobra.Command, client resources.Client, op Opera
Use: op.Use,
}

cmd.SetUsageTemplate(operationUsageTemplate())
cmd.SetUsageTemplate(OperationUsageTemplate())

opCmd.cmd = cmd
_ = opCmd.initFlags()
Expand Down Expand Up @@ -395,10 +395,11 @@ Global Flags:
Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
{{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}`
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
`
}

func operationUsageTemplate() string {
func OperationUsageTemplate() string {
return `Usage:{{if .Runnable}}
{{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
{{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}}
Expand Down
9 changes: 9 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
cmdAnalytics "ldcli/cmd/analytics"
"ldcli/cmd/cliflags"
configcmd "ldcli/cmd/config"
flagscmd "ldcli/cmd/flags"
resourcecmd "ldcli/cmd/resources"
"ldcli/internal/analytics"
"ldcli/internal/config"
Expand Down Expand Up @@ -186,6 +187,14 @@ func NewRootCommand(
cmd.AddCommand(resourcecmd.NewResourcesCmd())
resourcecmd.AddAllResourceCmds(cmd, clients.ResourcesClient, analyticsTrackerFn)

// add non-generated commands
for _, c := range cmd.Commands() {
if c.Name() == "flags" {
c.AddCommand(flagscmd.NewToggleOnCmd(clients.ResourcesClient))
c.AddCommand(flagscmd.NewToggleOffCmd(clients.ResourcesClient))
}
}

rootCmd.Commands = append(rootCmd.Commands, configCmd)

return rootCmd, nil
Expand Down
20 changes: 20 additions & 0 deletions internal/resources/mock_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package resources

import "net/url"

type MockClient struct {
Input []byte
Response []byte
}

var _ Client = &MockClient{}

func (c *MockClient) MakeRequest(
accessToken, method, path, contentType string,
query url.Values,
data []byte,
) ([]byte, error) {
c.Input = data

return c.Response, nil
}

0 comments on commit 76de2a5

Please sign in to comment.