diff options
author | Chris Rebert <code@rebertia.com> | 2014-10-10 05:45:54 +0400 |
---|---|---|
committer | Chris Rebert <code@rebertia.com> | 2014-10-10 05:48:16 +0400 |
commit | ae4710d99f95fe0d5920a5adc942679bba5b7f27 (patch) | |
tree | afff8461164d7aaeba7e84b96fd892d4e5d79785 /src | |
parent | a6fd8eaedbbc5d8ace8bb7a32c093e9be643ba8b (diff) |
have Rorschach try to close bad PRs
Diffstat (limited to 'src')
11 files changed, 170 insertions, 85 deletions
diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf new file mode 100644 index 0000000..bcc55f0 --- /dev/null +++ b/src/main/resources/application.conf @@ -0,0 +1,27 @@ +akka { + loglevel = INFO +} + +spray.can { + server { + request-timeout = 5 s + } + + client { + user-agent-header = "Rorschach/0.1 (https://github.com/cvrebert/rorschach)" + request-timeout = 20 s + idle-timeout = 15 s + } + host-connector { + max-connections = 5 + max-retries = 3 + max-redirects = 3 + } +} + +rorschach { + default-port = 9090 + username = throwaway9475947 + password = XXXXXXXX + web-hook-secret-key = abcdefg +} diff --git a/src/main/scala/com/getbootstrap/rorschach/github/GitHubIssueCommenter.scala b/src/main/scala/com/getbootstrap/rorschach/github/GitHubIssueCommenter.scala deleted file mode 100644 index 368c96a..0000000 --- a/src/main/scala/com/getbootstrap/rorschach/github/GitHubIssueCommenter.scala +++ /dev/null @@ -1,40 +0,0 @@ -package com.getbootstrap.rorschach.github - -import scala.util.{Try,Failure,Success} -import org.eclipse.egit.github.core.service.IssueService -import org.eclipse.egit.github.core.RepositoryId -import com.getbootstrap.rorschach.server.Settings - - -class GitHubIssueCommenter extends GitHubActorWithLogging { - // val settings = Settings(context.system) - - private def tryToCommentOn(repo: RepositoryId, issue: IssueNumber, commentMarkdown: String) = { - val issueService = new IssueService(gitHubClient) - Try { issueService.createComment(repo, issue.number, commentMarkdown) } - } - - override def receive = { - case PullRequestFeedback(prNum, requester, messages) => { - val username = requester.getLogin - val messagesMarkdown = messages.map{ "* " + _ }.mkString("\n") - val commentMarkdown = s""" - |Hi @${username}! - | - |Thanks for wanting to contribute to Bootstrap by sending this pull request. - |Unfortunately, your pull request seems to have some problems: - |${messagesMarkdown} - | - |You'll need to **fix these mistakes** and revise your pull request before we can proceed further. - |Thanks! - | - |(*Please note that this is a fully automated comment.*) - """.stripMargin - - tryToCommentOn(BootstrapRepoId, prNum, commentMarkdown) match { - case Success(comment) => log.info(s"Successfully posted comment ${comment.getUrl} for ${prNum}") - case Failure(exc) => log.error(exc, s"Error posting comment for ${prNum}") - } - } - } -} diff --git a/src/main/scala/com/getbootstrap/rorschach/github/GitHubPullRequestCommenter.scala b/src/main/scala/com/getbootstrap/rorschach/github/GitHubPullRequestCommenter.scala new file mode 100644 index 0000000..77171c2 --- /dev/null +++ b/src/main/scala/com/getbootstrap/rorschach/github/GitHubPullRequestCommenter.scala @@ -0,0 +1,61 @@ +package com.getbootstrap.rorschach.github + +import scala.util.{Try,Failure,Success} +import org.eclipse.egit.github.core.service.{PullRequestService, IssueService} +import org.eclipse.egit.github.core.RepositoryId +import com.getbootstrap.rorschach.github.util.RichPullRequest +import com.getbootstrap.rorschach.server.Settings + + +class GitHubPullRequestCommenter extends GitHubActorWithLogging { + // val settings = Settings(context.system) + + private def tryToCommentOn(repo: RepositoryId, prNum: PullRequestNumber, commentMarkdown: String) = { + val issueService = new IssueService(gitHubClient) + Try { issueService.createComment(repo, prNum.number, commentMarkdown) } + } + + private def tryToClose(repo: RepositoryId, prNum: PullRequestNumber): Try[None.type] = { + val prService = new PullRequestService(gitHubClient) + val prTry = Try { prService.getPullRequest(repo, prNum.number) } match { + case fetchFail@Failure(exc) => { + log.error(exc, s"Error fetching pull request ${prNum} in order to close it") + fetchFail + } + case Success(pr) => { + pr.status = Closed + Try { prService.editPullRequest(repo, pr) } + } + } + prTry.map{ x => None } + } + + override def receive = { + case PullRequestFeedback(prNum, requester, messages) => { + val username = requester.getLogin + val messagesMarkdown = messages.map{ "* " + _ }.mkString("\n") + val commentMarkdown = s""" + |Hi @${username}! + | + |Thanks for wanting to contribute to Bootstrap by sending this pull request. + |Unfortunately, your pull request seems to have some problems: + |${messagesMarkdown} + | + |You'll need to **fix these mistakes** and revise your pull request before we can proceed further. + |Thanks! + | + |(*Please note that this is a [fully automated](https://github.com/cvrebert/rorschach) comment.*) + """.stripMargin + + tryToCommentOn(BootstrapRepoId, prNum, commentMarkdown) match { + case Success(comment) => log.info(s"Successfully posted comment ${comment.getUrl} for ${prNum}") + case Failure(exc) => log.error(exc, s"Error posting comment for ${prNum}") + } + + tryToClose(BootstrapRepoId, prNum) match { + case Success(_) => log.info(s"Successfully closed ${prNum} due to failed audit(s)") + case Failure(exc) => log.error(exc, s"Error closing ${prNum}") + } + } + } +} diff --git a/src/main/scala/com/getbootstrap/rorschach/github/IssueNumber.scala b/src/main/scala/com/getbootstrap/rorschach/github/IssueNumber.scala deleted file mode 100644 index 86e7a80..0000000 --- a/src/main/scala/com/getbootstrap/rorschach/github/IssueNumber.scala +++ /dev/null @@ -1,15 +0,0 @@ -package com.getbootstrap.rorschach.github - -object IssueNumber { - def apply(number: Int): Option[IssueNumber] = { - if (number > 0) { - Some(new IssueNumber(number)) - } - else { - None - } - } -} -class IssueNumber private(val number: Int) extends AnyVal { - override def toString = s"IssueNumber(${number})" -} diff --git a/src/main/scala/com/getbootstrap/rorschach/github/PullRequestFeedback.scala b/src/main/scala/com/getbootstrap/rorschach/github/PullRequestFeedback.scala index a5dc57e..511fe48 100644 --- a/src/main/scala/com/getbootstrap/rorschach/github/PullRequestFeedback.scala +++ b/src/main/scala/com/getbootstrap/rorschach/github/PullRequestFeedback.scala @@ -3,7 +3,7 @@ package com.getbootstrap.rorschach.github import org.eclipse.egit.github.core.User case class PullRequestFeedback( - prNum: IssueNumber, + prNum: PullRequestNumber, requester: User, messages: Seq[String] ) diff --git a/src/main/scala/com/getbootstrap/rorschach/github/PullRequestNumber.scala b/src/main/scala/com/getbootstrap/rorschach/github/PullRequestNumber.scala new file mode 100644 index 0000000..e05c996 --- /dev/null +++ b/src/main/scala/com/getbootstrap/rorschach/github/PullRequestNumber.scala @@ -0,0 +1,15 @@ +package com.getbootstrap.rorschach.github + +object PullRequestNumber { + def apply(number: Int): Option[PullRequestNumber] = { + if (number > 0) { + Some(new PullRequestNumber(number)) + } + else { + None + } + } +} +class PullRequestNumber private(val number: Int) extends AnyVal { + override def toString = s"IssueNumber(${number})" +} diff --git a/src/main/scala/com/getbootstrap/rorschach/github/PullRequestStatus.scala b/src/main/scala/com/getbootstrap/rorschach/github/PullRequestStatus.scala new file mode 100644 index 0000000..e136f32 --- /dev/null +++ b/src/main/scala/com/getbootstrap/rorschach/github/PullRequestStatus.scala @@ -0,0 +1,20 @@ +package com.getbootstrap.rorschach.github + +object PullRequestStatus { + def apply(value: String): PullRequestStatus = { + value match { + case Open.Value => Open + case Closed.Value => Closed + case _ => throw new IllegalArgumentException(s"Invalid pull request status string: ${value}") + } + } +} +sealed trait PullRequestStatus { + val Value: String +} +object Open extends PullRequestStatus { + override val Value = "open" +} +object Closed extends PullRequestStatus { + override val Value = "closed" +} diff --git a/src/main/scala/com/getbootstrap/rorschach/github/util/package.scala b/src/main/scala/com/getbootstrap/rorschach/github/util/package.scala new file mode 100644 index 0000000..9a2aa6e --- /dev/null +++ b/src/main/scala/com/getbootstrap/rorschach/github/util/package.scala @@ -0,0 +1,23 @@ +package com.getbootstrap.rorschach.github + +import org.eclipse.egit.github.core._ + +package object util { + implicit class RichRepository(repo: Repository) { + def repositoryId: RepositoryId = new RepositoryId(repo.getOwner.getLogin, repo.getName) + } + implicit class RichPullRequestMarker(marker: PullRequestMarker) { + def commitSha: CommitSha = new CommitSha(marker.getSha) + } + implicit class RichCommitFile(file: CommitFile) { + def status: CommitFileStatus = CommitFileStatus(file.getStatus) + } + implicit class RichPullRequest(pr: PullRequest) { + def number: PullRequestNumber = PullRequestNumber(pr.getNumber).get + + def status_= (value: PullRequestStatus) { + pr.setState(value.Value) + } + def status = PullRequestStatus(pr.getState) + } +} diff --git a/src/main/scala/com/getbootstrap/rorschach/server/Boot.scala b/src/main/scala/com/getbootstrap/rorschach/server/Boot.scala index 36923f8..a1ccbeb 100644 --- a/src/main/scala/com/getbootstrap/rorschach/server/Boot.scala +++ b/src/main/scala/com/getbootstrap/rorschach/server/Boot.scala @@ -1,5 +1,6 @@ package com.getbootstrap.rorschach.server +import scala.util.{Success,Failure} import scala.concurrent.duration._ import scala.util.Try import akka.actor.{ActorSystem, Props} @@ -8,34 +9,36 @@ import spray.can.Http import akka.pattern.ask import akka.routing.SmallestMailboxPool import akka.util.Timeout -import com.getbootstrap.rorschach.github.GitHubIssueCommenter +import com.getbootstrap.rorschach.github.GitHubPullRequestCommenter object Boot extends App { val arguments = args.toSeq - val maybePort = arguments match { + val argsPort = arguments match { case Seq(portStr: String) => { - Try{ portStr.toInt }.toOption - } - case _ => None - } - maybePort match { - case Some(port) => run(port) - case _ => { - System.err.println("USAGE: rorschach <port-number>") - System.exit(1) + Try{ portStr.toInt } match { + case Failure(_) => { + System.err.println("USAGE: lmvtfy <port-number>") + System.exit(1) + None // dead code + } + case Success(portNum) => Some(portNum) + } } + case Seq() => None } - def run(port: Int) { + run(argsPort) + + def run(port: Option[Int]) { implicit val system = ActorSystem("on-spray-can") // import actorSystem.dispatcher - val commenter = system.actorOf(SmallestMailboxPool(3).props(Props(classOf[GitHubIssueCommenter])), "gh-pr-commenter") + val commenter = system.actorOf(SmallestMailboxPool(3).props(Props(classOf[GitHubPullRequestCommenter])), "gh-pr-commenter") val prAuditorPool = system.actorOf(SmallestMailboxPool(5).props(Props(classOf[PullRequestEventHandler], commenter)), "pr-auditor-pool") val webService = system.actorOf(Props(classOf[RorschachActor], prAuditorPool), "rorschach-service") implicit val timeout = Timeout(15.seconds) - IO(Http) ? Http.Bind(webService, interface = "0.0.0.0", port = port) + IO(Http) ? Http.Bind(webService, interface = "0.0.0.0", port = port.getOrElse(settings.DefaultPort)) } } diff --git a/src/main/scala/com/getbootstrap/rorschach/server/PullRequestEventHandler.scala b/src/main/scala/com/getbootstrap/rorschach/server/PullRequestEventHandler.scala index 0d2ebed..b2ed228 100644 --- a/src/main/scala/com/getbootstrap/rorschach/server/PullRequestEventHandler.scala +++ b/src/main/scala/com/getbootstrap/rorschach/server/PullRequestEventHandler.scala @@ -5,23 +5,13 @@ import com.getbootstrap.rorschach.auditing.{BaseAndHeadBranchesAuditor, Modified import scala.collection.JavaConverters._ import scala.util.{Try,Success,Failure} import akka.actor.ActorRef -import com.getbootstrap.rorschach.github._ -import org.eclipse.egit.github.core.service.CommitService import org.eclipse.egit.github.core._ +import org.eclipse.egit.github.core.service.CommitService +import com.getbootstrap.rorschach.github._ +import com.getbootstrap.rorschach.github.util._ class PullRequestEventHandler(commenter: ActorRef) extends GitHubActorWithLogging { - implicit class RichRepository(repo: Repository) { - def repositoryId: RepositoryId = new RepositoryId(repo.getOwner.getLogin, repo.getName) - } - implicit class RichPullRequestMarker(marker: PullRequestMarker) { - def commitSha: CommitSha = new CommitSha(marker.getSha) - } - implicit class RichCommitFile(file: CommitFile) { - def status: CommitFileStatus = CommitFileStatus(file.getStatus) - } - implicit class RichPullRequest(pr: PullRequest) { - def issueNumber: IssueNumber = IssueNumber(pr.getNumber).get - } + private def modifiedFilesFor(repoId: RepositoryId, base: CommitSha, head: CommitSha) = { val commitService = new CommitService(gitHubClient) @@ -54,7 +44,7 @@ class PullRequestEventHandler(commenter: ActorRef) extends GitHubActorWithLoggin val allMessages = fileMessages ++ branchMessages if (allMessages.nonEmpty) { - commenter ! PullRequestFeedback(pr.issueNumber, pr.getUser, allMessages) + commenter ! PullRequestFeedback(pr.number, pr.getUser, allMessages) } } case otherRepo => log.error(s"Received event from GitHub about irrelevant repository: ${otherRepo}") diff --git a/src/main/scala/com/getbootstrap/rorschach/server/Settings.scala b/src/main/scala/com/getbootstrap/rorschach/server/Settings.scala index 1b47482..20788d8 100644 --- a/src/main/scala/com/getbootstrap/rorschach/server/Settings.scala +++ b/src/main/scala/com/getbootstrap/rorschach/server/Settings.scala @@ -13,6 +13,7 @@ class SettingsImpl(config: Config) extends Extension { val BotUsername: String = config.getString("rorschach.username") val BotPassword: String = config.getString("rorschach.password") val WebHookSecretKey: ByteString = ByteString(config.getString("rorschach.web-hook-secret-key").utf8Bytes) + val DefaultPort: Int = config.getInt("rorschach.default-port") } object Settings extends ExtensionId[SettingsImpl] with ExtensionIdProvider { override def lookup() = Settings |