@@ -5,6 +5,7 @@ package main
55
66import (
77 "context"
8+ "errors"
89 "fmt"
910 "html/template"
1011 "net/http"
@@ -56,22 +57,132 @@ type funcStyleBodyJS func(
5657 scope * coveragedb.SelectScope , onlyUnique bool , sss , managers []string , dataFilters cover.Format ,
5758) (template.CSS , template.HTML , template.HTML , error )
5859
59- func handleCoverageHeatmap (c context.Context , w http.ResponseWriter , r * http.Request ) error {
60- if r .FormValue ("jsonl" ) == "1" {
61- hdr , err := commonHeader (c , r , w , "" )
62- if err != nil {
63- return err
60+ type coverageHeatmapParams struct {
61+ manager string
62+ subsystem string
63+ onlyUnique bool
64+ periodType string
65+ nPeriods int
66+ dateTo civil.Date
67+ cover.Format
68+ }
69+
70+ const minPeriodsOnThePage = 1
71+ const maxPeriodsOnThePage = 12
72+
73+ func makeHeatmapParams (ctx context.Context , r * http.Request ) (* coverageHeatmapParams , error ) {
74+ minCoverLinesDrop , err := getIntParam (r , covPageParams [MinCoverLinesDrop ], 0 )
75+ if err != nil {
76+ return nil , fmt .Errorf ("min-cover-lines-drop is wrong: %w" , err )
77+ }
78+
79+ onlyUnique , err := getBoolParam (r , covPageParams [UniqueOnly ], false )
80+ if err != nil {
81+ return nil , fmt .Errorf ("unique-only is wrong: %w" , err )
82+ }
83+
84+ periodType , err := getStringParam (r , covPageParams [PeriodType ], coveragedb .DayPeriod )
85+ if err != nil {
86+ return nil , fmt .Errorf ("period is wrong: %w" , err )
87+ }
88+ if ! slices .Contains ([]string {coveragedb .DayPeriod , coveragedb .MonthPeriod , coveragedb .QuarterPeriod }, periodType ) {
89+ return nil , fmt .Errorf ("only 'day', 'month' and 'quarter' are allowed, but received %s instead, %w" ,
90+ periodType , ErrClientBadRequest )
91+ }
92+
93+ nPeriods , err := getIntParam (r , covPageParams [PeriodCount ], 4 )
94+ if err != nil || nPeriods > maxPeriodsOnThePage || nPeriods < minPeriodsOnThePage {
95+ return nil , fmt .Errorf ("periods_count is wrong, expected [1, 12]: %w" , err )
96+ }
97+
98+ dateTo := civil .DateOf (timeNow (ctx ))
99+ if customDate := r .FormValue (covPageParams [DateTo ]); customDate != "" {
100+ if dateTo , err = civil .ParseDate (customDate ); err != nil {
101+ return nil , fmt .Errorf ("civil.ParseDate(%s): %w" , customDate , err )
102+ }
103+ }
104+
105+ return & coverageHeatmapParams {
106+ manager : r .FormValue (covPageParams [ManagerName ]),
107+ subsystem : r .FormValue (covPageParams [SubsystemName ]),
108+ onlyUnique : onlyUnique ,
109+ periodType : periodType ,
110+ nPeriods : nPeriods ,
111+ dateTo : dateTo ,
112+ Format : cover.Format {
113+ DropCoveredLines0 : onlyUnique ,
114+ OrderByCoveredLinesDrop : r .FormValue (covPageParams [OrderByCoverDrop ]) == "1" ,
115+ FilterMinCoveredLinesDrop : minCoverLinesDrop ,
116+ },
117+ }, nil
118+ }
119+
120+ func getIntParam (r * http.Request , name string , orDefault ... int ) (int , error ) {
121+ if r .FormValue (name ) == "" {
122+ if len (orDefault ) > 0 {
123+ return orDefault [0 ], nil
64124 }
125+ return 0 , errors .New ("missing parameter " + name )
126+ }
127+ res , err := strconv .Atoi (r .FormValue (name ))
128+ if err != nil {
129+ return 0 , fmt .Errorf ("strconv.Atoi: %w" , err )
130+ }
131+ return res , nil
132+ }
133+
134+ func getBoolParam (r * http.Request , name string , orDefault ... bool ) (bool , error ) {
135+ if r .FormValue (name ) == "" {
136+ if len (orDefault ) > 0 {
137+ return orDefault [0 ], nil
138+ }
139+ return false , errors .New ("missing parameter " + name )
140+ }
141+ res , err := strconv .ParseBool (r .FormValue (name ))
142+ if err != nil {
143+ return false , fmt .Errorf ("strconv.ParseBool: %w" , err )
144+ }
145+ return res , nil
146+ }
147+
148+ func getStringParam (r * http.Request , name string , orDefault ... string ) (string , error ) {
149+ if r .FormValue (name ) == "" {
150+ if len (orDefault ) > 0 {
151+ return orDefault [0 ], nil
152+ }
153+ return "" , errors .New ("missing parameter " + name )
154+ }
155+ return r .FormValue (name ), nil
156+ }
157+
158+ func handleCoverageHeatmap (c context.Context , w http.ResponseWriter , r * http.Request ) error {
159+ hdr , err := commonHeader (c , r , w , "" )
160+ if err != nil {
161+ return err
162+ }
163+ params , err := makeHeatmapParams (c , r )
164+ if err != nil {
165+ return fmt .Errorf ("%s: %w" , err .Error (), ErrClientBadRequest )
166+ }
167+ if askJSONL , _ := getBoolParam (r , "jsonl" , false ); askJSONL {
65168 ns := hdr .Namespace
66169 repo , _ := getNsConfig (c , ns ).mainRepoBranch ()
67170 w .Header ().Set ("Content-Type" , "application/json" )
68- return writeExtAPICoverageFor (c , w , ns , repo )
171+ return writeExtAPICoverageFor (c , w , ns , repo , params )
69172 }
70- return handleHeatmap (c , w , r , cover .DoHeatMapStyleBodyJS )
173+ return handleHeatmap (c , w , hdr , params , cover .DoHeatMapStyleBodyJS )
71174}
72175
73176func handleSubsystemsCoverageHeatmap (c context.Context , w http.ResponseWriter , r * http.Request ) error {
74- return handleHeatmap (c , w , r , cover .DoSubsystemsHeatMapStyleBodyJS )
177+ hdr , err := commonHeader (c , r , w , "" )
178+ if err != nil {
179+ return err
180+ }
181+ params , err := makeHeatmapParams (c , r )
182+ if err != nil {
183+ return fmt .Errorf ("%s: %w" , err .Error (), ErrClientBadRequest )
184+ }
185+ return handleHeatmap (c , w , hdr , params , cover .DoSubsystemsHeatMapStyleBodyJS )
75186}
76187
77188type covPageParam int
@@ -127,46 +238,14 @@ func coveragePageLink(ns, periodType, dateTo string, minDrop, periodCount int, o
127238 return url
128239}
129240
130- func handleHeatmap (c context.Context , w http.ResponseWriter , r * http.Request , f funcStyleBodyJS ) error {
131- hdr , err := commonHeader (c , r , w , "" )
132- if err != nil {
133- return err
134- }
241+ func handleHeatmap (c context.Context , w http.ResponseWriter , hdr * uiHeader , p * coverageHeatmapParams ,
242+ f funcStyleBodyJS ) error {
135243 nsConfig := getNsConfig (c , hdr .Namespace )
136244 if nsConfig .Coverage == nil {
137245 return ErrClientNotFound
138246 }
139- ss := r .FormValue (covPageParams [SubsystemName ])
140- manager := r .FormValue (covPageParams [ManagerName ])
141247
142- periodType := r .FormValue (covPageParams [PeriodType ])
143- if periodType == "" {
144- periodType = coveragedb .DayPeriod
145- }
146- if periodType != coveragedb .DayPeriod &&
147- periodType != coveragedb .MonthPeriod &&
148- periodType != coveragedb .QuarterPeriod {
149- return fmt .Errorf ("only 'day', 'month' and 'quarter' are allowed, but received %s instead, %w" ,
150- periodType , ErrClientBadRequest )
151- }
152-
153- periodCount := r .FormValue (covPageParams [PeriodCount ])
154- if periodCount == "" {
155- periodCount = "4"
156- }
157- nPeriods , err := strconv .Atoi (periodCount )
158- if err != nil || nPeriods > 12 || nPeriods < 1 {
159- return fmt .Errorf ("periods_count is wrong, expected [1, 12]: %w" , err )
160- }
161-
162- dateTo := civil .DateOf (timeNow (c ))
163- if customDate := r .FormValue (covPageParams [DateTo ]); customDate != "" {
164- if dateTo , err = civil .ParseDate (customDate ); err != nil {
165- return fmt .Errorf ("civil.ParseDate(%s): %w" , customDate , err )
166- }
167- }
168-
169- periods , err := coveragedb .GenNPeriodsTill (nPeriods , dateTo , periodType )
248+ periods , err := coveragedb .GenNPeriodsTill (p .nPeriods , p .dateTo , p .periodType )
170249 if err != nil {
171250 return fmt .Errorf ("%s: %w" , err .Error (), ErrClientBadRequest )
172251 }
@@ -182,29 +261,17 @@ func handleHeatmap(c context.Context, w http.ResponseWriter, r *http.Request, f
182261 slices .Sort (managers )
183262 slices .Sort (subsystems )
184263
185- onlyUnique := r .FormValue (covPageParams [UniqueOnly ]) == "1"
186- orderByCoverLinesDrop := r .FormValue (covPageParams [OrderByCoverDrop ]) == "1"
187- // Prefixing "0" we don't fail on empty string.
188- minCoverLinesDrop , err := strconv .Atoi ("0" + r .FormValue (covPageParams [MinCoverLinesDrop ]))
189- if err != nil {
190- return fmt .Errorf (covPageParams [MinCoverLinesDrop ] + " should be integer" )
191- }
192-
193264 var style template.CSS
194265 var body , js template.HTML
195266 if style , body , js , err = f (c , getCoverageDBClient (c ),
196267 & coveragedb.SelectScope {
197268 Ns : hdr .Namespace ,
198- Subsystem : ss ,
199- Manager : manager ,
269+ Subsystem : p . subsystem ,
270+ Manager : p . manager ,
200271 Periods : periods ,
201272 },
202- onlyUnique , subsystems , managers ,
203- cover.Format {
204- FilterMinCoveredLinesDrop : minCoverLinesDrop ,
205- OrderByCoveredLinesDrop : orderByCoverLinesDrop ,
206- DropCoveredLines0 : onlyUnique ,
207- }); err != nil {
273+ p .onlyUnique , subsystems , managers , p .Format ,
274+ ); err != nil {
208275 return fmt .Errorf ("failed to generate heatmap: %w" , err )
209276 }
210277 return serveTemplate (w , "custom_content.html" , struct {
@@ -261,7 +328,7 @@ func handleFileCoverage(c context.Context, w http.ResponseWriter, r *http.Reques
261328 if err != nil {
262329 return fmt .Errorf ("coveragedb.MakeTimePeriod: %w" , err )
263330 }
264- onlyUnique := r . FormValue ( covPageParams [UniqueOnly ]) == "1"
331+ onlyUnique , _ := getBoolParam ( r , covPageParams [UniqueOnly ], false )
265332 mainNsRepo , _ := nsConfig .mainRepoBranch ()
266333 client := getCoverageDBClient (c )
267334 if client == nil {
0 commit comments