9

pre-commit hooks are run in a separate virtual environment (or Docker container). However our code is running on Docker and we're also developing using Docker.

Up until now we didn't have to install any dependencies on our host systems, but when running mypy, isort and pylint they run into problems because they can't access the dependencies installed.

Our first idea was to install the dependencies in a virtual environment on the host system, but that also seems like a clumsy workaround.

Is there a good way to run pre-commit with full access to the container?

Jann
  • 1,799
  • 3
  • 21
  • 38

3 Answers3

1

We had the same thought and that's what we ended up with in our team:

  • Pre-commit Docker image. Simple, minimal Docker image based on docker image containing just pre-commit itself (implicitly containing python, pip and so on). Note: docker image is really needed here because we do use Docker-based hooks.
  • Set of separated Docker images containing "complicated" hooks/checkers. By "complicated" I mean ones which require some build-time dependencies, compilers, extra libraries and so on, stuff which cannot be installed with simple "pip install" on clean machine. One example would be clang-format which we build from sources so the final clang-format Docker image contains just clang-format binary. That's where mypy would go probably as well as it has a lot of extra non-Python dependencies.

Note: pre-commit is a bit bad when working in "docker in docker" mode, so we had to apply a workaround, see https://github.com/pre-commit/pre-commit/issues/1387

In the end, our .pre-commit-config.yaml file has entries like:

# Normal, "simple" hooks which can be just installed as is
- repo: ...pre-commit-hooks/pre-commit-hooks
  rev: v3.3.0
  hooks:
   - ...

# Docker hooks
- repo: local
  hooks:
  - id: docker-clang-format
    name: Docker Clang Format
    language: docker_image
    types:
    - c++
    entry: <our-registry.com>/clang_format:11

# Local workarounds for devs who cannot or don't want to use Docker, but still would like to benefit from running pre-commit locally
- repo: <...>/pre-commit-clang-format
    rev: ...
    hooks:
      - id: clang-format
        stages: [manual]  # Mind this line, only for manual run
        types:
          - c++
The Godfather
  • 4,235
  • 4
  • 39
  • 61
0

How about creating a special container for code style checks?

It should have all needed linters installed and a bash file to check code directory.

Your hook command will look something like docker run -v [mount code dir to container in RO mode] codestyle_check_container

stepuncius
  • 266
  • 1
  • 4
  • 17
  • I'm not sure if I understood your solution correctly. Would that mean (if I'd like to continue using the features of pre-commit) that I would need to install pre-commit on the host system and set it up to run a docker-container that is separately set up with all dependencies (and the actual repo mounted in)? I assume it could work, keeping in mind though that pre-commit does stash any unstaged changes. It doesn't seem very simple, though. – Jann Jan 22 '20 at 12:52
  • @Jann suppose, you understood it right. If you would like to run pre-commit inside container, you can give your container access to host system's docker daemon, so `docker run` inside container will call host system's docker ( never do it in production). https://stackoverflow.com/questions/48152736/how-can-i-call-docker-daemon-of-the-host-machine-from-a-container . So you have docker volume with code, you run pre-commit hook inside your container and it starts another container, who checks your code.( using host system's docker daemon) – stepuncius Jan 24 '20 at 12:36
  • The more code checks you have, the bigger your image would be (and the less reusable!) :) So it's better to separate the concerns from the very beginning, also helps when one day you have two checkers requiring different version of something. – The Godfather Feb 15 '21 at 13:11
0

We use a docker-compose.yml file for local development for a Ruby on Rails API, with the ruby pre-commit gem (https://github.com/jish/pre-commit) so we ended up configuring the pre-commit this way:

git config pre-commit.ruby "docker compose run api bundle exec ruby"

With our container service named api

Littletime
  • 527
  • 6
  • 12