Skip to content

Latest commit

 

History

History
87 lines (64 loc) · 8.51 KB

CONTRIBUTING.md

File metadata and controls

87 lines (64 loc) · 8.51 KB

Contributing Guidelines

In this document you will find a detailed description of how to add new functionality to Hyperstyle.

Contents

  1. Adding a new inspector for an existing language.
  2. Adding a new inspector for a new language.

Adding a new inspector for an existing language

If you want to add a new inspector for an existing language, you need to:

  1. Inherit from the BaseInspector class.
  2. Define the inspector_type property. To do this, you need to update the InspectorType class by adding there a name of the inspector.
  3. Implement the inspect function, which should run an analysis of the language and return a list of found issues;

Usually the inspector runs a third-party linter through a command line and parses its result. In this case it will be useful to implement several auxiliary functions:

  1. create_command – creates a command to run the linter via subprocess.
  2. parse – parses the linter's result and returns the list of found issues. For more details about the implementation of this function, see this section.
  3. choose_issue_type – selects an issue type by its origin class. This function usually uses the ORIGIN_CLASS_TO_ISSUE_TYPE dictionary, stored next to the inspector, to select the issue type. Also the ORIGIN_CLASS_PREFIX_TO_ISSUE_TYPE dictionary can sometimes be useful to determine the type of groups of issues.

Usually the third-party linter needs a configuration file to run. This file should be stored next to the inspector.

An example of inspectors that are implemented in such a way: PMDInpsector, GolangLintInspector, Flake8Inspector.

If the inspector does not need the third-party linter (for example, if the inspector works with a code directly), then the above functions are not necessary. In this case, each such inspector is implemented uniquely. Currently, only one inspector of this kind is implemented in Hyperstyle: PythonAstInspector.

After implementing all the necessary functions, you need to add the inspector instance to the LANGUAGE_TO_INSPECTORS dictionary, and update the main README file with a mention of the new inspector there.

If you are implementing the inspector that uses the third-party linter, you must also update the Dockerfile with necessary environment variables and commands to install the linter, and update the README file and the setup_environment.sh script in the same way.

Implementation of the parse function

Usually, the parse function parses the result of the third-party linter line-by-line, then creates a base issue using the BaseIssue dataclass, which is later converted to either CodeIssue or one of the measurable issues using the convert_base_issue function and an instance of the IssueConigsHandler class. The resulting issue is added to the general list of found issues and this list is returned from the function after the parsing is finished.

The IssueConfigHandler class handles custom issue descriptions and also parses metrics from their descriptions (examples of metrics are: line or function length, cyclomatic complexity, maintainability index). It receives instances of IssueConfig or MeasurableIssueConfig classes as input, which should be stored in the ISSUE_CONFIGS list next to the inspector.

Also, if the third-party linter supports output in "Checkstyle" format, you can use the parse_xml_file_result function to parse the output file.

Checklist

A sample checklist for adding a new inspector looks like this:

  • I've inherited from the BaseInspector class.
  • I've implemented the inspect function and if needed I've added a check for the existence of third-party linter environment variables using the check_set_up_env_variable function.
  • I've added a new inspector type to the InspectorType class, updated the available_values function and defined the inspector type.
  • If needed. I've added a config to run the third-party linter.
  • If needed. I've implemented the create_command function.
  • if needed. I've implemented the parse function and defined the ISSUES_CONFIGS list in a separate file.
  • If needed. I've implemented the choose_issue_type function and defined the ORIGIN_CLASS_TO_ISSUE_TYPE dictionary in a separate file.
  • I've added an instance of the new inspector to the LANGUAGE_TO_INSPECTORS dictionary.
  • I've updated the main README file:
    • I've added an information about the new inspector.
    • I've updated a description of the --disable flag.
    • If needed. I've added an information about the new linter environment variables.
    • If needed. I've added a command to manually install the third-party linter.
  • If needed. I've updated the Dockerfile with the new linter environment variables and commands to install the third-party linter.
  • I've added tests to check the inspector:
    • If needed. The linter's output parsing is working correctly.
    • If needed. The issue categorization is working correctly.
    • The total number of issues from a source code is collected correctly.
    • The number of issues of each type from a source code is collected correctly.
    • If needed. Metric issues are parsed correctly.
    • If needed. Custom issues descriptions are added correctly.

Adding a new inspector for a new language

Before you can add a new inspector, you must add support for a new language to Hyperstyle. To do this, you must do the following:

  1. Add a new language in the Language class.
  2. Add a version of the new language in the LanguageVersion class.
  3. Add file extensions of the new language in the Extension class.
  4. Define configurations for the new language in the rules module.
  5. Add an entry for the new language in the language_to_reviewer dictionary.
  6. Install all necessary files for the new language in the base.Dockerfile.

Next, use the "Adding a new inspector for an existing language" guideline.

Checklist

A sample checklist for adding a new linter looks like this:

  • I've added a new language to the Language class, updated the from_language_version function and the EXTENSION_TO_LANGUAGE dictionary.
  • I've added a version of the new language to LanguageVersion.
  • I've added new language file extensions to the Extensions class and updated the language_to_extension_dict dictionary.
  • I've defined rule configs for the new language.
  • I've added functional tests for the new language.
  • I've installed all necessary files for the new language in the base.Dockerfile.

And all the items from the "Adding a new inspector for an existing language" checklist.