Skip to content

Commit 3e6e66f

Browse files
authored
Merge pull request #1 from KN4CK3R/npm-search-api-unity
Implement npm search api
2 parents 01ddefe + 363174d commit 3e6e66f

File tree

5 files changed

+77
-27
lines changed

5 files changed

+77
-27
lines changed

docs/content/doc/packages/npm.en-us.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ npm dist-tag add [email protected] release
127127

128128
The tag name must not be a valid version. All tag names which are parsable as a version are rejected.
129129

130+
## Search packages
131+
132+
The registry supports [searching](https://docs.npmjs.com/cli/v7/commands/npm-search/) but does not support special search qualifiers like `author:gitea`.
133+
130134
## Supported commands
131135

132136
```
@@ -136,4 +140,5 @@ npm publish
136140
npm unpublish
137141
npm dist-tag
138142
npm view
143+
npm search
139144
```

modules/packages/npm/creator.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,20 +98,24 @@ type PackageDistribution struct {
9898

9999
type PackageSearch struct {
100100
Objects []*PackageSearchObject `json:"objects"`
101-
Total int `json:"total"`
102-
Time map[string]time.Time `json:"time,omitempty"`
101+
Total int64 `json:"total"`
103102
}
104103

105104
type PackageSearchObject struct {
106105
Package *PackageSearchPackage `json:"package"`
107106
}
108107

109108
type PackageSearchPackage struct {
109+
Scope string `json:"scope"`
110110
Name string `json:"name"`
111111
Version string `json:"version"`
112+
Date time.Time `json:"date"`
112113
Description string `json:"description"`
114+
Author User `json:"author"`
115+
Publisher User `json:"publisher"`
116+
Maintainers []User `json:"maintainers"`
117+
Keywords []string `json:"keywords,omitempty"`
113118
Links *PackageSearchPackageLinks `json:"links"`
114-
Maintainers []User `json:"maintainers,omitempty"`
115119
}
116120

117121
type PackageSearchPackageLinks struct {

routers/api/packages/npm/api.go

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -75,31 +75,37 @@ func createPackageMetadataVersion(registryURL string, pd *packages_model.Package
7575
}
7676
}
7777

78-
func createPackageSearchResponse(registryURL string, pds []*packages_model.PackageDescriptor) *npm_module.PackageSearch {
79-
versions := make([]*npm_module.PackageSearchObject, len(pds))
80-
for i := range pds {
81-
pd := pds[i]
82-
metadata := createPackageMetadataVersion(registryURL, pd)
83-
84-
pkg := &npm_module.PackageSearchPackage{
85-
Name: pd.Package.Name,
86-
Version: pd.Version.Version,
87-
Description: metadata.Description,
88-
Links: &npm_module.PackageSearchPackageLinks{
89-
Registry: registryURL,
90-
Homepage: metadata.Homepage,
91-
Repository: metadata.Repository.URL,
92-
},
93-
Maintainers: metadata.Maintainers,
94-
}
78+
func createPackageSearchResponse(pds []*packages_model.PackageDescriptor, total int64) *npm_module.PackageSearch {
79+
objects := make([]*npm_module.PackageSearchObject, 0, len(pds))
80+
for _, pd := range pds {
81+
metadata := pd.Metadata.(*npm_module.Metadata)
9582

96-
versions[i] = &npm_module.PackageSearchObject{
97-
Package: pkg,
83+
scope := metadata.Scope
84+
if scope == "" {
85+
scope = "unscoped"
9886
}
87+
88+
objects = append(objects, &npm_module.PackageSearchObject{
89+
Package: &npm_module.PackageSearchPackage{
90+
Scope: scope,
91+
Name: metadata.Name,
92+
Version: pd.Version.Version,
93+
Date: pd.Version.CreatedUnix.AsLocalTime(),
94+
Description: metadata.Description,
95+
Author: npm_module.User{Name: metadata.Author},
96+
Publisher: npm_module.User{Name: pd.Owner.Name},
97+
Maintainers: []npm_module.User{}, // npm cli needs this field
98+
Keywords: metadata.Keywords,
99+
Links: &npm_module.PackageSearchPackageLinks{
100+
Registry: pd.FullWebLink(),
101+
Homepage: metadata.ProjectURL,
102+
},
103+
},
104+
})
99105
}
100106

101107
return &npm_module.PackageSearch{
102-
Objects: versions,
103-
Total: len(versions),
108+
Objects: objects,
109+
Total: total,
104110
}
105111
}

routers/api/packages/npm/npm.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,13 +352,17 @@ func setPackageTag(tag string, pv *packages_model.PackageVersion, deleteOnly boo
352352
}
353353

354354
func PackageSearch(ctx *context.Context) {
355-
pvs, _, err := packages_model.SearchLatestVersions(ctx, &packages_model.PackageSearchOptions{
355+
pvs, total, err := packages_model.SearchLatestVersions(ctx, &packages_model.PackageSearchOptions{
356356
OwnerID: ctx.Package.Owner.ID,
357357
Type: packages_model.TypeNpm,
358358
Name: packages_model.SearchValue{
359359
ExactMatch: false,
360-
Value: ctx.Req.URL.Query().Get("text"),
360+
Value: ctx.FormTrim("text"),
361361
},
362+
Paginator: db.NewAbsoluteListOptions(
363+
ctx.FormInt("from"),
364+
ctx.FormInt("size"),
365+
),
362366
})
363367
if err != nil {
364368
apiError(ctx, http.StatusInternalServerError, err)
@@ -372,8 +376,8 @@ func PackageSearch(ctx *context.Context) {
372376
}
373377

374378
resp := createPackageSearchResponse(
375-
setting.AppURL+"api/packages/"+ctx.Package.Owner.Name+"/npm",
376379
pds,
380+
total,
377381
)
378382

379383
ctx.JSON(http.StatusOK, resp)

tests/integration/api_packages_npm_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,37 @@ func TestPackageNpm(t *testing.T) {
224224
test(t, http.StatusOK, packageTag2)
225225
})
226226

227+
t.Run("Search", func(t *testing.T) {
228+
defer tests.PrintCurrentTest(t)()
229+
230+
url := fmt.Sprintf("/api/packages/%s/npm/-/v1/search", user.Name)
231+
232+
cases := []struct {
233+
Query string
234+
Skip int
235+
Take int
236+
ExpectedTotal int64
237+
ExpectedResults int
238+
}{
239+
{"", 0, 0, 1, 1},
240+
{"", 0, 10, 1, 1},
241+
{"gitea", 0, 10, 0, 0},
242+
{"test", 0, 10, 1, 1},
243+
{"test", 1, 10, 1, 0},
244+
}
245+
246+
for i, c := range cases {
247+
req := NewRequest(t, "GET", fmt.Sprintf("%s?text=%s&from=%d&size=%d", url, c.Query, c.Skip, c.Take))
248+
resp := MakeRequest(t, req, http.StatusOK)
249+
250+
var result npm.PackageSearch
251+
DecodeJSON(t, resp, &result)
252+
253+
assert.Equal(t, c.ExpectedTotal, result.Total, "case %d: unexpected total hits", i)
254+
assert.Len(t, result.Objects, c.ExpectedResults, "case %d: unexpected result count", i)
255+
}
256+
})
257+
227258
t.Run("Delete", func(t *testing.T) {
228259
defer tests.PrintCurrentTest(t)()
229260

0 commit comments

Comments
 (0)