Skip to content

Commit

Permalink
SUP-2587 | Support inviting users via the CLI (#367)
Browse files Browse the repository at this point in the history
* Allow users to be invited to the org.

* Remove RunE from base User command so help prints.

* Add USER as usage option in README
  • Loading branch information
mcncl authored Oct 10, 2024
1 parent d5343af commit a7904e6
Show file tree
Hide file tree
Showing 7 changed files with 265 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Available Commands:
package Manage packages
pipeline Manage pipelines
use Select an organization
user Invite users to the organization
Flags:
-h, --help help for bk
Expand Down
139 changes: 139 additions & 0 deletions internal/graphql/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions internal/organization/organization.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
query GetOrganizationID ($slug: ID!) {
organization(slug: $slug){
id
}
}

7 changes: 7 additions & 0 deletions internal/user/user.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mutation InviteUser($organization: ID!, $emails: [String!]!) {
organizationInvitationCreate(
input: { organizationID: $organization, emails: $emails }
) {
clientMutationId
}
}
2 changes: 2 additions & 0 deletions pkg/cmd/root/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
pipelineCmd "github.com/buildkite/cli/v3/pkg/cmd/pipeline"
packageCmd "github.com/buildkite/cli/v3/pkg/cmd/pkg"
useCmd "github.com/buildkite/cli/v3/pkg/cmd/use"
"github.com/buildkite/cli/v3/pkg/cmd/user"
versionCmd "github.com/buildkite/cli/v3/pkg/cmd/version"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -51,6 +52,7 @@ func NewCmdRoot(f *factory.Factory) (*cobra.Command, error) {
cmd.AddCommand(pipelineCmd.NewCmdPipeline(f))
cmd.AddCommand(packageCmd.NewCmdPackage(f))
cmd.AddCommand(useCmd.NewCmdUse(f))
cmd.AddCommand(user.CommandUser(f))
cmd.AddCommand(versionCmd.NewCmdVersion(f))

cmd.Flags().BoolP("version", "v", false, "Print the version number")
Expand Down
84 changes: 84 additions & 0 deletions pkg/cmd/user/invite.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package user

import (
"context"
"fmt"
"sync"

"github.com/MakeNowJust/heredoc"
"github.com/buildkite/cli/v3/internal/graphql"
"github.com/buildkite/cli/v3/pkg/cmd/factory"
"github.com/spf13/cobra"
)

func CommandUserInvite(f *factory.Factory) *cobra.Command {
cmd := &cobra.Command{
Use: "invite [emails]",
Short: "Invite users to your organization",
Long: heredoc.Doc(`
Invite 1 or many users to your organization.
`),
Example: heredoc.Doc(`
# Invite a single user to your organization
$ bk user invite bob@supercoolorg.com
# Invite multiple users to your organization
$ bk user invite bob@supercoolorg.com bobs_mate@supercoolorg.com
`),
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return fmt.Errorf("at least one email address is required")
}

orgID, err := graphql.GetOrganizationID(cmd.Context(), f.GraphQLClient, f.Config.OrganizationSlug())
if err != nil {
return err
}

return createInvite(cmd.Context(), f, orgID.Organization.GetId(), args...)
},
}
return cmd
}

func createInvite(ctx context.Context, f *factory.Factory, orgID string, emails ...string) error {
if len(emails) == 0 {
return nil
}

errChan := make(chan error, len(emails))
var wg sync.WaitGroup

for _, email := range emails {
wg.Add(1)
go func(email string) {
defer wg.Done()
_, err := graphql.InviteUser(ctx, f.GraphQLClient, orgID, []string{email})
if err != nil {
errChan <- fmt.Errorf("error creating user invite for %s: %w", email, err)
}
}(email)
}

go func() {
wg.Wait()
close(errChan)
}()

var errs []error
for err := range errChan {
errs = append(errs, err)
}

if len(errs) > 0 {
return fmt.Errorf("errors creating user invites: %v", errs)
}

message := "Invite sent to"
if len(emails) > 1 {
message = "Invites sent to"
}

fmt.Printf("%s: %v\n", message, emails)
return nil
}
26 changes: 26 additions & 0 deletions pkg/cmd/user/user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package user

import (
"github.com/MakeNowJust/heredoc"
"github.com/buildkite/cli/v3/pkg/cmd/factory"
"github.com/buildkite/cli/v3/pkg/cmd/validation"
"github.com/spf13/cobra"
)

func CommandUser(f *factory.Factory) *cobra.Command {
cmd := cobra.Command{
Use: "user <command>",
Short: "Invite users to the organization",
Long: heredoc.Doc(`
Manage organization users via the CLI.
To invite a user:
bk user invite [email address]
`),
PersistentPreRunE: validation.CheckValidConfiguration(f.Config),
}

cmd.AddCommand(CommandUserInvite(f))

return &cmd
}

0 comments on commit a7904e6

Please sign in to comment.