Skip to content
This repository was archived by the owner on Jul 16, 2021. It is now read-only.

Commit fb4e3d5

Browse files
author
Andres Martinez Gotor
authored
[chartsvc] Allow to return duplicated charts (#628)
1 parent a929343 commit fb4e3d5

File tree

3 files changed

+69
-16
lines changed

3 files changed

+69
-16
lines changed

cmd/chartsvc/handler.go

+32-16
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ func getPageNumberAndSize(req *http.Request) (int, int) {
8585
return int(pageInt), int(sizeInt)
8686
}
8787

88+
// showDuplicates returns if a request wants to retrieve charts. Default false
89+
func showDuplicates(req *http.Request) bool {
90+
return len(req.FormValue("showDuplicates")) > 0
91+
}
92+
8893
// min returns the minimum of two integers.
8994
// We are not using math.Min since that compares float64
9095
// and it's unnecessarily complex.
@@ -110,7 +115,7 @@ func uniqChartList(charts []*models.Chart) []*models.Chart {
110115
return res
111116
}
112117

113-
func getPaginatedChartList(repo string, pageNumber, pageSize int) (apiListResponse, interface{}, error) {
118+
func getPaginatedChartList(repo string, pageNumber, pageSize int, showDuplicates bool) (apiListResponse, interface{}, error) {
114119
db, closer := dbSession.DB()
115120
defer closer()
116121
var charts []*models.Chart
@@ -121,17 +126,20 @@ func getPaginatedChartList(repo string, pageNumber, pageSize int) (apiListRespon
121126
pipeline = append(pipeline, bson.M{"$match": bson.M{"repo.name": repo}})
122127
}
123128

124-
// We should query unique charts
125-
pipeline = append(pipeline,
126-
// Add a new field to store the latest version
127-
bson.M{"$addFields": bson.M{"firstChartVersion": bson.M{"$arrayElemAt": []interface{}{"$chartversions", 0}}}},
128-
// Group by unique digest for the latest version (remove duplicates)
129-
bson.M{"$group": bson.M{"_id": "$firstChartVersion.digest", "chart": bson.M{"$first": "$$ROOT"}}},
130-
// Restore original object struct
131-
bson.M{"$replaceRoot": bson.M{"newRoot": "$chart"}},
132-
// Order by name
133-
bson.M{"$sort": bson.M{"name": 1}},
134-
)
129+
if !showDuplicates {
130+
// We should query unique charts
131+
pipeline = append(pipeline,
132+
// Add a new field to store the latest version
133+
bson.M{"$addFields": bson.M{"firstChartVersion": bson.M{"$arrayElemAt": []interface{}{"$chartversions", 0}}}},
134+
// Group by unique digest for the latest version (remove duplicates)
135+
bson.M{"$group": bson.M{"_id": "$firstChartVersion.digest", "chart": bson.M{"$first": "$$ROOT"}}},
136+
// Restore original object struct
137+
bson.M{"$replaceRoot": bson.M{"newRoot": "$chart"}},
138+
)
139+
}
140+
141+
// Order by name
142+
pipeline = append(pipeline, bson.M{"$sort": bson.M{"name": 1}})
135143

136144
totalPages := 1
137145
if pageSize != 0 {
@@ -166,7 +174,7 @@ func getPaginatedChartList(repo string, pageNumber, pageSize int) (apiListRespon
166174
// listCharts returns a list of charts
167175
func listCharts(w http.ResponseWriter, req *http.Request) {
168176
pageNumber, pageSize := getPageNumberAndSize(req)
169-
cl, meta, err := getPaginatedChartList("", pageNumber, pageSize)
177+
cl, meta, err := getPaginatedChartList("", pageNumber, pageSize, showDuplicates(req))
170178
if err != nil {
171179
log.WithError(err).Error("could not fetch charts")
172180
response.NewErrorResponse(http.StatusInternalServerError, "could not fetch all charts").Write(w)
@@ -178,7 +186,7 @@ func listCharts(w http.ResponseWriter, req *http.Request) {
178186
// listRepoCharts returns a list of charts in the given repo
179187
func listRepoCharts(w http.ResponseWriter, req *http.Request, params Params) {
180188
pageNumber, pageSize := getPageNumberAndSize(req)
181-
cl, meta, err := getPaginatedChartList(params["repo"], pageNumber, pageSize)
189+
cl, meta, err := getPaginatedChartList(params["repo"], pageNumber, pageSize, showDuplicates(req))
182190
if err != nil {
183191
log.WithError(err).Error("could not fetch charts")
184192
response.NewErrorResponse(http.StatusInternalServerError, "could not fetch all charts").Write(w)
@@ -317,7 +325,11 @@ func listChartsWithFilters(w http.ResponseWriter, req *http.Request, params Para
317325
// continue to return empty list
318326
}
319327

320-
cl := newChartListResponse(uniqChartList(charts))
328+
chartResponse := charts
329+
if !showDuplicates(req) {
330+
chartResponse = uniqChartList(charts)
331+
}
332+
cl := newChartListResponse(chartResponse)
321333
response.NewDataResponse(cl).Write(w)
322334
}
323335

@@ -355,7 +367,11 @@ func searchCharts(w http.ResponseWriter, req *http.Request, params Params) {
355367
// continue to return empty list
356368
}
357369

358-
cl := newChartListResponse(uniqChartList(charts))
370+
chartResponse := charts
371+
if !showDuplicates(req) {
372+
chartResponse = uniqChartList(charts)
373+
}
374+
cl := newChartListResponse(chartResponse)
359375
response.NewDataResponse(cl).Write(w)
360376
}
361377

cmd/chartsvc/handler_test.go

+33
Original file line numberDiff line numberDiff line change
@@ -800,4 +800,37 @@ func Test_findLatestChart(t *testing.T) {
800800
t.Errorf("Expecting %v, received %v", charts[0], data[0].ID)
801801
}
802802
})
803+
t.Run("includes duplicated charts when showDuplicates param set", func(t *testing.T) {
804+
charts := []*models.Chart{
805+
{Name: "foo", ID: "stable/foo", Repo: models.Repo{Name: "bar"}, ChartVersions: []models.ChartVersion{models.ChartVersion{Version: "1.0.0", AppVersion: "0.1.0", Digest: "123"}}},
806+
{Name: "foo", ID: "bitnami/foo", Repo: models.Repo{Name: "bar"}, ChartVersions: []models.ChartVersion{models.ChartVersion{Version: "1.0.0", AppVersion: "0.1.0", Digest: "123"}}},
807+
}
808+
reqVersion := "1.0.0"
809+
reqAppVersion := "0.1.0"
810+
811+
var m mock.Mock
812+
dbSession = mockstore.NewMockSession(&m)
813+
m.On("All", &chartsList).Run(func(args mock.Arguments) {
814+
*args.Get(0).(*[]*models.Chart) = charts
815+
})
816+
817+
w := httptest.NewRecorder()
818+
req := httptest.NewRequest("GET", "/charts?showDuplicates=true&name="+charts[0].Name+"&version="+reqVersion+"&appversion="+reqAppVersion, nil)
819+
params := Params{
820+
"name": charts[0].Name,
821+
"version": reqVersion,
822+
"appversion": reqAppVersion,
823+
}
824+
825+
listChartsWithFilters(w, req, params)
826+
827+
var b bodyAPIListResponse
828+
json.NewDecoder(w.Body).Decode(&b)
829+
if b.Data == nil {
830+
t.Fatal("chart list shouldn't be null")
831+
}
832+
data := *b.Data
833+
834+
assert.Equal(t, len(data), 2, "it should return both charts")
835+
})
803836
}

cmd/chartsvc/main.go

+4
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,14 @@ func setupRoutes() http.Handler {
4343
// Routes
4444
apiv1 := r.PathPrefix(pathPrefix).Subrouter()
4545
apiv1.Methods("GET").Path("/charts").Queries("name", "{chartName}", "version", "{version}", "appversion", "{appversion}").Handler(WithParams(listChartsWithFilters))
46+
apiv1.Methods("GET").Path("/charts").Queries("name", "{chartName}", "version", "{version}", "appversion", "{appversion}", "showDuplicates", "{showDuplicates}").Handler(WithParams(listChartsWithFilters))
4647
apiv1.Methods("GET").Path("/charts").HandlerFunc(listCharts)
48+
apiv1.Methods("GET").Path("/charts").Queries("showDuplicates", "{showDuplicates}").HandlerFunc(listCharts)
4749
apiv1.Methods("GET").Path("/charts/search").Queries("q", "{query}").Handler(WithParams(searchCharts))
50+
apiv1.Methods("GET").Path("/charts/search").Queries("q", "{query}", "showDuplicates", "{showDuplicates}").Handler(WithParams(searchCharts))
4851
apiv1.Methods("GET").Path("/charts/{repo}").Handler(WithParams(listRepoCharts))
4952
apiv1.Methods("GET").Path("/charts/{repo}/search").Queries("q", "{query}").Handler(WithParams(searchCharts))
53+
apiv1.Methods("GET").Path("/charts/{repo}/search").Queries("q", "{query}", "showDuplicates", "{showDuplicates}").Handler(WithParams(searchCharts))
5054
apiv1.Methods("GET").Path("/charts/{repo}/{chartName}").Handler(WithParams(getChart))
5155
apiv1.Methods("GET").Path("/charts/{repo}/{chartName}/versions").Handler(WithParams(listChartVersions))
5256
apiv1.Methods("GET").Path("/charts/{repo}/{chartName}/versions/{version}").Handler(WithParams(getChartVersion))

0 commit comments

Comments
 (0)