1
1
module Json = Yojson. Safe
2
2
3
+ let ( let * ) = Result. bind
3
4
let ( / ) a b = Json.Util. member b a
4
5
5
6
let query user =
@@ -66,8 +67,8 @@ module Datetime = struct
66
67
type t = string
67
68
68
69
let parse = function
69
- | `String s -> s
70
- | x -> Fmt. failwith " Invalid Datatime %a" Json. pp x
70
+ | `String s -> Ok s
71
+ | x -> Error ( `Msg ( Fmt. str " Invalid Datatime %a" Json. pp x))
71
72
end
72
73
73
74
module Repo_map = Map. Make (String )
@@ -83,75 +84,84 @@ type item = {
83
84
84
85
type t = { username : string ; activity : item list Repo_map .t }
85
86
87
+ let to_string x =
88
+ Json.Util. to_string_option x
89
+ |> Option. to_result ~none: (`Msg (Fmt. str " Expected string, got %a" Json. pp x))
90
+
91
+ let combine lx =
92
+ List. fold_left
93
+ (fun acc x ->
94
+ let * acc = acc in
95
+ let * x = x in
96
+ Ok (x :: acc))
97
+ (Ok [] ) lx
98
+
86
99
let read_issues json =
87
100
Json.Util. to_list (json / " nodes" )
88
101
|> List. filter (( <> ) `Null )
89
- |> List. map @@ fun node ->
90
- let date = Datetime. parse (node / " occurredAt" ) in
91
- let x = node / " issue" in
92
- let url = x / " url" |> Json.Util. to_string in
93
- let title = x / " title" |> Json.Util. to_string in
94
- let body = x / " body" |> Json.Util. to_string in
95
- let repo = x / " repository" / " nameWithOwner" |> Json.Util. to_string in
96
- { kind = `Issue ; date; url; title; body; repo }
102
+ |> List. map (fun node ->
103
+ let * date = Datetime. parse (node / " occurredAt" ) in
104
+ let x = node / " issue" in
105
+ let * url = x / " url" |> to_string in
106
+ let * title = x / " title" |> to_string in
107
+ let * body = x / " body" |> to_string in
108
+ let * repo = x / " repository" / " nameWithOwner" |> to_string in
109
+ Ok { kind = `Issue ; date; url; title; body; repo })
110
+ |> combine
97
111
98
112
let read_prs json =
99
113
Json.Util. to_list (json / " nodes" )
100
114
|> List. filter (( <> ) `Null )
101
- |> List. map @@ fun node ->
102
- let date = Datetime. parse (node / " occurredAt" ) in
103
- let pr = node / " pullRequest" in
104
- let url = pr / " url" |> Json.Util. to_string in
105
- let title = pr / " title" |> Json.Util. to_string in
106
- let body = pr / " body" |> Json.Util. to_string in
107
- let repo = pr / " repository" / " nameWithOwner" |> Json.Util. to_string in
108
- { kind = `PR ; date; url; title; body; repo }
115
+ |> List. map (fun node ->
116
+ let * date = node / " occurredAt" |> Datetime. parse in
117
+ let pr = node / " pullRequest" in
118
+ let * url = pr / " url" |> to_string in
119
+ let * title = pr / " title" |> to_string in
120
+ let * body = pr / " body" |> to_string in
121
+ let * repo = pr / " repository" / " nameWithOwner" |> to_string in
122
+ Ok { kind = `PR ; date; url; title; body; repo })
123
+ |> combine
109
124
110
125
let read_reviews json =
111
126
Json.Util. to_list (json / " nodes" )
112
127
|> List. filter (( <> ) `Null )
113
- |> List. map @@ fun node ->
114
- let date = Datetime. parse (node / " occurredAt" ) in
115
- let review = node / " pullRequestReview" in
116
- let state = review / " state" |> Json.Util. to_string in
117
- let url = review / " url" |> Json.Util. to_string in
118
- let pr = review / " pullRequest" in
119
- let title = pr / " title" |> Json.Util. to_string in
120
- let body = review / " body" |> Json.Util. to_string in
121
- let repo =
122
- review / " repository" / " nameWithOwner" |> Json.Util. to_string
123
- in
124
- { kind = `Review state; date; url; title; body; repo }
128
+ |> List. map (fun node ->
129
+ let * date = node / " occurredAt" |> Datetime. parse in
130
+ let review = node / " pullRequestReview" in
131
+ let * state = review / " state" |> to_string in
132
+ let * url = review / " url" |> to_string in
133
+ let pr = review / " pullRequest" in
134
+ let * title = pr / " title" |> to_string in
135
+ let * body = review / " body" |> to_string in
136
+ let * repo = review / " repository" / " nameWithOwner" |> to_string in
137
+ Ok { kind = `Review state; date; url; title; body; repo })
138
+ |> combine
125
139
126
140
let read_repos json =
127
141
Json.Util. to_list (json / " nodes" )
128
142
|> List. filter (( <> ) `Null )
129
- |> List. map @@ fun node ->
130
- let date = Datetime. parse (node / " occurredAt" ) in
131
- let repo = node / " repository" in
132
- let url = repo / " url" |> Json.Util. to_string in
133
- let repo = repo / " nameWithOwner" |> Json.Util. to_string in
134
- {
135
- kind = `New_repo ;
136
- date;
137
- url;
138
- title = " Created new repository" ;
139
- body = " " ;
140
- repo;
141
- }
143
+ |> List. map (fun node ->
144
+ let * date = node / " occurredAt" |> Datetime. parse in
145
+ let repo = node / " repository" in
146
+ let * url = repo / " url" |> to_string in
147
+ let * repo = repo / " nameWithOwner" |> to_string in
148
+ let title = " Created new repository" in
149
+ Ok { kind = `New_repo ; date; url; title; body = " " ; repo })
150
+ |> combine
142
151
143
152
let of_json ~from ~user json =
144
- let username =
145
- json / " data" / User. response_field user / " login" |> Json.Util. to_string
153
+ let * username =
154
+ json / " data" / User. response_field user / " login" |> to_string
146
155
in
147
156
let contribs =
148
157
json / " data" / User. response_field user / " contributionsCollection"
149
158
in
150
- let items =
151
- read_issues (contribs / " issueContributions" )
152
- @ read_prs (contribs / " pullRequestContributions" )
153
- @ read_reviews (contribs / " pullRequestReviewContributions" )
154
- @ read_repos (contribs / " repositoryContributions" )
159
+ let * items =
160
+ let * issues = read_issues (contribs / " issueContributions" ) in
161
+ let * prs = read_prs (contribs / " pullRequestContributions" ) in
162
+ let * reviews = read_reviews (contribs / " pullRequestReviewContributions" ) in
163
+ let * repos = read_repos (contribs / " repositoryContributions" ) in
164
+ Ok (issues @ prs @ reviews @ repos)
155
165
in
156
166
let activity =
157
167
(* GitHub seems to ignore the time part, so do the filtering here. *)
@@ -165,7 +175,7 @@ let of_json ~from ~user json =
165
175
Repo_map. add item.repo (item :: items) acc)
166
176
Repo_map. empty
167
177
in
168
- { username; activity }
178
+ Ok { username; activity }
169
179
170
180
let id url =
171
181
match Astring.String. cut ~sep: " /" ~rev: true url with
0 commit comments