| # 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. |
| |
| """Presubmit script for Chrome Android feature flag code.""" |
| |
| def CheckChromeFeatureIsSorted(input_api, output_api, file_path, name, start_pattern, end_pattern): |
| """ |
| Checks that the section of code within `start_pattern` and `end_pattern` |
| inside the `file_path` file is sorted alphabetically. |
| """ |
| # Find the file in the list of changed files. |
| affected_file = None |
| for f in input_api.AffectedFiles(): |
| if f.LocalPath() == file_path: |
| affected_file = f |
| break |
| |
| # If the file was not modified in this change, return. |
| if not affected_file: |
| return [] |
| |
| contents = affected_file.NewContents() |
| in_array = False |
| feature_lines = [] |
| |
| # Extract the lines that are inside the array definition. |
| for line in contents: |
| stripped_line = line.strip() |
| if not in_array and start_pattern in line: |
| in_array = True |
| |
| if in_array: |
| if stripped_line == end_pattern: |
| break # We've reached the end of the array. |
| # Ignore comments and empty lines within the array. |
| if stripped_line and not stripped_line.startswith('//'): |
| feature_lines.append(stripped_line) |
| |
| # If the array wasn't found or is empty, return. |
| if not feature_lines: |
| return [] |
| |
| # Create a sorted version of the list for comparison. |
| # The sort is not case-sensitive to be user-friendly. |
| sorted_feature_names = sorted(feature_lines) |
| |
| # If the list is already sorted, the check passes. |
| if feature_lines == sorted_feature_names: |
| return [] |
| |
| # If the list is not sorted, find the first discrepancy to create a |
| # helpful and actionable error message for the developer. |
| error_detail = '' |
| for i, original in enumerate(feature_lines): |
| if original != sorted_feature_names[i]: |
| error_detail = ( |
| "The list is not sorted alphabetically.\n" |
| f" - The first out-of-order item is: '{original}'\n" |
| f" - The expected item was: '{sorted_feature_names[i]}'" |
| ) |
| break |
| |
| error_message = ( |
| f"The `{name}` values in {file_path} must be sorted " |
| f"alphabetically.\n\n{error_detail}\n\nPlease sort the list to " |
| "fix this error." |
| ) |
| |
| # We want this to be an error because it is an easy fix, and this list has |
| # historically become out-of-order, which makes automated scripting harder. |
| return [output_api.PresubmitError(error_message)] |
| |
| |
| def CheckChangeOnCommit(input_api, output_api): |
| results = [] |
| |
| # Check that the array of exported features is in order. |
| results.extend(CheckChromeFeatureIsSorted( |
| input_api, |
| output_api, |
| 'chrome/browser/flags/android/chrome_feature_list.cc', |
| 'kFeaturesExposedToJava', |
| '// FEATURE_EXPORT_LIST_START', |
| '// FEATURE_EXPORT_LIST_END') |
| ) |
| |
| # Check that all feature definitions are in order. |
| results.extend(CheckChromeFeatureIsSorted(input_api, output_api, |
| 'chrome/browser/flags/android/chrome_feature_list.cc', |
| 'BASE_FEATURE', |
| '// BASE_FEATURE_START', |
| '// BASE_FEATURE_END')) |
| |
| # Check that all feature declarations are in order. |
| results.extend(CheckChromeFeatureIsSorted(input_api, output_api, |
| 'chrome/browser/flags/android/chrome_feature_list.h', |
| 'BASE_DECLARE_FEATURE', |
| '// BASE_DECLARE_FEATURE_START', |
| '// BASE_DECLARE_FEATURE_END')) |
| |
| return results |