From f3ed858916ed37880398a80ec4765165174d3da5 Mon Sep 17 00:00:00 2001 From: Enric Tobella Date: Sat, 24 Jan 2026 10:41:35 +0100 Subject: [PATCH 01/18] [ADD] vcp_github --- vcp_github/README.rst | 211 +++++++++ vcp_github/__init__.py | 1 + vcp_github/__manifest__.py | 19 + vcp_github/models/__init__.py | 3 + vcp_github/models/res_partner.py | 123 +++++ vcp_github/models/vcp_platform.py | 79 ++++ vcp_github/models/vcp_repository.py | 193 ++++++++ vcp_github/pyproject.toml | 3 + vcp_github/readme/CONFIGURE.md | 10 + vcp_github/readme/CONTEXT.md | 16 + vcp_github/readme/CONTRIBUTORS.md | 2 + vcp_github/readme/CREDITS.md | 7 + vcp_github/readme/DESCRIPTION.md | 7 + vcp_github/readme/HISTORY.md | 22 + vcp_github/readme/INSTALL.md | 7 + vcp_github/readme/ROADMAP.md | 5 + vcp_github/readme/USAGE.md | 21 + vcp_github/static/description/icon.png | Bin 0 -> 9455 bytes vcp_github/static/description/index.html | 555 +++++++++++++++++++++++ vcp_github/tests/__init__.py | 1 + vcp_github/tests/test_github.py | 114 +++++ 21 files changed, 1399 insertions(+) create mode 100644 vcp_github/README.rst create mode 100644 vcp_github/__init__.py create mode 100644 vcp_github/__manifest__.py create mode 100644 vcp_github/models/__init__.py create mode 100644 vcp_github/models/res_partner.py create mode 100644 vcp_github/models/vcp_platform.py create mode 100644 vcp_github/models/vcp_repository.py create mode 100644 vcp_github/pyproject.toml create mode 100644 vcp_github/readme/CONFIGURE.md create mode 100644 vcp_github/readme/CONTEXT.md create mode 100644 vcp_github/readme/CONTRIBUTORS.md create mode 100644 vcp_github/readme/CREDITS.md create mode 100644 vcp_github/readme/DESCRIPTION.md create mode 100644 vcp_github/readme/HISTORY.md create mode 100644 vcp_github/readme/INSTALL.md create mode 100644 vcp_github/readme/ROADMAP.md create mode 100644 vcp_github/readme/USAGE.md create mode 100644 vcp_github/static/description/icon.png create mode 100644 vcp_github/static/description/index.html create mode 100644 vcp_github/tests/__init__.py create mode 100644 vcp_github/tests/test_github.py diff --git a/vcp_github/README.rst b/vcp_github/README.rst new file mode 100644 index 0000000..07627b8 --- /dev/null +++ b/vcp_github/README.rst @@ -0,0 +1,211 @@ +========== +Vcp Github +========== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:086596db3dcb4fa7565fc97cf01ccd22449731243622d4587a1f609eab8bc121 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fversion--control--platform-lightgray.png?logo=github + :target: https://github.com/OCA/version-control-platform/tree/18.0/vcp_github + :alt: OCA/version-control-platform +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/version-control-platform-18-0/version-control-platform-18-0-vcp_github + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/version-control-platform&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +[ This file must be max 2-3 paragraphs, and is required. + +The goal of this document is to explain quickly the features of this +module: “what” this module does and “what” it is for. ] + +Example: + +This module extends the functionality of ... to support ... and to allow +users to ... + +**Table of contents** + +.. contents:: + :local: + +Use Cases / Context +=================== + +[ This file is optional but strongly suggested to allow end-users to +evaluate the module's usefulness in their context. ] + +BUSINESS NEED: It should explain the “why” of the module: + +- what is the business requirement that generated the need to develop + this module +- in which context or use cases this module can be useful (practical + examples are welcome!). + +APPROACH: It could also explain the approach to address the mentioned +need. + +USEFUL INFORMATION: It can also inform on related modules: + +- modules it depends on and their features +- other modules that can work well together with this one +- suggested setups where the module is useful (eg: multicompany, + multi-website) + +Installation +============ + +[ This file must only be present if there are very specific installation +instructions, such as installing non-python dependencies. The audience +is systems administrators. ] + +To install this module, you need to: + +1. Do this ... + +Configuration +============= + +[ This file is not always required; it should explain **how to configure +the module before using it**; it is aimed at users with administration +privileges. + +Please be detailed on the path to configuration (eg: do you need to +activate developer mode?), describe step by step configurations and the +use of screenshots is strongly recommended.] + +To configure this module, you need to: + +- Go to *App* > Menu > Menu item +- Activate boolean… > save +- … + +Usage +===== + +[ This file is required and contains the instructions on **“how”** to +use the module for end-users. + +If the module does not have a visible impact on the user interface, just +add the following sentence: + + This module does not impact the user interface. + +If that’s not the case, please make sure that every usage step is +covered and remember that images speak more than words!] + +To use this module, you need to: + +- Go to *App* > Menu > Menu item + + *insert screenshot!* + +- In “Contact” form, add a value to field *xyz* > save + + *insert screenshot!* + +- The value of *xyz* is now displayed in the list view. + + *insert screenshot!* + +Known issues / Roadmap +====================== + +[ Enumerate known caveats and future potential improvements. It is +mostly intended for end-users, and can also help potential new +contributors discovering new features to implement. ] + +- ... + +Changelog +========= + +[ The change log. The goal of this file is to help readers understand +changes between version. The primary audience is end users and +integrators. Purely technical changes such as code refactoring must not +be mentioned here. + +This file may contain ONE level of section titles, underlined with the ~ +(tilde) character. Other section markers are forbidden and will likely +break the structure of the README.rst or other documents where this +fragment is included. ] + +11.0.x.y.z (YYYY-MM-DD) +----------------------- + +- [BREAKING] Breaking changes come first. + (`#70 `__) +- [ADD] New feature. (`#74 `__) +- [FIX] Correct this. (`#71 `__) + +11.0.x.y.z (YYYY-MM-DD) +----------------------- + +- ... + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Dixmit + +Contributors +------------ + +- Firstname Lastname email.address@example.org (optional company website + url) +- Second Person second.person@example.org (optional company website url) + +Other credits +------------- + +[ This file is optional and contains additional credits, other than +authors, contributors, and maintainers. ] + +The development of this module has been financially supported by: + +- Company 1 name +- Company 2 name + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/version-control-platform `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/vcp_github/__init__.py b/vcp_github/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/vcp_github/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/vcp_github/__manifest__.py b/vcp_github/__manifest__.py new file mode 100644 index 0000000..9ddb87a --- /dev/null +++ b/vcp_github/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Vcp Github", + "summary": """Integrate Virtual Control Platform with Github""", + "version": "18.0.1.0.0", + "license": "AGPL-3", + "author": "Dixmit,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/version-control-platform", + "depends": [ + "vcp", + ], + "external_dependencies": { + "python": ["github3.py"], + }, + "data": [], + "demo": [], +} diff --git a/vcp_github/models/__init__.py b/vcp_github/models/__init__.py new file mode 100644 index 0000000..8fe49b4 --- /dev/null +++ b/vcp_github/models/__init__.py @@ -0,0 +1,3 @@ +from . import vcp_platform +from . import vcp_repository +from . import res_partner diff --git a/vcp_github/models/res_partner.py b/vcp_github/models/res_partner.py new file mode 100644 index 0000000..f46fed1 --- /dev/null +++ b/vcp_github/models/res_partner.py @@ -0,0 +1,123 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import github3 + +from odoo import fields, models, tools + + +class ResPartner(models.Model): + _inherit = "res.partner" + + github_name = fields.Char( + string="GitHub Username", + help="GitHub username of the contributor or organization", + readonly=True, + ) + github_organization = fields.Boolean( + string="Is GitHub Organization", + help="Check if this partner represents a GitHub organization", + readonly=True, + ) + github_user = fields.Boolean( + string="Is GitHub User", + help="Check if this partner represents a GitHub user", + readonly=True, + ) + + _sql_constraints = [ + ( + "github_name_uniq", + "unique(github_name)", + "The GitHub username must be unique across partners.", + ), + ] + + @tools.ormcache("github_login") + def _get_github_user_id(self, github_login): + partner = self.with_context(active_test=False).search( + [("github_name", "=ilike", github_login)], limit=1 + ) + if not partner: + return False + if not partner.github_user: + partner.github_user = True + return partner.id + + @tools.ormcache("github_login") + def _get_github_organization_id(self, github_login): + partner = self.with_context(active_test=False).search( + [("github_name", "=ilike", github_login)], limit=1 + ) + if not partner: + return False + if not partner.github_organization: + partner.github_organization = True + return partner.id + + def _get_github_user(self, gh, client): + if not gh: + return False + if isinstance(gh, github3.users.User): + github_login = gh.login + else: + github_login = str(gh) + partner = self._get_github_user_id(github_login) + if partner: + return partner + if isinstance(gh, str): + try: + gh = client.user(github_login) + name = gh.name or github_login + except github3.exceptions.NotFoundError: + name = gh + else: + if hasattr(gh, "name"): + name = gh.name or github_login + else: + name = github_login + self.env.registry.clear_cache() + return self.create( + { + "name": name, + "github_name": github_login, + "github_user": True, + } + ).id + + def _get_github_organization(self, gh, client): + if not gh: + return False + partner = self._get_github_organization_id(str(gh)) + if partner: + return partner + self.env.registry.clear_cache() + try: + org = client.organization(str(gh)) + + return self.create( + { + "name": org.name or str(gh), + "github_name": str(gh), + "github_organization": True, + } + ).id + except github3.exceptions.NotFoundError: + user = client.user(str(gh)) + name = user.name or str(gh) + except github3.exceptions.ForbiddenError: + name = str(gh) + return self.create( + { + "name": name, + "github_name": str(gh), + "github_user": True, + "github_organization": True, + } + ).id + + def _get_contributor_url(self): + result = super()._get_contributor_url() + if not result and self.github_name: + return f"https://github.com/{self.github_name}" + return result diff --git a/vcp_github/models/vcp_platform.py b/vcp_github/models/vcp_platform.py new file mode 100644 index 0000000..656128f --- /dev/null +++ b/vcp_github/models/vcp_platform.py @@ -0,0 +1,79 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import base64 +from datetime import datetime + +import github3 +import requests +from pytz import UTC + +from odoo import fields, models + + +class VcpPlatform(models.Model): + _inherit = "vcp.platform" + + kind = fields.Selection( + selection_add=[("github", "GitHub")], + ondelete={"github": "cascade"}, + ) + + def _get_github_clients(self): + git = [] + for key in self.key_ids: + git.append(github3.login(token=key.name)) + return git + + def _update_information_github(self): + self.ensure_one() + clients = self._get_github_clients() + org = clients[0].organization(self.name) + self.short_description = org.name + self.description = org.description + if org.avatar_url: + response = requests.get(org.avatar_url, timeout=10) + response.raise_for_status() + self.image_1920 = base64.b64encode(response.content) + repos = org.repositories() + for repo in repos: + self._update_github_repository(repo) + self.last_update = fields.Datetime.now() + + def _parse_github_date(self, date): + if not date: + return False + return UTC.normalize( + datetime.fromisoformat(date.replace("Z", "+00:00")) + ).replace(tzinfo=None) + + def _update_github_repository(self, repo): + vals = { + "created_at": self._parse_github_date(repo.created_at), + "stargazers_count": repo.stargazers_count, + "fork_count": repo.forks_count, + "watchers_count": repo.watchers_count, + "description": repo.description, + } + repository = self.env["vcp.repository"].search( + [ + ("name", "=", repo.name), + ("platform_id", "=", self.id), + ], + limit=1, + ) + if not repository: + repository = ( + self.env["vcp.repository"] + .sudo() + .create( + { + "name": repo.name, + "platform_id": self.id, + "from_date": vals.get("created_at"), + **vals, + } + ) + ) + else: + repository.sudo().write(vals) diff --git a/vcp_github/models/vcp_repository.py b/vcp_github/models/vcp_repository.py new file mode 100644 index 0000000..6d1630a --- /dev/null +++ b/vcp_github/models/vcp_repository.py @@ -0,0 +1,193 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +import logging +from datetime import datetime, timedelta + +import github3 +from github3 import pulls +from pytz import UTC + +from odoo import fields, models +from odoo.exceptions import ValidationError + +_logger = logging.getLogger(__name__) + + +class VcpRepository(models.Model): + _inherit = "vcp.repository" + + def _parse_github_pr(self, pr, client): + origin_data = pr.as_dict() + comments_url = pr.comments_url + comments_req = client.session.get(comments_url) + comments = comments_req.json() + while comments_req.links.get("next"): + comments_url = comments_req.links["next"]["url"] + comments_req = client.session.get(comments_url) + comments += comments_req.json() + reviews_url = pr.reviews().url + reviews_req = client.session.get(reviews_url) + reviews = reviews_req.json() + while reviews_req.links.get("next"): + reviews_url = reviews_req.links["next"]["url"] + reviews_req = client.session.get(reviews_url) + reviews += reviews_req.json() + return ( + str(pr.id), + { + "partner_id": self.env["res.partner"]._get_github_user(pr.user, client), + "repository_id": self.id, + "branch_id": self.platform_id._get_branch(pr.base.ref), + "organization_id": self.env["res.partner"]._get_github_organization( + pr.head.repo[0], client + ), + "url": pr.html_url, + "state": pr.state, + "name": pr.title, + "is_merged": any(label["name"] == "merged 🎉" for label in pr.labels) + or pr.is_merged(), + "created_at": self.platform_id._parse_github_date( + origin_data["created_at"] + ), + "closed_at": self.platform_id._parse_github_date( + origin_data["closed_at"] + ), + "number": pr.number, + "updated_at": self.platform_id._parse_github_date( + origin_data["updated_at"] + ), + "label_ids": [fields.Command.clear()] + + [ + fields.Command.link( + self.env["vcp.request.label"]._get_label(label["name"]) + ) + for label in origin_data["labels"] + ], + "commits": origin_data["commits"], + "total_comments": origin_data["comments"], + "review_comments": origin_data["review_comments"], + "additions": origin_data["additions"], + "deletions": origin_data["deletions"], + }, + [ + { + "id": str(c["id"]), + "partner_id": c.get("user") + and self.env["res.partner"]._get_github_user( + c["user"].get("login"), client + ), + "body": c["body"], + "created_at": self.platform_id._parse_github_date(c["created_at"]), + "updated_at": self.platform_id._parse_github_date(c["updated_at"]), + } + for c in comments + ], + [ + { + "id": str(r["id"]), + "partner_id": r.get("user") + and self.env["res.partner"]._get_github_user( + r["user"].get("login"), client + ), + "body": r["body"], + "submitted_at": self.platform_id._parse_github_date( + r.get("submitted_at") + ), + "state": r["state"]["keyword"] + if isinstance(r["state"], dict) + else r["state"], + } + for r in reviews + ], + ) + + def _update_information_github( + self, update_interval_days=None, client_for_search=0 + ): + self.ensure_one() + clients = self.platform_id._get_github_clients() + try: + start = UTC.localize(self.from_date) + end = min( + start + + timedelta( + days=update_interval_days or self.platform_id.update_interval_days + ), + UTC.localize(datetime.now()), + ) + start += timedelta( + days=-1 + ) # Add buffer day to avoid missing PRs on boundary dates + i = client_for_search % len(clients) + for pr in clients[i].search_issues( + f"is:pr repo:{self.platform_id.name}/{self.name} " + f"updated:{start.isoformat()}..{end.isoformat()}" + ): + i = (1 + i) % len(clients) + pr_id, pr_data, comments, reviews = self._parse_github_pr( + clients[i]._instance_or_null( + pulls.PullRequest, + clients[i]._json( + pr.issue._get(pr.issue.pull_request_urls.get("url")), 200 + ), + ), + clients[i], + ) + opr = self.env["vcp.request"].search( + [("external_id", "=", pr_id), ("repository_id", "=", self.id)], + limit=1, + ) + if not opr: + opr = ( + self.env["vcp.request"] + .sudo() + .create({"external_id": pr_id, **pr_data}) + ) + else: + opr.sudo().write(pr_data) + for comment in comments: + comment_id = comment.pop("id") + ocomment = self.env["vcp.comment"].search( + [ + ("external_id", "=", comment_id), + ("repository_id", "=", self.id), + ], + limit=1, + ) + if not ocomment: + self.env["vcp.comment"].sudo().create( + { + "external_id": comment_id, + "request_id": opr.id, + **comment, + } + ) + else: + ocomment.sudo().write(comment) + for review in reviews: + review_id = review.pop("id") + oreview = self.env["vcp.review"].search( + [ + ("external_id", "=", review_id), + ("repository_id", "=", self.id), + ], + limit=1, + ) + if not oreview: + self.env["vcp.review"].sudo().create( + { + "external_id": review_id, + "request_id": opr.id, + **review, + } + ) + else: + oreview.sudo().write(review) + self.sudo().from_date = end.replace(tzinfo=None) + except github3.exceptions.ForbiddenError as e: + _logger.error(e) + rate = clients[i].rate_limit() + reset = fields.Datetime.to_string( + datetime.utcfromtimestamp(rate["resources"]["core"]["reset"]) + ) + raise ValidationError(self.env._(f"Reset on {reset}")) from e diff --git a/vcp_github/pyproject.toml b/vcp_github/pyproject.toml new file mode 100644 index 0000000..4231d0c --- /dev/null +++ b/vcp_github/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/vcp_github/readme/CONFIGURE.md b/vcp_github/readme/CONFIGURE.md new file mode 100644 index 0000000..2fdb0e6 --- /dev/null +++ b/vcp_github/readme/CONFIGURE.md @@ -0,0 +1,10 @@ +[ This file is not always required; it should explain **how to configure the module before using it**; it is aimed at users with administration privileges. + +Please be detailed on the path to configuration (eg: do you need to activate developer mode?), describe step by step configurations and the use of screenshots is strongly recommended.] + + +To configure this module, you need to: + +- Go to *App* > Menu > Menu item +- Activate boolean… > save +- … diff --git a/vcp_github/readme/CONTEXT.md b/vcp_github/readme/CONTEXT.md new file mode 100644 index 0000000..096235a --- /dev/null +++ b/vcp_github/readme/CONTEXT.md @@ -0,0 +1,16 @@ +[ This file is optional but strongly suggested to allow end-users to evaluate the +module's usefulness in their context. ] + +BUSINESS NEED: +It should explain the “why” of the module: +- what is the business requirement that generated the need to develop this module +- in which context or use cases this module can be useful (practical examples are welcome!). + +APPROACH: +It could also explain the approach to address the mentioned need. + +USEFUL INFORMATION: +It can also inform on related modules: +- modules it depends on and their features +- other modules that can work well together with this one +- suggested setups where the module is useful (eg: multicompany, multi-website) diff --git a/vcp_github/readme/CONTRIBUTORS.md b/vcp_github/readme/CONTRIBUTORS.md new file mode 100644 index 0000000..7be72fb --- /dev/null +++ b/vcp_github/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- Firstname Lastname (optional company website url) +- Second Person (optional company website url) diff --git a/vcp_github/readme/CREDITS.md b/vcp_github/readme/CREDITS.md new file mode 100644 index 0000000..9c2b025 --- /dev/null +++ b/vcp_github/readme/CREDITS.md @@ -0,0 +1,7 @@ +[ This file is optional and contains additional credits, other than + authors, contributors, and maintainers. ] + +The development of this module has been financially supported by: + +- Company 1 name +- Company 2 name diff --git a/vcp_github/readme/DESCRIPTION.md b/vcp_github/readme/DESCRIPTION.md new file mode 100644 index 0000000..2371a14 --- /dev/null +++ b/vcp_github/readme/DESCRIPTION.md @@ -0,0 +1,7 @@ +[ This file must be max 2-3 paragraphs, and is required. + +The goal of this document is to explain quickly the features of this module: “what” this module does and “what” it is for. ] + +Example: + +This module extends the functionality of ... to support ... and to allow users to ... diff --git a/vcp_github/readme/HISTORY.md b/vcp_github/readme/HISTORY.md new file mode 100644 index 0000000..a6daf58 --- /dev/null +++ b/vcp_github/readme/HISTORY.md @@ -0,0 +1,22 @@ +[ The change log. The goal of this file is to help readers + understand changes between version. The primary audience is + end users and integrators. Purely technical changes such as + code refactoring must not be mentioned here. + + This file may contain ONE level of section titles, underlined + with the ~ (tilde) character. Other section markers are + forbidden and will likely break the structure of the README.rst + or other documents where this fragment is included. ] + +## 11.0.x.y.z (YYYY-MM-DD) + +- [BREAKING] Breaking changes come first. + ([#70](https://github.com/OCA/repo/issues/70)) +- [ADD] New feature. + ([#74](https://github.com/OCA/repo/issues/74)) +- [FIX] Correct this. + ([#71](https://github.com/OCA/repo/issues/71)) + +## 11.0.x.y.z (YYYY-MM-DD) + +- ... diff --git a/vcp_github/readme/INSTALL.md b/vcp_github/readme/INSTALL.md new file mode 100644 index 0000000..77b98e7 --- /dev/null +++ b/vcp_github/readme/INSTALL.md @@ -0,0 +1,7 @@ +[ This file must only be present if there are very specific + installation instructions, such as installing non-python + dependencies. The audience is systems administrators. ] + +To install this module, you need to: + +1. Do this ... diff --git a/vcp_github/readme/ROADMAP.md b/vcp_github/readme/ROADMAP.md new file mode 100644 index 0000000..446840c --- /dev/null +++ b/vcp_github/readme/ROADMAP.md @@ -0,0 +1,5 @@ +[ Enumerate known caveats and future potential improvements. + It is mostly intended for end-users, and can also help + potential new contributors discovering new features to implement. ] + +- ... diff --git a/vcp_github/readme/USAGE.md b/vcp_github/readme/USAGE.md new file mode 100644 index 0000000..2cf1275 --- /dev/null +++ b/vcp_github/readme/USAGE.md @@ -0,0 +1,21 @@ +[ This file is required and contains the instructions on **“how”** to use the module for end-users. + +If the module does not have a visible impact on the user interface, just add the following sentence: + +> This module does not impact the user interface. + +If that’s not the case, please make sure that every usage step is covered and remember that images speak more than words!] + +To use this module, you need to: + +- Go to *App* > Menu > Menu item + + *insert screenshot!* + +- In “Contact” form, add a value to field *xyz* > save + + *insert screenshot!* + +- The value of *xyz* is now displayed in the list view. + + *insert screenshot!* diff --git a/vcp_github/static/description/icon.png b/vcp_github/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/vcp_github/static/description/index.html b/vcp_github/static/description/index.html new file mode 100644 index 0000000..63aa4a5 --- /dev/null +++ b/vcp_github/static/description/index.html @@ -0,0 +1,555 @@ + + + + + +Vcp Github + + + +
+

Vcp Github

+ + +

Beta License: AGPL-3 OCA/version-control-platform Translate me on Weblate Try me on Runboat

+

[ This file must be max 2-3 paragraphs, and is required.

+

The goal of this document is to explain quickly the features of this +module: “what” this module does and “what” it is for. ]

+

Example:

+

This module extends the functionality of … to support … and to allow +users to …

+

Table of contents

+ +
+

Use Cases / Context

+

[ This file is optional but strongly suggested to allow end-users to +evaluate the module’s usefulness in their context. ]

+

BUSINESS NEED: It should explain the “why” of the module:

+
    +
  • what is the business requirement that generated the need to develop +this module
  • +
  • in which context or use cases this module can be useful (practical +examples are welcome!).
  • +
+

APPROACH: It could also explain the approach to address the mentioned +need.

+

USEFUL INFORMATION: It can also inform on related modules:

+
    +
  • modules it depends on and their features
  • +
  • other modules that can work well together with this one
  • +
  • suggested setups where the module is useful (eg: multicompany, +multi-website)
  • +
+
+
+

Installation

+

[ This file must only be present if there are very specific installation +instructions, such as installing non-python dependencies. The audience +is systems administrators. ]

+

To install this module, you need to:

+
    +
  1. Do this …
  2. +
+
+
+

Configuration

+

[ This file is not always required; it should explain how to configure +the module before using it; it is aimed at users with administration +privileges.

+

Please be detailed on the path to configuration (eg: do you need to +activate developer mode?), describe step by step configurations and the +use of screenshots is strongly recommended.]

+

To configure this module, you need to:

+
    +
  • Go to App > Menu > Menu item
  • +
  • Activate boolean… > save
  • +
  • +
+
+
+

Usage

+

[ This file is required and contains the instructions on “how” to +use the module for end-users.

+

If the module does not have a visible impact on the user interface, just +add the following sentence:

+
+This module does not impact the user interface.
+

If that’s not the case, please make sure that every usage step is +covered and remember that images speak more than words!]

+

To use this module, you need to:

+
    +
  • Go to App > Menu > Menu item

    +

    insert screenshot!

    +
  • +
  • In “Contact” form, add a value to field xyz > save

    +

    insert screenshot!

    +
  • +
  • The value of xyz is now displayed in the list view.

    +

    insert screenshot!

    +
  • +
+
+
+

Known issues / Roadmap

+

[ Enumerate known caveats and future potential improvements. It is +mostly intended for end-users, and can also help potential new +contributors discovering new features to implement. ]

+
    +
  • +
+
+
+

Changelog

+

[ The change log. The goal of this file is to help readers understand +changes between version. The primary audience is end users and +integrators. Purely technical changes such as code refactoring must not +be mentioned here.

+

This file may contain ONE level of section titles, underlined with the ~ +(tilde) character. Other section markers are forbidden and will likely +break the structure of the README.rst or other documents where this +fragment is included. ]

+
+

11.0.x.y.z (YYYY-MM-DD)

+
    +
  • [BREAKING] Breaking changes come first. +(#70)
  • +
  • [ADD] New feature. (#74)
  • +
  • [FIX] Correct this. (#71)
  • +
+
+ +
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Dixmit
  • +
+
+
+

Contributors

+ +
+
+

Other credits

+

[ This file is optional and contains additional credits, other than +authors, contributors, and maintainers. ]

+

The development of this module has been financially supported by:

+
    +
  • Company 1 name
  • +
  • Company 2 name
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/version-control-platform project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/vcp_github/tests/__init__.py b/vcp_github/tests/__init__.py new file mode 100644 index 0000000..c63e32e --- /dev/null +++ b/vcp_github/tests/__init__.py @@ -0,0 +1 @@ +from . import test_github diff --git a/vcp_github/tests/test_github.py b/vcp_github/tests/test_github.py new file mode 100644 index 0000000..76cd448 --- /dev/null +++ b/vcp_github/tests/test_github.py @@ -0,0 +1,114 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import base64 +from unittest.mock import MagicMock, patch + +from odoo.fields import Command +from odoo.tests.common import TransactionCase + + +class TestGithub(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.platform = cls.env["vcp.platform"].create( + { + "name": "oca", + "kind": "github", + "key_ids": [ + Command.create({"name": "ghp_exampletoken1234567890abcdef"}) + ], + } + ) + + def test_update_organization_and_logo(self): + base_url = self.env["ir.config_parameter"].sudo().get_param("web.base.url") + with ( + patch("odoo.addons.vcp_github.models.vcp_platform.github3") as mock_github3, + patch( + "odoo.addons.vcp_github.models.vcp_platform.requests.get" + ) as mock_requests_get, + ): + mock_client = MagicMock() + mock_org = MagicMock() + mock_org.name = "Odoo Community Association" + mock_org.avatar_url = f"{base_url}/logo.png" + mock_requests_get.return_value.content = base64.b64decode( + self.env.company.logo + ) + mock_client.organization.return_value = mock_org + mock_github3.login.return_value = mock_client + self.platform.update_information() + self.assertEqual( + self.platform.short_description, "Odoo Community Association" + ) + mock_github3.login.assert_called_once_with( + token="ghp_exampletoken1234567890abcdef" + ) + mock_client.organization.assert_called_once_with("oca") + + def test_update_organization_with_repository(self): + with patch( + "odoo.addons.vcp_github.models.vcp_platform.github3" + ) as mock_github3: + mock_client = MagicMock() + mock_org = MagicMock() + mock_org.name = "Odoo Community Association" + mock_org.avatar_url = False + mock_repo1 = MagicMock() + mock_repo1.name = "server-tools" + mock_repo1.created_at = "2020-01-01T00:00:00Z" + mock_repo2 = MagicMock() + mock_repo2.name = "server-brand" + mock_repo2.created_at = "2021-01-01T10:00:00Z" + mock_org.repositories.return_value = [mock_repo1, mock_repo2] + mock_client.organization.return_value = mock_org + mock_github3.login.return_value = mock_client + self.platform.update_information() + self.assertEqual(len(self.platform.repository_ids), 2) + repo_names = {repo.name for repo in self.platform.repository_ids} + self.assertSetEqual(repo_names, {"server-tools", "server-brand"}) + mock_github3.login.assert_called_once_with( + token="ghp_exampletoken1234567890abcdef" + ) + mock_client.organization.assert_called_once_with("oca") + return self.platform.repository_ids.filtered(lambda r: r.name == "server-tools") + + def test_update_repository(self): + repository = self.test_update_organization_with_repository() + self.assertFalse(repository.request_ids) + with patch( + "odoo.addons.vcp_github.models.vcp_platform.github3.login" + ) as mock_client: + mock_login = MagicMock() + mock_client.return_value = mock_login + mock_login.session.get.return_value = MagicMock( + links={}, + json=lambda: [], + ) + mock_issue_request = MagicMock( + as_dict=lambda: { + "id": 1, + "user": {"login": "contributor1"}, + "base": {"ref": "main"}, + "head": {"repo": [MagicMock()]}, + "html_url": "https://github.com/oca/server-tools/pull/1", + "state": "closed", + "title": "Fix issue", + "labels": [{"name": "merged 🎉"}], + "created_at": "2023-01-01T00:00:00Z", + "updated_at": "2023-01-03T00:00:00Z", + "closed_at": "2023-01-02T00:00:00Z", + "commits": 3, + "comments": 2, + "review_comments": 1, + "additions": 150, + "deletions": 50, + "number": 1, + } + ) + mock_login._instance_or_null.return_value = mock_issue_request + mock_login.search_issues.return_value = [mock_issue_request] + repository.update_information() + self.assertTrue(repository.request_ids) From 2a14d278994c81fef28099cc441e4a4e70767af8 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Sun, 25 Jan 2026 00:14:56 +0100 Subject: [PATCH 02/18] [FIX] vcp_github: handle correctly the error, if no API Keys are defined --- vcp_github/models/vcp_platform.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/vcp_github/models/vcp_platform.py b/vcp_github/models/vcp_platform.py index 656128f..ddd91c7 100644 --- a/vcp_github/models/vcp_platform.py +++ b/vcp_github/models/vcp_platform.py @@ -8,7 +8,8 @@ import requests from pytz import UTC -from odoo import fields, models +from odoo import _, fields, models +from odoo.exceptions import ValidationError class VcpPlatform(models.Model): @@ -28,6 +29,10 @@ def _get_github_clients(self): def _update_information_github(self): self.ensure_one() clients = self._get_github_clients() + if not clients: + raise ValidationError( + _("No github clients configured. Please enter at least an API Key.") + ) org = clients[0].organization(self.name) self.short_description = org.name self.description = org.description From 5e1104d56788ae8fa21942047d07df7966a3fce7 Mon Sep 17 00:00:00 2001 From: Enric Tobella Date: Mon, 26 Jan 2026 08:37:49 +0100 Subject: [PATCH 03/18] [FIX] vcp_github use users and partners Fix rename from vcp.platform.type to vcp.host Adapt to Host Type Fix tests add git url Adapt tests and code to get data --- vcp_github/__manifest__.py | 6 +- vcp_github/data/data.xml | 11 +++ vcp_github/models/__init__.py | 4 +- vcp_github/models/res_partner.py | 123 -------------------------- vcp_github/models/vcp_host.py | 19 ++++ vcp_github/models/vcp_organization.py | 15 ++++ vcp_github/models/vcp_platform.py | 6 +- vcp_github/models/vcp_repository.py | 49 +++++++--- vcp_github/models/vcp_user.py | 15 ++++ vcp_github/tests/test_github.py | 4 +- 10 files changed, 110 insertions(+), 142 deletions(-) create mode 100644 vcp_github/data/data.xml delete mode 100644 vcp_github/models/res_partner.py create mode 100644 vcp_github/models/vcp_host.py create mode 100644 vcp_github/models/vcp_organization.py create mode 100644 vcp_github/models/vcp_user.py diff --git a/vcp_github/__manifest__.py b/vcp_github/__manifest__.py index 9ddb87a..668f42d 100644 --- a/vcp_github/__manifest__.py +++ b/vcp_github/__manifest__.py @@ -9,11 +9,13 @@ "author": "Dixmit,Odoo Community Association (OCA)", "website": "https://github.com/OCA/version-control-platform", "depends": [ - "vcp", + "vcp_management", ], "external_dependencies": { "python": ["github3.py"], }, - "data": [], + "data": [ + "data/data.xml", + ], "demo": [], } diff --git a/vcp_github/data/data.xml b/vcp_github/data/data.xml new file mode 100644 index 0000000..2a6e4c6 --- /dev/null +++ b/vcp_github/data/data.xml @@ -0,0 +1,11 @@ + + + + GitHub + github + + + GitHub + + + diff --git a/vcp_github/models/__init__.py b/vcp_github/models/__init__.py index 8fe49b4..c6c3d79 100644 --- a/vcp_github/models/__init__.py +++ b/vcp_github/models/__init__.py @@ -1,3 +1,5 @@ +from . import vcp_host from . import vcp_platform from . import vcp_repository -from . import res_partner +from . import vcp_user +from . import vcp_organization diff --git a/vcp_github/models/res_partner.py b/vcp_github/models/res_partner.py deleted file mode 100644 index f46fed1..0000000 --- a/vcp_github/models/res_partner.py +++ /dev/null @@ -1,123 +0,0 @@ -# Copyright 2026 Dixmit -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). - -import github3 - -from odoo import fields, models, tools - - -class ResPartner(models.Model): - _inherit = "res.partner" - - github_name = fields.Char( - string="GitHub Username", - help="GitHub username of the contributor or organization", - readonly=True, - ) - github_organization = fields.Boolean( - string="Is GitHub Organization", - help="Check if this partner represents a GitHub organization", - readonly=True, - ) - github_user = fields.Boolean( - string="Is GitHub User", - help="Check if this partner represents a GitHub user", - readonly=True, - ) - - _sql_constraints = [ - ( - "github_name_uniq", - "unique(github_name)", - "The GitHub username must be unique across partners.", - ), - ] - - @tools.ormcache("github_login") - def _get_github_user_id(self, github_login): - partner = self.with_context(active_test=False).search( - [("github_name", "=ilike", github_login)], limit=1 - ) - if not partner: - return False - if not partner.github_user: - partner.github_user = True - return partner.id - - @tools.ormcache("github_login") - def _get_github_organization_id(self, github_login): - partner = self.with_context(active_test=False).search( - [("github_name", "=ilike", github_login)], limit=1 - ) - if not partner: - return False - if not partner.github_organization: - partner.github_organization = True - return partner.id - - def _get_github_user(self, gh, client): - if not gh: - return False - if isinstance(gh, github3.users.User): - github_login = gh.login - else: - github_login = str(gh) - partner = self._get_github_user_id(github_login) - if partner: - return partner - if isinstance(gh, str): - try: - gh = client.user(github_login) - name = gh.name or github_login - except github3.exceptions.NotFoundError: - name = gh - else: - if hasattr(gh, "name"): - name = gh.name or github_login - else: - name = github_login - self.env.registry.clear_cache() - return self.create( - { - "name": name, - "github_name": github_login, - "github_user": True, - } - ).id - - def _get_github_organization(self, gh, client): - if not gh: - return False - partner = self._get_github_organization_id(str(gh)) - if partner: - return partner - self.env.registry.clear_cache() - try: - org = client.organization(str(gh)) - - return self.create( - { - "name": org.name or str(gh), - "github_name": str(gh), - "github_organization": True, - } - ).id - except github3.exceptions.NotFoundError: - user = client.user(str(gh)) - name = user.name or str(gh) - except github3.exceptions.ForbiddenError: - name = str(gh) - return self.create( - { - "name": name, - "github_name": str(gh), - "github_user": True, - "github_organization": True, - } - ).id - - def _get_contributor_url(self): - result = super()._get_contributor_url() - if not result and self.github_name: - return f"https://github.com/{self.github_name}" - return result diff --git a/vcp_github/models/vcp_host.py b/vcp_github/models/vcp_host.py new file mode 100644 index 0000000..e320947 --- /dev/null +++ b/vcp_github/models/vcp_host.py @@ -0,0 +1,19 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, models +from odoo.exceptions import ValidationError + + +class VcpHost(models.Model): + _inherit = "vcp.host" + + @api.constrains("type_id") + def _check_kind_github(self): + for record in self.filtered(lambda r: r.type_id.code == "github"): + platforms = self.search( + [("id", "!=", record.id), ("type_id.code", "=", "github")], + limit=1, + ) + if platforms: + raise ValidationError(_("Only one GitHub Host type is allowed.")) diff --git a/vcp_github/models/vcp_organization.py b/vcp_github/models/vcp_organization.py new file mode 100644 index 0000000..be5339a --- /dev/null +++ b/vcp_github/models/vcp_organization.py @@ -0,0 +1,15 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + + +from odoo import models + + +class VcpOrganization(models.Model): + _inherit = "vcp.organization" + + def _get_contributor_url(self): + result = super()._get_contributor_url() + if not result and self.host_id.type_id.code == "github": + return f"https://github.com/{self.external_id}" + return result diff --git a/vcp_github/models/vcp_platform.py b/vcp_github/models/vcp_platform.py index ddd91c7..b8534bc 100644 --- a/vcp_github/models/vcp_platform.py +++ b/vcp_github/models/vcp_platform.py @@ -15,10 +15,8 @@ class VcpPlatform(models.Model): _inherit = "vcp.platform" - kind = fields.Selection( - selection_add=[("github", "GitHub")], - ondelete={"github": "cascade"}, - ) + def _get_git_url_github(self, repository): + return f"https://github.com/{self.name}/{repository.name}" def _get_github_clients(self): git = [] diff --git a/vcp_github/models/vcp_repository.py b/vcp_github/models/vcp_repository.py index 6d1630a..cadc3e6 100644 --- a/vcp_github/models/vcp_repository.py +++ b/vcp_github/models/vcp_repository.py @@ -16,6 +16,37 @@ class VcpRepository(models.Model): _inherit = "vcp.repository" + def _update_branches_github(self): + self.ensure_one() + client = self.platform_id._get_github_clients()[0] + try: + repo = client.repository(self.platform_id.name, self.name) + original_branches = self.branch_ids + existing_branches = {b.branch_id.name: b for b in self.branch_ids} + found_branches = self.env["vcp.repository.branch"] + for branch in repo.branches(): + if branch.name in existing_branches: + existing_branches[branch.name].sudo().write( + {"last_commit": branch.commit.sha} + ) + found_branches |= existing_branches[branch.name] + else: + self.env["vcp.repository.branch"].sudo().create( + { + "repository_id": self.id, + "branch_id": self.platform_id._get_branch(branch.name), + "last_commit": branch.commit.sha, + } + ) + (original_branches - found_branches).sudo().unlink() + except github3.exceptions.ForbiddenError as e: + _logger.error(e) + rate = client.rate_limit() + reset = fields.Datetime.to_string( + datetime.utcfromtimestamp(rate["resources"]["core"]["reset"]) + ) + raise ValidationError(self.env._(f"Reset on {reset}")) from e + def _parse_github_pr(self, pr, client): origin_data = pr.as_dict() comments_url = pr.comments_url @@ -35,11 +66,11 @@ def _parse_github_pr(self, pr, client): return ( str(pr.id), { - "partner_id": self.env["res.partner"]._get_github_user(pr.user, client), + "user_id": self.platform_id.host_id._get_user(pr.user.login), "repository_id": self.id, "branch_id": self.platform_id._get_branch(pr.base.ref), - "organization_id": self.env["res.partner"]._get_github_organization( - pr.head.repo[0], client + "organization_id": self.platform_id.host_id._get_organization( + pr.head.repo[0] ), "url": pr.html_url, "state": pr.state, @@ -72,10 +103,8 @@ def _parse_github_pr(self, pr, client): [ { "id": str(c["id"]), - "partner_id": c.get("user") - and self.env["res.partner"]._get_github_user( - c["user"].get("login"), client - ), + "user_id": c.get("user") + and self.platform_id.host_id._get_user(c["user"].get("login")), "body": c["body"], "created_at": self.platform_id._parse_github_date(c["created_at"]), "updated_at": self.platform_id._parse_github_date(c["updated_at"]), @@ -85,10 +114,8 @@ def _parse_github_pr(self, pr, client): [ { "id": str(r["id"]), - "partner_id": r.get("user") - and self.env["res.partner"]._get_github_user( - r["user"].get("login"), client - ), + "user_id": r.get("user") + and self.platform_id.host_id._get_user(r["user"].get("login")), "body": r["body"], "submitted_at": self.platform_id._parse_github_date( r.get("submitted_at") diff --git a/vcp_github/models/vcp_user.py b/vcp_github/models/vcp_user.py new file mode 100644 index 0000000..7b85782 --- /dev/null +++ b/vcp_github/models/vcp_user.py @@ -0,0 +1,15 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + + +from odoo import models + + +class VcpUser(models.Model): + _inherit = "vcp.user" + + def _get_contributor_url(self): + result = super()._get_contributor_url() + if not result and self.host_id.type_id.code == "github": + return f"https://github.com/{self.external_id}" + return result diff --git a/vcp_github/tests/test_github.py b/vcp_github/tests/test_github.py index 76cd448..dd00238 100644 --- a/vcp_github/tests/test_github.py +++ b/vcp_github/tests/test_github.py @@ -15,10 +15,12 @@ def setUpClass(cls): cls.platform = cls.env["vcp.platform"].create( { "name": "oca", - "kind": "github", + "host_id": cls.env.ref("vcp_github.vcp_github_host").id, "key_ids": [ Command.create({"name": "ghp_exampletoken1234567890abcdef"}) ], + "default_update_repository_information": True, + "information_update": True, } ) From 5e044f3ace0876075db89a81b9a2226b7b739cf8 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Wed, 25 Feb 2026 22:03:51 +0100 Subject: [PATCH 04/18] [IMP] vcp_github: allow to fetch only 'sources' repositories, ignoring forks allow to fetch only 'active' repositories, ignoring archived repositories add last_commit_date (in github, it related to 'PushedAt' field. (https://github.com/orgs/community/discussions/24442). It's an important field that show if the repo is active, or totally abandonned adapt github mock to latest changes demo data Add branch pattern, to fetch only branches whose names are matching a given pattern. It allows to ignore ocabot branches, in case of fetching OCA repositories Add vcp.branch menuitem, and improve display. Fix body storage. (convert markdown into html) get 'draft' state of pull requests. add a new 'status' field on vcp.request, that is based on 'is_draft', 'is_merged' and 'state' field to display the correct ribbon on form view / badge on list view improve naming of field, renaming information_update into scheduled_information_update. Add an helper. Check the field by default, as it is the expected behaviour user want Improve naming of field, renaming information_update into scheduled_information_update for vcp.repository model. Add helpers. explicit limit in cron python code. do not create a branch when fetching pull request, if the target branch doesn't match the pattern --- vcp_github/__manifest__.py | 6 ++++-- vcp_github/demo/demo_vcp_platform.xml | 9 +++++++++ vcp_github/models/vcp_platform.py | 27 +++++++++++++++++++++------ vcp_github/models/vcp_repository.py | 26 +++++++++++++++++++++++--- vcp_github/tests/test_github.py | 11 +++++++++-- 5 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 vcp_github/demo/demo_vcp_platform.xml diff --git a/vcp_github/__manifest__.py b/vcp_github/__manifest__.py index 668f42d..d10048f 100644 --- a/vcp_github/__manifest__.py +++ b/vcp_github/__manifest__.py @@ -12,10 +12,12 @@ "vcp_management", ], "external_dependencies": { - "python": ["github3.py"], + "python": ["github3.py", "markdown"], }, "data": [ "data/data.xml", ], - "demo": [], + "demo": [ + "demo/demo_vcp_platform.xml", + ], } diff --git a/vcp_github/demo/demo_vcp_platform.xml b/vcp_github/demo/demo_vcp_platform.xml new file mode 100644 index 0000000..984dc6c --- /dev/null +++ b/vcp_github/demo/demo_vcp_platform.xml @@ -0,0 +1,9 @@ + + + + OCA + + ^\d+\.\d+$ + + + diff --git a/vcp_github/models/vcp_platform.py b/vcp_github/models/vcp_platform.py index b8534bc..aba8a07 100644 --- a/vcp_github/models/vcp_platform.py +++ b/vcp_github/models/vcp_platform.py @@ -5,6 +5,7 @@ from datetime import datetime import github3 +import markdown import requests from pytz import UTC @@ -40,6 +41,10 @@ def _update_information_github(self): self.image_1920 = base64.b64encode(response.content) repos = org.repositories() for repo in repos: + if repo.fork and not self.fetch_repository_fork: + continue + if repo.archived and not self.fetch_repository_archived: + continue self._update_github_repository(repo) self.last_update = fields.Datetime.now() @@ -50,20 +55,30 @@ def _parse_github_date(self, date): datetime.fromisoformat(date.replace("Z", "+00:00")) ).replace(tzinfo=None) + def _parse_github_markdown(self, text): + return markdown.markdown(text) + def _update_github_repository(self, repo): vals = { "created_at": self._parse_github_date(repo.created_at), + "last_commit_date": self._parse_github_date(repo.pushed_at), "stargazers_count": repo.stargazers_count, "fork_count": repo.forks_count, + "is_fork": repo.fork, + "active": not repo.archived, "watchers_count": repo.watchers_count, "description": repo.description, } - repository = self.env["vcp.repository"].search( - [ - ("name", "=", repo.name), - ("platform_id", "=", self.id), - ], - limit=1, + repository = ( + self.env["vcp.repository"] + .with_context(active_test=False) + .search( + [ + ("name", "=", repo.name), + ("platform_id", "=", self.id), + ], + limit=1, + ) ) if not repository: repository = ( diff --git a/vcp_github/models/vcp_repository.py b/vcp_github/models/vcp_repository.py index cadc3e6..016e5e9 100644 --- a/vcp_github/models/vcp_repository.py +++ b/vcp_github/models/vcp_repository.py @@ -1,6 +1,7 @@ # Copyright 2026 Dixmit # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). import logging +import re from datetime import datetime, timedelta import github3 @@ -25,6 +26,13 @@ def _update_branches_github(self): existing_branches = {b.branch_id.name: b for b in self.branch_ids} found_branches = self.env["vcp.repository.branch"] for branch in repo.branches(): + branch_pattern = ( + self.fetch_branch_pattern + or self.platform_id.fetch_repository_branch_pattern + or False + ) + if branch_pattern and not re.match(branch_pattern, branch.name): + continue if branch.name in existing_branches: existing_branches[branch.name].sudo().write( {"last_commit": branch.commit.sha} @@ -48,6 +56,7 @@ def _update_branches_github(self): raise ValidationError(self.env._(f"Reset on {reset}")) from e def _parse_github_pr(self, pr, client): + self.ensure_one() origin_data = pr.as_dict() comments_url = pr.comments_url comments_req = client.session.get(comments_url) @@ -63,12 +72,22 @@ def _parse_github_pr(self, pr, client): reviews_url = reviews_req.links["next"]["url"] reviews_req = client.session.get(reviews_url) reviews += reviews_req.json() + + branch_pattern = ( + self.fetch_branch_pattern + or self.platform_id.fetch_repository_branch_pattern + or False + ) + if branch_pattern and not re.match(branch_pattern, pr.base.ref): + branch_id = False + else: + branch_id = self.platform_id._get_branch(pr.base.ref) return ( str(pr.id), { "user_id": self.platform_id.host_id._get_user(pr.user.login), "repository_id": self.id, - "branch_id": self.platform_id._get_branch(pr.base.ref), + "branch_id": branch_id, "organization_id": self.platform_id.host_id._get_organization( pr.head.repo[0] ), @@ -77,6 +96,7 @@ def _parse_github_pr(self, pr, client): "name": pr.title, "is_merged": any(label["name"] == "merged 🎉" for label in pr.labels) or pr.is_merged(), + "is_draft": pr.draft, "created_at": self.platform_id._parse_github_date( origin_data["created_at"] ), @@ -105,7 +125,7 @@ def _parse_github_pr(self, pr, client): "id": str(c["id"]), "user_id": c.get("user") and self.platform_id.host_id._get_user(c["user"].get("login")), - "body": c["body"], + "body": self.platform_id._parse_github_markdown(c["body"]), "created_at": self.platform_id._parse_github_date(c["created_at"]), "updated_at": self.platform_id._parse_github_date(c["updated_at"]), } @@ -116,7 +136,7 @@ def _parse_github_pr(self, pr, client): "id": str(r["id"]), "user_id": r.get("user") and self.platform_id.host_id._get_user(r["user"].get("login")), - "body": r["body"], + "body": self.platform_id._parse_github_markdown(r["body"]), "submitted_at": self.platform_id._parse_github_date( r.get("submitted_at") ), diff --git a/vcp_github/tests/test_github.py b/vcp_github/tests/test_github.py index dd00238..e598de7 100644 --- a/vcp_github/tests/test_github.py +++ b/vcp_github/tests/test_github.py @@ -19,8 +19,8 @@ def setUpClass(cls): "key_ids": [ Command.create({"name": "ghp_exampletoken1234567890abcdef"}) ], - "default_update_repository_information": True, - "information_update": True, + "default_repository_scheduled_information_update": True, + "scheduled_information_update": True, } ) @@ -60,10 +60,16 @@ def test_update_organization_with_repository(self): mock_org.avatar_url = False mock_repo1 = MagicMock() mock_repo1.name = "server-tools" + mock_repo1.archived = False + mock_repo1.fork = False mock_repo1.created_at = "2020-01-01T00:00:00Z" + mock_repo1.pushed_at = "2020-02-01T00:00:00Z" mock_repo2 = MagicMock() mock_repo2.name = "server-brand" + mock_repo2.archived = False + mock_repo2.fork = False mock_repo2.created_at = "2021-01-01T10:00:00Z" + mock_repo2.pushed_at = "2021-02-01T00:00:00Z" mock_org.repositories.return_value = [mock_repo1, mock_repo2] mock_client.organization.return_value = mock_org mock_github3.login.return_value = mock_client @@ -102,6 +108,7 @@ def test_update_repository(self): "created_at": "2023-01-01T00:00:00Z", "updated_at": "2023-01-03T00:00:00Z", "closed_at": "2023-01-02T00:00:00Z", + "pushed_at": "2024-01-02T00:00:00Z", "commits": 3, "comments": 2, "review_comments": 1, From 387fe9370b1c9582e981ae5a7968879091754fc9 Mon Sep 17 00:00:00 2001 From: Enric Tobella Date: Thu, 19 Mar 2026 06:11:40 +0100 Subject: [PATCH 05/18] [IMP] vcp_github Improve error message Fix minor texts and readme Adapt to new VCP logic --- vcp_github/README.rst | 140 +------------------- vcp_github/__manifest__.py | 4 +- vcp_github/data/data.xml | 1 + vcp_github/models/vcp_platform.py | 7 +- vcp_github/readme/CONFIGURE.md | 10 -- vcp_github/readme/CONTEXT.md | 16 --- vcp_github/readme/CONTRIBUTORS.md | 4 +- vcp_github/readme/CREDITS.md | 7 - vcp_github/readme/DESCRIPTION.md | 8 +- vcp_github/readme/HISTORY.md | 22 ---- vcp_github/readme/INSTALL.md | 7 - vcp_github/readme/ROADMAP.md | 5 - vcp_github/readme/USAGE.md | 21 --- vcp_github/static/description/index.html | 158 +++-------------------- 14 files changed, 31 insertions(+), 379 deletions(-) delete mode 100644 vcp_github/readme/CONFIGURE.md delete mode 100644 vcp_github/readme/CONTEXT.md delete mode 100644 vcp_github/readme/CREDITS.md delete mode 100644 vcp_github/readme/HISTORY.md delete mode 100644 vcp_github/readme/INSTALL.md delete mode 100644 vcp_github/readme/ROADMAP.md delete mode 100644 vcp_github/readme/USAGE.md diff --git a/vcp_github/README.rst b/vcp_github/README.rst index 07627b8..1c659e0 100644 --- a/vcp_github/README.rst +++ b/vcp_github/README.rst @@ -28,135 +28,14 @@ Vcp Github |badge1| |badge2| |badge3| |badge4| |badge5| -[ This file must be max 2-3 paragraphs, and is required. - -The goal of this document is to explain quickly the features of this -module: “what” this module does and “what” it is for. ] - -Example: - -This module extends the functionality of ... to support ... and to allow -users to ... +This module facilitates the integration between Github and Version +Control Platform. **Table of contents** .. contents:: :local: -Use Cases / Context -=================== - -[ This file is optional but strongly suggested to allow end-users to -evaluate the module's usefulness in their context. ] - -BUSINESS NEED: It should explain the “why” of the module: - -- what is the business requirement that generated the need to develop - this module -- in which context or use cases this module can be useful (practical - examples are welcome!). - -APPROACH: It could also explain the approach to address the mentioned -need. - -USEFUL INFORMATION: It can also inform on related modules: - -- modules it depends on and their features -- other modules that can work well together with this one -- suggested setups where the module is useful (eg: multicompany, - multi-website) - -Installation -============ - -[ This file must only be present if there are very specific installation -instructions, such as installing non-python dependencies. The audience -is systems administrators. ] - -To install this module, you need to: - -1. Do this ... - -Configuration -============= - -[ This file is not always required; it should explain **how to configure -the module before using it**; it is aimed at users with administration -privileges. - -Please be detailed on the path to configuration (eg: do you need to -activate developer mode?), describe step by step configurations and the -use of screenshots is strongly recommended.] - -To configure this module, you need to: - -- Go to *App* > Menu > Menu item -- Activate boolean… > save -- … - -Usage -===== - -[ This file is required and contains the instructions on **“how”** to -use the module for end-users. - -If the module does not have a visible impact on the user interface, just -add the following sentence: - - This module does not impact the user interface. - -If that’s not the case, please make sure that every usage step is -covered and remember that images speak more than words!] - -To use this module, you need to: - -- Go to *App* > Menu > Menu item - - *insert screenshot!* - -- In “Contact” form, add a value to field *xyz* > save - - *insert screenshot!* - -- The value of *xyz* is now displayed in the list view. - - *insert screenshot!* - -Known issues / Roadmap -====================== - -[ Enumerate known caveats and future potential improvements. It is -mostly intended for end-users, and can also help potential new -contributors discovering new features to implement. ] - -- ... - -Changelog -========= - -[ The change log. The goal of this file is to help readers understand -changes between version. The primary audience is end users and -integrators. Purely technical changes such as code refactoring must not -be mentioned here. - -This file may contain ONE level of section titles, underlined with the ~ -(tilde) character. Other section markers are forbidden and will likely -break the structure of the README.rst or other documents where this -fragment is included. ] - -11.0.x.y.z (YYYY-MM-DD) ------------------------ - -- [BREAKING] Breaking changes come first. - (`#70 `__) -- [ADD] New feature. (`#74 `__) -- [FIX] Correct this. (`#71 `__) - -11.0.x.y.z (YYYY-MM-DD) ------------------------ - -- ... - Bug Tracker =========== @@ -178,20 +57,9 @@ Authors Contributors ------------ -- Firstname Lastname email.address@example.org (optional company website - url) -- Second Person second.person@example.org (optional company website url) - -Other credits -------------- - -[ This file is optional and contains additional credits, other than -authors, contributors, and maintainers. ] - -The development of this module has been financially supported by: +- `Dixmit `__ -- Company 1 name -- Company 2 name + - Enric Tobella Maintainers ----------- diff --git a/vcp_github/__manifest__.py b/vcp_github/__manifest__.py index d10048f..c6116fe 100644 --- a/vcp_github/__manifest__.py +++ b/vcp_github/__manifest__.py @@ -3,13 +3,13 @@ { "name": "Vcp Github", - "summary": """Integrate Virtual Control Platform with Github""", + "summary": """Integrate Version Control Platform with Github""", "version": "18.0.1.0.0", "license": "AGPL-3", "author": "Dixmit,Odoo Community Association (OCA)", "website": "https://github.com/OCA/version-control-platform", "depends": [ - "vcp_management", + "vcp_git", ], "external_dependencies": { "python": ["github3.py", "markdown"], diff --git a/vcp_github/data/data.xml b/vcp_github/data/data.xml index 2a6e4c6..47915bb 100644 --- a/vcp_github/data/data.xml +++ b/vcp_github/data/data.xml @@ -3,6 +3,7 @@ GitHub github + git GitHub diff --git a/vcp_github/models/vcp_platform.py b/vcp_github/models/vcp_platform.py index aba8a07..14ebfaf 100644 --- a/vcp_github/models/vcp_platform.py +++ b/vcp_github/models/vcp_platform.py @@ -30,7 +30,12 @@ def _update_information_github(self): clients = self._get_github_clients() if not clients: raise ValidationError( - _("No github clients configured. Please enter at least an API Key.") + _( + "No github clients configured. " + "Please enter at least a Github Personal Access Token. " + "You can check more information at " + "https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens" + ) ) org = clients[0].organization(self.name) self.short_description = org.name diff --git a/vcp_github/readme/CONFIGURE.md b/vcp_github/readme/CONFIGURE.md deleted file mode 100644 index 2fdb0e6..0000000 --- a/vcp_github/readme/CONFIGURE.md +++ /dev/null @@ -1,10 +0,0 @@ -[ This file is not always required; it should explain **how to configure the module before using it**; it is aimed at users with administration privileges. - -Please be detailed on the path to configuration (eg: do you need to activate developer mode?), describe step by step configurations and the use of screenshots is strongly recommended.] - - -To configure this module, you need to: - -- Go to *App* > Menu > Menu item -- Activate boolean… > save -- … diff --git a/vcp_github/readme/CONTEXT.md b/vcp_github/readme/CONTEXT.md deleted file mode 100644 index 096235a..0000000 --- a/vcp_github/readme/CONTEXT.md +++ /dev/null @@ -1,16 +0,0 @@ -[ This file is optional but strongly suggested to allow end-users to evaluate the -module's usefulness in their context. ] - -BUSINESS NEED: -It should explain the “why” of the module: -- what is the business requirement that generated the need to develop this module -- in which context or use cases this module can be useful (practical examples are welcome!). - -APPROACH: -It could also explain the approach to address the mentioned need. - -USEFUL INFORMATION: -It can also inform on related modules: -- modules it depends on and their features -- other modules that can work well together with this one -- suggested setups where the module is useful (eg: multicompany, multi-website) diff --git a/vcp_github/readme/CONTRIBUTORS.md b/vcp_github/readme/CONTRIBUTORS.md index 7be72fb..2c066ba 100644 --- a/vcp_github/readme/CONTRIBUTORS.md +++ b/vcp_github/readme/CONTRIBUTORS.md @@ -1,2 +1,2 @@ -- Firstname Lastname (optional company website url) -- Second Person (optional company website url) +- [Dixmit](https://www.dixmit.com) + - Enric Tobella diff --git a/vcp_github/readme/CREDITS.md b/vcp_github/readme/CREDITS.md deleted file mode 100644 index 9c2b025..0000000 --- a/vcp_github/readme/CREDITS.md +++ /dev/null @@ -1,7 +0,0 @@ -[ This file is optional and contains additional credits, other than - authors, contributors, and maintainers. ] - -The development of this module has been financially supported by: - -- Company 1 name -- Company 2 name diff --git a/vcp_github/readme/DESCRIPTION.md b/vcp_github/readme/DESCRIPTION.md index 2371a14..345189d 100644 --- a/vcp_github/readme/DESCRIPTION.md +++ b/vcp_github/readme/DESCRIPTION.md @@ -1,7 +1 @@ -[ This file must be max 2-3 paragraphs, and is required. - -The goal of this document is to explain quickly the features of this module: “what” this module does and “what” it is for. ] - -Example: - -This module extends the functionality of ... to support ... and to allow users to ... +This module facilitates the integration between Github and Version Control Platform. diff --git a/vcp_github/readme/HISTORY.md b/vcp_github/readme/HISTORY.md deleted file mode 100644 index a6daf58..0000000 --- a/vcp_github/readme/HISTORY.md +++ /dev/null @@ -1,22 +0,0 @@ -[ The change log. The goal of this file is to help readers - understand changes between version. The primary audience is - end users and integrators. Purely technical changes such as - code refactoring must not be mentioned here. - - This file may contain ONE level of section titles, underlined - with the ~ (tilde) character. Other section markers are - forbidden and will likely break the structure of the README.rst - or other documents where this fragment is included. ] - -## 11.0.x.y.z (YYYY-MM-DD) - -- [BREAKING] Breaking changes come first. - ([#70](https://github.com/OCA/repo/issues/70)) -- [ADD] New feature. - ([#74](https://github.com/OCA/repo/issues/74)) -- [FIX] Correct this. - ([#71](https://github.com/OCA/repo/issues/71)) - -## 11.0.x.y.z (YYYY-MM-DD) - -- ... diff --git a/vcp_github/readme/INSTALL.md b/vcp_github/readme/INSTALL.md deleted file mode 100644 index 77b98e7..0000000 --- a/vcp_github/readme/INSTALL.md +++ /dev/null @@ -1,7 +0,0 @@ -[ This file must only be present if there are very specific - installation instructions, such as installing non-python - dependencies. The audience is systems administrators. ] - -To install this module, you need to: - -1. Do this ... diff --git a/vcp_github/readme/ROADMAP.md b/vcp_github/readme/ROADMAP.md deleted file mode 100644 index 446840c..0000000 --- a/vcp_github/readme/ROADMAP.md +++ /dev/null @@ -1,5 +0,0 @@ -[ Enumerate known caveats and future potential improvements. - It is mostly intended for end-users, and can also help - potential new contributors discovering new features to implement. ] - -- ... diff --git a/vcp_github/readme/USAGE.md b/vcp_github/readme/USAGE.md deleted file mode 100644 index 2cf1275..0000000 --- a/vcp_github/readme/USAGE.md +++ /dev/null @@ -1,21 +0,0 @@ -[ This file is required and contains the instructions on **“how”** to use the module for end-users. - -If the module does not have a visible impact on the user interface, just add the following sentence: - -> This module does not impact the user interface. - -If that’s not the case, please make sure that every usage step is covered and remember that images speak more than words!] - -To use this module, you need to: - -- Go to *App* > Menu > Menu item - - *insert screenshot!* - -- In “Contact” form, add a value to field *xyz* > save - - *insert screenshot!* - -- The value of *xyz* is now displayed in the list view. - - *insert screenshot!* diff --git a/vcp_github/static/description/index.html b/vcp_github/static/description/index.html index 63aa4a5..f258b6c 100644 --- a/vcp_github/static/description/index.html +++ b/vcp_github/static/description/index.html @@ -370,141 +370,22 @@

Vcp Github

!! source digest: sha256:086596db3dcb4fa7565fc97cf01ccd22449731243622d4587a1f609eab8bc121 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/version-control-platform Translate me on Weblate Try me on Runboat

-

[ This file must be max 2-3 paragraphs, and is required.

-

The goal of this document is to explain quickly the features of this -module: “what” this module does and “what” it is for. ]

-

Example:

-

This module extends the functionality of … to support … and to allow -users to …

+

This module facilitates the integration between Github and Version +Control Platform.

Table of contents

-
-

Use Cases / Context

-

[ This file is optional but strongly suggested to allow end-users to -evaluate the module’s usefulness in their context. ]

-

BUSINESS NEED: It should explain the “why” of the module:

-
    -
  • what is the business requirement that generated the need to develop -this module
  • -
  • in which context or use cases this module can be useful (practical -examples are welcome!).
  • -
-

APPROACH: It could also explain the approach to address the mentioned -need.

-

USEFUL INFORMATION: It can also inform on related modules:

-
    -
  • modules it depends on and their features
  • -
  • other modules that can work well together with this one
  • -
  • suggested setups where the module is useful (eg: multicompany, -multi-website)
  • -
-
-
-

Installation

-

[ This file must only be present if there are very specific installation -instructions, such as installing non-python dependencies. The audience -is systems administrators. ]

-

To install this module, you need to:

-
    -
  1. Do this …
  2. -
-
-
-

Configuration

-

[ This file is not always required; it should explain how to configure -the module before using it; it is aimed at users with administration -privileges.

-

Please be detailed on the path to configuration (eg: do you need to -activate developer mode?), describe step by step configurations and the -use of screenshots is strongly recommended.]

-

To configure this module, you need to:

-
    -
  • Go to App > Menu > Menu item
  • -
  • Activate boolean… > save
  • -
  • -
-
-
-

Usage

-

[ This file is required and contains the instructions on “how” to -use the module for end-users.

-

If the module does not have a visible impact on the user interface, just -add the following sentence:

-
-This module does not impact the user interface.
-

If that’s not the case, please make sure that every usage step is -covered and remember that images speak more than words!]

-

To use this module, you need to:

-
    -
  • Go to App > Menu > Menu item

    -

    insert screenshot!

    -
  • -
  • In “Contact” form, add a value to field xyz > save

    -

    insert screenshot!

    -
  • -
  • The value of xyz is now displayed in the list view.

    -

    insert screenshot!

    -
  • -
-
-
-

Known issues / Roadmap

-

[ Enumerate known caveats and future potential improvements. It is -mostly intended for end-users, and can also help potential new -contributors discovering new features to implement. ]

-
    -
  • -
-
-
-

Changelog

-

[ The change log. The goal of this file is to help readers understand -changes between version. The primary audience is end users and -integrators. Purely technical changes such as code refactoring must not -be mentioned here.

-

This file may contain ONE level of section titles, underlined with the ~ -(tilde) character. Other section markers are forbidden and will likely -break the structure of the README.rst or other documents where this -fragment is included. ]

-
-

11.0.x.y.z (YYYY-MM-DD)

-
    -
  • [BREAKING] Breaking changes come first. -(#70)
  • -
  • [ADD] New feature. (#74)
  • -
  • [FIX] Correct this. (#71)
  • -
-
-
-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed @@ -512,33 +393,24 @@

Bug Tracker

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Dixmit
-

Contributors

+

Contributors

-
-

Other credits

-

[ This file is optional and contains additional credits, other than -authors, contributors, and maintainers. ]

-

The development of this module has been financially supported by:

-
    -
  • Company 1 name
  • -
  • Company 2 name
  • +
-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association From 7c77efc4f274cd13c0f935510a167a8a2188bc6f Mon Sep 17 00:00:00 2001 From: oca-ci Date: Wed, 1 Apr 2026 08:00:44 +0000 Subject: [PATCH 06/18] [UPD] Update vcp_github.pot --- vcp_github/i18n/vcp_github.pot | 55 ++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 vcp_github/i18n/vcp_github.pot diff --git a/vcp_github/i18n/vcp_github.pot b/vcp_github/i18n/vcp_github.pot new file mode 100644 index 0000000..87b0648 --- /dev/null +++ b/vcp_github/i18n/vcp_github.pot @@ -0,0 +1,55 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * vcp_github +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: vcp_github +#. odoo-python +#: code:addons/vcp_github/models/vcp_platform.py:0 +msgid "" +"No github clients configured. Please enter at least a Github Personal Access" +" Token. You can check more information at " +"https://docs.github.com/en/authentication/keeping-your-account-and-data-" +"secure/managing-your-personal-access-tokens" +msgstr "" + +#. module: vcp_github +#. odoo-python +#: code:addons/vcp_github/models/vcp_host.py:0 +msgid "Only one GitHub Host type is allowed." +msgstr "" + +#. module: vcp_github +#: model:ir.model,name:vcp_github.model_vcp_organization +msgid "Organization" +msgstr "" + +#. module: vcp_github +#: model:ir.model,name:vcp_github.model_vcp_repository +msgid "Repository" +msgstr "" + +#. module: vcp_github +#: model:ir.model,name:vcp_github.model_vcp_user +msgid "User" +msgstr "" + +#. module: vcp_github +#: model:ir.model,name:vcp_github.model_vcp_host +msgid "VCP Host" +msgstr "" + +#. module: vcp_github +#: model:ir.model,name:vcp_github.model_vcp_platform +msgid "VCP Platform" +msgstr "" From 5c554a8a9bae5c5dd976ff0a4a144271f93b478a Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Wed, 1 Apr 2026 08:04:26 +0000 Subject: [PATCH 07/18] [BOT] post-merge updates --- vcp_github/README.rst | 8 ++++++-- vcp_github/static/description/index.html | 26 +++++++++++++++--------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/vcp_github/README.rst b/vcp_github/README.rst index 1c659e0..75eda72 100644 --- a/vcp_github/README.rst +++ b/vcp_github/README.rst @@ -1,3 +1,7 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + ========== Vcp Github ========== @@ -7,13 +11,13 @@ Vcp Github !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:086596db3dcb4fa7565fc97cf01ccd22449731243622d4587a1f609eab8bc121 + !! source digest: sha256:e658564d23337fe17b8a0bda9c6f780e8a4ce61ef1368682e9dbeded389b3be8 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status :alt: Beta -.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fversion--control--platform-lightgray.png?logo=github diff --git a/vcp_github/static/description/index.html b/vcp_github/static/description/index.html index f258b6c..cbd40c1 100644 --- a/vcp_github/static/description/index.html +++ b/vcp_github/static/description/index.html @@ -3,7 +3,7 @@ -Vcp Github +README.rst -
-

Vcp Github

+
+ + +Odoo Community Association + +
+

Vcp Github

-

Beta License: AGPL-3 OCA/version-control-platform Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/version-control-platform Translate me on Weblate Try me on Runboat

This module facilitates the integration between Github and Version Control Platform.

Table of contents

@@ -385,7 +390,7 @@

Vcp Github

-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed @@ -393,15 +398,15 @@

Bug Tracker

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Dixmit
-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -423,5 +428,6 @@

Maintainers

+
From 394c4683fa8a94274ea7b47d15ad451cb30e9d98 Mon Sep 17 00:00:00 2001 From: mymage Date: Wed, 8 Apr 2026 10:14:50 +0000 Subject: [PATCH 08/18] Added translation using Weblate (Italian) --- vcp_github/i18n/it.po | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 vcp_github/i18n/it.po diff --git a/vcp_github/i18n/it.po b/vcp_github/i18n/it.po new file mode 100644 index 0000000..f452b7d --- /dev/null +++ b/vcp_github/i18n/it.po @@ -0,0 +1,56 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * vcp_github +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: vcp_github +#. odoo-python +#: code:addons/vcp_github/models/vcp_platform.py:0 +msgid "" +"No github clients configured. Please enter at least a Github Personal Access" +" Token. You can check more information at " +"https://docs.github.com/en/authentication/keeping-your-account-and-data-" +"secure/managing-your-personal-access-tokens" +msgstr "" + +#. module: vcp_github +#. odoo-python +#: code:addons/vcp_github/models/vcp_host.py:0 +msgid "Only one GitHub Host type is allowed." +msgstr "" + +#. module: vcp_github +#: model:ir.model,name:vcp_github.model_vcp_organization +msgid "Organization" +msgstr "" + +#. module: vcp_github +#: model:ir.model,name:vcp_github.model_vcp_repository +msgid "Repository" +msgstr "" + +#. module: vcp_github +#: model:ir.model,name:vcp_github.model_vcp_user +msgid "User" +msgstr "" + +#. module: vcp_github +#: model:ir.model,name:vcp_github.model_vcp_host +msgid "VCP Host" +msgstr "" + +#. module: vcp_github +#: model:ir.model,name:vcp_github.model_vcp_platform +msgid "VCP Platform" +msgstr "" From adabca5d1ee50eeaedbbb62ca6554a4ac472bff7 Mon Sep 17 00:00:00 2001 From: mymage Date: Wed, 8 Apr 2026 10:19:55 +0000 Subject: [PATCH 09/18] Translated using Weblate (Italian) Currently translated at 100.0% (7 of 7 strings) Translation: version-control-platform-18.0/version-control-platform-18.0-vcp_github Translate-URL: https://translation.odoo-community.org/projects/version-control-platform-18-0/version-control-platform-18-0-vcp_github/it/ --- vcp_github/i18n/it.po | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/vcp_github/i18n/it.po b/vcp_github/i18n/it.po index f452b7d..b26bac8 100644 --- a/vcp_github/i18n/it.po +++ b/vcp_github/i18n/it.po @@ -6,13 +6,15 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 18.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: Automatically generated\n" +"PO-Revision-Date: 2026-04-08 12:45+0000\n" +"Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.15.2\n" #. module: vcp_github #. odoo-python @@ -23,34 +25,38 @@ msgid "" "https://docs.github.com/en/authentication/keeping-your-account-and-data-" "secure/managing-your-personal-access-tokens" msgstr "" +"Nessun client GitHub configurato. Inserire almeno un token di accesso " +"personale di GitHub. Si possono trovare maggiori informazioni su https://" +"docs.github.com/en/authentication/keeping-your-account-and-data-secure/" +"managing-your-personal-access-tokens" #. module: vcp_github #. odoo-python #: code:addons/vcp_github/models/vcp_host.py:0 msgid "Only one GitHub Host type is allowed." -msgstr "" +msgstr "È consentito solo un tipo host GitHub." #. module: vcp_github #: model:ir.model,name:vcp_github.model_vcp_organization msgid "Organization" -msgstr "" +msgstr "Organizzazione" #. module: vcp_github #: model:ir.model,name:vcp_github.model_vcp_repository msgid "Repository" -msgstr "" +msgstr "Repository" #. module: vcp_github #: model:ir.model,name:vcp_github.model_vcp_user msgid "User" -msgstr "" +msgstr "Utente" #. module: vcp_github #: model:ir.model,name:vcp_github.model_vcp_host msgid "VCP Host" -msgstr "" +msgstr "Host VCP" #. module: vcp_github #: model:ir.model,name:vcp_github.model_vcp_platform msgid "VCP Platform" -msgstr "" +msgstr "Piattaforma VCP" From fc220214b39dad270db5a252a1c33776c411963a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20BEAU?= Date: Wed, 25 Mar 2026 17:48:33 +0100 Subject: [PATCH 10/18] [FIX] vcp_github: fix getting repository url --- vcp_github/models/vcp_repository.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vcp_github/models/vcp_repository.py b/vcp_github/models/vcp_repository.py index 016e5e9..8f655d3 100644 --- a/vcp_github/models/vcp_repository.py +++ b/vcp_github/models/vcp_repository.py @@ -17,6 +17,12 @@ class VcpRepository(models.Model): _inherit = "vcp.repository" + def _get_repository_url(self): + result = super()._get_repository_url() + if not result and self.platform_id.host_id.type_id.code == "github": + return f"https://github.com/{self.platform_id.name}/{self.name}" + return result + def _update_branches_github(self): self.ensure_one() client = self.platform_id._get_github_clients()[0] From e513bf97536c991fed65266bc0730c7ea77c3456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20BEAU?= Date: Thu, 23 Apr 2026 18:38:36 +0200 Subject: [PATCH 11/18] [IMP] vcp_github: add implementation for sync user --- vcp_github/models/vcp_user.py | 41 ++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/vcp_github/models/vcp_user.py b/vcp_github/models/vcp_user.py index 7b85782..8f6d1ae 100644 --- a/vcp_github/models/vcp_user.py +++ b/vcp_github/models/vcp_user.py @@ -2,7 +2,15 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import models +import logging +from datetime import datetime + +import github3 + +from odoo import fields, models +from odoo.exceptions import ValidationError + +_logger = logging.getLogger(__name__) class VcpUser(models.Model): @@ -13,3 +21,34 @@ def _get_contributor_url(self): if not result and self.host_id.type_id.code == "github": return f"https://github.com/{self.external_id}" return result + + def _prepare_user_vals(self, user): + return { + "name": user.name or user.login, + "email": user.email, + "avatar_url": user.avatar_url, + "company": user.company, + } + + def _update_information_github(self): + self.ensure_one() + # TODO maybe we should move the api key on the host ? + platform = self.env["vcp.platform"].search( + [("host_id", "=", self.host_id.id)], limit=1 + ) + client = platform._get_github_clients()[0] + try: + user = client.user(self.external_id) + self.write(self._prepare_user_vals(user)) + except github3.exceptions.ForbiddenError as e: + _logger.error(e) + rate = client.rate_limit() + reset = fields.Datetime.to_string( + datetime.utcfromtimestamp(rate["resources"]["core"]["reset"]) + ) + raise ValidationError(self.env._(f"Reset on {reset}")) from e + except github3.exceptions.NotFoundError: + _logger.warning( + "The user %s do not exist anymore, inactive it", self.external_id + ) + self.active = False From e485ae3d6458ad02ee3d409c1c958100d4bc5e11 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Tue, 26 May 2026 14:45:35 +0000 Subject: [PATCH 12/18] [BOT] post-merge updates --- vcp_github/README.rst | 2 +- vcp_github/__manifest__.py | 2 +- vcp_github/static/description/index.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vcp_github/README.rst b/vcp_github/README.rst index 75eda72..f83869c 100644 --- a/vcp_github/README.rst +++ b/vcp_github/README.rst @@ -11,7 +11,7 @@ Vcp Github !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:e658564d23337fe17b8a0bda9c6f780e8a4ce61ef1368682e9dbeded389b3be8 + !! source digest: sha256:02ea297e01fa30d3efb357e90456e0cf7f1de8495337a61c9575da8deb421981 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/vcp_github/__manifest__.py b/vcp_github/__manifest__.py index c6116fe..7b875a5 100644 --- a/vcp_github/__manifest__.py +++ b/vcp_github/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Vcp Github", "summary": """Integrate Version Control Platform with Github""", - "version": "18.0.1.0.0", + "version": "18.0.1.0.1", "license": "AGPL-3", "author": "Dixmit,Odoo Community Association (OCA)", "website": "https://github.com/OCA/version-control-platform", diff --git a/vcp_github/static/description/index.html b/vcp_github/static/description/index.html index cbd40c1..a6dee48 100644 --- a/vcp_github/static/description/index.html +++ b/vcp_github/static/description/index.html @@ -372,7 +372,7 @@

Vcp Github

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:e658564d23337fe17b8a0bda9c6f780e8a4ce61ef1368682e9dbeded389b3be8 +!! source digest: sha256:02ea297e01fa30d3efb357e90456e0cf7f1de8495337a61c9575da8deb421981 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/version-control-platform Translate me on Weblate Try me on Runboat

This module facilitates the integration between Github and Version From 8edaa2c6ba3da03d157c164644c85ce37d25fd29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20BEAU?= Date: Wed, 10 Jun 2026 14:50:00 +0200 Subject: [PATCH 13/18] vcp_github: some review can be not submitted after importing all oca prn there is some review that are not submitted and so not public but still available in the API, only import review submitted --- vcp_github/models/vcp_repository.py | 1 + 1 file changed, 1 insertion(+) diff --git a/vcp_github/models/vcp_repository.py b/vcp_github/models/vcp_repository.py index 8f655d3..70a98f9 100644 --- a/vcp_github/models/vcp_repository.py +++ b/vcp_github/models/vcp_repository.py @@ -151,6 +151,7 @@ def _parse_github_pr(self, pr, client): else r["state"], } for r in reviews + if r.get("submitted_at") ], ) From 3d6b2b9aa9b1cb09a8733acbc195a2e6a4227771 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Tue, 16 Jun 2026 07:25:29 +0000 Subject: [PATCH 14/18] [BOT] post-merge updates --- vcp_github/README.rst | 2 +- vcp_github/__manifest__.py | 2 +- vcp_github/static/description/index.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vcp_github/README.rst b/vcp_github/README.rst index f83869c..8885bed 100644 --- a/vcp_github/README.rst +++ b/vcp_github/README.rst @@ -11,7 +11,7 @@ Vcp Github !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:02ea297e01fa30d3efb357e90456e0cf7f1de8495337a61c9575da8deb421981 + !! source digest: sha256:c11ed718a96213c61adaf41d94d05c5ae2965b6a676231d6d4fac3a6ebf3264b !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/vcp_github/__manifest__.py b/vcp_github/__manifest__.py index 7b875a5..8eddf10 100644 --- a/vcp_github/__manifest__.py +++ b/vcp_github/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Vcp Github", "summary": """Integrate Version Control Platform with Github""", - "version": "18.0.1.0.1", + "version": "18.0.1.0.2", "license": "AGPL-3", "author": "Dixmit,Odoo Community Association (OCA)", "website": "https://github.com/OCA/version-control-platform", diff --git a/vcp_github/static/description/index.html b/vcp_github/static/description/index.html index a6dee48..f265d07 100644 --- a/vcp_github/static/description/index.html +++ b/vcp_github/static/description/index.html @@ -372,7 +372,7 @@

Vcp Github

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:02ea297e01fa30d3efb357e90456e0cf7f1de8495337a61c9575da8deb421981 +!! source digest: sha256:c11ed718a96213c61adaf41d94d05c5ae2965b6a676231d6d4fac3a6ebf3264b !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/version-control-platform Translate me on Weblate Try me on Runboat

This module facilitates the integration between Github and Version From 0152612b917ebd665166d44b6736736572979032 Mon Sep 17 00:00:00 2001 From: Enric Tobella Date: Mon, 27 Jul 2026 08:51:06 +0200 Subject: [PATCH 15/18] [IMP] vcp_github: Markdown using fenced code --- vcp_github/models/vcp_platform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vcp_github/models/vcp_platform.py b/vcp_github/models/vcp_platform.py index 14ebfaf..27b6699 100644 --- a/vcp_github/models/vcp_platform.py +++ b/vcp_github/models/vcp_platform.py @@ -61,7 +61,7 @@ def _parse_github_date(self, date): ).replace(tzinfo=None) def _parse_github_markdown(self, text): - return markdown.markdown(text) + return markdown.markdown(text, extensions=["fenced_code"]) def _update_github_repository(self, repo): vals = { From 8e395702e524ed0f5dc306be47cfb46a5dd05713 Mon Sep 17 00:00:00 2001 From: Bhavesh Heliconia Date: Mon, 29 Jun 2026 10:55:58 +0530 Subject: [PATCH 16/18] [IMP] vcp_github: pre-commit auto fixes --- requirements.txt | 3 +++ vcp_github/models/vcp_host.py | 6 ++++-- vcp_github/models/vcp_platform.py | 4 ++-- vcp_github/models/vcp_repository.py | 4 ++-- vcp_github/models/vcp_user.py | 2 +- 5 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b8a95bb --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +# generated from manifests external_dependencies +github3.py +markdown diff --git a/vcp_github/models/vcp_host.py b/vcp_github/models/vcp_host.py index e320947..5b3331b 100644 --- a/vcp_github/models/vcp_host.py +++ b/vcp_github/models/vcp_host.py @@ -1,7 +1,7 @@ # Copyright 2026 Dixmit # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import _, api, models +from odoo import api, models from odoo.exceptions import ValidationError @@ -16,4 +16,6 @@ def _check_kind_github(self): limit=1, ) if platforms: - raise ValidationError(_("Only one GitHub Host type is allowed.")) + raise ValidationError( + self.env._("Only one GitHub Host type is allowed.") + ) diff --git a/vcp_github/models/vcp_platform.py b/vcp_github/models/vcp_platform.py index 27b6699..22d95e0 100644 --- a/vcp_github/models/vcp_platform.py +++ b/vcp_github/models/vcp_platform.py @@ -9,7 +9,7 @@ import requests from pytz import UTC -from odoo import _, fields, models +from odoo import fields, models from odoo.exceptions import ValidationError @@ -30,7 +30,7 @@ def _update_information_github(self): clients = self._get_github_clients() if not clients: raise ValidationError( - _( + self.env._( "No github clients configured. " "Please enter at least a Github Personal Access Token. " "You can check more information at " diff --git a/vcp_github/models/vcp_repository.py b/vcp_github/models/vcp_repository.py index 70a98f9..2654c8e 100644 --- a/vcp_github/models/vcp_repository.py +++ b/vcp_github/models/vcp_repository.py @@ -59,7 +59,7 @@ def _update_branches_github(self): reset = fields.Datetime.to_string( datetime.utcfromtimestamp(rate["resources"]["core"]["reset"]) ) - raise ValidationError(self.env._(f"Reset on {reset}")) from e + raise ValidationError(self.env._("Reset on %(reset)s", reset=reset)) from e def _parse_github_pr(self, pr, client): self.ensure_one() @@ -244,4 +244,4 @@ def _update_information_github( reset = fields.Datetime.to_string( datetime.utcfromtimestamp(rate["resources"]["core"]["reset"]) ) - raise ValidationError(self.env._(f"Reset on {reset}")) from e + raise ValidationError(self.env._("Reset on %(reset)s", reset=reset)) from e diff --git a/vcp_github/models/vcp_user.py b/vcp_github/models/vcp_user.py index 8f6d1ae..f395d2c 100644 --- a/vcp_github/models/vcp_user.py +++ b/vcp_github/models/vcp_user.py @@ -46,7 +46,7 @@ def _update_information_github(self): reset = fields.Datetime.to_string( datetime.utcfromtimestamp(rate["resources"]["core"]["reset"]) ) - raise ValidationError(self.env._(f"Reset on {reset}")) from e + raise ValidationError(self.env._("Reset on %(reset)s", reset=reset)) from e except github3.exceptions.NotFoundError: _logger.warning( "The user %s do not exist anymore, inactive it", self.external_id From e6718999419f27b22672734948559fd2d0918db8 Mon Sep 17 00:00:00 2001 From: Bhavesh Heliconia Date: Mon, 29 Jun 2026 11:09:45 +0530 Subject: [PATCH 17/18] [MIG] vcp_github: Migration to 19.0 --- vcp_github/README.rst | 10 +++++----- vcp_github/__manifest__.py | 2 +- vcp_github/static/description/index.html | 6 +++--- vcp_github/tests/test_github.py | 19 ++++++++++++++++++- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/vcp_github/README.rst b/vcp_github/README.rst index 8885bed..ecf860e 100644 --- a/vcp_github/README.rst +++ b/vcp_github/README.rst @@ -21,13 +21,13 @@ Vcp Github :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fversion--control--platform-lightgray.png?logo=github - :target: https://github.com/OCA/version-control-platform/tree/18.0/vcp_github + :target: https://github.com/OCA/version-control-platform/tree/19.0/vcp_github :alt: OCA/version-control-platform .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/version-control-platform-18-0/version-control-platform-18-0-vcp_github + :target: https://translation.odoo-community.org/projects/version-control-platform-19-0/version-control-platform-19-0-vcp_github :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/version-control-platform&target_branch=18.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/version-control-platform&target_branch=19.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -46,7 +46,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -78,6 +78,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -This module is part of the `OCA/version-control-platform `_ project on GitHub. +This module is part of the `OCA/version-control-platform `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/vcp_github/__manifest__.py b/vcp_github/__manifest__.py index 8eddf10..ee41152 100644 --- a/vcp_github/__manifest__.py +++ b/vcp_github/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Vcp Github", "summary": """Integrate Version Control Platform with Github""", - "version": "18.0.1.0.2", + "version": "19.0.1.0.0", "license": "AGPL-3", "author": "Dixmit,Odoo Community Association (OCA)", "website": "https://github.com/OCA/version-control-platform", diff --git a/vcp_github/static/description/index.html b/vcp_github/static/description/index.html index f265d07..5ab8cc7 100644 --- a/vcp_github/static/description/index.html +++ b/vcp_github/static/description/index.html @@ -374,7 +374,7 @@

Vcp Github

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! source digest: sha256:c11ed718a96213c61adaf41d94d05c5ae2965b6a676231d6d4fac3a6ebf3264b !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/version-control-platform Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/version-control-platform Translate me on Weblate Try me on Runboat

This module facilitates the integration between Github and Version Control Platform.

Table of contents

@@ -394,7 +394,7 @@

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -423,7 +423,7 @@

Maintainers

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

-

This module is part of the OCA/version-control-platform project on GitHub.

+

This module is part of the OCA/version-control-platform project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

diff --git a/vcp_github/tests/test_github.py b/vcp_github/tests/test_github.py index e598de7..b467154 100644 --- a/vcp_github/tests/test_github.py +++ b/vcp_github/tests/test_github.py @@ -100,7 +100,7 @@ def test_update_repository(self): "id": 1, "user": {"login": "contributor1"}, "base": {"ref": "main"}, - "head": {"repo": [MagicMock()]}, + "head": {"repo": ["oca"]}, "html_url": "https://github.com/oca/server-tools/pull/1", "state": "closed", "title": "Fix issue", @@ -117,6 +117,23 @@ def test_update_repository(self): "number": 1, } ) + mock_issue_request.id = 1 + mock_issue_request.user.login = "contributor1" + mock_issue_request.base.ref = "main" + mock_issue_request.head.repo = ["oca"] + mock_issue_request.html_url = "https://github.com/oca/server-tools/pull/1" + mock_issue_request.state = "closed" + mock_issue_request.title = "Fix issue" + mock_issue_request.labels = [{"name": "merged 🎉"}] + mock_issue_request.is_merged.return_value = False + mock_issue_request.draft = False + mock_issue_request.number = 1 + mock_issue_request.comments_url = ( + "https://api.github.com/repos/oca/server-tools/issues/1/comments" + ) + mock_issue_request.reviews.return_value.url = ( + "https://api.github.com/repos/oca/server-tools/pulls/1/reviews" + ) mock_login._instance_or_null.return_value = mock_issue_request mock_login.search_issues.return_value = [mock_issue_request] repository.update_information() From 6ff0ccf99037e44fa69b59a6f3b1ba1f803df13b Mon Sep 17 00:00:00 2001 From: Bhavesh Heliconia Date: Mon, 29 Jun 2026 11:13:59 +0530 Subject: [PATCH 18/18] [DON'T MERGE] test-requirements.txt --- test-requirements.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 test-requirements.txt diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..c30a4a4 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,2 @@ +odoo-addon-vcp_management @ git+https://github.com/OCA/version-control-platform.git@refs/pull/11/head#subdirectory=vcp_management +odoo-addon-vcp_git @ git+https://github.com/OCA/version-control-platform.git@refs/pull/12/head#subdirectory=vcp_git