This repository has been archived by the owner on Dec 11, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
trend.py
143 lines (118 loc) · 4.88 KB
/
trend.py
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
# vim: set expandtab sw=4 ts=4:
# disable pylint message about unused variable 'fig'
# pylint: disable=unused-variable
"""
Generate a chart from the gathered buildtime data.
Copyright (C) 2014-2016 Dieter Adriaenssens <ruleant@users.sourceforge.net>
This file is part of buildtimetrend/python-lib
<https://github.com/buildtimetrend/python-lib/>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from lxml import etree
from buildtimetrend import logger
from buildtimetrend.tools import check_file
from collections import OrderedDict
import matplotlib
# Force matplotlib to not use any Xwindow backend.
matplotlib.use('Agg')
from matplotlib import pyplot as plt
class Trend(object):
"""Trend class, generate a chart from gathered buildtime data."""
def __init__(self):
"""Initialize instance."""
self.stages = {}
self.builds = []
def gather_data(self, result_file):
"""
Get buildtime data from an xml file.
Parameters
- result_file : xml file containing the buildtime data
"""
# load buildtimes file
if check_file(result_file):
root_xml = etree.parse(result_file).getroot()
else:
return False
index = 0
# print content of buildtimes file
for build_xml in root_xml:
build_id = build_xml.get('build')
job_id = build_xml.get('job')
if job_id is None and build_id is None:
build_name = "#{0:d}".format(index + 1)
elif job_id is not None:
build_name = job_id
else:
build_name = build_id
self.builds.append(build_name)
# add 0 to each existing stage, to make sure that
# the indexes of each value
# are correct, even if a stage does not exist in a build
# if a stage exists, the zero will be replaced by its duration
for stage in self.stages:
self.stages[stage].append(0)
# add duration of each stage to stages list
for build_child in build_xml:
if build_child.tag == 'stages':
stage_count = len(build_child)
self.parse_xml_stages(build_child, index)
logger.debug("Build ID : %s, Job : %s, stages : %d",
build_id, job_id, stage_count)
index += 1
return True
def parse_xml_stages(self, stages, index):
"""Parse stages in from xml file."""
for stage in stages:
if (stage.tag == 'stage' and
stage.get('name') is not None and
stage.get('duration') is not None):
if stage.get('name') in self.stages:
temp_dict = self.stages[stage.get('name')]
else:
# when a new stage is added,
# create list with zeros,
# one for each existing build
temp_dict = [0] * (index + 1)
temp_dict[index] = float(stage.get('duration'))
self.stages[stage.get('name')] = temp_dict
def generate(self, trend_file):
"""
Generate the trend chart and save it as a PNG image using matplotlib.
Parameters
- trend_file : file name to save chart image to
"""
fig, axes = plt.subplots()
# sort stages by key
stages = OrderedDict(sorted(self.stages.items()))
# add data
x_values = list(range(len(self.builds)))
y_values = list(stages.values())
plots = plt.stackplot(x_values, y_values)
plt.xticks(x_values, self.builds, rotation=45, size=10)
# label axes and add graph title
axes.set_xlabel("Builds", {'fontsize': 14})
axes.xaxis.set_label_coords(1.05, -0.05)
axes.set_ylabel("Duration [s]", {'fontsize': 14})
axes.set_title("Build stages trend", {'fontsize': 22})
# display legend
legend_proxies = []
for plot in plots:
legend_proxies.append(
plt.Rectangle((0, 0), 1, 1, fc=plot.get_facecolor()[0]))
# add legend in reverse order, in upper left corner
axes.legend(
legend_proxies[::-1],
list(stages.keys())[::-1],
loc=2
)
# save figure
plt.savefig(trend_file)