diff --git a/runbot_merge/controllers/misc.py b/runbot_merge/controllers/misc.py index bbd27c1c0..8f18973c5 100644 --- a/runbot_merge/controllers/misc.py +++ b/runbot_merge/controllers/misc.py @@ -6,9 +6,9 @@ class MergebotController(Controller): @from_role('tx', signed=True) @route('/i18n/merge_commit', type='json', auth='public') - def merge_commit(self, commit_hash, repository, branch, project="RD"): + def merge_commit(self, commit_hash, repository, branch, project="RD", callback_url=None): """Merge a specific commit hash in a repository - + The commit_hash must be known by mergebot (in the git network) Used for translation synchronisation from transifex """ @@ -25,9 +25,12 @@ def merge_commit(self, commit_hash, repository, branch, project="RD"): if not target: return {"error": f"Target branch {project}:{branch} not found"} - patch = request.env["runbot_merge.patch"].sudo().create({ + vals = { "repository": repository_id.id, "target": target.id, - "commit": commit_hash - }) + "commit": commit_hash, + } + if callback_url: + vals["callback_url"] = callback_url + patch = request.env["runbot_merge.patch"].sudo().create(vals) return {"patch": patch.id} diff --git a/runbot_merge/models/patcher.py b/runbot_merge/models/patcher.py index 699a4cf41..7feeb97b7 100644 --- a/runbot_merge/models/patcher.py +++ b/runbot_merge/models/patcher.py @@ -21,6 +21,7 @@ from typing import Union from markupsafe import Markup +import requests from odoo import models, fields, api from odoo.exceptions import ValidationError @@ -144,6 +145,10 @@ class Patch(models.Model): repository = fields.Many2one('runbot_merge.repository', required=True, tracking=True) target = fields.Many2one('runbot_merge.branch', required=True, tracking=True) commit = fields.Char(size=40, string="commit to cherry-pick, must be in-network", tracking=True) + callback_url = fields.Char( + "Callback URL", + help="If set, a POST request is made to this URL after the patch was either applied or failed.", + ) patch = fields.Text(string="unified diff to apply", tracking=True) format = fields.Selection([ @@ -335,6 +340,7 @@ def _apply_patches(self, target: Branch) -> bool: # TODO: do better body=e.args[0] if isinstance(e.args[0], Markup) else Markup("
{}").format(e),
)
+ patch._fire_callback(success=False)
continue
# push patch by patch, avoids sync issues and in most cases we have 0~1 patches
@@ -352,11 +358,38 @@ def _apply_patches(self, target: Branch) -> bool:
"Unable to push result of %s (%s)\nout:\n%s\nerr:\n%s",
patch, c, res.stdout, res.stderr,
)
+ patch._fire_callback(success=False)
else:
info['target_head'] = c
+ patch._fire_callback(success=True)
return True
+ def _fire_callback(self, success: bool) -> None:
+ """POST to callback_url (if set) to notify the caller that the patch was applied or failed."""
+ self.ensure_one()
+ # hide from pytest as it's not on the PYTHONPATH
+ from odoo.addons.saas_worker.auth_util import SaasAuth
+ if not self.callback_url:
+ return
+ data = {
+ 'jsonrpc': '2.0',
+ 'id': None,
+ 'method': 'call',
+ 'params': {
+ 'repository': self.repository.name,
+ 'branch': self.target.name,
+ 'patch': self.id,
+ 'success': success,
+ },
+ }
+ try:
+ res = requests.post(self.callback_url, json=data, auth=SaasAuth(), timeout=30)
+ res.raise_for_status()
+ _logger.info("Patch callback to %s succeeded.", self.callback_url)
+ except requests.RequestException:
+ _logger.error("Patch callback to %s failed.", self.callback_url)
+
def _apply_commit(self, r: git.Repo, parent: str) -> str:
r = r.check(True).stdout().with_config(encoding="utf-8")
target = r.show('--no-patch', '--pretty=%an%n%ae%n%ai%n%cn%n%ce%n%ci%n%B', self.commit)