# pre-commit

* [setup](#setup)
  * [install pre-commit](#install-pre-commit)
  * [init hook in repo](#init-hook-in-repo)
* [run](#run)
* [migrate-config](#migrate-config)
* [hooks](#hooks)
  * [copyright manager](#copyright-manager)
  * [checker and fixer](#checker-and-fixer)
  * [convert tab to spaces](#convert-tab-to-spaces)
  * [typos](#typos)

### setup

#### install pre-commit

```bash
$ python -m pip install --user pipx
$ pipx ensurepath
$ pipx install pre-commit

# or
$ brew install --HEAD pre-commit
```

#### init hook in repo

```bash
$ pre-commit install

# or
$ pre-commit install --install-hook
pre-commit installed at .git/hooks/pre-commit
```

### run

```bash
# -- all files --
$ pre-commit run --all-files
# or
$ pre-commit run --all-files --show-diff-on-failure --color always

# -- all files with specific hook --
$ pre-commit run <hook_id> --all-files
# i.e.:
$ pre-commit run trailing-whitespace --all-files
```

### migrate-config

```bash
$ pre-commit migrate-config
```

### hooks

> \[!NOTE|labels:reference:]
>
> * sample config
>
> > ```bash
> > $ pre-commit sample-config
> > # See https://pre-commit.com for more information
> > # See https://pre-commit.com/hooks.html for more hooks
> > repos:
> > -   repo: https://github.com/pre-commit/pre-commit-hooks
> >     rev: v3.2.0
> >     hooks:
> >     -   id: trailing-whitespace
> >     -   id: end-of-file-fixer
> >     -   id: check-yaml
> >     -   id: check-added-large-files
> > ```
>
> * update to repo's latest version
>
> > ```bash
> > $ pre-commit autoupdate
> > [https://github.com/pre-commit/pre-commit-hooks] already up to date!
> > [https://github.com/psf/black] already up to date!
> > ```

#### copyright manager

> \[!NOTE|labels:reference:]
>
> * [\* iMarslo: cr-manager](https://github.com/marslo/cr-manager)

```yaml
# yamllint disable rule:indentation
---
repos:
  - repo: https://github.com/marslo/cr-manager
    rev: v0.0.4
    hooks:
      - id: update-copyright
        args: ["--update"]
```

#### checker and fixer

```yaml
# yamllint disable rule:indentation
---
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: trailing-whitespace
        name: Trim Trailing Whitespace
      - id: end-of-file-fixer
        name: End Of File Fixer
      - id: check-yaml
        name: Check YAML
        args: ["--unsafe"]
      - id: check-json
        name: Check JSON
      - id: check-merge-conflict
        name: Check Merge Conflict
      - id: check-case-conflict
        name: Check Case Conflict
      - id: mixed-line-ending
        name: Mixed Line Ending
        args: ["--fix=lf"]
```

**mixed-line-ending**

| `--fix` OPTIONS | COMMENTS                     |
| --------------- | ---------------------------- |
| `auto`          | auto-detect line-ending      |
| `no`            | no change line-ending        |
| `cr`            | force use (legacy Mac)       |
| `crlf`          | force use `\r`(Windows)      |
| `lf`            | force use (Unix/Linux/macOS) |

#### convert tab to spaces

*   `expand` + `sponge`

    ```yaml
    # yamllint disable rule:indentation
    ---
    repos:
      - repo: local
        hooks:
          - id: tab-to-space
            name: Convert Tabs to 2 Spaces
            entry: bash -c 'expand -t 2 "$@" | sponge "$@"' --
            language: system
            types: [text]
            exclude: \.(py|groovy|jenkinsfile/.*)$

          - id: tab-to-4-spaces
            name: Convert Tabs to 4 Spaces
            entry: bash -c 'expand -t 4 "$@" | sponge "$@"' --
            language: system
            files: \.py$

          - id: tab-to-2-spaces
            name: Convert Tabs to 2 Spaces
            entry: bash -c 'expand -t 2 "$@" | sponge "$@"' --
            language: system
            files: (\.groovy$|jenkinsfile/.*)
    ```
*   python solution

    ```python
    import argparse
    import fileinput

    def convert_tabs(file_path, spaces):
        with fileinput.FileInput(file_path, inplace=True) as file:
            for line in file:
                print(line.expandtabs(spaces), end='')

    if __name__ == '__main__':
        parser = argparse.ArgumentParser()
        parser.add_argument('--spaces', type=int, required=True)
        parser.add_argument('files', nargs='*')
        args = parser.parse_args()

        for file in args.files:
            convert_tabs(file, args.spaces)
    ```

    ```yaml
    repos:
      - repo: local
        hooks:
          - id: tab-to-space
            name: Convert Tabs to 2 Spaces [ DEFAULT ]
            entry: python tab_converter.py --spaces 2
            language: system
            types: [text]
            exclude: \.(py|groovy)$
            pass_filenames: true

          - id: tab-to-4-spaces
            name: Convert Tabs to 4 Spaces
            entry: python tab_converter.py --spaces 4
            language: system
            files: \.py$
            pass_filenames: true

          - id: tab-to-2-spaces
            name: Convert Tabs to 2 Spaces
            entry: python tab_converter.py --spaces 2
            language: system
            files: (\.groovy$|jenkinsfile/.*)
            pass_filenames: true
    ```

#### typos

```yaml
# yamllint disable rule:indentation
---
repos:
  - repo: https://github.com/crate-ci/typos
    rev: v1.31.1
    hooks:
        - id: typos
          name: Typos
          description: Finds and corrects spelling mistakes among source code.
          exclude: \.git
```
