refactor(errors): explain failed requests through the SDK

The hints for a missing repository, a pull request number that names an
issue and an existing pull request read the API with raw GETs from the app
layer. Read them through SDK lookups in services, which reuse the failed
request's instance and credential, and let transport only hand out that
client.

Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
bircni committed 2026-10-12 09:57:12 +02:00
1 parent 03aa64233f
commit 5fd4be9803
4 files changed
+106 -59

No files matched your search

+9 -23
View File
@@ -10,7 +10,7 @@ import (
"fmt"
"net"
"net/http"
"net/url"
"strconv"
"strings"
"syscall"
"time"
@@ -116,18 +116,10 @@ func explainable(err error, apiErr *transport.APIError) bool {
// names an issue. It returns "" when the resource itself is missing.
func explainRepositoryNotFound(ctx context.Context, apiErr *transport.APIError, resource services.Resource) string {
repo := resource.Repository
var state struct {
Empty bool `json:"empty"`
HasIssues bool `json:"has_issues"`
HasPullRequests bool `json:"has_pull_requests"`
HasWiki bool `json:"has_wiki"`
HasReleases bool `json:"has_releases"`
HasActions bool `json:"has_actions"`
HasProjects bool `json:"has_projects"`
}
var state services.RepositoryState
status := http.StatusNotFound
if resource.Kind != "repository" {
status = apiErr.Lookup(ctx, "repos/"+repo, &state)
state, status = services.LookupRepository(ctx, apiErr, repo)
}
switch status {
case http.StatusNotFound:
@@ -140,9 +132,9 @@ func explainRepositoryNotFound(ctx context.Context, apiErr *transport.APIError,
name string
enabled bool
}{
"issues": {"issues are", state.HasIssues}, "pulls": {"pull requests are", state.HasPullRequests},
"wiki": {"the wiki is", state.HasWiki}, "releases": {"releases are", state.HasReleases},
"actions": {"Actions are", state.HasActions}, "projects": {"projects are", state.HasProjects},
"issues": {"issues are", state.Issues}, "pulls": {"pull requests are", state.PullRequests},
"wiki": {"the wiki is", state.Wiki}, "releases": {"releases are", state.Releases},
"actions": {"Actions are", state.Actions}, "projects": {"projects are", state.Projects},
}
if feature, ok := features[resource.Section]; ok && !feature.enabled {
return feature.name + " disabled for " + repo
@@ -151,10 +143,7 @@ func explainRepositoryNotFound(ctx context.Context, apiErr *transport.APIError,
return repo + " is empty; it has no pull requests"
}
if number, ok := strings.CutPrefix(resource.Key, "#"); ok && resource.Kind == "pull request" {
var issue struct {
PullRequest any `json:"pull_request"`
}
if apiErr.Lookup(ctx, "repos/"+repo+"/issues/"+number, &issue) == http.StatusOK && issue.PullRequest == nil {
if index, err := strconv.ParseInt(number, 10, 64); err == nil && services.LookupIsIssue(ctx, apiErr, repo, index) {
return fmt.Sprintf("#%s in %s is an issue, not a pull request; view it with: tea issue view %s", number, repo, number)
}
}
@@ -204,11 +193,8 @@ func existsHint(ctx context.Context, apiErr *transport.APIError, conflict *servi
if !ok || conflict.Scope == "" {
return ""
}
var pull struct {
URL string `json:"html_url"`
}
if apiErr.Lookup(ctx, "repos/"+conflict.Scope+"/pulls/"+url.PathEscape(base)+"/"+url.PathEscape(head), &pull) == http.StatusOK && pull.URL != "" {
return "see " + pull.URL
if pullURL := services.LookupPullURL(ctx, apiErr, conflict.Scope, base, head); pullURL != "" {
return "see " + pullURL
}
case "wiki page":
return "edit it with: tea wiki edit " + conflict.Key