Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate lint checks to pre-commit? #17430

Open
ScottTodd opened this issue May 17, 2024 · 13 comments
Open

Migrate lint checks to pre-commit? #17430

ScottTodd opened this issue May 17, 2024 · 13 comments
Assignees
Labels
infrastructure Relating to build systems, CI, or testing quality of life 😊 Nice things are nice; let's have some

Comments

@ScottTodd
Copy link
Collaborator

Current lint checks

We have a lint workflow and script, both of which require some manual setup and can get out of sync:

We currently run:

Tool Description
bazel_to_cmake Our custom tool for translating BUILD.bazel files to CMakeLists.txt files
buildifier Formatting BUILD.bazel files
black Formatting Python files
pytype Analyzing types in Python files
This has enough false positives to remove-- we could switch to mypy
clang-format Formatting C/C++ files
tabs Our custom script to check source files tabs when spaces should be used
yamllint Linting yaml files
markdownlint Linting markdown files
path_lengths Checking for long path lengths (problematic on Windows)
generated_cmake_files Checking that our test suite generation scripts have been run
build_file_names Checking that Bazel files are named BUILD.bazel instead of BUILD
Remove? Helps with integration into Google's downstream repo

Pre-commit

Pre-commit is "a multi-language package manager for pre-commit hooks" that can be run easily on developer machines (no need to separately install specific versions of each tool) and on GitHub Actions via either an action or a service.

We've started using pre-commit on a few related projects and it has been helpful. See also this recent discussion on Discord.

@ScottTodd ScottTodd added infrastructure Relating to build systems, CI, or testing quality of life 😊 Nice things are nice; let's have some labels May 17, 2024
@ScottTodd
Copy link
Collaborator Author

We can also update our required status checks to block on all lint checks using this (or we could use the 'summary' style that ci.yml has. Right now we only block on clang-format, bazel_to_cmake, and yamllint:
image

@ScottTodd ScottTodd self-assigned this May 30, 2024
@ScottTodd
Copy link
Collaborator Author

@ScottTodd
Copy link
Collaborator Author

ScottTodd commented May 30, 2024

Started testing this out in IREE with #17534 and this .pre-commit-config.yaml file:

exclude: "third_party/"

repos:
-   repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v3.2.0
    hooks:
    -   id: trailing-whitespace
    -   id: end-of-file-fixer
        exclude_types: ["image", "jupyter"]
    -   id: check-yaml
        exclude: "mkdocs.yml"  # Extensions aren't included in the schema: https://github.com/squidfunk/mkdocs-material/issues/6378
-   repo: https://github.com/psf/black
    rev: 23.3.0
    hooks:
    -   id: black

So far I'm liking the ergonomics.

Setup on Windows:

py -m pip install --user pipx
py -m pipx ensurepath
pipx install pre-commit

pre-commit run --all-files

@ScottTodd
Copy link
Collaborator Author

ScottTodd commented May 31, 2024

Buildifier has some annoying gotchas:

The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in compiler/plugins/target/LLVMCPU/Builtins/BUILD.bazel.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in compiler/plugins/target/LLVMCPU/internal/BUILD.bazel.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in compiler/plugins/target/LLVMCPU/test/BUILD.bazel.
  • despite buildifier being written in go and pre-commit supporting package manager features, the community pre-commit hooks assume that it is already installed

@benvanik
Copy link
Collaborator

benvanik commented May 31, 2024

git add . --renormalize fixes line ending stuff for me whenever I have issues - maybe could run that after

(git line ending handling confuses me, so I use python build_tools/bazel_to_cmake/bazel_to_cmake.py && git add . --renormalize as my bazel-to-cmake command)

ScottTodd added a commit that referenced this issue May 31, 2024
Prep for switching our lint checks to use
[pre-commit](https://pre-commit.com/) - tracked in
#17430.

Formatting hooks applied in this PR:

* trailing-whitespace
* end-of-file-fixer
* check-yaml
* black
* clang-format
* markdownlint
* bazel_to_cmake
@ScottTodd
Copy link
Collaborator Author

ScottTodd commented Jun 1, 2024

Got this mostly done. Remaining work:

@ScottTodd
Copy link
Collaborator Author

git add . --renormalize fixes line ending stuff for me whenever I have issues - maybe could run that after

(git line ending handling confuses me, so I use python build_tools/bazel_to_cmake/bazel_to_cmake.py && git add . --renormalize as my bazel-to-cmake command)

Okay, this sort of works. A few ideas for working within the limits of pre-commit:

  • Add a run_buildifier.py script that runs on all files in a single step then runs git add . --renormalize
  • Add a run_buildifier.py script that runs on a single file then runs git add {FILENAME} --renormalize (watch for git process lock if running in parallel)
  • Make the buildifier check optional (https://pre-commit.com/#confining-hooks-to-run-at-certain-stages makes it manual, might prefer a way to just skip it on Windows) and have the CI opt-in

ScottTodd added a commit that referenced this issue Jun 3, 2024
This adds a [pre-commit](https://pre-commit.com/) configuration file and
migrates checks from our previous `lint.yml` and `lint.sh` files to
using these new hooks, making progress on
#17430. Each hook is versioned
and is automatically installed by pre-commit when used.

* Documentation updates to
https://iree.dev/developers/general/contributing/#coding-style-guidelines
will follow after some soak time (I haven't tested the actual pre-commit
git hook portion of the tooling yet, for example).

    TLDR:
    
    ```bash
    # setup (or using your package manager of choice)
    py -m pip install --user pipx
    py -m pipx ensurepath
    pipx install pre-commit
    
    # run manually on changed files
    pre-commit run
    
    # run manually on all files
    pre-commit run --all-files
    
    # install git hook scripts
    pre-commit install
    ```

* A few checks are disabled for now.
* `end-of-file-fixer` and `trailing-whitespace` are new checks for this
project so I want to give developers some time to learn pre-commit
workflows before adding them.
* Other checks like `generated_cmake_files` and `buildifier` are still
using the existing scripts while I figure out how to cleanly migrate
them.

Sample runs:

* Success:
https://github.com/iree-org/iree/actions/runs/9324252254/job/25669139815?pr=17538#step:4:54
* One error:
https://github.com/iree-org/iree/actions/runs/9324187058/job/25668919747?pr=17538#step:4:85

skip-ci: test lint job only
@ScottTodd
Copy link
Collaborator Author

Started looking at mypy on https://github.com/ScottTodd/iree/tree/pre-commit-mypy

Will need to either fix some issues or figure out how to limit how much of the repo it looks at

D:\dev\projects\iree (pre-commit-mypy)
λ pre-commit run --all-files mypy
mypy.....................................................................Failed
- hook id: mypy
- exit code: 2

build_tools\benchmarks\comparisons\common\__init__.py: error: Duplicate module named "common" (also at "build_tools\benchmarks\common\__init__.py")
build_tools\benchmarks\comparisons\common\__init__.py: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#mapping-file-paths-to-modules for more info
build_tools\benchmarks\comparisons\common\__init__.py: note: Common resolutions include: a) using `--exclude` to avoid checking one of them, b) adding `__init__.py` somewhere, c) using `--explicit-package-bases` or adjusting MYPYPATH
Found 1 error in 1 file (errors prevented further checking)

@ScottTodd
Copy link
Collaborator Author

The git hook works, even via git gui:
image

ScottTodd added a commit that referenced this issue Jun 3, 2024
These are produced by `python -m pip wheel compiler/` and are already
ignored by .gitignore.

Progress on #17430

skip-ci: lint-only change
gglangg pushed a commit to gglangg/iree that referenced this issue Jun 4, 2024
Prep for switching our lint checks to use
[pre-commit](https://pre-commit.com/) - tracked in
iree-org#17430.

Formatting hooks applied in this PR:

* trailing-whitespace
* end-of-file-fixer
* check-yaml
* black
* clang-format
* markdownlint
* bazel_to_cmake
gglangg pushed a commit to gglangg/iree that referenced this issue Jun 4, 2024
…#17538)

This adds a [pre-commit](https://pre-commit.com/) configuration file and
migrates checks from our previous `lint.yml` and `lint.sh` files to
using these new hooks, making progress on
iree-org#17430. Each hook is versioned
and is automatically installed by pre-commit when used.

* Documentation updates to
https://iree.dev/developers/general/contributing/#coding-style-guidelines
will follow after some soak time (I haven't tested the actual pre-commit
git hook portion of the tooling yet, for example).

    TLDR:
    
    ```bash
    # setup (or using your package manager of choice)
    py -m pip install --user pipx
    py -m pipx ensurepath
    pipx install pre-commit
    
    # run manually on changed files
    pre-commit run
    
    # run manually on all files
    pre-commit run --all-files
    
    # install git hook scripts
    pre-commit install
    ```

* A few checks are disabled for now.
* `end-of-file-fixer` and `trailing-whitespace` are new checks for this
project so I want to give developers some time to learn pre-commit
workflows before adding them.
* Other checks like `generated_cmake_files` and `buildifier` are still
using the existing scripts while I figure out how to cleanly migrate
them.

Sample runs:

* Success:
https://github.com/iree-org/iree/actions/runs/9324252254/job/25669139815?pr=17538#step:4:54
* One error:
https://github.com/iree-org/iree/actions/runs/9324187058/job/25668919747?pr=17538#step:4:85

skip-ci: test lint job only
gglangg pushed a commit to gglangg/iree that referenced this issue Jun 4, 2024
These are produced by `python -m pip wheel compiler/` and are already
ignored by .gitignore.

Progress on iree-org#17430

skip-ci: lint-only change
gglangg pushed a commit to gglangg/iree that referenced this issue Jun 4, 2024
Prep for switching our lint checks to use
[pre-commit](https://pre-commit.com/) - tracked in
iree-org#17430.

Formatting hooks applied in this PR:

* trailing-whitespace
* end-of-file-fixer
* check-yaml
* black
* clang-format
* markdownlint
* bazel_to_cmake
gglangg pushed a commit to gglangg/iree that referenced this issue Jun 4, 2024
…#17538)

This adds a [pre-commit](https://pre-commit.com/) configuration file and
migrates checks from our previous `lint.yml` and `lint.sh` files to
using these new hooks, making progress on
iree-org#17430. Each hook is versioned
and is automatically installed by pre-commit when used.

* Documentation updates to
https://iree.dev/developers/general/contributing/#coding-style-guidelines
will follow after some soak time (I haven't tested the actual pre-commit
git hook portion of the tooling yet, for example).

    TLDR:
    
    ```bash
    # setup (or using your package manager of choice)
    py -m pip install --user pipx
    py -m pipx ensurepath
    pipx install pre-commit
    
    # run manually on changed files
    pre-commit run
    
    # run manually on all files
    pre-commit run --all-files
    
    # install git hook scripts
    pre-commit install
    ```

* A few checks are disabled for now.
* `end-of-file-fixer` and `trailing-whitespace` are new checks for this
project so I want to give developers some time to learn pre-commit
workflows before adding them.
* Other checks like `generated_cmake_files` and `buildifier` are still
using the existing scripts while I figure out how to cleanly migrate
them.

Sample runs:

* Success:
https://github.com/iree-org/iree/actions/runs/9324252254/job/25669139815?pr=17538#step:4:54
* One error:
https://github.com/iree-org/iree/actions/runs/9324187058/job/25668919747?pr=17538#step:4:85

skip-ci: test lint job only
gglangg pushed a commit to gglangg/iree that referenced this issue Jun 4, 2024
These are produced by `python -m pip wheel compiler/` and are already
ignored by .gitignore.

Progress on iree-org#17430

skip-ci: lint-only change
pashu123 pushed a commit to pashu123/iree that referenced this issue Jun 4, 2024
These are produced by `python -m pip wheel compiler/` and are already
ignored by .gitignore.

Progress on iree-org#17430

skip-ci: lint-only change
@ScottTodd
Copy link
Collaborator Author

Most of the hooks are fast and only run on individual files when relevant. The slowest right now appears to be bazel_to_cmake, taking several seconds. I just set bazel_to_cmake to always run regardless of which files changed since it does its own walk through to discover Bazel and CMake source files. Could speed that up by teaching the python script to run on individual source files (bazel source -> generate cmake, cmake source -> look for corresponding bazel and edit in-place) and then let pre-commit handle finding affected files.

Performance is particularly important when running as a git hook, since git commit should take milliseconds, not seconds.

@ScottTodd
Copy link
Collaborator Author

Got a few devs specifically request getting the buildifier check running seamlessly (all platforms, ideally no manual download) here on Discord.

Can also check if there is an automatic deps adder we can use in open source. Google had an internal one but it sometimes was wrong or added extra deps (mostly across selects, which we barely use, IIRC). If such a tool / run mode exists we could try having pre-commit run it automatically.

bangtianliu pushed a commit to bangtianliu/iree that referenced this issue Jun 5, 2024
Prep for switching our lint checks to use
[pre-commit](https://pre-commit.com/) - tracked in
iree-org#17430.

Formatting hooks applied in this PR:

* trailing-whitespace
* end-of-file-fixer
* check-yaml
* black
* clang-format
* markdownlint
* bazel_to_cmake
bangtianliu pushed a commit to bangtianliu/iree that referenced this issue Jun 5, 2024
…#17538)

This adds a [pre-commit](https://pre-commit.com/) configuration file and
migrates checks from our previous `lint.yml` and `lint.sh` files to
using these new hooks, making progress on
iree-org#17430. Each hook is versioned
and is automatically installed by pre-commit when used.

* Documentation updates to
https://iree.dev/developers/general/contributing/#coding-style-guidelines
will follow after some soak time (I haven't tested the actual pre-commit
git hook portion of the tooling yet, for example).

    TLDR:
    
    ```bash
    # setup (or using your package manager of choice)
    py -m pip install --user pipx
    py -m pipx ensurepath
    pipx install pre-commit
    
    # run manually on changed files
    pre-commit run
    
    # run manually on all files
    pre-commit run --all-files
    
    # install git hook scripts
    pre-commit install
    ```

* A few checks are disabled for now.
* `end-of-file-fixer` and `trailing-whitespace` are new checks for this
project so I want to give developers some time to learn pre-commit
workflows before adding them.
* Other checks like `generated_cmake_files` and `buildifier` are still
using the existing scripts while I figure out how to cleanly migrate
them.

Sample runs:

* Success:
https://github.com/iree-org/iree/actions/runs/9324252254/job/25669139815?pr=17538#step:4:54
* One error:
https://github.com/iree-org/iree/actions/runs/9324187058/job/25668919747?pr=17538#step:4:85

skip-ci: test lint job only
bangtianliu pushed a commit to bangtianliu/iree that referenced this issue Jun 5, 2024
These are produced by `python -m pip wheel compiler/` and are already
ignored by .gitignore.

Progress on iree-org#17430

skip-ci: lint-only change
@ScottTodd
Copy link
Collaborator Author

Classic... there are two hooks for running buildifier listed at https://pre-commit.com/hooks.html, both of which assume that buildifier is already installed (despite pre-commit being a package manager), then https://github.com/bazelbuild/buildtools itself uses a third hook: https://github.com/keith/pre-commit-buildifier. That one claims it downloads buildifier, but instead of working like other pre-commit hooks and building from source (again - package manager) it uses a bash wrapper script that only supports macOS and Linux 🤦

ScottTodd added a commit that referenced this issue Jun 6, 2024
…17589)

ლ(ಠ益ಠლ)

Progress on #17430

This runs
[`buildifier`](https://github.com/bazelbuild/buildtools/tree/master/buildifier)
to format `BUILD.bazel`, `WORKSPACE`, and other [Bazel build
system](https://bazel.build/) files.

* Sample manual usage showing it working:
https://gist.github.com/ScottTodd/615416803b5595e9b9c4cffb3b83b1b9. It
can also run automatically via the git hook.
* ~~The current version of `buildifier` changes line endings on Windows
when it really shouldn't. Not sure how I want to fix or work around
that.~~ ("fixed" by adding a `.gitattributes` file)
ScottTodd added a commit that referenced this issue Jun 7, 2024
ScottTodd added a commit that referenced this issue Jun 7, 2024
)

Progress on #17430. With these
optimizations, the git hook is much faster to run, since unrelated file
changes will no longer trigger directory walks for these hooks.

* Taught `bazel_to_cmake.py` to accept positional arguments (paths to
`BUILD.bazel` and/or `CMakeLists.txt` files)
* Switched `bazel_to_cmake` pre-commit hook to use the new positional
arguments on only changed files
* Replaced `build_tools/scripts/check_path_lengths.py` hook entry with a
regex. The script will stick around since it provides a better debug
experience.
  
  Output for this check looks like this after lowering the limit:

    ```
    λ pre-commit run --all-files check_path_lengths
Check for excessively long path
lengths..................................Failed
    - hook id: check_path_lengths
    - exit code: 1
    
Path lengths relative to the root should be < 75 characters (run
./build_tools/scripts/check_path_lengths.py for detailed output)
    

compiler/src/iree/compiler/Modules/HAL/Inline/Conversion/StreamToHALInline/BUILD.bazel

compiler/src/iree/compiler/Modules/HAL/Inline/Conversion/StreamToHALInline/CMakeLists.txt

compiler/src/iree/compiler/Modules/HAL/Inline/Conversion/StreamToHALInline/Patterns.cpp

compiler/src/iree/compiler/Modules/HAL/Inline/Conversion/StreamToHALInline/Patterns.h

compiler/src/iree/compiler/Modules/HAL/Loader/Conversion/StreamToHALLoader/BUILD.bazel

compiler/src/iree/compiler/Modules/HAL/Loader/Conversion/StreamToHALLoader/CMakeLists.txt

compiler/src/iree/compiler/Modules/HAL/Loader/Conversion/StreamToHALLoader/Patterns.cpp

compiler/src/iree/compiler/Modules/HAL/Loader/Conversion/StreamToHALLoader/Patterns.h

compiler/src/iree/compiler/Modules/IO/Parameters/Conversion/StreamToParams/BUILD.bazel

compiler/src/iree/compiler/Modules/IO/Parameters/Conversion/StreamToParams/CMakeLists.txt

compiler/src/iree/compiler/Modules/IO/Parameters/Conversion/StreamToParams/Patterns.cpp

compiler/src/iree/compiler/Modules/IO/Parameters/Conversion/StreamToParams/Patterns.h
    ```

skip-ci: lint-only change
ScottTodd added a commit that referenced this issue Jun 7, 2024
This isn't providing enough value, triggers false positives, and we want
to switch to [mypy](https://mypy-lang.org/) (as a pre-commit check, see
#17430).

Could also remove `pytype: disable=` annotations and related comments.
ScottTodd added a commit that referenced this issue Jun 10, 2024
Progress on #17430. We've had
pre-commit enabled as blocking on PRs for about a week now and setup is
documented at
https://iree.dev/developers/general/contributing/#coding-style-guidelines,
so I'm comfortable enforcing these extra checks:

* `end-of-file-fixer` ensures that files end with a single `\n`
character, trimming extra newlines and inserting missing newlines
* `trailing-whitespace` ensures that lines in files do not contain
trailing whitespace

Together, both of these hooks enforce more consistency in file
formatting, making large scale changes easier and cleaner.
@ScottTodd
Copy link
Collaborator Author

Except for one last change (#17619) and pytype (which will be replaced with mypy), this migration is complete 🥳

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
infrastructure Relating to build systems, CI, or testing quality of life 😊 Nice things are nice; let's have some
Projects
None yet
Development

No branches or pull requests

2 participants