@@ -6,7 +6,7 @@ module Distribution.Server.Features.BuildReports (
6
6
initBuildReportsFeature
7
7
) where
8
8
9
- import Distribution.Server.Framework hiding (BuildLog , BuildCovg )
9
+ import Distribution.Server.Framework hiding (BuildLog , TestLog , BuildCovg )
10
10
11
11
import Distribution.Server.Features.Users
12
12
import Distribution.Server.Features.Upload
@@ -16,7 +16,7 @@ import Distribution.Server.Features.BuildReports.Backup
16
16
import Distribution.Server.Features.BuildReports.State
17
17
import qualified Distribution.Server.Features.BuildReports.BuildReport as BuildReport
18
18
import Distribution.Server.Features.BuildReports.BuildReport (BuildReport (.. ))
19
- import Distribution.Server.Features.BuildReports.BuildReports (BuildReports , BuildReportId (.. ), BuildCovg (.. ), BuildLog (.. ))
19
+ import Distribution.Server.Features.BuildReports.BuildReports (BuildReports , BuildReportId (.. ), BuildCovg (.. ), BuildLog (.. ), TestLog ( .. ) )
20
20
import qualified Distribution.Server.Framework.ResponseContentTypes as Resource
21
21
22
22
import Distribution.Server.Packages.Types
@@ -42,10 +42,11 @@ data ReportsFeature = ReportsFeature {
42
42
reportsFeatureInterface :: HackageFeature ,
43
43
44
44
packageReports :: DynamicPath -> ([(BuildReportId , BuildReport )] -> ServerPartE Response ) -> ServerPartE Response ,
45
- packageReport :: DynamicPath -> ServerPartE (BuildReportId , BuildReport , Maybe BuildLog , Maybe BuildCovg ),
45
+ packageReport :: DynamicPath -> ServerPartE (BuildReportId , BuildReport , Maybe BuildLog , Maybe TestLog , Maybe BuildCovg ),
46
46
47
47
queryPackageReports :: forall m . MonadIO m => PackageId -> m [(BuildReportId , BuildReport )],
48
48
queryBuildLog :: forall m . MonadIO m => BuildLog -> m Resource. BuildLog ,
49
+ queryTestLog :: forall m . MonadIO m => TestLog -> m Resource. TestLog ,
49
50
pkgReportDetails :: forall m . MonadIO m => (PackageIdentifier , Bool ) -> m BuildReport. PkgDetails ,
50
51
queryLastReportStats :: forall m . MonadIO m => PackageIdentifier -> m (Maybe (BuildReportId , BuildReport , Maybe BuildCovg )),
51
52
queryRunTests :: forall m . MonadIO m => PackageId -> m Bool ,
@@ -60,8 +61,9 @@ data ReportsResource = ReportsResource {
60
61
reportsList :: Resource ,
61
62
reportsPage :: Resource ,
62
63
reportsLog :: Resource ,
63
- reportsReset :: Resource ,
64
64
reportsTest :: Resource ,
65
+ reportsReset :: Resource ,
66
+ reportsTestsEnabled :: Resource ,
65
67
reportsListUri :: String -> PackageId -> String ,
66
68
reportsPageUri :: String -> PackageId -> BuildReportId -> String ,
67
69
reportsLogUri :: PackageId -> BuildReportId -> String
@@ -121,8 +123,9 @@ buildReportsFeature name
121
123
reportsList
122
124
, reportsPage
123
125
, reportsLog
124
- , reportsReset
125
126
, reportsTest
127
+ , reportsReset
128
+ , reportsTestsEnabled
126
129
]
127
130
, featureState = [abstractAcidStateComponent reportsState]
128
131
}
@@ -144,12 +147,12 @@ buildReportsFeature name
144
147
]
145
148
, resourceGet = [ (" " , resetBuildFails) ]
146
149
}
147
- , reportsTest = (extendResourcePath " /reports/test /" corePackagePage) {
150
+ , reportsTestsEnabled = (extendResourcePath " /reports/testsEnabled /" corePackagePage) {
148
151
resourceDesc = [ (GET , " Get reports test settings" )
149
152
, (POST , " Set reports test settings" )
150
153
]
151
- , resourceGet = [ (" json" , getReportsTest ) ]
152
- , resourcePost = [ (" " , postReportsTest ) ]
154
+ , resourceGet = [ (" json" , getReportsTestsEnabled ) ]
155
+ , resourcePost = [ (" " , postReportsTestsEnabled ) ]
153
156
}
154
157
, reportsPage = (extendResourcePath " /reports/:id.:format" corePackagePage) {
155
158
resourceDesc = [ (GET , " Get a specific build report" )
@@ -167,6 +170,15 @@ buildReportsFeature name
167
170
, resourceDelete = [ (" " , deleteBuildLog )]
168
171
, resourcePut = [ (" " , putBuildLog) ]
169
172
}
173
+ , reportsTest = (extendResourcePath " /reports/:id/test" corePackagePage) {
174
+ resourceDesc = [ (GET , " Get the test log associated with a build report" )
175
+ , (DELETE , " Delete a test log" )
176
+ , (PUT , " Upload a test log for a build report" )
177
+ ]
178
+ , resourceGet = [ (" txt" , serveTestLog) ]
179
+ , resourceDelete = [ (" " , deleteTestLog )]
180
+ , resourcePut = [ (" " , putTestLog) ]
181
+ }
170
182
, reportsListUri = \ format pkgid -> renderResource (reportsList reportsResource) [display pkgid, format]
171
183
, reportsPageUri = \ format pkgid repid -> renderResource (reportsPage reportsResource) [display pkgid, display repid, format]
172
184
, reportsLogUri = \ pkgid repid -> renderResource (reportsLog reportsResource) [display pkgid, display repid]
@@ -187,26 +199,30 @@ buildReportsFeature name
187
199
guardValidPackageId pkgid
188
200
queryPackageReports pkgid >>= continue
189
201
190
- packageReport :: DynamicPath -> ServerPartE (BuildReportId , BuildReport , Maybe BuildLog , Maybe BuildCovg )
202
+ packageReport :: DynamicPath -> ServerPartE (BuildReportId , BuildReport , Maybe BuildLog , Maybe TestLog , Maybe BuildCovg )
191
203
packageReport dpath = do
192
204
pkgid <- packageInPath dpath
193
205
guardValidPackageId pkgid
194
206
reportId <- reportIdInPath dpath
195
207
mreport <- queryState reportsState $ LookupReportCovg pkgid reportId
196
208
case mreport of
197
209
Nothing -> errNotFound " Report not found" [MText " Build report does not exist" ]
198
- Just (report, mlog, covg) -> return (reportId, report, mlog, covg)
210
+ Just (report, mlog, mtest, covg) -> return (reportId, report, mlog, mtest , covg)
199
211
200
212
queryPackageReports :: MonadIO m => PackageId -> m [(BuildReportId , BuildReport )]
201
213
queryPackageReports pkgid = do
202
214
reports <- queryState reportsState $ LookupPackageReports pkgid
203
- return $ map (second fst ) reports
215
+ return $ map (second ( \ (a, _, _) -> a) ) reports
204
216
205
217
queryBuildLog :: MonadIO m => BuildLog -> m Resource. BuildLog
206
218
queryBuildLog (BuildLog blobId) = do
207
219
file <- liftIO $ BlobStorage. fetch store blobId
208
220
return $ Resource. BuildLog file
209
221
222
+ queryTestLog :: MonadIO m => TestLog -> m Resource. TestLog
223
+ queryTestLog (TestLog blobId) = do
224
+ file <- liftIO $ BlobStorage. fetch store blobId
225
+ return $ Resource. TestLog file
210
226
211
227
pkgReportDetails :: MonadIO m => (PackageIdentifier , Bool ) -> m BuildReport. PkgDetails-- (PackageIdentifier, Bool, Maybe (BuildStatus, Maybe UTCTime, Maybe Version))
212
228
pkgReportDetails (pkgid, docs) = do
@@ -215,7 +231,7 @@ buildReportsFeature name
215
231
runTests <- fmap Just . queryState reportsState $ LookupRunTests pkgid
216
232
(time, ghcId) <- case latestRpt of
217
233
Nothing -> return (Nothing ,Nothing )
218
- Just (_, brp, _, _) -> do
234
+ Just (_, brp, _, _, _ ) -> do
219
235
let (CompilerId _ vrsn) = compiler brp
220
236
return (time brp, Just vrsn)
221
237
return (BuildReport. PkgDetails pkgid docs failCnt time ghcId runTests)
@@ -225,7 +241,7 @@ buildReportsFeature name
225
241
lookupRes <- queryState reportsState $ LookupLatestReport pkgid
226
242
case lookupRes of
227
243
Nothing -> return Nothing
228
- Just (rptId, rpt, _, covg) -> return (Just (rptId, rpt, covg))
244
+ Just (rptId, rpt, _, _, covg) -> return (Just (rptId, rpt, covg))
229
245
230
246
queryRunTests :: MonadIO m => PackageId -> m Bool
231
247
queryRunTests pkgid = queryState reportsState $ LookupRunTests pkgid
@@ -235,19 +251,30 @@ buildReportsFeature name
235
251
textPackageReports dpath = packageReports dpath $ return . toResponse . show
236
252
237
253
textPackageReport dpath = do
238
- (_, report, _, _) <- packageReport dpath
254
+ (_, report, _, _, _ ) <- packageReport dpath
239
255
return . toResponse $ BuildReport. show report
240
256
241
257
-- result: not-found error or text file
242
258
serveBuildLog :: DynamicPath -> ServerPartE Response
243
259
serveBuildLog dpath = do
244
- (repid, _, mlog, _) <- packageReport dpath
260
+ (repid, _, mlog, _, _ ) <- packageReport dpath
245
261
case mlog of
246
262
Nothing -> errNotFound " Log not found" [MText $ " Build log for report " ++ display repid ++ " not found" ]
247
263
Just logId -> do
248
264
cacheControlWithoutETag [Public , maxAgeDays 30 ]
249
265
toResponse <$> queryBuildLog logId
250
266
267
+ -- result: not-found error or text file
268
+ serveTestLog :: DynamicPath -> ServerPartE Response
269
+ serveTestLog dpath = do
270
+ (repid, _, _, mtest, _) <- packageReport dpath
271
+ case mtest of
272
+ Nothing -> errNotFound " Test log not found" [MText $ " Test log for report " ++ display repid ++ " not found" ]
273
+ Just logId -> do
274
+ cacheControlWithoutETag [Public , maxAgeDays 30 ]
275
+ toResponse <$> queryTestLog logId
276
+
277
+
251
278
-- result: auth error, not-found error, parse error, or redirect
252
279
submitBuildReport :: DynamicPath -> ServerPartE Response
253
280
submitBuildReport dpath = do
@@ -300,6 +327,18 @@ buildReportsFeature name
300
327
void $ updateState reportsState $ SetBuildLog pkgid reportId (Just $ BuildLog buildLog)
301
328
noContent (toResponse () )
302
329
330
+ putTestLog :: DynamicPath -> ServerPartE Response
331
+ putTestLog dpath = do
332
+ pkgid <- packageInPath dpath
333
+ guardValidPackageId pkgid
334
+ reportId <- reportIdInPath dpath
335
+ -- logged in users
336
+ guardAuthorised_ [AnyKnownUser ]
337
+ blogbody <- expectTextPlain
338
+ testLog <- liftIO $ BlobStorage. add store blogbody
339
+ void $ updateState reportsState $ SetTestLog pkgid reportId (Just $ TestLog testLog)
340
+ noContent (toResponse () )
341
+
303
342
{-
304
343
Example using curl: (TODO: why is this PUT, while logs are POST?)
305
344
@@ -319,6 +358,15 @@ buildReportsFeature name
319
358
void $ updateState reportsState $ SetBuildLog pkgid reportId Nothing
320
359
noContent (toResponse () )
321
360
361
+ deleteTestLog :: DynamicPath -> ServerPartE Response
362
+ deleteTestLog dpath = do
363
+ pkgid <- packageInPath dpath
364
+ guardValidPackageId pkgid
365
+ reportId <- reportIdInPath dpath
366
+ guardAuthorised_ [InGroup trusteesGroup]
367
+ void $ updateState reportsState $ SetTestLog pkgid reportId Nothing
368
+ noContent (toResponse () )
369
+
322
370
guardAuthorisedAsMaintainerOrTrustee pkgname =
323
371
guardAuthorised_ [InGroup (maintainersGroup pkgname), InGroup trusteesGroup]
324
372
@@ -332,16 +380,16 @@ buildReportsFeature name
332
380
then seeOther (reportsListUri reportsResource " " pkgid) $ toResponse ()
333
381
else errNotFound " Report not found" [MText " Build report does not exist" ]
334
382
335
- getReportsTest :: DynamicPath -> ServerPartE Response
336
- getReportsTest dpath = do
383
+ getReportsTestsEnabled :: DynamicPath -> ServerPartE Response
384
+ getReportsTestsEnabled dpath = do
337
385
pkgid <- packageInPath dpath
338
386
guardValidPackageId pkgid
339
387
guardAuthorisedAsMaintainerOrTrustee (packageName pkgid)
340
388
runTest <- queryRunTests pkgid
341
389
pure $ toResponse $ toJSON runTest
342
390
343
- postReportsTest :: DynamicPath -> ServerPartE Response
344
- postReportsTest dpath = do
391
+ postReportsTestsEnabled :: DynamicPath -> ServerPartE Response
392
+ postReportsTestsEnabled dpath = do
345
393
pkgid <- packageInPath dpath
346
394
runTests <- body $ looks " runTests"
347
395
guardValidPackageId pkgid
@@ -360,6 +408,7 @@ buildReportsFeature name
360
408
buildFiles <- expectAesonContent:: ServerPartE BuildReport. BuildFiles
361
409
let reportBody = BuildReport. reportContent buildFiles
362
410
logBody = BuildReport. logContent buildFiles
411
+ testBody = BuildReport. testContent buildFiles
363
412
covgBody = BuildReport. coverageContent buildFiles
364
413
failStatus = BuildReport. buildFail buildFiles
365
414
@@ -374,8 +423,9 @@ buildReportsFeature name
374
423
guardAuthorisedAsMaintainerOrTrustee (packageName pkgid)
375
424
report' <- liftIO $ BuildReport. affixTimestamp report
376
425
logBlob <- liftIO $ traverse (\ x -> BlobStorage. add store $ fromString x) logBody
426
+ testBlob <- liftIO $ traverse (\ x -> BlobStorage. add store $ fromString x) testBody
377
427
reportId <- updateState reportsState $
378
- AddRptLogCovg pkgid (report', (fmap BuildLog logBlob), (fmap BuildReport. parseCovg covgBody))
428
+ AddRptLogTestCovg pkgid (report', (fmap BuildLog logBlob), ( fmap TestLog testBlob), (fmap BuildReport. parseCovg covgBody))
379
429
-- redirect to new reports page
380
430
seeOther (reportsPageUri reportsResource " " pkgid reportId) $ toResponse ()
381
431
0 commit comments