metripy 0.2.7__py3-none-any.whl → 0.3.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of metripy might be problematic. Click here for more details.
- metripy/Application/Analyzer.py +23 -3
- metripy/Application/Application.py +16 -2
- metripy/Application/Config/Config.py +34 -0
- metripy/Application/Config/File/ConfigFileReaderFactory.py +6 -5
- metripy/Application/Config/File/ConfigFileReaderInterface.py +70 -3
- metripy/Application/Config/File/JsonConfigFileReader.py +5 -70
- metripy/Application/Config/File/YamlConfigFileReader.py +17 -0
- metripy/Application/Config/Parser.py +24 -11
- metripy/Application/Config/ProjectConfig.py +64 -0
- metripy/Application/Info.py +61 -0
- metripy/Dependency/Dependency.py +17 -1
- metripy/Dependency/Pip/Pip.py +21 -31
- metripy/Dependency/Pip/PyPi.py +1 -0
- metripy/Git/GitAnalyzer.py +0 -3
- metripy/Import/Json/JsonImporter.py +17 -0
- metripy/LangAnalyzer/AbstractLangAnalyzer.py +4 -3
- metripy/LangAnalyzer/Php/PhpAnalyzer.py +2 -1
- metripy/LangAnalyzer/Python/PythonAnalyzer.py +31 -9
- metripy/LangAnalyzer/Python/PythonHalSteadAnalyzer.py +55 -0
- metripy/LangAnalyzer/Typescript/TypescriptAnalyzer.py +12 -9
- metripy/LangAnalyzer/Typescript/TypescriptAstParser.py +1 -1
- metripy/Metric/Code/AggregatedMetrics.py +12 -5
- metripy/Metric/Code/FileMetrics.py +32 -1
- metripy/Metric/Code/ModuleMetrics.py +5 -5
- metripy/Metric/Code/SegmentedMetrics.py +72 -36
- metripy/Metric/Code/Segmentor.py +44 -0
- metripy/Metric/FileTree/FileTreeParser.py +0 -4
- metripy/Metric/Git/GitMetrics.py +1 -1
- metripy/Metric/ProjectMetrics.py +29 -0
- metripy/Metric/Trend/AggregatedTrendMetric.py +101 -0
- metripy/Metric/Trend/ClassTrendMetric.py +20 -0
- metripy/Metric/Trend/FileTrendMetric.py +46 -0
- metripy/Metric/Trend/FunctionTrendMetric.py +28 -0
- metripy/Metric/Trend/SegmentedTrendMetric.py +29 -0
- metripy/Report/Html/DependencyPageRenderer.py +21 -0
- metripy/Report/Html/FilesPageRenderer.py +28 -0
- metripy/Report/Html/GitAnalysisPageRenderer.py +55 -0
- metripy/Report/Html/IndexPageRenderer.py +47 -0
- metripy/Report/Html/PageRenderer.py +43 -0
- metripy/Report/Html/PageRendererFactory.py +37 -0
- metripy/Report/Html/Reporter.py +78 -137
- metripy/Report/Html/TopOffendersPageRenderer.py +84 -0
- metripy/Report/Html/TrendsPageRenderer.py +137 -0
- metripy/Report/Json/GitJsonReporter.py +3 -0
- metripy/Report/Json/JsonReporter.py +6 -2
- metripy/Report/ReporterFactory.py +6 -3
- metripy/Tree/ClassNode.py +21 -0
- metripy/Tree/FunctionNode.py +66 -1
- metripy/Trend/TrendAnalyzer.py +150 -0
- metripy/templates/html_report/css/styles.css +1386 -0
- metripy/templates/html_report/dependencies.html +411 -0
- metripy/templates/html_report/files.html +1080 -0
- metripy/templates/html_report/git_analysis.html +325 -0
- metripy/templates/html_report/images/logo.svg +31 -0
- metripy/templates/html_report/index.html +374 -0
- metripy/templates/html_report/js/charts.js +313 -0
- metripy/templates/html_report/js/dashboard.js +546 -0
- metripy/templates/html_report/js/git_analysis.js +383 -0
- metripy/templates/html_report/top_offenders.html +267 -0
- metripy/templates/html_report/trends.html +468 -0
- {metripy-0.2.7.dist-info → metripy-0.3.6.dist-info}/METADATA +27 -9
- metripy-0.3.6.dist-info/RECORD +96 -0
- {metripy-0.2.7.dist-info → metripy-0.3.6.dist-info}/licenses/LICENSE +1 -1
- metripy-0.2.7.dist-info/RECORD +0 -66
- {metripy-0.2.7.dist-info → metripy-0.3.6.dist-info}/WHEEL +0 -0
- {metripy-0.2.7.dist-info → metripy-0.3.6.dist-info}/entry_points.txt +0 -0
- {metripy-0.2.7.dist-info → metripy-0.3.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from metripy.Metric.Code.SegmentedMetrics import SegmentedMetrics
|
|
2
|
+
from metripy.Metric.Trend.SegmentedTrendMetric import SegmentedTrendMetric
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AggregatedTrendMetric:
|
|
6
|
+
def __init__(
|
|
7
|
+
self,
|
|
8
|
+
historical_loc: int,
|
|
9
|
+
loc: int,
|
|
10
|
+
historical_avgCcPerFunction: float,
|
|
11
|
+
avgCcPerFunction: float,
|
|
12
|
+
historical_maintainabilityIndex: float,
|
|
13
|
+
maintainabilityIndex: float,
|
|
14
|
+
historical_avgLocPerFunction: float,
|
|
15
|
+
avgLocPerFunction: float,
|
|
16
|
+
historical_num_files: int,
|
|
17
|
+
num_files: int,
|
|
18
|
+
historical_segmented_loc: SegmentedMetrics,
|
|
19
|
+
segmented_loc: SegmentedMetrics,
|
|
20
|
+
historical_segmented_complexity: SegmentedMetrics,
|
|
21
|
+
segmented_complexity: SegmentedMetrics,
|
|
22
|
+
historical_segmented_maintainability: SegmentedMetrics,
|
|
23
|
+
segmented_maintainability: SegmentedMetrics,
|
|
24
|
+
historical_segmented_method_size: SegmentedMetrics,
|
|
25
|
+
segmented_method_size: SegmentedMetrics,
|
|
26
|
+
):
|
|
27
|
+
self.historical_loc = historical_loc
|
|
28
|
+
self.loc_delta = loc - historical_loc
|
|
29
|
+
self.historical_avgCcPerFunction = historical_avgCcPerFunction
|
|
30
|
+
self.avgCcPerFunction_delta = avgCcPerFunction - historical_avgCcPerFunction
|
|
31
|
+
self.historical_maintainabilityIndex = historical_maintainabilityIndex
|
|
32
|
+
self.maintainabilityIndex_delta = (
|
|
33
|
+
maintainabilityIndex - historical_maintainabilityIndex
|
|
34
|
+
)
|
|
35
|
+
self.historical_avgLocPerFunction = historical_avgLocPerFunction
|
|
36
|
+
self.avgLocPerFunction_delta = avgLocPerFunction - historical_avgLocPerFunction
|
|
37
|
+
self.historical_num_files = historical_num_files
|
|
38
|
+
self.num_files_delta = num_files - historical_num_files
|
|
39
|
+
|
|
40
|
+
self.historical_segmentation_data = {
|
|
41
|
+
"loc": historical_segmented_loc,
|
|
42
|
+
"complexity": historical_segmented_complexity,
|
|
43
|
+
"maintainability": historical_segmented_maintainability,
|
|
44
|
+
"methodSize": historical_segmented_method_size,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
self.segmentation_data_deltas = {
|
|
48
|
+
"loc": SegmentedTrendMetric(historical_segmented_loc, segmented_loc),
|
|
49
|
+
"complexity": SegmentedTrendMetric(
|
|
50
|
+
historical_segmented_complexity, segmented_complexity
|
|
51
|
+
),
|
|
52
|
+
"maintainability": SegmentedTrendMetric(
|
|
53
|
+
historical_segmented_maintainability, segmented_maintainability
|
|
54
|
+
),
|
|
55
|
+
"methodSize": SegmentedTrendMetric(
|
|
56
|
+
historical_segmented_method_size, segmented_method_size
|
|
57
|
+
),
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
def get_trend_type(self, delta: float, up_is_good: bool) -> str:
|
|
61
|
+
if up_is_good:
|
|
62
|
+
return "positive" if delta > 0 else "negative" if delta < 0 else "neutral"
|
|
63
|
+
else:
|
|
64
|
+
return "negative" if delta > 0 else "positive" if delta < 0 else "neutral"
|
|
65
|
+
|
|
66
|
+
def get_trend_icon(self, delta: float) -> str:
|
|
67
|
+
return "arrow-up" if delta > 0 else "arrow-down" if delta < 0 else "arrow-right"
|
|
68
|
+
|
|
69
|
+
def to_dict(self) -> dict:
|
|
70
|
+
return {
|
|
71
|
+
"loc_delta": round(self.loc_delta, 2),
|
|
72
|
+
"loc_trend_type": self.get_trend_type(self.loc_delta, False),
|
|
73
|
+
"loc_trend_icon": self.get_trend_icon(self.loc_delta),
|
|
74
|
+
"avgCcPerFunction_delta": round(self.avgCcPerFunction_delta, 2),
|
|
75
|
+
"avgCcPerFunction_trend_type": self.get_trend_type(
|
|
76
|
+
self.avgCcPerFunction_delta, False
|
|
77
|
+
),
|
|
78
|
+
"avgCcPerFunction_trend_icon": self.get_trend_icon(
|
|
79
|
+
self.avgCcPerFunction_delta
|
|
80
|
+
),
|
|
81
|
+
"maintainabilityIndex_delta": round(self.maintainabilityIndex_delta, 2),
|
|
82
|
+
"maintainabilityIndex_trend_type": self.get_trend_type(
|
|
83
|
+
self.maintainabilityIndex_delta, True
|
|
84
|
+
),
|
|
85
|
+
"maintainabilityIndex_trend_icon": self.get_trend_icon(
|
|
86
|
+
self.maintainabilityIndex_delta
|
|
87
|
+
),
|
|
88
|
+
"avgLocPerFunction_delta": round(self.avgLocPerFunction_delta, 2),
|
|
89
|
+
"avgLocPerFunction_trend_type": self.get_trend_type(
|
|
90
|
+
self.avgLocPerFunction_delta, False
|
|
91
|
+
),
|
|
92
|
+
"avgLocPerFunction_trend_icon": self.get_trend_icon(
|
|
93
|
+
self.avgLocPerFunction_delta
|
|
94
|
+
),
|
|
95
|
+
"num_files_delta": self.num_files_delta,
|
|
96
|
+
"num_files_trend_type": self.get_trend_type(self.num_files_delta, False),
|
|
97
|
+
"num_files_trend_icon": self.get_trend_icon(self.num_files_delta),
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
def to_dict_segmentation(self) -> dict:
|
|
101
|
+
return {k: v.to_dict() for k, v in self.segmentation_data_deltas.items()}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
class ClassTrendMetric:
|
|
2
|
+
def __init__(
|
|
3
|
+
self,
|
|
4
|
+
historical_lineno: int,
|
|
5
|
+
lineno: int,
|
|
6
|
+
historical_real_complexity: int,
|
|
7
|
+
real_complexity: int,
|
|
8
|
+
):
|
|
9
|
+
self.historical_lineno = historical_lineno
|
|
10
|
+
self.lineno_delta = lineno - historical_lineno
|
|
11
|
+
self.historical_real_complexity = historical_real_complexity
|
|
12
|
+
self.real_complexity_delta = real_complexity - historical_real_complexity
|
|
13
|
+
|
|
14
|
+
def to_dict(self) -> dict:
|
|
15
|
+
return {
|
|
16
|
+
"historical_lineno": self.historical_lineno,
|
|
17
|
+
"lineno_delta": self.lineno_delta,
|
|
18
|
+
"historical_real_complexity": self.historical_real_complexity,
|
|
19
|
+
"real_complexity_delta": self.real_complexity_delta,
|
|
20
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
class FileTrendMetric:
|
|
2
|
+
def __init__(
|
|
3
|
+
self,
|
|
4
|
+
historical_loc: int,
|
|
5
|
+
loc: int,
|
|
6
|
+
historical_totalCc: int,
|
|
7
|
+
totalCc: int,
|
|
8
|
+
historical_avgCcPerFunction: float,
|
|
9
|
+
avgCcPerFunction: float,
|
|
10
|
+
historical_maintainabilityIndex: float,
|
|
11
|
+
maintainabilityIndex: float,
|
|
12
|
+
historical_avgLocPerFunction: float,
|
|
13
|
+
avgLocPerFunction: float,
|
|
14
|
+
):
|
|
15
|
+
self.historical_loc = historical_loc
|
|
16
|
+
self.loc_delta = loc - historical_loc
|
|
17
|
+
|
|
18
|
+
self.historical_totalCc = historical_totalCc
|
|
19
|
+
self.totalCc_delta = totalCc - historical_totalCc
|
|
20
|
+
|
|
21
|
+
self.historical_avgCcPerFunction = historical_avgCcPerFunction
|
|
22
|
+
self.avgCcPerFunction_delta = avgCcPerFunction - historical_avgCcPerFunction
|
|
23
|
+
|
|
24
|
+
self.maintainabilityIndex_delta = (
|
|
25
|
+
maintainabilityIndex - historical_maintainabilityIndex
|
|
26
|
+
)
|
|
27
|
+
self.historical_maintainabilityIndex = historical_maintainabilityIndex
|
|
28
|
+
|
|
29
|
+
self.avgLocPerFunction_delta = avgLocPerFunction - historical_avgLocPerFunction
|
|
30
|
+
self.historical_avgLocPerFunction = historical_avgLocPerFunction
|
|
31
|
+
|
|
32
|
+
def to_dict(self) -> dict:
|
|
33
|
+
return {
|
|
34
|
+
"historical_loc": round(self.historical_loc, 2),
|
|
35
|
+
"loc_delta": round(self.loc_delta, 2),
|
|
36
|
+
"historical_totalCc": round(self.historical_totalCc, 2),
|
|
37
|
+
"totalCc_delta": round(self.totalCc_delta, 2),
|
|
38
|
+
"historical_avgCcPerFunction": round(self.historical_avgCcPerFunction, 2),
|
|
39
|
+
"avgCcPerFunction_delta": round(self.avgCcPerFunction_delta, 2),
|
|
40
|
+
"historical_maintainabilityIndex": round(
|
|
41
|
+
self.historical_maintainabilityIndex, 2
|
|
42
|
+
),
|
|
43
|
+
"maintainabilityIndex_delta": round(self.maintainabilityIndex_delta, 2),
|
|
44
|
+
"historical_avgLocPerFunction": round(self.historical_avgLocPerFunction, 2),
|
|
45
|
+
"avgLocPerFunction_delta": round(self.avgLocPerFunction_delta, 2),
|
|
46
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
class FunctionTrendMetric:
|
|
2
|
+
def __init__(
|
|
3
|
+
self,
|
|
4
|
+
historical_loc: int,
|
|
5
|
+
loc: int,
|
|
6
|
+
historical_complexity: int,
|
|
7
|
+
complexity: int,
|
|
8
|
+
historical_maintainability_index: float,
|
|
9
|
+
maintainability_index: float,
|
|
10
|
+
):
|
|
11
|
+
self.historical_loc = historical_loc
|
|
12
|
+
self.loc_delta = loc - historical_loc
|
|
13
|
+
self.historical_complexity = historical_complexity
|
|
14
|
+
self.complexity_delta = complexity - historical_complexity
|
|
15
|
+
self.historical_maintainability_index = historical_maintainability_index
|
|
16
|
+
self.maintainability_index_delta = (
|
|
17
|
+
maintainability_index - historical_maintainability_index
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
def to_dict(self) -> dict:
|
|
21
|
+
return {
|
|
22
|
+
"historical_loc": self.historical_loc,
|
|
23
|
+
"loc_delta": self.loc_delta,
|
|
24
|
+
"historical_complexity": self.historical_complexity,
|
|
25
|
+
"complexity_delta": self.complexity_delta,
|
|
26
|
+
"historical_maintainability_index": self.historical_maintainability_index,
|
|
27
|
+
"maintainability_index_delta": self.maintainability_index_delta,
|
|
28
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from metripy.Metric.Code.SegmentedMetrics import SegmentedMetrics
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class SegmentedTrendMetric:
|
|
5
|
+
def __init__(
|
|
6
|
+
self,
|
|
7
|
+
historical_segmentation: SegmentedMetrics,
|
|
8
|
+
segmentation: SegmentedMetrics,
|
|
9
|
+
):
|
|
10
|
+
self.historical_good = historical_segmentation.good
|
|
11
|
+
self.good_delta = segmentation.good - historical_segmentation.good
|
|
12
|
+
self.historical_ok = historical_segmentation.ok
|
|
13
|
+
self.ok_delta = segmentation.ok - historical_segmentation.ok
|
|
14
|
+
self.historical_warning = historical_segmentation.warning
|
|
15
|
+
self.warning_delta = segmentation.warning - historical_segmentation.warning
|
|
16
|
+
self.historical_critical = historical_segmentation.critical
|
|
17
|
+
self.critical_delta = segmentation.critical - historical_segmentation.critical
|
|
18
|
+
|
|
19
|
+
def to_dict(self) -> dict:
|
|
20
|
+
return {
|
|
21
|
+
"historical_good": self.historical_good,
|
|
22
|
+
"good_delta": self.good_delta,
|
|
23
|
+
"historical_ok": self.historical_ok,
|
|
24
|
+
"ok_delta": self.ok_delta,
|
|
25
|
+
"historical_warning": self.historical_warning,
|
|
26
|
+
"warning_delta": self.warning_delta,
|
|
27
|
+
"historical_critical": self.historical_critical,
|
|
28
|
+
"critical_delta": self.critical_delta,
|
|
29
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from metripy.Dependency.Dependency import Dependency
|
|
2
|
+
from metripy.Metric.ProjectMetrics import ProjectMetrics
|
|
3
|
+
from metripy.Report.Html.PageRenderer import PageRenderer
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
class DependencyPageRenderer(PageRenderer):
|
|
7
|
+
def __init__(self, template_dir: str, output_dir: str, project_name: str):
|
|
8
|
+
super().__init__(template_dir, output_dir, project_name)
|
|
9
|
+
|
|
10
|
+
def render(self, metrics: ProjectMetrics):
|
|
11
|
+
dependencies = metrics.dependencies if metrics.dependencies is not None else []
|
|
12
|
+
license_by_type = Dependency.get_lisence_distribution(dependencies)
|
|
13
|
+
|
|
14
|
+
self.render_template(
|
|
15
|
+
"dependencies.html",
|
|
16
|
+
{
|
|
17
|
+
"has_dependencies_data": bool(metrics.dependencies),
|
|
18
|
+
"dependencies": [d.to_dict() for d in dependencies],
|
|
19
|
+
"license_distribution_json": json.dumps(license_by_type, indent=2),
|
|
20
|
+
},
|
|
21
|
+
)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from metripy.Metric.FileTree.FileTreeParser import FileTreeParser
|
|
4
|
+
from metripy.Metric.ProjectMetrics import ProjectMetrics
|
|
5
|
+
from metripy.Report.Html.PageRenderer import PageRenderer
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FilesPageRenderer(PageRenderer):
|
|
9
|
+
def __init__(self, template_dir: str, output_dir: str, project_name: str):
|
|
10
|
+
super().__init__(template_dir, output_dir, project_name)
|
|
11
|
+
|
|
12
|
+
def render(self, metrics: ProjectMetrics):
|
|
13
|
+
file_names = []
|
|
14
|
+
file_details = {}
|
|
15
|
+
for file_metrics in metrics.file_metrics:
|
|
16
|
+
file_name = file_metrics.full_name
|
|
17
|
+
file_details[file_name] = file_metrics.to_dict()
|
|
18
|
+
file_names.append(file_name)
|
|
19
|
+
|
|
20
|
+
filetree = FileTreeParser.parse(file_names, shorten=True)
|
|
21
|
+
|
|
22
|
+
self.render_template(
|
|
23
|
+
"files.html",
|
|
24
|
+
{
|
|
25
|
+
"filetree": json.dumps(filetree.to_dict()),
|
|
26
|
+
"file_details": json.dumps(file_details),
|
|
27
|
+
},
|
|
28
|
+
)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from metripy.Metric.ProjectMetrics import ProjectMetrics
|
|
4
|
+
from metripy.Report.Html.PageRenderer import PageRenderer
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class GitAnalysisPageRenderer(PageRenderer):
|
|
8
|
+
def __init__(self, template_dir: str, output_dir: str, project_name: str):
|
|
9
|
+
super().__init__(template_dir, output_dir, project_name)
|
|
10
|
+
|
|
11
|
+
def _render_empty_template(self):
|
|
12
|
+
self.render_template(
|
|
13
|
+
"git_analysis.html",
|
|
14
|
+
{
|
|
15
|
+
"has_git_analysis_data": False,
|
|
16
|
+
"git_analysis": {},
|
|
17
|
+
"git_analysis_json": "{}",
|
|
18
|
+
"git_stats_data": "{}",
|
|
19
|
+
"git_churn_data": "{}",
|
|
20
|
+
"git_silos_data": [],
|
|
21
|
+
"git_contributors": [],
|
|
22
|
+
"git_hotspots_data": [],
|
|
23
|
+
},
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
def render(self, metrics: ProjectMetrics):
|
|
27
|
+
if not metrics.git_metrics:
|
|
28
|
+
self._render_empty_template()
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
self.render_template(
|
|
32
|
+
"git_analysis.html",
|
|
33
|
+
{
|
|
34
|
+
"has_git_analysis_data": bool(metrics.git_metrics),
|
|
35
|
+
"git_analysis": metrics.git_metrics.to_dict(),
|
|
36
|
+
"git_analysis_json": json.dumps(
|
|
37
|
+
metrics.git_metrics.get_contributors_dict(), indent=4
|
|
38
|
+
),
|
|
39
|
+
"git_stats_data": json.dumps(
|
|
40
|
+
metrics.git_metrics.get_commit_stats_per_month(), indent=4
|
|
41
|
+
), # git commit graph
|
|
42
|
+
"git_churn_data": json.dumps(
|
|
43
|
+
metrics.git_metrics.get_churn_per_month(), indent=4
|
|
44
|
+
), # git chrun graph
|
|
45
|
+
"git_silos_data": metrics.git_metrics.get_silos_list()[
|
|
46
|
+
:10
|
|
47
|
+
], # silos list
|
|
48
|
+
"git_contributors": metrics.git_metrics.get_contributors_list()[
|
|
49
|
+
:10
|
|
50
|
+
], # contributors list
|
|
51
|
+
"git_hotspots_data": metrics.git_metrics.get_hotspots_list()[
|
|
52
|
+
:10
|
|
53
|
+
], # hotspots list
|
|
54
|
+
},
|
|
55
|
+
)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from metripy.Metric.ProjectMetrics import ProjectMetrics
|
|
4
|
+
from metripy.Report.Html.PageRenderer import PageRenderer
|
|
5
|
+
|
|
6
|
+
from metripy.Dependency.Dependency import Dependency
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class IndexPageRenderer(PageRenderer):
|
|
10
|
+
def __init__(self, template_dir: str, output_dir: str, project_name: str):
|
|
11
|
+
super().__init__(template_dir, output_dir, project_name)
|
|
12
|
+
|
|
13
|
+
def render(self, metrics: ProjectMetrics):
|
|
14
|
+
git_stats_data = {}
|
|
15
|
+
if metrics.git_metrics:
|
|
16
|
+
git_stats_data = metrics.git_metrics.get_commit_stats_per_month()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
dependencies = metrics.dependencies if metrics.dependencies is not None else []
|
|
20
|
+
license_by_type = Dependency.get_lisence_distribution(dependencies)
|
|
21
|
+
|
|
22
|
+
self.render_template(
|
|
23
|
+
"index.html",
|
|
24
|
+
{
|
|
25
|
+
"git_stats_data": json.dumps(git_stats_data, indent=4),
|
|
26
|
+
"license_distribution_json": json.dumps(license_by_type, indent=2),
|
|
27
|
+
"total_code_metrics": metrics.total_code_metrics.to_dict(),
|
|
28
|
+
"has_total_code_metrics_trend": metrics.total_code_metrics.trend
|
|
29
|
+
is not None,
|
|
30
|
+
"total_code_metrics_trend": (
|
|
31
|
+
metrics.total_code_metrics.trend.to_dict()
|
|
32
|
+
if metrics.total_code_metrics.trend
|
|
33
|
+
else None
|
|
34
|
+
),
|
|
35
|
+
"segmentation_data": json.dumps(
|
|
36
|
+
metrics.total_code_metrics.to_dict_segmentation(), indent=4
|
|
37
|
+
),
|
|
38
|
+
"segmentation_data_trend": (
|
|
39
|
+
json.dumps(
|
|
40
|
+
metrics.total_code_metrics.trend.to_dict_segmentation(),
|
|
41
|
+
indent=4,
|
|
42
|
+
)
|
|
43
|
+
if metrics.total_code_metrics.trend
|
|
44
|
+
else None
|
|
45
|
+
),
|
|
46
|
+
},
|
|
47
|
+
)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
|
|
4
|
+
from py_template_engine import TemplateEngine
|
|
5
|
+
|
|
6
|
+
from metripy.Application.Info import Info
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PageRenderer:
|
|
10
|
+
def __init__(self, template_dir: str, output_dir: str, project_name: str):
|
|
11
|
+
self.template_dir = template_dir
|
|
12
|
+
self.output_dir = output_dir
|
|
13
|
+
|
|
14
|
+
self.global_template_args = {
|
|
15
|
+
"project_name": project_name,
|
|
16
|
+
"last_updated": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
|
17
|
+
"date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
|
18
|
+
"author": "Metripy",
|
|
19
|
+
"version": Info().get_version(),
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@staticmethod
|
|
23
|
+
def _stringify_values(obj):
|
|
24
|
+
if isinstance(obj, dict):
|
|
25
|
+
return {
|
|
26
|
+
key: PageRenderer._stringify_values(value) for key, value in obj.items()
|
|
27
|
+
}
|
|
28
|
+
elif isinstance(obj, list):
|
|
29
|
+
return [PageRenderer._stringify_values(item) for item in obj]
|
|
30
|
+
else:
|
|
31
|
+
return str(obj)
|
|
32
|
+
|
|
33
|
+
def render_template(self, template_name: str, data: dict):
|
|
34
|
+
data = self._stringify_values(
|
|
35
|
+
{
|
|
36
|
+
**self.global_template_args,
|
|
37
|
+
**data,
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
engine = TemplateEngine(os.path.join(self.template_dir, template_name))
|
|
41
|
+
content = engine.render(**data)
|
|
42
|
+
with open(os.path.join(self.output_dir, template_name), "w") as file:
|
|
43
|
+
file.write(content)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from metripy.Report.Html.DependencyPageRenderer import DependencyPageRenderer
|
|
2
|
+
from metripy.Report.Html.FilesPageRenderer import FilesPageRenderer
|
|
3
|
+
from metripy.Report.Html.GitAnalysisPageRenderer import GitAnalysisPageRenderer
|
|
4
|
+
from metripy.Report.Html.IndexPageRenderer import IndexPageRenderer
|
|
5
|
+
from metripy.Report.Html.TopOffendersPageRenderer import TopOffendersPageRenderer
|
|
6
|
+
from metripy.Report.Html.TrendsPageRenderer import TrendsPageRenderer
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PageRendererFactory:
|
|
10
|
+
def __init__(self, template_dir: str, output_dir: str, project_name: str):
|
|
11
|
+
self.template_dir = template_dir
|
|
12
|
+
self.output_dir = output_dir
|
|
13
|
+
self.project_name = project_name
|
|
14
|
+
|
|
15
|
+
def create_index_page_renderer(self) -> IndexPageRenderer:
|
|
16
|
+
return IndexPageRenderer(self.template_dir, self.output_dir, self.project_name)
|
|
17
|
+
|
|
18
|
+
def create_files_page_renderer(self) -> FilesPageRenderer:
|
|
19
|
+
return FilesPageRenderer(self.template_dir, self.output_dir, self.project_name)
|
|
20
|
+
|
|
21
|
+
def create_top_offenders_page_renderer(self) -> TopOffendersPageRenderer:
|
|
22
|
+
return TopOffendersPageRenderer(
|
|
23
|
+
self.template_dir, self.output_dir, self.project_name
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
def create_git_analysis_page_renderer(self) -> GitAnalysisPageRenderer:
|
|
27
|
+
return GitAnalysisPageRenderer(
|
|
28
|
+
self.template_dir, self.output_dir, self.project_name
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
def create_dependency_page_renderer(self) -> DependencyPageRenderer:
|
|
32
|
+
return DependencyPageRenderer(
|
|
33
|
+
self.template_dir, self.output_dir, self.project_name
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def create_trends_page_renderer(self) -> TrendsPageRenderer:
|
|
37
|
+
return TrendsPageRenderer(self.template_dir, self.output_dir, self.project_name)
|