Add pre-commit hook to verify static analysis passes & format is correct#11941
Add pre-commit hook to verify static analysis passes & format is correct#11941camsim99 wants to merge 23 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a new githooks Dart package to automate pre-commit checks, including formatting and static analysis, for staged files. The package includes an installation script, a pre-commit command runner, and associated unit tests. Review feedback highlights a potential infinite loop on Windows when locating the .git directory, raw ANSI escape sequences being printed without verifying terminal support, the use of loose any version constraints in pubspec.yaml, and redundant dead code in the test mocks.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a Dart-based pre-commit git hook framework to automate formatting and static analysis checks on staged files. The feedback suggests enhancing compatibility with Git submodules and worktrees by checking for .git as a file, adding support for .hpp extensions in Clang formatting, conditionally writing ANSI escape sequences based on terminal support, and adding test coverage for the native formatting execution path.
reidbaker
left a comment
There was a problem hiding this comment.
I left a bunch of comments on the code but before addressing any of those 2 high level questions.
Why did you rewrite analyze and format logic instead of using the logic that is already built into the flutter packages tooling?
If we were not going to use the existing flutter packages tooling for some good technical reason why not use something like https://github.com/pre-commit/pre-commit
| '--diff-filter=ACM', | ||
| ], workingDirectory: repoRoot.path); | ||
|
|
||
| if (diffResult.exitCode != 0) { |
There was a problem hiding this comment.
With your ACM filter there could be a commit that was just a deletion but I dont think it would give any files. What error code is returned in that situation or is that a success? Looks like empty sets are handled below.
| ], workingDirectory: repoRoot.path); | ||
|
|
||
| if (diffResult.exitCode != 0) { | ||
| print('❌ Failed to get staged files'); |
There was a problem hiding this comment.
Do you think we should include the command that failed and the error code?
| } | ||
|
|
||
| @override | ||
| Future<bool> run() async { |
| } | ||
|
|
||
| if (targetPackageDirs.isEmpty) { | ||
| // None of the changed files are part of a package we care about. |
There was a problem hiding this comment.
I am a bit confused as to what this does. It looks like it is building a set of packages from staged files. But if that is the case then where does the filtering happen.
| final packageArgs = '--packages=${targetPackages.join(',')}'; | ||
|
|
||
| // Determine which toolchains are needed based on file extensions to avoid uneccessary slowdown. | ||
| final bool hasClang = stagedFiles.any( |
There was a problem hiding this comment.
What code determines if this list needs to change?
| f.endsWith('.m') || | ||
| f.endsWith('.mm'), | ||
| ); | ||
| final bool hasJava = stagedFiles.any((f) => f.endsWith('.java')); |
There was a problem hiding this comment.
Recommend structuring this a bit more formally. What information is needed per language? How do you execute per language. Lets make the blast radius clear and the file manipulations happen outside of any language logic.
| // Format staged native files. | ||
| final bool needsNativeFormat = hasClang || hasJava || hasKotlin || hasSwift; | ||
| if (needsNativeFormat) { | ||
| final nativeFormatFlags = [ |
There was a problem hiding this comment.
Lets use the args package. https://pub.dev/packages/args
| print(nativeFormatResult.stderr); | ||
| } | ||
| print( | ||
| '❌ Formatting issues found in native files. Please run "dart run script/tool/bin/flutter_plugin_tools.dart format $packageArgs" to fix them.', |
There was a problem hiding this comment.
I am guessing ai wrote this script because it tends to use these unicode chars for success and failure. Lets remove those unicode chars.
|
|
||
| if (!hasError) { | ||
| stdout.write( | ||
| stdout.supportsAnsiEscapes |
There was a problem hiding this comment.
is this complexity needed? What value do we get from having ansiExcapes here.
|
|
||
| // Run static analysis on staged files. | ||
| var analyzeHasError = false; | ||
| stdout.write('Running static analysis...'); |
There was a problem hiding this comment.
Structurally my gut is organizing code by job type instead of by when in the hooks process the code runs is more likely to be a durable standard.
|
@reidbaker To answer your high level question, I initially just called the plugin tool but it was extremely slow to the point where I wouldn't have felt comfortable landing this, so that's why I made optimizations around avoiding setup of non-required native tool chains and ignoring files that are not staged. However, your point is taken because the right way for me to fix things is to add the optimizations to the plugin tool itself. Working on that now! That should make the pre-commit hook itself much simpler, but I'll still refactor as needed. I was unaware of https://pre-commit.com/#usage and modeled this PR after the engine. If you prefer we use the pre-commit tool, I can look into that, but either way I need to make some optimizations to the plugin tool to make this hook usable. |
|
Fwiw I don't have a strong preference but I wanted to point out the duplication especially since there was a tool that was aware in the repo. Adding optimizations to the tool seems like a good plan. |
Adds a pre-commit hook that you can install to verify that
dart analyze --fatal-infosand the package format are correct when you make a call togit commit. Intended to ensure agents commit code that meets are quality standards.Miscellaneous notes:
script/githooks/bin/install_hooks.dartis the script to install the hook that devs would need to run to use it.githooksdirectory like https://github.com/flutter/flutter/tree/master/engine/src/flutter/tools/githooks to make it easier for folks to add new hooksPre-Review Checklist
[shared_preferences]///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assistbot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.Footnotes
Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. ↩ ↩2