Skip to content
This documentation applies to Codacy Self-hosted v1.4.0

For the latest updates and improvements, see the latest Cloud documentation instead.

Tool Developer Guide

Integrate an external tool on Codacy

By creating a docker and writing code to handle the tool invocation and output, you can integrate the tool of your choice on Codacy!

To know more about dockers, and how to write a docker file please refer to https://docs.docker.com/reference/builder/

We use external tools at Codacy; in this tutorial, we explain how you can integrate the tool of your choice with our platform.

You can check the code of an already implemented tool and, if you wish, fork it to start yours. You are free to modify it and use it for your integration.

We also have a tutorial to integrate your tool using our Scala templates.

Requirements

  • Docker definition with the tool you want to integrate
  • Define the documentation for the patterns provided by the tool

Assumptions and Behaviour

  • To run the tool we provide the configuration file, /src/.codacy.json, with the files you should analyse and also the patterns you should check.
  • The files to analyse are located in /src, meaning that when provided in the configuration, the paths are relative to /src.

.codacy.json

  • files: Files to be analysed (their path is relative to /src)
  • tools: Array of tools *
    • name: Unique identifier of the tool
    • patterns: Array of patterns that must be checked
      • patternId: Unique identifier of the pattern
      • parameters: Parameters of the pattern
        • name: Unique identifier of the parameter
        • value: Value to be used as parameter value

.codacy.json

    {
      "files" : ["foo/bar/baz.js", "foo2/bar/baz.php"],
      "tools":[
        {
          "name":"jshint",
          "patterns":[
            {
              "patternId":"latedef",
              "parameters":[
                {
                  "name":"latedef",
                  "value":"vars"
                }
              ]
            }
          ]
        }
      ]
    }

If /src/.codacy.json does not exist or any of its contents (files or patterns) is not available, you should invoke the tool for all files from /src (files should be searched recursively for all folders in /src) and check them with the default patterns.

  • When receiving /src/.codacy.json, you should only run your tool for the subset of files in files, and for the patterns present on patterns for your tool name.

Setup

1. Write the docker file that will run the tool. It must have a binary entry point without any parameters. 

2. Write a patterns.json with the configuration of your tool. This file must be located on /docs/patterns.json.

  • name: Unique identifier of the tool (lower-case letters without spaces)

  • patterns: The patterns that the tool provides

    • patternId: Unique identifier of the pattern (lower-case letters without spaces)

    • level: Severity level of the issue *

    • category: Category of the issue *

    • parameters: Parameters received by the pattern

      • name: Unique identifier of the parameter (lower-case letters without spaces)
      • default: Default value of the parameter

patterns.json

    {
      "name":"jshint",
      "patterns":[
        {
          "patternId":"latedef",
          "level": "Error",
          "category": "UnusedCode",
          "parameters":[
            {
              "name":"latedef",
              "default":"vars"
            }
          ]
        }
      ]
    }

Levels and Categories

For level types we have:

  • Error, Warning, Info

For category types we have:

  • ErrorProne, CodeStyle, UnusedCode, Security, Compatibility, Performance, Documentation

3. Write the code to run the tool.

You are free to write this code in the language you want. Here you have to invoke the tool according to the configuration.

After you have your results from the tool, you should print them to the standard output in our Result format, one result per line.

The filename should not include the prefix "/src/"

Example

absolute path: /src/folder/file.js filename path: folder/file.js

    {
      "filename":"codacy/core/test.js",
      "message":"found this in your code",
      "patternId":"latedef",
      "line":2
    }

If you are not able to run the analysis for any of the files requested you should return an error for each one of them to the standard output in our Error format.

Error

    {
      "filename":"codacy/core/test.js",
      "message":"could not parse the file",
    }

Documentation

At Codacy we strive to provide the best value to our users and, to accomplish that, we document our patterns so that the user can better understand the problem and fix it.

At this point, your tool has everything it needs to run, but there is one other really important thing that you should do before submitting your docker: the documentation for your tool.

Your files for this section should be placed in /docs/description/.

In order to provide more details you can create:

  • A single /docs/description/description.json
  • [Optional] A /docs/description/<PATTERN-ID>.md for each pattern

In the description.json you define the title for the pattern, brief description, time to fix (in minutes), and also a description of the parameters in the following format:

description.json

    [
      {
        "patternId":"latedef",
        "title":"This is a title",
        "description":"This is a description",
        "timeToFix": 5,
        "parameters":[
          {
            "name":"latedef",
            "description":"this is a param description"
          }
        ]
      }
    ]

[Optional] To give a more detailed explanation about the issue, you should define the <PATTERN-ID>.md

UnusedModifier.md

    Fields in interfaces are automatically public static final, and methods are public abstract.
    Classes or interfaces nested in an interface are automatically public and static (all nested interfaces are automatically static).

    For historical reasons, modifiers which are implied by the context are accepted by the compiler, but are superfluous.

    Ex:

        public interface Foo {
            public abstract void bar();         // both abstract and public are ignored by the compiler
            public static final int X = 0;         // public, static, and final all ignored
            public static class Bar {}             // public, static ignored
            public static interface Baz {}         // ditto

            void foo();                            //this is correct
        }

        public class Bar {
            public static interface Baz {} // static ignored
        }

    [Source](http://pmd.sourceforge.net/pmd-5.3.2/pmd-java/rules/java/unusedcode.html#UnusedModifier)

You should explain the *what* and *why* of the issue. Adding an example
is always a nice way to help other people understand the problem. For a
more thorough explanation you can also add a link at the end referring a
more complete source.
``` 

## Tests

After all the docker is prepared you can now test your work.

To do it you should write test files and place them in **/docs/tests**,
for example for PHP, **/docs/tests/UnusedModifier.php**.

Each test is composed by two parts.

- Identification of the patterns on the file
- Identification of the errors on the file

The pattern identification is placed in the beginning of the file in the following format:

- &lt;LANGUAGE\_COMMENT&gt;\#Patterns:
  &lt;PATTERN\_ID&gt;,&lt;PATTERN\_ID&gt;,...

The error identification is placed in the line before the error should happen:

- &lt;LANGUAGE\_COMMENT&gt;\#&lt;ERROR\_LEVEL&gt;: &lt;PATTERN\_ID&gt;

Instead of commenting in the line before the error, you can alternatively specify the line of the warning with this syntax:

- &lt;LANGUAGE\_COMMENT&gt;\#Issue: {"severity":
  "&lt;ERROR\_LEVEL&gt;", "line": &lt;LINE\_NUMBER\_WITH\_ISSUE&gt;,
  "patternId": "PATTERN\_ID"}


UnusedModifier.php
```php
    //#Patterns: UnusedModifier
    public interface Foo {
       //#Warn: UnusedModifier
       public abstract void bar();         // both abstract and public are ignored by the compiler
       //#Warn: UnusedModifier
       public static final int X = 0;         // public, static, and final all ignored
       //#Warn: UnusedModifier
       public static class Bar {}             // public, static ignored
       //#Warn: UnusedModifier
       public static interface Baz {}         // ditto

       void foo();
    }

    public class Bar {
       //#Warn: UnusedModifier
       public static interface Baz {} // static ignored
    }

To run this use our test repository available here.

You just need the docker image built in your local repo and then follow the steps to run it.

Submit the Docker

Running the docker

docker run -t \\
--net=none \\
--privileged=false \\
--cap-drop=ALL \\
--user=docker \\
--rm=true \\
-v &lt;PATH-TO-FOLDER-WITH-FILES-TO-CHECK&gt;:/src:ro \\

&lt;YOUR-DOCKER-NAME&gt;:&lt;YOUR-DOCKER-VERSION&gt;

Docker restrictions

  • Docker image size should not exceed 500MB
  • Docker should contain a non-root user named docker with UID/GID 2004
  • All the source code of the docker must be public
  • The docker base must officially be supported on DockerHub
  • Your docker must be provided in a repository through a public git host (ex: GitHub, Bitbucket, ...)

Docker submission

  • To submit the docker you should send an email to support@codacy.com with the link to the git repository with your docker definition.
  • The docker will then be subjected to a review by our team and we will then contact you with more details.

If you have any question or suggestion regarding this guide please contact us.

Share your feedback 📢

Did this page help you?

Thanks for the feedback! Is there anything else you'd like to tell us about this page?

We're sorry to hear that. Please let us know what we can improve:

Alternatively, you can create a more detailed issue on our GitHub repository.

Thanks for helping improve the Codacy documentation.

If you have a question or need help please contact support@codacy.com.

Last modified April 2, 2020