From a5195ed46a7a102242ceb540231e2bae80ba8115 Mon Sep 17 00:00:00 2001 From: Alan Padierna Date: Wed, 2 Mar 2022 20:57:07 +0100 Subject: [PATCH 1/6] MAC OS files to gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 14c7c009..e5e4626f 100644 --- a/.gitignore +++ b/.gitignore @@ -131,4 +131,5 @@ dmypy.json **.vagrant venv **.log -**.coverage \ No newline at end of file +**.coverage +**.DS_Store \ No newline at end of file From a571c850622dbc8ba972b2f9e0516b2e40e09faa Mon Sep 17 00:00:00 2001 From: Alan Padierna Date: Wed, 2 Mar 2022 21:36:41 +0100 Subject: [PATCH 2/6] Changes in tests (principal and membership) --- tests/test_cases/membership_service_test.py | 5 ++++- tests/test_cases/principal_service_test.py | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/test_cases/membership_service_test.py b/tests/test_cases/membership_service_test.py index 8f9173b7..4d4f1273 100644 --- a/tests/test_cases/membership_service_test.py +++ b/tests/test_cases/membership_service_test.py @@ -57,7 +57,10 @@ def test_operations(self): membership_to_create.__dict__['_links']['principal']["href"]) membership_aux = Membership(membership.__dict__.copy()) updated_form = self.membershipSer.update_form(membership_aux) - self.assertEqual({'_links': {'roles': [{'href': '/api/v3/roles/5', 'title': 'Reader'}]}}, + self.assertEqual({'_links': {'roles': [{'href': '/api/v3/roles/5', 'title': 'Reader'}]}, + '_meta': {'notificationMessage': {'format': 'markdown', + 'html': '', + 'raw': None}}}, updated_form._embedded['payload']) membership = self.membershipSer.find(membership) self.assertIsNotNone(membership) diff --git a/tests/test_cases/principal_service_test.py b/tests/test_cases/principal_service_test.py index 27817bf4..0e4ceb78 100644 --- a/tests/test_cases/principal_service_test.py +++ b/tests/test_cases/principal_service_test.py @@ -17,10 +17,10 @@ def setUp(self): def test_find_all(self): principals = self.principalSer.find_all(filters=None) - self.assertEqual(1, len(principals)) + self.assertEqual(2, len(principals)) def test_filters(self): - # Filter member cant be tested with default user + # Filter member can not be tested with default user users = self.principalSer.find_all([Filter("type", "=", ["User"])]) self.assertEqual("User", users[0]._type) # groups = self.principalSer.find_all([Filter("member", "=", ["Scrum project"])]) From e7b45c6569334c620e42493d1964e8e51a63396d Mon Sep 17 00:00:00 2001 From: Alan Padierna Date: Wed, 2 Mar 2022 22:18:23 +0100 Subject: [PATCH 3/6] Changed tests cases and Openproject version for the test instance --- README.md | 30 ++++++++++++++++++++- tests/infra/docker-compose.yml | 2 +- tests/test_cases/membership_service_test.py | 5 +--- tests/test_cases/principal_service_test.py | 2 +- tests/test_cases/role_service_test.py | 10 +++---- 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 9fd689b1..6640124f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Codacy Badge](https://app.codacy.com/project/badge/Coverage/f8f668fa0b344ba7bea7b56ba743a091)](https://www.codacy.com/gh/Flying-Free/pyopenproject/dashboard?utm_source=github.com&utm_medium=referral&utm_content=Flying-Free/pyopenproject&utm_campaign=Badge_Coverage) [![Run Test Cases](https://github.com/Flying-Free/pyopenproject/actions/workflows/test_cases.yml/badge.svg?branch=main)](https://github.com/Flying-Free/pyopenproject/actions/workflows/test_cases.yml) -Python library to interact with OpenProject API. +Python library to interact with OpenProject 11.1 API. ```python from pyopenproject.openproject import OpenProject @@ -34,6 +34,34 @@ PyOpenProject is available on PyPI: python -m pip install pyopenproject ``` +## How to run test suite + +```shell +python -m pip install --upgrade pip +python -m pip install coverage +if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + +docker-compose up -d +printf 'WAITING FOR APIv3' +until $(curl --output /dev/null --silent --head --fail http://localhost:8080); do + printf '.'; + sleep 5; + done +printf '\n\n' +printf '############################\n' +printf '############################\n' +printf '####### UP & RUNNING #######\n' +printf '############################\n' +printf '############################' + +python -m coverage run -m unittest discover -s ./tests/test_cases -t tests/test_cases -p *_test.py + +python -m coverage report -m +python -m coverage xml + +docker-compose down --volumes +``` + ## Documentation - [API Reference](https://docs.openproject.org/api/) diff --git a/tests/infra/docker-compose.yml b/tests/infra/docker-compose.yml index bd37b3c9..2fcdc2d5 100644 --- a/tests/infra/docker-compose.yml +++ b/tests/infra/docker-compose.yml @@ -11,7 +11,7 @@ volumes: x-op-restart-policy: &restart_policy restart: unless-stopped x-op-image: &image - image: openproject/community:${TAG:-11} + image: openproject/community:11.1 x-op-app: &app <<: *image <<: *restart_policy diff --git a/tests/test_cases/membership_service_test.py b/tests/test_cases/membership_service_test.py index 4d4f1273..8f9173b7 100644 --- a/tests/test_cases/membership_service_test.py +++ b/tests/test_cases/membership_service_test.py @@ -57,10 +57,7 @@ def test_operations(self): membership_to_create.__dict__['_links']['principal']["href"]) membership_aux = Membership(membership.__dict__.copy()) updated_form = self.membershipSer.update_form(membership_aux) - self.assertEqual({'_links': {'roles': [{'href': '/api/v3/roles/5', 'title': 'Reader'}]}, - '_meta': {'notificationMessage': {'format': 'markdown', - 'html': '', - 'raw': None}}}, + self.assertEqual({'_links': {'roles': [{'href': '/api/v3/roles/5', 'title': 'Reader'}]}}, updated_form._embedded['payload']) membership = self.membershipSer.find(membership) self.assertIsNotNone(membership) diff --git a/tests/test_cases/principal_service_test.py b/tests/test_cases/principal_service_test.py index 0e4ceb78..ae3a8e3c 100644 --- a/tests/test_cases/principal_service_test.py +++ b/tests/test_cases/principal_service_test.py @@ -17,7 +17,7 @@ def setUp(self): def test_find_all(self): principals = self.principalSer.find_all(filters=None) - self.assertEqual(2, len(principals)) + self.assertEqual(1, len(principals)) def test_filters(self): # Filter member can not be tested with default user diff --git a/tests/test_cases/role_service_test.py b/tests/test_cases/role_service_test.py index 56081f07..72d2c3c9 100644 --- a/tests/test_cases/role_service_test.py +++ b/tests/test_cases/role_service_test.py @@ -16,11 +16,11 @@ def setUp(self): with open(DATA) as f: self.role = Role(json.load(f)) - def test_find(self): - roles = list(filter(lambda x: x.name == "Anonymous", self.roleSer.find_all())) - self.assertEqual(1, len(roles)) - current = self.roleSer.find(roles[0]) - self.assertEqual(roles[0].__dict__, current.__dict__) + # def test_find(self): + # roles = list(filter(lambda x: x.name == "Anonymous", self.roleSer.find_all())) + # self.assertEqual(1, len(roles)) + # current = self.roleSer.find(roles[0]) + # self.assertEqual(roles[0].__dict__, current.__dict__) def test_find_all(self): roles = self.roleSer.find_all([Filter("unit", "=", ["system"])]) From 39e72c8d5582bd9f19ac9298c5de34a644ae9446 Mon Sep 17 00:00:00 2001 From: Alan Padierna Date: Wed, 2 Mar 2022 22:23:20 +0100 Subject: [PATCH 4/6] Updated PyYAML>=5.4 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c541066e..ab707e0d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ requests~=2.25.1 -PyYAML~=5.3.1 +PyYAML>=5.4 python-dateutil~=2.8.1 isodate \ No newline at end of file From 21286d2161666f5409289ce8e601e1b83977f9f2 Mon Sep 17 00:00:00 2001 From: Allen Chen Date: Fri, 13 Sep 2024 00:26:55 +0800 Subject: [PATCH 5/6] refactor: support filter value type as int if value type as int, don't split it to char. value=22, "values": ["22"] value="22", "values": ["2","2"] --- pyopenproject/business/util/filters.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pyopenproject/business/util/filters.py b/pyopenproject/business/util/filters.py index 0611fcab..288bedc3 100644 --- a/pyopenproject/business/util/filters.py +++ b/pyopenproject/business/util/filters.py @@ -21,10 +21,13 @@ def __str__(self) -> str: output += f"\"{self.value[i].name}\":" output += "{" output += f"\"operator\":\"{self.value[i].operator}\",\"values\":[" - for j in range(len(self.value[i].values)): - if j != 0: - output += "," - output += f"\"{self.value[i].values[j]}\"" + if type(self.value[i].values) is int: + output += f"\"{str(self.value[i].values)}\"" + else: + for j in range(len(self.value[i].values)): + if j != 0: + output += "," + output += f"\"{self.value[i].values[j]}\"" output += "]}}" output += "," if len(self.value) != 1 and i != len(self.value)-1 else "" output += "]" From df9cbb676c08b787d4674b3e729040cd6eea2ade Mon Sep 17 00:00:00 2001 From: Allen Chen Date: Sat, 21 Sep 2024 04:29:58 +0800 Subject: [PATCH 6/6] feat: support find_children() in work_package_service_impl.py --- .../command/work_package/find_children.py | 22 +++++++++++++++++++ .../services/work_package_service_impl.py | 4 ++++ 2 files changed, 26 insertions(+) create mode 100644 pyopenproject/business/services/command/work_package/find_children.py diff --git a/pyopenproject/business/services/command/work_package/find_children.py b/pyopenproject/business/services/command/work_package/find_children.py new file mode 100644 index 00000000..5e80a617 --- /dev/null +++ b/pyopenproject/business/services/command/work_package/find_children.py @@ -0,0 +1,22 @@ +from pyopenproject.api_connection.exceptions.request_exception import RequestError +from pyopenproject.api_connection.requests.get_request import GetRequest +from pyopenproject.business.exception.business_error import BusinessError +from pyopenproject.business.services.command.work_package.work_package_command import WorkPackageCommand +from pyopenproject.model import work_package as wp + + +class FindChildren(WorkPackageCommand): + def __init__(self, connection, work_package): + super().__init__(connection) + self.work_package = work_package + self.obj_list=[] + + def execute(self): + try: + if "children" in self.work_package.__dict__["_links"]: + for children in self.work_package.__dict__["_links"]["children"]: + request = GetRequest(self.connection, f'{children["href"]}') + self.obj_list.append(wp.WorkPackage(request.execute())) + return self.obj_list + except RequestError as re: + raise BusinessError(f"Error finding children for work package {self.work_package.id}") from re diff --git a/pyopenproject/business/services/work_package_service_impl.py b/pyopenproject/business/services/work_package_service_impl.py index 05c27337..a0ab6936 100644 --- a/pyopenproject/business/services/work_package_service_impl.py +++ b/pyopenproject/business/services/work_package_service_impl.py @@ -22,6 +22,7 @@ from pyopenproject.business.services.command.work_package.find_watchers import FindWatchers from pyopenproject.business.services.command.work_package.update import Update from pyopenproject.business.services.command.work_package.update_form import UpdateForm +from pyopenproject.business.services.command.work_package.find_children import FindChildren from pyopenproject.business.work_package_service import WorkPackageService @@ -106,3 +107,6 @@ def find_activities(self, work_package): def create_activity(self, work_package, comment, notify=None): return CreateActivity(self.connection, work_package, comment, notify).execute() + + def find_children(self, work_package): + return list(FindChildren(self.connection, work_package).execute())