allow delete of multiple backup IDs (#4335)
<!-- PR description--> allow deletion of multiple IDs in single command #### Does this PR need a docs update or release note? - [ ] ✅ Yes, it's included - [ ] 🕐 Yes, but in a later PR - [ ] ⛔ No #### Type of change <!--- Please check the type of change your PR introduces: ---> - [ ] 🌻 Feature #### Issue(s) <!-- Can reference multiple issues. Use one of the following "magic words" - "closes, fixes" to auto-close the Github issue. --> * https://github.com/alcionai/corso/issues/4119 #### Test Plan <!-- How will this be tested prior to merging.--> - [ ] 💪 Manual - [ ] 💚 E2E
This commit is contained in:
parent
5c4419fdc0
commit
adbc7fe03e
@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Enables local or network-attached storage for Corso repositories.
|
- Enables local or network-attached storage for Corso repositories.
|
||||||
- Reduce backup runtime for OneDrive and SharePoint incremental backups that have no file changes.
|
- Reduce backup runtime for OneDrive and SharePoint incremental backups that have no file changes.
|
||||||
- Increase Exchange backup performance by lazily fetching data only for items whose content changed.
|
- Increase Exchange backup performance by lazily fetching data only for items whose content changed.
|
||||||
|
- Added `--backups` flag to delete multiple backups in `corso backup delete` command.
|
||||||
|
|
||||||
## [v0.13.0] (beta) - 2023-09-18
|
## [v0.13.0] (beta) - 2023-09-18
|
||||||
|
|
||||||
|
|||||||
@ -252,8 +252,8 @@ func runBackups(
|
|||||||
func genericDeleteCommand(
|
func genericDeleteCommand(
|
||||||
cmd *cobra.Command,
|
cmd *cobra.Command,
|
||||||
pst path.ServiceType,
|
pst path.ServiceType,
|
||||||
bID, designation string,
|
designation string,
|
||||||
args []string,
|
bID, args []string,
|
||||||
) error {
|
) error {
|
||||||
if utils.HasNoFlagsAndShownHelp(cmd) {
|
if utils.HasNoFlagsAndShownHelp(cmd) {
|
||||||
return nil
|
return nil
|
||||||
@ -275,11 +275,11 @@ func genericDeleteCommand(
|
|||||||
|
|
||||||
defer utils.CloseRepo(ctx, r)
|
defer utils.CloseRepo(ctx, r)
|
||||||
|
|
||||||
if err := r.DeleteBackups(ctx, true, bID); err != nil {
|
if err := r.DeleteBackups(ctx, true, bID...); err != nil {
|
||||||
return Only(ctx, clues.Wrap(err, "Deleting backup "+bID))
|
return Only(ctx, clues.Wrap(err, fmt.Sprintf("Deleting backup %v", bID)))
|
||||||
}
|
}
|
||||||
|
|
||||||
Infof(ctx, "Deleted %s backup %s", designation, bID)
|
Infof(ctx, "Deleted %s backup %v", designation, bID)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,7 +32,7 @@ const (
|
|||||||
const (
|
const (
|
||||||
exchangeServiceCommand = "exchange"
|
exchangeServiceCommand = "exchange"
|
||||||
exchangeServiceCommandCreateUseSuffix = "--mailbox <email> | '" + flags.Wildcard + "'"
|
exchangeServiceCommandCreateUseSuffix = "--mailbox <email> | '" + flags.Wildcard + "'"
|
||||||
exchangeServiceCommandDeleteUseSuffix = "--backup <backupId>"
|
exchangeServiceCommandDeleteUseSuffix = "--backups <backupId>"
|
||||||
exchangeServiceCommandDetailsUseSuffix = "--backup <backupId>"
|
exchangeServiceCommandDetailsUseSuffix = "--backup <backupId>"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -46,8 +46,9 @@ corso backup create exchange --mailbox alice@example.com,bob@example.com --data
|
|||||||
# Backup all Exchange data for all M365 users
|
# Backup all Exchange data for all M365 users
|
||||||
corso backup create exchange --mailbox '*'`
|
corso backup create exchange --mailbox '*'`
|
||||||
|
|
||||||
exchangeServiceCommandDeleteExamples = `# Delete Exchange backup with ID 1234abcd-12ab-cd34-56de-1234abcd
|
exchangeServiceCommandDeleteExamples = `# Delete Exchange backup with IDs 1234abcd-12ab-cd34-56de-1234abcd \
|
||||||
corso backup delete exchange --backup 1234abcd-12ab-cd34-56de-1234abcd`
|
and 1234abcd-12ab-cd34-56de-1234abce
|
||||||
|
corso backup delete exchange --backups 1234abcd-12ab-cd34-56de-1234abcd,1234abcd-12ab-cd34-56de-1234abce`
|
||||||
|
|
||||||
exchangeServiceCommandDetailsExamples = `# Explore items in Alice's latest backup (1234abcd...)
|
exchangeServiceCommandDetailsExamples = `# Explore items in Alice's latest backup (1234abcd...)
|
||||||
corso backup details exchange --backup 1234abcd-12ab-cd34-56de-1234abcd
|
corso backup details exchange --backup 1234abcd-12ab-cd34-56de-1234abcd
|
||||||
@ -121,7 +122,8 @@ func addExchangeCommands(cmd *cobra.Command) *cobra.Command {
|
|||||||
c.Use = c.Use + " " + exchangeServiceCommandDeleteUseSuffix
|
c.Use = c.Use + " " + exchangeServiceCommandDeleteUseSuffix
|
||||||
c.Example = exchangeServiceCommandDeleteExamples
|
c.Example = exchangeServiceCommandDeleteExamples
|
||||||
|
|
||||||
flags.AddBackupIDFlag(c, true)
|
flags.AddMultipleBackupIDsFlag(c, false)
|
||||||
|
flags.AddBackupIDFlag(c, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
@ -352,5 +354,15 @@ func exchangeDeleteCmd() *cobra.Command {
|
|||||||
|
|
||||||
// deletes an exchange service backup.
|
// deletes an exchange service backup.
|
||||||
func deleteExchangeCmd(cmd *cobra.Command, args []string) error {
|
func deleteExchangeCmd(cmd *cobra.Command, args []string) error {
|
||||||
return genericDeleteCommand(cmd, path.ExchangeService, flags.BackupIDFV, "Exchange", args)
|
var backupIDValue []string
|
||||||
|
|
||||||
|
if len(flags.BackupIDsFV) > 0 {
|
||||||
|
backupIDValue = flags.BackupIDsFV
|
||||||
|
} else if len(flags.BackupIDFV) > 0 {
|
||||||
|
backupIDValue = append(backupIDValue, flags.BackupIDFV)
|
||||||
|
} else {
|
||||||
|
return clues.New("either --backup or --backups flag is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return genericDeleteCommand(cmd, path.ExchangeService, "Exchange", backupIDValue, args)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -563,6 +563,7 @@ type BackupDeleteExchangeE2ESuite struct {
|
|||||||
tester.Suite
|
tester.Suite
|
||||||
dpnd dependencies
|
dpnd dependencies
|
||||||
backupOp operations.BackupOperation
|
backupOp operations.BackupOperation
|
||||||
|
secondaryBackupOp operations.BackupOperation
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBackupDeleteExchangeE2ESuite(t *testing.T) {
|
func TestBackupDeleteExchangeE2ESuite(t *testing.T) {
|
||||||
@ -595,6 +596,14 @@ func (suite *BackupDeleteExchangeE2ESuite) SetupSuite() {
|
|||||||
|
|
||||||
err = suite.backupOp.Run(ctx)
|
err = suite.backupOp.Run(ctx)
|
||||||
require.NoError(t, err, clues.ToCore(err))
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
backupOp2, err := suite.dpnd.repo.NewBackup(ctx, sel.Selector)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
suite.secondaryBackupOp = backupOp2
|
||||||
|
|
||||||
|
err = suite.secondaryBackupOp.Run(ctx)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *BackupDeleteExchangeE2ESuite) TestExchangeBackupDeleteCmd() {
|
func (suite *BackupDeleteExchangeE2ESuite) TestExchangeBackupDeleteCmd() {
|
||||||
@ -608,7 +617,10 @@ func (suite *BackupDeleteExchangeE2ESuite) TestExchangeBackupDeleteCmd() {
|
|||||||
cmd := cliTD.StubRootCmd(
|
cmd := cliTD.StubRootCmd(
|
||||||
"backup", "delete", "exchange",
|
"backup", "delete", "exchange",
|
||||||
"--config-file", suite.dpnd.configFilePath,
|
"--config-file", suite.dpnd.configFilePath,
|
||||||
"--"+flags.BackupFN, string(suite.backupOp.Results.BackupID))
|
"--"+flags.BackupIDsFN,
|
||||||
|
fmt.Sprintf("%s,%s",
|
||||||
|
string(suite.backupOp.Results.BackupID),
|
||||||
|
string(suite.secondaryBackupOp.Results.BackupID)))
|
||||||
cli.BuildCommandTree(cmd)
|
cli.BuildCommandTree(cmd)
|
||||||
|
|
||||||
// run the command
|
// run the command
|
||||||
@ -624,6 +636,46 @@ func (suite *BackupDeleteExchangeE2ESuite) TestExchangeBackupDeleteCmd() {
|
|||||||
|
|
||||||
err = cmd.ExecuteContext(ctx)
|
err = cmd.ExecuteContext(ctx)
|
||||||
require.Error(t, err, clues.ToCore(err))
|
require.Error(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
// a follow-up details call should fail, due to the backup ID being deleted
|
||||||
|
cmd = cliTD.StubRootCmd(
|
||||||
|
"backup", "details", "exchange",
|
||||||
|
"--config-file", suite.dpnd.configFilePath,
|
||||||
|
"--backup", string(suite.secondaryBackupOp.Results.BackupID))
|
||||||
|
cli.BuildCommandTree(cmd)
|
||||||
|
|
||||||
|
err = cmd.ExecuteContext(ctx)
|
||||||
|
require.Error(t, err, clues.ToCore(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *BackupDeleteExchangeE2ESuite) TestExchangeBackupDeleteCmd_SingleID() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
ctx, flush := tester.NewContext(t)
|
||||||
|
ctx = config.SetViper(ctx, suite.dpnd.vpr)
|
||||||
|
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
cmd := cliTD.StubRootCmd(
|
||||||
|
"backup", "delete", "exchange",
|
||||||
|
"--config-file", suite.dpnd.configFilePath,
|
||||||
|
"--"+flags.BackupFN,
|
||||||
|
string(suite.backupOp.Results.BackupID))
|
||||||
|
cli.BuildCommandTree(cmd)
|
||||||
|
|
||||||
|
// run the command
|
||||||
|
err := cmd.ExecuteContext(ctx)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
// a follow-up details call should fail, due to the backup ID being deleted
|
||||||
|
cmd = cliTD.StubRootCmd(
|
||||||
|
"backup", "details", "exchange",
|
||||||
|
"--config-file", suite.dpnd.configFilePath,
|
||||||
|
"--backup", string(suite.secondaryBackupOp.Results.BackupID))
|
||||||
|
cli.BuildCommandTree(cmd)
|
||||||
|
|
||||||
|
err = cmd.ExecuteContext(ctx)
|
||||||
|
require.Error(t, err, clues.ToCore(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *BackupDeleteExchangeE2ESuite) TestExchangeBackupDeleteCmd_UnknownID() {
|
func (suite *BackupDeleteExchangeE2ESuite) TestExchangeBackupDeleteCmd_UnknownID() {
|
||||||
@ -637,10 +689,28 @@ func (suite *BackupDeleteExchangeE2ESuite) TestExchangeBackupDeleteCmd_UnknownID
|
|||||||
cmd := cliTD.StubRootCmd(
|
cmd := cliTD.StubRootCmd(
|
||||||
"backup", "delete", "exchange",
|
"backup", "delete", "exchange",
|
||||||
"--config-file", suite.dpnd.configFilePath,
|
"--config-file", suite.dpnd.configFilePath,
|
||||||
"--"+flags.BackupFN, uuid.NewString())
|
"--"+flags.BackupIDsFN, uuid.NewString())
|
||||||
cli.BuildCommandTree(cmd)
|
cli.BuildCommandTree(cmd)
|
||||||
|
|
||||||
// unknown backupIDs should error since the modelStore can't find the backup
|
// unknown backupIDs should error since the modelStore can't find the backup
|
||||||
err := cmd.ExecuteContext(ctx)
|
err := cmd.ExecuteContext(ctx)
|
||||||
require.Error(t, err, clues.ToCore(err))
|
require.Error(t, err, clues.ToCore(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *BackupDeleteExchangeE2ESuite) TestExchangeBackupDeleteCmd_NoBackupID() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
ctx, flush := tester.NewContext(t)
|
||||||
|
ctx = config.SetViper(ctx, suite.dpnd.vpr)
|
||||||
|
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
cmd := cliTD.StubRootCmd(
|
||||||
|
"backup", "delete", "exchange",
|
||||||
|
"--config-file", suite.dpnd.configFilePath)
|
||||||
|
cli.BuildCommandTree(cmd)
|
||||||
|
|
||||||
|
// empty backupIDs should error since no data provided
|
||||||
|
err := cmd.ExecuteContext(ctx)
|
||||||
|
require.Error(t, err, clues.ToCore(err))
|
||||||
|
}
|
||||||
|
|||||||
@ -32,7 +32,7 @@ const (
|
|||||||
groupsServiceCommand = "groups"
|
groupsServiceCommand = "groups"
|
||||||
teamsServiceCommand = "teams"
|
teamsServiceCommand = "teams"
|
||||||
groupsServiceCommandCreateUseSuffix = "--group <groupName> | '" + flags.Wildcard + "'"
|
groupsServiceCommandCreateUseSuffix = "--group <groupName> | '" + flags.Wildcard + "'"
|
||||||
groupsServiceCommandDeleteUseSuffix = "--backup <backupId>"
|
groupsServiceCommandDeleteUseSuffix = "--backups <backupId>"
|
||||||
groupsServiceCommandDetailsUseSuffix = "--backup <backupId>"
|
groupsServiceCommandDetailsUseSuffix = "--backup <backupId>"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -46,8 +46,9 @@ corso backup create groups --group Marketing --data messages
|
|||||||
# Backup all Groups and Teams data for all groups
|
# Backup all Groups and Teams data for all groups
|
||||||
corso backup create groups --group '*'`
|
corso backup create groups --group '*'`
|
||||||
|
|
||||||
groupsServiceCommandDeleteExamples = `# Delete Groups backup with ID 1234abcd-12ab-cd34-56de-1234abcd
|
groupsServiceCommandDeleteExamples = `# Delete Groups backup with ID 1234abcd-12ab-cd34-56de-1234abcd \
|
||||||
corso backup delete groups --backup 1234abcd-12ab-cd34-56de-1234abcd`
|
and 1234abcd-12ab-cd34-56de-1234abce
|
||||||
|
corso backup delete groups --backups 1234abcd-12ab-cd34-56de-1234abcd,1234abcd-12ab-cd34-56de-1234abce`
|
||||||
|
|
||||||
groupsServiceCommandDetailsExamples = `# Explore items in Marketing's latest backup (1234abcd...)
|
groupsServiceCommandDetailsExamples = `# Explore items in Marketing's latest backup (1234abcd...)
|
||||||
corso backup details groups --backup 1234abcd-12ab-cd34-56de-1234abcd
|
corso backup details groups --backup 1234abcd-12ab-cd34-56de-1234abcd
|
||||||
@ -110,7 +111,8 @@ func addGroupsCommands(cmd *cobra.Command) *cobra.Command {
|
|||||||
c.Use = c.Use + " " + groupsServiceCommandDeleteUseSuffix
|
c.Use = c.Use + " " + groupsServiceCommandDeleteUseSuffix
|
||||||
c.Example = groupsServiceCommandDeleteExamples
|
c.Example = groupsServiceCommandDeleteExamples
|
||||||
|
|
||||||
flags.AddBackupIDFlag(c, true)
|
flags.AddMultipleBackupIDsFlag(c, false)
|
||||||
|
flags.AddBackupIDFlag(c, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
@ -305,7 +307,17 @@ func groupsDeleteCmd() *cobra.Command {
|
|||||||
|
|
||||||
// deletes an groups service backup.
|
// deletes an groups service backup.
|
||||||
func deleteGroupsCmd(cmd *cobra.Command, args []string) error {
|
func deleteGroupsCmd(cmd *cobra.Command, args []string) error {
|
||||||
return genericDeleteCommand(cmd, path.GroupsService, flags.BackupIDFV, "Groups", args)
|
backupIDValue := []string{}
|
||||||
|
|
||||||
|
if len(flags.BackupIDsFV) > 0 {
|
||||||
|
backupIDValue = flags.BackupIDsFV
|
||||||
|
} else if len(flags.BackupIDFV) > 0 {
|
||||||
|
backupIDValue = append(backupIDValue, flags.BackupIDFV)
|
||||||
|
} else {
|
||||||
|
return clues.New("either --backup or --backups flag is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return genericDeleteCommand(cmd, path.GroupsService, "Groups", backupIDValue, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
@ -499,6 +499,7 @@ type BackupDeleteGroupsE2ESuite struct {
|
|||||||
tester.Suite
|
tester.Suite
|
||||||
dpnd dependencies
|
dpnd dependencies
|
||||||
backupOp operations.BackupOperation
|
backupOp operations.BackupOperation
|
||||||
|
secondaryBackupOp operations.BackupOperation
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBackupDeleteGroupsE2ESuite(t *testing.T) {
|
func TestBackupDeleteGroupsE2ESuite(t *testing.T) {
|
||||||
@ -531,6 +532,15 @@ func (suite *BackupDeleteGroupsE2ESuite) SetupSuite() {
|
|||||||
|
|
||||||
err = suite.backupOp.Run(ctx)
|
err = suite.backupOp.Run(ctx)
|
||||||
require.NoError(t, err, clues.ToCore(err))
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
// secondary backup
|
||||||
|
secondaryBackupOp, err := suite.dpnd.repo.NewBackup(ctx, sel.Selector)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
suite.secondaryBackupOp = secondaryBackupOp
|
||||||
|
|
||||||
|
err = suite.secondaryBackupOp.Run(ctx)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *BackupDeleteGroupsE2ESuite) TestGroupsBackupDeleteCmd() {
|
func (suite *BackupDeleteGroupsE2ESuite) TestGroupsBackupDeleteCmd() {
|
||||||
@ -544,7 +554,40 @@ func (suite *BackupDeleteGroupsE2ESuite) TestGroupsBackupDeleteCmd() {
|
|||||||
cmd := cliTD.StubRootCmd(
|
cmd := cliTD.StubRootCmd(
|
||||||
"backup", "delete", "groups",
|
"backup", "delete", "groups",
|
||||||
"--config-file", suite.dpnd.configFilePath,
|
"--config-file", suite.dpnd.configFilePath,
|
||||||
"--"+flags.BackupFN, string(suite.backupOp.Results.BackupID))
|
"--"+flags.BackupIDsFN,
|
||||||
|
fmt.Sprintf("%s,%s",
|
||||||
|
string(suite.backupOp.Results.BackupID),
|
||||||
|
string(suite.secondaryBackupOp.Results.BackupID)))
|
||||||
|
cli.BuildCommandTree(cmd)
|
||||||
|
|
||||||
|
// run the command
|
||||||
|
err := cmd.ExecuteContext(ctx)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
// a follow-up details call should fail, due to the backup ID being deleted
|
||||||
|
cmd = cliTD.StubRootCmd(
|
||||||
|
"backup", "details", "groups",
|
||||||
|
"--config-file", suite.dpnd.configFilePath,
|
||||||
|
"--backups", string(suite.backupOp.Results.BackupID))
|
||||||
|
cli.BuildCommandTree(cmd)
|
||||||
|
|
||||||
|
err = cmd.ExecuteContext(ctx)
|
||||||
|
require.Error(t, err, clues.ToCore(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *BackupDeleteGroupsE2ESuite) TestGroupsBackupDeleteCmd_SingleID() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
ctx, flush := tester.NewContext(t)
|
||||||
|
ctx = config.SetViper(ctx, suite.dpnd.vpr)
|
||||||
|
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
cmd := cliTD.StubRootCmd(
|
||||||
|
"backup", "delete", "groups",
|
||||||
|
"--config-file", suite.dpnd.configFilePath,
|
||||||
|
"--"+flags.BackupFN,
|
||||||
|
string(suite.backupOp.Results.BackupID))
|
||||||
cli.BuildCommandTree(cmd)
|
cli.BuildCommandTree(cmd)
|
||||||
|
|
||||||
// run the command
|
// run the command
|
||||||
@ -573,7 +616,7 @@ func (suite *BackupDeleteGroupsE2ESuite) TestGroupsBackupDeleteCmd_UnknownID() {
|
|||||||
cmd := cliTD.StubRootCmd(
|
cmd := cliTD.StubRootCmd(
|
||||||
"backup", "delete", "groups",
|
"backup", "delete", "groups",
|
||||||
"--config-file", suite.dpnd.configFilePath,
|
"--config-file", suite.dpnd.configFilePath,
|
||||||
"--"+flags.BackupFN, uuid.NewString())
|
"--"+flags.BackupIDsFN, uuid.NewString())
|
||||||
cli.BuildCommandTree(cmd)
|
cli.BuildCommandTree(cmd)
|
||||||
|
|
||||||
// unknown backupIDs should error since the modelStore can't find the backup
|
// unknown backupIDs should error since the modelStore can't find the backup
|
||||||
@ -581,6 +624,24 @@ func (suite *BackupDeleteGroupsE2ESuite) TestGroupsBackupDeleteCmd_UnknownID() {
|
|||||||
require.Error(t, err, clues.ToCore(err))
|
require.Error(t, err, clues.ToCore(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *BackupDeleteGroupsE2ESuite) TestGroupsBackupDeleteCmd_NoBackupID() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
ctx, flush := tester.NewContext(t)
|
||||||
|
ctx = config.SetViper(ctx, suite.dpnd.vpr)
|
||||||
|
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
cmd := cliTD.StubRootCmd(
|
||||||
|
"backup", "delete", "groups",
|
||||||
|
"--config-file", suite.dpnd.configFilePath)
|
||||||
|
cli.BuildCommandTree(cmd)
|
||||||
|
|
||||||
|
// empty backupIDs should error since no data provided
|
||||||
|
err := cmd.ExecuteContext(ctx)
|
||||||
|
require.Error(t, err, clues.ToCore(err))
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// helpers
|
// helpers
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
oneDriveServiceCommand = "onedrive"
|
oneDriveServiceCommand = "onedrive"
|
||||||
oneDriveServiceCommandCreateUseSuffix = "--user <email> | '" + flags.Wildcard + "'"
|
oneDriveServiceCommandCreateUseSuffix = "--user <email> | '" + flags.Wildcard + "'"
|
||||||
oneDriveServiceCommandDeleteUseSuffix = "--backup <backupId>"
|
oneDriveServiceCommandDeleteUseSuffix = "--backups <backupId>"
|
||||||
oneDriveServiceCommandDetailsUseSuffix = "--backup <backupId>"
|
oneDriveServiceCommandDetailsUseSuffix = "--backup <backupId>"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -40,8 +40,9 @@ corso backup create onedrive --user alice@example.com,bob@example.com
|
|||||||
# Backup all OneDrive data for all M365 users
|
# Backup all OneDrive data for all M365 users
|
||||||
corso backup create onedrive --user '*'`
|
corso backup create onedrive --user '*'`
|
||||||
|
|
||||||
oneDriveServiceCommandDeleteExamples = `# Delete OneDrive backup with ID 1234abcd-12ab-cd34-56de-1234abcd
|
oneDriveServiceCommandDeleteExamples = `# Delete OneDrive backup with ID 1234abcd-12ab-cd34-56de-1234abcd \
|
||||||
corso backup delete onedrive --backup 1234abcd-12ab-cd34-56de-1234abcd`
|
and 1234abcd-12ab-cd34-56de-1234abce
|
||||||
|
corso backup delete onedrive --backups 1234abcd-12ab-cd34-56de-1234abcd,1234abcd-12ab-cd34-56de-1234abce`
|
||||||
|
|
||||||
oneDriveServiceCommandDetailsExamples = `# Explore items in Bob's latest backup (1234abcd...)
|
oneDriveServiceCommandDetailsExamples = `# Explore items in Bob's latest backup (1234abcd...)
|
||||||
corso backup details onedrive --backup 1234abcd-12ab-cd34-56de-1234abcd
|
corso backup details onedrive --backup 1234abcd-12ab-cd34-56de-1234abcd
|
||||||
@ -100,7 +101,8 @@ func addOneDriveCommands(cmd *cobra.Command) *cobra.Command {
|
|||||||
c.Use = c.Use + " " + oneDriveServiceCommandDeleteUseSuffix
|
c.Use = c.Use + " " + oneDriveServiceCommandDeleteUseSuffix
|
||||||
c.Example = oneDriveServiceCommandDeleteExamples
|
c.Example = oneDriveServiceCommandDeleteExamples
|
||||||
|
|
||||||
flags.AddBackupIDFlag(c, true)
|
flags.AddMultipleBackupIDsFlag(c, false)
|
||||||
|
flags.AddBackupIDFlag(c, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
@ -306,5 +308,15 @@ func oneDriveDeleteCmd() *cobra.Command {
|
|||||||
|
|
||||||
// deletes a oneDrive service backup.
|
// deletes a oneDrive service backup.
|
||||||
func deleteOneDriveCmd(cmd *cobra.Command, args []string) error {
|
func deleteOneDriveCmd(cmd *cobra.Command, args []string) error {
|
||||||
return genericDeleteCommand(cmd, path.OneDriveService, flags.BackupIDFV, "OneDrive", args)
|
backupIDValue := []string{}
|
||||||
|
|
||||||
|
if len(flags.BackupIDsFV) > 0 {
|
||||||
|
backupIDValue = flags.BackupIDsFV
|
||||||
|
} else if len(flags.BackupIDFV) > 0 {
|
||||||
|
backupIDValue = append(backupIDValue, flags.BackupIDFV)
|
||||||
|
} else {
|
||||||
|
return clues.New("either --backup or --backups flag is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return genericDeleteCommand(cmd, path.OneDriveService, "OneDrive", backupIDValue, args)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -123,6 +123,7 @@ type BackupDeleteOneDriveE2ESuite struct {
|
|||||||
tester.Suite
|
tester.Suite
|
||||||
dpnd dependencies
|
dpnd dependencies
|
||||||
backupOp operations.BackupOperation
|
backupOp operations.BackupOperation
|
||||||
|
secondaryBackupOp operations.BackupOperation
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBackupDeleteOneDriveE2ESuite(t *testing.T) {
|
func TestBackupDeleteOneDriveE2ESuite(t *testing.T) {
|
||||||
@ -158,6 +159,15 @@ func (suite *BackupDeleteOneDriveE2ESuite) SetupSuite() {
|
|||||||
|
|
||||||
err = suite.backupOp.Run(ctx)
|
err = suite.backupOp.Run(ctx)
|
||||||
require.NoError(t, err, clues.ToCore(err))
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
// secondary backup
|
||||||
|
secondaryBackupOp, err := suite.dpnd.repo.NewBackupWithLookup(ctx, sel.Selector, ins)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
suite.secondaryBackupOp = secondaryBackupOp
|
||||||
|
|
||||||
|
err = suite.secondaryBackupOp.Run(ctx)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *BackupDeleteOneDriveE2ESuite) TestOneDriveBackupDeleteCmd() {
|
func (suite *BackupDeleteOneDriveE2ESuite) TestOneDriveBackupDeleteCmd() {
|
||||||
@ -173,7 +183,10 @@ func (suite *BackupDeleteOneDriveE2ESuite) TestOneDriveBackupDeleteCmd() {
|
|||||||
cmd := cliTD.StubRootCmd(
|
cmd := cliTD.StubRootCmd(
|
||||||
"backup", "delete", "onedrive",
|
"backup", "delete", "onedrive",
|
||||||
"--config-file", suite.dpnd.configFilePath,
|
"--config-file", suite.dpnd.configFilePath,
|
||||||
"--"+flags.BackupFN, string(suite.backupOp.Results.BackupID))
|
"--"+flags.BackupIDsFN,
|
||||||
|
fmt.Sprintf("%s,%s",
|
||||||
|
string(suite.backupOp.Results.BackupID),
|
||||||
|
string(suite.secondaryBackupOp.Results.BackupID)))
|
||||||
cli.BuildCommandTree(cmd)
|
cli.BuildCommandTree(cmd)
|
||||||
cmd.SetErr(&suite.dpnd.recorder)
|
cmd.SetErr(&suite.dpnd.recorder)
|
||||||
|
|
||||||
@ -187,7 +200,51 @@ func (suite *BackupDeleteOneDriveE2ESuite) TestOneDriveBackupDeleteCmd() {
|
|||||||
assert.True(t,
|
assert.True(t,
|
||||||
strings.HasSuffix(
|
strings.HasSuffix(
|
||||||
result,
|
result,
|
||||||
fmt.Sprintf("Deleted OneDrive backup %s\n", string(suite.backupOp.Results.BackupID))))
|
fmt.Sprintf("Deleted OneDrive backup [%s %s]\n",
|
||||||
|
string(suite.backupOp.Results.BackupID),
|
||||||
|
string(suite.secondaryBackupOp.Results.BackupID))))
|
||||||
|
|
||||||
|
// a follow-up details call should fail, due to the backup ID being deleted
|
||||||
|
cmd = cliTD.StubRootCmd(
|
||||||
|
"backup", "details", "onedrive",
|
||||||
|
"--config-file", suite.dpnd.configFilePath,
|
||||||
|
"--backups", string(suite.backupOp.Results.BackupID))
|
||||||
|
cli.BuildCommandTree(cmd)
|
||||||
|
|
||||||
|
err = cmd.ExecuteContext(ctx)
|
||||||
|
require.Error(t, err, clues.ToCore(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *BackupDeleteOneDriveE2ESuite) TestOneDriveBackupDeleteCmd_SingleID() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
ctx, flush := tester.NewContext(t)
|
||||||
|
ctx = config.SetViper(ctx, suite.dpnd.vpr)
|
||||||
|
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
suite.dpnd.recorder.Reset()
|
||||||
|
|
||||||
|
cmd := cliTD.StubRootCmd(
|
||||||
|
"backup", "delete", "onedrive",
|
||||||
|
"--config-file", suite.dpnd.configFilePath,
|
||||||
|
"--"+flags.BackupFN,
|
||||||
|
string(suite.backupOp.Results.BackupID))
|
||||||
|
cli.BuildCommandTree(cmd)
|
||||||
|
cmd.SetErr(&suite.dpnd.recorder)
|
||||||
|
|
||||||
|
ctx = print.SetRootCmd(ctx, cmd)
|
||||||
|
|
||||||
|
// run the command
|
||||||
|
err := cmd.ExecuteContext(ctx)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
result := suite.dpnd.recorder.String()
|
||||||
|
assert.True(t,
|
||||||
|
strings.HasSuffix(
|
||||||
|
result,
|
||||||
|
fmt.Sprintf("Deleted OneDrive backup [%s]\n",
|
||||||
|
string(suite.backupOp.Results.BackupID))))
|
||||||
|
|
||||||
// a follow-up details call should fail, due to the backup ID being deleted
|
// a follow-up details call should fail, due to the backup ID being deleted
|
||||||
cmd = cliTD.StubRootCmd(
|
cmd = cliTD.StubRootCmd(
|
||||||
@ -211,10 +268,28 @@ func (suite *BackupDeleteOneDriveE2ESuite) TestOneDriveBackupDeleteCmd_unknownID
|
|||||||
cmd := cliTD.StubRootCmd(
|
cmd := cliTD.StubRootCmd(
|
||||||
"backup", "delete", "onedrive",
|
"backup", "delete", "onedrive",
|
||||||
"--config-file", suite.dpnd.configFilePath,
|
"--config-file", suite.dpnd.configFilePath,
|
||||||
"--"+flags.BackupFN, uuid.NewString())
|
"--"+flags.BackupIDsFN, uuid.NewString())
|
||||||
cli.BuildCommandTree(cmd)
|
cli.BuildCommandTree(cmd)
|
||||||
|
|
||||||
// unknown backupIDs should error since the modelStore can't find the backup
|
// unknown backupIDs should error since the modelStore can't find the backup
|
||||||
err := cmd.ExecuteContext(ctx)
|
err := cmd.ExecuteContext(ctx)
|
||||||
require.Error(t, err, clues.ToCore(err))
|
require.Error(t, err, clues.ToCore(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *BackupDeleteOneDriveE2ESuite) TestOneDriveBackupDeleteCmd_NoBackupID() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
ctx, flush := tester.NewContext(t)
|
||||||
|
ctx = config.SetViper(ctx, suite.dpnd.vpr)
|
||||||
|
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
cmd := cliTD.StubRootCmd(
|
||||||
|
"backup", "delete", "onedrive",
|
||||||
|
"--config-file", suite.dpnd.configFilePath)
|
||||||
|
cli.BuildCommandTree(cmd)
|
||||||
|
|
||||||
|
// empty backupIDs should error since no data provided
|
||||||
|
err := cmd.ExecuteContext(ctx)
|
||||||
|
require.Error(t, err, clues.ToCore(err))
|
||||||
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
sharePointServiceCommand = "sharepoint"
|
sharePointServiceCommand = "sharepoint"
|
||||||
sharePointServiceCommandCreateUseSuffix = "--site <siteURL> | '" + flags.Wildcard + "'"
|
sharePointServiceCommandCreateUseSuffix = "--site <siteURL> | '" + flags.Wildcard + "'"
|
||||||
sharePointServiceCommandDeleteUseSuffix = "--backup <backupId>"
|
sharePointServiceCommandDeleteUseSuffix = "--backups <backupId>"
|
||||||
sharePointServiceCommandDetailsUseSuffix = "--backup <backupId>"
|
sharePointServiceCommandDetailsUseSuffix = "--backup <backupId>"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -44,8 +44,9 @@ corso backup create sharepoint --site https://example.com/hr,https://example.com
|
|||||||
# Backup all SharePoint data for all Sites
|
# Backup all SharePoint data for all Sites
|
||||||
corso backup create sharepoint --site '*'`
|
corso backup create sharepoint --site '*'`
|
||||||
|
|
||||||
sharePointServiceCommandDeleteExamples = `# Delete SharePoint backup with ID 1234abcd-12ab-cd34-56de-1234abcd
|
sharePointServiceCommandDeleteExamples = `# Delete SharePoint backup with ID 1234abcd-12ab-cd34-56de-1234abcd \
|
||||||
corso backup delete sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd`
|
and 1234abcd-12ab-cd34-56de-1234abce
|
||||||
|
corso backup delete sharepoint --backups 1234abcd-12ab-cd34-56de-1234abcd,1234abcd-12ab-cd34-56de-1234abce`
|
||||||
|
|
||||||
sharePointServiceCommandDetailsExamples = `# Explore items in the HR site's latest backup (1234abcd...)
|
sharePointServiceCommandDetailsExamples = `# Explore items in the HR site's latest backup (1234abcd...)
|
||||||
corso backup details sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd
|
corso backup details sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd
|
||||||
@ -111,7 +112,8 @@ func addSharePointCommands(cmd *cobra.Command) *cobra.Command {
|
|||||||
c.Use = c.Use + " " + sharePointServiceCommandDeleteUseSuffix
|
c.Use = c.Use + " " + sharePointServiceCommandDeleteUseSuffix
|
||||||
c.Example = sharePointServiceCommandDeleteExamples
|
c.Example = sharePointServiceCommandDeleteExamples
|
||||||
|
|
||||||
flags.AddBackupIDFlag(c, true)
|
flags.AddMultipleBackupIDsFlag(c, false)
|
||||||
|
flags.AddBackupIDFlag(c, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
@ -284,7 +286,17 @@ func sharePointDeleteCmd() *cobra.Command {
|
|||||||
|
|
||||||
// deletes a sharePoint service backup.
|
// deletes a sharePoint service backup.
|
||||||
func deleteSharePointCmd(cmd *cobra.Command, args []string) error {
|
func deleteSharePointCmd(cmd *cobra.Command, args []string) error {
|
||||||
return genericDeleteCommand(cmd, path.SharePointService, flags.BackupIDFV, "SharePoint", args)
|
backupIDValue := []string{}
|
||||||
|
|
||||||
|
if len(flags.BackupIDsFV) > 0 {
|
||||||
|
backupIDValue = flags.BackupIDsFV
|
||||||
|
} else if len(flags.BackupIDFV) > 0 {
|
||||||
|
backupIDValue = append(backupIDValue, flags.BackupIDFV)
|
||||||
|
} else {
|
||||||
|
return clues.New("either --backup or --backups flag is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return genericDeleteCommand(cmd, path.SharePointService, "SharePoint", backupIDValue, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@ -86,6 +86,7 @@ type BackupDeleteSharePointE2ESuite struct {
|
|||||||
tester.Suite
|
tester.Suite
|
||||||
dpnd dependencies
|
dpnd dependencies
|
||||||
backupOp operations.BackupOperation
|
backupOp operations.BackupOperation
|
||||||
|
secondaryBackupOp operations.BackupOperation
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBackupDeleteSharePointE2ESuite(t *testing.T) {
|
func TestBackupDeleteSharePointE2ESuite(t *testing.T) {
|
||||||
@ -121,6 +122,15 @@ func (suite *BackupDeleteSharePointE2ESuite) SetupSuite() {
|
|||||||
|
|
||||||
err = suite.backupOp.Run(ctx)
|
err = suite.backupOp.Run(ctx)
|
||||||
require.NoError(t, err, clues.ToCore(err))
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
// secondary backup
|
||||||
|
secondaryBackupOp, err := suite.dpnd.repo.NewBackupWithLookup(ctx, sel.Selector, ins)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
|
|
||||||
|
suite.secondaryBackupOp = secondaryBackupOp
|
||||||
|
|
||||||
|
err = suite.secondaryBackupOp.Run(ctx)
|
||||||
|
require.NoError(t, err, clues.ToCore(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *BackupDeleteSharePointE2ESuite) TestSharePointBackupDeleteCmd() {
|
func (suite *BackupDeleteSharePointE2ESuite) TestSharePointBackupDeleteCmd() {
|
||||||
@ -136,7 +146,10 @@ func (suite *BackupDeleteSharePointE2ESuite) TestSharePointBackupDeleteCmd() {
|
|||||||
cmd := cliTD.StubRootCmd(
|
cmd := cliTD.StubRootCmd(
|
||||||
"backup", "delete", "sharepoint",
|
"backup", "delete", "sharepoint",
|
||||||
"--config-file", suite.dpnd.configFilePath,
|
"--config-file", suite.dpnd.configFilePath,
|
||||||
"--"+flags.BackupFN, string(suite.backupOp.Results.BackupID))
|
"--"+flags.BackupIDsFN,
|
||||||
|
fmt.Sprintf("%s,%s",
|
||||||
|
string(suite.backupOp.Results.BackupID),
|
||||||
|
string(suite.secondaryBackupOp.Results.BackupID)))
|
||||||
cli.BuildCommandTree(cmd)
|
cli.BuildCommandTree(cmd)
|
||||||
cmd.SetErr(&suite.dpnd.recorder)
|
cmd.SetErr(&suite.dpnd.recorder)
|
||||||
|
|
||||||
@ -150,7 +163,9 @@ func (suite *BackupDeleteSharePointE2ESuite) TestSharePointBackupDeleteCmd() {
|
|||||||
assert.True(t,
|
assert.True(t,
|
||||||
strings.HasSuffix(
|
strings.HasSuffix(
|
||||||
result,
|
result,
|
||||||
fmt.Sprintf("Deleted SharePoint backup %s\n", string(suite.backupOp.Results.BackupID))))
|
fmt.Sprintf("Deleted SharePoint backup [%s %s]\n",
|
||||||
|
string(suite.backupOp.Results.BackupID),
|
||||||
|
string(suite.secondaryBackupOp.Results.BackupID))))
|
||||||
}
|
}
|
||||||
|
|
||||||
// moved out of the func above to make the linter happy
|
// moved out of the func above to make the linter happy
|
||||||
@ -175,10 +190,28 @@ func (suite *BackupDeleteSharePointE2ESuite) TestSharePointBackupDeleteCmd_unkno
|
|||||||
cmd := cliTD.StubRootCmd(
|
cmd := cliTD.StubRootCmd(
|
||||||
"backup", "delete", "sharepoint",
|
"backup", "delete", "sharepoint",
|
||||||
"--config-file", suite.dpnd.configFilePath,
|
"--config-file", suite.dpnd.configFilePath,
|
||||||
"--"+flags.BackupFN, uuid.NewString())
|
"--"+flags.BackupIDsFN, uuid.NewString())
|
||||||
cli.BuildCommandTree(cmd)
|
cli.BuildCommandTree(cmd)
|
||||||
|
|
||||||
// unknown backupIDs should error since the modelStore can't find the backup
|
// unknown backupIDs should error since the modelStore can't find the backup
|
||||||
err := cmd.ExecuteContext(ctx)
|
err := cmd.ExecuteContext(ctx)
|
||||||
require.Error(t, err, clues.ToCore(err))
|
require.Error(t, err, clues.ToCore(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *BackupDeleteSharePointE2ESuite) TestSharePointBackupDeleteCmd_NoBackupID() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
ctx, flush := tester.NewContext(t)
|
||||||
|
ctx = config.SetViper(ctx, suite.dpnd.vpr)
|
||||||
|
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
cmd := cliTD.StubRootCmd(
|
||||||
|
"backup", "delete", "groups",
|
||||||
|
"--config-file", suite.dpnd.configFilePath)
|
||||||
|
cli.BuildCommandTree(cmd)
|
||||||
|
|
||||||
|
// empty backupIDs should error since no data provided
|
||||||
|
err := cmd.ExecuteContext(ctx)
|
||||||
|
require.Error(t, err, clues.ToCore(err))
|
||||||
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
BackupFN = "backup"
|
BackupFN = "backup"
|
||||||
|
BackupIDsFN = "backups"
|
||||||
AWSAccessKeyFN = "aws-access-key"
|
AWSAccessKeyFN = "aws-access-key"
|
||||||
AWSSecretAccessKeyFN = "aws-secret-access-key"
|
AWSSecretAccessKeyFN = "aws-secret-access-key"
|
||||||
AWSSessionTokenFN = "aws-session-token"
|
AWSSessionTokenFN = "aws-session-token"
|
||||||
@ -17,6 +18,7 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
BackupIDFV string
|
BackupIDFV string
|
||||||
|
BackupIDsFV []string
|
||||||
AWSAccessKeyFV string
|
AWSAccessKeyFV string
|
||||||
AWSSecretAccessKeyFV string
|
AWSSecretAccessKeyFV string
|
||||||
AWSSessionTokenFV string
|
AWSSessionTokenFV string
|
||||||
@ -24,6 +26,18 @@ var (
|
|||||||
SucceedIfExistsFV bool
|
SucceedIfExistsFV bool
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AddMultipleBackupIDsFlag adds the --backups flag.
|
||||||
|
func AddMultipleBackupIDsFlag(cmd *cobra.Command, require bool) {
|
||||||
|
cmd.Flags().StringSliceVar(
|
||||||
|
&BackupIDsFV,
|
||||||
|
BackupIDsFN, nil,
|
||||||
|
"',' separated IDs of the backup to retrieve")
|
||||||
|
|
||||||
|
if require {
|
||||||
|
cobra.CheckErr(cmd.MarkFlagRequired(BackupIDsFN))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AddBackupIDFlag adds the --backup flag.
|
// AddBackupIDFlag adds the --backup flag.
|
||||||
func AddBackupIDFlag(cmd *cobra.Command, require bool) {
|
func AddBackupIDFlag(cmd *cobra.Command, require bool) {
|
||||||
cmd.Flags().StringVar(&BackupIDFV, BackupFN, "", "ID of the backup to retrieve.")
|
cmd.Flags().StringVar(&BackupIDFV, BackupFN, "", "ID of the backup to retrieve.")
|
||||||
|
|||||||
@ -46,7 +46,7 @@ const (
|
|||||||
corso restore groups --backup 1234abcd-12ab-cd34-56de-1234abcd --file 98765abcdef
|
corso restore groups --backup 1234abcd-12ab-cd34-56de-1234abcd --file 98765abcdef
|
||||||
|
|
||||||
# Restore the file with ID 98765abcdef without its associated permissions
|
# Restore the file with ID 98765abcdef without its associated permissions
|
||||||
corso restore groups --backup 1234abcd-12ab-cd34-56de-1234abcd --file 98765abcdef --skip-permissions
|
corso restore groups --backup 1234abcd-12ab-cd34-56de-1234abcd --file 98765abcdef --no-permissions
|
||||||
|
|
||||||
# Restore all files named "FY2021 Planning.xlsx"
|
# Restore all files named "FY2021 Planning.xlsx"
|
||||||
corso restore groups --backup 1234abcd-12ab-cd34-56de-1234abcd --file "FY2021 Planning.xlsx"
|
corso restore groups --backup 1234abcd-12ab-cd34-56de-1234abcd --file "FY2021 Planning.xlsx"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user