check_author.py (3703B)
1 #!/usr/bin/env python3 2 # Copyright (c) the JPEG XL Project Authors. All rights reserved. 3 # 4 # Use of this source code is governed by a BSD-style 5 # license that can be found in the LICENSE file. 6 7 8 """check_author.py: Check that a given author is listed in the AUTHORS file.""" 9 10 import argparse 11 import fnmatch 12 import os 13 import re 14 import sys 15 16 17 def IsAuthorInFile(email, name, filename): 18 """Return whether we find the name/email in the authors filename""" 19 # Organization emails have emails listed as <*@domain.com>. This matches those 20 # patterns. 21 email_pattern_regex = re.compile(r'.*<([^>]+)>') 22 23 with open(filename, 'r') as f: 24 for line in f: 25 line = line.strip() 26 if line.startswith('#') or not line: 27 continue 28 # Exact match for a line without an email is OK. 29 if line == name: 30 return True 31 # Exact email address match is OK, even if the name is different. 32 if fnmatch.fnmatch(line, '* <%s>' % email): 33 print( 34 "User %s <%s> matched with different name %s" % (name, email, line), 35 file=sys.stderr) 36 return True 37 # Organizations often have *@domain.com email patterns which don't match 38 # the name. 39 if '*' in line: 40 m = email_pattern_regex.match(line) 41 if m and fnmatch.fnmatch(email, m.group(1)): 42 print("User %s <%s> matched pattern %s" % (name, email, line), 43 file=sys.stderr) 44 return True 45 return False 46 47 def IndividualsInAlphabeticOrder(filename): 48 """Checks if the names are in alphabetic order""" 49 with open(filename, 'r') as f: 50 lines = f.readlines() 51 individual_header = '# Individuals:\n' 52 if individual_header in lines: 53 individual_authors = lines[lines.index(individual_header) + 1:] 54 sorted_authors = sorted(individual_authors, key=str.casefold) 55 if sorted_authors == individual_authors: 56 print("Individual authors are sorted alphabetically.") 57 return True 58 else: 59 print("Individual authors are not sorted alphabetically." 60 " The expected order is:") 61 print(''.join(sorted_authors)) 62 return False 63 else: 64 print("Cannot find line '# Individuals:' in file.") 65 return False 66 67 68 def CheckAuthor(args): 69 authors_path = os.path.join(args.source_dir, 'AUTHORS') 70 author_in_file = IsAuthorInFile( 71 args.email, args.name, authors_path) 72 if not author_in_file: 73 print("User %s <%s> not found, please add yourself to the AUTHORS file" % ( 74 args.name, args.email), 75 file=sys.stderr) 76 print("Hint: to override author in PR run:\n" 77 " git commit --amend --author=\"Your Name <ldap@corp.com>\" --no-edit") 78 79 sorted_alphabetically = IndividualsInAlphabeticOrder(authors_path) 80 if not sorted_alphabetically: 81 print("Authors not in alphabetical order, please sort them.", file=sys.stderr) 82 if not author_in_file or not sorted_alphabetically: 83 if not args.dry_run: 84 sys.exit(1) 85 86 87 def main(): 88 parser = argparse.ArgumentParser(description=__doc__) 89 parser.add_argument('email', type=str, 90 help='email of the commit author to check') 91 parser.add_argument('name', type=str, 92 help='name of the commit author to check') 93 parser.add_argument( 94 '--source-dir', 95 default=os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))), 96 help='path to the source directory where the AUTHORS file is located') 97 parser.add_argument('--dry-run', default=False, action='store_true', 98 help='Don\'t return an exit code in case of failure') 99 args = parser.parse_args() 100 CheckAuthor(args) 101 102 103 if __name__ == '__main__': 104 main()