Skip to content
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ importfmtlint:
golangcilint:
@echo -n "Running 'golangci-lint' to check for code quality issues..."
@# Clear the cache for every run, so that the linter outputs the same results as the GH Actions workflow
@if golangci-lint cache clear && golangci-lint run --timeout 5m ./...; then \
@if golangci-lint cache clean && golangci-lint run --timeout 5m ./...; then \
echo " SUCCESS"; \
else \
echo " FAILED"; \
Expand Down
1 change: 1 addition & 0 deletions cmd/config/list_keys_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ func Example_listKeysValue() {
// - export.outputDirectory
// - export.overwrite
// - export.pingone.environmentID
// - export.serviceGroup
// - export.services
// - noColor
// - outputFormat
Expand Down
4 changes: 4 additions & 0 deletions cmd/platform/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ const (
Export configuration-as-code packages for PingOne (core platform and SSO services).
pingcli platform export --services pingone-platform,pingone-sso

Export all configuration-as-code packages for PingOne. The --service-group flag can be used instead of listing all pingone-* packages in --services flag.
pingcli platform export --service-group pingone

Export configuration-as-code packages for PingOne (core platform), specifying the PingOne environment connection details.
pingcli platform export --services pingone-platform --pingone-client-environment-id 3cf2... --pingone-worker-client-id a719... --pingone-worker-client-secret ey..... --pingone-region-code EU

Expand Down Expand Up @@ -92,6 +95,7 @@ func exportRunE(cmd *cobra.Command, args []string) error {
func initGeneralExportFlags(cmd *cobra.Command) {
cmd.Flags().AddFlag(options.PlatformExportExportFormatOption.Flag)
cmd.Flags().AddFlag(options.PlatformExportServiceOption.Flag)
cmd.Flags().AddFlag(options.PlatformExportServiceGroupOption.Flag)
cmd.Flags().AddFlag(options.PlatformExportOutputDirectoryOption.Flag)
cmd.Flags().AddFlag(options.PlatformExportOverwriteOption.Flag)
cmd.Flags().AddFlag(options.PlatformExportPingOneEnvironmentIDOption.Flag)
Expand Down
23 changes: 21 additions & 2 deletions cmd/platform/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,27 @@ func TestPlatformExportCmd_HelpFlag(t *testing.T) {
testutils.CheckExpectedError(t, err, nil)
}

// Test Platform Export Command --service-group, -g flag
func TestPlatformExportCmd_ServiceGroupFlag(t *testing.T) {
outputDir := t.TempDir()

err := testutils_cobra.ExecutePingcli(t, "platform", "export",
"--"+options.PlatformExportOutputDirectoryOption.CobraParamName, outputDir,
"--"+options.PlatformExportOverwriteOption.CobraParamName,
"--"+options.PlatformExportServiceGroupOption.CobraParamName, "pingone")
testutils.CheckExpectedError(t, err, nil)
}

// Test Platform Export Command --service-group with non-supported service group
func TestPlatformExportCmd_ServiceGroupFlagInvalidServiceGroup(t *testing.T) {
expectedErrorPattern := `^invalid argument ".*" for "-g, --service-group" flag: unrecognized service group '.*'\. Must be one of: .*$`
err := testutils_cobra.ExecutePingcli(t, "platform", "export",
"--"+options.PlatformExportServiceGroupOption.CobraParamName, "invalid")
testutils.CheckExpectedError(t, err, &expectedErrorPattern)
}

// Test Platform Export Command --services flag
func TestPlatformExportCmd_ServiceFlag(t *testing.T) {
func TestPlatformExportCmd_ServicesFlag(t *testing.T) {
outputDir := t.TempDir()

err := testutils_cobra.ExecutePingcli(t, "platform", "export",
Expand All @@ -60,7 +79,7 @@ func TestPlatformExportCmd_ServiceFlag(t *testing.T) {
}

// Test Platform Export Command --services flag with invalid service
func TestPlatformExportCmd_ServiceFlagInvalidService(t *testing.T) {
func TestPlatformExportCmd_ServicesFlagInvalidService(t *testing.T) {
expectedErrorPattern := `^invalid argument ".*" for "-s, --services" flag: failed to set ExportServices: Invalid service: .*\. Allowed services: .*$`
err := testutils_cobra.ExecutePingcli(t, "platform", "export",
"--"+options.PlatformExportServiceOption.CobraParamName, "invalid")
Expand Down
1 change: 1 addition & 0 deletions docs/tool-configuration/configuration-key.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ The following parameters can be configured in Ping CLI's static configuration fi
| export.outputDirectory | ENUM_STRING | --output-directory / -d | Specifies the output directory for export. Example: `$HOME/pingcli-export` |
| export.overwrite | ENUM_BOOL | --overwrite / -o | Overwrite the existing generated exports in output directory. |
| export.pingone.environmentID | ENUM_UUID | --pingone-export-environment-id | The ID of the PingOne environment to export. Must be a valid PingOne UUID. |
| export.serviceGroup | ENUM_EXPORT_SERVICE_GROUP | --service-group / -g | Specifies the service group to export. <br><br>Options are: pingone.<br><br>Example: `pingone` |
| export.services | ENUM_EXPORT_SERVICES | --services / -s | Specifies the service(s) to export. Accepts a comma-separated string to delimit multiple services.<br><br>Options are: pingfederate, pingone-mfa, pingone-platform, pingone-protect, pingone-sso.<br><br>Example: `pingone-sso,pingone-mfa,pingfederate` |

#### Custom Request Properties
Expand Down
6 changes: 6 additions & 0 deletions internal/commands/config/set_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ func setValue(profileViper *viper.Viper, vKey, vValue string, valueType options.
return fmt.Errorf("value for key '%s' must be a valid export format. Allowed [%s]: %v", vKey, strings.Join(customtypes.ExportFormatValidValues(), ", "), err)
}
profileViper.Set(vKey, exportFormat)
case options.ENUM_EXPORT_SERVICE_GROUP:
exportServiceGroup := new(customtypes.ExportServiceGroup)
if err = exportServiceGroup.Set(vValue); err != nil {
return fmt.Errorf("value for key '%s' must be valid export service group. Allowed [%s]: %v", vKey, strings.Join(customtypes.ExportServiceGroupValidValues(), ", "), err)
}
profileViper.Set(vKey, exportServiceGroup)
case options.ENUM_EXPORT_SERVICES:
exportServices := new(customtypes.ExportServices)
if err = exportServices.Set(vValue); err != nil {
Expand Down
23 changes: 21 additions & 2 deletions internal/commands/platform/export_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ func RunInternalExport(ctx context.Context, commandVersion string) (err error) {
if err != nil {
return err
}
exportServiceGroup, err := profiles.GetOptionValue(options.PlatformExportServiceGroupOption)
if err != nil {
return err
}
exportServices, err := profiles.GetOptionValue(options.PlatformExportServiceOption)
if err != nil {
return err
Expand All @@ -63,11 +67,26 @@ func RunInternalExport(ctx context.Context, commandVersion string) (err error) {
return err
}

var exportableConnectors *[]connector.Exportable
es := new(customtypes.ExportServices)
if err = es.Set(exportServices); err != nil {
return err
}

esg := new(customtypes.ExportServiceGroup)
if err = esg.Set(exportServiceGroup); err != nil {
return err
}

es2 := new(customtypes.ExportServices)
if err = es2.SetServicesByServiceGroup(esg); err != nil {
return err
}

if err = es.Merge(*es2); err != nil {
return err
}

if es.ContainsPingOneService() {
if err = initPingOneServices(ctx, commandVersion); err != nil {
return err
Expand All @@ -80,6 +99,8 @@ func RunInternalExport(ctx context.Context, commandVersion string) (err error) {
}
}

exportableConnectors = getExportableConnectors(es)

overwriteExportBool, err := strconv.ParseBool(overwriteExport)
if err != nil {
return err
Expand All @@ -88,8 +109,6 @@ func RunInternalExport(ctx context.Context, commandVersion string) (err error) {
return err
}

exportableConnectors := getExportableConnectors(es)

if err := exportConnectors(exportableConnectors, exportFormat, outputDir, overwriteExportBool); err != nil {
return err
}
Expand Down
3 changes: 3 additions & 0 deletions internal/configuration/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const (
ENUM_BOOL OptionType = "ENUM_BOOL"
ENUM_EXPORT_FORMAT OptionType = "ENUM_EXPORT_FORMAT"
ENUM_INT OptionType = "ENUM_INT"
ENUM_EXPORT_SERVICE_GROUP OptionType = "ENUM_EXPORT_SERVICE_GROUP"
ENUM_EXPORT_SERVICES OptionType = "ENUM_EXPORT_SERVICES"
ENUM_OUTPUT_FORMAT OptionType = "ENUM_OUTPUT_FORMAT"
ENUM_PINGFEDERATE_AUTH_TYPE OptionType = "ENUM_PINGFEDERATE_AUTH_TYPE"
Expand Down Expand Up @@ -48,6 +49,7 @@ func Options() []Option {
PingOneRegionCodeOption,

PlatformExportExportFormatOption,
PlatformExportServiceGroupOption,
PlatformExportServiceOption,
PlatformExportOutputDirectoryOption,
PlatformExportOverwriteOption,
Expand Down Expand Up @@ -142,6 +144,7 @@ var (
var (
PlatformExportExportFormatOption Option
PlatformExportServiceOption Option
PlatformExportServiceGroupOption Option
PlatformExportOutputDirectoryOption Option
PlatformExportOverwriteOption Option
PlatformExportPingOneEnvironmentIDOption Option
Expand Down
34 changes: 30 additions & 4 deletions internal/configuration/platform/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
func InitPlatformExportOptions() {
initFormatOption()
initServicesOption()
initServiceGroupOption()
initOutputDirectoryOption()
initOverwriteOption()
initPingOneEnvironmentIDOption()
Expand Down Expand Up @@ -47,12 +48,39 @@ func initFormatOption() {
}
}

func initServiceGroupOption() {
cobraParamName := "service-group"
cobraValue := new(customtypes.ExportServiceGroup)
defaultValue := customtypes.ExportServiceGroup("")
envVar := "PINGCLI_EXPORT_SERVICE_GROUP"
options.PlatformExportServiceGroupOption = options.Option{
CobraParamName: cobraParamName,
CobraParamValue: cobraValue,
DefaultValue: &defaultValue,
EnvVar: envVar,
Flag: &pflag.Flag{
Name: cobraParamName,
Shorthand: "g",
Usage: fmt.Sprintf(
"Specifies the service group to export. "+
"\nOptions are: %s."+
"\nExample: '%s'",
strings.Join(customtypes.ExportServiceGroupValidValues(), ", "),
string(customtypes.ENUM_EXPORT_SERVICE_GROUP_PINGONE),
),
Value: cobraValue,
},
Sensitive: false,
Type: options.ENUM_EXPORT_SERVICE_GROUP,
ViperKey: "export.serviceGroup",
}
}

func initServicesOption() {
cobraParamName := "services"
cobraValue := new(customtypes.ExportServices)
defaultValue := customtypes.ExportServices(customtypes.ExportServicesValidValues())
defaultValue := customtypes.ExportServices([]string{})
envVar := "PINGCLI_EXPORT_SERVICES"

options.PlatformExportServiceOption = options.Option{
CobraParamName: cobraParamName,
CobraParamValue: cobraValue,
Expand All @@ -63,11 +91,9 @@ func initServicesOption() {
Shorthand: "s",
Usage: fmt.Sprintf(
"Specifies the service(s) to export. Accepts a comma-separated string to delimit multiple services. "+
"(default %s)"+
"\nOptions are: %s."+
"\nExample: '%s,%s,%s'",
strings.Join(customtypes.ExportServicesValidValues(), ", "),
strings.Join(customtypes.ExportServicesValidValues(), ", "),
string(customtypes.ENUM_EXPORT_SERVICE_PINGONE_SSO),
string(customtypes.ENUM_EXPORT_SERVICE_PINGONE_MFA),
string(customtypes.ENUM_EXPORT_SERVICE_PINGFEDERATE),
Expand Down
54 changes: 54 additions & 0 deletions internal/customtypes/export_service_group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package customtypes

import (
"fmt"
"slices"
"strings"

"github.com/spf13/pflag"
)

const (
ENUM_EXPORT_SERVICE_GROUP_PINGONE string = "pingone"
)

type ExportServiceGroup string

// Verify that the custom type satisfies the pflag.Value interface
var _ pflag.Value = (*ExportServiceGroup)(nil)

func (esg *ExportServiceGroup) Set(serviceGroup string) error {
if esg == nil {
return fmt.Errorf("failed to set ExportServiceGroup value: %s. ExportServiceGroup is nil", serviceGroup)
}

if serviceGroup == "" {
return nil
}

switch {
case strings.EqualFold(ENUM_EXPORT_SERVICE_GROUP_PINGONE, serviceGroup):
*esg = ExportServiceGroup(ENUM_EXPORT_SERVICE_GROUP_PINGONE)
default:
return fmt.Errorf("unrecognized service group '%s'. Must be one of: %s", serviceGroup, strings.Join(ExportServiceGroupValidValues(), ", "))
}
return nil
}

func (esg ExportServiceGroup) Type() string {
return "string"
}

func (esg ExportServiceGroup) String() string {
return string(esg)
}

func ExportServiceGroupValidValues() []string {
validServiceGroups := []string{
ENUM_EXPORT_SERVICE_GROUP_PINGONE,
}

slices.Sort(validServiceGroups)

return validServiceGroups
}
52 changes: 52 additions & 0 deletions internal/customtypes/export_service_group_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package customtypes_test

import (
"testing"

"github.com/pingidentity/pingcli/internal/customtypes"
"github.com/pingidentity/pingcli/internal/testing/testutils"
)

// Test ExportServiceGroup Set function
func Test_ExportServiceGroup_Set(t *testing.T) {
// Create a new ExportServiceGroup
esg := new(customtypes.ExportServiceGroup)

err := esg.Set(customtypes.ENUM_EXPORT_SERVICE_GROUP_PINGONE)
if err != nil {
t.Errorf("Set returned error: %v", err)
}
}

// Test ExportServiceGroup Set function fails with invalid value
func Test_ExportServiceGroup_Set_InvalidValue(t *testing.T) {
// Create a new ExportServiceGroup
esg := new(customtypes.ExportServiceGroup)

invalidValue := "invalid"

expectedErrorPattern := `^unrecognized service group .*\. Must be one of: .*$`
err := esg.Set(invalidValue)
testutils.CheckExpectedError(t, err, &expectedErrorPattern)
}

// Test ExportServiceGroup Set function fails with nil
func Test_ExportServiceGroup_Set_Nil(t *testing.T) {
var esg *customtypes.ExportServiceGroup

val := customtypes.ENUM_EXPORT_SERVICE_GROUP_PINGONE

expectedErrorPattern := `^failed to set ExportServiceGroup value: .* ExportServiceGroup is nil$`
err := esg.Set(val)
testutils.CheckExpectedError(t, err, &expectedErrorPattern)
}

// Test ExportServiceGroup Valid Values returns expected amount
func Test_ExportServiceGroupValidValues(t *testing.T) {
serviceGroupEnum := customtypes.ENUM_EXPORT_SERVICE_GROUP_PINGONE

serviceGroupValidValues := customtypes.ExportServiceGroupValidValues()
if serviceGroupValidValues[0] != serviceGroupEnum {
t.Errorf("ExportServiceGroupValidValues returned: %v, expected: %v", serviceGroupValidValues, serviceGroupEnum)
}
}
Loading