# Getting started with `debputy` lint and LSP features

_This is [how-to guide] and is primarily aimed at getting a task done._

<!-- To writers and reviewers: Check the documentation against https://documentation.divio.com/ -->

This document will introduce you to how to use `debputy`'s maintainer support features such
as "linting" and the in-editor assistance. Prerequisites for this how-to guide:

 * Using the in-editor assistance requires an editor that support the Language Server Protocol (LSP)
   specification. Check if your editor is mentioned on 
   https://microsoft.github.io/language-server-protocol/implementors/tools/ or for mentions of `LSP`
   in your editor's documentation.

 * These features will require optional dependencies. Please see [Dependencies](#dependencies) for
   details.

# Reading guide

The guide covers all the different ways to use the lint and LSP features. Since you might only be
here for a subset of the features, this section provides a guide for a more streamlined experience.

 1. Start by reviewing [Dependencies](#dependencies) to ensure you are setup.
 2. Pick and read the relevant sections from for the maintainer/reviewer use-cases:
    - Command line for maintainer/reviewer  Command line for single package at a time:
      - [Linting via CLI (`debputy lint`)](#batch-linting-debputy-lint)
      - [reformatting via CLI  (`debputy reformat`)](#batch-reformatting)
    - [Editor assistance (LSP)](#editor-assistance-lsp)
 3. On top of this, these sections will cover topics like CI or `pre-commit` and bulk automation
    if relevant to you (they assume you read the previous sections).
    - Using `debputy` from CI:
      - [Linting for CI or bulk automation](#batch-linting-for-ci-or-other-automated-processing)
      - [Reformatting for CI or bulk automation](#batch-reformatting-for-ci-or-other-automated-processing)
    - Using `debputy` from `pre-commit`:
      - [Linting via pre-commit](#batch-linting-via-pre-commit)
      - [Reformatting via pre-commit](#batch-reformatting-via-pre-commit)
 4. Finally, you might want to have read:
    - [Known differences to `wrap-and-sort`](#known-differences-to-wrap-and-sort)


# Dependencies

As mentioned, you will need to install optional dependencies to use these features. The following
are the recommended set of packages to install:

    apt-get install -y debputy-lsp python3-levenshtein

If you want English spellchecking as well, also run:

    apt-get install -y python3-hunspell hunspell-en-us

If you are interested in using `debputy` in a CI pipeline, you may also want `python3-junit-xml`
if you want `debputy lint`'s report in a junit4 format. 

## Optional features

The `debputy` support features include various optional features that may be useful to you. You
can expect them via the `debputy lsp features` commands. The command output will tell you which
features are enabled plus how to enable features that are currently not available.

This guide only requires the minimum requirements to be available, though some of the example output
are from the "typo detection" feature. If you installed the dependencies listed under
[Dependencies](#dependencies), you should have both of these enabled already.

# Batch linting (`debputy lint`)

The simplest way to get started with using `debputy`'s support features is to install the dependencies
mentioned previously followed by placing yourself in the source root of an unpacked debian source package
(the directory containing the `debian`-directory). From there, you run:

    debputy lint

Add the `--spellchecking` (`debputy lint --spellchecking`) if you want to activate the English
spellchecking. It is not enabled by default as it can be overwhelming and have a lot of
false-positives (notably for names of people).

The output will be something like:

    $ debputy lint
    warning: File: ./debian/control:5:0:5:9: The "Uploadres" looks like a typo of "Uploaders". [Correctable via --auto-fix]
         5: Uploadres:

You can have `debputy` autocorrect issues via the `--auto-fix` option. This works for some of the issues
detected by `debputy lint`, where `debputy` has exactly one solution to the problem. However, please be
careful with this as there is no interactive way of picking which ones get fixed if you disagree with
one of the fixes.

Note that issues from `--spellchecking` are not fixed by `--auto-fix`.

## Batch linting for CI or other automated processing

If you want to use `debputy lint` from a CI pipeline, you may want to consider the options:

 * `--lint-report-format junit4-xml`: Generates a JUnit4 report instead of writing to a terminal.
   This can be useful if your CI framework can process JUnit4 reports. Some example cases:
   - GitHub: Via custom action (https://github.com/marketplace/actions/junit-report-action)
   - GitLab: Native support (https://docs.gitlab.com/ee/ci/testing/unit_test_reports.html)
   - Jenkins: Via JUnit plugin (https://www.jenkins.io/doc/pipeline/steps/junit/)

 * `--no-linter-exit-code` / `--linter-exit-code`: Whether `debputy lint` should have a non-zero
   exit status on "severe" issues (warning or errors).

## Batch linting via pre-commit

An example pre-commit hook is provided in https://salsa.debian.org/debian/debputy-pre-commit-hooks

# Batch reformatting

The `debputy` tool can also reformat packaging files. Reformatting is done by running:

    debputy reformat

On packages that have opted in to a known formatting style, `debputy reformat` will apply this
formatting to supported packaging files. Otherwise, `debputy` will inform you that no style was
found and tell you how to opt in to reformatting. This makes it safe to always run
`debputy reformat` as automated formatting is opt-in.

The simplest way to enable automatic reformatting, is to set the `X-Style` field to `black` in the
source stanza of `debian/control`. If you want to do a one-off reformatting, you can also use
`debputy reformat --style black`. When you pass `--style`, `debputy` will disregard any existing
style and blindly reformat according to the named style provided.

You can also pass the `--no-auto-fix` if you just want to see the delta between the current format
and the desired format. The output will be a unified diff that can be applied with `patch -p1`.

## Known differences to `wrap-and-sort`

If you are used to the `wrap-and-sort` command and is considering to replace it with
`debputy reformat`, then here are some important differences:

 1. The `debputy reformat` follows a "safe-by-default" principle and requires opt-in to apply formatting.
    On the other hand, `wrap-and-sort` applies a default style that ignores the existing formatting.
    To ignore the existing style with `debputy reformat`, you must explicitly add `--style <style-name>`.

 2. The `wrap-and-sort` tool will also reformat various `debhelper` config files like `debian/install`.
    This reformatting reorders the content of `debian/install`, which is unsafe in rare corner cases.
    The `debputy reformat` follows the mantra of "reformatting must not change semantics" and therefore
    does not support this feature. If you want this feature, you will need to run `wrap-and-sort`.

 3. The `wrap-and-sort` tool can reorder stanzas in `debian/control` to sort them by package name.
    The reordering variant `--no-keep-first` is unsafe with files like `debian/install`, since the
    reordering could change which package that file applies to. The `--keep-first` variant does not
    have this problem. Here, `debputy reformat` follows the  mantra of "reformatting must not change
    semantics" and only supports the `--keep-first`.
    - Note: The `debputy reformat` command only disables the stanza re-ordering in this case. Other
      style rules will still be applied.

On top of these, `debputy` also provides its own `black` style as mentioned in the previous section.
The `black` style is not a 1:1 with any `wrap-and-sort`. If you migrate to the `black` style, then
your CI and ideally your contributors should also be using `debputy reformat` instead of `wrap-and-sort`.

## Batch reformatting for CI or other automated processing

If you want to use `debputy reformat` from a CI pipeline, you may want to consider the options:

 * `--no-auto-fix` option is generally desired as it will have `debputy reformat` output a
   unified diff to standard out (the log). Without this option, `debputy reformat` will just
   reformat the files inline. However, if the CI job does not commit and push those changes,
   the changes will be lost. With `--no-auto-fix`, the changes needed to fix the formatting
   will at least be visible in the CI log.

 * `--style black` can be useful if you always want the `black` style without any divergence.

 * `--supported-style-is-required` / `--unknown-or-unsupported-style-is-ok` can be used to determine
   how `debputy reformat` reacts to packages without a known or supported formatting style. This can
   be useful if the CI job is generic and applied to multiple packages.

 * `--no-linter-exit-code` / `--linter-exit-code`: Whether `debputy reformat` should have a non-zero
   exit status if the current style does not match the desired style.

## Batch reformatting via pre-commit

An example pre-commit hook is provided in https://salsa.debian.org/debian/debputy-pre-commit-hooks

# Editor assistance (LSP)

To enable the full feature set of `debputy`, you can use the LSP integration of your editor. Generally,
each editor has their own way to configure a language server. The `debputy` tool contains a set of
examples for various editors via the `debputy lsp editor-config` that might be helpful. Otherwise,
you will have to consult your editor documentation for how to do it.

In general, the editor will need to know how to run `debputy` with the "stdio" communication mode.
The base command you need is `debputy lsp server`. You may also need `--ignore-language-ids` option
depending on the editor.

[how-to guide]: https://documentation.divio.com/how-to-guides/
[debputy issue tracker]: https://salsa.debian.org/debian/debputy/-/issues
