diff --git a/pkg/cmd/issue/create/create.go b/pkg/cmd/issue/create/create.go index 2a3dda638..f9fab11a1 100644 --- a/pkg/cmd/issue/create/create.go +++ b/pkg/cmd/issue/create/create.go @@ -179,18 +179,12 @@ func createRun(opts *CreateOptions) (err error) { // Replace special values in assignees // For web mode, @copilot should be replaced by name; otherwise, login. - assigneeSet := set.NewStringSet() - meReplacer := prShared.NewMeReplacer(apiClient, baseRepo.RepoHost()) - copilotReplacer := prShared.NewCopilotReplacer(!opts.WebMode) - assignees, err := meReplacer.ReplaceSlice(opts.Assignees) + assigneeReplacer := prShared.NewSpecialAssigneeReplacer(apiClient, baseRepo.RepoHost(), issueFeatures.ActorIsAssignable, !opts.WebMode) + assignees, err := assigneeReplacer.ReplaceSlice(opts.Assignees) if err != nil { return err } - - // TODO actorIsAssignableCleanup - if issueFeatures.ActorIsAssignable { - assignees = copilotReplacer.ReplaceSlice(assignees) - } + assigneeSet := set.NewStringSet() assigneeSet.AddValues(assignees) tb := prShared.IssueMetadataState{ diff --git a/pkg/cmd/pr/shared/editable.go b/pkg/cmd/pr/shared/editable.go index 1e13146c2..02fe5d33c 100644 --- a/pkg/cmd/pr/shared/editable.go +++ b/pkg/cmd/pr/shared/editable.go @@ -95,22 +95,7 @@ func (e Editable) AssigneeIds(client *api.Client, repo ghrepo.Interface) (*[]str // If assignees came in from command line flags, we need to // curate the final list of assignees from the default list. if len(e.Assignees.Add) != 0 || len(e.Assignees.Remove) != 0 { - meReplacer := NewMeReplacer(client, repo.RepoHost()) - copilotReplacer := NewCopilotReplacer(true) - - replaceSpecialAssigneeNames := func(value []string) ([]string, error) { - replaced, err := meReplacer.ReplaceSlice(value) - if err != nil { - return nil, err - } - - // Only suppported for actor assignees. - if e.Assignees.ActorAssignees { - replaced = copilotReplacer.ReplaceSlice(replaced) - } - - return replaced, nil - } + replacer := NewSpecialAssigneeReplacer(client, repo.RepoHost(), e.Assignees.ActorAssignees, true) assigneeSet := set.NewStringSet() @@ -128,13 +113,13 @@ func (e Editable) AssigneeIds(client *api.Client, repo ghrepo.Interface) (*[]str assigneeSet.AddValues(e.Assignees.Default) } - add, err := replaceSpecialAssigneeNames(e.Assignees.Add) + add, err := replacer.ReplaceSlice(e.Assignees.Add) if err != nil { return nil, err } assigneeSet.AddValues(add) - remove, err := replaceSpecialAssigneeNames(e.Assignees.Remove) + remove, err := replacer.ReplaceSlice(e.Assignees.Remove) if err != nil { return nil, err } @@ -156,28 +141,18 @@ func (e Editable) AssigneeLogins(client *api.Client, repo ghrepo.Interface) ([]s } if len(e.Assignees.Add) != 0 || len(e.Assignees.Remove) != 0 { - meReplacer := NewMeReplacer(client, repo.RepoHost()) - copilotReplacer := NewCopilotReplacer(true) - - replaceSpecialAssigneeNames := func(value []string) ([]string, error) { - replaced, err := meReplacer.ReplaceSlice(value) - if err != nil { - return nil, err - } - replaced = copilotReplacer.ReplaceSlice(replaced) - return replaced, nil - } + replacer := NewSpecialAssigneeReplacer(client, repo.RepoHost(), true, true) assigneeSet := set.NewStringSet() assigneeSet.AddValues(e.Assignees.DefaultLogins) - add, err := replaceSpecialAssigneeNames(e.Assignees.Add) + add, err := replacer.ReplaceSlice(e.Assignees.Add) if err != nil { return nil, err } assigneeSet.AddValues(add) - remove, err := replaceSpecialAssigneeNames(e.Assignees.Remove) + remove, err := replacer.ReplaceSlice(e.Assignees.Remove) if err != nil { return nil, err } @@ -189,6 +164,37 @@ func (e Editable) AssigneeLogins(client *api.Client, repo ghrepo.Interface) ([]s return e.Assignees.Value, nil } +// SpecialAssigneeReplacer expands special assignee names (@me, Copilot actors) +// in login slices. Use NewSpecialAssigneeReplacer to create one. +type SpecialAssigneeReplacer struct { + meReplacer *MeReplacer + copilotReplacer *CopilotReplacer + actorAssignees bool +} + +// NewSpecialAssigneeReplacer creates a replacer that expands @me and (when +// actorAssignees is true) Copilot actor names in assignee slices. +// copilotUseLogin controls whether Copilot actors are replaced with their +// login (true) or display name (false, used for web mode). +func NewSpecialAssigneeReplacer(client *api.Client, host string, actorAssignees bool, copilotUseLogin bool) *SpecialAssigneeReplacer { + return &SpecialAssigneeReplacer{ + meReplacer: NewMeReplacer(client, host), + copilotReplacer: NewCopilotReplacer(copilotUseLogin), + actorAssignees: actorAssignees, + } +} + +func (r *SpecialAssigneeReplacer) ReplaceSlice(logins []string) ([]string, error) { + replaced, err := r.meReplacer.ReplaceSlice(logins) + if err != nil { + return nil, err + } + if r.actorAssignees { + replaced = r.copilotReplacer.ReplaceSlice(replaced) + } + return replaced, nil +} + // ProjectIds returns a slice containing IDs of projects v1 that the issue or a PR has to be linked to. func (e Editable) ProjectIds() (*[]string, error) { if !e.Projects.Edited {