@@ -31,7 +31,7 @@ def _stop(self, sub_id):
31
31
if sub_id :
32
32
self ._api_helper .unsubscribe_filters (sub_id )
33
33
34
- def _create_regression (self , failed_node , last_successful_node ):
34
+ def _create_regression (self , failed_node , last_pass_node ):
35
35
"""Method to create a regression"""
36
36
regression = {}
37
37
regression ['kind' ] = 'regression'
@@ -41,7 +41,7 @@ def _create_regression(self, failed_node, last_successful_node):
41
41
regression ['state' ] = 'done'
42
42
regression ['data' ] = {
43
43
'fail_node' : failed_node ['id' ],
44
- 'pass_node' : last_successful_node ['id' ],
44
+ 'pass_node' : last_pass_node ['id' ],
45
45
'arch' : failed_node ['data' ].get ('arch' ),
46
46
'defconfig' : failed_node ['data' ].get ('defconfig' ),
47
47
'compiler' : failed_node ['data' ].get ('compiler' ),
@@ -53,7 +53,8 @@ def _create_regression(self, failed_node, last_successful_node):
53
53
self .log .info (f"Regression submitted: { reg ['id' ]} " )
54
54
55
55
def _detect_regression (self , fail_node ):
56
- """Method to check and detect regression"""
56
+ """Detects if <fail_node> (a failed job) produces a regression,
57
+ ie. if the previous job run with the same parameters passed"""
57
58
previous_nodes = self ._api .node .find ({
58
59
'name' : fail_node ['name' ],
59
60
'group' : fail_node ['group' ],
@@ -81,7 +82,20 @@ def _detect_regression(self, fail_node):
81
82
if previous_node ['result' ] == 'pass' :
82
83
self .log .info ("Detected regression for node id: "
83
84
f"{ fail_node ['id' ]} " )
84
- self ._create_regression (fail_node , previous_node )
85
+ # Skip the regression generation if it was already in the
86
+ # DB. This may happen if a job was detected to generate a
87
+ # regression when it failed and then the same job was
88
+ # checked again after its parent job finished running and
89
+ # was updated.
90
+ existing_regression = self ._api .node .find ({
91
+ 'kind' : 'regression' ,
92
+ 'data.fail_node' : fail_node ['id' ],
93
+ 'data.pass_node' : previous_node ['id' ]
94
+ })
95
+ if not existing_regression :
96
+ self ._create_regression (fail_node , previous_node )
97
+ else :
98
+ self .log .info (f"Skipping regression: already exists" )
85
99
86
100
def _get_all_failed_child_nodes (self , failures , root_node ):
87
101
"""Method to get all failed nodes recursively from top-level node"""
@@ -92,14 +106,19 @@ def _get_all_failed_child_nodes(self, failures, root_node):
92
106
self ._get_all_failed_child_nodes (failures , node )
93
107
94
108
def _run (self , sub_id ):
95
- """Method to run regression tracking """
109
+ """Method to run regression detection and generation """
96
110
self .log .info ("Tracking regressions... " )
97
111
self .log .info ("Press Ctrl-C to stop." )
98
112
sys .stdout .flush ()
99
113
while True :
100
114
node = self ._api_helper .receive_event_node (sub_id )
101
115
if node ['kind' ] == 'checkout' :
102
116
continue
117
+ if node ['result' ] == 'fail' :
118
+ self ._detect_regression (node )
119
+ # When a node hierarchy is submitted on a single operation,
120
+ # an event is generated only for the root node. Walk the
121
+ # children node tree to check for event-less failed jobs
103
122
failures = []
104
123
self ._get_all_failed_child_nodes (failures , node )
105
124
for node in failures :
0 commit comments