Skip to content

Commit a62ccc0

Browse files
committed
Merge remote-tracking branch 'paulrzcz/master'
2 parents fd1be29 + 1a5514a commit a62ccc0

File tree

8 files changed

+225
-24
lines changed

8 files changed

+225
-24
lines changed

Github/Gists.hs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,35 @@
11
-- | The gists API as described at <http://developer.github.com/v3/gists/>.
22
module Github.Gists (
33
gists
4+
,gists'
45
,gist
6+
,gist'
57
,module Github.Data
68
) where
79

810
import Github.Data
911
import Github.Private
1012

13+
-- | The list of all gists created by the user
14+
--
15+
-- > gists' (Just ("github-username", "github-password")) "mike-burns"
16+
gists' :: Maybe BasicAuth -> String -> IO (Either Error [Gist])
17+
gists' auth userName = githubGet' auth ["users", userName, "gists"]
18+
1119
-- | The list of all public gists created by the user.
1220
--
1321
-- > gists "mike-burns"
1422
gists :: String -> IO (Either Error [Gist])
15-
gists userName = githubGet ["users", userName, "gists"]
23+
gists = gists' Nothing
24+
25+
-- | A specific gist, given its id, with authentication credentials
26+
--
27+
-- > gist' (Just ("github-username", "github-password")) "225074"
28+
gist' :: Maybe BasicAuth -> String -> IO (Either Error Gist)
29+
gist' auth gistId = githubGet' auth ["gists", gistId]
1630

1731
-- | A specific gist, given its id.
1832
--
1933
-- > gist "225074"
2034
gist :: String -> IO (Either Error Gist)
21-
gist gistId = githubGet ["gists", gistId]
35+
gist = gist' Nothing

Github/Issues.hs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
-- | The issues API as described on <http://developer.github.com/v3/issues/>.
22
module Github.Issues (
33
issue
4+
,issue'
45
,issuesForRepo
6+
,issuesForRepo'
57
,IssueLimitation(..)
68
,module Github.Data
79
) where
@@ -30,21 +32,30 @@ data IssueLimitation =
3032
| Descending -- ^ Sort descending. [default]
3133
| Since UTCTime -- ^ Only issues created since the specified date and time.
3234

35+
36+
-- | Details on a specific issue, given the repo owner and name, and the issue
37+
-- number.'
38+
--
39+
-- > issue' (Just ("github-username", "github-password")) "thoughtbot" "paperclip" "462"
40+
issue' :: Maybe BasicAuth -> String -> String -> Int -> IO (Either Error Issue)
41+
issue' auth user repoName issueNumber =
42+
githubGet' auth ["repos", user, repoName, "issues", show issueNumber]
43+
3344
-- | Details on a specific issue, given the repo owner and name, and the issue
3445
-- number.
3546
--
3647
-- > issue "thoughtbot" "paperclip" "462"
3748
issue :: String -> String -> Int -> IO (Either Error Issue)
38-
issue user repoName issueNumber =
39-
githubGet ["repos", user, repoName, "issues", show issueNumber]
49+
issue = issue' Nothing
4050

4151
-- | All issues for a repo (given the repo owner and name), with optional
4252
-- restrictions as described in the @IssueLimitation@ data type.
4353
--
44-
-- > issuesForRepo "thoughtbot" "paperclip" [NoMilestone, OnlyClosed, Mentions "jyurek", Ascending]
45-
issuesForRepo :: String -> String -> [IssueLimitation] -> IO (Either Error [Issue])
46-
issuesForRepo user repoName issueLimitations =
47-
githubGetWithQueryString
54+
-- > issuesForRepo' (Just ("github-username", "github-password")) "thoughtbot" "paperclip" [NoMilestone, OnlyClosed, Mentions "jyurek", Ascending]
55+
issuesForRepo' :: Maybe BasicAuth -> String -> String -> [IssueLimitation] -> IO (Either Error [Issue])
56+
issuesForRepo' auth user repoName issueLimitations =
57+
githubGetWithQueryString'
58+
auth
4859
["repos", user, repoName, "issues"]
4960
(queryStringFromLimitations issueLimitations)
5061
where
@@ -64,3 +75,10 @@ issuesForRepo user repoName issueLimitations =
6475
convert Descending = "direction=desc"
6576
convert (Since t) =
6677
"since=" ++ formatTime defaultTimeLocale "%FT%TZ" t
78+
79+
-- | All issues for a repo (given the repo owner and name), with optional
80+
-- restrictions as described in the @IssueLimitation@ data type.
81+
--
82+
-- > issuesForRepo "thoughtbot" "paperclip" [NoMilestone, OnlyClosed, Mentions "jyurek", Ascending]
83+
issuesForRepo :: String -> String -> [IssueLimitation] -> IO (Either Error [Issue])
84+
issuesForRepo = issuesForRepo' Nothing

Github/Organizations.hs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,35 @@
11
-- | The orgs API as described on <http://developer.github.com/v3/orgs/>.
22
module Github.Organizations (
33
publicOrganizationsFor
4+
,publicOrganizationsFor'
45
,publicOrganization
6+
,publicOrganization'
57
,module Github.Data
68
) where
79

810
import Github.Data
911
import Github.Private
1012

13+
-- | The public organizations for a user, given the user's login, with authorization
14+
--
15+
-- > publicOrganizationsFor' (Just ("github-username", "github-password")) "mike-burns"
16+
publicOrganizationsFor' :: Maybe BasicAuth -> String -> IO (Either Error [SimpleOrganization])
17+
publicOrganizationsFor' auth userName = githubGet' auth ["users", userName, "orgs"]
18+
1119
-- | The public organizations for a user, given the user's login.
1220
--
1321
-- > publicOrganizationsFor "mike-burns"
1422
publicOrganizationsFor :: String -> IO (Either Error [SimpleOrganization])
15-
publicOrganizationsFor userName = githubGet ["users", userName, "orgs"]
23+
publicOrganizationsFor = publicOrganizationsFor' Nothing
24+
25+
-- | Details on a public organization. Takes the organization's login.
26+
--
27+
-- > publicOrganization' (Just ("github-username", "github-password")) "thoughtbot"
28+
publicOrganization' :: Maybe BasicAuth -> String -> IO (Either Error Organization)
29+
publicOrganization' auth organizationName = githubGet' auth ["orgs", organizationName]
1630

1731
-- | Details on a public organization. Takes the organization's login.
1832
--
1933
-- > publicOrganization "thoughtbot"
2034
publicOrganization :: String -> IO (Either Error Organization)
21-
publicOrganization organizationName = githubGet ["orgs", organizationName]
35+
publicOrganization = publicOrganization' Nothing

Github/Private.hs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,23 @@ import qualified Control.Exception as E
1515
import Data.Maybe (fromMaybe)
1616

1717
githubGet :: (FromJSON b, Show b) => [String] -> IO (Either Error b)
18-
githubGet paths =
18+
githubGet = githubGet' Nothing
19+
20+
githubGet' :: (FromJSON b, Show b) => Maybe BasicAuth -> [String] -> IO (Either Error b)
21+
githubGet' auth paths =
1922
githubAPI (BS.pack "GET")
2023
(buildUrl paths)
21-
Nothing
24+
auth
2225
(Nothing :: Maybe Value)
2326

2427
githubGetWithQueryString :: (FromJSON b, Show b) => [String] -> String -> IO (Either Error b)
25-
githubGetWithQueryString paths queryString =
28+
githubGetWithQueryString = githubGetWithQueryString' Nothing
29+
30+
githubGetWithQueryString' :: (FromJSON b, Show b) => Maybe BasicAuth -> [String] -> String -> IO (Either Error b)
31+
githubGetWithQueryString' auth paths queryString =
2632
githubAPI (BS.pack "GET")
2733
(buildUrl paths ++ "?" ++ queryString)
28-
Nothing
34+
auth
2935
(Nothing :: Maybe Value)
3036

3137
githubPost :: (ToJSON a, Show a, FromJSON b, Show b) => BasicAuth -> [String] -> a -> IO (Either Error b)

Github/PullRequests.hs

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
-- | The pull requests API as documented at
22
-- <http://developer.github.com/v3/pulls/>.
33
module Github.PullRequests (
4-
pullRequestsFor
4+
pullRequestsFor'
5+
,pullRequest'
6+
,pullRequestCommits'
7+
,pullRequestFiles'
8+
,pullRequestsFor
59
,pullRequest
610
,pullRequestCommits
711
,pullRequestFiles
@@ -11,33 +15,63 @@ module Github.PullRequests (
1115
import Github.Data
1216
import Github.Private
1317

18+
-- | All pull requests for the repo, by owner and repo name.
19+
-- | With authentification
20+
--
21+
-- > pullRequestsFor' (Just ("github-username", "github-password")) "rails" "rails"
22+
pullRequestsFor' :: Maybe BasicAuth -> String -> String -> IO (Either Error [PullRequest])
23+
pullRequestsFor' auth userName repoName =
24+
githubGet' auth ["repos", userName, repoName, "pulls"]
25+
1426
-- | All pull requests for the repo, by owner and repo name.
1527
--
1628
-- > pullRequestsFor "rails" "rails"
1729
pullRequestsFor :: String -> String -> IO (Either Error [PullRequest])
18-
pullRequestsFor userName repoName =
19-
githubGet ["repos", userName, repoName, "pulls"]
30+
pullRequestsFor = pullRequestsFor' Nothing
31+
32+
-- | A detailed pull request, which has much more information. This takes the
33+
-- repo owner and name along with the number assigned to the pull request.
34+
-- | With authentification
35+
--
36+
-- > pullRequest' (Just ("github-username", "github-password")) "thoughtbot" "paperclip" 562
37+
pullRequest' :: Maybe BasicAuth -> String -> String -> Int -> IO (Either Error DetailedPullRequest)
38+
pullRequest' auth userName repoName number =
39+
githubGet' auth ["repos", userName, repoName, "pulls", show number]
2040

2141
-- | A detailed pull request, which has much more information. This takes the
2242
-- repo owner and name along with the number assigned to the pull request.
2343
--
2444
-- > pullRequest "thoughtbot" "paperclip" 562
2545
pullRequest :: String -> String -> Int -> IO (Either Error DetailedPullRequest)
26-
pullRequest userName repoName number =
27-
githubGet ["repos", userName, repoName, "pulls", show number]
46+
pullRequest = pullRequest' Nothing
47+
48+
-- | All the commits on a pull request, given the repo owner, repo name, and
49+
-- the number of the pull request.
50+
-- | With authentification
51+
--
52+
-- > pullRequestCommits' (Just ("github-username", "github-password")) "thoughtbot" "paperclip" 688
53+
pullRequestCommits' :: Maybe BasicAuth -> String -> String -> Int -> IO (Either Error [Commit])
54+
pullRequestCommits' auth userName repoName number =
55+
githubGet' auth ["repos", userName, repoName, "pulls", show number, "commits"]
2856

2957
-- | All the commits on a pull request, given the repo owner, repo name, and
3058
-- the number of the pull request.
3159
--
3260
-- > pullRequestCommits "thoughtbot" "paperclip" 688
3361
pullRequestCommits :: String -> String -> Int -> IO (Either Error [Commit])
34-
pullRequestCommits userName repoName number =
35-
githubGet ["repos", userName, repoName, "pulls", show number, "commits"]
62+
pullRequestCommits = pullRequestCommits' Nothing
3663

64+
-- | The individual files that a pull request patches. Takes the repo owner and
65+
-- name, plus the number assigned to the pull request.
66+
-- | With authentification
67+
--
68+
-- > pullRequestFiles' (Just ("github-username", "github-password")) "thoughtbot" "paperclip" 688
69+
pullRequestFiles' :: Maybe BasicAuth -> String -> String -> Int -> IO (Either Error [File])
70+
pullRequestFiles' auth userName repoName number =
71+
githubGet' auth ["repos", userName, repoName, "pulls", show number, "files"]
3772
-- | The individual files that a pull request patches. Takes the repo owner and
3873
-- name, plus the number assigned to the pull request.
3974
--
4075
-- > pullRequestFiles "thoughtbot" "paperclip" 688
4176
pullRequestFiles :: String -> String -> Int -> IO (Either Error [File])
42-
pullRequestFiles userName repoName number =
43-
githubGet ["repos", userName, repoName, "pulls", show number, "files"]
77+
pullRequestFiles = pullRequestFiles' Nothing

Github/Users.hs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,22 @@
22
-- <http://developer.github.com/v3/users/>.
33
module Github.Users (
44
userInfoFor
5+
,userInfoFor'
56
,module Github.Data
67
) where
78

89
import Github.Data
910
import Github.Private
1011

12+
-- | The information for a single user, by login name.
13+
-- | With authentification
14+
--
15+
-- > userInfoFor' (Just ("github-username", "github-password")) "mike-burns"
16+
userInfoFor' :: Maybe BasicAuth -> String -> IO (Either Error DetailedOwner)
17+
userInfoFor' auth userName = githubGet' auth ["users", userName]
18+
1119
-- | The information for a single user, by login name.
1220
--
1321
-- > userInfoFor "mike-burns"
1422
userInfoFor :: String -> IO (Either Error DetailedOwner)
15-
userInfoFor userName = githubGet ["users", userName]
23+
userInfoFor = userInfoFor' Nothing
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
module Main where
3+
4+
import qualified Github.Issues as Github
5+
import qualified Data.ByteString as B
6+
import Report
7+
8+
-- The example requires wl-pprint module "The Wadler/Leijen Pretty Printer"
9+
import Text.PrettyPrint.Leijen
10+
11+
auth :: Maybe (B.ByteString, B.ByteString)
12+
auth = Just ("yourgithub id", "somepassword")
13+
14+
mkIssue :: ReportedIssue -> Doc
15+
mkIssue (Issue n t h) = hsep [
16+
fill 5 (text ("#" ++ (show n))),
17+
fill 50 (text t),
18+
fill 5 (text (show h))]
19+
20+
vissues :: ([Doc], [Doc], [Doc]) -> Doc
21+
vissues (x, y, z) = hsep [(vcat x), align (vcat y), align (vcat z)]
22+
23+
mkDoc :: Report -> Doc
24+
mkDoc (Report issues total) = vsep [
25+
text "Report for the milestone",
26+
(vsep . map mkIssue) issues,
27+
text ("Total hours : " ++ (show total) ++" hours")
28+
]
29+
30+
mkFullDoc :: [Github.Issue] -> Doc
31+
mkFullDoc = mkDoc . prepareReport
32+
33+
-- The public repo is used as private are quite sensitive for this report
34+
--
35+
-- The main idea is to use labels like 1h, 2h etc for man-hour estimation of issues
36+
-- on private repos for development "on hire"
37+
--
38+
-- This tool is used to generate report on work done for the customer
39+
--
40+
main :: IO ()
41+
main = do
42+
let limitations = [Github.OnlyClosed, Github.MilestoneId 4]
43+
possibleIssues <- Github.issuesForRepo' auth "paulrzcz" "hquantlib" limitations
44+
case possibleIssues of
45+
(Left err) -> putStrLn $ "Error: " ++ show err
46+
(Right issues) -> putDoc $ mkFullDoc issues
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
module Report (
3+
ReportedIssue (..),
4+
Report (..),
5+
prepareReport,
6+
convertLabels
7+
) where
8+
9+
import Text.Regex.Posix
10+
import qualified Github.Issues as Github
11+
12+
data ReportedIssue = Issue {
13+
riNumber :: Int,
14+
riTitle :: String,
15+
riHour :: Double
16+
} deriving (Show)
17+
18+
data Report = Report {
19+
rIssues :: [ReportedIssue],
20+
rTotal :: Double
21+
} deriving (Show)
22+
23+
convertIssue :: Github.Issue -> ReportedIssue
24+
convertIssue issue = Issue {
25+
riNumber = Github.issueNumber issue,
26+
riTitle = Github.issueTitle issue,
27+
riHour = convertLabels issue
28+
}
29+
30+
convertLabels :: Github.Issue -> Double
31+
convertLabels = sumUp . toNames . Github.issueLabels
32+
33+
prepareReport :: [Github.Issue] -> Report
34+
prepareReport issues = Report {
35+
rIssues = reportedIssues,
36+
rTotal = foldl summator 0 reportedIssues
37+
} where reportedIssues = map convertIssue issues
38+
summator z x = z + (riHour x)
39+
40+
-- Helper functions to construct a sum of hour labels
41+
42+
sumUp :: [Maybe Double] -> Double
43+
sumUp = foldl s 0.0
44+
where s z Nothing = z
45+
s z (Just x) = z+x
46+
47+
toNames :: [Github.IssueLabel] -> [Maybe Double]
48+
toNames = map (toValue . Github.labelName)
49+
50+
isValue :: String -> Bool
51+
isValue label = (label =~ ("^[0-9]h" :: String)) :: Bool
52+
53+
convert :: Read a => [Char] -> a
54+
convert label = read $ take len label
55+
where len = (length label) - 1
56+
57+
toValue :: Read a => String -> Maybe a
58+
toValue label
59+
| isValue label = Just (convert label)
60+
| otherwise = Nothing
61+

0 commit comments

Comments
 (0)