Love GitLab and hate bugs? Want to improve the quality of your source code? Then you have come to the right place. Today we will tell you how to configure the PVS-Studio C# analyzer to check merge requests. Cheers to all and happy reading.
By the way, we have released PVS-Studio 7.08, in which we have done a lot of things
- C# analyzer for Linux and macOS;
- plugin for Rider;
- new file list check mode.
File list check mode
Previously, in order to check certain files, it was necessary to pass an .xml file with a list of files to the parser. But since this is not very convenient, we have added the ability to transfer .txt, which greatly simplifies life.
In order to check certain files, you must specify the flag --sourceFiles (-f) and pass .txt with a list of files. It looks like this:
pvs-studio-dotnet -t path/to/solution.sln -f fileList.txt -o project.json
If you're interested in setting up commit checks or pull requests, you can also do so using this mode. The difference will be in obtaining a list of files for analysis and will depend on which systems you are using.
Principle of merge request check
The main essence of the check is to ensure that the problems detected by the analyzer do not fall into the merge master branch. Also, we do not want to analyze the entire project each time. Moreover, when merging branches, we have a list of changed files. Therefore, I propose to add a merge request check.
This is what the merge request looks like before the introduction of the static analyzer:
That is, all the errors that were in the branch changes, will move to the master branch. Since we don't want this, we add the analysis, and now the circuit looks like this:
Analyzing changes2 and, if there are no errors, we accept the merge request, otherwise we reject it.
By the way, if you are interested in analyzing commits and pull requests for C/C++, then you can read about it.
GitLab
Before proceeding with the implementation of the analysis of merge requests, you need to register and upload your project. If you do not know how to do this, then I suggest
Note. The way to set up the environment described below is one of the possible ones. The goal is to show the steps for setting up the environment necessary for analysis and launching the analyzer. Perhaps, in your case, it would be more optimal to separate the stages of environment preparation (adding repositories, installing the analyzer) and analysis: for example, preparing Docker images with the necessary environment and using them, or some other way.
To better understand what will happen now, I suggest taking a look at the following diagram:
The analyzer requires the .NET Core SDK 3 to work, so before installing the analyzer, you need to add the Microsoft repositories, from which the dependencies necessary for the analyzer will be installed. Adding Microsoft repositories for various Linux distributions
To install PVS-Studio via the package manager, you will also need to add the PVS-Studio repositories. Adding repositories for various distributions is described in more detail in
The analyzer needs a license key to work. You can get a trial license at
Note. Please note that the described mode of operation (analysis of merge requests) requires an Enterprise license. Therefore, if you want to try this mode of operation, in the "Message" field, do not forget to indicate that you need an Enterprise license.
If a merge request occurs, then we need to analyze only the list of changed files, otherwise we analyze all files. After analysis, we need to convert the logs to the format we need.
Now, having the algorithm of work before our eyes, we can proceed to writing the script. To do this, you need to change the file .gitlab-ci.yml or, if it doesn't exist, create it. To create it, you need to click on the name of your project -> Set up CI/CD.
Now we are ready to write the script. Let's first write the code that will install the analyzer and enter the license:
before_script:
- apt-get update && apt-get -y install wget gnupg
- apt-get -y install git
- wget https://packages.microsoft.com/config/debian/10/
packages-microsoft-prod.deb -O packages-microsoft-prod.deb
- dpkg -i packages-microsoft-prod.deb
- apt-get update
- apt-get install apt-transport-https
- apt-get update
- wget -q -O - https://files.viva64.com/etc/pubkey.txt | apt-key add -
- wget -O /etc/apt/sources.list.d/viva64.list
https://files.viva64.com/etc/viva64.list
- apt-get update
- apt-get -y install pvs-studio-dotnet
- pvs-studio-analyzer credentials $PVS_NAME $PVS_KEY
- dotnet restore "$CI_PROJECT_DIR"/Test/Test.sln
Since installation and activation must occur before all other scripts, we use a special label before_script. Let me explain this part a bit.
Preparing to install the analyzer:
- wget https://packages.microsoft.com/config/debian/10/
packages-microsoft-prod.deb -O packages-microsoft-prod.deb
- dpkg -i packages-microsoft-prod.deb
- apt-get update
- apt-get install apt-transport-https
- apt-get update
Adding PVS-Studio and analyzer repositories:
- wget -q -O - https://files.viva64.com/etc/pubkey.txt | apt-key add -
- wget -O /etc/apt/sources.list.d/viva64.list
https://files.viva64.com/etc/viva64.list
- apt-get update
- apt-get -y install pvs-studio-dotnet
License activation:
- pvs-studio-analyzer credentials $PVS_NAME $PVS_KEY
$PVS_NAME - Username.
$PVS_KEY - product key.
Restore project dependencies where $CI_PROJECT_DIR β full path to the project directory:
- dotnet restore "$CI_PROJECT_DIR"/Path/To/Solution.sln
For correct analysis, the project must be successfully built, and its dependencies must be restored (for example, the necessary NuGet packages must be downloaded).
You can set environment variables containing license information by clicking on Setting, and after - on CI/CD.
In the window that opens, find the item Variables, right click on the button Expand and add variables. The result should be the following:
Now we can move on to the analysis. First, let's add a script for a complete analysis. To the flag -t pass the path to solution to the flag -o write the path to the file where the analysis results will be written. We are also interested in the return code. In this case, we are interested in stopping the work when the return code contains information that warnings were issued during the analysis. Here's what the snippet looks like:
job:
script:
- exit_code=0
- pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -o
PVS-Studio.json || exit_code=$?
- exit_code=$((($exit_code & 8)/8))
- if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi
Return codes work on the principle of a bit mask. For example, if warnings were issued as a result of the analysis, then the return code will be 8. If the license expires within a month, then the return code will be 4. If errors were found during the analysis, and the license also expires within a month, the code return, both values ββwill be written: add the numbers together and get the final return code - 8 + 4 = 12. Thus, by checking the corresponding bits, it is possible to obtain information about various states during analysis. Return codes are described in more detail in the pvs-studio-dotnet (Linux / macOS) Return Codes section of the document.
In this case, we are interested in all return codes where 8 appears.
- exit_code=$((($exit_code & 8)/8))
We will get 1 when the return code contains the bit of the number we are interested in, otherwise we will get 0.
It's time to add the merge request analysis. Before doing this, let's prepare a place for the script. We need it to be executed only when a merge request occurs. It looks like this:
merge:
script:
only:
- merge_requests
Let's move on to the script itself. I encountered the fact that the virtual machine does not know anything about origin/master. So let's help her a little:
- git fetch origin
Now we get the difference of the branches and save the result in txt file:
- git diff --name-only origin/master $CI_COMMIT_SHA > pvs-fl.txt
Where $CI_COMMIT_SHA β hash of the last commit.
Next, we start the analysis of the list of files using the flag -f. We transfer the previously received .txt file to it. Well, by analogy with the full analysis, we look at the return codes:
- exit_code=0
- pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -f
pvs-fl.txt -o PVS-Studio.json || exit_code=$?
- exit_code=$((($exit_code & 8)/8))
- if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi
The complete script for checking the merge request will look like this:
merge:
script:
- git fetch origin
- git diff --name-only origin/master $CI_COMMIT_SHA > pvs-fl.txt
- exit_code=0
- pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -f
pvs-fl.txt -o PVS-Studio.json || exit_code=$?
- exit_code=$((($exit_code & 8)/8))
- if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi
only:
- merge_requests
It remains only to add the log conversion after all the scripts have worked. Using the label after_script and utility plog-converter:
after_script:
- plog-converter -t html -o eLog ./PVS-Studio.json
Utility
By the way, if you want to conveniently work with a .json report locally from the IDE, then I suggest our
For convenience here .gitlab-ci.yml whole:
image: debian
before_script:
- apt-get update && apt-get -y install wget gnupg
- apt-get -y install git
- wget https://packages.microsoft.com/config/debian/10/
packages-microsoft-prod.deb -O packages-microsoft-prod.deb
- dpkg -i packages-microsoft-prod.deb
- apt-get update
- apt-get install apt-transport-https
- apt-get update
- wget -q -O - https://files.viva64.com/etc/pubkey.txt | apt-key add -
- wget -O /etc/apt/sources.list.d/viva64.list
https://files.viva64.com/etc/viva64.list
- apt-get update
- apt-get -y install pvs-studio-dotnet
- pvs-studio-analyzer credentials $PVS_NAME $PVS_KEY
- dotnet restore "$CI_PROJECT_DIR"/Test/Test.sln
merge:
script:
- git fetch origin
- git diff --name-only origin/master $CI_COMMIT_SHA > pvs-fl.txt
- exit_code=0
- pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -f
pvs-fl.txt -o PVS-Studio.json || exit_code=$?
- exit_code=$((($exit_code & 8)/8))
- if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi
only:
- merge_requests
job:
script:
- exit_code=0
- pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -o
PVS-Studio.json || exit_code=$?
- exit_code=$((($exit_code & 8)/8))
- if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi
after_script:
- plog-converter -t html -o eLog ./PVS-Studio.json
Once everything has been added to the file, click on commit changes. To see if everything is correct, go to CI / CD -> Pipelines -> Running. The virtual machine window will open, at the end of which should be the following:
saw Job succeeded - success, everything is fine. Now you can test what you've done.
Examples of work
For an example of work, let's create a simple project (in master) which will contain several files. After that, in another branch, we will change only one file and try to make a merge request.
Let's consider two cases: when the modified file contains an error and when it doesn't. First, an example with an error.
Let's say there is a file in the master branch program.cs, which does not contain errors, and in another branch, the developer added erroneous code and wants to make a merge request. What kind of mistake he made is not so important, the main thing is that it exists. For example, I forgot the operator throw (Yes,
void MyAwesomeMethod(String name)
{
if (name == null)
new ArgumentNullException(....);
// do something
....
}
Let's look at the result of the analysis of an example with an error. Also to make sure only one file was parsed I added the flag -r to the pvs-studio-dotnet start line:
We see that the analyzer found an error and did not allow the branches to be merged.
Let's check the example without error. Fixing the code:
void MyAwesomeMethod(String name)
{
if (name == null)
throw new ArgumentNullException(....);
// do something
....
}
Results of merge request analysis:
As we can see, no errors were found, and the execution of the task was successful, which is what we wanted to check.
Conclusion
Weeding out bad code before merging branches is very convenient and pleasant. Therefore, if you use CI/CD, try to embed a static analyzer to check it. Moreover, this is done quite simply.
Thank you for attention.
If you want to share this article with an English-speaking audience, please use the translation link: Nikolay Mironov.
Source: habr.com