VueJS+TS project integration with SonarQube

In our work, we actively use the platform Sonar Qube to maintain the quality of the code at a high level. When integrating one of the projects written in VueJs+Typescript, there are problems. Therefore, I would like to tell you more about how we managed to solve them.

VueJS+TS project integration with SonarQube

This article will focus, as I wrote above, on the SonarQube platform. A little theory - what it is in general, for those who hear about it for the first time:

Sonar Qube (former Sonar) is an open source platform for continuous inspection and code quality measurement.
Supports code analysis and error detection according to the rules of MISRA C, MISRA C++, MITER/CWE and CERT Secure Coding Standards. It also knows how to recognize errors from the OWASP Top 10 and CWE / SANS Top 25 programming errors lists.
Despite the fact that the platform uses various ready-made tools, SonarQube reduces the results to a single dashboard (English dashboard), keeping the history of runs and thus allowing you to see the overall trend in software quality during development.

More details can be found at the official website

A large number of programming languages ​​are supported. Judging by the information from the link above, these are more than 25 languages. To support a specific language, you must install the appropriate plugin. The community version includes a plugin for working with javascript (including typesscript), although the wiki says otherwise. Behind javascript plugin responds SonarJS, for Typescript SonarTS respectively.

An official client is used to send coverage information sonarqube-scanner, which, using the settings from config-file, sends this data to the server Sonar Qube for further consolidation and aggregation.

For javascript Yes npm wrapper. So, let's start the step-by-step implementation Sonar Qube в View- project using typescript.

For server deployment Sonar Qube use docker-compose.

sonar.yaml:

version: '1'
    services:
        simplesample-sonar:
            image: sonarqube:lts
            ports:
                - 9001:9000
                - 9092:9092
            network_mode: bridge

Run:

docker-compose -f sonar.yml up

Thereafter Sonar Qube will be available at - http://localhost:9001 .

VueJS+TS project integration with SonarQube
So far, there are no projects in it, and this is fair. We will correct this situation. As a basis, I took the official example project for VueJS+TS+Jest. Let's tilt it towards us:

git clone https://github.com/vuejs/vue-test-utils-typescript-example.git

First we need to install the client Sonar Qube, which is called sonar-scannerFor npm there is a wrapper:

yarn add sonarqube-scanner

And immediately add the command to scripts to work with him.

package.json:

{
 … 
   scripts: {
      ...
      "sonar": "sonar-scanner"
      ...
   },
 …
}

Next, for the scanner to work, you need to set the project settings in a special file. Let's start with the basics.

sonar-project.properties:

sonar.host.url=http://localhost:9001

sonar.projectKey=test-project-vuejs-ts
sonar.projectName=Test Application (VueJS+TS)

sonar.sources=src
# sonar.tests=
sonar.test.inclusions=src/**/*tests*/**
sonar.sourceEncoding=UTF-8

  • sonar.host.url - address Sonar'A;
  • sonar.projectKey – unique project identifier on the server Sonar'A;
  • sonar.projectName - its name, it can be changed at any time, since the project is identified by project key;
  • sonar.sources - source folder, usually src, but can be anything. This folder is relative to the root folder, which is the folder where the scanner is launched from;
  • sonar.tests - a parameter that is paired with the previous one. This is the folder where the tests are located. In this project, there is no such folder, and the test is located next to the component under test in the folder 'test', so we'll ignore it for now and use the next parameter;
  • sonar.test.inclusions – path for tests using a mask, there may be several elements separated by commas;
  • sonar.sourceEncoding – encoding for source files.

For the first launch of the scanner, everything is ready, except for the main previous action: launching the test engine itself, in order to generate information about the coverage, which the scanner will subsequently use.

But for this you need to configure the test engine to generate this information. In this project, the test engine is Jest. And its settings are in the corresponding section of the file package.json.

Let's add these settings:

"collectCoverage": true,
"collectCoverageFrom": [
      "src/**/*",
      "!src/main.ts",
      "!src/App.vue",
      "!src/**/*.d.*",
      "!src/**/*__tests__*"
],

That is, we set the flag itself for the need to calculate the coverage and the source (together with exceptions), on the basis of which it will be formed.

Now let's run the test:

yarn test

We will see the following:

VueJS+TS project integration with SonarQube

The reason is that there is no code in the component itself, as such. Let's fix this.

HelloWorld.vue:

...
methods: {
    calc(n) {
      return n + 1;
    }
  },
mounted() {
  this.msg1 = this.msg + this.calc(1);
},
...

This will be enough to calculate the coverage.

After restarting the test, make sure of this:

VueJS+TS project integration with SonarQube

On the screen, we should see coverage information, and a folder will be created in the project folder coverage with test coverage information in a universal format LCOV (LTP GCOV extension).

Gcov is a freely distributed utility for code coverage research. Gcov generates the exact number of executions for each statement in the program and allows you to add annotations to the source code. Gcov is supplied as a standard utility in the GCC package.
Lcov - GUI for gcov. It collects gcov files for several source files and creates a set of HTML pages with code and coverage information. Pages are also generated to make navigation easier. Lcov supports line, function, branch coverage.

After the tests are completed, the coverage information will be in coverage/lcov.info.
We need to say Sonar'Where to get it from. So let's add the following lines to its configuration file. But there is one point: projects can be multilingual, that is, in a folder src there are sources for several programming languages ​​and belonging to one or another, and, in turn, the use of a particular plugin is determined by its extension. And coverage information can be stored in different places for different programming languages, so each PL has its own section to configure this. Our project uses typescript, so we need a settings section for it:

sonar-project.properties:

sonar.typescript.coveragePlugin=lcov
sonar.typescript.lcov.reportPaths=coverage/lcov.info

Everything is ready for the first launch of the scanner. I would like to point out that the project Sonar'e is created automatically the first time you run the scanner for a given project. In subsequent times, the information will already be accumulated in order to see the dynamics of changes in project parameters over time.

So, let's use the command created earlier in package.json:

yarn run sonar 

Note: you can also use the option -X for more detailed logging.

If the scanner was launched for the first time, then the binary of the scanner itself will be downloaded first. After that it starts up and starts scanning the server Sonar'a for installed plugins, thereby calculating the supported PLs. It also loads other various options for it to work: quality profiles, active rules, metrics repository, server rules.

VueJS+TS project integration with SonarQube

VueJS+TS project integration with SonarQube

Note: we will not dwell on them in detail within the framework of this article, but you can always turn to official sources.

Next, the analysis of the folder begins src for the availability of source files for all (unless a specific one is explicitly specified) supported PLs, with their subsequent indexing.

VueJS+TS project integration with SonarQube

Then there are various other analyzes that we do not focus on in this article (for example, such as: linting, code duplication detection, etc.).

At the very end of the scanner, all the collected information is aggregated, archived and sent to the server.

After that, we can already see what happened in the web interface:

VueJS+TS project integration with SonarQube

As you can see, something turned out, and even shows some kind of coverage, but it does not correspond to ours Jest-report.

Let's figure it out. Let's look at the project in more detail, click on the coverage value, and "fall" into the detailed report on files:

VueJS+TS project integration with SonarQube

Here we see in addition to the main, investigated file HelloWorld.vue, the file is also present main.ts, which spoils the whole picture of the coverage. But how so, we excluded it from the coverage calculation. Yes, everything is correct, but it was on the level Jest, but the scanner indexed it, so it got into its calculations.

Let's fix this:

sonar-project.properties:

...
sonar.exclusions=src/main.ts
...

I would like to make a clarification: in addition to those folders that are specified in this parameter, all folders listed in the parameter are also added. sonar.test.inclusions.

After starting the scanner, we see the correct information:

VueJS+TS project integration with SonarQube

VueJS+TS project integration with SonarQube

Let's take a look at the next one - quality profiles. I talked about support Sonar'om several EPs at the same time. This is exactly what we are seeing. But we know that our project is written in TS, so why strain the scanner with unnecessary manipulations and checks. We will set the language for analysis by adding one more parameter to the configuration file Sonar'A:

sonar-project.properties:

...
sonar.language=ts
...

Run the scanner again and see the result:

VueJS+TS project integration with SonarQube

The cover is completely gone.

If we look at the scanner log, we can see the following line:

VueJS+TS project integration with SonarQube

That is, the files of our project were simply not indexed.

The situation is as follows: officially support vue js is in the plugin SonarJSwho is responsible for javascript.

VueJS+TS project integration with SonarQube

But this support is not in the plugin SonarTS for TS, about which an official ticket was opened in the bug tracker Sonar'A:

  1. https://jira.sonarsource.com/browse/MMF-1441
  2. https://github.com/SonarSource/SonarJS/issues/1281

Here are some answers from one of the representatives from the SonarQube developers, confirming this fact.

VueJS+TS project integration with SonarQube

VueJS+TS project integration with SonarQube

But everything worked for us, you object. Yes it is, let's try a little “hack”.
If there is support .vue-files Sonar'oh, then let's try to tell him to treat them like typescript.

Let's add a parameter:

sonar-project.properties:

...
sonar.typescript.file.suffixes=.ts,.tsx,.vue
...

Let's start the scanner:

VueJS+TS project integration with SonarQube

And, voila, everything is back to normal, and with one profile just for typescript. That is, we managed to solve the problem in support VueJs+TS for Sonar Qube.

Let's try to go further and improve the coverage information a bit.

What have we done so far:

  • added to the project Sonar-scanner;
  • set up Jest to generate coverage information;
  • configured Sonar-scanner;
  • solved the support problem .vue-files + typescript.

In addition to test coverage, there are other interesting useful code quality criteria, such as code duplication and the number of lines (involved in the calculation of coefficients related to code complexity) of the project.

In the current implementation of the plugin for working with TS (SonarTS) will not work CPD (Copy Paste Detector) and count lines of code .vue-files.

To create a synthetic situation for code duplication, simply duplicate the component file with a different name, also add to the code main.ts a dummy function and duplicate it with a different name. To check for duplication as in .vueAnd in .ts -files.

main.ts:

...
function name(params:string): void {
  console.log(params);
}
...

To do this, temporarily comment out the configuration line:

sonar-project.properties:

...
sonar.exclusions=src/main.ts
...

Restart the scanner along with testing:

yarn test && yarn run sonar

Of course, our coverage will fall, but now we are not interested.

In the context of duplicating lines of code, we will see:

VueJS+TS project integration with SonarQube

To check, we use CPD-utility - jscpd:

npx jscpd src

VueJS+TS project integration with SonarQube

For lines of code:

VueJS+TS project integration with SonarQube

Maybe this will be fixed in future versions of plugins. SonarJS(TS). I want to note that they are gradually starting to merge these two plugins into one SonarJSwhich I think is correct.

Now I would like to consider the option of improving coverage information.

So far, we can see the test coverage in percentage terms, for the entire project, and for files in particular. But it is possible to expand this indicator with information on the number unit-tests for the project, as well as in the context of files.

There is a library that can Jest-report to convert to format for Sonar'A:
generic test datahttps://docs.sonarqube.org/display/SONAR/Generic+Test+Data.

Install this library in your project:

yarn add jest-sonar-reporter

And add it to the configuration Jest:

package.json:

…
"testResultsProcessor": "jest-sonar-reporter"
…

Now let's run the test:

yarn test

After that, a file will be created in the root of the project test report.xml.

Enable it in config Sonar'A:

sonar-project.properties:

…
sonar.testExecutionReportPaths=test-report.xml
…

And restart the scanner:

yarn run sonar

Let's see what has changed in the interface Sonar'A:

VueJS+TS project integration with SonarQube

And nothing has changed. The fact is that Sonar does not consider the files described in the Jest report as files unit-tests. In order to fix this situation, we use the configuration parameter Sonar sonar.tests, in which we explicitly specify the folders with the tests (we still have one):

sonar-project.properties:

…
sonar.tests=src/components/__tests__
…

Restart the scanner:

yarn run sonar

Let's see what has changed in the interface:

VueJS+TS project integration with SonarQube

Now we have seen the number of our unit-tests and, having failed by clicking inside, we can see the distribution of this number among the project files:

VueJS+TS project integration with SonarQube

Conclusion

So, we have considered a tool for continuous analysis Sonar Qube. We successfully integrated into it a project written in VueJs+TS. Fixed some compatibility issues. Increased the information content of the test coverage indicator. In this article, we have considered only one of the code quality criteria (perhaps one of the main ones), but Sonar Qube supports other quality criteria, including safety testing. But not all of these features are fully available in community platforms-versions. One of the interesting and useful features is integrations. Sonar Qube with various code repository management systems such as GitLab and BitBucket. To prevent merge pull(merge) request'and to the main branch of the repository when the coverage degrades. But this is a completely different story.

PS: Everything that is described in the article in the form of code is available in my fork.

Only registered users can participate in the survey. Sign in, you are welcome.

Are you using the SonarQube platform:

  • 26,3%Yes5

  • 15,8%No3

  • 15,8%Heard about this platform and want to use3

  • 10,5%Heard about this platform and don't want to use2

  • 0,0%I'm using a different platform0

  • 31,6%First time I hear about her

19 users voted. 3 users abstained.

Source: habr.com

Add a comment