document and release groups and teams (#4238)

Adds the release documentation and reveals all cli commands for groups and teams channelMessages and files support.

---

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

- [x]  Yes, it's included

#### Type of change

- [x] 🗺️ Documentation

#### Issue(s)

* #3988 

#### Test Plan

- [x] 💪 Manual
This commit is contained in:
Keepers 2023-09-18 19:52:24 -06:00 committed by GitHub
parent 9a04d7154a
commit a60d599eaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 100 additions and 60 deletions

View File

@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] (beta)
### Added
- Groups and Teams service support available as a feature preview! Channel messages and Files are now available for backup and restore in the CLI: `corso backup create groups --group '*'`
* The cli commands for "groups" and "teams" can be used interchangably, and will operate on the same backup data.
* New permissions are required to backup Channel messages. See the [Corso Documentation](https://corsobackup.io/docs/setup/m365-access/#configure-required-permissions) for complete details.
Even though Channel message restoration is not available, message write permissions are included to cover future integration.
* This is a feature preview, and may be subject to breaking changes based on feedback and testing.
### Changed
- Switched to Go 1.21
- SharePoint exported libraries are now exported with a `Libraries` prefix.

View File

@ -3,7 +3,6 @@ package backup
import (
"context"
"fmt"
"os"
"strings"
"github.com/alcionai/clues"
@ -39,9 +38,7 @@ var serviceCommands = []func(cmd *cobra.Command) *cobra.Command{
addExchangeCommands,
addOneDriveCommands,
addSharePointCommands,
// awaiting release
// addGroupsCommands,
// addTeamsCommands,
addGroupsCommands,
}
// AddCommands attaches all `corso backup * *` commands to the parent.
@ -56,11 +53,6 @@ func AddCommands(cmd *cobra.Command) {
for _, addBackupTo := range serviceCommands {
addBackupTo(subCommand)
}
// delete after release
if len(os.Getenv("CORSO_ENABLE_GROUPS")) > 0 {
addGroupsCommands(subCommand)
}
}
}

View File

@ -31,7 +31,7 @@ import (
const (
groupsServiceCommand = "groups"
teamsServiceCommand = "teams"
groupsServiceCommandCreateUseSuffix = "--group <groupsName> | '" + flags.Wildcard + "'"
groupsServiceCommandCreateUseSuffix = "--group <groupName> | '" + flags.Wildcard + "'"
groupsServiceCommandDeleteUseSuffix = "--backup <backupId>"
groupsServiceCommandDetailsUseSuffix = "--backup <backupId>"
)
@ -66,7 +66,7 @@ func addGroupsCommands(cmd *cobra.Command) *cobra.Command {
switch cmd.Use {
case createCommand:
c, fs = utils.AddCommand(cmd, groupsCreateCmd(), utils.MarkPreReleaseCommand())
c, fs = utils.AddCommand(cmd, groupsCreateCmd(), utils.MarkPreviewCommand())
fs.SortFlags = false
c.Use = c.Use + " " + groupsServiceCommandCreateUseSuffix
@ -84,7 +84,7 @@ func addGroupsCommands(cmd *cobra.Command) *cobra.Command {
flags.AddForceItemDataDownloadFlag(c)
case listCommand:
c, fs = utils.AddCommand(cmd, groupsListCmd(), utils.MarkPreReleaseCommand())
c, fs = utils.AddCommand(cmd, groupsListCmd(), utils.MarkPreviewCommand())
fs.SortFlags = false
flags.AddBackupIDFlag(c, false)
@ -96,7 +96,7 @@ func addGroupsCommands(cmd *cobra.Command) *cobra.Command {
addRecoveredErrorsFN(c)
case detailsCommand:
c, fs = utils.AddCommand(cmd, groupsDetailsCmd(), utils.MarkPreReleaseCommand())
c, fs = utils.AddCommand(cmd, groupsDetailsCmd(), utils.MarkPreviewCommand())
fs.SortFlags = false
c.Use = c.Use + " " + groupsServiceCommandDetailsUseSuffix
@ -114,7 +114,7 @@ func addGroupsCommands(cmd *cobra.Command) *cobra.Command {
flags.AddSharePointDetailsAndRestoreFlags(c)
case deleteCommand:
c, fs = utils.AddCommand(cmd, groupsDeleteCmd(), utils.MarkPreReleaseCommand())
c, fs = utils.AddCommand(cmd, groupsDeleteCmd(), utils.MarkPreviewCommand())
fs.SortFlags = false
c.Use = c.Use + " " + groupsServiceCommandDeleteUseSuffix

View File

@ -3,7 +3,6 @@ package export
import (
"context"
"errors"
"os"
"github.com/alcionai/clues"
"github.com/spf13/cobra"
@ -21,9 +20,7 @@ import (
var exportCommands = []func(cmd *cobra.Command) *cobra.Command{
addOneDriveCommands,
addSharePointCommands,
// awaiting release
// addGroupsCommands,
// addTeamsCommands,
addGroupsCommands,
}
// AddCommands attaches all `corso export * *` commands to the parent.
@ -34,11 +31,6 @@ func AddCommands(cmd *cobra.Command) {
for _, addExportTo := range exportCommands {
addExportTo(exportC)
}
// delete after release
if len(os.Getenv("CORSO_ENABLE_GROUPS")) > 0 {
addGroupsCommands(exportC)
}
}
const exportCommand = "export"

View File

@ -18,7 +18,7 @@ func addGroupsCommands(cmd *cobra.Command) *cobra.Command {
switch cmd.Use {
case exportCommand:
c, fs = utils.AddCommand(cmd, groupsExportCmd(), utils.MarkPreReleaseCommand())
c, fs = utils.AddCommand(cmd, groupsExportCmd(), utils.MarkPreviewCommand())
c.Use = c.Use + " " + groupsServiceCommandUseSuffix
@ -43,16 +43,20 @@ const (
groupsServiceCommandUseSuffix = "<destination> --backup <backupId>"
//nolint:lll
groupsServiceCommandExportExamples = `# Export a message in Marketing's last backup (1234abcd...) to my-exports directory
groupsServiceCommandExportExamples = `# Export a message in Marketing's last backup (1234abcd...) to /my-exports
corso export groups my-exports --backup 1234abcd-12ab-cd34-56de-1234abcd --message 98765abcdef
# Export all messages named in channel "Finance Reports" to the current directory
corso export groups . --backup 1234abcd-12ab-cd34-56de-1234abcd \
--message '*' --channel "Finance Reports"
# Export all messages in channel "Finance Reports" that were created before 2020 to my-exports
# Export all messages in channel "Finance Reports" that were created before 2020 to /my-exports
corso export groups my-exports --backup 1234abcd-12ab-cd34-56de-1234abcd
--channel "Finance Reports" --message-created-before 2020-01-01T00:00:00`
--channel "Finance Reports" --message-created-before 2020-01-01T00:00:00
# Export all files and folders in folder "Documents/Finance Reports" that were created before 2020 to /my-exports
corso export groups my-exports --backup 1234abcd-12ab-cd34-56de-1234abcd \
--folder "Documents/Finance Reports" --file-created-before 2020-01-01T00:00:00`
)
// `corso export groups [<flag>...] <destination>`

View File

@ -42,15 +42,15 @@ const (
oneDriveServiceCommandUseSuffix = "<destination> --backup <backupId>"
//nolint:lll
oneDriveServiceCommandExportExamples = `# Export file with ID 98765abcdef in Bob's last backup (1234abcd...) to my-exports directory
oneDriveServiceCommandExportExamples = `# Export file with ID 98765abcdef in Bob's last backup (1234abcd...) to /my-exports
corso export onedrive my-exports --backup 1234abcd-12ab-cd34-56de-1234abcd --file 98765abcdef
# Export files named "FY2021 Planning.xlsx" in "Documents/Finance Reports" to current directory
# Export files named "FY2021 Planning.xlsx" in "Documents/Finance Reports" to he current directory
corso export onedrive . --backup 1234abcd-12ab-cd34-56de-1234abcd \
--file "FY2021 Planning.xlsx" --folder "Documents/Finance Reports"
# Export all files and folders in folder "Documents/Finance Reports" that were created before 2020 to my-exports
corso export onedrive my-exports --backup 1234abcd-12ab-cd34-56de-1234abcd
# Export all files and folders in folder "Documents/Finance Reports" that were created before 2020 to /my-exports
corso export onedrive my-exports --backup 1234abcd-12ab-cd34-56de-1234abcd \
--folder "Documents/Finance Reports" --file-created-before 2020-01-01T00:00:00`
)

View File

@ -42,19 +42,19 @@ const (
sharePointServiceCommandUseSuffix = "<destination> --backup <backupId>"
//nolint:lll
sharePointServiceCommandExportExamples = `# Export file with ID 98765abcdef in Bob's latest backup (1234abcd...) to my-exports directory
sharePointServiceCommandExportExamples = `# Export file with ID 98765abcdef in Bob's latest backup (1234abcd...) to /my-exports
corso export sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd --file 98765abcdef my-exports
# Export files named "ServerRenderTemplate.xsl" in the folder "Display Templates/Style Sheets". as archive to current directory
# Export file "ServerRenderTemplate.xsl" in "Display Templates/Style Sheets" as archive to the current directory
corso export sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd \
--file "ServerRenderTemplate.xsl" --folder "Display Templates/Style Sheets" --archive .
# Export all files in the folder "Display Templates/Style Sheets" that were created before 2020 to my-exports directory.
corso export sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd
# Export all files in the folder "Display Templates/Style Sheets" that were created before 2020 to /my-exports
corso export sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd \
--file-created-before 2020-01-01T00:00:00 --folder "Display Templates/Style Sheets" my-exports
# Export all files in the "Documents" library to current directory.
corso export sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd
# Export all files in the "Documents" library to the current directory.
corso export sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd \
--library Documents --folder "Display Templates/Style Sheets" .`
)

View File

@ -18,7 +18,7 @@ func addGroupsCommands(cmd *cobra.Command) *cobra.Command {
switch cmd.Use {
case restoreCommand:
c, fs = utils.AddCommand(cmd, groupsRestoreCmd(), utils.MarkPreReleaseCommand())
c, fs = utils.AddCommand(cmd, groupsRestoreCmd(), utils.MarkPreviewCommand())
c.Use = c.Use + " " + groupsServiceCommandUseSuffix
@ -40,24 +40,22 @@ func addGroupsCommands(cmd *cobra.Command) *cobra.Command {
return c
}
// TODO: correct examples
const (
groupsServiceCommand = "groups"
teamsServiceCommand = "teams"
groupsServiceCommandUseSuffix = "--backup <backupId>"
groupsServiceCommandRestoreExamples = `# Restore file with ID 98765abcdef in Bob's last backup (1234abcd...)
groupsServiceCommandRestoreExamples = `# Restore file with ID 98765abcdef in Marketing's last backup (1234abcd...)
corso restore groups --backup 1234abcd-12ab-cd34-56de-1234abcd --file 98765abcdef
# Restore the file with ID 98765abcdef along with its associated permissions
corso restore groups --backup 1234abcd-12ab-cd34-56de-1234abcd --file 98765abcdef --restore-permissions
# Restore files named "FY2021 Planning.xlsx" in "Documents/Finance Reports"
corso restore groups --backup 1234abcd-12ab-cd34-56de-1234abcd \
--file "FY2021 Planning.xlsx" --folder "Documents/Finance Reports"
# Restore all files named "FY2021 Planning.xlsx"
corso restore groups --backup 1234abcd-12ab-cd34-56de-1234abcd --file "FY2021 Planning.xlsx"
# Restore all files and folders in folder "Documents/Finance Reports" that were created before 2020
corso restore groups --backup 1234abcd-12ab-cd34-56de-1234abcd
corso restore groups --backup 1234abcd-12ab-cd34-56de-1234abcd \
--folder "Documents/Finance Reports" --file-created-before 2020-01-01T00:00:00`
)

View File

@ -54,7 +54,7 @@ corso restore onedrive --backup 1234abcd-12ab-cd34-56de-1234abcd \
--file "FY2021 Planning.xlsx" --folder "Documents/Finance Reports"
# Restore all files and folders in folder "Documents/Finance Reports" that were created before 2020
corso restore onedrive --backup 1234abcd-12ab-cd34-56de-1234abcd
corso restore onedrive --backup 1234abcd-12ab-cd34-56de-1234abcd \
--folder "Documents/Finance Reports" --file-created-before 2020-01-01T00:00:00`
)

View File

@ -2,7 +2,6 @@ package restore
import (
"context"
"os"
"github.com/alcionai/clues"
"github.com/pkg/errors"
@ -20,9 +19,7 @@ var restoreCommands = []func(cmd *cobra.Command) *cobra.Command{
addExchangeCommands,
addOneDriveCommands,
addSharePointCommands,
// awaiting release
// addGroupsCommands,
// addTeamsCommands,
addGroupsCommands,
}
// AddCommands attaches all `corso restore * *` commands to the parent.
@ -33,11 +30,6 @@ func AddCommands(cmd *cobra.Command) {
for _, addRestoreTo := range restoreCommands {
addRestoreTo(restoreC)
}
// delete after release
if len(os.Getenv("CORSO_ENABLE_GROUPS")) > 0 {
addGroupsCommands(restoreC)
}
}
const restoreCommand = "restore"

View File

@ -56,11 +56,11 @@ corso restore sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd \
--file "ServerRenderTemplate.xsl" --folder "Display Templates/Style Sheets"
# Restore all files in the folder "Display Templates/Style Sheets" that were created before 2020.
corso restore sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd
corso restore sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd \
--file-created-before 2020-01-01T00:00:00 --folder "Display Templates/Style Sheets"
# Restore all files in the "Documents" library.
corso restore sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd
corso restore sharepoint --backup 1234abcd-12ab-cd34-56de-1234abcd \
--library Documents --folder "Display Templates/Style Sheets" `
)

View File

@ -138,6 +138,7 @@ func HasNoFlagsAndShownHelp(cmd *cobra.Command) bool {
type cmdCfg struct {
hidden bool
preRelease bool
preview bool
}
type cmdOpt func(*cmdCfg)
@ -161,6 +162,12 @@ func MarkPreReleaseCommand() cmdOpt {
}
}
func MarkPreviewCommand() cmdOpt {
return func(cc *cmdCfg) {
cc.preview = true
}
}
// AddCommand adds a clone of the subCommand to the parent,
// and returns both the clone and its pflags.
func AddCommand(parent, c *cobra.Command, opts ...cmdOpt) (*cobra.Command, *pflag.FlagSet) {
@ -178,6 +185,14 @@ func AddCommand(parent, c *cobra.Command, opts ...cmdOpt) (*cobra.Command, *pfla
"==================================================================================================\n"
}
if cc.preview {
// There is a default deprecated message that always shows so we do some terminal magic to overwrite it
c.Deprecated = "\n\033[1F\033[K" +
"=============================================================================================================\n" +
"\tWARNING!!! THIS IS A FEATURE PREVIEW THAT MAY NOT FUNCTION PROPERLY AND MAY BREAK ACROSS RELEASES\n" +
"=============================================================================================================\n"
}
c.Flags().SortFlags = false
return c, c.Flags()

View File

@ -89,7 +89,7 @@ func fatal(err error) {
// Adapted from https://github.com/spf13/cobra/blob/main/doc/md_docs.go for Corso specific formatting
func genMarkdownCorso(cmd *cobra.Command, dir string) error {
for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
if !isAvailableCommand(c) || c.IsAdditionalHelpTopicCommand() {
continue
}
@ -116,6 +116,17 @@ func genMarkdownCorso(cmd *cobra.Command, dir string) error {
return genMarkdownCustomCorso(cmd, f)
}
// adapted from cobra.Command.IsAvailablecommand()
func isAvailableCommand(cmd *cobra.Command) bool {
return cmd.IsAvailableCommand() ||
// exception case to the cobra isAvailable:
// preview commands hijack the "deprecated"
// value, but are not hidden. In order for
// this to work, we'll need to hide any commands
// that we deprecate.
(len(cmd.Deprecated) > 0 && !cmd.Hidden)
}
func genMarkdownCustomCorso(cmd *cobra.Command, w io.Writer) error {
cmd.InitDefaultHelpCmd()
cmd.InitDefaultHelpFlag()

View File

@ -199,7 +199,9 @@ cryptic messages how you can fix the problems the linters flag.
Each subsection also includes the version of golangci-lint it applies to and the
linter in question.
### `gci` `Expected 's', Found 'a' at file.go`
```sh
gci Expected 's', Found 'a' at file.go
```
This applies to golangci-lint v1.45.2 for the `gci` linter and is due to an import
ordering issue. It occurs because imports in the file aren't grouped according

View File

@ -339,5 +339,5 @@ See [here](../setup/restore-options) for more restoration options.
The above tutorial only scratches the surface for Corso's capabilities. We encourage you to dig deeper by:
* Learning about [Corso concepts and setup](../setup/concepts)
* Explore Corso backup and restore options for Exchange and Onedrive in the [Command Line Reference](../cli/corso)
* Explore Corso backup and restore options for M365 Applications in the [Command Line Reference](../cli/corso)
* Leverage Corso's [Advanced Restoration Options](../setup/restore-options)

View File

@ -52,11 +52,18 @@ then click **Add permissions**.
| API / Permissions Name | Type | Description
|:--|:--|:--|
| Calendars.ReadWrite | Application | Read and write calendars in all mailboxes |
| ChannelMessage.Read.All | Application | Read all messages in Teams' channels |
| ChannelSettings.Read.All | Application | Read all Teams' channel settings |
| Chat.Read.All | Application | Read all Teams' chats and chat messages |
| Contacts.ReadWrite | Application | Read and write contacts in all mailboxes |
| Directory.Read.All | Application | Read all organization directory data |
| Files.ReadWrite.All | Application | Read and write files in all site collections |
| MailboxSettings.Read | Application | Read all user mailbox settings |
| Mail.ReadWrite | Application | Read and write mail in all mailboxes |
| Member.Read.Hidden | Application | Read hidden group memberships |
| Sites.FullControl.All | Application | Have full control of all site collections |
| TeamMember.Read.All | Application | Read all Teams' user memberships |
| TeamSettings.Read.All | Application | Read all Teams' settings |
| User.Read.All | Application | Read all users' full profiles |
<!-- vale Microsoft.Spacing = YES -->

View File

@ -26,4 +26,10 @@ Below is a list of known Corso issues and limitations:
* Link shares with password protection can't be restored.
* All replies in a Teams Conversation are removed from backup when the root message gets deleted.
* Teams conversation replies are only backed up if the parent message is available at the time of backup.
* Groups SharePoint files don't support Export. This limitation will be addressed in a follow-up release
* Teams messages don't support Restore due to limited Graph API support for message creation.
* Groups and Teams support is available in an early-access status, and may be subject to breaking changes.

View File

@ -67,6 +67,20 @@ const sidebars = {
'cli/corso-backup-delete-exchange',
'cli/corso-restore-exchange']
},
{
type: 'category',
label: 'Groups & Teams',
link: {
slug: 'cli/groups',
description: 'Documentation for commonly-used Corso Groups & Teams CLI commands',
},
items: [
'cli/corso-backup-create-groups',
'cli/corso-backup-list-groups',
'cli/corso-backup-details-groups',
'cli/corso-backup-delete-groups',
'cli/corso-restore-groups']
},
{
type: 'category',
label: 'OneDrive',