check-templates: Add fix option to tools/check_templates.

`valid_indent_html` allows for replacing the incorrectly
indented file with the correct pretty-printed version
if `--fix` is passed to `tools/lint`.

Fixes #12641.
This commit is contained in:
Wyatt Hoodes 2019-07-17 14:41:47 -10:00 committed by Tim Abbott
parent 86073588be
commit 89df6e9425
3 changed files with 29 additions and 14 deletions

View File

@ -22,8 +22,8 @@ EXCLUDED_FILES = [
'static/assets/icons/template.hbs', 'static/assets/icons/template.hbs',
] ]
def check_our_files(modified_only, all_dups, targets): def check_our_files(modified_only, all_dups, fix, targets):
# type: (bool, bool, List[str]) -> None # type: (bool, bool, bool, List[str]) -> None
by_lang = cast( by_lang = cast(
Dict[str, List[str]], Dict[str, List[str]],
lister.list_files( lister.list_files(
@ -32,11 +32,11 @@ def check_our_files(modified_only, all_dups, targets):
ftypes=['hbs', 'html'], ftypes=['hbs', 'html'],
group_by_ftype=True, exclude=EXCLUDED_FILES)) group_by_ftype=True, exclude=EXCLUDED_FILES))
check_handlebar_templates(by_lang['hbs']) check_handlebar_templates(by_lang['hbs'], fix)
check_html_templates(by_lang['html'], args.all_dups) check_html_templates(by_lang['html'], all_dups, fix)
def check_html_templates(templates, all_dups): def check_html_templates(templates, all_dups, fix):
# type: (Iterable[str], bool) -> None # type: (Iterable[str], bool, bool) -> None
# Our files with .html extensions are usually for Django, but we also # Our files with .html extensions are usually for Django, but we also
# have a few static .html files. # have a few static .html files.
# #
@ -141,11 +141,11 @@ def check_html_templates(templates, all_dups):
# TODO: Clean these files # TODO: Clean these files
for fn in templates: for fn in templates:
if fn not in IGNORE_FILES: if fn not in IGNORE_FILES:
if not validate_indent_html(fn): if not validate_indent_html(fn, fix):
sys.exit(1) sys.exit(1)
def check_handlebar_templates(templates): def check_handlebar_templates(templates, fix):
# type: (Iterable[str]) -> None # type: (Iterable[str], bool) -> None
# Check all our handlebars templates. # Check all our handlebars templates.
templates = [fn for fn in templates if fn.endswith('.hbs')] templates = [fn for fn in templates if fn.endswith('.hbs')]
@ -162,7 +162,7 @@ def check_handlebar_templates(templates):
for fn in templates: for fn in templates:
if fn in IGNORE_FILES: if fn in IGNORE_FILES:
continue continue
if not validate_indent_html(fn): if not validate_indent_html(fn, fix):
sys.exit(1) sys.exit(1)
if __name__ == '__main__': if __name__ == '__main__':
@ -173,6 +173,9 @@ if __name__ == '__main__':
parser.add_argument('--all-dups', parser.add_argument('--all-dups',
action="store_true", default=False, action="store_true", default=False,
help='Run lint tool to detect duplicate ids on ignored files as well') help='Run lint tool to detect duplicate ids on ignored files as well')
parser.add_argument('--fix',
action='store_true', default=False,
help='Automatically fix indentation problems.')
parser.add_argument('targets', nargs=argparse.REMAINDER) parser.add_argument('targets', nargs=argparse.REMAINDER)
args = parser.parse_args() args = parser.parse_args()
check_our_files(args.modified, args.all_dups, args.targets) check_our_files(args.modified, args.all_dups, args.fix, args.targets)

View File

@ -5,6 +5,9 @@ from .template_parser import (
tokenize, tokenize,
is_django_block_tag, is_django_block_tag,
) )
from zulint.printer import GREEN, ENDC
import subprocess import subprocess
def pretty_print_html(html, num_spaces=4): def pretty_print_html(html, num_spaces=4):
@ -189,13 +192,19 @@ def pretty_print_html(html, num_spaces=4):
return '\n'.join(formatted_lines) return '\n'.join(formatted_lines)
def validate_indent_html(fn): def validate_indent_html(fn, fix):
# type: (str) -> int # type: (str, bool) -> int
file = open(fn) file = open(fn)
html = file.read() html = file.read()
phtml = pretty_print_html(html) phtml = pretty_print_html(html)
file.close() file.close()
if not html.split('\n') == phtml.split('\n'): if not html.split('\n') == phtml.split('\n'):
if fix:
print(GREEN + "Automatically fixing problems..." + ENDC)
with open(fn, 'w') as f:
f.write(phtml)
# Since we successfully fixed the issues, we exit with status 0
return 0
print('Invalid Indentation detected in file: ' print('Invalid Indentation detected in file: '
'%s\nDiff for the file against expected indented file:' % (fn,), flush=True) '%s\nDiff for the file against expected indented file:' % (fn,), flush=True)
with subprocess.Popen( with subprocess.Popen(
@ -204,5 +213,7 @@ def validate_indent_html(fn):
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
universal_newlines=True) as p: universal_newlines=True) as p:
p.communicate(phtml) p.communicate(phtml)
print()
print("This problem can be fixed with the `--fix` option.")
return 0 return 0
return 1 return 1

View File

@ -72,7 +72,8 @@ def run():
"(config: tools/linter_lib/exclude.py)") "(config: tools/linter_lib/exclude.py)")
linter_config.external_linter('templates', ['tools/check-templates'], ['hbs', 'html'], linter_config.external_linter('templates', ['tools/check-templates'], ['hbs', 'html'],
description="Custom linter checks whitespace formatting" description="Custom linter checks whitespace formatting"
"of HTML templates.") "of HTML templates.",
fix_arg='--fix')
linter_config.external_linter('swagger', ['node', 'tools/check-swagger'], ['yaml'], linter_config.external_linter('swagger', ['node', 'tools/check-swagger'], ['yaml'],
description="Validates our OpenAPI/Swagger API documentation" description="Validates our OpenAPI/Swagger API documentation"
"(zerver/openapi/zulip.yaml) ") "(zerver/openapi/zulip.yaml) ")