corso/src/cmd/getM365/getItem.go
Keepers a31b01458c
flush logs on cmd failure (#1338)
## Description

The secondary scripts in corso (factory, purge, etc) are not currently flushing their logs if an error occurrs since os.Exit(1) kills the current process without alloting time for deferred funcs to run.

## Type of change

- [x] 🐛 Bugfix

## Issue(s)

* #902

## Test Plan

- [x] 💚 E2E
2022-10-27 22:57:05 +00:00

180 lines
4.9 KiB
Go

// getItem.go is a source file designed to retrieve an m365 object from an
// existing M365 account. Data displayed is representative of the current
// serialization abstraction versioning used by Microsoft Graph and stored by Corso.
package main
import (
"bytes"
"context"
"fmt"
"os"
kw "github.com/microsoft/kiota-serialization-json-go"
"github.com/pkg/errors"
"github.com/spf13/cobra"
. "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/connector"
"github.com/alcionai/corso/src/internal/connector/exchange"
"github.com/alcionai/corso/src/internal/connector/graph"
"github.com/alcionai/corso/src/internal/connector/support"
"github.com/alcionai/corso/src/internal/data"
"github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/credentials"
"github.com/alcionai/corso/src/pkg/logger"
"github.com/alcionai/corso/src/pkg/path"
)
var getCmd = &cobra.Command{
Use: "get",
Short: "Get a M365ID item JSON",
RunE: handleGetCommand,
}
// Required inputs from user for command execution
var (
tenant, user, m365ID, category string
)
// main function will produce the JSON String for a given m365 object of a
// user. Displayed Objects can be used as inputs for Mockable data
// Supports:
// - exchange (contacts, email, and events)
// Input: go run ./getItem.go --user <user>
// --m365ID <m365ID> --category <oneof: contacts, email, events>
func main() {
ctx, _ := logger.SeedLevel(context.Background(), logger.Development)
ctx = SetRootCmd(ctx, getCmd)
defer logger.Flush(ctx)
fs := getCmd.PersistentFlags()
fs.StringVar(&user, "user", "", "m365 user id of M365 user")
fs.StringVar(&tenant, "tenant", "",
"m365 Tenant: m365 identifier for the tenant, not required if active in OS Environment")
fs.StringVar(&m365ID, "m365ID", "", "m365 identifier for object to be created")
fs.StringVar(&category, "category", "", "type of M365 data (contacts, email, events or files)") // files not supported
cobra.CheckErr(getCmd.MarkPersistentFlagRequired("user"))
cobra.CheckErr(getCmd.MarkPersistentFlagRequired("m365ID"))
cobra.CheckErr(getCmd.MarkPersistentFlagRequired("category"))
if err := getCmd.ExecuteContext(ctx); err != nil {
logger.Flush(ctx)
os.Exit(1)
}
}
func handleGetCommand(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
if utils.HasNoFlagsAndShownHelp(cmd) {
return nil
}
gc, err := getGC(ctx)
if err != nil {
return err
}
err = runDisplayM365JSON(
ctx,
gc)
if err != nil {
return Only(ctx, errors.Wrapf(err, "unable to create mock from M365: %s", m365ID))
}
return nil
}
func runDisplayM365JSON(
ctx context.Context,
gs graph.Service,
) error {
var (
get exchange.GraphRetrievalFunc
serializeFunc exchange.GraphSerializeFunc
cat = graph.StringToPathCategory(category)
)
switch cat {
case path.EmailCategory, path.EventsCategory, path.ContactsCategory:
get, serializeFunc = exchange.GetQueryAndSerializeFunc(exchange.CategoryToOptionIdentifier(cat))
default:
return fmt.Errorf("unable to process category: %s", cat)
}
channel := make(chan data.Stream, 1)
sw := kw.NewJsonSerializationWriter()
response, err := get(ctx, gs, user, m365ID)
if err != nil {
return errors.Wrap(err, support.ConnectorStackErrorTrace(err))
}
// First return is the number of bytes that were serialized. Ignored
_, err = serializeFunc(ctx, gs.Client(), sw, channel, response, user)
close(channel)
if err != nil {
return err
}
for item := range channel {
buf := &bytes.Buffer{}
_, err := buf.ReadFrom(item.ToReader())
if err != nil {
return errors.Wrapf(err, "unable to parse given data: %s", m365ID)
}
byteArray := buf.Bytes()
newValue := string(byteArray)
err = sw.WriteStringValue("", &newValue)
if err != nil {
return errors.Wrapf(err, "unable to %s to string value", m365ID)
}
array, err := sw.GetSerializedContent()
if err != nil {
return errors.Wrapf(err, "unable to serialize new value from M365:%s", m365ID)
}
fmt.Println(string(array))
return nil
}
// This should never happen
return errors.New("m365 object not serialized")
}
//-------------------------------------------------------------------------------
// Helpers
//-------------------------------------------------------------------------------
func getGC(ctx context.Context) (*connector.GraphConnector, error) {
// get account info
m365Cfg := account.M365Config{
M365: credentials.GetM365(),
AzureTenantID: common.First(tenant, os.Getenv(account.AzureTenantID)),
}
acct, err := account.NewAccount(account.ProviderM365, m365Cfg)
if err != nil {
return nil, Only(ctx, errors.Wrap(err, "finding m365 account details"))
}
gc, err := connector.NewGraphConnector(ctx, acct)
if err != nil {
return nil, Only(ctx, errors.Wrap(err, "connecting to graph API"))
}
return gc, nil
}