Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion atlassian/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from .insight import Insight
from .insight import Insight as Assets # used for Insight on-premise
from .assets import AssetsCloud # used for Insight Cloud
from .jira import Jira
from .jira import Jira, JiraCloud, JiraServer, JiraServiceManagement, JiraSoftware, create_jira_cloud
from .marketplace import MarketPlace
from .portfolio import Portfolio
from .service_desk import ServiceDesk
Expand All @@ -36,6 +36,11 @@ def create_confluence(url, *args, api_version=1, **kwargs):
"ConfluenceV2",
"create_confluence",
"Jira",
"JiraServer",
"JiraCloud",
"JiraSoftware",
"JiraServiceManagement",
"create_jira_cloud",
"Bitbucket",
"CloudAdminOrgs",
"CloudAdminUsers",
Expand Down
21 changes: 21 additions & 0 deletions atlassian/jira/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# coding=utf-8
"""Jira API clients split by deployment target.

``Jira`` remains the legacy-compatible Server/Data Center client. Use
``JiraCloud`` for Jira Cloud Core REST v2/v3.
"""

from .jira_cloud import JiraCloud, JiraServiceManagement, JiraSoftware, create_jira_cloud
from .jira_server import Jira as JiraServer

# Preserve ``from atlassian.jira import Jira`` and ``from atlassian import Jira``.
Jira = JiraServer

__all__ = [
"Jira",
"JiraServer",
"JiraCloud",
"JiraSoftware",
"JiraServiceManagement",
"create_jira_cloud",
]
5,563 changes: 5,563 additions & 0 deletions atlassian/jira/core_methods.py

Large diffs are not rendered by default.

104 changes: 104 additions & 0 deletions atlassian/jira/jira_cloud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# coding=utf-8
"""Versioned Jira Cloud clients.

These clients are deliberately additive. ``Jira`` and ``ServiceDesk`` remain
the compatibility clients for Server, Data Center, and existing Cloud users.
"""

from typing import Any, Optional, Union

from ..rest_client import AtlassianRestAPI
from .core_methods import JiraCloudCoreMethods
from .service_management_methods import JiraServiceManagementMethods
from .software_methods import JiraSoftwareMethods


class JiraCloud(JiraCloudCoreMethods, AtlassianRestAPI):
"""Jira Cloud platform (Core) REST API client for version 2 or 3.

Use ``api_version=3`` for new integrations; version 2 is retained for
payload compatibility. The legacy ``Jira`` methods remain in
:class:`JiraServer` and are intentionally not mixed into this client.
"""

SUPPORTED_API_VERSIONS = (2, 3)

def __init__(self, url: str, *args: Any, api_version: Union[str, int] = 3, **kwargs: Any):
api_version = int(api_version)
if api_version not in self.SUPPORTED_API_VERSIONS:
raise ValueError("Jira Cloud Core api_version must be 2 or 3")
kwargs["api_version"] = api_version
kwargs["cloud"] = True
super(JiraCloud, self).__init__(url, *args, **kwargs)

def endpoint(self, resource: str, api_version: Optional[Union[str, int]] = None) -> str:
"""Return a Core REST endpoint path without issuing a request."""
version = self.api_version if api_version is None else int(api_version)
if version not in self.SUPPORTED_API_VERSIONS:
raise ValueError("Jira Cloud Core api_version must be 2 or 3")
return self.resource_url(resource, api_root="rest/api", api_version=version)


class JiraSoftware(JiraSoftwareMethods, AtlassianRestAPI):
"""Jira Software Cloud REST APIs.

``endpoint`` covers documented Agile, Software, DevInfo, deployments,
builds, feature-flags, remote-links, security, operations, and DevOps
component roots. Call ``get``, ``post``, ``put``, or ``delete`` with its
returned path.
"""

API_VERSIONS = {
"agile": "1.0",
"software": "1.0",
"devinfo": "0.10",
"featureflags": "0.1",
"deployments": "0.1",
"builds": "0.1",
"remotelinks": "1.0",
"security": "1.0",
"operations": "1.0",
"devopscomponents": "1.0",
}

def __init__(self, url: str, *args: Any, **kwargs: Any):
# These APIs do not share one root/version, so endpoint() supplies it.
kwargs["cloud"] = True
kwargs.setdefault("api_root", "rest")
kwargs.setdefault("api_version", None)
super(JiraSoftware, self).__init__(url, *args, **kwargs)

def endpoint(self, api: str, resource: str = "", api_version: Optional[str] = None) -> str:
"""Build a Jira Software Cloud endpoint path.

``api`` is one of :attr:`API_VERSIONS`; ``resource`` is the documented
portion following its version (for example ``"board/42/sprint"``).
"""
if api not in self.API_VERSIONS:
supported = ", ".join(sorted(self.API_VERSIONS))
raise ValueError(f"Unsupported Jira Software API '{api}'. Use one of: {supported}")
version = api_version or self.API_VERSIONS[api]
return self.resource_url(resource, api_root=f"rest/{api}", api_version=version)


class JiraServiceManagement(JiraServiceManagementMethods, AtlassianRestAPI):
"""Jira Service Management Cloud public REST API client.

This client is independent from the legacy ``ServiceDesk`` surface, which
remains available unchanged for existing integrations.
"""

API_VERSION = "1"

def __init__(self, url: str, *args: Any, **kwargs: Any):
kwargs["cloud"] = True
super(JiraServiceManagement, self).__init__(url, *args, **kwargs)

def endpoint(self, resource: str = "") -> str:
"""Return a JSM public REST endpoint path without issuing a request."""
return self.url_joiner("rest/servicedeskapi", resource)


def create_jira_cloud(url: str, *args: Any, api_version: Union[str, int] = 3, **kwargs: Any) -> JiraCloud:
"""Create a versioned Jira Cloud Core client (v3 by default)."""
return JiraCloud(url, *args, api_version=api_version, **kwargs)
7 changes: 4 additions & 3 deletions atlassian/jira.py → atlassian/jira/jira_server.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# coding=utf-8
# Jira Server/Data Center compatibility implementation.
import logging
import os
import re
Expand All @@ -14,9 +15,9 @@
from typing import Literal # Python 3.8+
else:
from typing_extensions import Literal # Python <=3.7
from .errors import ApiNotFoundError, ApiPermissionError
from .rest_client import AtlassianRestAPI
from .typehints import T_id, T_resp_json, copy_type
from ..errors import ApiNotFoundError, ApiPermissionError
from ..rest_client import AtlassianRestAPI
from ..typehints import T_id, T_resp_json, copy_type

log = logging.getLogger(__name__)

Expand Down
Loading
Loading