blob: bac3553e74981584f6b24eb594ca4863ead206f9 [file] [log] [blame]
#! /usr/bin/env python3
import sys
import re
import argparse
# partially copied from tools/repohooks/rh/hooks.py
TEST_MSG = """Commit message is missing a "Flag:" line. It must match one of the
following case-sensitive regex:
%s
The Flag: stanza is regex matched and should describe whether your change is behind a flag or flags.
As a CL author, you'll have a consistent place to describe the risk of the proposed change by explicitly calling out the name of the
flag in addition to its state (ENABLED|DISABLED|DEVELOPMENT|STAGING|TEAMFOOD|TRUNKFOOD|NEXTFOOD).
Some examples below:
Flag: NONE
Flag: NA
Flag: LEGACY ENABLE_ONE_SEARCH DISABLED
Flag: ACONFIG com.android.launcher3.enable_twoline_allapps DEVELOPMENT
Flag: ACONFIG com.android.launcher3.enable_twoline_allapps TRUNKFOOD
Check the git history for more examples. It's a regex matched field.
"""
def main():
"""Check the commit message for a 'Flag:' line."""
parser = argparse.ArgumentParser(
description='Check the commit message for a Flag: line.')
parser.add_argument('--msg',
metavar='msg',
type=str,
nargs='?',
default='HEAD',
help='commit message to process.')
parser.add_argument(
'--files',
metavar='files',
nargs='?',
default='',
help=
'PREUPLOAD_FILES in repo upload to determine whether the check should run for the files.')
parser.add_argument(
'--project',
metavar='project',
type=str,
nargs='?',
default='',
help=
'REPO_PATH in repo upload to determine whether the check should run for this project.')
# Parse the arguments
args = parser.parse_args()
desc = args.msg
files = args.files
project = args.project
if not should_run_path(project, files):
return
field = 'Flag'
none = '(NONE|NA|N\/A)' # NONE|NA|N/A
typeExpression = '\s*(LEGACY|ACONFIG)' # [type:LEGACY|ACONFIG]
# legacyFlagName contains only uppercase alphabets with '_' - Ex: ENABLE_ONE_SEARCH
# Aconfig Flag name format = "packageName"."flagName"
# package name - Contains only lowercase alphabets + digits + '.' - Ex: com.android.launcher3
# For now alphabets, digits, "_", "." characters are allowed in flag name and not adding stricter format check.
#common_typos_disable
flagName = '([a-zA-z0-9_.])+'
#[state:ENABLED|DISABLED|DEVELOPMENT|TEAM*(TEAMFOOD)|STAGING|TRUNK*(TRUNK_STAGING, TRUNK_FOOD)|NEXT*(NEXTFOOD)]
stateExpression = '\s*(ENABLED|DISABLED|DEVELOPMENT|TEAM[a-zA-z]*|STAGING|TRUNK[a-zA-z]*|NEXT[a-zA-z]*)'
#common_typos_enable
readableRegexMsg = '\n\tFlag: (NONE|NA)\n\tFlag: LEGACY|ACONFIG FlagName|packageName.flagName ENABLED|DISABLED|DEVELOPMENT|TEAMFOOD|STAGING|TRUNKFOOD|NEXTFOOD'
flagRegex = fr'^{field}: .*$'
check_flag = re.compile(flagRegex) #Flag:
# Ignore case for flag name format.
flagNameRegex = fr'(?i)^{field}:\s*({none}|{typeExpression}\s*{flagName}\s*{stateExpression})\s*'
check_flagName = re.compile(flagNameRegex) #Flag: <flag name format>
flagError = False
foundFlag = []
# Check for multiple "Flag:" lines and all lines should match this format
for line in desc.splitlines():
if check_flag.match(line):
if not check_flagName.match(line):
flagError = True
break
foundFlag.append(line)
# Throw error if
# 1. No "Flag:" line is found
# 2. "Flag:" doesn't follow right format.
if (not foundFlag) or (flagError):
error = TEST_MSG % (readableRegexMsg)
print(error)
sys.exit(1)
sys.exit(0)
def should_run_path(path, files):
"""Returns a boolean if this check should run with these paths.
If you want to check for a particular subdirectory under the path,
add a check here, call should_run_files and check for a specific sub dir path in should_run_files.
"""
if not path:
return False
if path == 'frameworks/base':
return should_run_files(files)
# Default case, run for all other paths which calls this script.
return True
def should_run_files(files):
"""Returns a boolean if this check should run with these files."""
if not files:
return False
if 'packages/SystemUI' in files:
return True
return False
if __name__ == '__main__':
main()