Skip to content

Commit

Permalink
fix: add ability to render to Ory Kratos config YAML
Browse files Browse the repository at this point in the history
  • Loading branch information
aeneasr committed Mar 24, 2022
1 parent 4edb210 commit 002637e
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 41 deletions.
1 change: 0 additions & 1 deletion cloudx/cmd_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,5 @@ func NewGetCmd() *cobra.Command {
RegisterConfigFlag(cmd.PersistentFlags())
RegisterYesFlag(cmd.PersistentFlags())
cmdx.RegisterNoiseFlags(cmd.PersistentFlags())
cmdx.RegisterJSONFormatFlags(cmd.PersistentFlags())
return cmd
}
10 changes: 6 additions & 4 deletions cloudx/cmd_get_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@ import (
"fmt"

"github.com/spf13/cobra"

"github.com/ory/x/cmdx"
)

func NewGetProjectCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "project id",
Args: cobra.ExactArgs(1),
Short: fmt.Sprintf("Get an Ory Cloud project"),
Example: `ory get project ecaaa3cb-0730-4ee8-a6df-9553cdfeef89
ory get project ecaaa3cb-0730-4ee8-a6df-9553cdfeef89 --format json
ory get project ecaaa3cb-0730-4ee8-a6df-9553cdfeef89 --format kratos-config > kratos-config.yml`,
Long: `If you wish to generate a configuration for self-hosting Ory Kratos, use ` + "`--format kratos-config`" + `.`,
RunE: func(cmd *cobra.Command, args []string) error {
h, err := NewSnakeCharmer(cmd)
if err != nil {
Expand All @@ -24,10 +26,10 @@ func NewGetProjectCmd() *cobra.Command {
return PrintOpenAPIError(cmd, err)
}

cmdx.PrintRow(cmd, (*outputProject)(project))
return nil
return PrintExtendedFormat(cmd, project)
},
}

RegisterExtendedOutput(cmd.Flags())
return cmd
}
10 changes: 10 additions & 0 deletions cloudx/cmd_get_project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"fmt"
"testing"

"github.com/ghodss/yaml"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"
Expand Down Expand Up @@ -41,4 +43,12 @@ func TestGetProject(t *testing.T) {
require.NoError(t, err)
assert.Contains(t, project, gjson.Parse(stdout).Get("id").String())
})

t.Run("is able to get project as a kratos config", func(t *testing.T) {
stdout, _, err := cmd.ExecDebug(t, nil, "get", "project", project, "--format", "kratos-config")
require.NoError(t, err)
actual, err := yaml.YAMLToJSON([]byte(stdout))
require.NoError(t, err)
assert.Equal(t, "/ui/error", gjson.GetBytes(actual, "selfservice.flows.error.ui_url").String())
})
}
33 changes: 20 additions & 13 deletions cloudx/cmd_patch_project.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package cloudx

import (
"fmt"

"github.com/pkg/errors"
"github.com/spf13/cobra"

"github.com/ory/x/flagx"

"github.com/ory/x/cmdx"

"github.com/ory/x/flagx"
)

func NewProjectsPatchCmd() *cobra.Command {
Expand All @@ -20,7 +18,21 @@ func NewProjectsPatchCmd() *cobra.Command {
--replace '/name="My new project name"' \
--add '/services/identity/config/courier/smtp={"from_name":"My new email name"}' \
--replace '/services/identity/config/selfservice/methods/password/enabled=false' \
--delete '/services/identity/config/selfservice/methods/totp/enabled'`,
--delete '/services/identity/config/selfservice/methods/totp/enabled'
ory patch project ecaaa3cb-0730-4ee8-a6df-9553cdfeef89 \
--replace '/name="My new project name"' \
--delete '/services/identity/config/selfservice/methods/totp/enabled'
--format kratos-config > my-config.yaml`,
Long: `Use this command to patch your current Ory Cloud Project's service configuration. Only values
specified in the patch will be overwritten. To replace the config use the ` + "`update`" + ` command instead.
The format of the patch is a JSON-Patch document. For more details please check:
https://www.ory.sh/docs/reference/api#operation/patchProject
https://jsonpatch.com
If you wish to generate a configuration for self-hosting Ory Kratos, use ` + "`--format kratos-config`" + `.`,
RunE: func(cmd *cobra.Command, args []string) (err error) {
h, err := NewSnakeCharmer(cmd)
if err != nil {
Expand All @@ -46,13 +58,7 @@ func NewProjectsPatchCmd() *cobra.Command {
return PrintOpenAPIError(cmd, err)
}

cmdx.PrintRow(cmd, (*outputProject)(&p.Project))
for _, warning := range p.Warnings {
_, _ = fmt.Fprintf(h.verboseErrWriter, "WARNING: %s\n", *warning.Message)
}

_, _ = fmt.Fprintln(h.verboseErrWriter, "Project updated successfully!")
return nil
return h.PrintUpdateProject(cmd, p)
},
}

Expand All @@ -61,6 +67,7 @@ func NewProjectsPatchCmd() *cobra.Command {
cmd.Flags().StringArray("add", nil, "Add a specific key to the configuration")
cmd.Flags().StringArray("remove", nil, "Remove a specific key from the configuration")
RegisterYesFlag(cmd.Flags())
cmdx.RegisterFormatFlags(cmd.Flags())
cmdx.RegisterNoiseFlags(cmd.Flags())
RegisterExtendedOutput(cmd.Flags())
return cmd
}
10 changes: 10 additions & 0 deletions cloudx/cmd_patch_project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package cloudx
import (
"testing"

"github.com/ghodss/yaml"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"
Expand Down Expand Up @@ -38,6 +40,14 @@ func TestPatchProject(t *testing.T) {
assert.Equal(t, "https://example.org/error-ui", gjson.Get(stdout, "services.identity.config.selfservice.flows.error.ui_url").String())
})

t.Run("is able to add a key with raw json and output it as a kratos config", func(t *testing.T) {
stdout, _, err := cmd.ExecDebug(t, nil, "patch", "project", project, "--format", "kratos-config", "--replace", `/services/identity/config/selfservice/flows/error={"ui_url":"https://example.org/kratos-ui"}`)
require.NoError(t, err)
actual, err := yaml.YAMLToJSON([]byte(stdout))
require.NoError(t, err)
assert.Equal(t, "https://example.org/kratos-ui", gjson.GetBytes(actual, "selfservice.flows.error.ui_url").String())
})

t.Run("is able to remove a key", func(t *testing.T) {
stdout, _, err := cmd.ExecDebug(t, nil, "patch", "project", project, "--format", "json", "--remove", `/services/identity/config/selfservice/methods/password/enabled`)
require.NoError(t, err)
Expand Down
34 changes: 17 additions & 17 deletions cloudx/cmd_update_project.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package cloudx

import (
"fmt"

"github.com/pkg/errors"
"github.com/spf13/cobra"

"github.com/ory/x/cmdx"

"github.com/ory/x/flagx"
)

Expand All @@ -16,20 +15,26 @@ func NewProjectsUpdateCmd() *cobra.Command {
Args: cobra.ExactArgs(1),
Short: "Update Ory Cloud Project Service Configuration",
Example: `ory update project ecaaa3cb-0730-4ee8-a6df-9553cdfeef89 \
--name \"my updated name\" \
--file /path/to/config.json \
--file /path/to/config.yml \
--file https://example.org/config.yaml \
--file base64://<json>`,
--name \"my updated name\" \
--file /path/to/config.json \
--file /path/to/config.yml \
--file https://example.org/config.yaml \
--file base64://<json>
ory update project ecaaa3cb-0730-4ee8-a6df-9553cdfeef89 \
--name \"my updated name\" \
--file /path/to/config.json \
--format kratos-config > my-config.yaml`,
Long: `Use this command to replace your current Ory Cloud Project's service configuration. All values
will be overwritten. To update individual files use the ` + "`patch`" + ` command instead.
will be overwritten. To update individual settings use the ` + "`patch`" + ` command instead.
If the ` + "`--name`" + ` flag is not set, the project's name will not be changed.
The configuration file format can be found at:
https://www.ory.sh/docs/reference/api#operation/updateProject
`,
If you wish to generate a configuration for self-hosting Ory Kratos, use ` + "`--format kratos-config`" + `.`,
RunE: func(cmd *cobra.Command, args []string) (err error) {
h, err := NewSnakeCharmer(cmd)
if err != nil {
Expand All @@ -52,19 +57,14 @@ The configuration file format can be found at:
return PrintOpenAPIError(cmd, err)
}

cmdx.PrintRow(cmd, (*outputProject)(&p.Project))
for _, warning := range p.Warnings {
_, _ = fmt.Fprintf(h.verboseErrWriter, "WARNING: %s\n", *warning.Message)
}

_, _ = fmt.Fprintln(h.verboseErrWriter, "Project updated successfully!")
return nil
return h.PrintUpdateProject(cmd, p)
},
}

cmd.Flags().StringP("name", "n", "", "The name of the project, required when quiet mode is used")
cmd.Flags().StringSliceP("file", "f", nil, "Configuration file(s) (file://config.json, https://example.org/config.yaml, ...) to update the project")
cmdx.RegisterFormatFlags(cmd.Flags())
RegisterYesFlag(cmd.Flags())
cmdx.RegisterNoiseFlags(cmd.Flags())
RegisterExtendedOutput(cmd.Flags())
return cmd
}
10 changes: 10 additions & 0 deletions cloudx/cmd_update_project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"encoding/json"
"testing"

"github.com/ghodss/yaml"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"
Expand Down Expand Up @@ -81,4 +83,12 @@ func TestUpdateProject(t *testing.T) {
_, _, err := cmd.ExecDebug(t, &r, "update", "project", project, "--format", "json", "--file", "./fixtures/update/json/config.json")
require.NoError(t, err)
})

t.Run("is able to update a project and get it as a kratos config", func(t *testing.T) {
stdout, _, err := cmd.ExecDebug(t, nil, "update", "project", project, "--format", "kratos-config", "--file", "./fixtures/update/json/config.json")
require.NoError(t, err)
actual, err := yaml.YAMLToJSON([]byte(stdout))
require.NoError(t, err)
assert.Equal(t, "/ui/error", gjson.GetBytes(actual, "selfservice.flows.error.ui_url").String())
})
}
13 changes: 7 additions & 6 deletions cloudx/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,13 @@ import (
)

const (
fileName = ".ory-cloud.json"
configFlag = "config"
osEnvVar = "ORY_CLOUD_CONFIG_PATH"
cloudURL = "ORY_CLOUD_URL"
version = "v0alpha0"
yesFlag = "yes"
fileName = ".ory-cloud.json"
configFlag = "config"
osEnvVar = "ORY_CLOUD_CONFIG_PATH"
cloudURL = "ORY_CLOUD_URL"
version = "v0alpha0"
yesFlag = "yes"
FormatKratosConfig = "kratos-config"
)

func RegisterConfigFlag(f *pflag.FlagSet) {
Expand Down
43 changes: 43 additions & 0 deletions cloudx/print.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@ import (
"encoding/json"
"fmt"

"github.com/ghodss/yaml"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/tidwall/gjson"

"github.com/ory/client-go"
"github.com/ory/x/flagx"

"github.com/ory/x/cmdx"
)

Expand Down Expand Up @@ -46,3 +51,41 @@ func PrintOpenAPIError(cmd *cobra.Command, err error) error {

return err
}

func RegisterExtendedOutput(flags *pflag.FlagSet) {
flags.String(cmdx.FlagFormat, string(cmdx.FormatDefault), fmt.Sprintf("Set the output format. One of %s, %s, %s, and %s.", cmdx.FormatDefault, cmdx.FormatJSON, cmdx.FormatJSONPretty, FormatKratosConfig))
}

func PrintExtendedFormat(cmd *cobra.Command, project *client.Project) error {
if flagx.MustGetString(cmd, cmdx.FlagFormat) != FormatKratosConfig {
cmdx.PrintRow(cmd, (*outputProject)(project))
return nil
}

out, err := yaml.Marshal(project.Services.Identity.Config)
if err != nil {
return errors.WithStack(err)
}
if _, err := fmt.Fprintf(cmd.OutOrStdout(), "%s\n", out); err != nil {
return err
}
return nil
}

func (h *SnakeCharmer) PrintUpdateProject(cmd *cobra.Command, p *client.SuccessfulProjectUpdate) error {
if err := PrintExtendedFormat(cmd, &p.Project); err != nil {
return err
}

if len(p.Warnings) > 0 {
_, _ = fmt.Fprintln(h.verboseErrWriter)
_, _ = fmt.Fprintln(h.verboseErrWriter, "Warnings were found.")
for _, warning := range p.Warnings {
_, _ = fmt.Fprintf(h.verboseErrWriter, "- %s\n", *warning.Message)
}
_, _ = fmt.Fprintln(h.verboseErrWriter, "It is save to ignore these warnings unless your intention was to set these keys.")
}

_, _ = fmt.Fprintf(h.verboseErrWriter, "\nProject updated successfully!\n")
return nil
}

0 comments on commit 002637e

Please sign in to comment.