Skip to content

Add missing domain classes, sub-resource methods, and utility APIs to close gap vs Xurrent REST API v1 - #30

Merged
fasteiner merged 6 commits into
Devfrom
copilot/add-missing-domain-classes
May 13, 2026
Merged

Add missing domain classes, sub-resource methods, and utility APIs to close gap vs Xurrent REST API v1#30
fasteiner merged 6 commits into
Devfrom
copilot/add-missing-domain-classes

Conversation

CopilotAI commented Apr 15, 2026

Copy link
Copy Markdown

The Python wrapper was missing ~10 core ITSM resource types, dozens of sub-resource traversal methods on existing classes, and several utility APIs available in the Xurrent REST API v1.

New domain classes (10)

  • Problem — predefined filters, archive/trash/restore, notes/requests/workflows sub-resources
  • ServiceInstance — cis/slas/users sub-resources; referenced widely by other resources
  • Release — archive/trash/restore, workflows/notes sub-resources
  • Project — tasks/phases/workflows/risks/notes sub-resources, archive/trash/restore
  • Contract — CI listing sub-resource
  • KnowledgeArticle — archive/trash/restore, requests/service_instances/translations sub-resources
  • Risk — archive/trash/restore, organizations/projects/services sub-resources
  • ServiceOffering — catalog/portfolio filters
  • SkillPool — enable/disable, members/effort_classes sub-resources
  • ClosureCode — basic CRUD

Sub-resource methods on existing classes (43 new methods)

  • Request: get_attachments, get_knowledge_articles, get_automation_rules, get_satisfaction_feedback, get_tags, get_watches
  • Task: get_notes, add_note, get_approvals, get_cis, get_predecessors, get_successors, get_service_instances, get_automation_rules
  • Workflow: get_notes, add_note, get_automation_rules, get_phases, get_requests, get_problems
  • Person: get_cis, get_addresses, get_contacts, get_permissions, get_ci_coverages, get_sla_coverages, get_service_coverages, get_out_of_office_periods, get_skill_pools
  • Organization: get_addresses, get_contacts, get_contracts, get_risks, get_slas, get_time_allocations
  • Service: get_workflows, get_request_templates, get_risks, get_service_instances, get_slas, get_service_offerings
  • Calendar: get_duration(start, end, time_zone), get_hours, get_holidays
  • Team: get_service_instances
  • Holiday: get_calendars

Utility APIs on XurrentApiHelper (5)

  • search(query, types) — cross-resource full-text search via GET /search
  • bulk_import(data, import_type, import_format) — CSV/TSV bulk import via POST /import
  • list_archive(queryfilter), list_trash(queryfilter) — global archive/trash listings
  • list_audit_lines(queryfilter) — global audit log query

Other

  • __init__.py updated to export all 35 modules
  • 301 unit tests (up from 148); all cross-module references use lazy imports per established convention

CopilotAIand others added 6 commits April 15, 2026 20:33
…jects, contracts, knowledge_articles, risks, service_offerings, skill_pools, closure_codes
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: fasteiner <75947402+fasteiner@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: fasteiner <75947402+fasteiner@users.noreply.github.com>
- Requests: get_attachments, get_knowledge_articles, get_automation_rules,
get_satisfaction_feedback, get_tags, get_watches
- Tasks: get_notes, add_note, get_approvals, get_cis, get_predecessors,
get_successors, get_service_instances, get_automation_rules
- Workflows: get_notes, add_note, get_automation_rules, get_phases,
get_requests, get_problems
- People: get_cis, get_addresses, get_contacts, get_permissions,
get_ci_coverages, get_sla_coverages, get_service_coverages,
get_out_of_office_periods, get_skill_pools
- Organizations: get_addresses, get_contacts, get_contracts, get_risks,
get_slas, get_time_allocations
- Services: get_workflows, get_request_templates, get_risks,
get_service_instances, get_slas, get_service_offerings
- Calendars: get_duration, get_hours, get_holidays
- Teams: get_service_instances
- Holidays: get_calendars
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: fasteiner <75947402+fasteiner@users.noreply.github.com>
…exports
- Add search(), bulk_import(), list_archive(), list_trash(), list_audit_lines() methods to XurrentApiHelper
- Populate __init__.py with exports for all domain classes across all modules
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: fasteiner <75947402+fasteiner@users.noreply.github.com>
…methods
- test_problems.py: Problem CRUD, notes, requests, workflows
- test_service_instances.py: ServiceInstance CRUD, CIs, users
- test_releases.py: Release CRUD, archive/trash/restore, workflows, notes
- test_projects.py: Project CRUD, archive/trash/restore, tasks/phases/workflows/notes
- test_contracts.py: Contract CRUD, CIs
- test_knowledge_articles.py: KnowledgeArticle CRUD, archive/trash/restore, requests/service_instances/translations
- test_risks.py: Risk CRUD, archive/trash/restore, organizations/projects/services
- test_service_offerings.py: ServiceOffering CRUD
- test_skill_pools.py: SkillPool CRUD, enable/disable, members/effort_classes
- test_closure_codes.py: ClosureCode CRUD
- test_new_sub_resources.py: new sub-resource methods on Request, Task, Workflow,
Person, Organization, Service, Calendar, Holiday, Team; core search/bulk_import/
list_archive/list_trash/list_audit_lines utilities
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: fasteiner <75947402+fasteiner@users.noreply.github.com>
@fasteiner
fasteiner marked this pull request as ready for review May 13, 2026 15:01
CopilotAI review requested due to automatic review settings May 13, 2026 15:01
@fasteiner
fasteiner merged commit 94eca1e into DevMay 13, 2026
1 check passed
@fasteiner
fasteiner deleted the copilot/add-missing-domain-classes branch May 13, 2026 15:01

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR closes feature gaps between the Python SDK and Xurrent REST API v1 by adding missing domain resource classes, expanding sub-resource traversal methods on existing resources, and introducing several helper utility endpoints in XurrentApiHelper.

Changes:

  • Added 10 new domain classes (e.g., Problem, Project, Release, Risk, ServiceInstance, ServiceOffering, SkillPool, etc.) with CRUD and relevant sub-resources.
  • Added many new sub-resource instance methods across existing resources (Request, Task, Workflow, Person, Organization, Service, Calendar, Team, Holiday).
  • Added core helper utilities: search, bulk_import, and global archive/trash/audit_lines list APIs; expanded unit test coverage accordingly.

Reviewed changes

Copilot reviewed 33 out of 33 changed files in this pull request and generated 5 comments.

Show a summary per file
FileDescription
tests/unit_tests/test_closure_codes.pyAdds unit tests for new ClosureCode domain class.
tests/unit_tests/test_contracts.pyAdds unit tests for new Contract domain class and CI sub-resource.
tests/unit_tests/test_knowledge_articles.pyAdds unit tests for new KnowledgeArticle class and its sub-resources.
tests/unit_tests/test_new_sub_resources.pyAdds unit tests covering many newly added sub-resource methods and core utilities.
tests/unit_tests/test_problems.pyAdds unit tests for new Problem class and its sub-resources.
tests/unit_tests/test_projects.pyAdds unit tests for new Project class and its sub-resources.
tests/unit_tests/test_releases.pyAdds unit tests for new Release class and its sub-resources.
tests/unit_tests/test_risks.pyAdds unit tests for new Risk class and its sub-resources.
tests/unit_tests/test_service_instances.pyAdds unit tests for new ServiceInstance class and its sub-resources.
tests/unit_tests/test_service_offerings.pyAdds unit tests for new ServiceOffering class.
tests/unit_tests/test_skill_pools.pyAdds unit tests for new SkillPool class and its sub-resources.
src/xurrent/init.pyExports newly added modules/resources from the package root.
src/xurrent/calendars.pyAdds get_duration, get_hours, and get_holidays APIs.
src/xurrent/closure_codes.pyIntroduces new ClosureCode resource wrapper.
src/xurrent/contracts.pyIntroduces new Contract resource wrapper + CI listing sub-resource.
src/xurrent/core.pyAdds search, bulk_import, and global archive/trash/audit listing APIs.
src/xurrent/holidays.pyAdds Holiday.get_calendars() sub-resource traversal.
src/xurrent/knowledge_articles.pyIntroduces new KnowledgeArticle wrapper + sub-resource traversal methods.
src/xurrent/organizations.pyAdds organization sub-resource traversal methods (addresses/contacts/contracts/risks/slas/time_allocations).
src/xurrent/people.pyAdds person sub-resource traversal methods (cis/addresses/contacts/permissions/coverages/ooo/skill_pools).
src/xurrent/problems.pyIntroduces new Problem resource wrapper + notes/requests/workflows sub-resources.
src/xurrent/projects.pyIntroduces new Project resource wrapper + tasks/phases/workflows/risks/notes sub-resources.
src/xurrent/releases.pyIntroduces new Release resource wrapper + workflows/notes sub-resources.
src/xurrent/requests.pyAdds new request sub-resource traversal methods (attachments/knowledge_articles/automation_rules/satisfaction_feedback/tags/watches).
src/xurrent/risks.pyIntroduces new Risk wrapper + organizations/projects/services sub-resources.
src/xurrent/service_instances.pyIntroduces new ServiceInstance wrapper + cis/slas/users sub-resources.
src/xurrent/service_offerings.pyIntroduces new ServiceOffering wrapper and predefined filters/status enum.
src/xurrent/services.pyAdds service sub-resource traversal methods (workflows/templates/risks/instances/slas/offerings).
src/xurrent/skill_pools.pyIntroduces new SkillPool wrapper + members/effort_classes sub-resources + enable/disable.
src/xurrent/tasks.pyAdds task sub-resource traversal methods (notes/approvals/cis/predecessors/successors/service_instances/automation_rules).
src/xurrent/teams.pyAdds team → service_instances traversal method.
src/xurrent/workflows.pyAdds workflow sub-resource traversal methods (notes/phases/requests/problems/automation_rules).
CHANGELOG.mdDocuments newly added resources/methods/utilities.
Comments suppressed due to low confidence (2)

tests/unit_tests/test_new_sub_resources.py:531

  • This test overrides mock_connection.search with a lambda instead of exercising the real XurrentApiHelper.search() implementation, so it doesn't validate library behavior and duplicates coverage already provided by test_search_core. Consider removing it or rewriting it to call the actual method (and assert the expected encoded URL).
def test_search(mock_connection):
mock_connection.api_call.return_value = [{"id": 1, "type": "request"}]
mock_connection.search = lambda query, types=None: mock_connection.api_call(
f"/search?q={query}", "GET"
)
result = mock_connection.search("password reset")
mock_connection.api_call.assert_called_once_with("/search?q=password reset", "GET")
assert result == [{"id": 1, "type": "request"}]

tests/unit_tests/test_new_sub_resources.py:550

  • The search tests currently assert unencoded spaces in the URL (e.g. q=test query). If XurrentApiHelper.search() is fixed to URL-encode query parameters, update this assertion to match the encoded form (or parse the query string and compare decoded values).
def test_search_core():
helper = XurrentApiHelper(
"https://api.example.com", api_key="key", api_account="acct", resolve_user=False
)
helper.api_call = MagicMock(return_value=[{"id": 1}])
result = helper.search("test query")
helper.api_call.assert_called_once_with("/search?q=test query", "GET")
assert result == [{"id": 1}]
def test_search_with_types_core():
helper = XurrentApiHelper(
"https://api.example.com", api_key="key", api_account="acct", resolve_user=False
)
helper.api_call = MagicMock(return_value=[])
helper.search("test query", types=["request", "person"])
helper.api_call.assert_called_once_with("/search?q=test query&types=request,person", "GET")

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadsrc/xurrent/core.py
Comment on lines +391 to +401
def search(self, query: str, types: list = None) -> list:
"""
Perform a cross-resource full-text search.
:param query: Search query string
:param types: Optional list of resource types to search (e.g. ['request', 'person'])
:return: List of search results
"""
uri = f'/search?q={query}'
if types:
uri += '&types=' + ','.join(types)
return self.api_call(uri, 'GET')
Comment on lines +82 to +96
def get_duration(self, start: str, end: str, time_zone: str = None) -> dict:
"""
Calculate the duration between two timestamps according to the calendar.

:param start: Start datetime string (ISO 8601)
:param end: End datetime string (ISO 8601)
:param time_zone: Optional time zone name
:return: Duration data from the API
"""
uri = f'{self._connection_object.base_url}/{self.__resourceUrl__}/{self.id}/duration'
params = f'start={start}&end={end}'
if time_zone:
params += f'&time_zone={time_zone}'
uri += f'?{params}'
return self._connection_object.api_call(uri, 'GET')
Comment on lines +133 to +151
def get_workflows(self, queryfilter: dict = None) -> List:
"""Retrieve workflows for this service instance."""
from .workflows import Workflow
uri = f'{self._connection_object.base_url}/{self.__resourceUrl__}/{self.id}/workflows'
if queryfilter:
uri += '?' + self._connection_object.create_filter_string(queryfilter)
response = self._connection_object.api_call(uri, 'GET')
return [Workflow.from_data(self._connection_object, w) for w in response]

def get_request_templates(self) -> List:
"""Retrieve request templates for this service instance."""
from .request_templates import RequestTemplate
uri = f'{self._connection_object.base_url}/{self.__resourceUrl__}/{self.id}/request_templates'
response = self._connection_object.api_call(uri, 'GET')
return [RequestTemplate.from_data(self._connection_object, rt) for rt in response]

def get_risks(self) -> List:
"""Retrieve risks for this service instance."""
from .risks import Risk
import pytest
import os
import sys
from unittest.mock import MagicMock, patch
Comment on lines +444 to +447
def get_satisfaction_feedback(self) -> List[dict]:
"""Retrieve satisfaction feedback for this request instance."""
uri = f'{self._connection_object.base_url}/{self.__resourceUrl__}/{self.id}/satisfaction_feedback'
return self._connection_object.api_call(uri, 'GET')
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@fasteiner