From 1890678adfddaa185f4eaed9b5b29c54d8a8f181 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Sun, 20 Jun 2021 16:12:53 -0700 Subject: [PATCH] Add pre-push git hook (#26699) --- DEPS | 8 ++ ci/analyze.sh | 11 ++- testing/run_tests.py | 16 ++++ tools/githooks/README.md | 43 +++++++++ tools/githooks/bin/main.dart | 11 +++ tools/githooks/lib/githooks.dart | 77 +++++++++++++++++ tools/githooks/lib/src/pre_push_command.dart | 91 ++++++++++++++++++++ tools/githooks/pre-push | 33 +++++++ tools/githooks/pubspec.yaml | 41 +++++++++ tools/githooks/setup.py | 30 +++++++ tools/githooks/test/githooks_test.dart | 71 +++++++++++++++ tools/pub_get_offline.py | 1 + 12 files changed, 431 insertions(+), 2 deletions(-) create mode 100644 tools/githooks/README.md create mode 100644 tools/githooks/bin/main.dart create mode 100644 tools/githooks/lib/githooks.dart create mode 100644 tools/githooks/lib/src/pre_push_command.dart create mode 100755 tools/githooks/pre-push create mode 100644 tools/githooks/pubspec.yaml create mode 100755 tools/githooks/setup.py create mode 100644 tools/githooks/test/githooks_test.dart diff --git a/DEPS b/DEPS index ee07fc6dde..c54c3387dd 100644 --- a/DEPS +++ b/DEPS @@ -712,5 +712,13 @@ hooks = [ 'python3', 'src/build/win/generate_winrt_headers.py', ] + }, + { + 'name': 'Setup githooks', + 'pattern': '.', + 'action': [ + 'python3', + 'src/flutter/tools/githooks/setup.py', + ] } ] diff --git a/ci/analyze.sh b/ci/analyze.sh index bbacb87635..2f265ed9c8 100755 --- a/ci/analyze.sh +++ b/ci/analyze.sh @@ -32,6 +32,7 @@ SRC_DIR="$(cd "$SCRIPT_DIR/../.."; pwd -P)" FLUTTER_DIR="$SRC_DIR/flutter" DART_BIN="$SRC_DIR/third_party/dart/tools/sdks/dart-sdk/bin" PUB="$DART_BIN/pub" +DART="$DART_BIN/dart" DART_ANALYZER="$DART_BIN/dartanalyzer" echo "Using analyzer from $DART_ANALYZER" @@ -125,7 +126,13 @@ analyze \ --options "$FLUTTER_DIR/analysis_options.yaml" \ "$FLUTTER_DIR/testing/symbols" +echo "Analyzing githooks..." +analyze \ + --packages="$FLUTTER_DIR/tools/githooks/.dart_tool/package_config.json" \ + --options "$FLUTTER_DIR/analysis_options.yaml" \ + "$FLUTTER_DIR/tools/githooks" + # Check that dart libraries conform. echo "Checking web_ui api conformance..." -(cd "$FLUTTER_DIR/web_sdk"; pub get) -(cd "$FLUTTER_DIR"; dart "web_sdk/test/api_conform_test.dart") +(cd "$FLUTTER_DIR/web_sdk"; "$PUB" get) +(cd "$FLUTTER_DIR"; "$DART" "web_sdk/test/api_conform_test.dart") diff --git a/testing/run_tests.py b/testing/run_tests.py index 410d59c592..1dfaac5001 100755 --- a/testing/run_tests.py +++ b/testing/run_tests.py @@ -485,6 +485,21 @@ def RunBenchmarkTests(build_dir): cwd=test_dir) +def RunGithooksTests(build_dir): + test_dir = os.path.join(buildroot_dir, 'flutter', 'tools', 'githooks') + dart_tests = glob.glob('%s/test/*_test.dart' % test_dir) + for dart_test_file in dart_tests: + opts = [ + '--disable-dart-dev', + dart_test_file] + RunEngineExecutable( + build_dir, + os.path.join('dart-sdk', 'bin', 'dart'), + None, + flags=opts, + cwd=test_dir) + + def main(): parser = argparse.ArgumentParser() @@ -526,6 +541,7 @@ def main(): dart_filter = args.dart_filter.split(',') if args.dart_filter else None RunDartSmokeTest(build_dir, args.verbose_dart_snapshot) RunLitetestTests(build_dir) + RunGithooksTests(build_dir) RunDartTests(build_dir, dart_filter, args.verbose_dart_snapshot) RunConstFinderTests(build_dir) RunFrontEndServerTests(build_dir) diff --git a/tools/githooks/README.md b/tools/githooks/README.md new file mode 100644 index 0000000000..1ac57c8ca3 --- /dev/null +++ b/tools/githooks/README.md @@ -0,0 +1,43 @@ +# Git Hooks + +The behavior of `git` commands can be customized through the use of "hooks". +These hooks are described in detail in git's +[documentation](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks). + +`git` looks for an executables by name in the directory specified by +the `core.hooksPath` `git config` setting. The script `setup.py` here points +`core.hooksPath` at this directory. It runs during a `gclient sync` or a +`gclient runhooks`. + +The hooks here are implemented in Dart by the program with +entrypoint `bin/main.dart` in this directory. The commands of the program +are the implementation of the different hooks, for example +`bin/main.dart pre-push ...`. Since the Dart program itself isn't an executable, +these commands are invoked by small Python wrapper scripts. These wrapper +scripts have the names that `git` will look for. + +## pre-push + +This hooks runs when pushing commits to a remote branch, for example to +create or update a pull request: `git push origin my-local-branch`. + +The `pre-push` hook runs `ci/lint.sh` and `ci/format.sh`. `ci/analyze.sh` and +`ci/licenses.sh` are more expensive and are not run. + +### Adding new pre-push checks + +Since the pre-push checks run on every `git push`, they should run quickly. +New checks can be added by modifying the `run()` method of the `PrePushCommand` +class in `lib/src/pre_push_command.dart`. + +## Creating a new hook + +1. Check the `git` documentation, and copy `pre-push` into a script with +the right name. +1. Make sure the script has the executable bit set +(`chmod +x