feat(assignees): add set, add, and remove assignees APIs (#1045)

Implemented set, add, and remove assignees APIs.
Closes https://gitea.com/gitea/tea/issues/965 and https://gitea.com/gitea/tea/issues/966Reviewed-on: https://gitea.com/gitea/tea/pulls/1045
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Minjie Fang <wingsallen@gmail.com>
This commit is contained in:
Minjie Fang
2026-07-18 00:20:03 +00:00
committed by Lunny Xiao
parent 2d6dcd062f
commit d664c01e18
11 changed files with 434 additions and 27 deletions
+49
View File
@@ -0,0 +1,49 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package task
import (
stdctx "context"
"fmt"
"strings"
gitea "gitea.dev/sdk"
)
// ResolveAssigneeOpts resolves assignee names to IssueAssigneesOption. Returns nil if names is empty.
func ResolveAssigneeOpts(names []string) *gitea.IssueAssigneesOption {
names = cleanAssignees(names)
if len(names) == 0 {
return nil
}
return &gitea.IssueAssigneesOption{Assignees: names}
}
// ApplyAssigneeChanges adds and removes assignees on an issue or pull request.
func ApplyAssigneeChanges(requestCtx stdctx.Context, client *gitea.Client, owner, repo string, index int64, add, rm *gitea.IssueAssigneesOption) error {
if rm != nil {
_, _, err := client.Issues.DeleteIssueAssignees(requestCtx, owner, repo, index, *rm)
if err != nil {
return fmt.Errorf("could not remove assignees: %s", err)
}
}
if add != nil {
_, _, err := client.Issues.AddIssueAssignees(requestCtx, owner, repo, index, *add)
if err != nil {
return fmt.Errorf("could not add assignees: %s", err)
}
}
return nil
}
func cleanAssignees(list []string) []string {
out := make([]string, 0, len(list))
for _, a := range list {
if strings.TrimSpace(a) != "" {
out = append(out, a)
}
}
return out
}
+18 -10
View File
@@ -23,23 +23,26 @@ type EditIssueOption struct {
Deadline *time.Time
AddLabels []string
RemoveLabels []string
SetAssignees []string
AddAssignees []string
RemoveAssignees []string
AddReviewers []string
RemoveReviewers []string
// RemoveAssignees []string // NOTE: with the current go-sdk, clearing assignees is not possible.
}
// Normalizes the options into parameters that can be passed to the sdk.
// the returned value will be nil, when no change to this part of the issue is requested.
func (o EditIssueOption) toSdkOptions(requestCtx stdctx.Context, ctx *context.TeaContext, client *gitea.Client) (*gitea.EditIssueOption, *gitea.IssueLabelsOption, *gitea.IssueLabelsOption, error) {
func (o EditIssueOption) toSdkOptions(requestCtx stdctx.Context, ctx *context.TeaContext, client *gitea.Client) (*gitea.EditIssueOption, *gitea.IssueLabelsOption, *gitea.IssueLabelsOption, *gitea.IssueAssigneesOption, *gitea.IssueAssigneesOption, error) {
addLabelOpts, err := ResolveLabelOpts(requestCtx, client, ctx.Owner, ctx.Repo, o.AddLabels)
if err != nil {
return nil, nil, nil, err
return nil, nil, nil, nil, nil, err
}
rmLabelOpts, err := ResolveLabelOpts(requestCtx, client, ctx.Owner, ctx.Repo, o.RemoveLabels)
if err != nil {
return nil, nil, nil, err
return nil, nil, nil, nil, nil, err
}
addAssigneeOpts := ResolveAssigneeOpts(o.AddAssignees)
rmAssigneeOpts := ResolveAssigneeOpts(o.RemoveAssignees)
issueOpts := gitea.EditIssueOption{}
var issueOptsDirty bool
@@ -58,7 +61,7 @@ func (o EditIssueOption) toSdkOptions(requestCtx stdctx.Context, ctx *context.Te
if o.Milestone != nil {
id, err := ResolveMilestoneID(requestCtx, client, ctx.Owner, ctx.Repo, *o.Milestone)
if err != nil {
return nil, nil, nil, err
return nil, nil, nil, nil, nil, err
}
issueOpts.Milestone = gitea.OptionalInt64(id)
issueOptsDirty = true
@@ -70,15 +73,16 @@ func (o EditIssueOption) toSdkOptions(requestCtx stdctx.Context, ctx *context.Te
issueOpts.RemoveDeadline = gitea.OptionalBool(true)
}
}
if len(o.AddAssignees) != 0 {
issueOpts.Assignees = o.AddAssignees
o.SetAssignees = cleanAssignees(o.SetAssignees)
if len(o.SetAssignees) != 0 {
issueOpts.Assignees = o.SetAssignees
issueOptsDirty = true
}
if issueOptsDirty {
return &issueOpts, addLabelOpts, rmLabelOpts, nil
return &issueOpts, addLabelOpts, rmLabelOpts, addAssigneeOpts, rmAssigneeOpts, nil
}
return nil, addLabelOpts, rmLabelOpts, nil
return nil, addLabelOpts, rmLabelOpts, addAssigneeOpts, rmAssigneeOpts, nil
}
// EditIssue edits an issue and returns the updated issue.
@@ -87,7 +91,7 @@ func EditIssue(requestCtx stdctx.Context, ctx *context.TeaContext, client *gitea
client = ctx.Login.Client()
}
issueOpts, addLabelOpts, rmLabelOpts, err := opts.toSdkOptions(requestCtx, ctx, client)
issueOpts, addLabelOpts, rmLabelOpts, addAssigneeOpts, rmAssigneeOpts, err := opts.toSdkOptions(requestCtx, ctx, client)
if err != nil {
return nil, err
}
@@ -96,6 +100,10 @@ func EditIssue(requestCtx stdctx.Context, ctx *context.TeaContext, client *gitea
return nil, err
}
if err := ApplyAssigneeChanges(requestCtx, client, ctx.Owner, ctx.Repo, opts.Index, addAssigneeOpts, rmAssigneeOpts); err != nil {
return nil, err
}
var issue *gitea.Issue
if issueOpts != nil {
issue, _, err = client.Issues.EditIssue(requestCtx, ctx.Owner, ctx.Repo, opts.Index, *issueOpts)
+9 -2
View File
@@ -25,6 +25,8 @@ func EditPull(requestCtx stdctx.Context, ctx *context.TeaContext, client *gitea.
if err != nil {
return nil, err
}
addAssigneeOpts := ResolveAssigneeOpts(opts.AddAssignees)
rmAssigneeOpts := ResolveAssigneeOpts(opts.RemoveAssignees)
prOpts := gitea.EditPullRequestOption{}
var prOptsDirty bool
@@ -51,8 +53,9 @@ func EditPull(requestCtx stdctx.Context, ctx *context.TeaContext, client *gitea.
prOpts.RemoveDeadline = gitea.OptionalBool(true)
}
}
if len(opts.AddAssignees) != 0 {
prOpts.Assignees = opts.AddAssignees
opts.SetAssignees = cleanAssignees(opts.SetAssignees)
if len(opts.SetAssignees) != 0 {
prOpts.Assignees = opts.SetAssignees
prOptsDirty = true
}
@@ -60,6 +63,10 @@ func EditPull(requestCtx stdctx.Context, ctx *context.TeaContext, client *gitea.
return nil, err
}
if err := ApplyAssigneeChanges(requestCtx, client, ctx.Owner, ctx.Repo, opts.Index, addAssigneeOpts, rmAssigneeOpts); err != nil {
return nil, err
}
if err := ApplyReviewerChanges(requestCtx, client, ctx.Owner, ctx.Repo, opts.Index, opts.AddReviewers, opts.RemoveReviewers); err != nil {
return nil, err
}