-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy path__main__.py
More file actions
147 lines (117 loc) · 5.58 KB
/
__main__.py
File metadata and controls
147 lines (117 loc) · 5.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#
# Sonar Scanner Python
# Copyright (C) 2011-2024 SonarSource SA.
# mailto:info AT sonarsource DOT com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
#
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
import logging
from typing import Any
from pysonar_scanner import app_logging
from pysonar_scanner import cache
from pysonar_scanner import exceptions
from pysonar_scanner.api import get_base_urls, SonarQubeApi, BaseUrls, MIN_SUPPORTED_SQ_VERSION
from pysonar_scanner.configuration import configuration_loader
from pysonar_scanner.configuration.configuration_loader import ConfigurationLoader
from pysonar_scanner.configuration.properties import (
SONAR_VERBOSE,
SONAR_HOST_URL,
SONAR_SCANNER_API_BASE_URL,
SONAR_SCANNER_SONARCLOUD_URL,
SONAR_SCANNER_PROXY_PORT,
SONAR_SCANNER_JAVA_EXE_PATH,
SONAR_SCANNER_OS,
SONAR_SCANNER_ARCH,
SONAR_SCANNER_DRY_RUN,
SONAR_PROJECT_BASE_DIR,
SONAR_PYTHON_COVERAGE_REPORT_PATHS,
)
from pysonar_scanner.exceptions import SQTooOldException
from pysonar_scanner.jre import JREResolvedPath, JREProvisioner, JREResolver, JREResolverConfiguration
from pysonar_scanner.scannerengine import ScannerEngine, ScannerEngineProvisioner
from pysonar_scanner.dry_run_reporter import DryRunReporter, CoverageReportValidator, ValidationResult
def main():
exit(scan())
def scan():
try:
return do_scan()
except Exception as e:
return exceptions.log_error(e)
def do_scan():
app_logging.setup()
logging.info(
"Enhance your workflow: Pair pysonar with SonarQube Server per your license or SonarQube Cloud for deeper analysis, and try SonarQube-IDE in your favourite IDE."
)
logging.info("Starting Pysonar, the Sonar scanner CLI for Python")
config = ConfigurationLoader.load()
set_logging_options(config)
if config.get(SONAR_SCANNER_DRY_RUN, False):
return run_dry_run(config)
ConfigurationLoader.check_configuration(config)
api = build_api(config)
check_version(api)
update_config_with_api_urls(config, api.base_urls)
logging.debug(f"Final loaded configuration: {config}")
cache_manager = cache.get_cache(config)
scanner = create_scanner_engine(api, cache_manager, config)
logging.info("Starting the analysis...")
return scanner.run(config)
def set_logging_options(config):
app_logging.configure_logging_level(verbose=config.get(SONAR_VERBOSE, False))
def build_api(config: dict[str, Any]) -> SonarQubeApi:
token = configuration_loader.get_token(config)
base_urls = get_base_urls(config)
return SonarQubeApi(base_urls, token)
def check_version(api: SonarQubeApi):
if api.is_sonar_qube_cloud():
logging.debug(f"SonarQube Cloud url: {api.base_urls.base_url}")
return
version = api.get_analysis_version()
logging.debug(f"SonarQube url: {api.base_urls.base_url}")
if not version.does_support_bootstrapping():
raise SQTooOldException(
f"This scanner only supports SonarQube versions >= {MIN_SUPPORTED_SQ_VERSION}. \n"
f"The server at {api.base_urls.base_url} is on version {version}\n"
"Please either upgrade your SonarQube server or use the Sonar Scanner CLI (see https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/scanners/sonarscanner/)."
)
def update_config_with_api_urls(config, base_urls: BaseUrls):
config[SONAR_HOST_URL] = base_urls.base_url
config[SONAR_SCANNER_API_BASE_URL] = base_urls.api_base_url
if base_urls.is_sonar_qube_cloud:
config[SONAR_SCANNER_SONARCLOUD_URL] = base_urls.base_url
config[SONAR_SCANNER_PROXY_PORT] = "443" if base_urls.base_url.startswith("https") else "80"
def create_scanner_engine(api, cache_manager, config):
jre_path = create_jre(api, cache_manager, config)
config[SONAR_SCANNER_JAVA_EXE_PATH] = str(jre_path.path)
logging.debug(f"JRE path: {jre_path.path}")
scanner_engine_path = ScannerEngineProvisioner(api, cache_manager).provision()
scanner = ScannerEngine(jre_path, scanner_engine_path)
return scanner
def create_jre(api, cache, config: dict[str, Any]) -> JREResolvedPath:
jre_provisioner = JREProvisioner(api, cache, config[SONAR_SCANNER_OS], config[SONAR_SCANNER_ARCH])
jre_resolver = JREResolver(JREResolverConfiguration.from_dict(config), jre_provisioner)
return jre_resolver.resolve_jre()
def run_dry_run(config: dict[str, Any]) -> int:
"""
Run in dry-run mode without connecting to SonarQube server.
Validates configuration and coverage reports.
"""
logging.info("Running in DRY RUN mode")
logging.info("No server connection will be made and no analysis will be submitted")
DryRunReporter.report_configuration(config)
coverage_paths = config.get(SONAR_PYTHON_COVERAGE_REPORT_PATHS)
project_base_dir = config.get(SONAR_PROJECT_BASE_DIR, ".")
validation_result = CoverageReportValidator.validate_coverage_reports(coverage_paths, project_base_dir)
return DryRunReporter.report_validation_results(validation_result)