Skip to content

Latest commit

 

History

History
249 lines (200 loc) · 9.75 KB

cEP-0005.md

File metadata and controls

249 lines (200 loc) · 9.75 KB

coala Configuration

Metadata
cEP 5
Version 2.0
Title coala Configuration
Authors Lasse Schuirmann lasse.schuirmann@gmail.com
Status Implementation Due
Type Feature

Problem

One main pain point for our users is that coala is hard to configure. It tries to provide full options to a full set of tools. At the same time we try to provide an abstraction over the tools by e.g. giving the same setting names to similar bears across languages so the user can reuse the same configuration for other languages too.

By integrating lots of different existing tools with coala we have gained a huge set of possible analysis but it makes it very hard to understand and configure without knowledge about a particular tool. Also the conflict of bears versus linter bears that effectively offer multiple "checks" or sets of analyses rises: it is confusing to have to use multiple bears for one language for a set of analyses that is provided by only one bear for another language.

Other problems of the configuration file are, that some duplication is involved, especially when dealing with settings that are used for file collection.

Proposal

One important aspect of coala and its usability is that the configuration of a new language is as easy as possible. There should be no learning involved. Naturally, one very good aspect of a good configuration would be that it can be used for a new language without changing anything. Also, namespaces are a honking great idea and explicit is better than implicit.

The following changes are proposed and illustrated in the mockup following this paragraph:

  • Implicit default section inheritance will be removed. (It will be kept with warning for some time to allow people to do the switch.)
  • Explicit inheritance is possible by giving sections namespaces (all.python would inherit from the all section.)
  • Values can be added to inherited values. E.g. ignore += ./vendor would take the inherited value and add , ./vendor to it. Note that additions within a section will not be possible! The configuration should describe a state and not a program and must remain flow insensitive.
  • To specify, what analysis should be run the user will not have to care about bears. Instead, an aspects setting will be provided allowing the user to specify what aspects of their code should be analyzed. Aspects could be spelling or smells and are namespaced such that redundancy.clones will be possible as well. Aspects can be defined inclusive (analyze those aspects, with the aspects settings) or exclusive (analyze all but those aspects, with the ignore_aspects setting).
  • Specifying bears manually will still be possible as it eases use especially for bear developers.

Mockup

The following is a mockup of how a configuration could look like.

[all]
# Values can be added to inherited ones only, not within the section because
# a configuration should describe a state and not involve operations.
# A system wide coafile can define venv, .git, ... and we would recommend to
# always use += for ignore even in the default section to inherit those values.
# += always concatenates with a comma.
ignore += ./vendor

max_line_length = 80

# This inherits all settings from the `all` section. There is no implicit
# inheritance.
[all.python]
language = Python
files = **.py
aspects = smell, redundancy.clone  # Inclusive

[all.c]
language = C
files = **.(c|h)
ignore_aspects = redundancy  # Exclusive

Bear API

Bears will receive the aspects that should be checked as a parameter and results will get metadata to indicate what aspect has been checked.

from coalib.bears.LocalBear import LocalBear
from coalib.results.Result import Result
from coalib.bearlib.aspects import Root


class RedundancyBear(LocalBear):
    # coala will run bears based on this metadata
    LANGUAGES = {"C", "Python"}
    # This bear is supposed to be able to fix unused imports...
    FIX_ASPECTS = {Root.Redundancy.UnusedImport}
    # ... and detect code clones.
    DETECT_ASPECTS = {Root.Redundancy.Clone}

    # Aspects are passed as parameter
    def run(self, filename, file, aspects):
        # No documentation required anymore for the bears.

        if unused_imports(file):
            # A bear may yield results for any aspect even if it's not selected.
            # coala will filter out only selected aspects.
            yield Result.from_values(aspect=Root.Redundancy.UnusedImport, ...)

        # Bears can save performance by only performing needed checks
        aspect = aspects.get(Root.Redundancy.Clone, False)
        if aspect:
            # Bears can access settings right from the aspect instance
            min_clone_tokens = aspect.min_clone_tokens

            # The aspect is tied to the result. coala now knows everything from
            # the aspect documentation!
            yield Result.from_values(aspect=aspect, ...)

The concept of aspects allows us to implement a consistency check and reduce documentation redundancy. Instead of documenting settings and results in every bear, we can create a new aspects class. A working implementation of the aspects concept is available here.

An aspect can be defined as follows:

from coalib.bearlib.aspects import Root


@Root.subaspect  # Every aspect is inherited from Root
class Metadata:  # The description can be given as a documentation comment
    """
    This describes any aspect that is related to metadata that is not your
    source code.
    """


@Metadata.subaspect  #  Now we can build a tree of aspects
class CommitMessage:
    """
    Your commit message is important documentation associated with your
    source code. It can help you to identify bugs (e.g. through
    `git bisect`) or find missing information about unknown source code
    (through `git blame`).

    Commit messages are also sometimes used to generate - or write
    manually - release notes.
    """


@CommitMessage.subaspect
class Shortlog:
    """
    Your commit shortlog is the first line of your commit message. It is the
    most crucial part and summarizes the change in the shortest possible manner.
    """

# This is a leaf of the tree! It has to be well documented and bears will only
# implement leaves. However, users may use just Metadata.Shortlog to check for
# groups of aspects. This simplifies browsing aspect documentation:
#
# Whether the user wants to see/configure aspects precisely or roughly, he can
# just go deeper into the tree as needed.
@Shortlog.subaspect
class ColonExistence:
    """
    Some projects force you to use colons in the commit message shortlog (first
    line).
    """
    class docs:
        example = """
        FIX: Describe change further
        context: Describe change further
        """
        example_language = "English"
        importance_reason = """
        The colon can be a useful separator for a context (e.g. a filename) so
        the commit message makes more sense to the reader or a classification
        (e.g. FIX, ...) or others. Some projects prefer not using colons
        specifically: consistency is key.
        """
        fix_suggestions = """
        Add or remove the colon according to the commit message guidelines.
        """

    def style_paragraph(self):
        if self.shortlog_colon:
            return """
            Your commit message must have a colon. You can use the colon to
            give your commit message some context, for example::

                coafile: Add colon shortlog check
            """
        else:
            return """
            Your commit message must not contain a colon. A colon interrupts
            the readability of your commit message::

                Removed colon shortlog check in coafile

            This allows your commit messages to resemble natural language
            more closely.
            """

    def result_message(self):
        if self.shortlog_colon:
            return "Missing colon in commit message shortlog."
        else:
            return "Colon found in commit message shortlog."

    shortlog_colon = Setting[bool](
        "Whether or not the shortlog has to contain a colon.",
        (True, False), default=True)

This allows to show more information in results. Bears can give a custom result message; however, by default the message can be generated from the settings of the aspects with the result_message function.

Aspects can also define a style_paragraph function that returns a small paragraph describing how the user should write their source code according to the given settings. This will be used to generate a full style definition from a coala configuration.

Bears are expected to use all of the settings they get via the aspects.

Implementation

The implementation will have to be two phased as we should ideally deprecate the old way of using bears, keep it around for few releases and then phase it out and remove unneeded source code.

Gathering Metadata

To get all bears for a set of aspects, all bears will have to be collected. It can then be filtered against its metadata to get only bears that analyze the given aspects. This information should be cached to improve the performance.

If multiple bears provide the same aspects a debug message should be emitted so developers consider removing the aspects from one of the bears and the bear to run will be chosen depending on alphabetical order.