src/Pure/Tools/ci_api.scala
changeset 63646 74604a9fc4c8
child 63992 3aa9837d05c7
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/Pure/Tools/ci_api.scala	Tue Aug 09 23:26:51 2016 +0200
     1.3 @@ -0,0 +1,74 @@
     1.4 +/*  Title:      Pure/Tools/build.scala
     1.5 +    Author:     Makarius
     1.6 +
     1.7 +API for Isabelle Jenkins continuous integration services.
     1.8 +*/
     1.9 +
    1.10 +package isabelle
    1.11 +
    1.12 +
    1.13 +import java.net.URL
    1.14 +
    1.15 +import scala.util.matching.Regex
    1.16 +
    1.17 +
    1.18 +object CI_API
    1.19 +{
    1.20 +  /* CI service */
    1.21 +
    1.22 +  def root(): String =
    1.23 +    Isabelle_System.getenv_strict("ISABELLE_JENKINS_ROOT")
    1.24 +
    1.25 +  def invoke(url: String, args: String*): Any =
    1.26 +  {
    1.27 +    val req = url + "/api/json?" + args.mkString("&")
    1.28 +    val result = Url.read(req)
    1.29 +    try { JSON.parse(result) }
    1.30 +    catch { case ERROR(_) => error("Malformed JSON from " + quote(req)) }
    1.31 +  }
    1.32 +
    1.33 +
    1.34 +  /* build jobs */
    1.35 +
    1.36 +  def build_jobs(): List[String] =
    1.37 +    for {
    1.38 +      job <- JSON.array(invoke(root()), "jobs")
    1.39 +      _class <- JSON.string(job, "_class")
    1.40 +      if _class == "hudson.model.FreeStyleProject"
    1.41 +      name <- JSON.string(job, "name")
    1.42 +    } yield name
    1.43 +
    1.44 +  sealed case class Build_Info(
    1.45 +    job_name: String,
    1.46 +    timestamp: Long,
    1.47 +    output: URL,
    1.48 +    session_logs: List[(String, URL)])
    1.49 +  {
    1.50 +    def read_output(): String = Url.read(output)
    1.51 +    def read_log(full_stats: Boolean, name: String): Build.Log_Info =
    1.52 +      Build.parse_log(full_stats,
    1.53 +        session_logs.collectFirst({ case (a, b) if a == name => Url.read_gzip(b) }) getOrElse "")
    1.54 +  }
    1.55 +
    1.56 +  def build_job_builds(job_name: String): List[Build_Info] =
    1.57 +  {
    1.58 +    val Log_Session = new Regex("""^.*/log/([^/]+)\.gz$""")
    1.59 +
    1.60 +    for {
    1.61 +      build <- JSON.array(
    1.62 +        invoke(root() + "/job/" + job_name, "tree=builds[number,timestamp,artifacts[*]]"), "builds")
    1.63 +      number <- JSON.int(build, "number")
    1.64 +      timestamp <- JSON.long(build, "timestamp")
    1.65 +    } yield {
    1.66 +      val job_prefix = root() + "/job/" + job_name + "/" + number
    1.67 +      val output = Url(job_prefix + "/consoleText")
    1.68 +      val session_logs =
    1.69 +        for {
    1.70 +          artifact <- JSON.array(build, "artifacts")
    1.71 +          log_path <- JSON.string(artifact, "relativePath")
    1.72 +          session <- (log_path match { case Log_Session(name) => Some(name) case _ => None })
    1.73 +        } yield (session -> Url(job_prefix + "/artifact/" + log_path))
    1.74 +      Build_Info(job_name, timestamp, output, session_logs)
    1.75 +    }
    1.76 +  }
    1.77 +}