Add support for bug_open field to bug_job_map when create or reopen bug.

This commit is contained in:
Joel Maher 2024-11-13 13:52:17 -08:00
Родитель 51715109c1
Коммит 7e5db45b91
8 изменённых файлов: 62 добавлений и 11 удалений

Просмотреть файл

@ -3,7 +3,7 @@ import pytest
from django.urls import reverse
from treeherder.etl.bugzilla import BzApiBugProcess
from treeherder.model.models import Bugscache
from treeherder.model.models import Bugscache, BugJobMap
@pytest.mark.django_db(transaction=True)
@ -50,7 +50,12 @@ def test_bz_reopen_bugs(
not_incomplete_bugs[0],
not_incomplete_bugs[2],
]:
submit_obj = {"job_id": test_jobs[idx].id, "bug_id": bug.id, "type": "manual"}
submit_obj = {
"job_id": test_jobs[idx].id,
"bug_id": bug.id,
"type": "manual",
"bug_open": False,
}
client.post(
reverse("bug-job-map-list", kwargs={"project": test_jobs[idx].repository.name}),
@ -61,10 +66,29 @@ def test_bz_reopen_bugs(
if idx % 11 == 0:
idx = 0
# always closed
# as we only reopen a single instance of a bug, we choose the most recent instance
# since the reopen code queries and then `.order_by("-created")`
bug_job_map = BugJobMap.objects.filter(job_id=test_jobs[4].id, bug_id=incomplete_bugs[0].id)[0]
assert bug_job_map.bug_open is False
bug_job_map = BugJobMap.objects.filter(job_id=test_jobs[3].id, bug_id=incomplete_bugs[2].id)[0]
assert bug_job_map.bug_open is False
process = BzApiBugProcess()
process.minimum_failures_to_reopen = minimum_failures_to_reopen
process.run()
# reopens based on minimum_failures_to_reopen
bug_job_map = BugJobMap.objects.filter(job_id=test_jobs[4].id, bug_id=incomplete_bugs[0].id)[0]
assert bug_job_map.bug_open is True
bug_job_map = BugJobMap.objects.filter(job_id=test_jobs[3].id, bug_id=incomplete_bugs[2].id)[0]
if minimum_failures_to_reopen < 3:
assert bug_job_map.bug_open is True
else:
assert bug_job_map.bug_open is False
reopened_bugs = request.config.cache.get("reopened_bugs", None)
import json

Просмотреть файл

@ -7,10 +7,11 @@ from treeherder.model.models import BugJobMap, Job
@pytest.mark.parametrize(
"test_no_auth,test_duplicate_handling", [(True, False), (False, False), (False, True)]
"test_no_auth,test_duplicate_handling,bug_open",
[(True, False, False), (False, False, False), (False, True, True)],
)
def test_create_bug_job_map(
client, test_job, test_user, bugs, test_no_auth, test_duplicate_handling
client, test_job, test_user, bugs, test_no_auth, test_duplicate_handling, bug_open
):
"""
test creating a single note via endpoint
@ -19,7 +20,12 @@ def test_create_bug_job_map(
if not test_no_auth:
client.force_authenticate(user=test_user)
submit_obj = {"job_id": test_job.id, "bug_id": bug.id, "type": "manual"}
submit_obj = {
"job_id": test_job.id,
"bug_id": bug.id,
"type": "manual",
"bug_open": bug_open,
}
# if testing duplicate handling, submit twice
if test_duplicate_handling:
@ -43,6 +49,7 @@ def test_create_bug_job_map(
assert bug_job_map.job_id == submit_obj["job_id"]
assert bug_job_map.bug_id == submit_obj["bug_id"]
assert bug_job_map.user == test_user
assert bug_job_map.bug_open == bug_open
def test_bug_job_map_list(client, test_repository, eleven_jobs_stored, test_user, bugs):

Просмотреть файл

@ -50,7 +50,10 @@ def reopen_intermittent_bugs(minimum_failures_to_reopen=1):
comment = {"body": "New failure instance: " + log_url}
url = settings.BUGFILER_API_URL + "/rest/bug/" + str(bug_id)
headers = {"x-bugzilla-api-key": settings.BUGFILER_API_KEY, "Accept": "application/json"}
headers = {
"x-bugzilla-api-key": settings.BUGFILER_API_KEY,
"Accept": "application/json",
}
data = {
"status": "REOPENED",
"comment": comment,
@ -59,6 +62,8 @@ def reopen_intermittent_bugs(minimum_failures_to_reopen=1):
try:
reopen_request(url, method="PUT", headers=headers, json=data)
# NOTE: this will only toggle 1 bug_job_map entry, not all (if there are retriggers)
BugJobMap.objects.filter(job_id=job_id, bug_id=bug_id).update(bug_open=True)
except requests.exceptions.HTTPError as e:
try:
message = e.response.json()["message"]

Просмотреть файл

@ -737,12 +737,12 @@ class BugJobMap(models.Model):
return "autoclassifier"
@classmethod
def create(cls, job_id, bug_id, user=None):
def create(cls, job_id, bug_id, user=None, bug_open=False):
bug_map = BugJobMap.objects.create(
job_id=job_id,
bug_id=bug_id,
user=user,
bug_open=False,
bug_open=bug_open,
)
if not user:

Просмотреть файл

@ -13,12 +13,14 @@ class BugJobMapViewSet(viewsets.ViewSet):
"""Add a new relation between a job and a bug."""
job_id = int(request.data["job_id"])
bug_id = int(request.data["bug_id"])
bug_open = bool(request.data["bug_open"])
try:
BugJobMap.create(
job_id=job_id,
bug_id=bug_id,
user=request.user,
bug_open=bug_open,
)
message = "Bug job map saved"
except IntegrityError:

Просмотреть файл

@ -150,13 +150,14 @@ class PinBoard extends React.Component {
};
saveBugs = (job) => {
const { pinnedJobBugs, notify } = this.props;
const { pinnedJobBugs, newBug, notify } = this.props;
pinnedJobBugs.forEach((bugId) => {
const bjm = new BugJobMapModel({
bug_id: bugId,
job_id: job.id,
type: 'annotation',
bug_open: newBug.has(bugId),
});
bjm.create().catch((response) => {
@ -703,6 +704,7 @@ PinBoard.propTypes = {
isPinBoardVisible: PropTypes.bool.isRequired,
pinnedJobs: PropTypes.shape({}).isRequired,
pinnedJobBugs: PropTypes.shape({}).isRequired,
newBug: PropTypes.string.isRequired,
addBug: PropTypes.func.isRequired,
removeBug: PropTypes.func.isRequired,
unPinJob: PropTypes.func.isRequired,
@ -733,6 +735,7 @@ const mapStateToProps = ({
pinnedJobBugs,
failureClassificationId,
failureClassificationComment,
newBug,
},
}) => ({
revisionTips,
@ -743,6 +746,7 @@ const mapStateToProps = ({
pinnedJobBugs,
failureClassificationId,
failureClassificationComment,
newBug,
});
export default connect(mapStateToProps, {

Просмотреть файл

@ -108,13 +108,20 @@ export const pinJobs = (jobsToPin) => {
export const addBug = (bug, job) => {
return async (dispatch, getState) => {
const {
pinnedJobs: { pinnedJobBugs },
pinnedJobs: { pinnedJobBugs, newBug },
} = getState();
const bugId = bug.dupe_of ? bug.dupe_of : bug.id;
if (!pinnedJobBugs.has(bugId)) {
pinnedJobBugs.add(bugId);
}
if ('newBug' in bug) {
if (!newBug.has(bug.newBug)) {
newBug.add(bug.newBug);
}
}
dispatch({
type: SET_PINNED_JOB_BUGS,
pinnedJobBugs: new Set(pinnedJobBugs),
@ -148,6 +155,7 @@ export const unPinAll = () => ({
payload: {
failureClassificationId: 4,
failureClassificationComment: '',
newBug: new Set(),
pinnedJobs: {},
pinnedJobBugs: new Set(),
},
@ -171,6 +179,7 @@ const initialState = {
pinnedJobs: {},
pinnedJobBugs: new Set(),
failureClassificationComment: '',
newBug: new Set(),
failureClassificationId: 4,
isPinBoardVisible: false,
};

Просмотреть файл

@ -61,7 +61,7 @@ class FailureSummaryTab extends React.Component {
bugFilerCallback = (data) => {
const { addBug } = this.props;
addBug({ id: data.id });
addBug({ id: data.id, newBug: data.id });
window.dispatchEvent(new CustomEvent(thEvents.saveClassification));
// Open the newly filed bug in a new tab or window for further editing
window.open(data.url);