odoo-addon-odoo-repository 16.0.1.3.0.13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- odoo/addons/odoo_repository/README.rst +81 -0
- odoo/addons/odoo_repository/__init__.py +2 -0
- odoo/addons/odoo_repository/__manifest__.py +58 -0
- odoo/addons/odoo_repository/controllers/__init__.py +1 -0
- odoo/addons/odoo_repository/controllers/main.py +32 -0
- odoo/addons/odoo_repository/data/ir_cron.xml +38 -0
- odoo/addons/odoo_repository/data/odoo.repository.csv +216 -0
- odoo/addons/odoo_repository/data/odoo_branch.xml +82 -0
- odoo/addons/odoo_repository/data/odoo_module.xml +16 -0
- odoo/addons/odoo_repository/data/odoo_repository.xml +71 -0
- odoo/addons/odoo_repository/data/odoo_repository_addons_path.xml +59 -0
- odoo/addons/odoo_repository/data/odoo_repository_org.xml +14 -0
- odoo/addons/odoo_repository/data/queue_job.xml +56 -0
- odoo/addons/odoo_repository/lib/__init__.py +0 -0
- odoo/addons/odoo_repository/lib/scanner.py +1302 -0
- odoo/addons/odoo_repository/migrations/16.0.1.1.0/post-migration.py +26 -0
- odoo/addons/odoo_repository/migrations/16.0.1.2.0/pre-migration.py +43 -0
- odoo/addons/odoo_repository/migrations/16.0.1.3.0/post-migration.py +19 -0
- odoo/addons/odoo_repository/models/__init__.py +18 -0
- odoo/addons/odoo_repository/models/authentication_token.py +12 -0
- odoo/addons/odoo_repository/models/odoo_author.py +16 -0
- odoo/addons/odoo_repository/models/odoo_branch.py +111 -0
- odoo/addons/odoo_repository/models/odoo_license.py +16 -0
- odoo/addons/odoo_repository/models/odoo_maintainer.py +31 -0
- odoo/addons/odoo_repository/models/odoo_module.py +24 -0
- odoo/addons/odoo_repository/models/odoo_module_branch.py +873 -0
- odoo/addons/odoo_repository/models/odoo_module_branch_version.py +123 -0
- odoo/addons/odoo_repository/models/odoo_module_category.py +15 -0
- odoo/addons/odoo_repository/models/odoo_module_dev_status.py +15 -0
- odoo/addons/odoo_repository/models/odoo_python_dependency.py +16 -0
- odoo/addons/odoo_repository/models/odoo_repository.py +664 -0
- odoo/addons/odoo_repository/models/odoo_repository_addons_path.py +40 -0
- odoo/addons/odoo_repository/models/odoo_repository_branch.py +98 -0
- odoo/addons/odoo_repository/models/odoo_repository_org.py +23 -0
- odoo/addons/odoo_repository/models/res_company.py +23 -0
- odoo/addons/odoo_repository/models/res_config_settings.py +23 -0
- odoo/addons/odoo_repository/models/ssh_key.py +12 -0
- odoo/addons/odoo_repository/readme/CONTRIBUTORS.rst +2 -0
- odoo/addons/odoo_repository/readme/DESCRIPTION.rst +1 -0
- odoo/addons/odoo_repository/security/ir.model.access.csv +27 -0
- odoo/addons/odoo_repository/security/res_groups.xml +25 -0
- odoo/addons/odoo_repository/static/description/README +4 -0
- odoo/addons/odoo_repository/static/description/icon.png +0 -0
- odoo/addons/odoo_repository/static/description/index.html +430 -0
- odoo/addons/odoo_repository/tests/__init__.py +6 -0
- odoo/addons/odoo_repository/tests/common.py +162 -0
- odoo/addons/odoo_repository/tests/test_base_scanner.py +214 -0
- odoo/addons/odoo_repository/tests/test_odoo_module_branch.py +97 -0
- odoo/addons/odoo_repository/tests/test_odoo_repository_scan.py +242 -0
- odoo/addons/odoo_repository/tests/test_repository_scanner.py +215 -0
- odoo/addons/odoo_repository/tests/test_sync_node.py +55 -0
- odoo/addons/odoo_repository/tests/test_utils.py +25 -0
- odoo/addons/odoo_repository/utils/__init__.py +0 -0
- odoo/addons/odoo_repository/utils/github.py +30 -0
- odoo/addons/odoo_repository/utils/module.py +25 -0
- odoo/addons/odoo_repository/utils/scanner.py +90 -0
- odoo/addons/odoo_repository/views/authentication_token.xml +63 -0
- odoo/addons/odoo_repository/views/menu.xml +38 -0
- odoo/addons/odoo_repository/views/odoo_author.xml +54 -0
- odoo/addons/odoo_repository/views/odoo_branch.xml +84 -0
- odoo/addons/odoo_repository/views/odoo_license.xml +40 -0
- odoo/addons/odoo_repository/views/odoo_maintainer.xml +69 -0
- odoo/addons/odoo_repository/views/odoo_module.xml +90 -0
- odoo/addons/odoo_repository/views/odoo_module_branch.xml +353 -0
- odoo/addons/odoo_repository/views/odoo_module_category.xml +40 -0
- odoo/addons/odoo_repository/views/odoo_module_dev_status.xml +40 -0
- odoo/addons/odoo_repository/views/odoo_python_dependency.xml +40 -0
- odoo/addons/odoo_repository/views/odoo_repository.xml +165 -0
- odoo/addons/odoo_repository/views/odoo_repository_addons_path.xml +49 -0
- odoo/addons/odoo_repository/views/odoo_repository_branch.xml +60 -0
- odoo/addons/odoo_repository/views/odoo_repository_org.xml +54 -0
- odoo/addons/odoo_repository/views/res_config_settings.xml +123 -0
- odoo/addons/odoo_repository/views/ssh_key.xml +63 -0
- odoo_addon_odoo_repository-16.0.1.3.0.13.dist-info/METADATA +100 -0
- odoo_addon_odoo_repository-16.0.1.3.0.13.dist-info/RECORD +77 -0
- odoo_addon_odoo_repository-16.0.1.3.0.13.dist-info/WHEEL +5 -0
- odoo_addon_odoo_repository-16.0.1.3.0.13.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# Copyright 2024 Camptocamp SA
|
|
2
|
+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
|
3
|
+
|
|
4
|
+
import tempfile
|
|
5
|
+
|
|
6
|
+
from odoo.addons.odoo_repository.lib.scanner import BaseScanner
|
|
7
|
+
|
|
8
|
+
from .common import Common
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestBaseScanner(Common):
|
|
12
|
+
def _init_scanner(self, **params):
|
|
13
|
+
kwargs = {
|
|
14
|
+
"org": self.fork_org,
|
|
15
|
+
"name": self.repo_name,
|
|
16
|
+
"clone_url": self.repo_upstream_path,
|
|
17
|
+
"branches": [
|
|
18
|
+
self.branch1_name,
|
|
19
|
+
self.branch2_name,
|
|
20
|
+
self.branch3_name,
|
|
21
|
+
],
|
|
22
|
+
"repositories_path": self.repositories_path,
|
|
23
|
+
}
|
|
24
|
+
if params:
|
|
25
|
+
kwargs.update(params)
|
|
26
|
+
return BaseScanner(**kwargs)
|
|
27
|
+
|
|
28
|
+
def test_init(self):
|
|
29
|
+
scanner = self._init_scanner()
|
|
30
|
+
self.assertTrue(scanner.repositories_path.exists())
|
|
31
|
+
self.assertEqual(scanner.path.parts[-1], self.repo_name)
|
|
32
|
+
self.assertEqual(scanner.path.parts[-2], self.fork_org)
|
|
33
|
+
self.assertEqual(scanner.full_name, f"{self.fork_org}/{self.repo_name}")
|
|
34
|
+
|
|
35
|
+
def test_clone_url_github_token(self):
|
|
36
|
+
# Without token
|
|
37
|
+
base_clone_url = "https://github.com/OCA/test"
|
|
38
|
+
scanner = self._init_scanner(repo_type="github", clone_url=base_clone_url)
|
|
39
|
+
self.assertEqual(scanner.clone_url, base_clone_url)
|
|
40
|
+
# With a token
|
|
41
|
+
token = "test"
|
|
42
|
+
scanner = self._init_scanner(
|
|
43
|
+
repo_type="github", clone_url=base_clone_url, token=token
|
|
44
|
+
)
|
|
45
|
+
token_clone_url = f"https://oauth2:{token}@github.com/OCA/test"
|
|
46
|
+
self.assertEqual(scanner.clone_url, token_clone_url)
|
|
47
|
+
|
|
48
|
+
def test_sync(self):
|
|
49
|
+
scanner = self._init_scanner(repositories_path=tempfile.mkdtemp())
|
|
50
|
+
# Clone
|
|
51
|
+
self.assertFalse(scanner.path.exists())
|
|
52
|
+
self.assertFalse(scanner.is_cloned)
|
|
53
|
+
scanner.sync()
|
|
54
|
+
self.assertTrue(scanner.is_cloned)
|
|
55
|
+
# Fetch once cloned
|
|
56
|
+
scanner.sync()
|
|
57
|
+
|
|
58
|
+
def test_branch_exists(self):
|
|
59
|
+
scanner = self._init_scanner()
|
|
60
|
+
scanner.sync()
|
|
61
|
+
with scanner.repo() as repo:
|
|
62
|
+
self.assertTrue(scanner._branch_exists(repo, self.branch1_name))
|
|
63
|
+
self.assertTrue(scanner._branch_exists(repo, self.branch2_name))
|
|
64
|
+
self.assertTrue(scanner._branch_exists(repo, self.branch3_name))
|
|
65
|
+
|
|
66
|
+
def test_checkout_branch(self):
|
|
67
|
+
scanner = self._init_scanner()
|
|
68
|
+
scanner.sync()
|
|
69
|
+
with scanner.repo() as repo:
|
|
70
|
+
branch = self.branch2_name
|
|
71
|
+
branch_sha = repo.refs[f"origin/{branch}"].object.hexsha
|
|
72
|
+
self.assertNotEqual(repo.head.object.hexsha, branch_sha)
|
|
73
|
+
scanner._checkout_branch(repo, branch)
|
|
74
|
+
self.assertEqual(repo.head.object.hexsha, branch_sha)
|
|
75
|
+
|
|
76
|
+
def test_get_last_fetched_commit(self):
|
|
77
|
+
scanner = self._init_scanner()
|
|
78
|
+
scanner.sync()
|
|
79
|
+
with scanner.repo() as repo:
|
|
80
|
+
branch1 = self.branch1_name
|
|
81
|
+
branch2 = self.branch2_name
|
|
82
|
+
branch3 = self.branch3_name
|
|
83
|
+
branch1_sha = repo.refs[f"origin/{branch1}"].object.hexsha
|
|
84
|
+
branch2_sha = repo.refs[f"origin/{branch2}"].object.hexsha
|
|
85
|
+
branch3_sha = repo.refs[f"origin/{branch3}"].object.hexsha
|
|
86
|
+
self.assertEqual(
|
|
87
|
+
scanner._get_last_fetched_commit(repo, branch1), branch1_sha
|
|
88
|
+
)
|
|
89
|
+
self.assertEqual(
|
|
90
|
+
scanner._get_last_fetched_commit(repo, branch2), branch2_sha
|
|
91
|
+
)
|
|
92
|
+
self.assertEqual(
|
|
93
|
+
scanner._get_last_fetched_commit(repo, branch3), branch3_sha
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
def test_get_module_paths(self):
|
|
97
|
+
scanner = self._init_scanner()
|
|
98
|
+
scanner.sync()
|
|
99
|
+
with scanner.repo() as repo:
|
|
100
|
+
branch = self.branch1_name
|
|
101
|
+
module_paths = scanner._get_module_paths(repo, ".", branch)
|
|
102
|
+
self.assertEqual(len(module_paths), 1)
|
|
103
|
+
self.assertEqual(module_paths[0], self.addon)
|
|
104
|
+
|
|
105
|
+
def test_get_module_paths_updated(self):
|
|
106
|
+
scanner = self._init_scanner()
|
|
107
|
+
scanner.sync()
|
|
108
|
+
branch = self.branch1_name
|
|
109
|
+
with scanner.repo() as repo:
|
|
110
|
+
initial_commit = scanner._get_last_fetched_commit(repo, branch)
|
|
111
|
+
# Case where from_commit and to_commit are the same: no change detected
|
|
112
|
+
module_paths = scanner._get_module_paths_updated(
|
|
113
|
+
repo,
|
|
114
|
+
relative_path=".",
|
|
115
|
+
from_commit=initial_commit,
|
|
116
|
+
to_commit=initial_commit,
|
|
117
|
+
branch=branch,
|
|
118
|
+
)
|
|
119
|
+
self.assertFalse(module_paths)
|
|
120
|
+
# Update the upstream repository with a new commit
|
|
121
|
+
self._update_module_version_on_branch(branch, "1.0.1")
|
|
122
|
+
# Module is now detected has updated
|
|
123
|
+
scanner.sync() # Fetch new commit from upstream repo
|
|
124
|
+
with scanner.repo() as repo:
|
|
125
|
+
last_commit = scanner._get_last_fetched_commit(repo, branch)
|
|
126
|
+
module_paths = scanner._get_module_paths_updated(
|
|
127
|
+
repo,
|
|
128
|
+
relative_path=".",
|
|
129
|
+
from_commit=initial_commit,
|
|
130
|
+
to_commit=last_commit,
|
|
131
|
+
branch=branch,
|
|
132
|
+
)
|
|
133
|
+
self.assertEqual(len(module_paths), 1)
|
|
134
|
+
self.assertEqual(module_paths.pop(), self.addon)
|
|
135
|
+
|
|
136
|
+
def test_filter_file_path(self):
|
|
137
|
+
scanner = self._init_scanner()
|
|
138
|
+
self.assertFalse(scanner._filter_file_path("fr.po"))
|
|
139
|
+
self.assertTrue(scanner._filter_file_path("test.py"))
|
|
140
|
+
|
|
141
|
+
def test_get_last_commit_of_git_tree(self):
|
|
142
|
+
scanner = self._init_scanner()
|
|
143
|
+
scanner.sync()
|
|
144
|
+
with scanner.repo() as repo:
|
|
145
|
+
branch = self.branch1_name
|
|
146
|
+
remote_branch = f"origin/{branch}"
|
|
147
|
+
module = self.addon
|
|
148
|
+
module_tree = repo.tree(remote_branch) / module
|
|
149
|
+
all_commits = [c.hexsha for c in repo.iter_commits(remote_branch)]
|
|
150
|
+
commit = scanner._get_last_commit_of_git_tree(remote_branch, module_tree)
|
|
151
|
+
self.assertIn(commit, all_commits)
|
|
152
|
+
|
|
153
|
+
def test_get_commits_of_git_tree(self):
|
|
154
|
+
scanner = self._init_scanner()
|
|
155
|
+
scanner.sync()
|
|
156
|
+
with scanner.repo() as repo:
|
|
157
|
+
branch = self.branch1_name
|
|
158
|
+
remote_branch = f"origin/{branch}"
|
|
159
|
+
module = self.addon
|
|
160
|
+
module_tree = repo.tree(remote_branch) / module
|
|
161
|
+
all_commits = [c.hexsha for c in repo.iter_commits(remote_branch)]
|
|
162
|
+
commits = scanner._get_commits_of_git_tree(
|
|
163
|
+
from_=None, to_=remote_branch, tree=module_tree
|
|
164
|
+
)
|
|
165
|
+
for commit in commits:
|
|
166
|
+
self.assertIn(commit, all_commits)
|
|
167
|
+
|
|
168
|
+
def test_odoo_module(self):
|
|
169
|
+
scanner = self._init_scanner()
|
|
170
|
+
scanner.sync()
|
|
171
|
+
with scanner.repo() as repo:
|
|
172
|
+
branch = self.branch1_name
|
|
173
|
+
remote_branch = f"origin/{branch}"
|
|
174
|
+
module = self.addon
|
|
175
|
+
module_tree = repo.tree(remote_branch) / module
|
|
176
|
+
self.assertTrue(scanner._odoo_module(module_tree))
|
|
177
|
+
|
|
178
|
+
def test_manifest_exists(self):
|
|
179
|
+
scanner = self._init_scanner()
|
|
180
|
+
scanner.sync()
|
|
181
|
+
with scanner.repo() as repo:
|
|
182
|
+
branch = self.branch1_name
|
|
183
|
+
remote_branch = f"origin/{branch}"
|
|
184
|
+
# Check module tree: OK
|
|
185
|
+
module = self.addon
|
|
186
|
+
module_tree = repo.tree(remote_branch) / module
|
|
187
|
+
self.assertTrue(scanner._manifest_exists(module_tree))
|
|
188
|
+
# Check repository root tree: KO
|
|
189
|
+
self.assertFalse(scanner._manifest_exists(repo.tree(remote_branch)))
|
|
190
|
+
|
|
191
|
+
def test_get_subtree(self):
|
|
192
|
+
scanner = self._init_scanner()
|
|
193
|
+
scanner.sync()
|
|
194
|
+
with scanner.repo() as repo:
|
|
195
|
+
branch = self.branch1_name
|
|
196
|
+
remote_branch = f"origin/{branch}"
|
|
197
|
+
module = self.addon
|
|
198
|
+
# Module/folder exists: OK
|
|
199
|
+
self.assertTrue(scanner._get_subtree(repo.tree(remote_branch), module))
|
|
200
|
+
# Module/folder doesn't exist: KO
|
|
201
|
+
self.assertFalse(scanner._get_subtree(repo.tree(remote_branch), "none"))
|
|
202
|
+
|
|
203
|
+
def test_workaround_fs_errors(self):
|
|
204
|
+
scanner = self._init_scanner(
|
|
205
|
+
repositories_path=tempfile.mkdtemp(),
|
|
206
|
+
workaround_fs_errors=True,
|
|
207
|
+
)
|
|
208
|
+
# Clone
|
|
209
|
+
self.assertFalse(scanner.path.exists())
|
|
210
|
+
self.assertFalse(scanner.is_cloned)
|
|
211
|
+
scanner.sync()
|
|
212
|
+
self.assertTrue(scanner.is_cloned)
|
|
213
|
+
# Fetch once cloned
|
|
214
|
+
scanner.sync()
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Copyright 2024 Camptocamp SA
|
|
2
|
+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
|
3
|
+
|
|
4
|
+
from odoo.exceptions import ValidationError
|
|
5
|
+
|
|
6
|
+
from .common import Common
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestOdooModuleBranch(Common):
|
|
10
|
+
def test_constraint_generic_depends_on_specific(self):
|
|
11
|
+
generic_mod = self._create_odoo_module("generic_mod")
|
|
12
|
+
generic_mod_branch = self._create_odoo_module_branch(
|
|
13
|
+
generic_mod, self.branch, specific=False
|
|
14
|
+
)
|
|
15
|
+
specific_mod = self._create_odoo_module("specific_mod")
|
|
16
|
+
specific_mod_branch = self._create_odoo_module_branch(
|
|
17
|
+
specific_mod, self.branch, specific=True
|
|
18
|
+
)
|
|
19
|
+
with self.assertRaises(ValidationError):
|
|
20
|
+
generic_mod_branch.dependency_ids = specific_mod_branch
|
|
21
|
+
|
|
22
|
+
def test_dependency_level(self):
|
|
23
|
+
# base module in the dependencies tree
|
|
24
|
+
mod_base = self._create_odoo_module("base")
|
|
25
|
+
mod_base_branch = self._create_odoo_module_branch(
|
|
26
|
+
mod_base, self.branch, is_standard=True
|
|
27
|
+
)
|
|
28
|
+
self.assertEqual(mod_base_branch.global_dependency_level, 1)
|
|
29
|
+
self.assertEqual(mod_base_branch.non_std_dependency_level, 0)
|
|
30
|
+
# add a standard module depending on the base one
|
|
31
|
+
mod_std = self._create_odoo_module("std")
|
|
32
|
+
mod_std_branch = self._create_odoo_module_branch(
|
|
33
|
+
mod_std,
|
|
34
|
+
self.branch,
|
|
35
|
+
is_standard=True,
|
|
36
|
+
dependency_ids=[(4, mod_base_branch.id)],
|
|
37
|
+
)
|
|
38
|
+
self.assertEqual(mod_std_branch.global_dependency_level, 2)
|
|
39
|
+
self.assertEqual(mod_std_branch.non_std_dependency_level, 0)
|
|
40
|
+
# add a non-standard module depending on the std one
|
|
41
|
+
mod_non_std = self._create_odoo_module("non_std")
|
|
42
|
+
mod_non_std_branch = self._create_odoo_module_branch(
|
|
43
|
+
mod_non_std,
|
|
44
|
+
self.branch,
|
|
45
|
+
is_standard=False,
|
|
46
|
+
dependency_ids=[(4, mod_std_branch.id)],
|
|
47
|
+
)
|
|
48
|
+
self.assertEqual(mod_non_std_branch.global_dependency_level, 3)
|
|
49
|
+
self.assertEqual(mod_non_std_branch.non_std_dependency_level, 1)
|
|
50
|
+
# add another one depending on base module
|
|
51
|
+
mod_non_std2 = self._create_odoo_module("non_std2")
|
|
52
|
+
mod_non_std2_branch = self._create_odoo_module_branch(
|
|
53
|
+
mod_non_std2,
|
|
54
|
+
self.branch,
|
|
55
|
+
is_standard=False,
|
|
56
|
+
dependency_ids=[(4, mod_base_branch.id)],
|
|
57
|
+
)
|
|
58
|
+
self.assertEqual(mod_non_std2_branch.global_dependency_level, 2)
|
|
59
|
+
self.assertEqual(mod_non_std2_branch.non_std_dependency_level, 1)
|
|
60
|
+
# add another one depending on non-std module
|
|
61
|
+
mod_non_std3 = self._create_odoo_module("non_std3")
|
|
62
|
+
mod_non_std3_branch = self._create_odoo_module_branch(
|
|
63
|
+
mod_non_std3,
|
|
64
|
+
self.branch,
|
|
65
|
+
is_standard=False,
|
|
66
|
+
dependency_ids=[(4, mod_non_std_branch.id)],
|
|
67
|
+
)
|
|
68
|
+
self.assertEqual(mod_non_std3_branch.global_dependency_level, 4)
|
|
69
|
+
self.assertEqual(mod_non_std3_branch.non_std_dependency_level, 2)
|
|
70
|
+
|
|
71
|
+
def test_find(self):
|
|
72
|
+
mb_model = self.env["odoo.module.branch"]
|
|
73
|
+
mod = self._create_odoo_module("my_module")
|
|
74
|
+
repo = self.odoo_repository
|
|
75
|
+
repo2 = self.odoo_repository.copy({"name": "Repo2"})
|
|
76
|
+
# Find orphaned module
|
|
77
|
+
mod_orphaned = mb_model._create_orphaned_module_branch(self.branch, mod)
|
|
78
|
+
self.assertEqual(mb_model._find(self.branch, mod, repo), mod_orphaned)
|
|
79
|
+
# Find generic module
|
|
80
|
+
repo_branch = self._create_odoo_repository_branch(repo, self.branch)
|
|
81
|
+
mod_generic = self._create_odoo_module_branch(
|
|
82
|
+
mod,
|
|
83
|
+
self.branch,
|
|
84
|
+
specific=False,
|
|
85
|
+
repository_branch_id=repo_branch.id,
|
|
86
|
+
)
|
|
87
|
+
self.assertEqual(mb_model._find(self.branch, mod, repo), mod_generic)
|
|
88
|
+
# Find module in current repository
|
|
89
|
+
repo2_branch = self._create_odoo_repository_branch(repo2, self.branch)
|
|
90
|
+
mod_in_repo2 = self._create_odoo_module_branch(
|
|
91
|
+
mod,
|
|
92
|
+
self.branch,
|
|
93
|
+
repository_branch_id=repo2_branch.id,
|
|
94
|
+
)
|
|
95
|
+
self.assertEqual(mb_model._find(self.branch, mod, repo2), mod_in_repo2)
|
|
96
|
+
# While we have 3 modules (hosted in different repos or orphaned)
|
|
97
|
+
self.assertEqual(len(mod.module_branch_ids), 3)
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# Copyright 2024 Camptocamp SA
|
|
2
|
+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
|
3
|
+
|
|
4
|
+
from odoo import fields
|
|
5
|
+
|
|
6
|
+
from .common import Common
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestOdooRepositoryScan(Common):
|
|
10
|
+
def test_check_config(self):
|
|
11
|
+
self.odoo_repository._check_config()
|
|
12
|
+
|
|
13
|
+
def test_action_scan_basic(self):
|
|
14
|
+
"""Test the creation of a module when scanning a (generic) repository."""
|
|
15
|
+
self.assertFalse(self.odoo_repository.specific)
|
|
16
|
+
module = self.env["odoo.module"].search([("name", "=", self.module_name)])
|
|
17
|
+
self.assertFalse(module)
|
|
18
|
+
self._run_odoo_repository_action_scan(self.branch.id)
|
|
19
|
+
# Check module technical name
|
|
20
|
+
module = self.env["odoo.module"].search([("name", "=", self.module_name)])
|
|
21
|
+
self.assertTrue(module)
|
|
22
|
+
# Check module branch
|
|
23
|
+
module_branch = self.env["odoo.module.branch"].search(
|
|
24
|
+
[("module_id", "=", module.id), ("branch_id", "=", self.branch.id)]
|
|
25
|
+
)
|
|
26
|
+
self.assertEqual(module_branch.module_name, self.module_name)
|
|
27
|
+
self.assertTrue(module_branch.last_scanned_commit)
|
|
28
|
+
self.assertEqual(module_branch.repository_id, self.odoo_repository)
|
|
29
|
+
self.assertEqual(module_branch.org_id, self.org)
|
|
30
|
+
self.assertEqual(module_branch.title, "Test")
|
|
31
|
+
self.assertEqual(module_branch.category_id.name, "Test Module")
|
|
32
|
+
self.assertItemsEqual(
|
|
33
|
+
module_branch.author_ids.mapped("name"),
|
|
34
|
+
["Odoo Community Association (OCA)", "Camptocamp"],
|
|
35
|
+
)
|
|
36
|
+
self.assertFalse(module_branch.specific)
|
|
37
|
+
self.assertEqual(module_branch.dependency_ids.module_name, "base")
|
|
38
|
+
self.assertFalse(module_branch.dependency_ids.specific)
|
|
39
|
+
self.assertEqual(module_branch.license_id.name, "AGPL-3")
|
|
40
|
+
self.assertEqual(module_branch.version, "1.0.0")
|
|
41
|
+
self.assertEqual(module_branch.version_ids.manifest_value, "1.0.0")
|
|
42
|
+
self.assertEqual(module_branch.version_ids.name, f"{self.branch.name}.1.0.0")
|
|
43
|
+
self.assertEqual(
|
|
44
|
+
module_branch.version_ids.commit, module_branch.last_scanned_commit
|
|
45
|
+
)
|
|
46
|
+
self.assertFalse(module_branch.version_ids.has_migration_script)
|
|
47
|
+
self.assertTrue(module_branch.sloc_python)
|
|
48
|
+
self.assertEqual(module_branch.addons_path, ".")
|
|
49
|
+
# Check repository branch
|
|
50
|
+
repo_branch = module_branch.repository_branch_id
|
|
51
|
+
self.assertEqual(repo_branch.branch_id, self.branch)
|
|
52
|
+
self.assertEqual(
|
|
53
|
+
repo_branch.last_scanned_commit, module_branch.last_scanned_commit
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
def test_action_scan_repo_specific(self):
|
|
57
|
+
"""Test the creation of a module when scanning a specific repository."""
|
|
58
|
+
self.odoo_repository.specific = True
|
|
59
|
+
self.odoo_repository.write(
|
|
60
|
+
{
|
|
61
|
+
"specific": True,
|
|
62
|
+
"branch_ids": [
|
|
63
|
+
fields.Command.create({"branch_id": self.branch.id}),
|
|
64
|
+
],
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
self.assertTrue(self.odoo_repository.specific)
|
|
68
|
+
self._run_odoo_repository_action_scan(self.branch.id)
|
|
69
|
+
# Check module data
|
|
70
|
+
module = self.env["odoo.module"].search([("name", "=", self.module_name)])
|
|
71
|
+
module_branch = self.env["odoo.module.branch"].search(
|
|
72
|
+
[("module_id", "=", module.id), ("branch_id", "=", self.branch.id)]
|
|
73
|
+
)
|
|
74
|
+
self.assertTrue(module_branch.specific)
|
|
75
|
+
self.assertFalse(module_branch.dependency_ids.specific)
|
|
76
|
+
|
|
77
|
+
def test_action_scan_repo_module_exists(self):
|
|
78
|
+
"""Test the update of existing module when scanning a repository.
|
|
79
|
+
|
|
80
|
+
If a module has already been scanned in the current repository, a second
|
|
81
|
+
scan will trigger an update of its data.
|
|
82
|
+
"""
|
|
83
|
+
# First scan, like in `test_action_scan_first_time`
|
|
84
|
+
self._run_odoo_repository_action_scan(self.branch.id)
|
|
85
|
+
module = self.env["odoo.module"].search([("name", "=", self.module_name)])
|
|
86
|
+
module_branch = self.env["odoo.module.branch"].search(
|
|
87
|
+
[("module_id", "=", module.id), ("branch_id", "=", self.branch.id)]
|
|
88
|
+
)
|
|
89
|
+
# Change some data in the module before triggering the second scan
|
|
90
|
+
module_branch.write({"title": False})
|
|
91
|
+
# Launch a second scan (force it to make it happen)
|
|
92
|
+
self._run_odoo_repository_action_scan(self.branch.id, force=True)
|
|
93
|
+
self.assertEqual(module_branch.title, "Test")
|
|
94
|
+
|
|
95
|
+
def test_action_scan_orphaned_module_exists(self):
|
|
96
|
+
"""Test the link of an orphaned module when scanning a repository.
|
|
97
|
+
|
|
98
|
+
An orphaned module is a record without repository assigned while we know
|
|
99
|
+
its name and branch. Such record is automatically created when generating
|
|
100
|
+
dependencies of a given module that have not been scanned yet, or by
|
|
101
|
+
importing installed modules in a project (see `odoo_project` Odoo module).
|
|
102
|
+
|
|
103
|
+
If such a module matches a module scanned in a repository, it is updated
|
|
104
|
+
accordingly to belong to this repository.
|
|
105
|
+
"""
|
|
106
|
+
# Create an orphaned module.
|
|
107
|
+
# To ease its creation, we run a scan to get the record created, and
|
|
108
|
+
# we update it to make it orphaned.
|
|
109
|
+
self._run_odoo_repository_action_scan(self.branch.id)
|
|
110
|
+
module = self.env["odoo.module"].search([("name", "=", self.module_name)])
|
|
111
|
+
module_branch = self.env["odoo.module.branch"].search(
|
|
112
|
+
[("module_id", "=", module.id), ("branch_id", "=", self.branch.id)]
|
|
113
|
+
)
|
|
114
|
+
module_branch.write(
|
|
115
|
+
{
|
|
116
|
+
"repository_branch_id": False,
|
|
117
|
+
"last_scanned_commit": False,
|
|
118
|
+
"dependency_ids": False,
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
# Launch a scan
|
|
122
|
+
self._run_odoo_repository_action_scan(self.branch.id, force=True)
|
|
123
|
+
self.assertEqual(module_branch.repository_id, self.odoo_repository)
|
|
124
|
+
|
|
125
|
+
def _create_wrong_repo_branch(self, repo_sequence=100):
|
|
126
|
+
wrong_repo = self.env["odoo.repository"].create(
|
|
127
|
+
{
|
|
128
|
+
"org_id": self.odoo_repository.org_id.id,
|
|
129
|
+
"name": "wrong_repo",
|
|
130
|
+
"repo_url": "https://example.net/OCA-test/wrong_repo",
|
|
131
|
+
"clone_url": "https://example.net/OCA-test/wrong_repo",
|
|
132
|
+
"repo_type": "github",
|
|
133
|
+
"sequence": repo_sequence,
|
|
134
|
+
}
|
|
135
|
+
)
|
|
136
|
+
wrong_repo_branch = self.env["odoo.repository.branch"].create(
|
|
137
|
+
{
|
|
138
|
+
"repository_id": wrong_repo.id,
|
|
139
|
+
"branch_id": self.branch.id,
|
|
140
|
+
}
|
|
141
|
+
)
|
|
142
|
+
return wrong_repo_branch
|
|
143
|
+
|
|
144
|
+
def _create_unmerged_module_branch(self):
|
|
145
|
+
# To ease the creation of such module, we run a scan to get the record
|
|
146
|
+
# created, and we update it to make it unmerged/pending.
|
|
147
|
+
self._run_odoo_repository_action_scan(self.branch.id)
|
|
148
|
+
module = self.env["odoo.module"].search([("name", "=", self.module_name)])
|
|
149
|
+
module_branch = self.env["odoo.module.branch"].search(
|
|
150
|
+
[("module_id", "=", module.id), ("branch_id", "=", self.branch.id)]
|
|
151
|
+
)
|
|
152
|
+
wrong_repo_branch = self._create_wrong_repo_branch(
|
|
153
|
+
# Lower priority than self.odoo_repository
|
|
154
|
+
repo_sequence=200
|
|
155
|
+
)
|
|
156
|
+
wrong_repo = wrong_repo_branch.repository_id
|
|
157
|
+
module_branch.write(
|
|
158
|
+
{
|
|
159
|
+
"repository_branch_id": wrong_repo_branch,
|
|
160
|
+
"last_scanned_commit": False,
|
|
161
|
+
"dependency_ids": False,
|
|
162
|
+
"pr_url": f"{wrong_repo.repo_url}/pull/1",
|
|
163
|
+
"specific": False,
|
|
164
|
+
}
|
|
165
|
+
)
|
|
166
|
+
return module_branch
|
|
167
|
+
|
|
168
|
+
def test_action_scan_repo_generic_unmerged_module_exists(self):
|
|
169
|
+
"""Test link of an unmerged module when scanning a generic repository.
|
|
170
|
+
|
|
171
|
+
An unmerged module is like an orphaned module but with a PR attached.
|
|
172
|
+
However such PR indicates from which repository a module is coming from,
|
|
173
|
+
but this information could also be wrong (wrong PR detected on the wrong
|
|
174
|
+
repository).
|
|
175
|
+
|
|
176
|
+
Note: unmerged modules can only be generic, as PR detection is restricted
|
|
177
|
+
only to generic modules.
|
|
178
|
+
|
|
179
|
+
When scanning a generic repository, if an unmerged module is
|
|
180
|
+
detected it should be linked to this scanned repository.
|
|
181
|
+
"""
|
|
182
|
+
self.odoo_repository.specific = False
|
|
183
|
+
# Create an unmerged module
|
|
184
|
+
module_branch = self._create_unmerged_module_branch()
|
|
185
|
+
self.assertFalse(module_branch.specific)
|
|
186
|
+
self.assertNotEqual(module_branch.repository_id, self.odoo_repository)
|
|
187
|
+
# Launch a scan
|
|
188
|
+
self._run_odoo_repository_action_scan(self.branch.id, force=True)
|
|
189
|
+
self.assertFalse(module_branch.specific)
|
|
190
|
+
self.assertEqual(module_branch.repository_id, self.odoo_repository)
|
|
191
|
+
|
|
192
|
+
def test_action_scan_repo_specific_unmerged_module_exists(self):
|
|
193
|
+
"""Test non-link of an unmerged module when scanning a specific repository.
|
|
194
|
+
|
|
195
|
+
When scanning a specific repository, detection of unmerged modules is
|
|
196
|
+
not done as such modules are linked to generic repositories only.
|
|
197
|
+
"""
|
|
198
|
+
self.odoo_repository.specific = True
|
|
199
|
+
# Create an unmerged module
|
|
200
|
+
module_branch = self._create_unmerged_module_branch()
|
|
201
|
+
self.assertFalse(module_branch.specific)
|
|
202
|
+
self.assertNotEqual(module_branch.repository_id, self.odoo_repository)
|
|
203
|
+
# Launch a scan
|
|
204
|
+
self._run_odoo_repository_action_scan(self.branch.id, force=True)
|
|
205
|
+
# Unmerged module hasn't been attached to the scanned repository
|
|
206
|
+
self.assertNotEqual(module_branch.repository_id, self.odoo_repository)
|
|
207
|
+
|
|
208
|
+
def test_action_scan_uninstallable_module(self):
|
|
209
|
+
"""Test scan of an 'installable: False' module.
|
|
210
|
+
|
|
211
|
+
Such module should not be created with its dependencies (Odoo, Python...)
|
|
212
|
+
or versions history to not pollute the DB. Such data could be
|
|
213
|
+
outdated as the module is flagged as not installable. They will be updated
|
|
214
|
+
once the module is migrated/installable.
|
|
215
|
+
"""
|
|
216
|
+
self._update_module_installable_on_branch(self.branch.name, installable=False)
|
|
217
|
+
module = self.env["odoo.module"].search([("name", "=", self.module_name)])
|
|
218
|
+
self.assertFalse(module)
|
|
219
|
+
self._run_odoo_repository_action_scan(self.branch.id)
|
|
220
|
+
module = self.env["odoo.module"].search([("name", "=", self.module_name)])
|
|
221
|
+
self.assertTrue(module)
|
|
222
|
+
# Check module branch
|
|
223
|
+
module_branch = self.env["odoo.module.branch"].search(
|
|
224
|
+
[("module_id", "=", module.id), ("branch_id", "=", self.branch.id)]
|
|
225
|
+
)
|
|
226
|
+
self.assertEqual(module_branch.module_name, self.module_name)
|
|
227
|
+
self.assertTrue(module_branch.last_scanned_commit)
|
|
228
|
+
self.assertEqual(module_branch.repository_id, self.odoo_repository)
|
|
229
|
+
self.assertEqual(module_branch.org_id, self.org)
|
|
230
|
+
self.assertEqual(module_branch.title, "Test")
|
|
231
|
+
self.assertEqual(module_branch.category_id.name, "Test Module")
|
|
232
|
+
self.assertItemsEqual(
|
|
233
|
+
module_branch.author_ids.mapped("name"),
|
|
234
|
+
["Odoo Community Association (OCA)", "Camptocamp"],
|
|
235
|
+
)
|
|
236
|
+
self.assertFalse(module_branch.specific)
|
|
237
|
+
# No dependencies
|
|
238
|
+
self.assertFalse(module_branch.dependency_ids)
|
|
239
|
+
self.assertFalse(module_branch.external_dependencies)
|
|
240
|
+
self.assertFalse(module_branch.python_dependency_ids)
|
|
241
|
+
# No version scanned
|
|
242
|
+
self.assertFalse(module_branch.version_ids)
|