diff --git a/api/queries_pr.go b/api/queries_pr.go index 1b044a439..073ef6886 100644 --- a/api/queries_pr.go +++ b/api/queries_pr.go @@ -532,7 +532,7 @@ func CreatePullRequest(client *Client, repo *Repository, params map[string]inter } } - // TODO requestReviewsByLoginCleanup + // TODO ApiActorsSupported // Request reviewers using either login-based (github.com) or ID-based (GHES) mutation. // The ID-based path can be removed once GHES supports requestReviewsByLogin. userLogins, hasUserLogins := params["userReviewerLogins"].([]string) diff --git a/internal/featuredetection/feature_detection.go b/internal/featuredetection/feature_detection.go index 9af4c5aec..f0759bd3e 100644 --- a/internal/featuredetection/feature_detection.go +++ b/internal/featuredetection/feature_detection.go @@ -23,11 +23,17 @@ type Detector interface { } type IssueFeatures struct { - ActorIsAssignable bool + // TODO ApiActorsSupported + // ApiActorsSupported indicates the host supports actor-based APIs + // (replaceActorsForAssignable, requestReviewsByLogin, suggestedAssignableActors, etc.). + // True for github.com and ghe.com. False for GHES. + // Remove this flag once GHES supports these mutations, then collapse all + // // TODO ApiActorsSupported sites to the actor-only path. + ApiActorsSupported bool } var allIssueFeatures = IssueFeatures{ - ActorIsAssignable: true, + ApiActorsSupported: true, } type PullRequestFeatures struct { @@ -136,7 +142,7 @@ func (d *detector) IssueFeatures() (IssueFeatures, error) { } return IssueFeatures{ - ActorIsAssignable: false, // replaceActorsForAssignable GraphQL mutation unavailable on GHES + ApiActorsSupported: false, // TODO ApiActorsSupported — actor-based mutations unavailable on GHES }, nil } diff --git a/internal/featuredetection/feature_detection_test.go b/internal/featuredetection/feature_detection_test.go index 82132ab83..f24e31f4c 100644 --- a/internal/featuredetection/feature_detection_test.go +++ b/internal/featuredetection/feature_detection_test.go @@ -23,7 +23,7 @@ func TestIssueFeatures(t *testing.T) { name: "github.com", hostname: "github.com", wantFeatures: IssueFeatures{ - ActorIsAssignable: true, + ApiActorsSupported: true, }, wantErr: false, }, @@ -31,7 +31,7 @@ func TestIssueFeatures(t *testing.T) { name: "ghec data residency (ghe.com)", hostname: "stampname.ghe.com", wantFeatures: IssueFeatures{ - ActorIsAssignable: true, + ApiActorsSupported: true, }, wantErr: false, }, @@ -39,7 +39,7 @@ func TestIssueFeatures(t *testing.T) { name: "GHE", hostname: "git.my.org", wantFeatures: IssueFeatures{ - ActorIsAssignable: false, + ApiActorsSupported: false, }, wantErr: false, }, diff --git a/pkg/cmd/issue/create/create.go b/pkg/cmd/issue/create/create.go index 831495891..2712bc89d 100644 --- a/pkg/cmd/issue/create/create.go +++ b/pkg/cmd/issue/create/create.go @@ -179,7 +179,7 @@ func createRun(opts *CreateOptions) (err error) { // Replace special values in assignees // For web mode, @copilot should be replaced by name; otherwise, login. - assigneeReplacer := prShared.NewSpecialAssigneeReplacer(apiClient, baseRepo.RepoHost(), issueFeatures.ActorIsAssignable, !opts.WebMode) + assigneeReplacer := prShared.NewSpecialAssigneeReplacer(apiClient, baseRepo.RepoHost(), issueFeatures.ApiActorsSupported, !opts.WebMode) assignees, err := assigneeReplacer.ReplaceSlice(opts.Assignees) if err != nil { return err @@ -189,7 +189,7 @@ func createRun(opts *CreateOptions) (err error) { tb := prShared.IssueMetadataState{ Type: prShared.IssueMetadata, - ApiActorsSupported: issueFeatures.ActorIsAssignable, // TODO ApiActorsSupported + ApiActorsSupported: issueFeatures.ApiActorsSupported, // TODO ApiActorsSupported Assignees: assigneeSet.ToSlice(), Labels: opts.Labels, ProjectTitles: opts.Projects, @@ -309,7 +309,7 @@ func createRun(opts *CreateOptions) (err error) { State: &tb, } var assigneeSearchFunc func(string) prompter.MultiSelectSearchResult - if issueFeatures.ActorIsAssignable { + if issueFeatures.ApiActorsSupported { assigneeSearchFunc = prShared.RepoAssigneeSearchFunc(apiClient, baseRepo) } err = prShared.MetadataSurvey(opts.Prompter, opts.IO, baseRepo, fetcher, &tb, projectsV1Support, nil, assigneeSearchFunc) diff --git a/pkg/cmd/issue/edit/edit.go b/pkg/cmd/issue/edit/edit.go index 965fc0b49..1d5455504 100644 --- a/pkg/cmd/issue/edit/edit.go +++ b/pkg/cmd/issue/edit/edit.go @@ -216,7 +216,7 @@ func editRun(opts *EditOptions) error { lookupFields := []string{"id", "number", "title", "body", "url"} if editable.Assignees.Edited { // TODO ApiActorsSupported - if issueFeatures.ActorIsAssignable { + if issueFeatures.ApiActorsSupported { editable.ApiActorsSupported = true lookupFields = append(lookupFields, "assignedActors") } else { @@ -249,9 +249,9 @@ func editRun(opts *EditOptions) error { // Fetch editable shared fields once for all issues. apiClient := api.NewClientFromHTTP(httpClient) - // Wire up search function for assignees when ActorIsAssignable is available. + // Wire up search function for assignees when ApiActorsSupported is available. // Interactive mode only supports a single issue, so we use its ID for the search query. - if issueFeatures.ActorIsAssignable && opts.Interactive && len(issues) == 1 { + if issueFeatures.ApiActorsSupported && opts.Interactive && len(issues) == 1 { editable.AssigneeSearchFunc = prShared.AssigneeSearchFunc(apiClient, baseRepo, issues[0].ID) } diff --git a/pkg/cmd/issue/edit/edit_test.go b/pkg/cmd/issue/edit/edit_test.go index 41af97fef..626c28162 100644 --- a/pkg/cmd/issue/edit/edit_test.go +++ b/pkg/cmd/issue/edit/edit_test.go @@ -935,7 +935,7 @@ func mockProjectV2ItemUpdate(t *testing.T, reg *httpmock.Registry) { ) } -func TestActorIsAssignable(t *testing.T) { +func TestApiActorsSupported(t *testing.T) { t.Run("when actors are assignable, query includes assignedActors", func(t *testing.T) { ios, _, _, _ := iostreams.Test() diff --git a/pkg/cmd/pr/create/create.go b/pkg/cmd/pr/create/create.go index b62e04d73..37f658379 100644 --- a/pkg/cmd/pr/create/create.go +++ b/pkg/cmd/pr/create/create.go @@ -399,7 +399,7 @@ func createRun(opts *CreateOptions) error { client := ctx.Client - // Detect ActorIsAssignable feature to determine if we can use search-based + // Detect ApiActorsSupported feature to determine if we can use search-based // reviewer selection (github.com) or need to use legacy ID-based selection (GHES) issueFeatures, err := opts.Detector.IssueFeatures() if err != nil { @@ -407,7 +407,7 @@ func createRun(opts *CreateOptions) error { } var reviewerSearchFunc func(string) prompter.MultiSelectSearchResult var assigneeSearchFunc func(string) prompter.MultiSelectSearchResult - if issueFeatures.ActorIsAssignable { + if issueFeatures.ApiActorsSupported { reviewerSearchFunc = func(query string) prompter.MultiSelectSearchResult { candidates, moreResults, err := api.SuggestedReviewerActorsForRepo(client, ctx.PRRefs.BaseRepo(), query) if err != nil { @@ -430,7 +430,7 @@ func createRun(opts *CreateOptions) error { } // TODO ApiActorsSupported - if issueFeatures.ActorIsAssignable { + if issueFeatures.ApiActorsSupported { state.ApiActorsSupported = true } diff --git a/pkg/cmd/pr/edit/edit.go b/pkg/cmd/pr/edit/edit.go index c2535019b..33a71154a 100644 --- a/pkg/cmd/pr/edit/edit.go +++ b/pkg/cmd/pr/edit/edit.go @@ -270,8 +270,8 @@ func editRun(opts *EditOptions) error { return err } - // TODO actorIsAssignableCleanup - if issueFeatures.ActorIsAssignable { + // TODO ApiActorsSupported + if issueFeatures.ApiActorsSupported { findOptions.Fields = append(findOptions.Fields, "assignedActors") } else { findOptions.Fields = append(findOptions.Fields, "assignees") @@ -290,7 +290,7 @@ func editRun(opts *EditOptions) error { editable.Reviewers.Default = pr.ReviewRequests.DisplayNames() editable.Reviewers.DefaultLogins = pr.ReviewRequests.Logins() // TODO ApiActorsSupported - if issueFeatures.ActorIsAssignable { + if issueFeatures.ApiActorsSupported { editable.ApiActorsSupported = true editable.Assignees.Default = pr.AssignedActors.DisplayNames() editable.Assignees.DefaultLogins = pr.AssignedActors.Logins() @@ -320,8 +320,8 @@ func editRun(opts *EditOptions) error { // Wire up search functions for assignees and reviewers. // When these aren't wired up, it triggers a downstream fallback // to legacy reviewer/assignee fetching. - // TODO actorIsAssignableCleanup - if issueFeatures.ActorIsAssignable { + // TODO ApiActorsSupported + if issueFeatures.ApiActorsSupported { editable.AssigneeSearchFunc = shared.AssigneeSearchFunc(apiClient, repo, pr.ID) editable.ReviewerSearchFunc = reviewerSearchFunc(apiClient, repo, &editable, pr.ID) } diff --git a/pkg/cmd/pr/shared/survey.go b/pkg/cmd/pr/shared/survey.go index 544c04bc8..0936d9414 100644 --- a/pkg/cmd/pr/shared/survey.go +++ b/pkg/cmd/pr/shared/survey.go @@ -275,7 +275,7 @@ func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface } values.Reviewers = selectedReviewers } else if len(reviewers) > 0 { - // TODO requestReviewsByLoginCleanup + // TODO ApiActorsSupported // The static MultiSelect path can be removed once GHES supports // requestReviewsByLogin and search-based selection is always used. selected, err := p.MultiSelect("Reviewers", state.Reviewers, reviewers)