From dbe2d376fee1e64c2ed07c5727cb17664591f2ce Mon Sep 17 00:00:00 2001 From: bircni Date: Mon, 12 Oct 2026 20:46:39 +0200 Subject: [PATCH] refactor(services): share the SDK list-page wrapper Signed-off-by: bircni --- internal/services/action_values.go | 35 ++++++++++--------------- internal/services/admin_users.go | 7 ++--- internal/services/helpers.go | 11 ++++++++ internal/services/issues.go | 10 +++---- internal/services/metadata.go | 7 ++--- internal/services/organizations.go | 36 +++++++++++--------------- internal/services/repository_search.go | 31 +++++++++------------- internal/services/search.go | 10 +++---- internal/services/ssh_keys.go | 8 ++---- internal/services/teams.go | 21 +++++---------- internal/services/time.go | 30 ++++++++++----------- internal/services/webhooks.go | 34 +++++++++++------------- 12 files changed, 98 insertions(+), 142 deletions(-) diff --git a/internal/services/action_values.go b/internal/services/action_values.go index a0dece53..b3cd1fef 100644 --- a/internal/services/action_values.go +++ b/internal/services/action_values.go @@ -68,19 +68,15 @@ func (s ActionSecrets) ListPage(ctx context.Context, limit, page int) (Page[Acti if s.Scope.Account { return Page[ActionSecret]{}, &CapabilityError{Feature: "account secret listing", Reason: "Gitea exposes account secret set/delete operations only"} } - window, err := listPage(limit, page, func(limit, page int) ([]*gitea.Secret, http.Header, error) { - options := listOptions(limit, page) - secrets, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.Secret, *gitea.Response, error) { - if s.Scope.Organization != "" { - return c.Actions.ListOrgSecrets(ctx, s.Scope.Organization, gitea.ListOrgActionsSecretOption{ListOptions: options}) - } - owner, repo, err := splitRepository(s.Scope.Repository) - if err != nil { - return nil, nil, err - } - return c.Actions.ListRepoSecrets(ctx, owner, repo, gitea.ListRepoActionsSecretOption{ListOptions: options}) - }) - return secrets, headerOf(resp), err + window, err := callPage(ctx, s.Client, limit, page, func(ctx context.Context, c *gitea.Client, list gitea.ListOptions) ([]*gitea.Secret, *gitea.Response, error) { + if s.Scope.Organization != "" { + return c.Actions.ListOrgSecrets(ctx, s.Scope.Organization, gitea.ListOrgActionsSecretOption{ListOptions: list}) + } + owner, repo, err := splitRepository(s.Scope.Repository) + if err != nil { + return nil, nil, err + } + return c.Actions.ListRepoSecrets(ctx, owner, repo, gitea.ListRepoActionsSecretOption{ListOptions: list}) }) return convertPage(window, secretFrom), err } @@ -146,14 +142,11 @@ func (s ActionVariables) ListPage(ctx context.Context, limit, page int) (Page[Ac var window Page[*gitea.ActionsVariable] var err error if s.Scope.Account || s.Scope.Organization != "" { - window, err = listPage(limit, page, func(limit, page int) ([]*gitea.ActionsVariable, http.Header, error) { - variables, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.ActionsVariable, *gitea.Response, error) { - if s.Scope.Account { - return c.Actions.ListUserVariables(ctx, listOptions(limit, page)) - } - return c.Actions.ListOrgVariables(ctx, s.Scope.Organization, gitea.ListOrgActionsVariableOption{ListOptions: listOptions(limit, page)}) - }) - return variables, headerOf(resp), err + window, err = callPage(ctx, s.Client, limit, page, func(ctx context.Context, c *gitea.Client, list gitea.ListOptions) ([]*gitea.ActionsVariable, *gitea.Response, error) { + if s.Scope.Account { + return c.Actions.ListUserVariables(ctx, list) + } + return c.Actions.ListOrgVariables(ctx, s.Scope.Organization, gitea.ListOrgActionsVariableOption{ListOptions: list}) }) } else { window, err = rawPage[*gitea.ActionsVariable](ctx, s.Client, s.repoVariables(""), nil, limit, page) diff --git a/internal/services/admin_users.go b/internal/services/admin_users.go index 2bdd90d8..9ec1e0b9 100644 --- a/internal/services/admin_users.go +++ b/internal/services/admin_users.go @@ -74,11 +74,8 @@ type AdminUsers struct{ Client *transport.Client } // List returns a page of the users whose username, full name or email contains query, or of // every user without one. func (s AdminUsers) List(ctx context.Context, query string, limit, page int) (Page[AdminUser], error) { - users, err := listPage(limit, page, func(limit, page int) ([]*gitea.User, http.Header, error) { - users, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.User, *gitea.Response, error) { - return c.Admin.ListUsers(ctx, gitea.AdminListUsersOptions{ListOptions: listOptions(limit, page), Query: query}) - }) - return users, headerOf(resp), err + users, err := callPage(ctx, s.Client, limit, page, func(ctx context.Context, c *gitea.Client, list gitea.ListOptions) ([]*gitea.User, *gitea.Response, error) { + return c.Admin.ListUsers(ctx, gitea.AdminListUsersOptions{ListOptions: list, Query: query}) }) return convertPage(users, adminUserFrom), err } diff --git a/internal/services/helpers.go b/internal/services/helpers.go index 8f99edf1..1742fe73 100644 --- a/internal/services/helpers.go +++ b/internal/services/helpers.go @@ -13,6 +13,7 @@ import ( "strings" "time" + gitea "gitea.dev/sdk" "gitea.dev/tea/internal/transport" ) @@ -99,6 +100,16 @@ func listPage[T any](limit, page int, fetch func(limit, page int) ([]T, http.Hea return Page[T]{Items: result[:min(len(result), limit)], More: more, Total: total, Counted: counted}, nil } +// callPage is listPage over an SDK list call. +func callPage[T any](ctx context.Context, client *transport.Client, limit, page int, list func(context.Context, *gitea.Client, gitea.ListOptions) ([]T, *gitea.Response, error)) (Page[T], error) { + return listPage(limit, page, func(limit, page int) ([]T, http.Header, error) { + items, resp, err := call(ctx, client, func(ctx context.Context, c *gitea.Client) ([]T, *gitea.Response, error) { + return list(ctx, c, listOptions(limit, page)) + }) + return items, headerOf(resp), err + }) +} + // rawPage is listPage over a raw JSON collection endpoint; it sets limit and page on query. func rawPage[T any](ctx context.Context, client *transport.Client, endpoint string, query url.Values, limit, page int) (Page[T], error) { query = maps.Clone(query) diff --git a/internal/services/issues.go b/internal/services/issues.go index f9bc5cda..22b57f83 100644 --- a/internal/services/issues.go +++ b/internal/services/issues.go @@ -5,7 +5,6 @@ package services import ( "context" - "net/http" "strconv" "strings" "time" @@ -122,12 +121,9 @@ func (s Issues) ListPage(ctx context.Context, opts ListOptions) (Page[Issue], er if opts.Before != nil { query.Before = *opts.Before } - issues, err := listPage(opts.Limit, opts.Page, func(limit, page int) ([]*gitea.Issue, http.Header, error) { - query.ListOptions = listOptions(limit, page) - issues, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.Issue, *gitea.Response, error) { - return c.Issues.ListRepoIssues(ctx, owner, repo, query) - }) - return issues, headerOf(resp), err + issues, err := callPage(ctx, s.Client, opts.Limit, opts.Page, func(ctx context.Context, c *gitea.Client, list gitea.ListOptions) ([]*gitea.Issue, *gitea.Response, error) { + query.ListOptions = list + return c.Issues.ListRepoIssues(ctx, owner, repo, query) }) if err != nil { return Page[Issue]{}, err diff --git a/internal/services/metadata.go b/internal/services/metadata.go index 4a376a95..177041ce 100644 --- a/internal/services/metadata.go +++ b/internal/services/metadata.go @@ -212,11 +212,8 @@ func (s Milestones) ListPage(ctx context.Context, state string, limit, page int) if err != nil { return Page[Milestone]{}, err } - milestones, err := listPage(limit, page, func(limit, page int) ([]*gitea.Milestone, http.Header, error) { - milestones, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.Milestone, *gitea.Response, error) { - return c.Repositories.ListMilestones(ctx, owner, repo, gitea.ListMilestoneOption{ListOptions: listOptions(limit, page), State: gitea.StateType(state)}) - }) - return milestones, headerOf(resp), err + milestones, err := callPage(ctx, s.Client, limit, page, func(ctx context.Context, c *gitea.Client, list gitea.ListOptions) ([]*gitea.Milestone, *gitea.Response, error) { + return c.Repositories.ListMilestones(ctx, owner, repo, gitea.ListMilestoneOption{ListOptions: list, State: gitea.StateType(state)}) }) return convertPage(milestones, milestoneFrom), err } diff --git a/internal/services/organizations.go b/internal/services/organizations.go index 794e498b..095433f6 100644 --- a/internal/services/organizations.go +++ b/internal/services/organizations.go @@ -62,18 +62,15 @@ type Organizations struct{ Client *transport.Client } // List selects public organizations, your organizations, or a named user's organizations. func (s Organizations) List(ctx context.Context, mine bool, username string, limit, page int) (Page[Organization], error) { - orgs, err := listPage(limit, page, func(limit, page int) ([]*gitea.Organization, http.Header, error) { - orgs, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.Organization, *gitea.Response, error) { - opts := gitea.ListOrgsOptions{ListOptions: listOptions(limit, page)} - switch { - case mine: - return c.Organizations.ListMyOrgs(ctx, opts) - case username != "": - return c.Organizations.ListUserOrgs(ctx, username, opts) - } - return c.Organizations.ListOrgs(ctx, opts) - }) - return orgs, headerOf(resp), err + orgs, err := callPage(ctx, s.Client, limit, page, func(ctx context.Context, c *gitea.Client, list gitea.ListOptions) ([]*gitea.Organization, *gitea.Response, error) { + opts := gitea.ListOrgsOptions{ListOptions: list} + switch { + case mine: + return c.Organizations.ListMyOrgs(ctx, opts) + case username != "": + return c.Organizations.ListUserOrgs(ctx, username, opts) + } + return c.Organizations.ListOrgs(ctx, opts) }) return convertPage(orgs, organizationFrom), err } @@ -215,15 +212,12 @@ type MemberListOptions struct { // Members lists the members of an organization. func (s Organizations) Members(ctx context.Context, name string, opts MemberListOptions) (Page[OrganizationMember], error) { - users, err := listPage(opts.Limit, opts.Page, func(limit, page int) ([]*gitea.User, http.Header, error) { - users, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.User, *gitea.Response, error) { - list := gitea.ListOrgMembershipOption{ListOptions: listOptions(limit, page)} - if opts.Public { - return c.Organizations.ListPublicOrgMembership(ctx, name, list) - } - return c.Organizations.ListOrgMembership(ctx, name, list) - }) - return users, headerOf(resp), err + users, err := callPage(ctx, s.Client, opts.Limit, opts.Page, func(ctx context.Context, c *gitea.Client, list gitea.ListOptions) ([]*gitea.User, *gitea.Response, error) { + membership := gitea.ListOrgMembershipOption{ListOptions: list} + if opts.Public { + return c.Organizations.ListPublicOrgMembership(ctx, name, membership) + } + return c.Organizations.ListOrgMembership(ctx, name, membership) }) members := convertPage(users, memberFrom) if err != nil || !(opts.Public || opts.Visibility) { diff --git a/internal/services/repository_search.go b/internal/services/repository_search.go index 4d485638..628c77b0 100644 --- a/internal/services/repository_search.go +++ b/internal/services/repository_search.go @@ -5,7 +5,6 @@ package services import ( "context" - "net/http" gitea "gitea.dev/sdk" ) @@ -77,18 +76,15 @@ func (s Repositories) ListPage(ctx context.Context, opts RepositoryListOptions) } window, err = rawPage[*gitea.Repository](ctx, s.Client, endpoint, nil, opts.Limit, opts.Page) } else { - window, err = listPage(opts.Limit, opts.Page, func(limit, page int) ([]*gitea.Repository, http.Header, error) { - items, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.Repository, *gitea.Response, error) { - switch { - case isOrg: - return c.Repositories.ListOrgRepos(ctx, opts.Owner, gitea.ListOrgReposOptions{ListOptions: listOptions(limit, page)}) - case opts.Owner != "": - return c.Repositories.ListUserRepos(ctx, opts.Owner, gitea.ListReposOptions{ListOptions: listOptions(limit, page)}) - default: - return c.Repositories.ListMyRepos(ctx, gitea.ListReposOptions{ListOptions: listOptions(limit, page)}) - } - }) - return items, headerOf(resp), err + window, err = callPage(ctx, s.Client, opts.Limit, opts.Page, func(ctx context.Context, c *gitea.Client, list gitea.ListOptions) ([]*gitea.Repository, *gitea.Response, error) { + switch { + case isOrg: + return c.Repositories.ListOrgRepos(ctx, opts.Owner, gitea.ListOrgReposOptions{ListOptions: list}) + case opts.Owner != "": + return c.Repositories.ListUserRepos(ctx, opts.Owner, gitea.ListReposOptions{ListOptions: list}) + default: + return c.Repositories.ListMyRepos(ctx, gitea.ListReposOptions{ListOptions: list}) + } }) } if err != nil { @@ -126,12 +122,9 @@ func (s Repositories) Search(ctx context.Context, opts RepositorySearchOptions) return Page[Repository]{}, err } options.PrioritizedByOwnerID = account.ID - window, err := listPage(opts.Limit, opts.Page, func(limit, page int) ([]*gitea.Repository, http.Header, error) { - options.ListOptions = listOptions(limit, page) - items, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.Repository, *gitea.Response, error) { - return c.Repositories.SearchRepos(ctx, options) - }) - return items, headerOf(resp), err + window, err := callPage(ctx, s.Client, opts.Limit, opts.Page, func(ctx context.Context, c *gitea.Client, list gitea.ListOptions) ([]*gitea.Repository, *gitea.Response, error) { + options.ListOptions = list + return c.Repositories.SearchRepos(ctx, options) }) if err != nil { return Page[Repository]{}, err diff --git a/internal/services/search.go b/internal/services/search.go index 760ffcab..c6d007c2 100644 --- a/internal/services/search.go +++ b/internal/services/search.go @@ -6,7 +6,6 @@ package services import ( "context" "fmt" - "net/http" "net/url" "time" @@ -107,12 +106,9 @@ func (s Issues) searchRepository(ctx context.Context, opts DiscussionSearchOptio query.MentionedBy = account } } - return listPage(opts.Limit, opts.Page, func(limit, page int) ([]*gitea.Issue, http.Header, error) { - query.ListOptions = listOptions(limit, page) - issues, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.Issue, *gitea.Response, error) { - return c.Issues.ListRepoIssues(ctx, owner, repo, query) - }) - return issues, headerOf(resp), err + return callPage(ctx, s.Client, opts.Limit, opts.Page, func(ctx context.Context, c *gitea.Client, list gitea.ListOptions) ([]*gitea.Issue, *gitea.Response, error) { + query.ListOptions = list + return c.Issues.ListRepoIssues(ctx, owner, repo, query) }) } diff --git a/internal/services/ssh_keys.go b/internal/services/ssh_keys.go index c268d988..6af727a5 100644 --- a/internal/services/ssh_keys.go +++ b/internal/services/ssh_keys.go @@ -5,7 +5,6 @@ package services import ( "context" - "net/http" "strconv" gitea "gitea.dev/sdk" @@ -31,11 +30,8 @@ type SSHKeys struct{ Client *transport.Client } // List returns a page of public keys. func (s SSHKeys) List(ctx context.Context, limit, page int) (Page[SSHKey], error) { - keys, err := listPage(limit, page, func(limit, page int) ([]*gitea.PublicKey, http.Header, error) { - keys, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.PublicKey, *gitea.Response, error) { - return c.Users.ListMyPublicKeys(ctx, gitea.ListPublicKeysOptions{ListOptions: listOptions(limit, page)}) - }) - return keys, headerOf(resp), err + keys, err := callPage(ctx, s.Client, limit, page, func(ctx context.Context, c *gitea.Client, list gitea.ListOptions) ([]*gitea.PublicKey, *gitea.Response, error) { + return c.Users.ListMyPublicKeys(ctx, gitea.ListPublicKeysOptions{ListOptions: list}) }) return convertPage(keys, sshKeyFrom), err } diff --git a/internal/services/teams.go b/internal/services/teams.go index 63500be6..3a4debf1 100644 --- a/internal/services/teams.go +++ b/internal/services/teams.go @@ -125,11 +125,8 @@ type Teams struct{ Client *transport.Client } // List lists teams in one organization. func (s Teams) List(ctx context.Context, org string, limit, page int) (Page[Team], error) { - teams, err := listPage(limit, page, func(limit, page int) ([]*gitea.Team, http.Header, error) { - teams, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.Team, *gitea.Response, error) { - return c.Organizations.ListOrgTeams(ctx, org, gitea.ListTeamsOptions{ListOptions: listOptions(limit, page)}) - }) - return teams, headerOf(resp), err + teams, err := callPage(ctx, s.Client, limit, page, func(ctx context.Context, c *gitea.Client, list gitea.ListOptions) ([]*gitea.Team, *gitea.Response, error) { + return c.Organizations.ListOrgTeams(ctx, org, gitea.ListTeamsOptions{ListOptions: list}) }) return inOrganization(convertPage(teams, teamFrom), org), err } @@ -274,11 +271,8 @@ func (s Teams) Delete(ctx context.Context, id int64) error { // Members lists members of a team. func (s Teams) Members(ctx context.Context, id int64, limit, page int) (Page[OrganizationMember], error) { - users, err := listPage(limit, page, func(limit, page int) ([]*gitea.User, http.Header, error) { - users, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.User, *gitea.Response, error) { - return c.Organizations.ListTeamMembers(ctx, id, gitea.ListTeamMembersOptions{ListOptions: listOptions(limit, page)}) - }) - return users, headerOf(resp), err + users, err := callPage(ctx, s.Client, limit, page, func(ctx context.Context, c *gitea.Client, list gitea.ListOptions) ([]*gitea.User, *gitea.Response, error) { + return c.Organizations.ListTeamMembers(ctx, id, gitea.ListTeamMembersOptions{ListOptions: list}) }) return convertPage(users, memberFrom), err } @@ -296,11 +290,8 @@ func (s Teams) SetMember(ctx context.Context, id int64, username string, add boo // Repositories lists repositories accessible to a team. func (s Teams) Repositories(ctx context.Context, id int64, limit, page int) (Page[Repository], error) { - repos, err := listPage(limit, page, func(limit, page int) ([]*gitea.Repository, http.Header, error) { - repos, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.Repository, *gitea.Response, error) { - return c.Organizations.ListTeamRepositories(ctx, id, gitea.ListTeamRepositoriesOptions{ListOptions: listOptions(limit, page)}) - }) - return repos, headerOf(resp), err + repos, err := callPage(ctx, s.Client, limit, page, func(ctx context.Context, c *gitea.Client, list gitea.ListOptions) ([]*gitea.Repository, *gitea.Response, error) { + return c.Organizations.ListTeamRepositories(ctx, id, gitea.ListTeamRepositoriesOptions{ListOptions: list}) }) return convertPage(repos, repositoryFrom), err } diff --git a/internal/services/time.go b/internal/services/time.go index 76d0946f..b1122bd7 100644 --- a/internal/services/time.go +++ b/internal/services/time.go @@ -6,7 +6,6 @@ package services import ( "context" "fmt" - "net/http" "strconv" "time" @@ -72,22 +71,19 @@ func (s Times) ListPage(ctx context.Context, opts TimeOptions) (Page[TrackedTime if opts.Before != nil { query.Before = *opts.Before } - records, err := listPage(opts.Limit, opts.Page, func(limit, page int) ([]*gitea.TrackedTime, http.Header, error) { - query.ListOptions = listOptions(limit, page) - records, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.TrackedTime, *gitea.Response, error) { - if opts.Mine { - return c.Issues.ListMyTrackedTimes(ctx, query) - } - owner, repo, err := splitRepository(s.Repository) - if err != nil { - return nil, nil, err - } - if opts.Issue != 0 { - return c.Issues.ListIssueTrackedTimes(ctx, owner, repo, opts.Issue, query) - } - return c.Issues.ListRepoTrackedTimes(ctx, owner, repo, query) - }) - return records, headerOf(resp), err + records, err := callPage(ctx, s.Client, opts.Limit, opts.Page, func(ctx context.Context, c *gitea.Client, list gitea.ListOptions) ([]*gitea.TrackedTime, *gitea.Response, error) { + query.ListOptions = list + if opts.Mine { + return c.Issues.ListMyTrackedTimes(ctx, query) + } + owner, repo, err := splitRepository(s.Repository) + if err != nil { + return nil, nil, err + } + if opts.Issue != 0 { + return c.Issues.ListIssueTrackedTimes(ctx, owner, repo, opts.Issue, query) + } + return c.Issues.ListRepoTrackedTimes(ctx, owner, repo, query) }) items := convertAll(records.Items, func(record *gitea.TrackedTime) TrackedTime { return trackedTimeFrom(record, s.Repository) }) return Page[TrackedTime]{Items: items, More: records.More, Total: records.Total, Counted: records.Counted}, err diff --git a/internal/services/webhooks.go b/internal/services/webhooks.go index 02ca9eca..f7936479 100644 --- a/internal/services/webhooks.go +++ b/internal/services/webhooks.go @@ -7,7 +7,6 @@ import ( "cmp" "context" "maps" - "net/http" "net/url" "slices" "strconv" @@ -109,24 +108,21 @@ func (s Webhooks) from(hook *gitea.Hook) Webhook { // List returns a page of hook metadata. func (s Webhooks) List(ctx context.Context, limit, page int) (Page[Webhook], error) { - hooks, err := listPage(limit, page, func(limit, page int) ([]*gitea.Hook, http.Header, error) { - hooks, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.Hook, *gitea.Response, error) { - opts := gitea.ListHooksOptions{ListOptions: listOptions(limit, page)} - switch { - case s.Scope.Global: - return c.Hooks.ListGlobalHooks(ctx, gitea.ListGlobalHooksOptions{ListOptions: opts.ListOptions}) - case s.Scope.Account: - return c.Hooks.ListMyHooks(ctx, opts) - case s.Scope.Organization != "": - return c.Hooks.ListOrgHooks(ctx, s.Scope.Organization, opts) - } - owner, name, err := splitRepository(s.Scope.Repository) - if err != nil { - return nil, nil, err - } - return c.Hooks.ListRepoHooks(ctx, owner, name, opts) - }) - return hooks, headerOf(resp), err + hooks, err := callPage(ctx, s.Client, limit, page, func(ctx context.Context, c *gitea.Client, list gitea.ListOptions) ([]*gitea.Hook, *gitea.Response, error) { + opts := gitea.ListHooksOptions{ListOptions: list} + switch { + case s.Scope.Global: + return c.Hooks.ListGlobalHooks(ctx, gitea.ListGlobalHooksOptions{ListOptions: opts.ListOptions}) + case s.Scope.Account: + return c.Hooks.ListMyHooks(ctx, opts) + case s.Scope.Organization != "": + return c.Hooks.ListOrgHooks(ctx, s.Scope.Organization, opts) + } + owner, name, err := splitRepository(s.Scope.Repository) + if err != nil { + return nil, nil, err + } + return c.Hooks.ListRepoHooks(ctx, owner, name, opts) }) return convertPage(hooks, s.from), err }