blob: c012b10aba1678d731a9bf64829fc1133086e76e [file] [log] [blame]
# Copyright 2025 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Asserts for checking changed files in git."""
import os
import subprocess
def _get_changed_files():
"""Returns the file to status for the current branch"""
result = subprocess.run(
['git', 'status', '--short'],
check=True,
capture_output=True,
text=True,
)
lines = result.stdout.strip().splitlines()
lines = [line.strip() for line in lines]
file_statuses = {
line[line.index(' ') + 1:].strip(): line[:line.index(' ')]
for line in lines if line
}
return file_statuses
def _check_files_status(context, expected_statuses, verb):
"""Helper function to check for files with specific git statuses."""
files = context.get('config', {}).get('files', {})
file_statuses = _get_changed_files()
files_with_status = {
file
for file, status in file_statuses.items()
if status in expected_statuses
}
files_without_status = [
file for file in files if file not in files_with_status
]
if len(files_without_status) != 0:
unexected_files = '\n'.join(files_without_status)
actual_files = '\n'.join(files_with_status)
return {
'pass': False,
'reason':
f'Expected {verb} files were not {verb}:\n{unexected_files}'
f'\nActual {verb} files:\n{actual_files}',
'score': 0
}
return {
'pass': True,
'reason': f'All expected {verb} files were {verb}.',
'score': 1
}
def check_files_changed(_: str, context):
"""Checks if specific files have been changed and uncommitted."""
return _check_files_status(context, ['M', 'T', 'R', 'U'], 'changed')
def check_files_added(_: str, context):
"""Checks if specific files have been added and uncommitted."""
return _check_files_status(context, ['A', '??'], 'added')
def check_files_exist(_: str, context):
"""Checks if specific files exist on the filesystem."""
files = context.get('config', {}).get('files', {})
files_that_do_not_exist = [
file for file in files if not os.path.exists(file)
]
if files_that_do_not_exist:
non_existent_files = '\n'.join(files_that_do_not_exist)
return {
'pass': False,
'reason': f'Expected files do not exist:\n{non_existent_files}',
'score': 0
}
return {'pass': True, 'reason': 'All expected files exist.', 'score': 1}
def check_file_content(_: str, context):
"""Checks if files contain or do not contain specific strings."""
file_configs = context.get('config', {}).get('files', [])
errors = []
for config in file_configs:
file_path = config.get('path')
if not file_path:
continue
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
except FileNotFoundError:
errors.append(f'File not found: {file_path}')
continue
except Exception as e:
errors.append(f'Error reading file {file_path}: {e}')
continue
for s in config.get('present', []):
if s not in content:
errors.append(
f'Expected to find "{s}" in {file_path}, but it was not '
'found.')
for s in config.get('absent', []):
if s in content:
errors.append(
f'Expected to not find "{s}" in {file_path}, but it was '
'found.')
if errors:
return {'pass': False, 'reason': '\n'.join(errors), 'score': 0}
return {
'pass': True,
'reason': 'All file content checks passed.',
'score': 1
}