CLI connect refactor (#3213)

Move code for connecting to a repo into a common
package so that backup and restore CLI code can
both use it

This will also make it easier for maintenance
code in the future as it can reuse the same
helper

There are no logic changes in this PR, only
code movement

---

#### Does this PR need a docs update or release note?

- [ ]  Yes, it's included
- [ ] 🕐 Yes, but in a later PR
- [x]  No

#### Type of change

- [ ] 🌻 Feature
- [ ] 🐛 Bugfix
- [ ] 🗺️ Documentation
- [ ] 🤖 Supportability/Tests
- [ ] 💻 CI/Deployment
- [x] 🧹 Tech Debt/Cleanup

#### Issue(s)
tangentially related to
* #3077

#### Test Plan

- [ ] 💪 Manual
- [x]  Unit test
- [ ] 💚 E2E
This commit is contained in:
ashmrtn 2023-04-25 11:35:50 -07:00 committed by GitHub
parent 51809cf6eb
commit 8a2e63dcad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 59 additions and 83 deletions

View File

@ -9,13 +9,10 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/alcionai/corso/src/cli/config"
"github.com/alcionai/corso/src/cli/options"
. "github.com/alcionai/corso/src/cli/print"
"github.com/alcionai/corso/src/cli/utils"
"github.com/alcionai/corso/src/internal/common/idname"
"github.com/alcionai/corso/src/internal/data"
"github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/backup"
"github.com/alcionai/corso/src/pkg/logger"
"github.com/alcionai/corso/src/pkg/path"
@ -270,7 +267,7 @@ func genericDeleteCommand(cmd *cobra.Command, bID, designation string, args []st
ctx := clues.Add(cmd.Context(), "delete_backup_id", bID)
r, _, err := getAccountAndConnect(ctx)
r, _, err := utils.GetAccountAndConnect(ctx)
if err != nil {
return Only(ctx, err)
}
@ -291,7 +288,7 @@ func genericDeleteCommand(cmd *cobra.Command, bID, designation string, args []st
func genericListCommand(cmd *cobra.Command, bID string, service path.ServiceType, args []string) error {
ctx := cmd.Context()
r, _, err := getAccountAndConnect(ctx)
r, _, err := utils.GetAccountAndConnect(ctx)
if err != nil {
return Only(ctx, err)
}
@ -324,20 +321,6 @@ func genericListCommand(cmd *cobra.Command, bID string, service path.ServiceType
return nil
}
func getAccountAndConnect(ctx context.Context) (repository.Repository, *account.Account, error) {
cfg, err := config.GetConfigRepoDetails(ctx, true, nil)
if err != nil {
return nil, nil, err
}
r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, options.Control())
if err != nil {
return nil, nil, clues.Wrap(err, "Failed to connect to the "+cfg.Storage.Provider.String()+" repository")
}
return r, &cfg.Account, nil
}
func ifShow(flag string) bool {
return strings.ToLower(strings.TrimSpace(flag)) == "show"
}

View File

@ -153,7 +153,7 @@ func createExchangeCmd(cmd *cobra.Command, args []string) error {
return err
}
r, acct, err := getAccountAndConnect(ctx)
r, acct, err := utils.GetAccountAndConnect(ctx)
if err != nil {
return Only(ctx, err)
}
@ -265,7 +265,7 @@ func detailsExchangeCmd(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
opts := utils.MakeExchangeOpts(cmd)
r, _, err := getAccountAndConnect(ctx)
r, _, err := utils.GetAccountAndConnect(ctx)
if err != nil {
return Only(ctx, err)
}

View File

@ -135,7 +135,7 @@ func createOneDriveCmd(cmd *cobra.Command, args []string) error {
return err
}
r, acct, err := getAccountAndConnect(ctx)
r, acct, err := utils.GetAccountAndConnect(ctx)
if err != nil {
return Only(ctx, err)
}
@ -224,7 +224,7 @@ func detailsOneDriveCmd(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
opts := utils.MakeOneDriveOpts(cmd)
r, _, err := getAccountAndConnect(ctx)
r, _, err := utils.GetAccountAndConnect(ctx)
if err != nil {
return Only(ctx, err)
}

View File

@ -146,7 +146,7 @@ func createSharePointCmd(cmd *cobra.Command, args []string) error {
return err
}
r, acct, err := getAccountAndConnect(ctx)
r, acct, err := utils.GetAccountAndConnect(ctx)
if err != nil {
return Only(ctx, err)
}
@ -308,7 +308,7 @@ func detailsSharePointCmd(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
opts := utils.MakeSharePointOpts(cmd)
r, _, err := getAccountAndConnect(ctx)
r, _, err := utils.GetAccountAndConnect(ctx)
if err != nil {
return Only(ctx, err)
}

View File

@ -6,7 +6,6 @@ import (
"github.com/alcionai/clues"
"github.com/spf13/viper"
"github.com/alcionai/corso/src/cli/utils"
"github.com/alcionai/corso/src/internal/common"
"github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/credentials"
@ -72,7 +71,7 @@ func configureAccount(
}
// ensure required properties are present
if err := utils.RequireProps(map[string]string{
if err := requireProps(map[string]string{
credentials.AzureClientID: m365Cfg.AzureClientID,
credentials.AzureClientSecret: m365Cfg.AzureClientSecret,
account.AzureTenantID: m365Cfg.AzureTenantID,

View File

@ -321,3 +321,15 @@ func mustMatchConfig(vpr *viper.Viper, m map[string]string) error {
return nil
}
// requireProps validates the existence of the properties
// in the map. Expects the format map[propName]propVal.
func requireProps(props map[string]string) error {
for name, val := range props {
if len(val) == 0 {
return clues.New(name + " is required to perform this command")
}
}
return nil
}

View File

@ -39,6 +39,27 @@ func TestConfigSuite(t *testing.T) {
suite.Run(t, &ConfigSuite{Suite: tester.NewUnitSuite(t)})
}
func (suite *ConfigSuite) TestRequireProps() {
table := []struct {
name string
props map[string]string
errCheck assert.ErrorAssertionFunc
}{
{
props: map[string]string{"exists": "I have seen the fnords!"},
errCheck: assert.NoError,
},
{
props: map[string]string{"not-exists": ""},
errCheck: assert.Error,
},
}
for _, test := range table {
err := requireProps(test.props)
test.errCheck(suite.T(), err, clues.ToCore(err))
}
}
func (suite *ConfigSuite) TestReadRepoConfigBasic() {
var (
t = suite.T()

View File

@ -9,7 +9,6 @@ import (
"github.com/aws/aws-sdk-go/aws/defaults"
"github.com/spf13/viper"
"github.com/alcionai/corso/src/cli/utils"
"github.com/alcionai/corso/src/internal/common"
"github.com/alcionai/corso/src/pkg/credentials"
"github.com/alcionai/corso/src/pkg/storage"
@ -112,7 +111,7 @@ func configureStorage(
}
// ensure required properties are present
if err := utils.RequireProps(map[string]string{
if err := requireProps(map[string]string{
storage.Bucket: s3Cfg.Bucket,
credentials.CorsoPassphrase: corso.CorsoPassphrase,
}); err != nil {

View File

@ -6,14 +6,12 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/alcionai/corso/src/cli/config"
"github.com/alcionai/corso/src/cli/options"
. "github.com/alcionai/corso/src/cli/print"
"github.com/alcionai/corso/src/cli/utils"
"github.com/alcionai/corso/src/internal/common"
"github.com/alcionai/corso/src/internal/data"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/repository"
)
// called by restore.go to map subcommands to provider-specific handling.
@ -90,16 +88,11 @@ func restoreExchangeCmd(cmd *cobra.Command, args []string) error {
return err
}
cfg, err := config.GetConfigRepoDetails(ctx, true, nil)
r, _, err := utils.GetAccountAndConnect(ctx)
if err != nil {
return Only(ctx, err)
}
r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, options.Control())
if err != nil {
return Only(ctx, clues.Wrap(err, "Failed to connect to the "+cfg.Storage.Provider.String()+" repository"))
}
defer utils.CloseRepo(ctx, r)
dest := control.DefaultRestoreDestination(common.SimpleDateTime)

View File

@ -6,14 +6,12 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/alcionai/corso/src/cli/config"
"github.com/alcionai/corso/src/cli/options"
. "github.com/alcionai/corso/src/cli/print"
"github.com/alcionai/corso/src/cli/utils"
"github.com/alcionai/corso/src/internal/common"
"github.com/alcionai/corso/src/internal/data"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/repository"
)
// called by restore.go to map subcommands to provider-specific handling.
@ -92,16 +90,11 @@ func restoreOneDriveCmd(cmd *cobra.Command, args []string) error {
return err
}
cfg, err := config.GetConfigRepoDetails(ctx, true, nil)
r, _, err := utils.GetAccountAndConnect(ctx)
if err != nil {
return Only(ctx, err)
}
r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, options.Control())
if err != nil {
return Only(ctx, clues.Wrap(err, "Failed to connect to the "+cfg.Storage.Provider.String()+" repository"))
}
defer utils.CloseRepo(ctx, r)
dest := control.DefaultRestoreDestination(common.SimpleDateTimeOneDrive)

View File

@ -6,14 +6,12 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/alcionai/corso/src/cli/config"
"github.com/alcionai/corso/src/cli/options"
. "github.com/alcionai/corso/src/cli/print"
"github.com/alcionai/corso/src/cli/utils"
"github.com/alcionai/corso/src/internal/common"
"github.com/alcionai/corso/src/internal/data"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/repository"
)
// called by restore.go to map subcommands to provider-specific handling.
@ -91,16 +89,11 @@ func restoreSharePointCmd(cmd *cobra.Command, args []string) error {
return err
}
cfg, err := config.GetConfigRepoDetails(ctx, true, nil)
r, _, err := utils.GetAccountAndConnect(ctx)
if err != nil {
return Only(ctx, err)
}
r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, options.Control())
if err != nil {
return Only(ctx, clues.Wrap(err, "Failed to connect to the "+cfg.Storage.Provider.String()+" repository"))
}
defer utils.CloseRepo(ctx, r)
dest := control.DefaultRestoreDestination(common.SimpleDateTimeOneDrive)

View File

@ -8,7 +8,10 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/alcionai/corso/src/cli/config"
"github.com/alcionai/corso/src/cli/options"
"github.com/alcionai/corso/src/internal/events"
"github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/logger"
"github.com/alcionai/corso/src/pkg/path"
@ -21,16 +24,18 @@ const (
Wildcard = "*"
)
// RequireProps validates the existence of the properties
// in the map. Expects the format map[propName]propVal.
func RequireProps(props map[string]string) error {
for name, val := range props {
if len(val) == 0 {
return clues.New(name + " is required to perform this command")
}
func GetAccountAndConnect(ctx context.Context) (repository.Repository, *account.Account, error) {
cfg, err := config.GetConfigRepoDetails(ctx, true, nil)
if err != nil {
return nil, nil, err
}
return nil
r, err := repository.Connect(ctx, cfg.Account, cfg.Storage, options.Control())
if err != nil {
return nil, nil, clues.Wrap(err, "Failed to connect to the "+cfg.Storage.Provider.String()+" repository")
}
return r, &cfg.Account, nil
}
// CloseRepo handles closing a repo.

View File

@ -3,7 +3,6 @@ package utils
import (
"testing"
"github.com/alcionai/clues"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
@ -19,27 +18,6 @@ func TestCliUtilsSuite(t *testing.T) {
suite.Run(t, &CliUtilsSuite{Suite: tester.NewUnitSuite(t)})
}
func (suite *CliUtilsSuite) TestRequireProps() {
table := []struct {
name string
props map[string]string
errCheck assert.ErrorAssertionFunc
}{
{
props: map[string]string{"exists": "I have seen the fnords!"},
errCheck: assert.NoError,
},
{
props: map[string]string{"not-exists": ""},
errCheck: assert.Error,
},
}
for _, test := range table {
err := RequireProps(test.props)
test.errCheck(suite.T(), err, clues.ToCore(err))
}
}
func (suite *CliUtilsSuite) TestSplitFoldersIntoContainsAndPrefix() {
table := []struct {
name string