cli/pkg/cmd/issue/shared/resolve.go
Kynan Ware 628325920d Reject cross-host issue refs in ResolveIssueRef
Relationship mutations (parent, sub-issue, blocked-by, blocking) run
against baseRepo's host with node IDs that must come from that same
host. Catch a different-host ref up front with a clear error instead
of letting the mutation fail with a confusing node-ID error.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-06 18:04:48 -06:00

47 lines
1.3 KiB
Go

package shared
import (
"fmt"
"strings"
"github.com/cli/cli/v2/api"
"github.com/cli/cli/v2/internal/ghrepo"
)
// ResolveIssueRef parses an issue reference (number or URL) and returns its node ID.
func ResolveIssueRef(client *api.Client, baseRepo ghrepo.Interface, ref string) (string, error) {
number, repo, err := ParseIssueFromArg(ref)
if err != nil {
return "", err
}
targetRepo := baseRepo
if r, ok := repo.Value(); ok {
if r.RepoHost() != baseRepo.RepoHost() {
return "", fmt.Errorf("issue reference %q belongs to a different host (%s) than the current repository (%s)", ref, r.RepoHost(), baseRepo.RepoHost())
}
targetRepo = r
}
return api.IssueNodeID(client, targetRepo, number)
}
// ResolveIssueTypeName resolves an issue type name to its ID by fetching
// available types from the repository. Returns an error listing available
// types if the name is not found.
func ResolveIssueTypeName(client *api.Client, repo ghrepo.Interface, typeName string) (string, error) {
issueTypes, err := api.RepoIssueTypes(client, repo)
if err != nil {
return "", err
}
typeNames := make([]string, len(issueTypes))
for i, t := range issueTypes {
typeNames[i] = t.Name
if strings.EqualFold(t.Name, typeName) {
return t.ID, nil
}
}
return "", fmt.Errorf("type %q not found; available types: %s", typeName, strings.Join(typeNames, ", "))
}