All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.server.handler.LintHandler.scala Maven / Gradle / Ivy

The newest version!
package com.twitter.server.handler

import com.twitter.finagle.Service
import com.twitter.finagle.http.{Response, Request}
import com.twitter.io.Buf
import com.twitter.server.handler.LintHandler.LintView
import com.twitter.server.util.HttpUtils._
import com.twitter.server.util.JsonConverter
import com.twitter.util.Future
import com.twitter.util.lint.{Issue, Rule, GlobalRules}

/**
 * UI for running the globally registered lint [[Rule Rules]].
 */
class LintHandler extends Service[Request, Response] {

  def apply(req: Request): Future[Response] =
    if (expectsHtml(req)) htmlResponse(req) else jsonResponse(req)

  private[this] def htmlResponse(req: Request): Future[Response] = {
    // first, run the rules.
    val rules = GlobalRules.get.iterable.toSeq
    val (oks, nots) = rules
      .map(rule => rule -> rule())
      .partition { case (_, res) => res.isEmpty }

    // render the ui and respond
    val view = new LintView(rules, oks.map(o => o._1), nots)
    val rendered = view()
    newResponse(
      // note: contentType must be explicit here because of `IndexView.isFragment`
      contentType = "text/html;charset=UTF-8",
      content = Buf.Utf8(rendered)
    )
  }

  private[this] def jsonString(s: String): String =
    s.replace("\n", " ").trim

  private[this] def jsonRule(rule: Rule): Map[String, Any] =
    Map(
      "category" -> rule.category.toString,
      "id" -> rule.id,
      "name" -> rule.name,
      "description" -> jsonString(rule.description)
    )

  private[this] def jsonResponse(req: Request): Future[Response] = {
    val rules = GlobalRules.get.iterable.toSeq
    val jsonMap = jsonMapFromRules(rules)
    newOk(JsonConverter.writeToString(jsonMap))
  }

  /** exposed for testing */
  private[handler] def jsonMapFromRules(rules: Seq[Rule]): Map[String, Any] = {
    val (oks, nots) = rules
      .map(rule => rule -> rule())
      .partition { case (_, res) => res.isEmpty }

    val numIssues = nots.foldLeft(0) { case (total, (_, issues)) =>
      total + issues.size
    }

    val failureIssues = nots.map { case (rule, issues) =>
      jsonRule(rule) ++
        Map("issues" -> issues.map(i => jsonString(i.details)))
    }

    val okRules = oks.map { case (rule, _) =>
      rule.id
    }

    Map("lint_results" ->
      Map(
        "metadata" ->
          Map(
            "num_rules_run" -> rules.size,
            "num_rules_ok" -> oks.size,
            "num_rules_failed" -> nots.size,
            "num_issues_found" -> numIssues
          ),
        "failed_rules" -> failureIssues,
        "ok_rules" -> okRules
      )
    )
  }

}

private object LintHandler {

  /**
   * Web UI for [[LintHandler]].
   */
  class LintView(
      rules: Seq[Rule],
      oks: Seq[Rule],
      nots: Seq[(Rule, Seq[Issue])])
  {

    def apply(): String = {
      scriptHeader +
        summary +
        failedRows +
        okRows
    }

    private def scriptHeader: String =
      """
"""

    private def escapeHtml(s: String): String =
      xml.Utility.escape(s)

    def summary: String = {
      val numIssues = nots.foldLeft(0) { case (total, (_, issues)) =>
        total + issues.size
      }

      s"""
Summary
Number of rules run ${rules.size}
Number of rules ok ${oks.size}
Number of rules failed ${nots.size}
Number of issues found $numIssues
""" } def nameWithDescription(rule: Rule): String = { val desc = escapeHtml(rule.description) s""" ${escapeHtml(rule.name)} """ } def failedRow(rule: Rule, issue: Issue): String = { val desc = escapeHtml(rule.description) s""" ${nameWithDescription(rule)} ${escapeHtml(issue.details)} """ } def failedRows: String = { val data = nots.map { case (rule, issues) => issues.map { issue => failedRow(rule, issue) }.mkString("") }.mkString("") s"""
Failed rules
$data
Name Issue
""" } def okRows: String = { val data = oks.map { rule => s""" ${nameWithDescription(rule)} """ }.mkString("") s"""
Ok rules
$data
Name
""" } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy