Skip to content

Commit 0a386c2

Browse files
committed
Fix search API response type and license field polymorphism
The Gitee search endpoint returns a plain JSON array, not a wrapper object. The license field alternates between a bare string and an object depending on the endpoint; UnmarshalJSON handles both forms. Also strip trailing .git from html_url when building the web URL.
1 parent 1017b7c commit 0a386c2

3 files changed

Lines changed: 45 additions & 22 deletions

File tree

gitee/gitee.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ func (c *Client) getJSON(ctx context.Context, rawURL string, v any) error {
151151
// ─── API methods ─────────────────────────────────────────────────────────────
152152

153153
// SearchRepos searches Gitee repositories. sort: "stars", "forks", "updated".
154+
// The Gitee search endpoint returns a plain JSON array (not a wrapper object).
154155
func (c *Client) SearchRepos(ctx context.Context, query, lang, sort string, limit int) ([]Repo, error) {
155156
if limit <= 0 {
156157
limit = 20
@@ -183,17 +184,17 @@ func (c *Client) SearchRepos(ctx context.Context, query, lang, sort string, limi
183184
params.Set("per_page", strconv.Itoa(pageSize))
184185

185186
rawURL := c.cfg.BaseURL + "/search/repositories?" + params.Encode()
186-
var resp searchResp
187-
if err := c.getJSON(ctx, rawURL, &resp); err != nil {
187+
var repos []wireRepo
188+
if err := c.getJSON(ctx, rawURL, &repos); err != nil {
188189
return out, err
189190
}
190-
for _, wr := range resp.Items {
191+
for _, wr := range repos {
191192
out = append(out, wireRepoToRepo(wr, len(out)+1))
192193
if len(out) >= limit {
193194
return out, nil
194195
}
195196
}
196-
if len(resp.Items) == 0 {
197+
if len(repos) == 0 {
197198
break
198199
}
199200
page++

gitee/gitee_test.go

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -84,22 +84,19 @@ func TestGetNullReturnsNotFound(t *testing.T) {
8484
}
8585

8686
func TestSearchRepos(t *testing.T) {
87-
resp := searchResp{
88-
TotalCount: 2,
89-
Items: []wireRepo{
90-
{FullName: "foo/bar", StargazersCount: 100, HTMLURL: "https://gitee.com/foo/bar"},
91-
{FullName: "baz/qux", StargazersCount: 50, HTMLURL: "https://gitee.com/baz/qux"},
92-
},
87+
items := []wireRepo{
88+
{FullName: "foo/bar", StargazersCount: 100, HTMLURL: "https://gitee.com/foo/bar.git"},
89+
{FullName: "baz/qux", StargazersCount: 50, HTMLURL: "https://gitee.com/baz/qux.git"},
9390
}
9491
calls := 0
9592
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
9693
calls++
9794
w.Header().Set("Content-Type", "application/json")
9895
if calls > 1 {
99-
_ = json.NewEncoder(w).Encode(searchResp{})
96+
_ = json.NewEncoder(w).Encode([]wireRepo{})
10097
return
10198
}
102-
_ = json.NewEncoder(w).Encode(resp)
99+
_ = json.NewEncoder(w).Encode(items)
103100
}))
104101
defer srv.Close()
105102

@@ -126,7 +123,7 @@ func TestGetRepo(t *testing.T) {
126123
wr := wireRepo{
127124
FullName: "gitee/gitee",
128125
StargazersCount: 999,
129-
HTMLURL: "https://gitee.com/gitee/gitee",
126+
HTMLURL: "https://gitee.com/gitee/gitee.git",
130127
Language: "Ruby",
131128
}
132129
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -144,7 +141,7 @@ func TestGetRepo(t *testing.T) {
144141
t.Errorf("full_name = %q", repo.FullName)
145142
}
146143
if repo.URL != "https://gitee.com/gitee/gitee" {
147-
t.Errorf("url = %q", repo.URL)
144+
t.Errorf("url = %q, want https://gitee.com/gitee/gitee", repo.URL)
148145
}
149146
if repo.Stars != 999 {
150147
t.Errorf("stars = %d", repo.Stars)

gitee/types.go

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package gitee
22

3-
import "fmt"
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"strings"
7+
)
48

59
// ─── Exported record types ────────────────────────────────────────────────────
610

@@ -62,8 +66,29 @@ type wireRepo struct {
6266
Owner wireOwner `json:"owner"`
6367
}
6468

69+
// wireLicense can appear as either an object {"spdx_id":"MIT"} or a bare
70+
// string "MIT" depending on which Gitee endpoint returns the repo.
6571
type wireLicense struct {
66-
SPDXID string `json:"spdx_id"`
72+
SPDXID string
73+
}
74+
75+
func (l *wireLicense) UnmarshalJSON(b []byte) error {
76+
if len(b) == 0 || string(b) == "null" {
77+
return nil
78+
}
79+
// bare string form
80+
if b[0] == '"' {
81+
return json.Unmarshal(b, &l.SPDXID)
82+
}
83+
// object form
84+
var obj struct {
85+
SPDXID string `json:"spdx_id"`
86+
}
87+
if err := json.Unmarshal(b, &obj); err != nil {
88+
return err
89+
}
90+
l.SPDXID = obj.SPDXID
91+
return nil
6792
}
6893

6994
type wireOwner struct {
@@ -95,14 +120,14 @@ type wireRelease struct {
95120
Author wireOwner `json:"author"`
96121
}
97122

98-
type searchResp struct {
99-
TotalCount int `json:"total_count"`
100-
Items []wireRepo `json:"items"`
101-
}
102-
103123
// ─── Conversion helpers ───────────────────────────────────────────────────────
104124

105125
func wireRepoToRepo(wr wireRepo, rank int) Repo {
126+
// The API html_url includes a trailing .git; strip it for the web URL.
127+
webURL := strings.TrimSuffix(wr.HTMLURL, ".git")
128+
if webURL == "" && wr.FullName != "" {
129+
webURL = "https://gitee.com/" + wr.FullName
130+
}
106131
return Repo{
107132
Rank: rank,
108133
FullName: wr.FullName,
@@ -111,7 +136,7 @@ func wireRepoToRepo(wr wireRepo, rank int) Repo {
111136
Stars: wr.StargazersCount,
112137
Forks: wr.ForksCount,
113138
UpdatedAt: wr.UpdatedAt,
114-
URL: wr.HTMLURL,
139+
URL: webURL,
115140
}
116141
}
117142

0 commit comments

Comments
 (0)