hghooks/mozhghooks/check/prevent_webidl_changes.py (122 lines of code) (raw):
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
import collections
from mercurial.node import short
from mercurial.utils import stringutil
from mozautomation.commitparser import (
parse_requal_reviewers,
is_backout,
)
from mozhg.util import repo_owner
from ..checks import (
PreTxnChangegroupCheck,
print_banner,
print_notice,
)
DOM_PEERS = [
{
"name": b"Andrea Marchesini",
"nick": [b"baku"],
"email": [b"amarchesini@mozilla.com"],
},
{"name": b"Andreas Farre", "nick": [b"farre"], "email": [b"afarre@mozilla.com"]},
{
"name": b"Andrew McCreight",
"nick": [b"mccr8"],
"email": [b"continuation@gmail.com"],
},
{
"name": b"Andrew Sutherland",
"nick": [b"asuth"],
"email": [b"bugmail@asutherland.org", b"asuth@mozilla.com"],
},
{"name": b"Bobby Holley", "nick": [b"bholley"], "email": [b"bholley@mozilla.com"]},
{"name": b"Edgar Chen", "nick": [b"edgar"], "email": [b"echen@mozilla.com"]},
{"name": b"Emilio Cobos", "nick": [b"emilio"], "email": [b"emilio@crisal.io"]},
{
"name": b"Henri Sivonen",
"nick": [b"hsivonen"],
"email": [b"hsivonen@hsivonen.fi"],
},
{
"name": b"Kagami Rosylight",
"nick": [b"saschanaz"],
"email": [b"krosylight@mozilla.com"],
},
{
"name": b"Nika Layzell",
"nick": [b"mystor", b"nika"],
"email": [b"nika@thelayzells.com"],
},
{
"name": b"Olli Pettay",
"nick": [b"smaug"],
"email": [b"olli.pettay@helsinki.fi", b"bugs@pettay.fi"],
},
{"name": b"Sean Feng", "nick": [b"sefeng"], "email": [b"sefeng@mozilla.com"]},
]
# The root directory for WebIDL files which contain only ChromeOnly
# interfaces, and do not require DOM peer review.
CHROME_WEBIDL_ROOT = b"dom/chrome-webidl/"
# Bug 1941617 - typescript config doesn't require DOM peer review
TS_WEBIDL_ROOT = b"tools/ts/config/"
MISSING_REVIEW = b"""
Changeset %s alters WebIDL file(s) without DOM peer review:
%s
Please, request review from the #webidl reviewer group or either:
"""
for p in DOM_PEERS:
MISSING_REVIEW += b" - %s (:%s)\n" % (p["name"], p["nick"][0])
CHROME_ONLY = b"""
Not enforcing DOM peer review for WebIDL files within the chrome WebIDL root.
Please make sure changes do not contain any web-visible binding definitions.
"""
class WebIDLCheck(PreTxnChangegroupCheck):
"""Prevents WebIDL file modifications without appropriate review."""
@property
def name(self):
return b"webidl_check"
def relevant(self):
return (
self.repo_metadata[b"firefox_releasing"]
and repo_owner(self.repo) != b"scm_allow_direct_push"
)
def pre(self, node):
# Accept the entire push for code uplifts
self.is_uplift = b"a=release" in self.repo[b"tip"].description().lower()
def check(self, ctx):
if self.is_uplift:
return True
# Ignore merge changesets
if len(ctx.parents()) > 1:
return True
# Ignore backouts
if is_backout(ctx.description()):
return True
# Ignore changes that don't touch .webidl files
webidl_files = [f for f in ctx.files() if f.endswith(b".webidl")]
if not webidl_files:
return True
# Allow patches authored by peers
if is_peer_email(stringutil.email(ctx.user())):
return True
# Categorise files
file_counts = collections.Counter()
review_required_files = []
for f in webidl_files:
file_counts["total"] += 1
if f.startswith(CHROME_WEBIDL_ROOT):
file_counts["chrome"] += 1
elif f.startswith(TS_WEBIDL_ROOT):
file_counts["ts"] += 1
else:
review_required_files.append(f)
# Allow chrome-only changes
if not review_required_files:
if file_counts["chrome"]:
print_notice(self.ui, CHROME_ONLY)
return True
# Allow if reviewed by any peer
requal = list(parse_requal_reviewers(ctx.description()))
if any(is_peer_nick(nick) for nick in requal):
return True
# Reject
print_banner(
self.ui,
b"error",
MISSING_REVIEW % (short(ctx.node()), b"\n".join(review_required_files)),
)
return False
def post_check(self):
return True
def is_peer_email(email):
email = email.lower()
for peer in DOM_PEERS:
if email in peer["email"]:
return True
return False
def is_peer_nick(nick):
nick = nick.lower()
for peer in DOM_PEERS:
if nick in peer["nick"]:
return True
return False