Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions tasktypes/vendoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ def _patch_exception_message(e):
return str(e)


def _is_patch_conflict(e):
# `./mach vendor --patch-mode only` applies the patches and then runs the
# post-patch actions. Only a patch that didn't apply is something the AI can
# fix; mach logs this message for that case and not for a failed action.
return "Could not apply" in _patch_exception_message(e)


class VendorTaskRunner(BaseTaskRunner):
def __init__(self, provider_dictionary, config_dictionary):
self.jobType = JOBTYPE.VENDORING
Expand Down Expand Up @@ -193,6 +200,13 @@ def _process_new_job(self, library, task, new_version, timestamp, most_recent_jo
except Exception as e:
msg = _patch_exception_message(e)

if not _is_patch_conflict(e):
# Something other than a patch conflict failed (e.g. a
# post-patch action), which the AI can't resolve.
self.dbProvider.update_job_status(created_job, JOBSTATUS.DONE, JOBOUTCOME.COULD_NOT_PATCH)
self.bugzillaProvider.comment_on_bug(created_job.bugzilla_id, CommentTemplates.COULD_NOT_GENERAL_ERROR("apply the mozilla patches (this wasn't a patch conflict, so Updatebot didn't ask its AI assistant to resolve it)", errormessage=msg), needinfo=library.maintainer_bz)
return

# The mozilla patches didn't apply cleanly. Ask the AI to try to
# resolve the conflicts (updating the .patch files / moz.yaml).
potential_commit_message = "Bug %s - Update %s local patches to apply cleanly" % (
Expand Down
33 changes: 29 additions & 4 deletions tests/functionality_all_platforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ def testFailsDuringPatching(self):
lambda: 50, # get_filed_bug_id_func,
lambda b: {}, # filed_bug_ids_func
AssertFalse, # treeherder_response
command_callbacks={'patch': lambda: raise_(Exception("No patching!"))}
command_callbacks={'patch': lambda: raise_(Exception("Could not apply mozilla.patch, possible reasons:"))}
)
try:
u.run(library_filter=library_filter)
Expand All @@ -380,10 +380,35 @@ def testFailsDuringPatching(self):
self.assertEqual(JOBSTATUS.DONE, j.status, "Expected status JOBSTATUS.DONE, got status %s" % (j.status.name))
self.assertEqual(JOBOUTCOME.COULD_NOT_PATCH, j.outcome, "Expected outcome JOBOUTCOME.COULD_NOT_PATCH, got outcome %s" % (j.outcome.name))
self.assertEqual(expected_values.get_filed_bug_id_func(), j.bugzilla_id)
self.assertEqual(u.aiProvider.resolve_call_count, 1, "A patch conflict should have been given to the AI")

finally:
self._cleanup(u, expected_values)

# Create -> patching fails, but not because a patch didn't apply (e.g. a
# post-patch action failed) -> the AI isn't asked -> COULD_NOT_PATCH
@logEntryExitHeaderLine
def testPatchFailureNotAConflictSkipsAI(self):
library_filter = 'png'
(u, expected_values, _check_jobs) = self._setup(
library_filter,
lambda b: ["try_rev|2021-02-09 15:30:04 -0500|2021-02-12 17:40:01 +0000"],
lambda: 56, # get_filed_bug_id_func
lambda b: {}, # filed_bug_ids_func
AssertFalse, # treeherder_response
command_callbacks={'patch': lambda: raise_(Exception("Importing local patches...\nERROR: Could not find revision field in moz.yaml."))},
ai_config={'ai_outcome': 'trivial success', 'ai_details': ['Should not be asked.']},
)
try:
u.run(library_filter=library_filter)
self.assertEqual(u.aiProvider.resolve_call_count, 0, "The AI should not be asked about a failure that isn't a patch conflict")
lib = [lib for lib in u.libraryProvider.get_libraries(u.config_dictionary['General']['gecko-path']) if library_filter in lib.name][0]
j = u.dbProvider.get_job(lib, expected_values.library_new_version_id())
self.assertEqual(JOBSTATUS.DONE, j.status)
self.assertEqual(JOBOUTCOME.COULD_NOT_PATCH, j.outcome)
finally:
self._cleanup(u, expected_values)

# Create -> patch fails -> AI resolves the conflict -> re-apply succeeds -> proceeds
@logEntryExitHeaderLine
def testPatchConflictResolvedByAI(self):
Expand All @@ -392,7 +417,7 @@ def testPatchConflictResolvedByAI(self):
def patch_callback():
patch_calls[0] += 1
if patch_calls[0] == 1:
raise_(Exception("patch does not apply cleanly"))
raise_(Exception("Could not apply mozilla.patch, possible reasons:"))
return ""

arc_calls = [0]
Expand Down Expand Up @@ -438,7 +463,7 @@ def testPatchConflictResolvedByAIUncertain(self):
def patch_callback():
patch_calls[0] += 1
if patch_calls[0] == 1:
raise_(Exception("patch does not apply cleanly"))
raise_(Exception("Could not apply mozilla.patch, possible reasons:"))
return ""

arc_calls = [0]
Expand Down Expand Up @@ -480,7 +505,7 @@ def testPatchConflictAIResolvedButReapplyStillFails(self):
lambda: 54, # get_filed_bug_id_func
lambda b: {}, # filed_bug_ids_func
AssertFalse, # treeherder_response
command_callbacks={'patch': lambda: raise_(Exception("patch still does not apply"))},
command_callbacks={'patch': lambda: raise_(Exception("Could not apply mozilla.patch, possible reasons:"))},
ai_config={'ai_outcome': 'trivial success', 'ai_details': ['I think I fixed it.']},
)
try:
Expand Down
Loading