bugbug
bugbug copied to clipboard
[model:component] Add initial product and component as features
Resolves #4297.
Includes the initial manually classified product and component of a bug as features.
Metrics of the model with the features included: metrics.log
Consistently achieves 0.59 for accuracy and recall for all confidence thresholds.
Instead of having specific features for this, you could make sure the function to restore the bug to its initial version also handles changes to product and component: https://github.com/mozilla/bugbug/blob/b7b96b574408f48e23b41cfbfabe4c650850e097/bugbug/bug_snapshot.py#L584.
Instead of having specific features for this, you could make sure the function to restore the bug to its initial version also handles changes to product and component:
Should I create an issue for this? @marco-c
Instead of having specific features for this, you could make sure the function to restore the bug to its initial version also handles changes to product and component:
Should I create an issue for this? @marco-c
Yes thanks!
Instead of having specific features for this, you could make sure the function to restore the bug to its initial version also handles changes to product and component:
Should I create an issue for this? @marco-c
Yes thanks!
Done here: https://github.com/mozilla/bugbug/issues/4356
Hi! 🤖 The test below is automatically generated and could serve as a regression test for this PR because it:
- passes, and
- fails in the codebase before the PR.
def test_initial_product_and_component():
import json
from bugbug.bug_features import InitialProduct, InitialComponent
# Sample bug data with history
bug_with_history = {
"product": "Firefox",
"component": "General",
"history": [
{
"changes": [
{"field_name": "product", "removed": "Core", "added": "Firefox"},
{"field_name": "component", "removed": "DOM", "added": "General"},
]
}
],
}
# Sample bug data without history
bug_without_history = {
"product": "Toolkit",
"component": "Password Manager",
"history": [],
}
# Initialize feature extractors
initial_product_extractor = InitialProduct()
initial_component_extractor = InitialComponent()
# Test with history
assert initial_product_extractor(bug_with_history) == "Core"
assert initial_component_extractor(bug_with_history) == "DOM"
# Test without history
assert initial_product_extractor(bug_without_history) == "Toolkit"
assert initial_component_extractor(bug_without_history) == "Password Manager"
If you find this regression test useful, feel free to insert it to your test suite.
Our automated pipeline inserted the test at the end of the tests/test_bug_features.py file before running it.
This is part of our research at the ZEST group of University of Zurich in collaboration with Mozilla. If you have any suggestions, questions, or simply want to learn more, feel free to contact us at [email protected] and [email protected].
Click to see which lines were covered.
diff --git a/bugbug/bug_features.py b/bugbug/bug_features.py
--- a/bugbug/bug_features.py
+++ b/bugbug/bug_features.py
@@ -900,6 +900,27 @@
]
+class InitialProduct(SingleBugFeature):# ✅ Covered by above test
+ def __call__(self, bug, **kwargs):# ✅ Covered by above test
+ history = bug.get("history", [])# ✅ Covered by above test
+ if history:# ✅ Covered by above test
+ for entry in history:# ✅ Covered by above test
+ for change in entry["changes"]:# ✅ Covered by above test
+ if change["field_name"] == "product":# ✅ Covered by above test
+ return change["removed"]# ✅ Covered by above test
+ return bug["product"]# ✅ Covered by above test
+# ✅ Covered by above test
+# ✅ Covered by above test
+class InitialComponent(SingleBugFeature):# ✅ Covered by above test
+ def __call__(self, bug, **kwargs):# ✅ Covered by above test
+ history = bug.get("history", [])# ✅ Covered by above test
+ if history:# ✅ Covered by above test
+ for entry in history:# ✅ Covered by above test
+ for change in entry["changes"]:# ✅ Covered by above test
+ if change["field_name"] == "component":# ✅ Covered by above test
+ return change["removed"]# ✅ Covered by above test
+ return bug["component"]# ✅ Covered by above test
+# ✅ Covered by above test
class BugType(SingleBugFeature):
"""Extracts the type of the bug."""
diff --git a/bugbug/models/component.py b/bugbug/models/component.py
--- a/bugbug/models/component.py
+++ b/bugbug/models/component.py
@@ -84,6 +84,8 @@
bug_features.Whiteboard(),
bug_features.Patches(),
bug_features.Landings(),
+ bug_features.InitialProduct(),
+ bug_features.InitialComponent(),
]
cleanup_functions = [
Line coverage* achieved: 91.3%
* Line coverage is calculated over the lines added in this PR.
Hi! 🤖 The test below is automatically generated and could serve as a regression test for this PR because it:
- passes, and
- fails in the codebase before the PR.
def test_initial_product_and_component():
import json
from bugbug.bug_features import InitialProduct, InitialComponent
# Sample bug data with history
bug_with_history = {
"product": "Firefox",
"component": "General",
"history": [
{
"changes": [
{"field_name": "product", "removed": "Core"},
{"field_name": "component", "removed": "DOM"},
]
}
],
}
# Sample bug data without history
bug_without_history = {
"product": "Firefox",
"component": "General",
"history": [],
}
# Initialize feature extractors
initial_product_extractor = InitialProduct()
initial_component_extractor = InitialComponent()
# Test with history
assert initial_product_extractor(bug_with_history) == "Core"
assert initial_component_extractor(bug_with_history) == "DOM"
# Test without history
assert initial_product_extractor(bug_without_history) == "Firefox"
assert initial_component_extractor(bug_without_history) == "General"
If you find this regression test useful, feel free to insert it to your test suite.
Our automated pipeline inserted the test at the end of the tests/test_bug_features.py file before running it.
This is part of our research at the ZEST group of University of Zurich in collaboration with Mozilla. If you have any suggestions, questions, or simply want to learn more, feel free to contact us at [email protected] and [email protected].
Click to see which lines were covered.
diff --git a/bugbug/bug_features.py b/bugbug/bug_features.py
--- a/bugbug/bug_features.py
+++ b/bugbug/bug_features.py
@@ -905,3 +905,24 @@
def __call__(self, bug, **kwargs):
return bug["type"]
+# ✅ Covered by above test
+class InitialProduct(SingleBugFeature):# ✅ Covered by above test
+ def __call__(self, bug, **kwargs):# ✅ Covered by above test
+ history = bug.get("history", [])# ✅ Covered by above test
+ if history:# ✅ Covered by above test
+ for entry in history:# ✅ Covered by above test
+ for change in entry["changes"]:# ✅ Covered by above test
+ if change["field_name"] == "product":# ✅ Covered by above test
+ return change["removed"]# ✅ Covered by above test
+ return bug["product"]# ✅ Covered by above test
+# ✅ Covered by above test
+# ✅ Covered by above test
+class InitialComponent(SingleBugFeature):# ✅ Covered by above test
+ def __call__(self, bug, **kwargs):# ✅ Covered by above test
+ history = bug.get("history", [])# ✅ Covered by above test
+ if history:# ✅ Covered by above test
+ for entry in history:# ✅ Covered by above test
+ for change in entry["changes"]:# ✅ Covered by above test
+ if change["field_name"] == "component":# ✅ Covered by above test
+ return change["removed"]# ✅ Covered by above test
+ return bug["component"]# ✅ Covered by above test
diff --git a/bugbug/models/component.py b/bugbug/models/component.py
--- a/bugbug/models/component.py
+++ b/bugbug/models/component.py
@@ -84,6 +84,8 @@
bug_features.Whiteboard(),
bug_features.Patches(),
bug_features.Landings(),
+ bug_features.InitialProduct(),
+ bug_features.InitialComponent(),
]
cleanup_functions = [
Line coverage* achieved: 91.3%
* Line coverage is calculated over the lines added in this PR.
With the feature (highest threshold): pre rec spe f1 geo iba sup avg / total 0.57 0.50 1.00 0.53 0.54 0.49 8986
Without the feature (highest threshold): pre rec spe f1 geo iba sup avg / total 0.51 0.28 1.00 0.35 0.39 0.26 8986
Hi! 🤖 The test below is automatically generated and could serve as a regression test for this PR because it:
- passes, and
- fails in the codebase before the PR.
def test_initial_product_and_component():
import json
from bugbug.bug_features import InitialProduct, InitialComponent
# Sample bug data with history
bug_with_history = {
"product": "Firefox",
"component": "General",
"history": [
{
"changes": [
{"field_name": "product", "removed": "Core", "added": "Firefox"},
{"field_name": "component", "removed": "DOM", "added": "General"},
]
}
],
}
# Sample bug data without history
bug_without_history = {
"product": "Firefox",
"component": "General",
"history": [],
}
# Initialize feature extractors
initial_product_extractor = InitialProduct()
initial_component_extractor = InitialComponent()
# Test with history
assert initial_product_extractor(bug_with_history) == "Core"
assert initial_component_extractor(bug_with_history) == "DOM"
# Test without history
assert initial_product_extractor(bug_without_history) == "Firefox"
assert initial_component_extractor(bug_without_history) == "General"
If you find this regression test useful, feel free to insert it to your test suite.
Our automated pipeline inserted the test at the end of the tests/test_bug_features.py file before running it.
This is part of our research at the ZEST group of University of Zurich in collaboration with Mozilla. If you have any suggestions, questions, or simply want to learn more, feel free to contact us at [email protected] and [email protected].
Click to see which lines were covered.
diff --git a/bugbug/bug_features.py b/bugbug/bug_features.py
--- a/bugbug/bug_features.py
+++ b/bugbug/bug_features.py
@@ -905,3 +905,25 @@
def __call__(self, bug, **kwargs):
return bug["type"]
+# ✅ Covered by above test
+# ✅ Covered by above test
+class InitialProduct(SingleBugFeature):# ✅ Covered by above test
+ def __call__(self, bug, **kwargs):# ✅ Covered by above test
+ history = bug.get("history", [])# ✅ Covered by above test
+ if history:# ✅ Covered by above test
+ for entry in history:# ✅ Covered by above test
+ for change in entry["changes"]:# ✅ Covered by above test
+ if change["field_name"] == "product":# ✅ Covered by above test
+ return change["removed"]# ✅ Covered by above test
+ return bug["product"]# ✅ Covered by above test
+# ✅ Covered by above test
+# ✅ Covered by above test
+class InitialComponent(SingleBugFeature):# ✅ Covered by above test
+ def __call__(self, bug, **kwargs):# ✅ Covered by above test
+ history = bug.get("history", [])# ✅ Covered by above test
+ if history:# ✅ Covered by above test
+ for entry in history:# ✅ Covered by above test
+ for change in entry["changes"]:# ✅ Covered by above test
+ if change["field_name"] == "component":# ✅ Covered by above test
+ return change["removed"]# ✅ Covered by above test
+ return bug["component"]# ✅ Covered by above test
diff --git a/bugbug/models/component.py b/bugbug/models/component.py
--- a/bugbug/models/component.py
+++ b/bugbug/models/component.py
@@ -84,6 +84,8 @@
bug_features.Whiteboard(),
bug_features.Patches(),
bug_features.Landings(),
+ bug_features.InitialProduct(),
+ bug_features.InitialComponent(),
]
cleanup_functions = [
Line coverage* achieved: 91.7%
* Line coverage is calculated over the lines added in this PR.
With the feature (highest threshold): pre rec spe f1 geo iba sup avg / total 0.57 0.50 1.00 0.53 0.54 0.49 8986
Without the feature (highest threshold): pre rec spe f1 geo iba sup avg / total 0.51 0.28 1.00 0.35 0.39 0.26 8986
Correction, with the feature the results are pre rec spe f1 geo iba sup avg / total 0.53 0.29 1.00 0.36 0.40 0.28 8984
Hi! 🤖 The test below is automatically generated and could serve as a regression test for this PR because it:
- passes, and
- fails in the codebase before the PR.
def test_initial_product_and_component():
import json
from bugbug.bug_features import InitialProduct, InitialComponent
# Sample bug data with history of changes
bug_data_with_history = {
"history": [
{
"changes": [
{"field_name": "product", "removed": "Firefox"},
{"field_name": "component", "removed": "General"},
]
}
]
}
# Sample bug data without history
bug_data_without_history = {}
# Initialize feature extractors
initial_product_extractor = InitialProduct()
initial_component_extractor = InitialComponent()
# Test with history
assert initial_product_extractor(bug_data_with_history) == "Firefox"
assert initial_component_extractor(bug_data_with_history) == "General"
# Test without history
assert initial_product_extractor(bug_data_without_history) is None
assert initial_component_extractor(bug_data_without_history) is None
If you find this regression test useful, feel free to insert it to your test suite.
Our automated pipeline inserted the test at the end of the tests/test_bug_features.py file before running it.
This is part of our research at the ZEST group of University of Zurich in collaboration with Mozilla. If you have any suggestions, questions, or simply want to learn more, feel free to contact us at [email protected] and [email protected].
Click to see which lines were covered.
diff --git a/bugbug/bug_features.py b/bugbug/bug_features.py
--- a/bugbug/bug_features.py
+++ b/bugbug/bug_features.py
@@ -905,3 +905,25 @@
def __call__(self, bug, **kwargs):
return bug["type"]
+# ✅ Covered by above test
+# ✅ Covered by above test
+class InitialProduct(SingleBugFeature):# ✅ Covered by above test
+ def __call__(self, bug, **kwargs):# ✅ Covered by above test
+ history = bug.get("history", [])# ✅ Covered by above test
+ if history:# ✅ Covered by above test
+ for entry in history:# ✅ Covered by above test
+ for change in entry["changes"]:# ✅ Covered by above test
+ if change["field_name"] == "product":# ✅ Covered by above test
+ return change["removed"]# ✅ Covered by above test
+ return None# ✅ Covered by above test
+# ✅ Covered by above test
+# ✅ Covered by above test
+class InitialComponent(SingleBugFeature):# ✅ Covered by above test
+ def __call__(self, bug, **kwargs):# ✅ Covered by above test
+ history = bug.get("history", [])# ✅ Covered by above test
+ if history:# ✅ Covered by above test
+ for entry in history:# ✅ Covered by above test
+ for change in entry["changes"]:# ✅ Covered by above test
+ if change["field_name"] == "component":# ✅ Covered by above test
+ return change["removed"]# ✅ Covered by above test
+ return None# ✅ Covered by above test
diff --git a/bugbug/models/component.py b/bugbug/models/component.py
--- a/bugbug/models/component.py
+++ b/bugbug/models/component.py
@@ -84,6 +84,8 @@
bug_features.Whiteboard(),
bug_features.Patches(),
bug_features.Landings(),
+ bug_features.InitialProduct(),
+ bug_features.InitialComponent(),
]
cleanup_functions = [
Line coverage* achieved: 91.7%
* Line coverage is calculated over the lines added in this PR.
Hi! 🤖 The test below is automatically generated and could serve as a regression test for this PR because it:
- passes, and
- fails in the codebase before the PR.
def test_initial_product_and_component():
import json
from bugbug.bug_features import InitialProduct, InitialComponent
# Sample bug data with history
bug_with_history = {
"product": "Firefox",
"component": "General",
"history": [
{
"changes": [
{"field_name": "product", "removed": "Core", "added": "Firefox"},
{"field_name": "component", "removed": "Networking", "added": "General"},
]
}
],
}
# Sample bug data without history
bug_without_history = {
"product": "Firefox",
"component": "General",
"history": [],
}
# Initialize feature extractors
initial_product_extractor = InitialProduct()
initial_component_extractor = InitialComponent()
# Test cases
assert initial_product_extractor(bug_with_history) == "Core"
assert initial_component_extractor(bug_with_history) == "Networking"
assert initial_product_extractor(bug_without_history) is None
assert initial_component_extractor(bug_without_history) is None
If you find this regression test useful, feel free to insert it to your test suite.
Our automated pipeline inserted the test at the end of the tests/test_bug_features.py file before running it.
This is part of our research at the ZEST group of University of Zurich in collaboration with Mozilla. If you have any suggestions, questions, or simply want to learn more, feel free to contact us at [email protected] and [email protected].
Click to see which lines were covered.
diff --git a/bugbug/bug_features.py b/bugbug/bug_features.py
--- a/bugbug/bug_features.py
+++ b/bugbug/bug_features.py
@@ -905,3 +905,31 @@
def __call__(self, bug, **kwargs):
return bug["type"]
+# ✅ Covered by above test
+# ✅ Covered by above test
+class InitialProduct(SingleBugFeature):# ✅ Covered by above test
+ def __call__(self, bug, **kwargs):# ✅ Covered by above test
+ history = bug.get("history", [])# ✅ Covered by above test
+ if history:# ✅ Covered by above test
+ for entry in history:# ✅ Covered by above test
+ for change in entry["changes"]:# ✅ Covered by above test
+ if (# ✅ Covered by above test
+ change["field_name"] == "product"# ✅ Covered by above test
+ and change["removed"] != bug["product"]# ✅ Covered by above test
+ ):# ✅ Covered by above test
+ return change["removed"]# ✅ Covered by above test
+ return None# ✅ Covered by above test
+# ✅ Covered by above test
+# ✅ Covered by above test
+class InitialComponent(SingleBugFeature):# ✅ Covered by above test
+ def __call__(self, bug, **kwargs):# ✅ Covered by above test
+ history = bug.get("history", [])# ✅ Covered by above test
+ if history:# ✅ Covered by above test
+ for entry in history:# ✅ Covered by above test
+ for change in entry["changes"]:# ✅ Covered by above test
+ if (# ✅ Covered by above test
+ change["field_name"] == "component"# ✅ Covered by above test
+ and change["removed"] != bug["component"]# ✅ Covered by above test
+ ):# ✅ Covered by above test
+ return change["removed"]# ✅ Covered by above test
+ return None# ✅ Covered by above test
diff --git a/bugbug/models/component.py b/bugbug/models/component.py
--- a/bugbug/models/component.py
+++ b/bugbug/models/component.py
@@ -84,6 +84,8 @@
bug_features.Whiteboard(),
bug_features.Patches(),
bug_features.Landings(),
+ bug_features.InitialProduct(),
+ bug_features.InitialComponent(),
]
cleanup_functions = [
Line coverage* achieved: 93.3%
* Line coverage is calculated over the lines added in this PR.
Closing due to https://github.com/mozilla/bugbug/pull/4298#discussion_r2045813624