@@ -6,7 +6,7 @@ module Distribution.Server.Features.BuildReports (
66 initBuildReportsFeature
77 ) where
88
9- import Distribution.Server.Framework hiding (BuildLog , BuildCovg )
9+ import Distribution.Server.Framework hiding (BuildLog , TestLog , BuildCovg )
1010
1111import Distribution.Server.Features.Users
1212import Distribution.Server.Features.Upload
@@ -16,7 +16,7 @@ import Distribution.Server.Features.BuildReports.Backup
1616import Distribution.Server.Features.BuildReports.State
1717import qualified Distribution.Server.Features.BuildReports.BuildReport as BuildReport
1818import 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 ( .. ) )
2020import qualified Distribution.Server.Framework.ResponseContentTypes as Resource
2121
2222import Distribution.Server.Packages.Types
@@ -42,10 +42,11 @@ data ReportsFeature = ReportsFeature {
4242 reportsFeatureInterface :: HackageFeature ,
4343
4444 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 ),
4646
4747 queryPackageReports :: forall m . MonadIO m => PackageId -> m [(BuildReportId , BuildReport )],
4848 queryBuildLog :: forall m . MonadIO m => BuildLog -> m Resource. BuildLog ,
49+ queryTestLog :: forall m . MonadIO m => TestLog -> m Resource. TestLog ,
4950 pkgReportDetails :: forall m . MonadIO m => (PackageIdentifier , Bool ) -> m BuildReport. PkgDetails ,
5051 queryLastReportStats :: forall m . MonadIO m => PackageIdentifier -> m (Maybe (BuildReportId , BuildReport , Maybe BuildCovg )),
5152 queryRunTests :: forall m . MonadIO m => PackageId -> m Bool ,
@@ -60,8 +61,9 @@ data ReportsResource = ReportsResource {
6061 reportsList :: Resource ,
6162 reportsPage :: Resource ,
6263 reportsLog :: Resource ,
63- reportsReset :: Resource ,
6464 reportsTest :: Resource ,
65+ reportsReset :: Resource ,
66+ reportsTestsEnabled :: Resource ,
6567 reportsListUri :: String -> PackageId -> String ,
6668 reportsPageUri :: String -> PackageId -> BuildReportId -> String ,
6769 reportsLogUri :: PackageId -> BuildReportId -> String
@@ -121,8 +123,9 @@ buildReportsFeature name
121123 reportsList
122124 , reportsPage
123125 , reportsLog
124- , reportsReset
125126 , reportsTest
127+ , reportsReset
128+ , reportsTestsEnabled
126129 ]
127130 , featureState = [abstractAcidStateComponent reportsState]
128131 }
@@ -144,12 +147,12 @@ buildReportsFeature name
144147 ]
145148 , resourceGet = [ (" " , resetBuildFails) ]
146149 }
147- , reportsTest = (extendResourcePath " /reports/test /" corePackagePage) {
150+ , reportsTestsEnabled = (extendResourcePath " /reports/testsEnabled /" corePackagePage) {
148151 resourceDesc = [ (GET , " Get reports test settings" )
149152 , (POST , " Set reports test settings" )
150153 ]
151- , resourceGet = [ (" json" , getReportsTest ) ]
152- , resourcePost = [ (" " , postReportsTest ) ]
154+ , resourceGet = [ (" json" , getReportsTestsEnabled ) ]
155+ , resourcePost = [ (" " , postReportsTestsEnabled ) ]
153156 }
154157 , reportsPage = (extendResourcePath " /reports/:id.:format" corePackagePage) {
155158 resourceDesc = [ (GET , " Get a specific build report" )
@@ -167,6 +170,15 @@ buildReportsFeature name
167170 , resourceDelete = [ (" " , deleteBuildLog )]
168171 , resourcePut = [ (" " , putBuildLog) ]
169172 }
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+ }
170182 , reportsListUri = \ format pkgid -> renderResource (reportsList reportsResource) [display pkgid, format]
171183 , reportsPageUri = \ format pkgid repid -> renderResource (reportsPage reportsResource) [display pkgid, display repid, format]
172184 , reportsLogUri = \ pkgid repid -> renderResource (reportsLog reportsResource) [display pkgid, display repid]
@@ -187,26 +199,30 @@ buildReportsFeature name
187199 guardValidPackageId pkgid
188200 queryPackageReports pkgid >>= continue
189201
190- packageReport :: DynamicPath -> ServerPartE (BuildReportId , BuildReport , Maybe BuildLog , Maybe BuildCovg )
202+ packageReport :: DynamicPath -> ServerPartE (BuildReportId , BuildReport , Maybe BuildLog , Maybe TestLog , Maybe BuildCovg )
191203 packageReport dpath = do
192204 pkgid <- packageInPath dpath
193205 guardValidPackageId pkgid
194206 reportId <- reportIdInPath dpath
195207 mreport <- queryState reportsState $ LookupReportCovg pkgid reportId
196208 case mreport of
197209 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)
199211
200212 queryPackageReports :: MonadIO m => PackageId -> m [(BuildReportId , BuildReport )]
201213 queryPackageReports pkgid = do
202214 reports <- queryState reportsState $ LookupPackageReports pkgid
203- return $ map (second fst ) reports
215+ return $ map (second ( \ (a, _, _) -> a) ) reports
204216
205217 queryBuildLog :: MonadIO m => BuildLog -> m Resource. BuildLog
206218 queryBuildLog (BuildLog blobId) = do
207219 file <- liftIO $ BlobStorage. fetch store blobId
208220 return $ Resource. BuildLog file
209221
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
210226
211227 pkgReportDetails :: MonadIO m => (PackageIdentifier , Bool ) -> m BuildReport. PkgDetails-- (PackageIdentifier, Bool, Maybe (BuildStatus, Maybe UTCTime, Maybe Version))
212228 pkgReportDetails (pkgid, docs) = do
@@ -215,7 +231,7 @@ buildReportsFeature name
215231 runTests <- fmap Just . queryState reportsState $ LookupRunTests pkgid
216232 (time, ghcId) <- case latestRpt of
217233 Nothing -> return (Nothing ,Nothing )
218- Just (_, brp, _, _) -> do
234+ Just (_, brp, _, _, _ ) -> do
219235 let (CompilerId _ vrsn) = compiler brp
220236 return (time brp, Just vrsn)
221237 return (BuildReport. PkgDetails pkgid docs failCnt time ghcId runTests)
@@ -225,7 +241,7 @@ buildReportsFeature name
225241 lookupRes <- queryState reportsState $ LookupLatestReport pkgid
226242 case lookupRes of
227243 Nothing -> return Nothing
228- Just (rptId, rpt, _, covg) -> return (Just (rptId, rpt, covg))
244+ Just (rptId, rpt, _, _, covg) -> return (Just (rptId, rpt, covg))
229245
230246 queryRunTests :: MonadIO m => PackageId -> m Bool
231247 queryRunTests pkgid = queryState reportsState $ LookupRunTests pkgid
@@ -235,19 +251,30 @@ buildReportsFeature name
235251 textPackageReports dpath = packageReports dpath $ return . toResponse . show
236252
237253 textPackageReport dpath = do
238- (_, report, _, _) <- packageReport dpath
254+ (_, report, _, _, _ ) <- packageReport dpath
239255 return . toResponse $ BuildReport. show report
240256
241257 -- result: not-found error or text file
242258 serveBuildLog :: DynamicPath -> ServerPartE Response
243259 serveBuildLog dpath = do
244- (repid, _, mlog, _) <- packageReport dpath
260+ (repid, _, mlog, _, _ ) <- packageReport dpath
245261 case mlog of
246262 Nothing -> errNotFound " Log not found" [MText $ " Build log for report " ++ display repid ++ " not found" ]
247263 Just logId -> do
248264 cacheControlWithoutETag [Public , maxAgeDays 30 ]
249265 toResponse <$> queryBuildLog logId
250266
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+
251278 -- result: auth error, not-found error, parse error, or redirect
252279 submitBuildReport :: DynamicPath -> ServerPartE Response
253280 submitBuildReport dpath = do
@@ -300,6 +327,18 @@ buildReportsFeature name
300327 void $ updateState reportsState $ SetBuildLog pkgid reportId (Just $ BuildLog buildLog)
301328 noContent (toResponse () )
302329
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+
303342 {-
304343 Example using curl: (TODO: why is this PUT, while logs are POST?)
305344
@@ -319,6 +358,15 @@ buildReportsFeature name
319358 void $ updateState reportsState $ SetBuildLog pkgid reportId Nothing
320359 noContent (toResponse () )
321360
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+
322370 guardAuthorisedAsMaintainerOrTrustee pkgname =
323371 guardAuthorised_ [InGroup (maintainersGroup pkgname), InGroup trusteesGroup]
324372
@@ -332,16 +380,16 @@ buildReportsFeature name
332380 then seeOther (reportsListUri reportsResource " " pkgid) $ toResponse ()
333381 else errNotFound " Report not found" [MText " Build report does not exist" ]
334382
335- getReportsTest :: DynamicPath -> ServerPartE Response
336- getReportsTest dpath = do
383+ getReportsTestsEnabled :: DynamicPath -> ServerPartE Response
384+ getReportsTestsEnabled dpath = do
337385 pkgid <- packageInPath dpath
338386 guardValidPackageId pkgid
339387 guardAuthorisedAsMaintainerOrTrustee (packageName pkgid)
340388 runTest <- queryRunTests pkgid
341389 pure $ toResponse $ toJSON runTest
342390
343- postReportsTest :: DynamicPath -> ServerPartE Response
344- postReportsTest dpath = do
391+ postReportsTestsEnabled :: DynamicPath -> ServerPartE Response
392+ postReportsTestsEnabled dpath = do
345393 pkgid <- packageInPath dpath
346394 runTests <- body $ looks " runTests"
347395 guardValidPackageId pkgid
@@ -360,6 +408,7 @@ buildReportsFeature name
360408 buildFiles <- expectAesonContent:: ServerPartE BuildReport. BuildFiles
361409 let reportBody = BuildReport. reportContent buildFiles
362410 logBody = BuildReport. logContent buildFiles
411+ testBody = BuildReport. testContent buildFiles
363412 covgBody = BuildReport. coverageContent buildFiles
364413 failStatus = BuildReport. buildFail buildFiles
365414
@@ -374,8 +423,9 @@ buildReportsFeature name
374423 guardAuthorisedAsMaintainerOrTrustee (packageName pkgid)
375424 report' <- liftIO $ BuildReport. affixTimestamp report
376425 logBlob <- liftIO $ traverse (\ x -> BlobStorage. add store $ fromString x) logBody
426+ testBlob <- liftIO $ traverse (\ x -> BlobStorage. add store $ fromString x) testBody
377427 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))
379429 -- redirect to new reports page
380430 seeOther (reportsPageUri reportsResource " " pkgid reportId) $ toResponse ()
381431
0 commit comments