Commit 00d8d005 authored by Andrew Gerrand's avatar Andrew Gerrand

misc/dashboard: notify golang-dev on build failure

Fixes #1229.

R=rsc
CC=golang-dev
https://golang.org/cl/4178048
parent 6095ff38
# Copyright 2011 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
mail_from = "Go Dashboard <builder@golang.org>"
mail_submit_to = "adg@golang.org"
mail_submit_subject = "New Project Submitted"
mail_fail_to = "golang-dev@googlegroups.com"
mail_fail_subject = "%s broken by %s"
Change {{node}} broke the {{builder}} build:
http://godashboard.appspot.com/log/{{loghash}}
{{desc}}
http://code.google.com/p/go/source/detail?r={{node}}
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
# This is the server part of the continuous build system for Go. It must be run # This is the server part of the continuous build system for Go. It must be run
# by AppEngine. # by AppEngine.
from google.appengine.api import mail
from google.appengine.api import memcache from google.appengine.api import memcache
from google.appengine.runtime import DeadlineExceededError from google.appengine.runtime import DeadlineExceededError
from google.appengine.ext import db from google.appengine.ext import db
...@@ -24,6 +25,7 @@ import bz2 ...@@ -24,6 +25,7 @@ import bz2
# local imports # local imports
import key import key
import const
# The majority of our state are commit objects. One of these exists for each of # The majority of our state are commit objects. One of these exists for each of
# the commits known to the build system. Their key names are of the form # the commits known to the build system. Their key names are of the form
...@@ -47,6 +49,8 @@ class Commit(db.Model): ...@@ -47,6 +49,8 @@ class Commit(db.Model):
# successful. # successful.
builds = db.StringListProperty() builds = db.StringListProperty()
fail_notification_sent = db.BooleanProperty()
class Benchmark(db.Model): class Benchmark(db.Model):
name = db.StringProperty() name = db.StringProperty()
version = db.IntegerProperty() version = db.IntegerProperty()
...@@ -259,7 +263,7 @@ class Init(webapp.RequestHandler): ...@@ -259,7 +263,7 @@ class Init(webapp.RequestHandler):
commit.num = 0 commit.num = 0
commit.node = node commit.node = node
commit.parentnode = '' commit.parentnode = ''
commit.user = self.request.get('user') commit.user = self.request.get('user').encode('utf8')
commit.date = date commit.date = date
commit.desc = self.request.get('desc').encode('utf8') commit.desc = self.request.get('desc').encode('utf8')
...@@ -285,34 +289,37 @@ class Build(webapp.RequestHandler): ...@@ -285,34 +289,37 @@ class Build(webapp.RequestHandler):
l.put() l.put()
date = parseDate(self.request.get('date')) date = parseDate(self.request.get('date'))
user = self.request.get('user').encode('utf8')
desc = self.request.get('desc').encode('utf8')
node = self.request.get('node') node = self.request.get('node')
parent = self.request.get('parent') parenthash = self.request.get('parent')
if not validNode(node) or not validNode(parent) or date is None: if not validNode(node) or not validNode(parenthash) or date is None:
logging.error("Not valid node ('%s') or bad date (%s %s)", node, date, self.request.get('date')) logging.error("Not valid node ('%s') or bad date (%s %s)", node, date, self.request.get('date'))
self.response.set_status(500) self.response.set_status(500)
return return
q = Commit.all() q = Commit.all()
q.filter('node =', parent) q.filter('node =', parenthash)
p = q.get() parent = q.get()
if p is None: if parent is None:
logging.error('Cannot find parent %s of node %s' % (parent, node)) logging.error('Cannot find parent %s of node %s' % (parenthash, node))
self.response.set_status(404) self.response.set_status(404)
return return
parentnum, _ = p.key().name().split('-', 1) parentnum, _ = parent.key().name().split('-', 1)
nodenum = int(parentnum, 16) + 1 nodenum = int(parentnum, 16) + 1
def add_build():
key_name = '%08x-%s' % (nodenum, node) key_name = '%08x-%s' % (nodenum, node)
def add_build():
n = Commit.get_by_key_name(key_name) n = Commit.get_by_key_name(key_name)
if n is None: if n is None:
n = Commit(key_name = key_name) n = Commit(key_name = key_name)
n.num = nodenum n.num = nodenum
n.node = node n.node = node
n.parentnode = parent n.parentnode = parenthash
n.user = self.request.get('user') n.user = user
n.date = date n.date = date
n.desc = self.request.get('desc').encode('utf8') n.desc = desc
s = '%s`%s' % (builder, loghash) s = '%s`%s' % (builder, loghash)
for i, b in enumerate(n.builds): for i, b in enumerate(n.builds):
if b.split('`', 1)[0] == builder: if b.split('`', 1)[0] == builder:
...@@ -333,8 +340,39 @@ class Build(webapp.RequestHandler): ...@@ -333,8 +340,39 @@ class Build(webapp.RequestHandler):
memcache.delete(key) memcache.delete(key)
memcache.delete('hw') memcache.delete('hw')
def mark_sent():
n = Commit.get_by_key_name(key_name)
n.fail_notification_sent = True
n.put()
n = Commit.get_by_key_name(key_name)
if loghash and not failed(parent, builder) and not n.fail_notification_sent:
subject = const.mail_fail_subject % (builder, desc.split("\n")[0])
path = os.path.join(os.path.dirname(__file__), 'fail-notify.txt')
body = template.render(path, {
"builder": builder,
"node": node,
"user": user,
"desc": desc,
"loghash": loghash
})
mail.send_mail(
sender=const.mail_from,
to=const.mail_fail_to,
subject=subject,
body=body
)
db.run_in_transaction(mark_sent)
self.response.set_status(200) self.response.set_status(200)
def failed(c, builder):
for i, b in enumerate(c.builds):
p = b.split('`', 1)
if p[0] == builder:
return len(p[1]) > 0
return False
class Benchmarks(webapp.RequestHandler): class Benchmarks(webapp.RequestHandler):
def json(self): def json(self):
q = Benchmark.all() q = Benchmark.all()
......
...@@ -5,10 +5,6 @@ ...@@ -5,10 +5,6 @@
# This is the server part of the package dashboard. # This is the server part of the package dashboard.
# It must be run by App Engine. # It must be run by App Engine.
mail_to = "adg@golang.org"
mail_from = "Go Dashboard <adg@golang.org>"
mail_subject = "New Project Submitted"
from google.appengine.api import memcache from google.appengine.api import memcache
from google.appengine.runtime import DeadlineExceededError from google.appengine.runtime import DeadlineExceededError
from google.appengine.ext import db from google.appengine.ext import db
...@@ -32,6 +28,7 @@ import sets ...@@ -32,6 +28,7 @@ import sets
# local imports # local imports
import toutf8 import toutf8
import const
template.register_template_library('toutf8') template.register_template_library('toutf8')
...@@ -241,7 +238,9 @@ class ProjectPage(webapp.RequestHandler): ...@@ -241,7 +238,9 @@ class ProjectPage(webapp.RequestHandler):
path = os.path.join(os.path.dirname(__file__), 'project-notify.txt') path = os.path.join(os.path.dirname(__file__), 'project-notify.txt')
mail.send_mail( mail.send_mail(
sender=mail_from, to=mail_to, subject=mail_subject, sender=const.mail_from,
to=const.mail_submit_to,
subject=const.mail_submit_subject,
body=template.render(path, {'project': p})) body=template.render(path, {'project': p}))
self.list({"submitMsg": "Your project has been submitted."}) self.list({"submitMsg": "Your project has been submitted."})
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment