.. _flycheck-contributors-guide:

=====================
 Contributor’s Guide
=====================

Thank you very much for your interest in contributing to Flycheck! We’d like to
warmly welcome you in the Flycheck community, and hope that you enjoy your time
with us!

There are many ways to contribute to Flycheck, and we appreciate all of them. We
hope that this document helps you to contribute. If you have questions, please
ask on our `issue tracker`_.

For a gentle start please take a look at all the things we `need your help
with`_ and look for `beginner-friendly tasks`_.

Please note that all contributors are expected to follow our :ref:`Code of
Conduct <flycheck-conduct>`.

.. _issue tracker: https://github.com/flycheck/flycheck/issues
.. _need your help with: https://github.com/flycheck/flycheck/issues?q=is%3Aissue+is%3Aopen+label%3A%22needs+help%22
.. _beginner-friendly tasks: https://github.com/flycheck/flycheck/labels/beginner%20friendly

.. _flycheck-bug-reports:

Bug reports
===========

Bugs are a sad reality in software, but we strive to have as few as possible in
Flycheck. Please liberally report any bugs you find. If you are not sure whether
something is a bug or not, please report anyway.

If you have the chance and time please `search existing issues`_, as it’s
possible that someone else already reported your issue. Of course, this doesn’t
always work, and sometimes it’s very hard to know what to search for, so this is
absolutely optional. We definitely don’t mind duplicates, please report
liberally.

To open an issue simply fill out the `issue form`_. To help us fix the issue,
include as much information as possible. When in doubt, better include too much
than too little. Here’s a list of facts that are important:

* What you did, and what you expected to happen instead
* Whether and how you were able to `reproduce the issue in emacs -Q`_
* Your Flycheck setup from ``M-x flycheck-verify-setup``

.. _search existing issues: https://github.com/flycheck/flycheck/issues?q=is%3Aissue
.. _issue form: https://github.com/flycheck/flycheck/issues/new
.. _reproduce the issue in emacs -Q: https://emacs.stackexchange.com/questions/28429/how-do-i-troubleshoot-emacs-problems


.. _flycheck-windows-issues:

Windows-only issues
-------------------

As Flycheck does not support Windows officially we generally do *not* attempt to
fix issues that only occur on Windows. We will move all Windows-only issues to
the `list of open Windows issues`_, and leave them to Windows users and
developers.

We welcome anyone who wants to fix open Windows issues, and we will merge pull
requests for improved Windows compatibility. If you know Windows and Emacs,
please take a look at the list of open Windows issues and try to fix any of
these.

.. _list of open Windows issues: https://github.com/flycheck/flycheck/labels/arch%3A%20windows%20only

Feature requests
================

To request a new feature please open a new issue through our `issue form`_.
A feature request needs to find a core developer or maintainer who adopts and
implements it.

The build system
================

Flycheck provides a :file:`Makefile` with some convenient targets to compile and
test Flycheck.  The Makefile requires Eask_, the Emacs Lisp dependency manager.
Run ``make help`` to see a list of all available targets.  Some common ones are:

- ``make init`` initialises the project by installing local Emacs Lisp
  dependencies.
- ``make check`` checks all Emacs Lisp sources.
- ``make compile`` compiles Flycheck and its libraries to byte code.
- ``make specs`` runs all Buttercup_ specs for Flycheck.  Set :makevar:`PATTERN`
  to run only specs matching a specific regular expression, e.g. ``make
  PATTERN='^Mode Line' specs`` to run only tests for the mode line.

.. _Eask: https://emacs-eask.github.io/
.. _Buttercup: https://github.com/jorgenschaefer/emacs-buttercup

.. _flycheck-recorded-output:

Testing a checker without its tool
==================================

Most of the tools Flycheck drives are not installed on any given machine, and
a spec that needs a missing tool skips itself.  That keeps the suite runnable
everywhere, but it also means a checker can stop working without a single test
going red.

So the part that usually breaks — reading the tool's output — is tested against
output recorded earlier, which needs nothing installed:

.. code-block:: console

   $ emacs -Q --batch -l test/record-fixture.el \
       -f flycheck-record-fixture-batch sh-shellcheck language/sh/shellcheck.sh

That runs the checker's own command, the one Flycheck would run, and writes what
the tool printed to :file:`test/fixtures/{checker}/{resource}.txt`.  A spec then
asserts what Flycheck reads back out of it:

.. code-block:: elisp

   (flycheck-buttercup-def-parse-test json-jq "language/json.json"
     '(1 44 error "Expected value before ','"))

Record the output on a machine that has the tool, commit it, and the spec runs
for everyone.  When a tool changes its format, re-record and the diff shows
exactly what moved.

:ref:`Testing your checker <flycheck-testing-a-checker>` in the developer's
guide covers this from the other end, for somebody adding a checker rather than
maintaining one, and lists the mistakes that keep being made.

The catch is that a recording says what the tool printed on the day it was
made, and the spec reading it keeps passing whatever the tool does afterwards.
``make verify-fixtures`` closes that: it runs the tools that are installed and
checks that Flycheck still reads errors out of them.

It deliberately does not compare the text.  A recording is made on somebody's
machine, and the same checker meets a different build of the tool elsewhere, so
comparing would report a difference every week until nobody read the report.
A checker that read errors when its output was recorded and reads none now has
stopped understanding its tool, which is what every one of these has looked
like: jq grew a prefix, rebar3 replaced its format, the byte compiler moved a
warning onto one line.

That target only reaches the tools the machine running it happens to have, so
there is a second one that runs the check inside the image described below:

.. code-block:: console

   $ make verify-fixtures-image

This reaches nearly every recording rather than the handful a given machine can
answer for, which is why it is the one the weekly job runs.  A pull request that
touches a recording gets the quicker, thinner check instead, so the answer
arrives while somebody is still looking at it.

Recording in bulk
-----------------

Nobody has all of Flycheck's checkers installed, so there is an image with as
many of them as is practical:

.. code-block:: console

   $ make record-fixtures

That builds :file:`test/docker/Dockerfile`, mounts your checkout into it, and
records every checker whose tool it has and whose spec names a file to check.
``make checker-shell`` drops you into the same container if you would rather
poke at a tool by hand.  The image is the current Ubuntu LTS, and the weekly
job runs inside it too, so what comes out of a recording session is what that
job later sees.

Recording in bulk will not write a recording that its own checker reads nothing
out of, because that is what a tool failing to start looks like: ``credo``
without a :file:`mix.exs`, the Go checkers without a module.  Those are
reported instead, and can be recorded by hand if the output really is what the
tool has to say.

Read what it wrote before committing it.  A recording nobody looked at is the
same trap as a spec that never ran.

Because your checkout is mounted rather than copied, anything a build on your
own machine left in it goes into the container too, and a tool that meets a
build artefact from a different version of itself can fail in ways that read
exactly like a checker that stopped understanding its tool.  A stale
:file:`_build` under the rebar3 resource is the one that has actually happened:
rebar3 could not read the ``.beam`` files a newer Erlang had written and died
before it compiled anything.  ``git clean -xfd test/resources`` before a run
that reports something surprising.

Pull requests
=============

Pull Requests are the primary mechanism to submit your own changes to
Flycheck. Github provides great documentation about `Pull Requests`_.

.. _Pull Requests: https://help.github.com/articles/using-pull-requests/

Please make your pull requests against the ``master`` branch.

Use ``make check specs unit`` to test your pull request locally. When making
changes to syntax checkers of a specific language, it’s also a good idea to run
:samp:`make LANGUAGE={language} integ` and check whether the tests for the
particular language still work.  A successful ``make integ`` is by no means
mandatory for pull requests, though, the continuous integration will test your
changes, too.

All pull requests go through a two-stage review process:

* :ref:`Maintainer <flycheck-maintainers>` review the general idea and direction
  of the pull request and leave a ``LGTM`` comment if they believe that the
  change is a good addition to Flycheck.  We currently require at least one
  approval from a maintainer.
* :ref:`All contributors <flycheck-language-teams>`—language teams in
  particular—check the technical implementation of a pull request through `pull
  request reviews`_, and either approve it or request changes.  We currently
  require at least one approval and no requested changes.

.. important::

   We have a comprehensive :ref:`flycheck-style-guide` that explains what
   features we will accept, how our code should look like, what tests we
   require, how commit messages should look like, and so on.

   Take a look at it to see what we look for in a code review.

Additionally all pull requests go through automated tests on `GitHub Actions`_
which check code style, run tests, etc.

Feel free to mention individual contributors or entire teams
(e.g. ``@flycheck/maintainers`` or ``@flycheck/javascript``) to ask for help or
feedback or request a review.  Please mention the maintainers
(``@flycheck/maintainers``) if you think that your pull request has been waiting
for review too long.  You can expect a first response to any pull request in a
couple of days.

Once the pull request passed review and automated tests we will merge it.  We
may also ask you whether you'd like to join Flycheck and help us, thus giving
you commit access to our repository and let you merge your own pull request.

.. _pull request reviews: https://help.github.com/articles/about-pull-request-reviews/
.. _GitHub Actions: https://github.com/flycheck/flycheck/actions

Writing documentation
=====================

Documentation improvements are very welcome.  Flycheck’s manual is written in
reStructuredText_ and built with Sphinx_.  The source of the manual resides in
the ``doc/`` directory.

You need Python 3.9 or newer to install Sphinx_ for Flycheck’s documentation.
On macOS it is recommended that you use Homebrew_ to install the latest Python
version with ``brew install python3``.  On Linux you should be able to obtain
Python 3 from the package manager of your distribution.

With Python 3 installed change into the ``doc/`` directory and run ``make init``
to install Sphinx and related tools required for Flycheck’s documentation.  We
recommend that you use a virtual environment to avoid a global installation of
Python modules.  ``make init`` will warn you if you do not.

When editing documentation run ``make html-auto`` to view the results of your
edits.  This target runs a local webserver at http://localhost:8000 which serves
the HTML documentation and watches the documentation sources for changes to
rebuild automatically.  When you have finished your edits it is a good idea to
run ``make linkcheck`` to verify all links in the documentation.  Note that this
target can take a while especially when run on a clean build.

Run ``make help`` to see a list of all available Make targets for the
documentation.

Documentation pull requests work in the same way as other pull requests.  To
find documentation issues sort by the `documentation`_ label.

.. _ReStructuredText: https://docutils.sourceforge.io/rst.html
.. _Sphinx: https://www.sphinx-doc.org
.. _Homebrew: https://brew.sh
.. _documentation: https://github.com/flycheck/flycheck/labels/documentation

Issue management
================

We use Github labels for basic issue management:

- **The red “bug” label denotes critical bugs in Flycheck that must be fixed
  urgently.**
- Violet labels describe the area of Flycheck the issue belongs to.
- The green “beginner friendly” label denotes easy tasks for newcomers to the
  project.
- Orange labels denote blockers.
- Grey labels indicate resolutions to issues.

Out of tree contributions
=========================

There are many ways that you can contribute to Flycheck that go beyond
this repository.

Answer questions on StackExchange_ or on our `issue tracker`_.

Participate in Flycheck discussions in other Emacs communities and help
users with troubles.

Write :ref:`extensions for Flycheck <flycheck-extensions>`.

.. _StackExchange: https://emacs.stackexchange.com/questions/tagged/flycheck

--------------

This contributing guide is heavily inspired by `Rust’s excellent
contributing
information <https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md>`__.
