Skip to content

Commit 89b0ed6

Browse files
committed
Review suggestions
1 parent 9381ffd commit 89b0ed6

File tree

1 file changed

+52
-44
lines changed

1 file changed

+52
-44
lines changed

Statistics.hs

Lines changed: 52 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ build-depends:
66
default-language: GHC2021
77
ghc-options: -Wall -Wno-type-defaults
88
-}
9+
{-# LANGUAGE ApplicativeDo #-}
910
{-# LANGUAGE ImportQualifiedPost #-}
1011
{-# LANGUAGE OverloadedStrings #-}
1112
{-# LANGUAGE RecordWildCards #-}
12-
{-# LANGUAGE ViewPatterns #-}
1313

1414
import Control.Exception
15+
import Control.Monad (when)
1516
import Data.Binary
1617
import Data.ByteString qualified as B
1718
import Data.ByteString.Lazy qualified as BL
@@ -20,39 +21,42 @@ import Data.List (sort)
2021
import Data.Maybe (isNothing, mapMaybe)
2122
import Data.Text (Text)
2223
import Data.Text qualified as T
23-
import Data.Time.Clock (UTCTime, diffUTCTime, getCurrentTime)
24+
import Data.Time.Calendar (Day, diffDays)
25+
import Data.Time.Clock (UTCTime (..), diffUTCTime, getCurrentTime)
2426
import Data.Tuple
2527
import Data.Vector qualified as V
2628
import GitHub qualified as GH
2729
import Options.Applicative
2830
import System.IO
2931
import Prelude hiding (until)
3032

31-
data Config = Config {
32-
since :: UTCTime
33-
, until :: Maybe UTCTime
33+
data Config = Config
34+
{ startTime :: Day
35+
, endTime :: Day
3436
, workMode :: WorkMode
3537
}
3638

3739
data WorkMode
3840
= Offline FilePath
3941
| Online (Maybe B.ByteString) (Maybe FilePath)
4042

41-
configParser :: Parser Config
42-
configParser = do
43+
configParser :: UTCTime -> Parser Config
44+
configParser currTime = do
45+
startTime <-
46+
option auto $
47+
long "since"
48+
<> metavar "DATE"
49+
<> help "The start date of the analysis"
50+
<> showDefault
51+
<> value (read "2021-10-23")
52+
endTime <-
53+
option auto $
54+
long "until"
55+
<> metavar "DATE"
56+
<> help "The end date of the analysis"
57+
<> showDefault
58+
<> value (utctDay currTime)
4359
let
44-
parseStartTime =
45-
option auto $
46-
long "since"
47-
<> metavar "SINCE"
48-
<> help "The start date of the analysis (default: 2021-10-23)"
49-
<> value (read "2021-10-23 00:00:00 UTC")
50-
parseEndTime =
51-
optional $
52-
option auto $
53-
long "until"
54-
<> metavar "UNTIL"
55-
<> help "The end date of the analysis"
5660
parseUsername =
5761
optional $
5862
strOption $
@@ -71,7 +75,8 @@ configParser = do
7175
<> metavar "FILE"
7276
<> help "Work offline using previously saved cache"
7377

74-
Config <$> parseStartTime <*> parseEndTime <*> (Offline <$> parseOffline <|> Online <$> parseUsername <*> parseCacheFile)
78+
workMode <- Offline <$> parseOffline <|> Online <$> parseUsername <*> parseCacheFile
79+
pure Config {..}
7580

7681
getPassword :: IO B.ByteString
7782
getPassword = do
@@ -90,10 +95,10 @@ getBasicAuth username = do
9095
password <- getPassword
9196
pure $ GH.BasicAuth username password
9297

93-
getGithubIssues :: Config -> IO (V.Vector GH.Issue)
94-
getGithubIssues (workMode -> (Offline cacheFile)) =
98+
getGithubIssues :: WorkMode -> IO (V.Vector GH.Issue)
99+
getGithubIssues (Offline cacheFile) =
95100
decode <$> BL.readFile cacheFile
96-
getGithubIssues (workMode -> (Online mUsername mCacheFile)) = do
101+
getGithubIssues (Online mUsername mCacheFile) = do
97102
let githubOrg = "haskell"
98103
githubRepo = "core-libraries-committee"
99104
am <- traverse getBasicAuth mUsername
@@ -133,23 +138,23 @@ computeLifeTimeInDays Issue {..} = case issClosedAt of
133138
Nothing -> Nothing
134139
Just t -> Just $ realToFrac (diffUTCTime t issCreatedAt) / 86400
135140

136-
computeDaysSinceCreation :: UTCTime -> Issue -> Double
141+
computeDaysSinceCreation :: Day -> Issue -> Double
137142
computeDaysSinceCreation currTime Issue {..} =
138-
realToFrac (diffUTCTime currTime issCreatedAt) / 86400
143+
realToFrac (diffUTCTime (UTCTime currTime 0) issCreatedAt) / 86400
139144

140145
isApproved :: Issue -> Bool
141146
isApproved Issue {..} = "approved" `elem` issLabels
142147

143148
isDeclined :: Issue -> Bool
144149
isDeclined Issue {..} = "declined" `elem` issLabels
145150

146-
isMeta :: Issue -> Bool
147-
isMeta Issue {..} = "meta" `elem` issLabels
151+
isProposal :: Issue -> Bool
152+
isProposal Issue {..} = not ("meta" `elem` issLabels || "core-libraries" `elem` issLabels)
148153

149-
isWithinTimeFrame :: UTCTime -> UTCTime -> Issue -> Bool
154+
isWithinTimeFrame :: Day -> Day -> Issue -> Bool
150155
isWithinTimeFrame since to Issue {..} =
151-
issCreatedAt >= since
152-
&& issCreatedAt <= to
156+
issCreatedAt >= UTCTime since 0
157+
&& issCreatedAt <= UTCTime to 0
153158

154159
isBase :: Int -> Issue -> Bool
155160
isBase n Issue {..} = ("base-4." <> T.pack (show n)) `elem` issLabels
@@ -169,6 +174,7 @@ data Stat = Stat
169174
deriving (Show)
170175

171176
collectStat :: (Issue -> Maybe Double) -> [Issue] -> Stat
177+
collectStat _ [] = error "collectStat: no issues found!"
172178
collectStat f is = Stat {..}
173179
where
174180
(statMinIssue, statMinMetric) = getMin is
@@ -189,26 +195,27 @@ collectStat f is = Stat {..}
189195

190196
main :: IO ()
191197
main = do
192-
cnf <-
198+
currTime <- getCurrentTime
199+
Config {..} <-
193200
execParser $
194201
info
195-
(configParser <**> helper)
202+
(configParser currTime <**> helper)
196203
(fullDesc <> header "Collect statistics for CLC proposals")
197-
issues <- getGithubIssues cnf
198-
199-
let startTime = since cnf
200-
endTime <- maybe getCurrentTime pure (until cnf)
204+
issues <- getGithubIssues workMode
201205

202206
let proposals =
203207
filter (isWithinTimeFrame startTime endTime) $
204-
filter (not . isMeta) . map githubIssueToIssue $
208+
filter isProposal . map githubIssueToIssue $
205209
filter (isNothing . GH.issuePullRequest) $
206210
V.toList issues
207211
approvedProposals = filter isApproved proposals
208212
declinedProposals = filter isDeclined proposals
209213

214+
putStrLn $ "Timeframe: since " ++ show startTime ++ " until " ++ show endTime
215+
putStrLn ""
216+
210217
putStrLn $ "Total number of CLC proposals: " ++ show (length proposals)
211-
putStrLn $ "Rate of proposals: " ++ show (round (fromIntegral (length proposals) * 86400 * 365.25 / 12 / realToFrac (diffUTCTime endTime startTime))) ++ " per month"
218+
putStrLn $ "Rate of proposals: " ++ show (round (fromIntegral (length proposals) * 365.25 / 12 / realToFrac (diffDays endTime startTime))) ++ " per month"
212219
putStrLn $ "Approved proposals: " ++ show (length approvedProposals)
213220
putStrLn $ "Declined proposals: " ++ show (length declinedProposals)
214221
putStrLn ""
@@ -243,9 +250,10 @@ main = do
243250
putStrLn ""
244251

245252
let openProposals = filter (isNothing . issClosedAt) proposals
246-
putStrLn $ "Open proposals: " ++ show (length openProposals)
247-
let openLifeTime = collectStat (Just . computeDaysSinceCreation endTime) openProposals
248-
putStrLn $ "Median age for open proposals: " ++ show (statMed openLifeTime) ++ " days"
249-
putStrLn $ "Average age for open proposals: " ++ show (statAvg openLifeTime) ++ " days"
250-
putStrLn $ "Newest open proposal:\n\t" ++ show (round (statMinMetric openLifeTime)) ++ " days for " ++ show (issTitle (statMinIssue openLifeTime))
251-
putStrLn $ "Oldest open proposal:\n\t" ++ show (round (statMaxMetric openLifeTime)) ++ " days for " ++ show (issTitle (statMaxIssue openLifeTime))
253+
when (not $ null openProposals) $ do
254+
putStrLn $ "Open proposals: " ++ show (length openProposals)
255+
let openLifeTime = collectStat (Just . computeDaysSinceCreation endTime) openProposals
256+
putStrLn $ "Median age for open proposals: " ++ show (statMed openLifeTime) ++ " days"
257+
putStrLn $ "Average age for open proposals: " ++ show (statAvg openLifeTime) ++ " days"
258+
putStrLn $ "Newest open proposal:\n\t" ++ show (round (statMinMetric openLifeTime)) ++ " days for " ++ show (issTitle (statMinIssue openLifeTime))
259+
putStrLn $ "Oldest open proposal:\n\t" ++ show (round (statMaxMetric openLifeTime)) ++ " days for " ++ show (issTitle (statMaxIssue openLifeTime))

0 commit comments

Comments
 (0)