mirror of
https://github.com/LukeHagar/sailpoint-cli.git
synced 2025-12-07 12:47:50 +00:00
Restructured all packages to be more modular
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
package client
|
||||
package connclient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -10,11 +10,13 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
)
|
||||
|
||||
// ConnClient is an sp connect client for a specific connector
|
||||
type ConnClient struct {
|
||||
client Client
|
||||
client client.Client
|
||||
version *int
|
||||
config json.RawMessage
|
||||
connectorRef string
|
||||
@@ -22,7 +24,7 @@ type ConnClient struct {
|
||||
}
|
||||
|
||||
// NewConnClient returns a client for the provided (connectorID, version, config)
|
||||
func NewConnClient(client Client, version *int, config json.RawMessage, connectorRef string, endpoint string) *ConnClient {
|
||||
func NewConnClient(client client.Client, version *int, config json.RawMessage, connectorRef string, endpoint string) *ConnClient {
|
||||
return &ConnClient{
|
||||
client: client,
|
||||
version: version,
|
||||
@@ -691,8 +693,6 @@ func (cc *ConnClient) rawInvokeWithConfig(cmdType string, input json.RawMessage,
|
||||
return json.Marshal(invokeCmd)
|
||||
}
|
||||
|
||||
const connectorsEndpoint = "/beta/platform-connectors"
|
||||
|
||||
func connResourceUrl(endpoint string, resourceParts ...string) string {
|
||||
u, err := url.Parse(endpoint)
|
||||
if err != nil {
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2022, SailPoint Technologies, Inc. All rights reserved.
|
||||
package client
|
||||
package connclient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -13,18 +13,20 @@ import (
|
||||
"net/url"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
)
|
||||
|
||||
const TimeFormatLocal = `2006-01-02T15:04:05.000-07:00`
|
||||
const TimeLocationLocal = "Local"
|
||||
|
||||
type LogsClient struct {
|
||||
client Client
|
||||
client client.Client
|
||||
endpoint string
|
||||
}
|
||||
|
||||
// NewConnClient returns a client for the provided (connectorID, version, config)
|
||||
func NewLogsClient(client Client, endpoint string) *LogsClient {
|
||||
func NewLogsClient(client client.Client, endpoint string) *LogsClient {
|
||||
return &LogsClient{
|
||||
client: client,
|
||||
endpoint: endpoint,
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2022, SailPoint Technologies, Inc. All rights reserved.
|
||||
package client
|
||||
package connclient
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -23,8 +23,8 @@ func NewConnCmd(client client.Client) *cobra.Command {
|
||||
Use: "connectors",
|
||||
Short: "Manage Connectors",
|
||||
Aliases: []string{"conn"},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(), cmd.UsageString())
|
||||
Run: func(command *cobra.Command, args []string) {
|
||||
_, _ = fmt.Fprintf(command.OutOrStdout(), command.UsageString())
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
connclient "github.com/sailpoint-oss/sp-cli/cmd/connector/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -69,16 +70,7 @@ func invokeConfig(cmd *cobra.Command) (json.RawMessage, error) {
|
||||
return os.ReadFile(cmd.Flags().Lookup("config-path").Value.String())
|
||||
}
|
||||
|
||||
type invokeCommand struct {
|
||||
ConnectorID string `json:"connectorID"`
|
||||
Version *int `json:"version"`
|
||||
|
||||
Type string `json:"type"`
|
||||
Config json.RawMessage `json:"config"`
|
||||
Input json.RawMessage `json:"input"`
|
||||
}
|
||||
|
||||
func connClient(cmd *cobra.Command, spClient client.Client) (*client.ConnClient, error) {
|
||||
func connClient(cmd *cobra.Command, spClient client.Client) (*connclient.ConnClient, error) {
|
||||
connectorRef := cmd.Flags().Lookup("id").Value.String()
|
||||
version := cmd.Flags().Lookup("version").Value.String()
|
||||
endpoint := cmd.Flags().Lookup("conn-endpoint").Value.String()
|
||||
@@ -96,18 +88,18 @@ func connClient(cmd *cobra.Command, spClient client.Client) (*client.ConnClient,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cc := client.NewConnClient(spClient, v, cfg, connectorRef, endpoint)
|
||||
cc := connclient.NewConnClient(spClient, v, cfg, connectorRef, endpoint)
|
||||
|
||||
return cc, nil
|
||||
}
|
||||
|
||||
func connClientWithCustomParams(spClient client.Client, cfg json.RawMessage, connectorID, version, endpoint string) (*client.ConnClient, error) {
|
||||
func connClientWithCustomParams(spClient client.Client, cfg json.RawMessage, connectorID, version, endpoint string) (*connclient.ConnClient, error) {
|
||||
v, err := strconv.Atoi(version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cc := client.NewConnClient(spClient, &v, cfg, connectorID, endpoint)
|
||||
cc := connclient.NewConnClient(spClient, &v, cfg, connectorID, endpoint)
|
||||
|
||||
return cc, nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
connclient "github.com/sailpoint-oss/sp-cli/cmd/connector/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -24,7 +25,7 @@ func newConnInvokeAccountUpdateCmd(spClient client.Client) *cobra.Command {
|
||||
}
|
||||
|
||||
changesRaw := cmd.Flags().Lookup("changes").Value.String()
|
||||
var changes []client.AttributeChange
|
||||
var changes []connclient.AttributeChange
|
||||
if err := json.Unmarshal([]byte(changesRaw), &changes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
connclient "github.com/sailpoint-oss/sp-cli/cmd/connector/client"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var logInput = client.LogInput{}
|
||||
var logInput = connclient.LogInput{}
|
||||
|
||||
func newConnLogsCmd(spClient client.Client) *cobra.Command {
|
||||
|
||||
@@ -33,7 +34,7 @@ func newConnLogsCmd(spClient client.Client) *cobra.Command {
|
||||
return nil
|
||||
},
|
||||
}
|
||||
cmd.PersistentFlags().StringP("logs-endpoint", "o", viper.GetString("baseurl")+client.LogsEndpoint, "Override logs endpoint")
|
||||
cmd.PersistentFlags().StringP("logs-endpoint", "o", viper.GetString("baseurl")+connclient.LogsEndpoint, "Override logs endpoint")
|
||||
//date filters
|
||||
cmd.Flags().StringP("start", "s", "", `start time - get the logs from this point. An absolute timestamp in RFC3339 format, or a relative time (eg. 2h). Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`)
|
||||
cmd.Flags().StringP("stop", "", "", `end time - get the logs upto this point. An absolute timestamp in RFC3339 format, or a relative time (eg. 2h). Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`)
|
||||
@@ -51,7 +52,7 @@ func newConnLogsCmd(spClient client.Client) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func printLogs(logEvents *client.LogEvents, cmd *cobra.Command) error {
|
||||
func printLogs(logEvents *connclient.LogEvents, cmd *cobra.Command) error {
|
||||
rawPrint, _ := cmd.Flags().GetBool("raw")
|
||||
|
||||
if rawPrint {
|
||||
@@ -66,9 +67,9 @@ func printLogs(logEvents *client.LogEvents, cmd *cobra.Command) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getAllLogs(spClient client.Client, cmd *cobra.Command, fn func(logEvents *client.LogEvents, cmd *cobra.Command) error) error {
|
||||
func getAllLogs(spClient client.Client, cmd *cobra.Command, fn func(logEvents *connclient.LogEvents, cmd *cobra.Command) error) error {
|
||||
endpoint := cmd.Flags().Lookup("logs-endpoint").Value.String()
|
||||
lc := client.NewLogsClient(spClient, endpoint)
|
||||
lc := connclient.NewLogsClient(spClient, endpoint)
|
||||
|
||||
logInput.NextToken = ""
|
||||
for {
|
||||
@@ -97,14 +98,14 @@ func formatDates(cmd *cobra.Command) error {
|
||||
return fmt.Errorf(`must provide a "--start" time when "--stop" specified`)
|
||||
}
|
||||
if startTimeFlag != "" {
|
||||
retTime, err := client.ParseTime(startTimeFlag, now)
|
||||
retTime, err := connclient.ParseTime(startTimeFlag, now)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logInput.Filter.StartTime = &retTime
|
||||
}
|
||||
if stopTimeFlag != "" {
|
||||
retTime, err := client.ParseTime(stopTimeFlag, now)
|
||||
retTime, err := connclient.ParseTime(stopTimeFlag, now)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -114,7 +115,7 @@ func formatDates(cmd *cobra.Command) error {
|
||||
}
|
||||
|
||||
// Format log message for display
|
||||
func formatLog(logMessage client.LogMessage) string {
|
||||
func formatLog(logMessage connclient.LogMessage) string {
|
||||
green := color.New(color.FgGreen).SprintFunc()
|
||||
yellow := color.New(color.FgYellow).SprintFunc()
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
connclient "github.com/sailpoint-oss/sp-cli/cmd/connector/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -26,7 +27,7 @@ func newConnLogsTailCmd(client client.Client) *cobra.Command {
|
||||
}
|
||||
|
||||
func tailLogs(spClient client.Client, cmd *cobra.Command) error {
|
||||
handleLogs := func(logEvents *client.LogEvents, cmd *cobra.Command) error {
|
||||
handleLogs := func(logEvents *connclient.LogEvents, cmd *cobra.Command) error {
|
||||
if err := printLogs(logEvents, cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
connclient "github.com/sailpoint-oss/sp-cli/cmd/connector/client"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
@@ -36,7 +37,7 @@ func newConnStatsCmd(spClient client.Client) *cobra.Command {
|
||||
return nil
|
||||
},
|
||||
}
|
||||
cmd.PersistentFlags().StringP("stats-endpoint", "o", viper.GetString("baseurl")+client.StatsEndpoint, "Override stats endpoint")
|
||||
cmd.PersistentFlags().StringP("stats-endpoint", "o", viper.GetString("baseurl")+connclient.StatsEndpoint, "Override stats endpoint")
|
||||
cmd.Flags().StringP("duration", "d", "", `Length of time represented by an integer(1-9) and a duration unit. Supported duration units: d,w. eg 1d, 3w`)
|
||||
cmd.Flags().StringP("id", "c", "", "Connector ID")
|
||||
return cmd
|
||||
@@ -44,7 +45,7 @@ func newConnStatsCmd(spClient client.Client) *cobra.Command {
|
||||
|
||||
func getTenantStats(spClient client.Client, cmd *cobra.Command) error {
|
||||
endpoint := cmd.Flags().Lookup("stats-endpoint").Value.String()
|
||||
lc := client.NewLogsClient(spClient, endpoint)
|
||||
lc := connclient.NewLogsClient(spClient, endpoint)
|
||||
|
||||
connectorID := cmd.Flags().Lookup("id").Value.String()
|
||||
durationStr := cmd.Flags().Lookup("duration").Value.String()
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
"github.com/sailpoint-oss/sp-cli/validate"
|
||||
connvalidate "github.com/sailpoint-oss/sp-cli/cmd/connector/validate"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -25,7 +25,7 @@ func newConnValidateCmd(apiClient client.Client) *cobra.Command {
|
||||
if list {
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"ID", "Description"})
|
||||
for _, c := range validate.Checks {
|
||||
for _, c := range connvalidate.Checks {
|
||||
table.Append([]string{
|
||||
c.ID,
|
||||
c.Description,
|
||||
@@ -43,7 +43,7 @@ func newConnValidateCmd(apiClient client.Client) *cobra.Command {
|
||||
check := cmd.Flags().Lookup("check").Value.String()
|
||||
|
||||
isReadOnly, _ := strconv.ParseBool(cmd.Flags().Lookup("read-only").Value.String())
|
||||
valid := validate.NewValidator(validate.Config{
|
||||
valid := connvalidate.NewValidator(connvalidate.Config{
|
||||
Check: check,
|
||||
ReadOnly: isReadOnly,
|
||||
}, cc)
|
||||
|
||||
@@ -19,8 +19,8 @@ import (
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
connvalidate "github.com/sailpoint-oss/sp-cli/cmd/connector/validate"
|
||||
"github.com/sailpoint-oss/sp-cli/util"
|
||||
"github.com/sailpoint-oss/sp-cli/validate"
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/alessio/shellescape.v1"
|
||||
"gopkg.in/yaml.v2"
|
||||
@@ -170,7 +170,7 @@ func validateConnectors(ctx context.Context, apiClient client.Client, source Sou
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
validator := validate.NewValidator(validate.Config{
|
||||
validator := connvalidate.NewValidator(connvalidate.Config{
|
||||
Check: "",
|
||||
ReadOnly: source.ReadOnly,
|
||||
}, cc)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package validate
|
||||
package connvalidate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/kr/pretty"
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
connclient "github.com/sailpoint-oss/sp-cli/cmd/connector/client"
|
||||
)
|
||||
|
||||
var accountCreateChecks = []Check{
|
||||
@@ -16,7 +16,7 @@ var accountCreateChecks = []Check{
|
||||
RequiredCommands: []string{
|
||||
"std:account:create",
|
||||
},
|
||||
Run: func(ctx context.Context, spec *client.ConnSpec, cc *client.ConnClient, res *CheckResult) {
|
||||
Run: func(ctx context.Context, spec *connclient.ConnSpec, cc *connclient.ConnClient, res *CheckResult) {
|
||||
input := map[string]interface{}{}
|
||||
_, _, err := cc.AccountCreate(ctx, nil, input)
|
||||
if err == nil {
|
||||
@@ -33,7 +33,7 @@ var accountCreateChecks = []Check{
|
||||
"std:account:read",
|
||||
"std:account:delete",
|
||||
},
|
||||
Run: func(ctx context.Context, spec *client.ConnSpec, cc *client.ConnClient, res *CheckResult) {
|
||||
Run: func(ctx context.Context, spec *connclient.ConnSpec, cc *connclient.ConnClient, res *CheckResult) {
|
||||
input := map[string]interface{}{}
|
||||
for _, field := range spec.AccountCreateTemplate.Fields {
|
||||
if field.Required {
|
||||
@@ -79,7 +79,7 @@ var accountCreateChecks = []Check{
|
||||
"std:account:read",
|
||||
"std:account:delete",
|
||||
},
|
||||
Run: func(ctx context.Context, spec *client.ConnSpec, cc *client.ConnClient, res *CheckResult) {
|
||||
Run: func(ctx context.Context, spec *connclient.ConnSpec, cc *connclient.ConnClient, res *CheckResult) {
|
||||
input := map[string]interface{}{}
|
||||
for _, field := range spec.AccountCreateTemplate.Fields {
|
||||
input[getFieldName(field)] = genCreateField(field)
|
||||
@@ -124,7 +124,7 @@ var accountCreateChecks = []Check{
|
||||
"std:account:delete",
|
||||
"std:account:list",
|
||||
},
|
||||
Run: func(ctx context.Context, spec *client.ConnSpec, cc *client.ConnClient, res *CheckResult) {
|
||||
Run: func(ctx context.Context, spec *connclient.ConnSpec, cc *connclient.ConnClient, res *CheckResult) {
|
||||
accountsPreCreate, _, err := cc.AccountList(ctx)
|
||||
if err != nil {
|
||||
res.err(err)
|
||||
@@ -1,12 +1,12 @@
|
||||
package validate
|
||||
package connvalidate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/kr/pretty"
|
||||
"strconv"
|
||||
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
"github.com/kr/pretty"
|
||||
connclient "github.com/sailpoint-oss/sp-cli/cmd/connector/client"
|
||||
)
|
||||
|
||||
var accountReadChecks = []Check{
|
||||
@@ -18,7 +18,7 @@ var accountReadChecks = []Check{
|
||||
"std:account:read",
|
||||
"std:account:list",
|
||||
},
|
||||
Run: func(ctx context.Context, spec *client.ConnSpec, cc *client.ConnClient, res *CheckResult) {
|
||||
Run: func(ctx context.Context, spec *connclient.ConnSpec, cc *connclient.ConnClient, res *CheckResult) {
|
||||
accounts, _, err := cc.AccountList(ctx)
|
||||
if err != nil {
|
||||
res.err(err)
|
||||
@@ -55,7 +55,7 @@ var accountReadChecks = []Check{
|
||||
RequiredCommands: []string{
|
||||
"std:account:read",
|
||||
},
|
||||
Run: func(ctx context.Context, spec *client.ConnSpec, cc *client.ConnClient, res *CheckResult) {
|
||||
Run: func(ctx context.Context, spec *connclient.ConnSpec, cc *connclient.ConnClient, res *CheckResult) {
|
||||
_, _, err := cc.AccountRead(ctx, "__sailpoint__not__found__", "")
|
||||
if err == nil {
|
||||
res.errf("expected error for non-existant identity")
|
||||
@@ -69,10 +69,10 @@ var accountReadChecks = []Check{
|
||||
RequiredCommands: []string{
|
||||
"std:account:list",
|
||||
},
|
||||
Run: func(ctx context.Context, spec *client.ConnSpec, cc *client.ConnClient, res *CheckResult) {
|
||||
Run: func(ctx context.Context, spec *connclient.ConnSpec, cc *connclient.ConnClient, res *CheckResult) {
|
||||
additionalAttributes := map[string]string{}
|
||||
|
||||
attrsByName := map[string]client.AccountSchemaAttribute{}
|
||||
attrsByName := map[string]connclient.AccountSchemaAttribute{}
|
||||
for _, value := range spec.AccountSchema.Attributes {
|
||||
attrsByName[value.Name] = value
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package validate
|
||||
package connvalidate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
connclient "github.com/sailpoint-oss/sp-cli/cmd/connector/client"
|
||||
)
|
||||
|
||||
var accountUpdateChecks = []Check{
|
||||
@@ -17,7 +17,7 @@ var accountUpdateChecks = []Check{
|
||||
"std:account:list",
|
||||
"std:account:update",
|
||||
},
|
||||
Run: func(ctx context.Context, spec *client.ConnSpec, cc *client.ConnClient, res *CheckResult) {
|
||||
Run: func(ctx context.Context, spec *connclient.ConnSpec, cc *connclient.ConnClient, res *CheckResult) {
|
||||
accounts, _, err := cc.AccountList(ctx)
|
||||
if err != nil {
|
||||
res.err(err)
|
||||
@@ -38,7 +38,7 @@ var accountUpdateChecks = []Check{
|
||||
}
|
||||
change := attrChange(&acct, &attr)
|
||||
|
||||
_, _, err = cc.AccountUpdate(ctx, acct.ID(), acct.UniqueID(), []client.AttributeChange{change})
|
||||
_, _, err = cc.AccountUpdate(ctx, acct.ID(), acct.UniqueID(), []connclient.AttributeChange{change})
|
||||
if err != nil {
|
||||
res.errf("update for %q failed: %s", attr.Name, err.Error())
|
||||
continue
|
||||
@@ -72,7 +72,7 @@ var accountUpdateChecks = []Check{
|
||||
"std:account:update",
|
||||
"std:account:delete",
|
||||
},
|
||||
Run: func(ctx context.Context, spec *client.ConnSpec, cc *client.ConnClient, res *CheckResult) {
|
||||
Run: func(ctx context.Context, spec *connclient.ConnSpec, cc *connclient.ConnClient, res *CheckResult) {
|
||||
entitlementAttr := entitlementAttr(spec)
|
||||
if entitlementAttr == "" {
|
||||
res.warnf("no entitlement attribute")
|
||||
@@ -122,7 +122,7 @@ var accountUpdateChecks = []Check{
|
||||
}
|
||||
|
||||
if isAvailableForUpdating(accEntitlements, e.ID()) {
|
||||
_, _, err = cc.AccountUpdate(ctx, acct.ID(), acct.UniqueID(), []client.AttributeChange{
|
||||
_, _, err = cc.AccountUpdate(ctx, acct.ID(), acct.UniqueID(), []connclient.AttributeChange{
|
||||
{
|
||||
Op: "Add",
|
||||
Attribute: entitlementAttr,
|
||||
@@ -151,7 +151,7 @@ var accountUpdateChecks = []Check{
|
||||
res.errf("failed to get acc entitlements")
|
||||
}
|
||||
if len(accEntitlements) != 1 {
|
||||
_, _, err = cc.AccountUpdate(ctx, acct.ID(), acct.UniqueID(), []client.AttributeChange{
|
||||
_, _, err = cc.AccountUpdate(ctx, acct.ID(), acct.UniqueID(), []connclient.AttributeChange{
|
||||
{
|
||||
Op: "Remove",
|
||||
Attribute: entitlementAttr,
|
||||
@@ -1,10 +1,10 @@
|
||||
package validate
|
||||
package connvalidate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
connclient "github.com/sailpoint-oss/sp-cli/cmd/connector/client"
|
||||
)
|
||||
|
||||
var Checks = []Check{}
|
||||
@@ -24,7 +24,7 @@ type Check struct {
|
||||
|
||||
// IsDataModifier determines a checking that will modify connectors data after applying
|
||||
IsDataModifier bool
|
||||
Run func(ctx context.Context, spec *client.ConnSpec, cc *client.ConnClient, res *CheckResult)
|
||||
Run func(ctx context.Context, spec *connclient.ConnSpec, cc *connclient.ConnClient, res *CheckResult)
|
||||
// RequiredCommands represents a list of commands that use for this check
|
||||
RequiredCommands []string
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
package validate
|
||||
package connvalidate
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/kr/pretty"
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
connclient "github.com/sailpoint-oss/sp-cli/cmd/connector/client"
|
||||
)
|
||||
|
||||
var entitlementReadChecks = []Check{
|
||||
@@ -14,7 +15,7 @@ var entitlementReadChecks = []Check{
|
||||
RequiredCommands: []string{
|
||||
"std:entitlement:read",
|
||||
},
|
||||
Run: func(ctx context.Context, spec *client.ConnSpec, cc *client.ConnClient, res *CheckResult) {
|
||||
Run: func(ctx context.Context, spec *connclient.ConnSpec, cc *connclient.ConnClient, res *CheckResult) {
|
||||
_, _, err := cc.EntitlementRead(ctx, "__sailpoint__not__found__", "", "group")
|
||||
if err == nil {
|
||||
res.errf("expected error for non-existant entitlement")
|
||||
@@ -30,7 +31,7 @@ var entitlementReadChecks = []Check{
|
||||
"std:entitlement:read",
|
||||
"std:entitlement:list",
|
||||
},
|
||||
Run: func(ctx context.Context, spec *client.ConnSpec, cc *client.ConnClient, res *CheckResult) {
|
||||
Run: func(ctx context.Context, spec *connclient.ConnSpec, cc *connclient.ConnClient, res *CheckResult) {
|
||||
entitlements, _, err := cc.EntitlementList(ctx, "group")
|
||||
if err != nil {
|
||||
res.err(err)
|
||||
@@ -68,10 +69,10 @@ var entitlementReadChecks = []Check{
|
||||
RequiredCommands: []string{
|
||||
"std:entitlement:list",
|
||||
},
|
||||
Run: func(ctx context.Context, spec *client.ConnSpec, cc *client.ConnClient, res *CheckResult) {
|
||||
Run: func(ctx context.Context, spec *connclient.ConnSpec, cc *connclient.ConnClient, res *CheckResult) {
|
||||
additionalAttributes := map[string]string{}
|
||||
|
||||
attrsByName := map[string]client.EntitlementSchemaAttribute{}
|
||||
attrsByName := map[string]connclient.EntitlementSchemaAttribute{}
|
||||
for _, value := range spec.EntitlementSchemas[0].Attributes {
|
||||
attrsByName[value.Name] = value
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package validate
|
||||
package connvalidate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
connclient "github.com/sailpoint-oss/sp-cli/cmd/connector/client"
|
||||
)
|
||||
|
||||
var testConnChecks = []Check{
|
||||
@@ -15,7 +15,7 @@ var testConnChecks = []Check{
|
||||
RequiredCommands: []string{
|
||||
"std:test-connection",
|
||||
},
|
||||
Run: func(ctx context.Context, spec *client.ConnSpec, cc *client.ConnClient, res *CheckResult) {
|
||||
Run: func(ctx context.Context, spec *connclient.ConnSpec, cc *connclient.ConnClient, res *CheckResult) {
|
||||
err := cc.TestConnectionWithConfig(ctx, json.RawMessage("{}"))
|
||||
if err == nil {
|
||||
res.errf("expected test-connection failure for empty config")
|
||||
@@ -29,7 +29,7 @@ var testConnChecks = []Check{
|
||||
RequiredCommands: []string{
|
||||
"std:test-connection",
|
||||
},
|
||||
Run: func(ctx context.Context, spec *client.ConnSpec, cc *client.ConnClient, res *CheckResult) {
|
||||
Run: func(ctx context.Context, spec *connclient.ConnSpec, cc *connclient.ConnClient, res *CheckResult) {
|
||||
_, err := cc.TestConnection(ctx)
|
||||
if err != nil {
|
||||
res.err(err)
|
||||
@@ -1,4 +1,4 @@
|
||||
package validate
|
||||
package connvalidate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -9,11 +9,11 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
connclient "github.com/sailpoint-oss/sp-cli/cmd/connector/client"
|
||||
)
|
||||
|
||||
// entitlementAttr returns the attribute for entitlements
|
||||
func entitlementAttr(spec *client.ConnSpec) string {
|
||||
func entitlementAttr(spec *connclient.ConnSpec) string {
|
||||
for _, attr := range spec.AccountSchema.Attributes {
|
||||
if attr.Entitlement {
|
||||
return attr.Name
|
||||
@@ -23,7 +23,7 @@ func entitlementAttr(spec *client.ConnSpec) string {
|
||||
}
|
||||
|
||||
// accountEntitlements returns all entitlements on the account
|
||||
func accountEntitlements(account *client.Account, spec *client.ConnSpec) ([]string, error) {
|
||||
func accountEntitlements(account *connclient.Account, spec *connclient.ConnSpec) ([]string, error) {
|
||||
entitlementAttr := entitlementAttr(spec)
|
||||
if entitlementAttr == "" {
|
||||
return nil, fmt.Errorf("no entitlement attr found")
|
||||
@@ -36,7 +36,7 @@ func accountEntitlements(account *client.Account, spec *client.ConnSpec) ([]stri
|
||||
}
|
||||
|
||||
// accountHasEntitlement returns whether or not an account has a specific entitlement
|
||||
func accountHasEntitlement(account *client.Account, spec *client.ConnSpec, entitlementID string) bool {
|
||||
func accountHasEntitlement(account *connclient.Account, spec *connclient.ConnSpec, entitlementID string) bool {
|
||||
entitlements, err := accountEntitlements(account, spec)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
@@ -106,7 +106,7 @@ const (
|
||||
)
|
||||
|
||||
// genCreateField generates a value for the provided account create template field
|
||||
func genCreateField(field client.AccountCreateTemplateField) interface{} {
|
||||
func genCreateField(field connclient.AccountCreateTemplateField) interface{} {
|
||||
|
||||
// Return typed based value if the field is in deprecated format
|
||||
// TODO: Once we move away from the old format, this should also be removed
|
||||
@@ -144,7 +144,7 @@ func genCreateField(field client.AccountCreateTemplateField) interface{} {
|
||||
|
||||
// getFieldName returns the name of the field
|
||||
// TODO: This is to support both key and name base field. Once the name based filds are gone, we can remove this helper method
|
||||
func getFieldName(field client.AccountCreateTemplateField) string {
|
||||
func getFieldName(field connclient.AccountCreateTemplateField) string {
|
||||
if field.Key == "" {
|
||||
return field.Name
|
||||
}
|
||||
@@ -152,7 +152,7 @@ func getFieldName(field client.AccountCreateTemplateField) string {
|
||||
}
|
||||
|
||||
// genValueByTypeAndName generates attribute values base on field type and name
|
||||
func genValueByTypeAndName(field client.AccountCreateTemplateField) interface{} {
|
||||
func genValueByTypeAndName(field connclient.AccountCreateTemplateField) interface{} {
|
||||
switch field.Type {
|
||||
case "string":
|
||||
if getFieldName(field) == "email" || getFieldName(field) == "name" {
|
||||
@@ -236,7 +236,7 @@ func testSchema(res *CheckResult, attrName string, value interface{}, expectedMu
|
||||
|
||||
// attrChange generates an attribute change event for the provided account and
|
||||
// attribute.
|
||||
func attrChange(acct *client.Account, attr *client.AccountSchemaAttribute) client.AttributeChange {
|
||||
func attrChange(acct *connclient.Account, attr *connclient.AccountSchemaAttribute) connclient.AttributeChange {
|
||||
var op string
|
||||
switch attr.Multi {
|
||||
case true:
|
||||
@@ -268,7 +268,7 @@ func attrChange(acct *client.Account, attr *client.AccountSchemaAttribute) clien
|
||||
}
|
||||
}
|
||||
|
||||
return client.AttributeChange{
|
||||
return connclient.AttributeChange{
|
||||
Op: op,
|
||||
Attribute: attr.Name,
|
||||
Value: newValue,
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2021, SailPoint Technologies, Inc. All rights reserved.
|
||||
package validate
|
||||
package connvalidate
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -9,14 +9,14 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
connclient "github.com/sailpoint-oss/sp-cli/cmd/connector/client"
|
||||
)
|
||||
|
||||
// Validator runs checks for a specific connector
|
||||
type Validator struct {
|
||||
cfg Config
|
||||
cc *client.ConnClient
|
||||
connSpec *client.ConnSpec
|
||||
cc *connclient.ConnClient
|
||||
connSpec *connclient.ConnSpec
|
||||
}
|
||||
|
||||
// Config provides options for how the validator runs
|
||||
@@ -31,7 +31,7 @@ type Config struct {
|
||||
}
|
||||
|
||||
// NewValidator creates a new validator with provided config and ConnClient
|
||||
func NewValidator(cfg Config, cc *client.ConnClient) *Validator {
|
||||
func NewValidator(cfg Config, cc *connclient.ConnClient) *Validator {
|
||||
return &Validator{
|
||||
cfg: cfg,
|
||||
cc: cc,
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2021, SailPoint Technologies, Inc. All rights reserved.
|
||||
package cmd
|
||||
package root
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2021, SailPoint Technologies, Inc. All rights reserved.
|
||||
package cmd
|
||||
package root
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright (c) 2021, SailPoint Technologies, Inc. All rights reserved.
|
||||
|
||||
package cmd
|
||||
package root
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
transmodel "github.com/sailpoint-oss/sp-cli/cmd/transform/model"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -40,16 +41,16 @@ func newListCmd(client client.Client) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
var transforms []transform
|
||||
var transforms []transmodel.Transform
|
||||
err = json.Unmarshal(raw, &transforms)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
table := tablewriter.NewWriter(cmd.OutOrStdout())
|
||||
table.SetHeader(transformColumns)
|
||||
table.SetHeader(transmodel.TransformColumns)
|
||||
for _, v := range transforms {
|
||||
table.Append(v.transformToColumns())
|
||||
table.Append(v.TransformToColumns())
|
||||
}
|
||||
table.Render()
|
||||
|
||||
|
||||
@@ -1,118 +1,115 @@
|
||||
// Copyright (c) 2021, SailPoint Technologies, Inc. All rights reserved.
|
||||
package transform
|
||||
package transmodel
|
||||
|
||||
type transform struct {
|
||||
type Transform struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type operation struct {
|
||||
}
|
||||
|
||||
func (t transform) transformToColumns() []string {
|
||||
func (t Transform) TransformToColumns() []string {
|
||||
return []string{t.ID, t.Name}
|
||||
}
|
||||
|
||||
var transformColumns = []string{"ID", "Name"}
|
||||
var TransformColumns = []string{"ID", "Name"}
|
||||
|
||||
type attributesOfAccount struct {
|
||||
type AttributesOfAccount struct {
|
||||
AttributeName string `json:"attributeName"`
|
||||
SourceName string `json:"sourceName"`
|
||||
}
|
||||
|
||||
type accountAttribute struct {
|
||||
type AccountAttribute struct {
|
||||
Type string `json:"type"`
|
||||
Attributes attributesOfAccount `json:"attributes"`
|
||||
Attributes AttributesOfAccount `json:"attributes"`
|
||||
}
|
||||
|
||||
type attributesOfReference struct {
|
||||
type AttributesOfReference struct {
|
||||
Id string `json:"id"`
|
||||
Input accountAttribute `json:"input"`
|
||||
Input AccountAttribute `json:"input"`
|
||||
}
|
||||
|
||||
type reference struct {
|
||||
type Reference struct {
|
||||
Type string `json:"type"`
|
||||
Attributes attributesOfReference `json:"attributes"`
|
||||
Attributes AttributesOfReference `json:"attributes"`
|
||||
}
|
||||
|
||||
type transformDefinition struct {
|
||||
type TransformDefinition struct {
|
||||
Type string `json:"type"`
|
||||
Attributes interface{} `json:"attributes"`
|
||||
}
|
||||
|
||||
type attributeTransform struct {
|
||||
type AttributeTransform struct {
|
||||
IdentityAttributeName string `json:"identityAttributeName"`
|
||||
TransformDefinition transformDefinition `json:"transformDefinition"`
|
||||
TransformDefinition TransformDefinition `json:"transformDefinition"`
|
||||
}
|
||||
|
||||
type attributeTransformPreview struct {
|
||||
type AttributeTransformPreview struct {
|
||||
AttributeName string `json:"attributeName"`
|
||||
Attributes attributesOfReference `json:"attributes"`
|
||||
Attributes AttributesOfReference `json:"attributes"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type previewBodyImplicit struct {
|
||||
AttributeTransforms []attributeTransformPreview `json:"attributeTransforms"`
|
||||
type PreviewBodyImplicit struct {
|
||||
AttributeTransforms []AttributeTransformPreview `json:"attributeTransforms"`
|
||||
}
|
||||
|
||||
type previewBodyExplicit struct {
|
||||
type PreviewBodyExplicit struct {
|
||||
AttributeTransforms []map[string]interface{} `json:"attributeTransforms"`
|
||||
}
|
||||
|
||||
type identityAttributeConfig struct {
|
||||
AttributeTransforms []attributeTransform `json:"attributeTransforms"`
|
||||
type IdentityAttributeConfig struct {
|
||||
AttributeTransforms []AttributeTransform `json:"attributeTransforms"`
|
||||
}
|
||||
|
||||
type objectRef struct {
|
||||
type ObjectRef struct {
|
||||
Type string `json:"type"`
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
type identityProfile struct {
|
||||
AuthoritativeSource objectRef `json:"authoritativeSource"`
|
||||
IdentityAttributeConfig identityAttributeConfig `json:"identityAttributeConfig"`
|
||||
type IdentityProfile struct {
|
||||
AuthoritativeSource ObjectRef `json:"authoritativeSource"`
|
||||
IdentityAttributeConfig IdentityAttributeConfig `json:"identityAttributeConfig"`
|
||||
}
|
||||
|
||||
type previewAttribute struct {
|
||||
type PreviewAttribute struct {
|
||||
Name string `json:"name"`
|
||||
PreviousValue string `json:"previousValue"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
type previewResponse struct {
|
||||
PreviewAttributes []previewAttribute `json:"previewAttributes"`
|
||||
type PreviewResponse struct {
|
||||
PreviewAttributes []PreviewAttribute `json:"previewAttributes"`
|
||||
}
|
||||
|
||||
type user struct {
|
||||
type User struct {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
func makeAttributesOfAccount(data interface{}) attributesOfAccount {
|
||||
func MakeAttributesOfAccount(data interface{}) AttributesOfAccount {
|
||||
m := data.(map[string]interface{})
|
||||
attribute := attributesOfAccount{}
|
||||
attribute := AttributesOfAccount{}
|
||||
attribute.AttributeName = m["attributeName"].(string)
|
||||
attribute.SourceName = m["sourceName"].(string)
|
||||
return attribute
|
||||
}
|
||||
|
||||
func makeAccountAttribute(data interface{}) accountAttribute {
|
||||
func MakeAccountAttribute(data interface{}) AccountAttribute {
|
||||
m := data.(map[string]interface{})
|
||||
account := accountAttribute{}
|
||||
account := AccountAttribute{}
|
||||
account.Type = m["type"].(string)
|
||||
account.Attributes = makeAttributesOfAccount(m["attributes"])
|
||||
account.Attributes = MakeAttributesOfAccount(m["attributes"])
|
||||
return account
|
||||
}
|
||||
|
||||
func makeReference(data interface{}) attributesOfReference {
|
||||
func MakeReference(data interface{}) AttributesOfReference {
|
||||
m := data.(map[string]interface{})
|
||||
reference := attributesOfReference{}
|
||||
reference := AttributesOfReference{}
|
||||
reference.Id = m["id"].(string)
|
||||
reference.Input = makeAccountAttribute(m["input"])
|
||||
reference.Input = MakeAccountAttribute(m["input"])
|
||||
return reference
|
||||
}
|
||||
|
||||
func makePreviewBodyImplicit(identityAttribute string, transformName string, accountAttribute string, sourceName string) previewBodyImplicit {
|
||||
attributeTransform := attributeTransformPreview{}
|
||||
func MakePreviewBodyImplicit(identityAttribute string, transformName string, accountAttribute string, sourceName string) PreviewBodyImplicit {
|
||||
attributeTransform := AttributeTransformPreview{}
|
||||
attributeTransform.AttributeName = identityAttribute
|
||||
attributeTransform.Attributes.Id = transformName
|
||||
attributeTransform.Attributes.Input.Type = "accountAttribute"
|
||||
@@ -120,16 +117,16 @@ func makePreviewBodyImplicit(identityAttribute string, transformName string, acc
|
||||
attributeTransform.Attributes.Input.Attributes.SourceName = sourceName
|
||||
attributeTransform.Type = "reference"
|
||||
|
||||
previewBody := previewBodyImplicit{}
|
||||
previewBody := PreviewBodyImplicit{}
|
||||
previewBody.AttributeTransforms = append(previewBody.AttributeTransforms, attributeTransform)
|
||||
|
||||
return previewBody
|
||||
}
|
||||
|
||||
func makePreviewBodyExplicit(identityAttribute string, transformData map[string]interface{}) previewBodyExplicit {
|
||||
func MakePreviewBodyExplicit(identityAttribute string, transformData map[string]interface{}) PreviewBodyExplicit {
|
||||
transformData["attributeName"] = identityAttribute
|
||||
|
||||
previewBody := previewBodyExplicit{}
|
||||
previewBody := PreviewBodyExplicit{}
|
||||
previewBody.AttributeTransforms = append(previewBody.AttributeTransforms, transformData)
|
||||
|
||||
return previewBody
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
transmodel "github.com/sailpoint-oss/sp-cli/cmd/transform/model"
|
||||
"github.com/sailpoint-oss/sp-cli/util"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
@@ -83,7 +84,7 @@ func newPreviewCmd(client client.Client) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
var profile identityProfile
|
||||
var profile transmodel.IdentityProfile
|
||||
err = json.Unmarshal(raw, &profile)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -119,7 +120,7 @@ func newPreviewCmd(client client.Client) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
var user []user
|
||||
var user []transmodel.User
|
||||
err = json.Unmarshal(raw, &user)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -141,11 +142,11 @@ func newPreviewCmd(client client.Client) *cobra.Command {
|
||||
if t.IdentityAttributeName == attribute {
|
||||
transType := t.TransformDefinition.Type
|
||||
if transType == "accountAttribute" {
|
||||
def := makeAttributesOfAccount(t.TransformDefinition.Attributes)
|
||||
def := transmodel.MakeAttributesOfAccount(t.TransformDefinition.Attributes)
|
||||
accountAttName = def.AttributeName
|
||||
sourceName = def.SourceName
|
||||
} else if transType == "reference" {
|
||||
def := makeReference(t.TransformDefinition.Attributes)
|
||||
def := transmodel.MakeReference(t.TransformDefinition.Attributes)
|
||||
accountAttName = def.Input.Attributes.AttributeName
|
||||
sourceName = def.Input.Attributes.SourceName
|
||||
} else {
|
||||
@@ -160,14 +161,14 @@ func newPreviewCmd(client client.Client) *cobra.Command {
|
||||
return fmt.Errorf("The transform name must be specified when previewing with implicit input.")
|
||||
}
|
||||
|
||||
previewBody := makePreviewBodyImplicit(attribute, name, accountAttName, sourceName)
|
||||
previewBody := transmodel.MakePreviewBodyImplicit(attribute, name, accountAttName, sourceName)
|
||||
|
||||
previewBodyRaw, err = json.Marshal(previewBody)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
previewBody := makePreviewBodyExplicit(attribute, transform)
|
||||
previewBody := transmodel.MakePreviewBodyExplicit(attribute, transform)
|
||||
|
||||
previewBodyRaw, err = json.Marshal(previewBody)
|
||||
if err != nil {
|
||||
@@ -195,7 +196,7 @@ func newPreviewCmd(client client.Client) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
var response previewResponse
|
||||
var response transmodel.PreviewResponse
|
||||
err = json.Unmarshal(raw, &response)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
5
main.go
5
main.go
@@ -4,8 +4,9 @@ package main
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/sailpoint-oss/sp-cli/client"
|
||||
"github.com/sailpoint-oss/sp-cli/cmd"
|
||||
"github.com/sailpoint-oss/sp-cli/cmd/root"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
@@ -45,7 +46,7 @@ func init() {
|
||||
Debug: viper.GetBool("debug"),
|
||||
})
|
||||
|
||||
rootCmd = cmd.NewRootCmd(c)
|
||||
rootCmd = root.NewRootCmd(c)
|
||||
}
|
||||
|
||||
// main the entry point for commands. Note that we do not need to do cobra.CheckErr(err)
|
||||
|
||||
Reference in New Issue
Block a user