2021-12-08 19:50:23 +07:00
|
|
|
from odoo import models, fields, api
|
|
|
|
from unittest.mock import patch
|
|
|
|
from odoo.tools import mute_logger
|
|
|
|
|
|
|
|
import logging
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
2023-06-20 14:47:20 +07:00
|
|
|
|
2021-12-08 19:50:23 +07:00
|
|
|
class Runbot(models.AbstractModel):
|
|
|
|
_inherit = 'runbot.runbot'
|
|
|
|
|
|
|
|
@api.model
|
|
|
|
@patch('odoo.addons.runbot.models.repo.Remote._github')
|
|
|
|
@patch('odoo.addons.runbot.models.repo.Repo._git')
|
|
|
|
def _create_demo_data(self, mock_git, mock_github):
|
|
|
|
mock_github.return_value = False
|
2023-01-11 00:48:55 +07:00
|
|
|
project = self.env.ref('runbot.main_project')
|
2021-12-08 19:50:23 +07:00
|
|
|
bundles = self.env['runbot.bundle'].browse(
|
|
|
|
self.env['ir.model.data'].search([
|
|
|
|
('module', '=', 'runbot_populate'), ('model', '=', 'runbot.bundle')
|
|
|
|
]).mapped('res_id')
|
2023-01-11 00:48:55 +07:00
|
|
|
).filtered(lambda bundle: bundle.project_id == project)
|
|
|
|
bundles |= project.master_bundle_id
|
2021-12-08 19:50:23 +07:00
|
|
|
bundles = bundles.sorted('is_base', reverse=True)
|
|
|
|
|
2023-01-11 00:48:55 +07:00
|
|
|
existing_bundle = bundles.search([('project_id', '=', project.id)])
|
|
|
|
expected_bundle = bundles | project.dummy_bundle_id
|
|
|
|
|
|
|
|
assert expected_bundle == existing_bundle
|
2021-12-08 19:50:23 +07:00
|
|
|
|
[IMP] runbot: use custom layout and improve views
Runbot layout modifies the website/portal base layout to remove navbar,
footer, overides some custom styles. A lot of assets are loaded but not
used. The only real usefull elements are base assets (bootstrap, ...)
and the login button.
Migrating to the next version of odoo is usually painfull because some
xpath may break, extra element added, or some style change may break the
page, needing to add more and more xpath, css rules, ... for very little
benefits.
This cleanup creates a custom base layout for runbot independant from
base odoo templates.
Also add a breadcrumb, navigation arrow, and improve batch links
2021-12-10 22:09:57 +07:00
|
|
|
if bundles.branch_ids:
|
2021-12-08 19:50:23 +07:00
|
|
|
# only populate data if no branch are found
|
|
|
|
return
|
|
|
|
|
|
|
|
if not bundles.branch_ids:
|
|
|
|
pr = True
|
|
|
|
count = 1000
|
|
|
|
for bundle in bundles:
|
|
|
|
_logger.info(bundle.name)
|
|
|
|
for repo in bundle.project_id.repo_ids:
|
|
|
|
main_remote = repo.main_remote_id
|
|
|
|
dev_remote = next((remote for remote in repo.remote_ids if remote != main_remote), main_remote)
|
|
|
|
if bundle.is_base:
|
|
|
|
dev_remote = main_remote
|
|
|
|
self.env['runbot.branch'].create({'remote_id': dev_remote.id, 'name': bundle.name, 'is_pr': False})
|
2022-02-01 14:48:16 +07:00
|
|
|
if not bundle.is_base:
|
2021-12-08 19:50:23 +07:00
|
|
|
mock_github.return_value = {
|
|
|
|
'base': {
|
|
|
|
'ref': bundle.base_id.name
|
|
|
|
},
|
|
|
|
'head': {
|
|
|
|
'label': '%s:%s' % (dev_remote.owner, bundle.name),
|
|
|
|
'repo': {'full_name': '%s/%s' % (dev_remote.owner, dev_remote.repo_name)}
|
2022-11-21 15:11:12 +07:00
|
|
|
},
|
|
|
|
'title': '[IMP] Title',
|
|
|
|
'body': 'Body',
|
2022-11-21 22:45:31 +07:00
|
|
|
'user': {
|
2022-11-21 15:11:12 +07:00
|
|
|
'login': 'Pr author'
|
|
|
|
},
|
2021-12-08 19:50:23 +07:00
|
|
|
}
|
|
|
|
branch = self.env['runbot.branch'].create({
|
|
|
|
'remote_id': main_remote.id,
|
|
|
|
'name': str(count),
|
|
|
|
'is_pr': True,
|
|
|
|
})
|
|
|
|
count += 1
|
2023-06-20 14:47:20 +07:00
|
|
|
branch.flush_recordset()
|
2021-12-08 19:50:23 +07:00
|
|
|
|
2022-02-01 14:48:16 +07:00
|
|
|
if 'partial' in bundle.name:
|
|
|
|
break
|
|
|
|
|
2021-12-08 19:50:23 +07:00
|
|
|
if not bundle.is_base:
|
|
|
|
pr = not pr
|
|
|
|
|
|
|
|
security_config = self.env.ref('runbot_populate.runbot_build_config_security')
|
|
|
|
linting_config = self.env.ref('runbot_populate.runbot_build_config_linting')
|
|
|
|
|
|
|
|
for bundle in bundles:
|
|
|
|
nb_batch = 4 if bundle.sticky else 2
|
|
|
|
for i in range(nb_batch):
|
|
|
|
values = {
|
|
|
|
'last_update': fields.Datetime.now(),
|
|
|
|
'bundle_id': bundle.id,
|
|
|
|
'state': 'preparing',
|
|
|
|
}
|
|
|
|
batch = self.env['runbot.batch'].create(values)
|
|
|
|
bundle.last_batch = batch
|
|
|
|
for repo in bundle.project_id.repo_ids:
|
|
|
|
commit = self.env['runbot.commit']._get('%s00b%s0000ba%s000' % (repo.id, bundle.id, batch.id), repo.id, {
|
|
|
|
'author': 'Author',
|
|
|
|
'author_email': 'author@example.com',
|
|
|
|
'committer': 'Committer',
|
|
|
|
'committer_email': 'committer@example.com',
|
|
|
|
'subject': '[IMP] core: come imp',
|
|
|
|
'date': fields.Datetime.now(),
|
|
|
|
})
|
|
|
|
branches = bundle.branch_ids.filtered(lambda b: b.remote_id.repo_id == repo)
|
|
|
|
for branch in branches:
|
|
|
|
branch.head = commit
|
|
|
|
batch._new_commit(branch)
|
|
|
|
|
|
|
|
def git(command):
|
|
|
|
if command[0] == 'merge-base':
|
|
|
|
_, sha1, sha2 = command
|
2022-02-01 14:48:16 +07:00
|
|
|
return sha1 if sha1 == sha2 else sha2 #if bundle.is_base else '%s_%s' % (sha1, sha2)
|
2021-12-08 19:50:23 +07:00
|
|
|
elif command[0] == 'rev-list':
|
|
|
|
_, _, _, shas = command
|
|
|
|
sha1, sha2 = shas.split('...')
|
|
|
|
return '0\t0' if command[1] == command[2] else '3\t5'
|
|
|
|
elif command[0] == 'diff':
|
|
|
|
_, _, sha1, sha2 = command
|
|
|
|
return '' if sha1 == sha2 else '0 5 _\n1 8 _'
|
|
|
|
else:
|
|
|
|
_logger.info(command)
|
|
|
|
|
|
|
|
mock_git.side_effect = git
|
|
|
|
with mute_logger('odoo.addons.runbot.models.batch'):
|
2024-03-29 17:12:27 +07:00
|
|
|
batch._process()
|
2021-12-08 19:50:23 +07:00
|
|
|
if i != nb_batch - 1:
|
|
|
|
for slot in batch.slot_ids:
|
|
|
|
if slot.build_id:
|
|
|
|
build = slot.build_id
|
|
|
|
with mute_logger('odoo.addons.runbot.models.build'):
|
|
|
|
build._log('******','Starting step X', level='SEPARATOR')
|
|
|
|
build._log('******','Some log')
|
|
|
|
for config in (linting_config, security_config):
|
|
|
|
child = build._add_child({'config_id': config.id})
|
|
|
|
build._log('create_build', 'created with config %s' % config.name, log_type='subbuild', path=str(child.id))
|
|
|
|
child.local_state = 'done'
|
|
|
|
child.local_result = 'ok'
|
|
|
|
child.description = "Description for security"
|
|
|
|
build._log('******','Step x finished')
|
|
|
|
build._log('******','Starting step Y', level='SEPARATOR')
|
|
|
|
build._log('******','Some log', level='ERROR')
|
|
|
|
build._log('******','Some log\n with multiple lines', level='ERROR')
|
[FIX] runbot: fix markdown adding escape
A common error on runbot is to generate link containing a __init__.py
file
[/some/path/to/__init__.py](/some/path/to/__init__.py)
This would be rendered as
<a href="/some/path/to/<ins>init<ins>.py">/some/path/to/<ins>init<ins>.py</a>
Breaking the link, and the display of the name
By default markdown will not render links avoiding this issue, but it
will remain for the content of the a, needing to manage some kind of
escaping.
The way to escape markdown is to add a \ before any special character
This must be done upront before formating, adding the method
markdown_escape
Our implementation of markdown is not meant to meet the exact
specification of markdown but better suit our needs. One of the
requirements is to be able to use it to format message easily but adding
dynamic countent comming from the outside. One of the error than can
occur is also
'Some code `%s`' % code can also cause problem if code contains `
This issue could be solved using indented code block, but this would
need to complexify the generated string, have a dedicated method to
escape the code blocs, ...
Since we have the controll on the input, we can easily sanitize all
ynamic content to avoid such issues. For code block we introduce a way
to escape backtick (\`). It is non standard but will be easier to use.
Combine with that, the build._log method now allows to add args with the
values to format the string (similar to logging) but will escape
params by default. (cr.execute spirit)
name = '__init__.py'
url = 'path/to/__init__.py'
code = '# comment `for` something'
build._log('f', 'Some message [%s](%s) \n `%s`', name, url, code)
name, url and code will be escaped
2024-09-03 20:25:17 +07:00
|
|
|
build._log('******','**Some** *markdown* [log](%s)', 'http://example.com', log_type='markdown')
|
2021-12-08 19:50:23 +07:00
|
|
|
build._log('******','Step x finished', level='SEPARATOR')
|
|
|
|
|
|
|
|
build.local_state = 'done'
|
|
|
|
build.local_result = 'ok' if bundle.sticky else 'ko'
|
|
|
|
|
|
|
|
|
|
|
|
batch._process()
|