Skip to content

Commit 91251dd

Browse files
committed
[ADD] vcp_psc
1 parent ce6180b commit 91251dd

20 files changed

Lines changed: 868 additions & 0 deletions

‎requirements.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# generated from manifests external_dependencies
22
GitPython
3+
PyYAML
34
github3.py
45
markdown
56
pathspec

‎vcp_psc/README.rst‎

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
=======================
2+
Contributors Github Psc
3+
=======================
4+
5+
..
6+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
7+
!! This file is generated by oca-gen-addon-readme !!
8+
!! changes will be overwritten. !!
9+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10+
!! source digest: sha256:183c6a4f3366dc8045913f644b065e91fe8cd0cc8f869dc7b02ca87df5267e50
11+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12+
13+
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
14+
:target: https://odoo-community.org/page/development-status
15+
:alt: Beta
16+
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
17+
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
18+
:alt: License: AGPL-3
19+
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fversion--control--platform-lightgray.png?logo=github
20+
:target: https://github.com/OCA/version-control-platform/tree/18.0/vcp_psc
21+
:alt: OCA/version-control-platform
22+
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
23+
:target: https://translation.odoo-community.org/projects/version-control-platform-18-0/version-control-platform-18-0-vcp_psc
24+
:alt: Translate me on Weblate
25+
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
26+
:target: https://runboat.odoo-community.org/builds?repo=OCA/version-control-platform&target_branch=18.0
27+
:alt: Try me on Runboat
28+
29+
|badge1| |badge2| |badge3| |badge4| |badge5|
30+
31+
This module adds PSCs information to users by following a repository of
32+
configuration that executes
33+
34+
https://github.com/OCA/repo-maintainer
35+
36+
**Table of contents**
37+
38+
.. contents::
39+
:local:
40+
41+
Bug Tracker
42+
===========
43+
44+
Bugs are tracked on `GitHub Issues <https://github.com/OCA/version-control-platform/issues>`_.
45+
In case of trouble, please check there if your issue has already been reported.
46+
If you spotted it first, help us to smash it by providing a detailed and welcomed
47+
`feedback <https://github.com/OCA/version-control-platform/issues/new?body=module:%20vcp_psc%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
48+
49+
Do not contact contributors directly about support or help with technical issues.
50+
51+
Credits
52+
=======
53+
54+
Authors
55+
-------
56+
57+
* Dixmit
58+
59+
Contributors
60+
------------
61+
62+
- `Dixmit <https://www.dixmit.com>`__
63+
64+
- Enric Tobella
65+
66+
Maintainers
67+
-----------
68+
69+
This module is maintained by the OCA.
70+
71+
.. image:: https://odoo-community.org/logo.png
72+
:alt: Odoo Community Association
73+
:target: https://odoo-community.org
74+
75+
OCA, or the Odoo Community Association, is a nonprofit organization whose
76+
mission is to support the collaborative development of Odoo features and
77+
promote its widespread use.
78+
79+
This module is part of the `OCA/version-control-platform <https://github.com/OCA/version-control-platform/tree/18.0/vcp_psc>`_ project on GitHub.
80+
81+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

‎vcp_psc/__init__.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import models

‎vcp_psc/__manifest__.py‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Copyright 2026 Dixmit
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
{
5+
"name": "Contributors Github Psc",
6+
"summary": """Integrate PSCs""",
7+
"version": "18.0.1.0.0",
8+
"license": "AGPL-3",
9+
"author": "Dixmit,Odoo Community Association (OCA)",
10+
"website": "https://github.com/OCA/version-control-platform",
11+
"depends": ["vcp_git"],
12+
"data": [
13+
"data/vcp_rule.xml",
14+
"views/vcp_repository.xml",
15+
"security/ir.model.access.csv",
16+
"views/vcp_platform_psc.xml",
17+
"views/vcp_platform.xml",
18+
],
19+
"external_dependencies": {"python": ["PyYAML"]},
20+
"assets": {},
21+
"demo": [],
22+
}

‎vcp_psc/data/vcp_rule.xml‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<!-- Copyright 2026 Dixmit
3+
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
4+
<odoo noupdate="1">
5+
<record id="vcp_rule_psc" model="vcp.rule">
6+
<field name="name">PSC Detection</field>
7+
<field name="rule_type">psc</field>
8+
<field name="branch_pattern">^master$</field>
9+
<field name="paths"><![CDATA[conf]]></field>
10+
</record>
11+
</odoo>

‎vcp_psc/models/__init__.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from . import vcp_platform
2+
from . import vcp_platform_psc
3+
from . import vcp_repository
4+
from . import vcp_rule
5+
from . import vcp_user

‎vcp_psc/models/vcp_platform.py‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright 2026 Dixmit
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
5+
from odoo import fields, models
6+
7+
8+
class VCPPlatform(models.Model):
9+
_inherit = "vcp.platform"
10+
11+
psc_ids = fields.One2many(
12+
"vcp.platform.psc",
13+
inverse_name="platform_id",
14+
readonly=True,
15+
)
16+
17+
def _get_merged_domain(self, start, end, psc_id=None, **values):
18+
result = super()._get_merged_domain(start, end, psc_id=psc_id, **values)
19+
if psc_id:
20+
result.append(("repository_id.psc_id", "=", int(psc_id)))
21+
return result
22+
23+
def _get_created_domain(self, start, end, psc_id=None, **values):
24+
result = super()._get_created_domain(start, end, psc_id=psc_id, **values)
25+
if psc_id:
26+
result.append(("repository_id.psc_id", "=", int(psc_id)))
27+
return result
28+
29+
def _get_comments_domain(self, start, end, psc_id=None, **values):
30+
result = super()._get_comments_domain(start, end, psc_id=psc_id, **values)
31+
if psc_id:
32+
result.append(("repository_id.psc_id", "=", int(psc_id)))
33+
return result
34+
35+
def _get_reviews_domain(self, start, end, psc_id=None, **values):
36+
result = super()._get_reviews_domain(start, end, psc_id=psc_id, **values)
37+
if psc_id:
38+
result.append(("repository_id.psc_id", "=", int(psc_id)))
39+
return result

‎vcp_psc/models/vcp_platform_psc.py‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright 2026 Dixmit
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
from odoo import fields, models
5+
6+
7+
class VCPPlatformPsc(models.Model):
8+
_name = "vcp.platform.psc"
9+
_description = "Version Control Platform PSC"
10+
11+
platform_id = fields.Many2one(
12+
comodel_name="vcp.platform",
13+
string="Platform",
14+
required=True,
15+
)
16+
name = fields.Char(required=True)
17+
key = fields.Char(required=True)
18+
member_ids = fields.Many2many(
19+
"vcp.user",
20+
readonly=True,
21+
)

‎vcp_psc/models/vcp_repository.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright 2026 Dixmit
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
from odoo import fields, models
5+
6+
7+
class VCPRepository(models.Model):
8+
_inherit = "vcp.repository"
9+
10+
psc_id = fields.Many2one(
11+
"vcp.platform.psc",
12+
readonly=True,
13+
)

‎vcp_psc/models/vcp_rule.py‎

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# Copyright 2026 Dixmit
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
import logging
4+
import os
5+
import re
6+
7+
import yaml
8+
9+
from odoo import fields, models
10+
11+
_logger = logging.getLogger(__name__)
12+
13+
14+
class VcpRule(models.Model):
15+
_inherit = "vcp.rule"
16+
17+
rule_type = fields.Selection(
18+
selection_add=[("psc", "PSC Analysis")],
19+
ondelete={"psc": "cascade"},
20+
)
21+
22+
def _process_rule_psc(self, record, parameters=None):
23+
"""
24+
Process a PSC rule for a given repository.
25+
26+
:param repository: The repository to process the rule for.
27+
:param rule: The PSC rule to process.
28+
"""
29+
if record._name != "vcp.repository.branch":
30+
# It doesn't make sense to process this kind of rules outside
31+
# of a repository branch, as they need the code to be downloaded
32+
# and analyzed.
33+
return
34+
record._download_code()
35+
_logger.info("Downloaded code for repository branch '%s'", record.display_name)
36+
for conf in self.paths.splitlines():
37+
conf = conf.strip()
38+
if not conf or conf.startswith("#"):
39+
continue
40+
conf = record.local_path + "/" + conf
41+
if not os.path.exists(conf):
42+
_logger.warning(
43+
"Path '%s' does not exist for repository branch '%s'",
44+
conf,
45+
record.display_name,
46+
)
47+
continue
48+
_logger.info(f"Found {conf}")
49+
for psc_file in os.listdir(os.path.join(record.local_path, conf, "psc")):
50+
if re.match(r"^.*\.yml$", psc_file):
51+
psc_path = os.path.join(record.local_path, conf, "psc", psc_file)
52+
with open(psc_path) as f:
53+
try:
54+
psc_data = yaml.safe_load(f)
55+
except yaml.YAMLError as e:
56+
_logger.error(f"Error parsing PSC file '{psc_path}': {e}")
57+
continue
58+
self._process_psc_data(record, psc_data)
59+
for psc_repo_file in os.listdir(
60+
os.path.join(record.local_path, conf, "repo")
61+
):
62+
if re.match(r"^.*\.yml$", psc_repo_file):
63+
psc_repo_path = os.path.join(
64+
record.local_path, conf, "repo", psc_repo_file
65+
)
66+
with open(psc_repo_path) as f:
67+
try:
68+
psc_repo_data = yaml.safe_load(f)
69+
except yaml.YAMLError as e:
70+
_logger.error(
71+
f"Error parsing PSC file '{psc_repo_path}': {e}"
72+
)
73+
continue
74+
self._process_psc_repo_data(record, psc_repo_data)
75+
76+
def _process_psc_data(self, record, psc_data):
77+
"""
78+
Process the PSC data.
79+
80+
:param record: The repository branch record to process the PSC data for.
81+
:param psc_data: The PSC data to process.
82+
"""
83+
if not psc_data:
84+
_logger.warning(
85+
"No PSC data found for repository branch '%s'", record.display_name
86+
)
87+
return
88+
for psc_name in psc_data:
89+
psc_record = self.env["vcp.platform.psc"].search(
90+
[
91+
("platform_id", "=", record.platform_id.id),
92+
("key", "=", psc_name),
93+
],
94+
limit=1,
95+
)
96+
if not psc_record:
97+
psc_record = (
98+
self.env["vcp.platform.psc"]
99+
.sudo()
100+
.create(
101+
{
102+
"platform_id": record.platform_id.id,
103+
"key": psc_name,
104+
"name": psc_data[psc_name].get("name", psc_name),
105+
}
106+
)
107+
)
108+
else:
109+
psc_record.sudo().write(
110+
{
111+
"name": psc_data[psc_name].get("name", psc_name),
112+
}
113+
)
114+
member_logins = psc_data[psc_name].get("members", []) + psc_data[
115+
psc_name
116+
].get("representatives", [])
117+
members = []
118+
for member in member_logins:
119+
members.append(record.platform_id.host_id._get_user(member))
120+
psc_record.sudo().member_ids = self.env["vcp.user"].browse(members)
121+
122+
def _process_psc_repo_data(self, record, psc_repo_data):
123+
"""
124+
Process the PSC Repository data
125+
126+
:param record: The repository branch record to process the PSC data for.
127+
:param psc_repo_data: The PSC Repository data to process.
128+
"""
129+
if not psc_repo_data:
130+
_logger.warning(
131+
"No data found for repository branch '%s'", record.display_name
132+
)
133+
return
134+
for repo_name in psc_repo_data:
135+
psc_name = psc_repo_data[repo_name].get("psc")
136+
psc_record = self.env["vcp.platform.psc"].search(
137+
[
138+
("platform_id", "=", record.platform_id.id),
139+
("key", "=", psc_name),
140+
],
141+
limit=1,
142+
)
143+
if not psc_record:
144+
continue
145+
repo_record = (
146+
self.env["vcp.repository"]
147+
.sudo()
148+
.search(
149+
[
150+
("platform_id", "=", record.platform_id.id),
151+
("name", "=", repo_name),
152+
],
153+
limit=1,
154+
)
155+
)
156+
if repo_record:
157+
repo_record.sudo().write(
158+
{
159+
"psc_id": psc_record.id,
160+
}
161+
)

0 commit comments

Comments
 (0)