From db9d2944d8dc0c3f6075965228b8c01a81d0aaad Mon Sep 17 00:00:00 2001 From: silverwind Date: Sun, 1 Nov 2026 07:57:30 +0100 Subject: [PATCH] fix(api): return language of starred and watched repositories (#40127) The starred and watched repository API lists converted repositories without loading their attributes, so `language` was always empty. They are now loaded in one batch, owners included. Three of these handlers also continued after an internal error and wrote a second response body, they now return. --- routers/api/v1/user/star.go | 4 ++++ routers/api/v1/user/watch.go | 5 +++++ tests/integration/api_user_star_test.go | 3 +++ 3 files changed, 12 insertions(+) diff --git a/routers/api/v1/user/star.go b/routers/api/v1/user/star.go index 397ebe209b1..2751aa95682 100644 --- a/routers/api/v1/user/star.go +++ b/routers/api/v1/user/star.go @@ -31,6 +31,9 @@ func getStarredRepos(ctx *context.APIContext, user *user_model.User, private boo if err != nil { return nil, err } + if err := repo_model.RepositoryList(starredRepos).LoadAttributes(ctx); err != nil { + return nil, err + } repos := make([]*api.Repository, 0, len(starredRepos)) for _, starred := range starredRepos { @@ -110,6 +113,7 @@ func GetMyStarredRepos(ctx *context.APIContext) { repos, err := getStarredRepos(ctx, ctx.Doer, true) if err != nil { ctx.APIErrorInternal(err) + return } ctx.SetLinkHeader(int64(ctx.Doer.NumStars), utils.GetListOptions(ctx).PageSize) diff --git a/routers/api/v1/user/watch.go b/routers/api/v1/user/watch.go index 9789a016d21..d50462f2530 100644 --- a/routers/api/v1/user/watch.go +++ b/routers/api/v1/user/watch.go @@ -29,6 +29,9 @@ func getWatchedRepos(ctx *context.APIContext, user *user_model.User, private boo if err != nil { return nil, 0, err } + if err := repo_model.RepositoryList(watchedRepos).LoadAttributes(ctx); err != nil { + return nil, 0, err + } repos := make([]*api.Repository, len(watchedRepos)) for i, watched := range watchedRepos { @@ -72,6 +75,7 @@ func GetWatchedRepos(ctx *context.APIContext) { repos, total, err := getWatchedRepos(ctx, ctx.ContextUser, private) if err != nil { ctx.APIErrorInternal(err) + return } ctx.SetLinkHeader(total, utils.GetListOptions(ctx).PageSize) @@ -102,6 +106,7 @@ func GetMyWatchedRepos(ctx *context.APIContext) { repos, total, err := getWatchedRepos(ctx, ctx.Doer, true) if err != nil { ctx.APIErrorInternal(err) + return } ctx.SetLinkHeader(total, utils.GetListOptions(ctx).PageSize) ctx.SetTotalCountHeader(total) diff --git a/tests/integration/api_user_star_test.go b/tests/integration/api_user_star_test.go index 626b010f56c..51780c12292 100644 --- a/tests/integration/api_user_star_test.go +++ b/tests/integration/api_user_star_test.go @@ -9,6 +9,7 @@ import ( "testing" auth_model "gitea.dev/models/auth" + "gitea.dev/models/db" "gitea.dev/models/perm" repo_model "gitea.dev/models/repo" "gitea.dev/models/unittest" @@ -27,6 +28,7 @@ func TestAPIStar(t *testing.T) { defer tests.PrepareTestEnv(t)() t.Run("PublicOnly", func(t *testing.T) { + require.NoError(t, db.Insert(t.Context(), &repo_model.LanguageStat{RepoID: 4, IsPrimary: true, Language: "Go", Size: 1})) token := getUserToken(t, "user2", auth_model.AccessTokenScopeReadUser, auth_model.AccessTokenScopeReadRepository, auth_model.AccessTokenScopePublicOnly) req := NewRequest(t, "GET", "/api/v1/user/starred"). AddTokenAuth(token) @@ -35,6 +37,7 @@ func TestAPIStar(t *testing.T) { repos := DecodeJSON(t, resp, []api.Repository{}) if assert.Len(t, repos, 1) { assert.Equal(t, "user5/repo4", repos[0].FullName) + assert.Equal(t, "Go", repos[0].Language) } req = NewRequest(t, "GET", "/api/v1/users/user2/starred").