feat(teams): add members subcommands

Provide list, add, and remove operations for team members via
'tea teams members {list,create,delete}'. The members package reuses
the RequireTeamID helper exported by cmd/teams.
This commit is contained in:
Ross Golder 2026-07-30 10:27:06 +07:00
parent bcdd28f395
commit c8f75c9975
No known key found for this signature in database
GPG key ID: 253A7E508D2D59CD
6 changed files with 239 additions and 0 deletions

View file

@ -5,6 +5,7 @@ package cmd
import (
"gitea.dev/tea/cmd/teams"
"gitea.dev/tea/cmd/teams/members"
"github.com/urfave/cli/v3"
)
@ -21,6 +22,7 @@ var CmdTeams = cli.Command{
&teams.CmdTeamsCreate,
&teams.CmdTeamsDelete,
&teams.CmdTeamsEdit,
&members.CmdTeamsMembers,
},
Flags: []cli.Flag{
&cli.StringFlag{

View file

@ -0,0 +1,55 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package members
import (
stdctx "context"
"errors"
"fmt"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/cmd/teams"
"gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3"
)
// CmdTeamsMembersCreate adds a member to a team.
var CmdTeamsMembersCreate = cli.Command{
Name: "create",
Aliases: []string{"add", "c"},
Usage: "Add a member to a team",
Description: "Add a user to a team",
ArgsUsage: "<team-id> <username>",
Action: runTeamsMembersCreate,
Flags: flags.AllDefaultFlags,
}
func runTeamsMembersCreate(ctx stdctx.Context, cmd *cli.Command) error {
if cmd.Args().Len() < 2 {
return errors.New("team ID and username are required")
}
teamID, err := teams.RequireTeamID(cmd)
if err != nil {
return err
}
username := cmd.Args().Get(1)
c, err := context.InitCommand(cmd)
if err != nil {
return err
}
client := c.Login.Client()
team, _, err := client.Organizations.GetTeam(ctx, teamID)
if err != nil {
return err
}
if _, err = client.Organizations.AddTeamMember(ctx, teamID, username); err != nil {
return err
}
fmt.Printf("User '%s' added to team '%s' (ID: %d)\n", username, team.Name, team.ID)
return nil
}

View file

@ -0,0 +1,71 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package members
import (
stdctx "context"
"errors"
"fmt"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/cmd/teams"
"gitea.dev/tea/modules/context"
"github.com/urfave/cli/v3"
)
// CmdTeamsMembersDelete removes a member from a team.
var CmdTeamsMembersDelete = cli.Command{
Name: "delete",
Aliases: []string{"rm", "remove"},
Usage: "Remove a member from a team",
Description: "Remove a user from a team",
ArgsUsage: "<team-id> <username>",
Action: runTeamsMembersDelete,
Flags: append([]cli.Flag{
&cli.BoolFlag{
Name: "confirm",
Aliases: []string{"y"},
Usage: "confirm removal without prompting",
},
}, flags.AllDefaultFlags...),
}
func runTeamsMembersDelete(ctx stdctx.Context, cmd *cli.Command) error {
if cmd.Args().Len() < 2 {
return errors.New("team ID and username are required")
}
teamID, err := teams.RequireTeamID(cmd)
if err != nil {
return err
}
username := cmd.Args().Get(1)
c, err := context.InitCommand(cmd)
if err != nil {
return err
}
client := c.Login.Client()
team, _, err := client.Organizations.GetTeam(ctx, teamID)
if err != nil {
return err
}
if !cmd.Bool("confirm") {
fmt.Printf("Are you sure you want to remove '%s' from team '%s' (ID: %d)? [y/N] ", username, team.Name, team.ID)
var response string
fmt.Scanln(&response)
if response != "y" && response != "Y" && response != "yes" {
fmt.Println("Removal canceled.")
return nil
}
}
if _, err = client.Organizations.RemoveTeamMember(ctx, teamID, username); err != nil {
return err
}
fmt.Printf("User '%s' removed from team '%s' (ID: %d)\n", username, team.Name, team.ID)
return nil
}

58
cmd/teams/members/list.go Normal file
View file

@ -0,0 +1,58 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package members
import (
stdctx "context"
gitea "gitea.dev/sdk"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/cmd/teams"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3"
)
// CmdTeamsMembersList lists all members of a team.
var CmdTeamsMembersList = cli.Command{
Name: "list",
Aliases: []string{"ls"},
Usage: "List team members",
Description: "List all members of a team",
ArgsUsage: "<team-id>",
Action: runTeamsMembersList,
Flags: append([]cli.Flag{
&flags.PaginationPageFlag,
&flags.PaginationLimitFlag,
}, flags.AllDefaultFlags...),
}
func runTeamsMembersList(ctx stdctx.Context, cmd *cli.Command) error {
teamID, err := teams.RequireTeamID(cmd)
if err != nil {
return err
}
c, err := context.InitCommand(cmd)
if err != nil {
return err
}
client := c.Login.Client()
team, _, err := client.Organizations.GetTeam(ctx, teamID)
if err != nil {
return err
}
members, _, err := client.Organizations.ListTeamMembers(ctx, teamID, gitea.ListTeamMembersOptions{
ListOptions: flags.GetListOptions(cmd),
})
if err != nil {
return err
}
print.TeamMembersList(members, c.Output, team.Name)
return nil
}

View file

@ -0,0 +1,26 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package members
import (
stdctx "context"
"github.com/urfave/cli/v3"
)
// CmdTeamsMembers is the parent command for managing team membership.
var CmdTeamsMembers = cli.Command{
Name: "members",
Aliases: []string{"member"},
Usage: "Manage team members",
Description: "List, add, or remove team members",
Commands: []*cli.Command{
&CmdTeamsMembersList,
&CmdTeamsMembersCreate,
&CmdTeamsMembersDelete,
},
Action: func(ctx stdctx.Context, cmd *cli.Command) error {
return cli.ShowCommandHelp(ctx, cmd, "members")
},
}

View file

@ -68,3 +68,30 @@ func yesNo(b bool) string {
}
return "no"
}
// TeamMembersList prints a list of team members.
func TeamMembersList(members []*gitea.User, output, teamName string) {
if len(members) == 0 {
fmt.Printf("No members found in team '%s'\n", teamName)
return
}
t := tableWithHeader(
"ID",
"Username",
"Full Name",
"Email",
)
for _, m := range members {
t.addRow(
strconv.FormatInt(m.ID, 10),
m.UserName,
m.FullName,
m.Email,
)
}
fmt.Printf("Members of team '%s':\n", teamName)
t.print(output)
}