mirror of
https://gitea.com/gitea/tea.git
synced 2026-09-10 07:26:33 -04:00
feat(pulls): add reviewer-request subcommands and create-time flags (#571)
Closes #571. Adds three pieces: - 'tea pulls create --reviewer <user>[,<user>...] [--team-reviewer <team>...]' to request reviews at PR-creation time (passes through to CreatePullRequestOption.Reviewers / TeamReviewers). - 'tea pulls request-review <idx> [<idx>...]' / 'tea pulls cancel-review ...' subcommands wrapping POST/DELETE /requested_reviewers, with both --reviewer and --team-reviewer CSV flags. - 'tea pulls reviewers' listing subcommand (GET /reviewers) so users can discover who can be requested before they invoke the above. The WIP/draft toggle was deliberately deferred: upstream main already exposes 'tea pulls create --draft' and 'tea pulls edit --draft/--ready' (PR #1008), so this patch stays focused on reviewer support only. Verification: make fmt fmt-check vet lint test docs docs-check build ./tea pulls create --help / request-review --help / cancel-review --help / reviewers --help Signed-off-by: Ross Golder <ross@golder.org>
This commit is contained in:
parent
6435b12202
commit
5d3db5d859
|
|
@ -1,5 +1,10 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
* FEATURES
|
||||||
|
* Add `tea pulls request-review` / `tea pulls cancel-review` subcommands and `--reviewer` / `--team-reviewer` flags on `tea pulls create` (#571)
|
||||||
|
|
||||||
## [v0.13.0](https://gitea.com/gitea/tea/releases/tag/v0.13.0) - 2026-04-05
|
## [v0.13.0](https://gitea.com/gitea/tea/releases/tag/v0.13.0) - 2026-04-05
|
||||||
|
|
||||||
* FEATURES
|
* FEATURES
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,10 @@ EXAMPLES
|
||||||
# your local "upstream" git remote
|
# your local "upstream" git remote
|
||||||
# list open pulls for any gitea repo at the given login instance
|
# list open pulls for any gitea repo at the given login instance
|
||||||
tea pulls --repo gitea/tea --login gitea.com
|
tea pulls --repo gitea/tea --login gitea.com
|
||||||
|
tea pulls create --reviewer alice,bob --team-reviewer owners # create a PR and request reviews
|
||||||
|
tea pulls request-review 7 --reviewer alice # request reviews on an existing PR
|
||||||
|
tea pulls cancel-review 7 --reviewer alice # cancel previously requested reviews
|
||||||
|
tea pulls reviewers # list users that can be requested to review
|
||||||
|
|
||||||
tea milestone issues 0.7.0 # view open issues for milestone '0.7.0'
|
tea milestone issues 0.7.0 # view open issues for milestone '0.7.0'
|
||||||
tea issue 189 # view contents of issue 189
|
tea issue 189 # view contents of issue 189
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,9 @@ var CmdPulls = cli.Command{
|
||||||
&pulls.CmdPullsReviewComments,
|
&pulls.CmdPullsReviewComments,
|
||||||
&pulls.CmdPullsResolve,
|
&pulls.CmdPullsResolve,
|
||||||
&pulls.CmdPullsUnresolve,
|
&pulls.CmdPullsUnresolve,
|
||||||
|
&pulls.CmdPullsRequestReview,
|
||||||
|
&pulls.CmdPullsCancelReview,
|
||||||
|
&pulls.CmdPullsReviewers,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
71
cmd/pulls/cancel_review.go
Normal file
71
cmd/pulls/cancel_review.go
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package pulls
|
||||||
|
|
||||||
|
import (
|
||||||
|
stdctx "context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
gitea "gitea.dev/sdk"
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
|
"gitea.dev/tea/cmd/flags"
|
||||||
|
"gitea.dev/tea/modules/context"
|
||||||
|
"gitea.dev/tea/modules/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CmdPullsCancelReview cancels previously requested reviews on one or more PRs
|
||||||
|
var CmdPullsCancelReview = cli.Command{
|
||||||
|
Name: "cancel-review",
|
||||||
|
Aliases: []string{"cr"},
|
||||||
|
Usage: "Cancel requested reviews from users or teams on a pull request",
|
||||||
|
Description: `Calls DELETE /repos/{owner}/{repo}/pulls/{index}/requested_reviewers.
|
||||||
|
At least one of --reviewer or --team-reviewer is required.`,
|
||||||
|
ArgsUsage: "<pull index> [<pull index>...]",
|
||||||
|
Action: runCancelReview,
|
||||||
|
Flags: append([]cli.Flag{
|
||||||
|
ReviewerFlag,
|
||||||
|
TeamReviewerFlag,
|
||||||
|
}, flags.AllDefaultFlags...),
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCancelReview(requestCtx stdctx.Context, cmd *cli.Command) error {
|
||||||
|
ctx, err := context.InitCommand(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := ctx.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
reviewers, err := ReviewerFlag.GetValues(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
teamReviewers, err := TeamReviewerFlag.GetValues(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(reviewers) == 0 && len(teamReviewers) == 0 {
|
||||||
|
return errors.New("at least one of --reviewer or --team-reviewer is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
indices, err := utils.ArgsToIndices(cmd.Args().Slice())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := ctx.Login.Client()
|
||||||
|
for _, idx := range indices {
|
||||||
|
if _, err := client.PullRequests.DeleteReviewRequests(requestCtx, ctx.Owner, ctx.Repo, idx, gitea.PullReviewRequestOptions{
|
||||||
|
Reviewers: reviewers,
|
||||||
|
TeamReviewers: teamReviewers,
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("PR#%d: canceled review requests for %v, teams %v\n", idx, reviewers, teamReviewers)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
58
cmd/pulls/cancel_review_test.go
Normal file
58
cmd/pulls/cancel_review_test.go
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package pulls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCancelReviewCommandMetadata(t *testing.T) {
|
||||||
|
cmd := &CmdPullsCancelReview
|
||||||
|
|
||||||
|
assert.Equal(t, "cancel-review", cmd.Name)
|
||||||
|
assert.Contains(t, cmd.Aliases, "cr")
|
||||||
|
assert.Equal(t, "Cancel requested reviews from users or teams on a pull request", cmd.Usage)
|
||||||
|
assert.Equal(t, "<pull index> [<pull index>...]", cmd.ArgsUsage)
|
||||||
|
assert.NotNil(t, cmd.Action)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCancelReviewCommandFlags(t *testing.T) {
|
||||||
|
cmd := &CmdPullsCancelReview
|
||||||
|
|
||||||
|
expectedFlags := []string{
|
||||||
|
"reviewer",
|
||||||
|
"team-reviewer",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, flagName := range expectedFlags {
|
||||||
|
found := false
|
||||||
|
for _, flag := range cmd.Flags {
|
||||||
|
if flag.Names()[0] == flagName {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.True(t, found, "Expected flag %s not found", flagName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestCancelReviewReusesReviewerFlag ensures request-review and cancel-review
|
||||||
|
// expose the same flag set, so the validation rules stay in sync.
|
||||||
|
func TestCancelReviewReusesReviewerFlag(t *testing.T) {
|
||||||
|
assert.Equal(t,
|
||||||
|
flagNames(CmdPullsRequestReview.Flags),
|
||||||
|
flagNames(CmdPullsCancelReview.Flags),
|
||||||
|
"request-review and cancel-review should expose identical flag sets")
|
||||||
|
}
|
||||||
|
|
||||||
|
func flagNames(flags []cli.Flag) []string {
|
||||||
|
names := make([]string, 0, len(flags))
|
||||||
|
for _, f := range flags {
|
||||||
|
names = append(names, f.Names()[0])
|
||||||
|
}
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
@ -51,6 +51,8 @@ var CmdPullsCreate = cli.Command{
|
||||||
Name: "draft",
|
Name: "draft",
|
||||||
Usage: "Create as a draft (prepends \"WIP: \" to the title; Gitea treats WIP-prefixed PRs as drafts)",
|
Usage: "Create as a draft (prepends \"WIP: \" to the title; Gitea treats WIP-prefixed PRs as drafts)",
|
||||||
},
|
},
|
||||||
|
ReviewerFlag,
|
||||||
|
TeamReviewerFlag,
|
||||||
}, flags.IssuePRCreateFlags...),
|
}, flags.IssuePRCreateFlags...),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,6 +110,15 @@ func runPullsCreate(requestCtx stdctx.Context, cmd *cli.Command) error {
|
||||||
allowMaintainerEdits = gitea.OptionalBool(ctx.Bool("allow-maintainer-edits"))
|
allowMaintainerEdits = gitea.OptionalBool(ctx.Bool("allow-maintainer-edits"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reviewers, err := ReviewerFlag.GetValues(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
teamReviewers, err := TeamReviewerFlag.GetValues(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return task.CreatePull(
|
return task.CreatePull(
|
||||||
requestCtx,
|
requestCtx,
|
||||||
ctx,
|
ctx,
|
||||||
|
|
@ -115,5 +126,7 @@ func runPullsCreate(requestCtx stdctx.Context, cmd *cli.Command) error {
|
||||||
ctx.String("head"),
|
ctx.String("head"),
|
||||||
allowMaintainerEdits,
|
allowMaintainerEdits,
|
||||||
opts,
|
opts,
|
||||||
|
reviewers,
|
||||||
|
teamReviewers,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
45
cmd/pulls/create_test.go
Normal file
45
cmd/pulls/create_test.go
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package pulls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreateCommandMetadata(t *testing.T) {
|
||||||
|
cmd := &CmdPullsCreate
|
||||||
|
|
||||||
|
assert.Equal(t, "create", cmd.Name)
|
||||||
|
assert.Contains(t, cmd.Aliases, "c")
|
||||||
|
assert.Equal(t, "Create a pull-request", cmd.Usage)
|
||||||
|
assert.NotNil(t, cmd.Action)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateCommandFlags(t *testing.T) {
|
||||||
|
cmd := &CmdPullsCreate
|
||||||
|
|
||||||
|
expectedFlags := []string{
|
||||||
|
"head",
|
||||||
|
"base",
|
||||||
|
"allow-maintainer-edits",
|
||||||
|
"agit",
|
||||||
|
"topic",
|
||||||
|
"draft",
|
||||||
|
"reviewer",
|
||||||
|
"team-reviewer",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, flagName := range expectedFlags {
|
||||||
|
found := false
|
||||||
|
for _, flag := range cmd.Flags {
|
||||||
|
if flag.Names()[0] == flagName {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.True(t, found, "Expected flag %s not found", flagName)
|
||||||
|
}
|
||||||
|
}
|
||||||
89
cmd/pulls/request_review.go
Normal file
89
cmd/pulls/request_review.go
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package pulls
|
||||||
|
|
||||||
|
import (
|
||||||
|
stdctx "context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
gitea "gitea.dev/sdk"
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
|
"gitea.dev/tea/cmd/flags"
|
||||||
|
"gitea.dev/tea/modules/context"
|
||||||
|
"gitea.dev/tea/modules/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReviewerFlag is a CSV flag listing usernames to request review from.
|
||||||
|
// Note: no short alias because 'R' is already taken by --remote (see
|
||||||
|
// flags.RemoteFlag) and 'r' by --repo (see flags.RepoFlag).
|
||||||
|
var ReviewerFlag = flags.NewCsvFlag(
|
||||||
|
"reviewer",
|
||||||
|
"usernames to request review from",
|
||||||
|
nil,
|
||||||
|
nil, nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
// TeamReviewerFlag is a CSV flag listing team names to request review from
|
||||||
|
var TeamReviewerFlag = flags.NewCsvFlag(
|
||||||
|
"team-reviewer",
|
||||||
|
"team names to request review from",
|
||||||
|
[]string{"T"},
|
||||||
|
nil, nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
// CmdPullsRequestReview requests reviews from users or teams on one or more PRs
|
||||||
|
var CmdPullsRequestReview = cli.Command{
|
||||||
|
Name: "request-review",
|
||||||
|
Aliases: []string{"rr"},
|
||||||
|
Usage: "Request reviews from users or teams on a pull request",
|
||||||
|
Description: `Calls POST /repos/{owner}/{repo}/pulls/{index}/requested_reviewers.
|
||||||
|
At least one of --reviewer or --team-reviewer is required.`,
|
||||||
|
ArgsUsage: "<pull index> [<pull index>...]",
|
||||||
|
Action: runRequestReview,
|
||||||
|
Flags: append([]cli.Flag{
|
||||||
|
ReviewerFlag,
|
||||||
|
TeamReviewerFlag,
|
||||||
|
}, flags.AllDefaultFlags...),
|
||||||
|
}
|
||||||
|
|
||||||
|
func runRequestReview(requestCtx stdctx.Context, cmd *cli.Command) error {
|
||||||
|
ctx, err := context.InitCommand(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := ctx.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
reviewers, err := ReviewerFlag.GetValues(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
teamReviewers, err := TeamReviewerFlag.GetValues(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(reviewers) == 0 && len(teamReviewers) == 0 {
|
||||||
|
return errors.New("at least one of --reviewer or --team-reviewer is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
indices, err := utils.ArgsToIndices(cmd.Args().Slice())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := ctx.Login.Client()
|
||||||
|
for _, idx := range indices {
|
||||||
|
if _, err := client.PullRequests.CreateReviewRequests(requestCtx, ctx.Owner, ctx.Repo, idx, gitea.PullReviewRequestOptions{
|
||||||
|
Reviewers: reviewers,
|
||||||
|
TeamReviewers: teamReviewers,
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("PR#%d: requested reviewers %v, teams %v\n", idx, reviewers, teamReviewers)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
74
cmd/pulls/request_review_test.go
Normal file
74
cmd/pulls/request_review_test.go
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package pulls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRequestReviewCommandMetadata(t *testing.T) {
|
||||||
|
cmd := &CmdPullsRequestReview
|
||||||
|
|
||||||
|
assert.Equal(t, "request-review", cmd.Name)
|
||||||
|
assert.Contains(t, cmd.Aliases, "rr")
|
||||||
|
assert.Equal(t, "Request reviews from users or teams on a pull request", cmd.Usage)
|
||||||
|
assert.Equal(t, "<pull index> [<pull index>...]", cmd.ArgsUsage)
|
||||||
|
assert.NotNil(t, cmd.Action)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRequestReviewCommandFlags(t *testing.T) {
|
||||||
|
cmd := &CmdPullsRequestReview
|
||||||
|
|
||||||
|
expectedFlags := []string{
|
||||||
|
"reviewer",
|
||||||
|
"team-reviewer",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, flagName := range expectedFlags {
|
||||||
|
found := false
|
||||||
|
for _, flag := range cmd.Flags {
|
||||||
|
if flag.Names()[0] == flagName {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.True(t, found, "Expected flag %s not found", flagName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestRequestReviewValidation asserts the inline guard shared between
|
||||||
|
// runRequestReview and runCancelReview: at least one of --reviewer or
|
||||||
|
// --team-reviewer must be supplied.
|
||||||
|
func TestRequestReviewValidation(t *testing.T) {
|
||||||
|
const msg = "at least one of --reviewer or --team-reviewer is required"
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
reviewers []string
|
||||||
|
teams []string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{name: "both empty", reviewers: nil, teams: nil, wantErr: true},
|
||||||
|
{name: "empty slice reviewers", reviewers: []string{}, teams: nil, wantErr: true},
|
||||||
|
{name: "reviewer only", reviewers: []string{"alice"}, teams: nil, wantErr: false},
|
||||||
|
{name: "team only", reviewers: nil, teams: []string{"devs"}, wantErr: false},
|
||||||
|
{name: "both set", reviewers: []string{"alice", "bob"}, teams: []string{"devs"}, wantErr: false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
if len(tt.reviewers) == 0 && len(tt.teams) == 0 {
|
||||||
|
err = errors.New(msg)
|
||||||
|
}
|
||||||
|
if tt.wantErr {
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Equal(t, msg, err.Error())
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
39
cmd/pulls/reviewers.go
Normal file
39
cmd/pulls/reviewers.go
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package pulls
|
||||||
|
|
||||||
|
import (
|
||||||
|
stdctx "context"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
|
||||||
|
"gitea.dev/tea/cmd/flags"
|
||||||
|
"gitea.dev/tea/modules/context"
|
||||||
|
"gitea.dev/tea/modules/print"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CmdPullsReviewers lists users that can be requested to review pull requests
|
||||||
|
var CmdPullsReviewers = cli.Command{
|
||||||
|
Name: "reviewers",
|
||||||
|
Aliases: []string{"rs"},
|
||||||
|
Usage: "List users that can be requested to review pull requests in this repo",
|
||||||
|
Description: `Calls GET /repos/{owner}/{repo}/reviewers.`,
|
||||||
|
Action: runReviewersList,
|
||||||
|
Flags: flags.AllDefaultFlags,
|
||||||
|
}
|
||||||
|
|
||||||
|
func runReviewersList(requestCtx stdctx.Context, cmd *cli.Command) error {
|
||||||
|
ctx, err := context.InitCommand(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := ctx.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
users, _, err := ctx.Login.Client().Repositories.GetReviewers(requestCtx, ctx.Owner, ctx.Repo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return print.ReviewersList(users, ctx.Output)
|
||||||
|
}
|
||||||
39
cmd/pulls/reviewers_test.go
Normal file
39
cmd/pulls/reviewers_test.go
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package pulls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReviewersCommandMetadata(t *testing.T) {
|
||||||
|
cmd := &CmdPullsReviewers
|
||||||
|
|
||||||
|
assert.Equal(t, "reviewers", cmd.Name)
|
||||||
|
assert.Contains(t, cmd.Aliases, "rs")
|
||||||
|
assert.Equal(t,
|
||||||
|
"List users that can be requested to review pull requests in this repo",
|
||||||
|
cmd.Usage)
|
||||||
|
assert.NotNil(t, cmd.Action)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReviewersCommandFlags(t *testing.T) {
|
||||||
|
cmd := &CmdPullsReviewers
|
||||||
|
|
||||||
|
// The reviewers subcommand inherits flags.AllDefaultFlags, which adds
|
||||||
|
// --login, --repo, --remote and --output. Verify those are wired.
|
||||||
|
expectedFlags := []string{"login", "repo", "remote", "output"}
|
||||||
|
for _, flagName := range expectedFlags {
|
||||||
|
found := false
|
||||||
|
for _, flag := range cmd.Flags {
|
||||||
|
if flag.Names()[0] == flagName {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.True(t, found, "Expected default flag %s not found", flagName)
|
||||||
|
}
|
||||||
|
}
|
||||||
60
docs/CLI.md
60
docs/CLI.md
|
|
@ -395,6 +395,14 @@ Create a pull-request
|
||||||
|
|
||||||
**--repo, -r**="": Override local repository path or gitea repository slug to interact with. Optional
|
**--repo, -r**="": Override local repository path or gitea repository slug to interact with. Optional
|
||||||
|
|
||||||
|
**--reviewer**="": Comma-separated list of usernames to request review from.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**--team-reviewer, -T**="": Comma-separated list of team names to request review from.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**--title, -t**="":
|
**--title, -t**="":
|
||||||
|
|
||||||
**--topic**="": Topic name for agit flow pull request
|
**--topic**="": Topic name for agit flow pull request
|
||||||
|
|
@ -567,6 +575,58 @@ Unresolve a review comment on a pull request
|
||||||
|
|
||||||
**--repo, -r**="": Override local repository path or gitea repository slug to interact with. Optional
|
**--repo, -r**="": Override local repository path or gitea repository slug to interact with. Optional
|
||||||
|
|
||||||
|
### request-review, rr
|
||||||
|
|
||||||
|
Request reviews from users or teams on a pull request
|
||||||
|
|
||||||
|
**--login, -l**="": Use a different Gitea Login. Optional
|
||||||
|
|
||||||
|
**--output, -o**="": Output format. (simple, table, csv, tsv, yaml, json)
|
||||||
|
|
||||||
|
**--remote, -R**="": Discover Gitea login from remote. Optional
|
||||||
|
|
||||||
|
**--repo, -r**="": Override local repository path or gitea repository slug to interact with. Optional
|
||||||
|
|
||||||
|
**--reviewer**="": Comma-separated list of usernames to request review from.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**--team-reviewer, -T**="": Comma-separated list of team names to request review from.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### cancel-review, cr
|
||||||
|
|
||||||
|
Cancel requested reviews from users or teams on a pull request
|
||||||
|
|
||||||
|
**--login, -l**="": Use a different Gitea Login. Optional
|
||||||
|
|
||||||
|
**--output, -o**="": Output format. (simple, table, csv, tsv, yaml, json)
|
||||||
|
|
||||||
|
**--remote, -R**="": Discover Gitea login from remote. Optional
|
||||||
|
|
||||||
|
**--repo, -r**="": Override local repository path or gitea repository slug to interact with. Optional
|
||||||
|
|
||||||
|
**--reviewer**="": Comma-separated list of usernames to request review from.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**--team-reviewer, -T**="": Comma-separated list of team names to request review from.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### reviewers, rs
|
||||||
|
|
||||||
|
List users that can be requested to review pull requests in this repo
|
||||||
|
|
||||||
|
**--login, -l**="": Use a different Gitea Login. Optional
|
||||||
|
|
||||||
|
**--output, -o**="": Output format. (simple, table, csv, tsv, yaml, json)
|
||||||
|
|
||||||
|
**--remote, -R**="": Discover Gitea login from remote. Optional
|
||||||
|
|
||||||
|
**--repo, -r**="": Override local repository path or gitea repository slug to interact with. Optional
|
||||||
|
|
||||||
## labels, label
|
## labels, label
|
||||||
|
|
||||||
Manage issue labels
|
Manage issue labels
|
||||||
|
|
|
||||||
|
|
@ -140,5 +140,7 @@ func CreatePull(requestCtx stdctx.Context, ctx *context.TeaContext) (err error)
|
||||||
base,
|
base,
|
||||||
head,
|
head,
|
||||||
&allowMaintainerEdits,
|
&allowMaintainerEdits,
|
||||||
&opts)
|
&opts,
|
||||||
|
nil,
|
||||||
|
nil)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
25
modules/print/pull_reviewers.go
Normal file
25
modules/print/pull_reviewers.go
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package print
|
||||||
|
|
||||||
|
import (
|
||||||
|
gitea "gitea.dev/sdk"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReviewersList prints a list of users eligible to be requested as PR reviewers
|
||||||
|
func ReviewersList(users []*gitea.User, output string) error {
|
||||||
|
t := tableWithHeader(
|
||||||
|
"Username",
|
||||||
|
"Full Name",
|
||||||
|
"Email",
|
||||||
|
)
|
||||||
|
for _, u := range users {
|
||||||
|
t.addRow(
|
||||||
|
u.UserName,
|
||||||
|
u.FullName,
|
||||||
|
u.Email,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return t.print(output)
|
||||||
|
}
|
||||||
|
|
@ -25,7 +25,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreatePull creates a PR in the given repo and prints the result
|
// CreatePull creates a PR in the given repo and prints the result
|
||||||
func CreatePull(requestCtx stdctx.Context, ctx *context.TeaContext, base, head string, allowMaintainerEdits *bool, opts *gitea.CreateIssueOption) (err error) {
|
func CreatePull(requestCtx stdctx.Context, ctx *context.TeaContext, base, head string, allowMaintainerEdits *bool, opts *gitea.CreateIssueOption, reviewers, teamReviewers []string) (err error) {
|
||||||
// default is default branch
|
// default is default branch
|
||||||
if len(base) == 0 {
|
if len(base) == 0 {
|
||||||
base, err = GetDefaultPRBase(requestCtx, ctx.Login, ctx.Owner, ctx.Repo)
|
base, err = GetDefaultPRBase(requestCtx, ctx.Login, ctx.Owner, ctx.Repo)
|
||||||
|
|
@ -64,14 +64,16 @@ func CreatePull(requestCtx stdctx.Context, ctx *context.TeaContext, base, head s
|
||||||
client := ctx.Login.Client()
|
client := ctx.Login.Client()
|
||||||
|
|
||||||
pr, _, err := client.PullRequests.CreatePullRequest(requestCtx, ctx.Owner, ctx.Repo, gitea.CreatePullRequestOption{
|
pr, _, err := client.PullRequests.CreatePullRequest(requestCtx, ctx.Owner, ctx.Repo, gitea.CreatePullRequestOption{
|
||||||
Head: head,
|
Head: head,
|
||||||
Base: base,
|
Base: base,
|
||||||
Title: opts.Title,
|
Title: opts.Title,
|
||||||
Body: opts.Body,
|
Body: opts.Body,
|
||||||
Assignees: opts.Assignees,
|
Assignees: opts.Assignees,
|
||||||
Labels: opts.Labels,
|
Reviewers: reviewers,
|
||||||
Milestone: opts.Milestone,
|
TeamReviewers: teamReviewers,
|
||||||
Deadline: opts.Deadline,
|
Labels: opts.Labels,
|
||||||
|
Milestone: opts.Milestone,
|
||||||
|
Deadline: opts.Deadline,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not create PR from %s to %s:%s: %s", head, ctx.Owner, base, err)
|
return fmt.Errorf("could not create PR from %s to %s:%s: %s", head, ctx.Owner, base, err)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue