17078Smjnelson#! /usr/bin/python 27078Smjnelson# 37078Smjnelson# CDDL HEADER START 47078Smjnelson# 57078Smjnelson# The contents of this file are subject to the terms of the 67078Smjnelson# Common Development and Distribution License (the "License"). 77078Smjnelson# You may not use this file except in compliance with the License. 87078Smjnelson# 97078Smjnelson# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107078Smjnelson# or http://www.opensolaris.org/os/licensing. 117078Smjnelson# See the License for the specific language governing permissions 127078Smjnelson# and limitations under the License. 137078Smjnelson# 147078Smjnelson# When distributing Covered Code, include this CDDL HEADER in each 157078Smjnelson# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167078Smjnelson# If applicable, add the following below this CDDL HEADER, with the 177078Smjnelson# fields enclosed by brackets "[]" replaced with your own identifying 187078Smjnelson# information: Portions Copyright [yyyy] [name of copyright owner] 197078Smjnelson# 207078Smjnelson# CDDL HEADER END 217078Smjnelson# 227078Smjnelson 237078Smjnelson# 247078Smjnelson# Copyright 2008 Sun Microsystems, Inc. All rights reserved. 257078Smjnelson# Use is subject to license terms. 267078Smjnelson# 277078Smjnelson 287078Smjnelson# 297078Smjnelson# Check delta comments: 307078Smjnelson# - Have the correct form. 317078Smjnelson# - Have a synopsis matching that of the CR or ARC case. 327078Smjnelson# - Appear only once. 337078Smjnelson# 347078Smjnelson 357078Smjnelsonimport re, sys 367078Smjnelsonfrom onbld.Checks.DbLookups import BugDB, ARC 377078Smjnelson 387078Smjnelsonarcre = re.compile(r'^([A-Z][A-Z]*ARC[/ \t][12]\d{3}/\d{3}) (.*)$') 397078Smjnelsonbugre = re.compile(r'^(\d{7}) (.*)$') 407711Srichlowe@richlowe.net 417078Smjnelsondef isARC(comment): 427078Smjnelson return arcre.match(comment) 437078Smjnelson 447078Smjnelsondef isBug(comment): 457078Smjnelson return bugre.match(comment) 467078Smjnelson 477078Smjnelson# 487078Smjnelson# Translate any acceptable case number format into "<ARC> <YEAR>/<NUM>" 497078Smjnelson# format. 507078Smjnelson# 517078Smjnelsondef normalize_arc(caseid): 527078Smjnelson return re.sub(r'^([A-Z][A-Z]*ARC)[/ \t]', '\\1 ', caseid) 537078Smjnelson 547078Smjnelsondef comchk(comments, check_db=True, output=sys.stderr): 55*8042SJohn.Sonnenschein@Sun.COM '''Validate checkin comments against ON standards. 567711Srichlowe@richlowe.net 57*8042SJohn.Sonnenschein@Sun.COM Comments must be a list of one-line comments, with no trailing 58*8042SJohn.Sonnenschein@Sun.COM newline. 59*8042SJohn.Sonnenschein@Sun.COM 60*8042SJohn.Sonnenschein@Sun.COM If check_db is True (the default), validate CR and ARC 61*8042SJohn.Sonnenschein@Sun.COM synopses against the databases. 627711Srichlowe@richlowe.net 63*8042SJohn.Sonnenschein@Sun.COM Error messages intended for the user are written to output, 64*8042SJohn.Sonnenschein@Sun.COM which defaults to stderr 65*8042SJohn.Sonnenschein@Sun.COM ''' 667078Smjnelson bugnospcre = re.compile(r'^(\d{7})([^ ].*)') 677321SJohn.Beck@Sun.COM ignorere = re.compile(r'^(Portions contributed by |Contributed by |back[ -]?out )') 687078Smjnelson 697078Smjnelson errors = { 'bugnospc': [], 707078Smjnelson 'mutant': [], 717078Smjnelson 'dup': [], 727078Smjnelson 'nomatch': [], 737078Smjnelson 'nonexistent': [] } 747078Smjnelson bugs = {} 757078Smjnelson arcs = {} 767711Srichlowe@richlowe.net ret = 0 777711Srichlowe@richlowe.net blanks = False 787078Smjnelson 797078Smjnelson for com in comments: 80*8042SJohn.Sonnenschein@Sun.COM # Our input must be newline-free, comments are line-wise. 81*8042SJohn.Sonnenschein@Sun.COM if com.find('\n') != -1: 82*8042SJohn.Sonnenschein@Sun.COM raise ValueError("newline in comment '%s'" % com) 83*8042SJohn.Sonnenschein@Sun.COM 847078Smjnelson # Ignore valid comments we can't check 857078Smjnelson if ignorere.search(com): 867078Smjnelson continue 877078Smjnelson 887078Smjnelson if not com or com.isspace(): 897711Srichlowe@richlowe.net blanks = True 907078Smjnelson continue 917078Smjnelson 927078Smjnelson match = bugre.search(com) 937078Smjnelson if match: 947078Smjnelson if match.group(1) not in bugs: 957078Smjnelson bugs[match.group(1)] = [] 967078Smjnelson bugs[match.group(1)].append(match.group(2)) 977078Smjnelson continue 987078Smjnelson 997078Smjnelson # 1007078Smjnelson # Bugs missing a space after the ID are still bugs 1017078Smjnelson # for the purposes of the duplicate ID and synopsis 1027078Smjnelson # checks. 1037078Smjnelson # 1047078Smjnelson match = bugnospcre.search(com) 1057078Smjnelson if match: 1067078Smjnelson if match.group(1) not in bugs: 1077078Smjnelson bugs[match.group(1)] = [] 1087078Smjnelson bugs[match.group(1)].append(match.group(2)) 1097078Smjnelson errors['bugnospc'].append(com) 1107078Smjnelson continue 1117078Smjnelson 1127078Smjnelson # ARC case 1137078Smjnelson match = arcre.search(com) 1147078Smjnelson if match: 115*8042SJohn.Sonnenschein@Sun.COM arc, case = re.split('[/ \t]', match.group(1), 1) 116*8042SJohn.Sonnenschein@Sun.COM arcs.setdefault((arc, case), []).append(match.group(2)) 1177078Smjnelson continue 1187078Smjnelson 1197078Smjnelson # Anything else is bogus 1207078Smjnelson errors['mutant'].append(com) 1217078Smjnelson 1227078Smjnelson if len(bugs) > 0 and check_db: 1237078Smjnelson bugdb = BugDB() 1247078Smjnelson results = bugdb.lookup(bugs.keys()) 1257078Smjnelson 1267078Smjnelson for crid, insts in bugs.iteritems(): 1277078Smjnelson if len(insts) > 1: 1287078Smjnelson errors['dup'].append(crid) 1297078Smjnelson 1307078Smjnelson if not check_db: 1317078Smjnelson continue 1327078Smjnelson 1337078Smjnelson if crid not in results: 1347078Smjnelson errors['nonexistent'].append(crid) 1357078Smjnelson continue 1367078Smjnelson 1377711Srichlowe@richlowe.net # 1387711Srichlowe@richlowe.net # For each synopsis, compare the real synopsis with 1397711Srichlowe@richlowe.net # that in the comments, allowing for possible '(fix 1407711Srichlowe@richlowe.net # stuff)'-like trailing text 1417711Srichlowe@richlowe.net # 1427078Smjnelson for entered in insts: 1437078Smjnelson synopsis = results[crid]["synopsis"] 1447711Srichlowe@richlowe.net if not re.search(r'^' + re.escape(synopsis) + 145*8042SJohn.Sonnenschein@Sun.COM r'( \([^)]+\))?$', entered): 1467078Smjnelson errors['nomatch'].append([crid, synopsis, 147*8042SJohn.Sonnenschein@Sun.COM entered]) 148*8042SJohn.Sonnenschein@Sun.COM 149*8042SJohn.Sonnenschein@Sun.COM if check_db: 150*8042SJohn.Sonnenschein@Sun.COM valid = ARC(arcs.keys()) 1517078Smjnelson 1527078Smjnelson for case, insts in arcs.iteritems(): 1537078Smjnelson if len(insts) > 1: 154*8042SJohn.Sonnenschein@Sun.COM errors['dup'].append(' '.join(case)) 1557078Smjnelson 156*8042SJohn.Sonnenschein@Sun.COM if not check_db: 1577078Smjnelson continue 158*8042SJohn.Sonnenschein@Sun.COM 159*8042SJohn.Sonnenschein@Sun.COM if not case in valid: 160*8042SJohn.Sonnenschein@Sun.COM errors['nonexistent'].append(' '.join(case)) 161*8042SJohn.Sonnenschein@Sun.COM continue 1627078Smjnelson # 1637078Smjnelson # The opensolaris.org ARC interfaces only give us the 1647078Smjnelson # first 40 characters of the case name, so we must limit 1657078Smjnelson # our checking similarly. 1667078Smjnelson # 1677078Smjnelson # We first try a direct match between the actual case name 1687078Smjnelson # and the entered comment. If that fails we remove a possible 1697078Smjnelson # trailing (fix nit)-type comment, and re-try. 1707078Smjnelson # 1717078Smjnelson for entered in insts: 172*8042SJohn.Sonnenschein@Sun.COM if entered[0:40] == valid[case]: 173*8042SJohn.Sonnenschein@Sun.COM break 1747078Smjnelson else: 1757711Srichlowe@richlowe.net # Try again with trailing (fix ...) removed. 1767078Smjnelson dbcom = re.sub(r' \([^)]+\)$', '', entered) 177*8042SJohn.Sonnenschein@Sun.COM if dbcom[0:40] != valid[case]: 178*8042SJohn.Sonnenschein@Sun.COM errors['nomatch'].append( 179*8042SJohn.Sonnenschein@Sun.COM [' '.join(case), valid[case], 180*8042SJohn.Sonnenschein@Sun.COM entered]) 1817078Smjnelson 1827078Smjnelson if blanks: 1837078Smjnelson output.write("WARNING: Blank line(s) in comments\n") 1847078Smjnelson ret = 1 1857078Smjnelson 1867078Smjnelson if errors['dup']: 1877078Smjnelson ret = 1 1887078Smjnelson output.write("These IDs appear more than once in your " 1897078Smjnelson "comments:\n") 1907078Smjnelson for err in errors['dup']: 1917078Smjnelson output.write(" %s\n" % err) 1927078Smjnelson 1937078Smjnelson if errors['bugnospc']: 1947078Smjnelson ret = 1 1957078Smjnelson output.write("These bugs are missing a single space following " 1967078Smjnelson "the ID:\n") 1977078Smjnelson for com in errors['bugnospc']: 1987078Smjnelson output.write(" %s\n" % com) 1997078Smjnelson 2007078Smjnelson if errors['mutant']: 2017078Smjnelson ret = 1 2027078Smjnelson output.write("These comments are neither bug nor ARC case:\n") 2037078Smjnelson for com in errors['mutant']: 2047078Smjnelson output.write(" %s\n" % com) 2057078Smjnelson 2067078Smjnelson if errors['nonexistent']: 2077078Smjnelson ret = 1 2087078Smjnelson output.write("These bugs/ARC cases were not found in the " 2097078Smjnelson "databases:\n") 2107078Smjnelson for id in errors['nonexistent']: 2117078Smjnelson output.write(" %s\n" % id) 2127078Smjnelson 2137078Smjnelson if errors['nomatch']: 2147078Smjnelson ret = 1 2157078Smjnelson output.write("These bugs/ARC case synopsis/names don't match " 2167078Smjnelson "the database entries:\n") 2177078Smjnelson for err in errors['nomatch']: 2187078Smjnelson output.write("Synopsis/name of %s is wrong:\n" % err[0]) 2197078Smjnelson output.write(" should be: '%s'\n" % err[1]) 2207078Smjnelson output.write(" is: '%s'\n" % err[2]) 2217078Smjnelson 2227078Smjnelson return ret 223