diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b457f4d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +# generated from manifests external_dependencies +GitPython diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..26dbef5 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1 @@ +odoo-addon-vcp_management @ git+https://github.com/OCA/version-control-platform.git@refs/pull/11/head#subdirectory=vcp_management diff --git a/vcp_git/README.rst b/vcp_git/README.rst new file mode 100644 index 0000000..8499b1f --- /dev/null +++ b/vcp_git/README.rst @@ -0,0 +1,84 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +======= +Vcp Git +======= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:1ca94913950dfe5023e3cbc4dfea32bd9c2afba8382c77319676bceda2cb69ae + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/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 + :target: https://github.com/OCA/version-control-platform/tree/19.0/vcp_git + :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-19-0/version-control-platform-19-0-vcp_git + :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=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds the necessary code to download using git. + +It should be parent on git possible origins, like github or gitlab. + +**Table of contents** + +.. contents:: + :local: + +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 +------------ + +- `Dixmit `__ + + - Enric Tobella + +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_git/__init__.py b/vcp_git/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/vcp_git/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/vcp_git/__manifest__.py b/vcp_git/__manifest__.py new file mode 100644 index 0000000..4e40191 --- /dev/null +++ b/vcp_git/__manifest__.py @@ -0,0 +1,17 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Vcp Git", + "summary": """Allows to download code from git""", + "version": "19.0.1.0.0", + "license": "AGPL-3", + "author": "Dixmit,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/version-control-platform", + "depends": [ + "vcp_management", + ], + "external_dependencies": { + "python": ["GitPython"], + }, +} diff --git a/vcp_git/i18n/it.po b/vcp_git/i18n/it.po new file mode 100644 index 0000000..c1578ce --- /dev/null +++ b/vcp_git/i18n/it.po @@ -0,0 +1,32 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * vcp_git +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \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_git +#: model:ir.model,name:vcp_git.model_vcp_repository_branch +msgid "Links Branches with Repositories" +msgstr "Collega i branch con i repository" + +#. module: vcp_git +#: model:ir.model,name:vcp_git.model_vcp_repository +msgid "Repository" +msgstr "Repository" + +#. module: vcp_git +#: model:ir.model,name:vcp_git.model_vcp_platform +msgid "VCP Platform" +msgstr "Piattaforma VCP" diff --git a/vcp_git/i18n/vcp_git.pot b/vcp_git/i18n/vcp_git.pot new file mode 100644 index 0000000..45506e9 --- /dev/null +++ b/vcp_git/i18n/vcp_git.pot @@ -0,0 +1,29 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * vcp_git +# +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_git +#: model:ir.model,name:vcp_git.model_vcp_repository_branch +msgid "Links Branches with Repositories" +msgstr "" + +#. module: vcp_git +#: model:ir.model,name:vcp_git.model_vcp_repository +msgid "Repository" +msgstr "" + +#. module: vcp_git +#: model:ir.model,name:vcp_git.model_vcp_platform +msgid "VCP Platform" +msgstr "" diff --git a/vcp_git/models/__init__.py b/vcp_git/models/__init__.py new file mode 100644 index 0000000..102fee0 --- /dev/null +++ b/vcp_git/models/__init__.py @@ -0,0 +1,3 @@ +from . import vcp_repository_branch +from . import vcp_platform +from . import vcp_repository diff --git a/vcp_git/models/vcp_platform.py b/vcp_git/models/vcp_platform.py new file mode 100644 index 0000000..4e25826 --- /dev/null +++ b/vcp_git/models/vcp_platform.py @@ -0,0 +1,14 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +import logging + +from odoo import models + +_logger = logging.getLogger(__name__) + + +class VcpPlatform(models.Model): + _inherit = "vcp.platform" + + def _get_git_url(self, repository): + return getattr(self, f"_get_git_url_{self.kind}")(repository) diff --git a/vcp_git/models/vcp_repository.py b/vcp_git/models/vcp_repository.py new file mode 100644 index 0000000..63d2017 --- /dev/null +++ b/vcp_git/models/vcp_repository.py @@ -0,0 +1,12 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models + + +class VcpRepository(models.Model): + _inherit = "vcp.repository" + + def _get_git_url(self): + self.ensure_one() + return self.platform_id._get_git_url(self) diff --git a/vcp_git/models/vcp_repository_branch.py b/vcp_git/models/vcp_repository_branch.py new file mode 100644 index 0000000..df32146 --- /dev/null +++ b/vcp_git/models/vcp_repository_branch.py @@ -0,0 +1,27 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import git + +from odoo import models + + +class VcpRepositoryBranch(models.Model): + _inherit = "vcp.repository.branch" + + def _download_code_git(self, local_path): + try: + repo = git.Repo(local_path) + for remote in repo.remotes: + if remote.url == self.repository_id._get_git_url(): + remote.fetch(self.branch_id.name) + repo.git.reset("--hard", f"{remote.name}/{self.branch_id.name}") + break + except git.exc.InvalidGitRepositoryError: + # Not cloned yet + repo = git.Repo.clone_from( + self.repository_id._get_git_url(), + local_path, + branch=self.branch_id.name, + depth=1, + ) diff --git a/vcp_git/pyproject.toml b/vcp_git/pyproject.toml new file mode 100644 index 0000000..4231d0c --- /dev/null +++ b/vcp_git/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/vcp_git/readme/CONTRIBUTORS.md b/vcp_git/readme/CONTRIBUTORS.md new file mode 100644 index 0000000..2c066ba --- /dev/null +++ b/vcp_git/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- [Dixmit](https://www.dixmit.com) + - Enric Tobella diff --git a/vcp_git/readme/DESCRIPTION.md b/vcp_git/readme/DESCRIPTION.md new file mode 100644 index 0000000..37884f9 --- /dev/null +++ b/vcp_git/readme/DESCRIPTION.md @@ -0,0 +1,3 @@ +This module adds the necessary code to download using git. + +It should be parent on git possible origins, like github or gitlab. diff --git a/vcp_git/static/description/icon.png b/vcp_git/static/description/icon.png new file mode 100644 index 0000000..3a0328b Binary files /dev/null and b/vcp_git/static/description/icon.png differ diff --git a/vcp_git/static/description/index.html b/vcp_git/static/description/index.html new file mode 100644 index 0000000..c6af789 --- /dev/null +++ b/vcp_git/static/description/index.html @@ -0,0 +1,433 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Vcp Git

+ +

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

+

This module adds the necessary code to download using git.

+

It should be parent on git possible origins, like github or gitlab.

+

Table of contents

+ +
+

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

+ +
+
+

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_git/tests/__init__.py b/vcp_git/tests/__init__.py new file mode 100644 index 0000000..45b614a --- /dev/null +++ b/vcp_git/tests/__init__.py @@ -0,0 +1 @@ +from . import test_vcp_rule diff --git a/vcp_git/tests/test_vcp_rule.py b/vcp_git/tests/test_vcp_rule.py new file mode 100644 index 0000000..1223d9f --- /dev/null +++ b/vcp_git/tests/test_vcp_rule.py @@ -0,0 +1,147 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import os +import tempfile +from unittest.mock import MagicMock, patch + +from odoo.fields import Date + +from odoo.addons.base.tests.common import TransactionCase + + +class TestVcpRules(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.host_type = cls.env["vcp.host.type"].create( + { + "name": "Dummy", + "code": "dummy", + "code_kind": "git", + } + ) + cls.host = cls.env["vcp.host"].create( + { + "name": "Dummy Platform", + "type_id": cls.host_type.id, + } + ) + # be sure some expected values are set otherwise homepage may fail + cls.platform = cls.env["vcp.platform"].create( + { + "name": "oca", + "short_description": "OCA", + "description": "OCA", + "host_id": cls.host.id, + } + ) + cls.repository = cls.env["vcp.repository"].create( + { + "name": "contributors-module", + "description": "OCA/contributors-module", + "platform_id": cls.platform.id, + "from_date": Date.today(), + } + ) + cls.branch = cls.env["vcp.branch"].create( + { + "name": "main", + "platform_id": cls.platform.id, + } + ) + cls.repository_branch = cls.env["vcp.repository.branch"].create( + { + "repository_id": cls.repository.id, + "branch_id": cls.branch.id, + } + ) + cls.rule = cls.env["vcp.rule"].create( + { + "name": "Test Rule", + "rule_type": "cloc", + } + ) + + def setUp(self): + super().setUp() + self._tmp_dir = tempfile.TemporaryDirectory(prefix="vcp-git") + self.env["ir.config_parameter"].sudo().set_param( + "vcp_management.source_code_local_path", self._tmp_dir.name + ) + self.addCleanup(self._tmp_dir.cleanup) + + def test_process_rules(self): + self.platform.rule_ids = self.rule + self.assertFalse(os.path.exists(self.repository_branch.local_path)) + self.assertFalse(self.repository_branch.rule_information_ids) + with ( + patch( + "odoo.addons.vcp_git.models.vcp_platform.VcpPlatform._get_git_url" + ) as mock_git_url, + patch( + "odoo.addons.vcp_git.models.vcp_repository_branch.git.Repo.clone_from" + ) as mock_clone_from, + ): + os.makedirs(self.repository_branch.local_path, exist_ok=True) + with open(f"{self.repository_branch.local_path}/demofile.py", "w") as f: + f.write(""" +print('Hello World') + +# This is a comment + +print('Bye bye world') +""") + self.repository_branch.process_rules() + mock_git_url.assert_called_once() + mock_clone_from.assert_called_once() + self.repository_branch.invalidate_recordset() + self.assertTrue(self.repository_branch.rule_information_ids) + rule_info = self.repository_branch.rule_information_ids.filtered( + lambda x: x.rule_id == self.rule + ) + self.assertEqual(rule_info.scanned_files, 1) + self.assertEqual(rule_info.code_count, 2) + self.assertEqual(rule_info.documentation_count, 1) + self.assertEqual(rule_info.empty_count, 3) + self.assertEqual(rule_info.total_count, 6) + + def test_process_rules_update(self): + self.platform.rule_ids = self.rule + self.assertFalse(os.path.exists(self.repository_branch.local_path)) + self.assertFalse(self.repository_branch.rule_information_ids) + with ( + patch( + "odoo.addons.vcp_git.models.vcp_platform.VcpPlatform._get_git_url" + ) as mock_git_url, + patch( + "odoo.addons.vcp_git.models.vcp_repository_branch.git.Repo" + ) as mock_git_repo, + ): + mock_git_url.return_value = "https://example.com/repo.git" + os.makedirs(self.repository_branch.local_path, exist_ok=True) + with open(f"{self.repository_branch.local_path}/demofile.py", "w") as f: + f.write(""" +print('Hello World') + +# This is a comment + +print('Bye bye world') +""") + + mock_git_repo.return_value.remotes = [ + MagicMock(name="origin", url="https://example.com/repo.git") + ] + self.repository_branch.process_rules() + mock_git_url.assert_called_once() + mock_git_repo.assert_called_once() + self.repository_branch.invalidate_recordset() + self.assertTrue(self.repository_branch.rule_information_ids) + rule_info = self.repository_branch.rule_information_ids.filtered( + lambda x: x.rule_id == self.rule + ) + self.assertEqual(rule_info.scanned_files, 1) + self.assertEqual(rule_info.code_count, 2) + self.assertEqual(rule_info.documentation_count, 1) + self.assertEqual(rule_info.empty_count, 3) + self.assertEqual(rule_info.total_count, 6)