Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cmd/azdo/azdo.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,11 @@ func mainRun() exitCode {
var noResultsError cmdutil.NoResultsError
var extError *cmdutil.ExternalCommandExitError
var authError *root.AuthError

stderr := iostrms.ErrOut

zap.L().Sugar().Debugf("Processing error %v", err)

if errors.Is(err, cmdutil.ErrSilent) { //nolint:golint,gocritic
return exitError
} else if cmdutil.IsUserCancellation(err) {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.2
github.com/emirpasic/gods v1.18.1
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/google/uuid v1.3.0
github.com/mattn/go-colorable v0.1.13
github.com/mattn/go-isatty v0.0.19
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
Expand Down Expand Up @@ -39,7 +40,6 @@ require (
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/fatih/color v1.7.0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
Expand Down
135 changes: 124 additions & 11 deletions internal/cmd/auth/status/status.go
Original file line number Diff line number Diff line change
@@ -1,37 +1,150 @@
package status

import (
"fmt"

"github.com/MakeNowJust/heredoc"
"github.com/google/uuid"
"github.com/microsoft/azure-devops-go-api/azuredevops/v7/security"
"github.com/samber/lo"
"github.com/spf13/cobra"
"github.com/tmeckel/azdo-cli/internal/cmd/util"
)

type statusOptions struct {
ctx util.CmdContext

OrganizationName string
ShowToken bool
organizationName string
}

func NewCmdStatus(ctx util.CmdContext) *cobra.Command {
opts := &statusOptions{
ctx: ctx,
}
opts := &statusOptions{}

cmd := &cobra.Command{
Use: "status",
Args: cobra.ExactArgs(0),
Short: "View authentication status",
Long: heredoc.Doc(`Verifies and displays information about your authentication state.

This command will test your authentication state for each Azure DevOps organization that azdo knows about and
report any issues.
`),
RunE: func(cmd *cobra.Command, args []string) error {
return statusRun(opts)
return statusRun(ctx, opts)
},
}

cmd.Flags().StringVarP(&opts.OrganizationName, "organization", "o", "", "Check a specific oragnizations's auth status")
cmd.Flags().BoolVarP(&opts.ShowToken, "show-token", "t", false, "Display the auth token")
cmd.Flags().StringVarP(&opts.organizationName, "organization", "o", "", "Check a specific oragnizations's auth status")

return cmd
}

func statusRun(opts *statusOptions) error {
type organizationStatus struct {
organizationName string
err error
}

func fetchOrganizationStates(ctx util.CmdContext, organizationsToCheck []string) (<-chan organizationStatus, error) {
statusChannel := make(chan organizationStatus)

go func(channel chan<- organizationStatus) error {
rctx, err := ctx.Context()
if err != nil {
return err
}

for _, organizationName := range organizationsToCheck {
conn, err := ctx.Connection(organizationName)
if err != nil {
return err
}

client := security.NewClient(rctx, conn)

_, err = client.QuerySecurityNamespaces(rctx, security.QuerySecurityNamespacesArgs{SecurityNamespaceId: lo.ToPtr(uuid.MustParse("5a27515b-ccd7-42c9-84f1-54c998f03866"))})

status := organizationStatus{
organizationName: organizationName,
}
if err != nil {
status.err = err
}

channel <- status
}

close(statusChannel)
return nil
}(statusChannel) //nolint:golint,errcheck

return statusChannel, nil
}

func statusRun(ctx util.CmdContext, opts *statusOptions) (err error) {
cfg, err := ctx.Config()
if err != nil {
return
}
authCfg := cfg.Authentication()

organizations := authCfg.GetOrganizations()

iostrms, err := ctx.IOStreams()
if err != nil {
return
}

stderr := iostrms.ErrOut
cs := iostrms.ColorScheme()

if len(organizations) == 0 {
fmt.Fprintf(
stderr,
"You are not logged into any Azure DevOps organizations. Run %s to authenticate.\n",
cs.Bold("azdo auth login"),
)

return util.ErrSilent
}

organizationsToCheck := organizations

if opts.organizationName != "" {
if !lo.Contains(organizations, opts.organizationName) {
fmt.Fprintf(
stderr,
"You are not logged the Azure DevOps organization %s. Run %s to authenticate.\n",
cs.Red(opts.organizationName), cs.Bold("azdo auth login"),
)
return util.ErrSilent
}
organizationsToCheck = []string{opts.organizationName}
}

organizationStatusResults := []organizationStatus{}

iostrms.StartProgressIndicator()
organizationStatusChannel, err := fetchOrganizationStates(ctx, organizationsToCheck)
if err != nil {
return err
}

for {
result, ok := <-organizationStatusChannel
if !ok {
break
}
organizationStatusResults = append(organizationStatusResults, result)
}

iostrms.StopProgressIndicator()

for _, v := range organizationStatusResults {
if v.err != nil {
fmt.Fprintf(iostrms.Out,
"%s %s: failed to check authentication status\n", cs.Red("X"), cs.Bold(v.organizationName))
} else {
fmt.Fprintf(iostrms.Out,
"%s %s: successfully checked authentication status\n", cs.GreenBold("X"), cs.Bold(v.organizationName))
}
}
return nil
}
4 changes: 4 additions & 0 deletions internal/cmd/root/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ func NewCmdRoot(ctx util.CmdContext) (*cobra.Command, error) {

cmd.PersistentFlags().Bool("help", false, "Show help for command")

cmd.SilenceErrors = true
cmd.SilenceUsage = true

cmd.Flags().Bool("version", false, "Show azdo version")

cmd.SetHelpFunc(func(c *cobra.Command, args []string) {
rootHelpFunc(iostrms, c, args)
})
Expand Down