Skip to content

Commit

Permalink
PDI-1459: CLI v2 Command Connector: Platform Export / PingOne (Early …
Browse files Browse the repository at this point in the history
…access) (#39)

* PDI-1459: CLI v2 Command Connector: Platform Export / PingOne (Early access)

- Add framework and one resource export (pingone_agreement) to pingctl.
Further work will follow this adding remaining resources to export
subcommand.
- Update test funcs to use NewRootCommand() to gain viper
functionality in test cases.
- Update most output messages to use Error instead of Fatal to
propigate error messages back through the call stack. This is useful
for chaining error messages to trace what pingctl was trying to do,
as well as make test cases recieve stdout for error messaging.
- Update Cobra Run functions to use RunE to allow error propigation
as well.
- Update export.go to use PingOne SDK and loop through user specified
services exports. Use user define export format and override varibles
to do so. Default export output directory to pwd. Fail to export if
previous export files are present.
- Update ExportableResource to define an ImportBlock struct to
house API data and use in text template output to file. Add utility
ResourceType function to interface as well.
- Create pingone_platform_connector.go to define a connector for
the pingone platform service. Pingone SSO service to be added in
further work.
- Create resources subfolder structure for connectors to define
each individual resource, as well as their sdk specific logic
or exporting data.

* Remove generated import block export for pingone_agreement resource.

* PR Review changes. Moved template to be embedded. Added custom type for service parameter on the export command.

* Remove noop from login/logout commands. Update export command test to write to a temp dir to cleanup make devcheck locally

* Update workflow to use github secrets for environment variables

* Add custom type for export format in export.go, and move cobra custom types to custom_types.go

* reduce scope of serviceName in connector, and verify custom types for export command implement pflag.Value interface.

* Update export command to use viper generated env vars, and improve user messaging on success path

* Update workflow to use new viper env vars for PingOne SDK client

* Add nil check to MultiService Set function
  • Loading branch information
erikostien-pingidentity authored Feb 22, 2024
1 parent 1e74302 commit 83dcc5c
Show file tree
Hide file tree
Showing 20 changed files with 546 additions and 117 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/code-analysis-lint-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ jobs:
name: go test
needs: [build]
runs-on: ubuntu-latest
env:
PINGCTL_PINGONE_WORKER_CLIENT_ID: ${{ secrets.PINGCTL_PINGONE_WORKER_CLIENT_ID }}
PINGCTL_PINGONE_WORKER_CLIENT_SECRET: ${{ secrets.PINGCTL_PINGONE_WORKER_CLIENT_SECRET }}
PINGCTL_PINGONE_REGION: ${{ secrets.PINGCTL_PINGONE_REGION }}
PINGCTL_PINGONE_WORKER_ENVIRONMENT_ID: ${{ secrets.PINGCTL_PINGONE_WORKER_ENVIRONMENT_ID }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
Expand Down
22 changes: 13 additions & 9 deletions cmd/auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,23 @@ import (
"bytes"
"testing"

"github.com/pingidentity/pingctl/cmd/auth"
"github.com/pingidentity/pingctl/cmd"
)

// Test Auth Login Command Executes without issue
func TestAuthLoginCmd_Execute(t *testing.T) {
// Create the command
loginCmd := auth.NewLoginCommand()
rootCmd := cmd.NewRootCommand()

// Redirect stdout to a buffer to capture the output
var stdout bytes.Buffer
loginCmd.SetOut(&stdout)
loginCmd.SetErr(&stdout)
rootCmd.SetOut(&stdout)
rootCmd.SetErr(&stdout)

rootCmd.SetArgs([]string{"auth", "login"})

// Execute the command
err := loginCmd.Execute()
err := rootCmd.Execute()
if err != nil {
t.Fatalf("Err: %q, Captured StdOut: %q", err, stdout.String())
}
Expand All @@ -27,15 +29,17 @@ func TestAuthLoginCmd_Execute(t *testing.T) {
// Test Auth Logout Command Executes without issue
func TestAuthLogoutCmd_Execute(t *testing.T) {
// Create the command
logoutCmd := auth.NewLogoutCommand()
rootCmd := cmd.NewRootCommand()

// Redirect stdout to a buffer to capture the output
var stdout bytes.Buffer
logoutCmd.SetOut(&stdout)
logoutCmd.SetErr(&stdout)
rootCmd.SetOut(&stdout)
rootCmd.SetErr(&stdout)

rootCmd.SetArgs([]string{"auth", "logout"})

// Execute the command
err := logoutCmd.Execute()
err := rootCmd.Execute()
if err != nil {
t.Fatalf("Err: %q, Captured StdOut: %q", err, stdout.String())
}
Expand Down
19 changes: 3 additions & 16 deletions cmd/auth/login.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package auth

import (
"github.com/pingidentity/pingctl/internal/connector"
"github.com/pingidentity/pingctl/internal/connector/noop"
"github.com/pingidentity/pingctl/internal/output"
"github.com/spf13/cobra"
)

Expand All @@ -13,19 +10,9 @@ func NewLoginCommand() *cobra.Command {
//TODO more fleshed-out descriptions
Short: "Login with Ping",
Long: "Login with Ping",
Run: func(cmd *cobra.Command, args []string) {
// Just use the no-op connector for now by default
authConnectors := []connector.Authenticatable{
noop.Connector(),
}
err := authConnectors[0].Login()
if err != nil {
output.Format(cmd, output.CommandOutput{
Message: "Login failed.",
Fatal: err,
Result: output.ENUMCOMMANDOUTPUTRESULT_FAILURE,
})
}
RunE: func(cmd *cobra.Command, args []string) error {
// authConnectors := []connector.Authenticatable{}
return nil
},
}

Expand Down
19 changes: 3 additions & 16 deletions cmd/auth/logout.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package auth

import (
"github.com/pingidentity/pingctl/internal/connector"
"github.com/pingidentity/pingctl/internal/connector/noop"
"github.com/pingidentity/pingctl/internal/output"
"github.com/spf13/cobra"
)

Expand All @@ -13,19 +10,9 @@ func NewLogoutCommand() *cobra.Command {
//TODO more fleshed-out descriptions
Short: "Logout with Ping",
Long: "Logout with Ping",
Run: func(cmd *cobra.Command, args []string) {
// Just use the no-op connector for now by default
authConnectors := []connector.Authenticatable{
noop.Connector(),
}
err := authConnectors[0].Logout()
if err != nil {
output.Format(cmd, output.CommandOutput{
Message: "Logout failed.",
Fatal: err,
Result: output.ENUMCOMMANDOUTPUTRESULT_FAILURE,
})
}
RunE: func(cmd *cobra.Command, args []string) error {
// authConnectors := []connector.Authenticatable{}
return nil
},
}

Expand Down
12 changes: 7 additions & 5 deletions cmd/feedback_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,18 @@ import (

// Test Feedback Command Executes without issue
func TestFeedbackCmd_Execute(t *testing.T) {
// Create the root command
feedbackCmd := cmd.NewFeedbackCommand()
// Create the command
rootCmd := cmd.NewRootCommand()

// Redirect stdout to a buffer to capture the output
var stdout bytes.Buffer
feedbackCmd.SetOut(&stdout)
feedbackCmd.SetErr(&stdout)
rootCmd.SetOut(&stdout)
rootCmd.SetErr(&stdout)

rootCmd.SetArgs([]string{"feedback"})

// Execute the root command
err := feedbackCmd.Execute()
err := rootCmd.Execute()
if err != nil {
t.Fatalf("Err: %q, Captured StdOut: %q", err, stdout.String())
}
Expand Down
68 changes: 68 additions & 0 deletions cmd/platform/custom_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package platform

import (
"fmt"
"strings"

"github.com/pingidentity/pingctl/internal/connector"
"github.com/spf13/pflag"
)

const (
serviceEnumPlatform = "pingone-platform"
)

type MultiService struct {
services *[]string
}

type ExportFormat string

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

// Implement pflag.Value interface for custom type in cobra service parameter

func (s *MultiService) Set(service string) error {
switch service {
case serviceEnumPlatform:
if *s.services == nil {
s.services = &[]string{}
}
*s.services = append(*s.services, service)
default:
return fmt.Errorf("unrecognized service %q", service)
}
return nil
}

func (s *MultiService) Type() string {
return "string"
}

func (s *MultiService) String() string {
return fmt.Sprintf("[ %s ]", strings.Join(*s.services, ", "))
}

// Implement pflag.Value interface for custom type in cobra export-format parameter

func (s *ExportFormat) Set(format string) error {
switch format {
case connector.ENUMEXPORTFORMAT_HCL:
*s = ExportFormat(format)
default:
return fmt.Errorf("unrecognized export format %q", format)
}
return nil
}

func (s *ExportFormat) Type() string {
return "string"
}

func (s *ExportFormat) String() string {
return string(*s)
}
Loading

0 comments on commit 83dcc5c

Please sign in to comment.