1
- package dotty .tools .bot
1
+ package dotty .tools
2
+ package bot
2
3
3
4
import org .http4s .{ Status => _ , _ }
4
5
import org .http4s .client .blaze ._
@@ -18,39 +19,26 @@ import org.http4s.dsl._
18
19
import org .http4s .util ._
19
20
20
21
import model .Github ._
21
-
22
- object TaskIsApplicative {
23
- implicit val taskIsApplicative = new cats.Applicative [Task ] {
24
- def pure [A ](x : A ): Task [A ] = Task .now(x)
25
- def ap [A , B ](ff : Task [A => B ])(fa : Task [A ]): Task [B ] =
26
- for (f <- ff; a <- fa) yield f(a)
27
- }
28
- }
29
- import TaskIsApplicative ._
22
+ import bot .util .TaskIsApplicative ._
23
+ import bot .util .HttpClientAux ._
30
24
31
25
trait PullRequestService {
32
26
33
27
/** Username for authorized admin */
34
- def user : String
28
+ def githubUser : String
35
29
36
30
/** OAuth token needed for user to create statuses */
37
- def token : String
31
+ def githubToken : String
32
+
33
+ /** OAuth token for drone, needed to cancel builds */
34
+ def droneToken : String
38
35
39
36
/** Pull Request HTTP service */
40
37
val prService = HttpService {
41
38
case request @ POST -> Root =>
42
39
request.as(jsonOf[Issue ]).flatMap(checkPullRequest)
43
40
}
44
41
45
- private [this ] lazy val authHeader = {
46
- val creds = BasicCredentials (user, token)
47
- new Authorization (creds)
48
- }
49
-
50
- private [this ] lazy val previewAcceptHeader =
51
- Accept .parse(" application/vnd.github.black-cat-preview+json" )
52
- .getOrElse(throw new Exception (" Couldn't initialize accept header" ))
53
-
54
42
private final case class CLASignature (
55
43
user : String ,
56
44
signed : Boolean ,
@@ -75,18 +63,6 @@ trait PullRequestService {
75
63
def reviewUrl (issueNbr : Int ): String =
76
64
s " $githubUrl/repos/lampepfl/dotty/pulls/ $issueNbr/reviews "
77
65
78
- def toUri (url : String ): Task [Uri ] =
79
- Uri .fromString(url).fold(Task .fail, Task .now)
80
-
81
- def getRequest (endpoint : Uri ): Task [Request ] =
82
- Request (uri = endpoint, method = Method .GET ).putHeaders(authHeader)
83
- .pure[Task ]
84
-
85
- def postRequest (endpoint : Uri ): Task [Request ] =
86
- Request (uri = endpoint, method = Method .POST )
87
- .putHeaders(authHeader, previewAcceptHeader)
88
- .pure[Task ]
89
-
90
66
def shutdownClient (client : Client ): Task [Unit ] =
91
67
client.shutdownNow().pure[Task ]
92
68
@@ -104,9 +80,7 @@ trait PullRequestService {
104
80
def checkCLA (xs : List [Commit ], httpClient : Client ): Task [List [CommitStatus ]] = {
105
81
def checkUser (user : String ): Task [Commit => CommitStatus ] = {
106
82
val claStatus = for {
107
- endpoint <- toUri(claUrl(user))
108
- claReq <- getRequest(endpoint)
109
- claRes <- httpClient.expect(claReq)(jsonOf[CLASignature ])
83
+ claRes <- httpClient.expect(get(claUrl(user)))(jsonOf[CLASignature ])
110
84
} yield { (commit : Commit ) =>
111
85
if (claRes.signed) Valid (Some (user), commit)
112
86
else Invalid (user, commit)
@@ -151,9 +125,8 @@ trait PullRequestService {
151
125
}
152
126
153
127
for {
154
- endpoint <- toUri(statusUrl(cm.commit.sha))
155
- req <- postRequest(endpoint).withBody(stat.asJson)
156
- res <- httpClient.expect(req)(jsonOf[StatusResponse ])
128
+ req <- post(statusUrl(cm.commit.sha)).withAuth(githubUser, githubToken)
129
+ res <- httpClient.expect(req.withBody(stat.asJson))(jsonOf[StatusResponse ])
157
130
} yield res
158
131
}
159
132
@@ -177,9 +150,7 @@ trait PullRequestService {
177
150
def getCommits (issueNbr : Int , httpClient : Client ): Task [List [Commit ]] = {
178
151
def makeRequest (url : String ): Task [List [Commit ]] =
179
152
for {
180
- endpoint <- toUri(url)
181
- req <- getRequest(endpoint)
182
- res <- httpClient.fetch(req){ res =>
153
+ res <- httpClient.fetch(get(url)) { res =>
183
154
val link = CaseInsensitiveString (" Link" )
184
155
val next = findNext(res.headers.get(link)).map(makeRequest).getOrElse(Task .now(Nil ))
185
156
@@ -191,12 +162,7 @@ trait PullRequestService {
191
162
}
192
163
193
164
def getComments (issueNbr : Int , httpClient : Client ): Task [List [Comment ]] =
194
- for {
195
- endpoint <- toUri(issueCommentsUrl(issueNbr))
196
- req <- getRequest(endpoint)
197
- res <- httpClient.expect(req)(jsonOf[List [Comment ]])
198
- } yield res
199
-
165
+ httpClient.expect(get(issueCommentsUrl(issueNbr)))(jsonOf[List [Comment ]])
200
166
201
167
private def usersFromInvalid (xs : List [CommitStatus ]) =
202
168
xs.collect { case Invalid (user, _) => user }
@@ -273,9 +239,8 @@ trait PullRequestService {
273
239
val review = Review .comment(body)
274
240
275
241
for {
276
- endpoint <- toUri(reviewUrl(issueNbr))
277
- req <- postRequest(endpoint).withBody(review.asJson)
278
- res <- client.expect(req)(jsonOf[ReviewResponse ])
242
+ req <- post(reviewUrl(issueNbr)).withAuth(githubUser, githubToken)
243
+ res <- client.expect(req.withBody(review.asJson))(jsonOf[ReviewResponse ])
279
244
} yield res
280
245
}
281
246
@@ -308,41 +273,22 @@ trait PullRequestService {
308
273
309
274
}
310
275
311
- def getStatus (commit : Commit , client : Client ): Task [StatusResponse ] =
312
- for {
313
- endpoint <- toUri(statusUrl(commit.sha))
314
- req <- getRequest(endpoint)
315
- res <- client.expect(req)(jsonOf[List [StatusResponse ]])
316
- } yield res.head
317
-
318
- def getStatuses (commits : List [Commit ], client : Client ): Task [List [StatusResponse ]] =
319
- Task .gatherUnordered(commits.map(getStatus(_, client)))
276
+ def getStatus (commit : Commit , client : Client ): Task [List [StatusResponse ]] =
277
+ client.expect(get(statusUrl(commit.sha)))(jsonOf[List [StatusResponse ]])
320
278
321
279
private def extractCommitSha (status : StatusResponse ): Task [String ] =
322
280
Task .delay(status.sha)
323
281
324
- def recheckCLA (statuses : List [StatusResponse ], commits : List [Commit ], client : Client ): Task [List [CommitStatus ]] = {
325
- /** Return the matching commits from the SHAs */
326
- def prunedCommits (shas : List [String ]): Task [List [Commit ]] =
327
- Task .delay(commits.filter(cm => shas.contains(cm.sha)))
328
-
329
- for {
330
- commitShas <- Task .gatherUnordered(statuses.map(extractCommitSha))
331
- commits <- prunedCommits(commitShas)
332
- statuses <- checkCLA(commits, client)
333
- } yield statuses
334
- }
335
282
336
283
def checkSynchronize (issue : Issue ): Task [Response ] = {
337
284
val httpClient = PooledHttp1Client ()
338
285
339
286
for {
340
287
commits <- getCommits(issue.number, httpClient)
341
288
statuses <- checkCLA(commits, httpClient)
342
-
343
- (_, invalid) = statuses.partition(_.isValid)
344
-
345
- _ <- sendStatuses(invalid, httpClient)
289
+ invalid = statuses.filterNot(_.isValid)
290
+ _ <- sendStatuses(invalid, httpClient)
291
+ _ <- cancelBuilds(commits.dropRight(1 ), httpClient)
346
292
347
293
// Set final commit status based on `invalid`:
348
294
_ <- {
0 commit comments