Project Setup
To setup a project there are two main steps:
Create project in sonarqube
Add support in project files
Create project in sonarqube
In projects page click on button
Create Project
selectLocal Project
Step 1
Set
Project display name
a meaningful nameProject key
must be the repository idMain branch name
should bedevelop
Step 2
Choose the baseline for new code for this project
SelectUse the global setting
On Analysis Method
page there is no need to do anything for now so can be skipped
Add support in project files
Add sonar-project.properties
file
The sonar-project.properties
must be created on top folder with following:
sonar.host.url=https://sonarqube.touchcastmaas.dev/
sonar.token=ANALYSIS_TOKEN
sonar.projectKey=PROJECT_KEY
sonar.python.version=3.11
sonar.sources=/app/src
sonar.tests=/app/tests
sonar.python.coverage.reportPaths=/app/tests/coverage.xml
sonar.python.xunit.reportPath=/app/tests/unit-test.xml
This project is for a python project note that the /app
prefix will be hardcoded and there is no need to have the same folders in the codebase, but this is the usual naming in projects
Change unit testing files
The unit testing files should include two things: unit testing reports
and coverage report
the paths must match the sonar-project.properties
so the base file for tests is:
import logging
import unittest
import xmlrunner
import os
import sys
import coverage
from typing import IO, Tuple
logging.basicConfig(
level=logging.INFO,
format="[%(asctime)s %(levelname)s] (%(threadName)s::%(funcName)s) %(message)s",
)
logger = logging.getLogger(__name__)
def coverage_start() -> Tuple[coverage.Coverage, IO]:
output_fp = None
# default path if run through venv
src_path = "src"
unitest_prefix = os.environ.get("UNITTEST_PREFIX")
if os.path.exists(unitest_prefix):
# this is only when running through docker
basepath = unitest_prefix
else:
basepath = os.path.realpath(basepath + f"/../")
coverage_basepath_code = os.path.join(
unitest_prefix,
src_path,
)
sys.path.append(coverage_basepath_code)
# extend here all the paths you want coverage
source_paths = [coverage_basepath_code]
coverage_instance = coverage.Coverage(
source=source_paths,
)
coverage_instance.start()
if os.environ.get("XMLRUNNER_OUTPUT_FILE"):
output_fp = open(
os.environ.get("XMLRUNNER_OUTPUT_FILE"),
'wb',
)
return (coverage_instance, output_fp)
def coverage_stop(coverage_instance: coverage.Coverage, output_fp: IO):
coverage_instance.stop()
if output_fp:
output_fp.close()
if os.environ.get("COVERAGE_OUTPUT_FILE"):
coverage_instance.xml_report(outfile=os.environ.get("COVERAGE_OUTPUT_FILE"))
if __name__ == "__main__":
basepath = os.path.dirname(os.path.realpath(__file__))
basepath_cases = os.path.realpath(basepath + "/cases")
sys.path.append(os.path.realpath(basepath + "/lib"))
runner_extra_params = {
"verbosity": 2,
"buffer": True,
}
coverage_instance, output_fp = coverage_start()
loader = unittest.TestLoader()
tests = loader.discover(pattern="*_test.py", start_dir=basepath_cases)
if output_fp:
runner = xmlrunner.XMLTestRunner(
output=output_fp,
**runner_extra_params,
)
else:
runner = unittest.runner.TextTestRunner(
**runner_extra_params,
)
response = runner.run(tests)
coverage_stop(coverage_instance, output_fp)
sys.exit(0 if response.wasSuccessful() else 1)
This file must be in tests/
folder
If source path is different from src
it must be changed in line 20 (src_path
variable)
Note that this will include all the paths under src/
folder to be covered, if there are need to remove some folders (like configuration files, etc) it can be restricted to the pats in line 32
The requirements-dev.txt
for this are:
coverage~=7.4.3
unittest-xml-reporting~=3.2.0
You will need to ignore the output files for sonarqube (.gitignore
)
Makefile
The unit_test
step needs to be something like this:
The core part here is to pass the following:
The environment variables are needed by the unit test script, and the volume is needed to force being under /app
folder (because sonarqube needs absolute paths)
The second change is to add a sonarqube_scanner
step
This will generate and upload the report to sonarqube
Change the test script to add a step to convert relative paths into absolute
Add the following at the end of tests/run_tests.sh
Update Jenkinsfile
For now the scan is only made on the develop
branch, so it needs the following in Jenkinsfile
to achieve this
After deploy / publish call