Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 98 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

## Local development

- The complete test suite depends on having at least the following installed (possibly not
a complete list)
- The complete test suite depends on having at least the following installed
(possibly not a complete list)
- git (A sufficiently newer version is required to run pre-push tests)
- python2 (Required by a test which checks different python versions)
- python3 (Required by a test which checks different python versions)
Expand All @@ -30,7 +30,7 @@ Running a specific test with the environment activated is as easy as:

### Running all the tests

Running all the tests can be done by running `tox -e py27` (or your
Running all the tests can be done by running `tox -e py37` (or your
interpreter version of choice). These often take a long time and consume
significant cpu while running the slower node / ruby integration tests.

Expand All @@ -49,5 +49,98 @@ Documentation is hosted at https://pre-commit.com
This website is controlled through
https://github.com/pre-commit/pre-commit.github.io

When adding a feature, please make a pull request to add yourself to the
contributors list and add documentation to the website if applicable.
## Adding support for a new hook language

pre-commit already supports many [programming languages](https://pre-commit.com/#supported-languages)
to write hook executables with.

When adding support for a language, you must first decide what level of support
to implement. The current implemented languages are at varying levels:

- 0th class - pre-commit does not require any dependencies for these languages
as they're not actually languages (current examples: fail, pygrep)
- 1st class - pre-commit will bootstrap a full interpreter requiring nothing to
be installed globally (current examples: node, ruby)
- 2nd class - pre-commit requires the user to install the language globally but
will install tools in an isolated fashion (current examples: python, go, rust,
swift, docker).
- 3rd class - pre-commit requires the user to install both the tool and the
language globally (current examples: script, system)

"third class" is usually the easiest to implement first and is perfectly
acceptable.

Ideally the language works on the supported platforms for pre-commit (linux,
windows, macos) but it's ok to skip one or more platforms (for example, swift
doesn't run on windows).

When writing your new language, it's often useful to look at other examples in
the `pre_commit/languages` directory.

It might also be useful to look at a recent pull request which added a
language, for example:

- [rust](https://github.com/pre-commit/pre-commit/pull/751)
- [fail](https://github.com/pre-commit/pre-commit/pull/812)
- [swift](https://github.com/pre-commit/pre-commit/pull/467)

### `language` api

here are the apis that should be implemented for a language

Note that these are also documented in [`pre_commit/languages/all.py`](https://github.com/pre-commit/pre-commit/blob/master/pre_commit/languages/all.py)

#### `ENVIRONMENT_DIR`

a short string which will be used for the prefix of where packages will be
installed. For example, python uses `py_env` and installs a `virtualenv` at
that location.

this will be `None` for 0th / 3rd class languages as they don't have an install
step.

#### `get_default_version`

This is used to retrieve the default `language_version` for a language. If
one cannot be determined, return `'default'`.

You generally don't need to implement this on a first pass and can just use:

```python
get_default_version = helpers.basic_default_version
```

`python` is currently the only language which implements this api

#### `healthy`

This is used to check whether the installed environment is considered healthy.
This function should return `True` or `False`.

You generally don't need to implement this on a first pass and can just use:

```python
healthy = helpers.basic_healthy
```

`python` is currently the only language which implements this api, for python
it is checking whether some common dlls are still available.

#### `install_environment`

this is the trickiest one to implement and where all the smart parts happen.

this api should do the following things

- (0th / 3rd class): `install_environment = helpers.no_install`
- (1st class): install a language runtime into the hook's directory
- (2nd class): install the package at `.` into the `ENVIRONMENT_DIR`
- (2nd class, optional): install packages listed in `additional_dependencies`
into `ENVIRONMENT_DIR` (not a required feature for a first pass)

#### `run_hook`

This is usually the easiest to implement, most of them look the same as the
`node` hook implementation:

https://github.com/pre-commit/pre-commit/blob/160238220f022035c8ef869c9a8642f622c02118/pre_commit/languages/node.py#L72-L74