Skip to content

Commit 51f8bc1

Browse files
committed
Add ability for bot to stop outdated jobs
1 parent 01da59f commit 51f8bc1

File tree

4 files changed

+79
-2
lines changed

4 files changed

+79
-2
lines changed

bot/src/dotty/tools/bot/PullRequestService.scala

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import org.http4s.dsl._
1919
import org.http4s.util._
2020

2121
import model.Github._
22+
import model.Drone
2223
import bot.util.TaskIsApplicative._
2324
import bot.util.HttpClientAux._
2425

@@ -279,6 +280,19 @@ trait PullRequestService {
279280
private def extractCommitSha(status: StatusResponse): Task[String] =
280281
Task.delay(status.sha)
281282

283+
def cancelBuilds(commits: List[Commit])(implicit client: Client): Task[Boolean] =
284+
Task.gatherUnordered {
285+
val droneContext = "continuous-integration/drone/pr"
286+
commits.map { commit =>
287+
for {
288+
statuses <- getStatus(commit, client)
289+
cancellable = statuses.filter(status => status.state == "pending" && status.context == droneContext)
290+
runningJobs = cancellable.map(_.target_url.split('/').last.toInt)
291+
cancelled <- Task.gatherUnordered(runningJobs.map(Drone.stopBuild(_, droneToken)))
292+
} yield cancelled.foldLeft(true)(_ == _)
293+
}
294+
}
295+
.map(xs => xs.foldLeft(true)(_ == _))
282296

283297
def checkSynchronize(issue: Issue): Task[Response] = {
284298
val httpClient = PooledHttp1Client()
@@ -288,7 +302,7 @@ trait PullRequestService {
288302
statuses <- checkCLA(commits, httpClient)
289303
invalid = statuses.filterNot(_.isValid)
290304
_ <- sendStatuses(invalid, httpClient)
291-
_ <- cancelBuilds(commits.dropRight(1), httpClient)
305+
_ <- cancelBuilds(commits.dropRight(1))(httpClient)
292306

293307
// Set final commit status based on `invalid`:
294308
_ <- {
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package dotty.tools
2+
package bot
3+
package model
4+
5+
import io.circe._
6+
import io.circe.generic.auto._
7+
import io.circe.syntax._
8+
9+
import org.http4s._
10+
import org.http4s.circe._
11+
import org.http4s.client.Client
12+
13+
import scalaz.concurrent.Task
14+
import bot.util.HttpClientAux
15+
16+
object Drone {
17+
import HttpClientAux._
18+
19+
case class Build(
20+
number: Int,
21+
event: String,
22+
status: String,
23+
commit: String,
24+
author: String
25+
)
26+
27+
private[this] val baseUrl = "http://dotty-ci.epfl.ch/api"
28+
29+
private def job(id: Int) =
30+
s"$baseUrl/repos/lampepfl/dotty/builds/$id"
31+
32+
private def job(id: Int, subId: Int) =
33+
s"$baseUrl/repos/lampepfl/dotty/builds/$id/$subId"
34+
35+
def stopBuild(id: Int, token: String)(implicit client: Client): Task[Boolean] = {
36+
def resToBoolean(res: Response): Task[Boolean] = Task.now {
37+
res.status.code >= 200 && res.status.code < 400
38+
}
39+
40+
val responses = List(1, 2, 3, 4).map { subId =>
41+
client.fetch(delete(job(id, subId)).withOauth2(token))(resToBoolean)
42+
}
43+
44+
Task.gatherUnordered(responses).map(xs => xs.exists(_ == true))
45+
}
46+
47+
def startBuild(id: Int, token: String)(implicit client: Client): Task[Build] =
48+
client.expect(post(job(id)).withOauth2(token))(jsonOf[Build])
49+
}

bot/src/dotty/tools/bot/model/Github.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,13 @@ object Github {
3030
context: String = "CLA"
3131
)
3232

33-
case class StatusResponse(url: String, id: Long, state: String) {
33+
case class StatusResponse(
34+
url: String,
35+
id: Long,
36+
state: String,
37+
context: String,
38+
target_url: String
39+
) {
3440
def sha: String = url.split('/').last
3541
}
3642

bot/test/PRServiceTests.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import io.circe.syntax._
99
import io.circe.parser.decode
1010

1111
import model.Github._
12+
import model.Drone
1213
import org.http4s.client.blaze._
1314
import org.http4s.client.Client
1415
import scalaz.concurrent.Task
@@ -116,4 +117,11 @@ class PRServiceTests extends PullRequestService {
116117
s"Body of review was not as expected:\n${res.body}"
117118
)
118119
}
120+
121+
@Test def canStartAndStopBuild = {
122+
val build = withClient(implicit client => Drone.startBuild(1921, droneToken))
123+
assert(build.status == "pending" || build.status == "building")
124+
val killed = withClient(implicit client => Drone.stopBuild(1921, droneToken))
125+
assert(killed, "Couldn't kill build")
126+
}
119127
}

0 commit comments

Comments
 (0)