# Contributors Guide

Thank you for considering contributing to the maintenance or development of
pantry! We hope that the following information will encourage and assist you. We
start with some advice about pantry's governance.

## pantry's governance

People involved in maintaining or developing pantry with rights to make commits
to the repository can be classified into two groups: 'committers' and
'maintainers'.

### pantry's committers

We encourages a wide range of people to be granted rights to make commits to the
repository.

People are encouraged to take initiative to make non-controversial changes, such
as documentation improvements, bug fixes, performance improvements, and feature enhancements.

Maintainers should be included in discussions of controversial changes and
tricky code changes.

Our general approach is **"it's easier to ask forgiveness than permission"**. If
there is ever a bad change, it can always be rolled back.

### pantry's maintainers

pantry's maintainers are long-term contributors to the project. Michael Snoyman
(@snoyberg) was the founder of pantry, and its initial maintainer - and he has
added others. Michael's current interests and priorities mean that he is no
longer actively involved in adding new features to pantry.

Maintainers are recognized for their contributions including:

* Direct code contribution
* Review of pull requests
* Interactions on the GitHub issue tracker

The maintainer team make certain decisions when that is necessary, specifically:

* How to proceed, if there is disagreement on how to do so on a specific topic
* Whether to add or remove (see further below) a maintainer

Generally, maintainers are only removed due to non-participation or actions
unhealthy to the project. Removal due to non-participation is not a punishment,
simply a recognition that maintainership is for active participants only.

We hope that removal due to unhealthy actions will never be necessary, but would
include protection for cases of:

* Disruptive behavior in public channels related to pantry
* Impairing the codebase through bad commits/merges

Like committers, maintainers are broadly encouraged to make autonomous
decisions. Each maintainer is empowered to make a unilateral decision. However,
maintainers should favor getting consensus first if:

* They are uncertain what is the best course of action
* They anticipate that other maintainers or users of pantry will disagree on the
  decision

## Bug Reports

Please [open an issue](https://github.com/commercialhaskell/pantry/issues/new)
and use the provided template to include all necessary details.

The more detailed your report, the faster it can be resolved and will ensure it
is resolved in the right way. Once your bug has been resolved, the responsible
person will tag the issue as _Needs confirmation_ and assign the issue back to
you. Once you have tested and confirmed that the issue is resolved, close the
issue. If you are not a member of the project, you will be asked for
confirmation and we will close it.

## Error messages

To support the Haskell Foundation's
[Haskell Error Index](https://errors.haskell.org/) initiative, all pantry
error messages generated by pantry itself should have a unique initial line:

~~~text
Error: [S-nnn]
~~~

where `nnn` is a three-digit number in the range 100 to 999.

If you create a new pantry error, select a number using a random number
generator (see, for example, [RANDOM.ORG](https://www.random.org/)) and check
that number is not already in use in pantry's code. If it is, pick another until
the number is unique.

All exceptions generated by pantry itself are implemented using data
constructors of closed sum types. Typically, there is one such type for each
module that exports functions that throw exceptions.

## Code

If you would like to contribute code to fix a bug, add a new feature, or
otherwise improve pantry, pull requests are most welcome. It's a good idea to
[submit an issue](https://github.com/commercialhaskell/pantry/issues/new) to
discuss the change before plowing into writing code.

Please include a
[ChangeLog](https://github.com/commercialhaskell/pantry/blob/master/ChangeLog.md)
entry with your pull request.

## Code Quality

The pantry project uses [yamllint](https://github.com/adrienverge/yamllint) as a
YAML file quality tool and [HLint](https://github.com/ndmitchell/hlint) as a
code quality tool.

### Linting of YAML files

The yamllint configuration extends the tools default and is set out in
`.yamllint.yaml`. In particular, indentation is set at 2 spaces and `- ` in
sequences is treated as part of the indentation.

### Linting of Haskell source code

The HLint configurations is set out in `.hlint.yaml`.

pantry contributors need not follow dogmatically the suggested HLint hints but
are encouraged to debate their usefulness. If you find a HLint hint is not
useful and detracts from readability of code, consider marking it in the
[configuration file](https://github.com/commercialhaskell/pantry/blob/master/.hlint.yaml)
to be ignored. Please refer to the
[HLint manual](https://github.com/ndmitchell/hlint#readme)
for configuration syntax.

We are optimizing for code clarity, not code concision or what HLint thinks.

You can install HLint with Stack. You might want to install it in the global
project in case you run into dependency conflicts. HLint can report hints in
your favourite text editor. Refer to the HLint repository for more details.

To install, command:

~~~text
stack install hlint
~~~

## Code Style

A single code style is not applied consistently to pantry's code and pantry is
not Procrustean about matters of style. Rules of thumb, however, are:

* keep pull requests that simply reformat code separate from those that make
  other changes to code; and
* when making changes to code other than reformatting, follow the existing style
  of the function(s) or module(s) in question.

That said, the following may help:

* pantry's code generally avoids the use of C preprocessor (CPP) directives.
  Windows and non-Windows code is separated in separate source code directories
  and distinguished in pantry's Cabal file. Multi-line strings are generally
  formatted on the assumption that GHC's `CPP` language pragma is not being
  used.
* Language pragmas usually start with `NoImplictPrelude`, where applicable, and
  then all others are listed alphabetically. The closing `#-}` are aligned, for
  purely aesthetic reasons.
* pantry is compiled with GHC's `-Wall` enabled, which includes `-Wtabs` (no
  tabs in source code). Most modules are based on two spaces (with one space for
  a `where`) for indentation but older and larger modules are still based on
  four spaces.
* pantry's code and documentation tends to be based on lines of no more than 80
  characters or, if longer, no longer than necessary.
* pantry uses export lists.
* pantry's imports are listed alphabetically. The module names are left aligned,
  with space left for `qualified` where it is absent.
* pantry's code is sufficiently stable that explict import lists can sensibly be
  used. Not all modules have comprehensive explicit import lists.
* Short explicit import lists follow the module name. Longer lists start on the
  line below the module name. Spaces are used to separate listed items from
  their enclosing parentheses.
* In function type signatures, the `::` is kept on the same line as the
  function's name. This format is Haskell syntax highlighter-friendly.
* If `where` is used, the declarations follow on a separate line.

## Continuous integration (CI)

We use [GitHub Actions](https://docs.github.com/en/actions) to do CI on pantry.
The configuration of the workflows is in the YAML files in `.github/workflows`.
The current active workflows are:

### Linting - `lint.yml`

This workflow will run if:

* there is a pull request
* commits are pushed to this branch: `master`

The workflow has one job (`style`). It runs on `ubuntu` only and applies
yamllint and Hlint.

### Stan tool - `stan.yml`

[Stan](https://hackage.haskell.org/package/stan) is a Haskell static analysis
tool. As of `stan-0.1.0.1`, it supports GHC >= 9.6.3. The tool is configured by
the contents of the `.stan.toml` file.

This workflow will run if:

* there is a pull request
* requested

## Haskell Language Server

You may be using [Visual Studio Code](https://code.visualstudio.com/) (VS Code)
with its
[Haskell extension](https://marketplace.visualstudio.com/items?itemName=haskell.haskell),
which is powered by the
[Haskell Language Server](https://github.com/haskell/haskell-language-server)
(HLS).

pantry can be built with Stack (which is recommended) or with Cabal (the tool).

=== "Stack"

    If you use Stack to build Stack, command `stack ghci` in the root directory
    of the pantry project should work as expected, if you have first commanded
    `stack build` once.

    `ghc` should be on the PATH if you run VS Code itself in the Stack
    environment:
    ~~~text
    stack exec -- code .
    ~~~

    The following [cradle (`hie.yaml`)](https://github.com/haskell/hie-bios)
    should suffice to configure Haskell Language Server (HLS) explicitly for
    each of the buildable components in pantry's Cabal file:
    ~~~yaml
    cradle:
      stack:
      - path: "./src"
        component: "pantry:lib"
      - path: "./int"
        component: "pantry:lib"
      - path: "./app"
        component: "pantry:exe:test-pretty-exceptions"
      - path: "./test"
        component: "pantry:test:spec"
    ~~~

=== "Cabal (the tool)"

    If you use Cabal (the tool) to build Stack, command `cabal repl` in the root
    directory of the Stack project should work as expected, if you have GHC and
    (on Windows) MSYS2 on the PATH.

    `ghc` and (on Windows) MSYS2 should be on the PATH if you run commands
    (including `cabal`) in the Stack environment:
    ~~~text
    stack exec --no-ghc-package-path -- cabal repl
    ~~~

    or
    ~~~text
    stack exec --no-ghc-package-path -- code .
    ~~~

    Use of GHC's environment variable `GHC_PACKAGE_PATH` is not compatible with
    Cabal (the tool). That is why the `--no-ghc-package-path` flag must be
    specified with `stack exec` when relying on Cabal (the tool).

    The following [cradle (`hie.yaml`)](https://github.com/haskell/hie-bios)
    should suffice to configure Haskell Language Server (HLS) explicitly for
    each of the buildable components in pantry's Cabal file:
    ~~~yaml
    cradle:
      cabal:
      - path: "./src"
        component: "lib:pantry"
      - path: "./int"
        component: "lib:pantry"
      - path: "./app"
        component: "exe:test-pretty-exceptions"
      - path: "./test"
        component: "test:spec"
    ~~~

A cradle is not committed to pantry's repository because it imposes a choice of
build tool.

## Slack channel

If you're making deep changes and real-time communication with the pantry team
would be helpful, we have a `#stack-collaborators` Slack channel in the
Haskell Foundation workspace. To join the workspace, follow this
[link](https://haskell-foundation.slack.com/join/shared_invite/zt-z45o9x38-8L55P27r12YO0YeEufcO2w#/shared-invite/email).

## Matrix room

There is also a
[Stack and Stackage room](https://matrix.to/#/#haskell-stack:matrix.org)
at address `#haskell-stack:matrix.org` on [Matrix](https://matrix.org/).
