| #!/usr/bin/env python3 | |
| # Copyright 2020 The Pigweed Authors | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); you may not | |
| # use this file except in compliance with the License. You may obtain a copy of | |
| # the License at | |
| # | |
| # https://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
| # License for the specific language governing permissions and limitations under | |
| # the License. | |
| """Example presubmit check script.""" | |
| import argparse | |
| import logging | |
| import os | |
| from pathlib import Path | |
| import re | |
| import sys | |
| try: | |
| import pw_cli.log | |
| except ImportError: | |
| print( | |
| 'ERROR: Activate the environment before running presubmits!', | |
| file=sys.stderr, | |
| ) | |
| sys.exit(2) | |
| import pw_presubmit | |
| from pw_presubmit import ( | |
| build, | |
| cli, | |
| cpp_checks, | |
| format_code, | |
| git_repo, | |
| inclusive_language, | |
| install_hook, | |
| keep_sorted, | |
| pw_internal_namespace, | |
| python_checks, | |
| ) | |
| from pw_presubmit.presubmit_context import PresubmitContext, PresubmitFailure | |
| _LOG = logging.getLogger(__name__) | |
| # Set up variables for key project paths. | |
| try: | |
| PROJECT_ROOT = Path(os.environ['SAMPLE_PROJECT_ROOT']) | |
| except KeyError: | |
| print( | |
| 'ERROR: The presubmit checks must be run in the sample project\'s root' | |
| ' directory', | |
| file=sys.stderr, | |
| ) | |
| sys.exit(2) | |
| PIGWEED_ROOT = PROJECT_ROOT / 'third_party' / 'pigweed' | |
| # Rerun the build if files with these extensions change. | |
| _BUILD_EXTENSIONS = frozenset( | |
| ['.rst', '.gn', '.gni', *format_code.C_FORMAT.extensions] | |
| ) | |
| # | |
| # Presubmit checks | |
| # | |
| def default_build(ctx: PresubmitContext): | |
| """Creates a default build.""" | |
| build.gn_gen(ctx) | |
| build.ninja(ctx) | |
| def check_for_git_changes(ctx: PresubmitContext): | |
| """Checks that repositories have all changes committed.""" | |
| checked_repos = (PIGWEED_ROOT, *ctx.repos) | |
| changes = [r for r in checked_repos if git_repo.has_uncommitted_changes(r)] | |
| for repo in changes: | |
| _LOG.error('There are uncommitted changes in the %s repo!', repo.name) | |
| if changes: | |
| _LOG.warning( | |
| 'Commit or stash pending changes before running the presubmit.' | |
| ) | |
| raise PresubmitFailure | |
| # Avoid running some checks on certain paths. | |
| PATH_EXCLUSIONS = ( | |
| re.compile(r'^external/'), | |
| re.compile(r'^third_party/'), | |
| re.compile(r'^vendor/'), | |
| ) | |
| # | |
| # Presubmit check programs | |
| # | |
| OTHER_CHECKS = (build.gn_gen_check,) | |
| QUICK = ( | |
| default_build, | |
| format_code.presubmit_checks( | |
| code_formats=format_code.CODE_FORMATS_WITH_BLACK | |
| ), | |
| ) | |
| LINTFORMAT = ( | |
| # keep-sorted: start | |
| cpp_checks.pragma_once, | |
| format_code.presubmit_checks(), | |
| inclusive_language.presubmit_check, | |
| keep_sorted.presubmit_check, | |
| pw_internal_namespace.pw_internal_namespace, | |
| python_checks.gn_python_lint, | |
| # keep-sorted: end | |
| ) | |
| FULL = ( | |
| QUICK, # Add all checks from the 'quick' program | |
| LINTFORMAT, | |
| # Use the upstream Python checks, with custom path filters applied. | |
| python_checks.gn_python_check, | |
| ) | |
| PROGRAMS = pw_presubmit.Programs( | |
| # keep-sorted: start | |
| full=FULL, | |
| lintformat=LINTFORMAT, | |
| other_checks=OTHER_CHECKS, | |
| quick=QUICK, | |
| # keep-sorted: end | |
| ) | |
| def run(install: bool, exclude: list, **presubmit_args) -> int: | |
| """Process the --install argument then invoke pw_presubmit.""" | |
| # Install the presubmit Git pre-push hook, if requested. | |
| if install: | |
| install_hook.install_git_hook( | |
| 'pre-push', | |
| [ | |
| 'python', | |
| '-m', | |
| 'sample_project_tools.presubmit_checks', | |
| '--base', | |
| 'origin/main..HEAD', | |
| '--program', | |
| 'quick', | |
| ], | |
| ) | |
| return 0 | |
| exclude.extend(PATH_EXCLUSIONS) | |
| repos = git_repo.discover_submodules(superproject_dir=PROJECT_ROOT) | |
| return cli.run( | |
| root=PROJECT_ROOT, repositories=repos, exclude=exclude, **presubmit_args | |
| ) | |
| def main() -> int: | |
| """Run the presubmit checks for this repository.""" | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| cli.add_arguments(parser, PROGRAMS, 'quick') | |
| # Define an option for installing a Git pre-push hook for this script. | |
| parser.add_argument( | |
| '--install', | |
| action='store_true', | |
| help='Install the presubmit as a Git pre-push hook and exit.', | |
| ) | |
| return run(**vars(parser.parse_args())) | |
| if __name__ == '__main__': | |
| pw_cli.log.install(logging.INFO) | |
| sys.exit(main()) |