blob: 4b4706618b7d8fa89bebb7d420a19fd90010b1f0 [file] [log] [blame]
#! /usr/bin/python
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or
# See the License for the specific language governing permissions
# and limitations under the License.
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
# Copyright 2007, 2010 Richard Lowe
# Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
# Check delta comments:
# - Have the correct form.
# - Have a synopsis matching that of the bug
# - Appear only once.
import re, sys
from onbld.Checks.DbLookups import BugDB
bugre = re.compile(r'^(\d{2,7}) (.*)$')
def isBug(comment):
return bugre.match(comment)
def comchk(comments, check_db=True, output=sys.stderr):
'''Validate checkin comments against ON standards.
Comments must be a list of one-line comments, with no trailing
If check_db is True (the default), validate bug synopses against the
Error messages intended for the user are written to output,
which defaults to stderr
bugnospcre = re.compile(r'^(\d{2,7})([^ ].*)')
ignorere = re.compile(r'^(' +
r'Portions contributed by|' +
r'Contributed by|' +
r'Reviewed[ -]by|' +
r'Approved[ -]by|' +
r'back[ -]?out)' +
r'[: ]')
errors = { 'bugnospc': [],
'mutant': [],
'dup': [],
'nomatch': [],
'nonexistent': [] }
bugs = {}
ret = 0
blanks = False
for com in comments:
# Our input must be newline-free, comments are line-wise.
if com.find('\n') != -1:
raise ValueError("newline in comment '%s'" % com)
# Ignore valid comments we can't check
if not com or com.isspace():
blanks = True
match =
if match:
if not in bugs:
bugs[] = []
# Bugs missing a space after the ID are still bugs
# for the purposes of the duplicate ID and synopsis
# checks.
match =
if match:
if not in bugs:
bugs[] = []
# Anything else is bogus
if len(bugs) > 0 and check_db:
bugdb = BugDB()
results = bugdb.lookup(list(bugs.keys()))
for crid, insts in bugs.items():
if len(insts) > 1:
if not check_db:
if crid not in results:
# For each synopsis, compare the real synopsis with
# that in the comments, allowing for possible '(fix
# stuff)'-like trailing text
for entered in insts:
synopsis = results[crid]["synopsis"]
if not'^' + re.escape(synopsis) +
r'( \([^)]+\))?$', entered):
errors['nomatch'].append([crid, synopsis,
if blanks:
output.write("WARNING: Blank line(s) in comments\n")
ret = 1
if errors['dup']:
ret = 1
output.write("These IDs appear more than once in your "
for err in errors['dup']:
output.write(" %s\n" % err)
if errors['bugnospc']:
ret = 1
output.write("These bugs are missing a single space following "
"the ID:\n")
for com in errors['bugnospc']:
output.write(" %s\n" % com)
if errors['mutant']:
ret = 1
output.write("These comments are not valid bugs:\n")
for com in errors['mutant']:
output.write(" %s\n" % com)
if errors['nonexistent']:
ret = 1
output.write("These bugs were not found in the databases:\n")
for id in errors['nonexistent']:
output.write(" %s\n" % id)
if errors['nomatch']:
ret = 1
output.write("These bug synopses don't match "
"the database entries:\n")
for err in errors['nomatch']:
output.write("Synopsis of %s is wrong:\n" % err[0])
output.write(" should be: '%s'\n" % err[1])
output.write(" is: '%s'\n" % err[2])
return ret