From 3a579822296090580245513c8d24781836c14b7c Mon Sep 17 00:00:00 2001 From: Balaji Venkatesan Date: Wed, 22 Jul 2026 14:56:36 +0530 Subject: [PATCH 1/2] Updated --- digitalai/release/integration/base_task.py | 30 ++++++++------------- tests/release/integration/test_base_task.py | 11 +++++--- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/digitalai/release/integration/base_task.py b/digitalai/release/integration/base_task.py index 8164774..d75eda9 100644 --- a/digitalai/release/integration/base_task.py +++ b/digitalai/release/integration/base_task.py @@ -178,7 +178,8 @@ def get_release_api_client(self, :param server_address: Optional Release server URL. Defaults to the task's server URL. :param username: Optional username. Defaults to the task user's username. - :param password: Optional password. Defaults to the task user's password. + :param password: Optional password. Defaults to the task user's password. When a + password is available but no username is, it is treated as a personal access token. :param personal_access_token: Optional personal access token for authentication. :param timeout: Optional default timeout (in seconds) applied to every request. Accepts a single float or a (connect, read) tuple. Can be overridden per call. @@ -186,38 +187,29 @@ def get_release_api_client(self, """ task_user = self.get_task_user() server_address = server_address or self.get_release_server_url() + username = username or (task_user and task_user.username) + password = password or (task_user and task_user.password) + + # A password without a username is treated as a personal access token. + token = personal_access_token or (None if username else password) - if personal_access_token: + if token: if not server_address: raise ValueError( "Cannot connect to Release API without server URL. " "Make sure that the release server URL is available." ) return ReleaseAPIClient(server_address, - personal_access_token=personal_access_token, + personal_access_token=token, timeout=timeout, **kwargs) - username = username or (task_user and task_user.username) - password = password or (task_user and task_user.password) - self._validate_api_credentials(server_address, username, password) - return ReleaseAPIClient(server_address, username, password, timeout=timeout, **kwargs) - - def _validate_api_credentials(self, server_address: str = None, - username: str = None, password: str = None) -> None: - """ - Validates that the necessary credentials are available for connecting to the Release API. - """ - task_user = self.get_task_user() - if not all([ - server_address or self.get_release_server_url(), - username or (task_user and task_user.username), - password or (task_user and task_user.password) - ]): + if not all([server_address, username, password]): raise ValueError( "Cannot connect to Release API without server URL, username, or password. " "Make sure that the 'Run as user' property is set on the release." ) + return ReleaseAPIClient(server_address, username, password, timeout=timeout, **kwargs) diff --git a/tests/release/integration/test_base_task.py b/tests/release/integration/test_base_task.py index a2b5dd8..f75987f 100644 --- a/tests/release/integration/test_base_task.py +++ b/tests/release/integration/test_base_task.py @@ -118,7 +118,7 @@ def test_get_task_user_returns_none_without_release_context(self): task = self._task() self.assertIsNone(task.get_task_user()) - def test_validate_api_credentials_raises_without_user(self): + def test_get_release_api_client_raises_without_task_user(self): task = self._task() task.release_server_url = "http://localhost:5516" with self.assertRaises(ValueError): @@ -158,10 +158,13 @@ def test_get_release_api_client_raises_when_password_missing(self): with self.assertRaises(ValueError): task.get_release_api_client() - def test_get_release_api_client_raises_when_username_missing(self): + def test_get_release_api_client_uses_password_as_token_when_username_missing(self): task = self._task(None, "secret") - with self.assertRaises(ValueError): - task.get_release_api_client() + with mock.patch("digitalai.release.integration.base_task.ReleaseAPIClient") as fake_client: + client = task.get_release_api_client() + fake_client.assert_called_once_with( + self.SERVER_URL, personal_access_token="secret", timeout=None) + self.assertIs(client, fake_client.return_value) def test_get_release_api_client_raises_when_credentials_blank(self): task = self._task("", "") From b8ed79650f3fd62711aafc76afbb8c9cb24fdc46 Mon Sep 17 00:00:00 2001 From: Balaji Venkatesan Date: Wed, 22 Jul 2026 16:02:39 +0530 Subject: [PATCH 2/2] updated version --- README.md | 2 +- pyproject.toml | 4 ++-- uv.lock | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 622c12c..e6eeb3b 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ class ShowVersion(ApiBaseTask): ## Changelog -### Version 26.3.0 +### Version 26.3.1 #### 🚀 Features diff --git a/pyproject.toml b/pyproject.toml index 7979c5d..01d5b3c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "digitalai_release_sdk" -version = "26.3.0" +version = "26.3.1" description = "Digital.ai Release SDK" readme = "README.md" license = "MIT" @@ -19,7 +19,7 @@ classifiers = [ "Operating System :: OS Independent" ] dependencies = [ - "digitalai-release-api-client==26.3.0", + "digitalai-release-api-client==26.3.1", "dataclasses-json>=0.6.7, <1.0.0", "pycryptodomex>=3.23.0, <4.0.0", "python-dateutil>=2.9.0, <3.0.0", diff --git a/uv.lock b/uv.lock index fbdf82e..a8d2ece 100644 --- a/uv.lock +++ b/uv.lock @@ -149,20 +149,20 @@ wheels = [ [[package]] name = "digitalai-release-api-client" -version = "26.3.0b5" +version = "26.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b1/09/b64a2257ddc36d7c4dae1533f92eb63e95e86b32e7362fd21a2c153aede4/digitalai_release_api_client-26.3.0b5.tar.gz", hash = "sha256:7f8c8058e6694a2210b29f394c93250738236c84b20ab7d77edb56b1e65604f9", size = 39161 } +sdist = { url = "https://files.pythonhosted.org/packages/3f/b1/81bcf5fc1d6cb5c74aff2294b1f2ca0243c2c5b7290c95a13a1a7d599b01/digitalai_release_api_client-26.3.1.tar.gz", hash = "sha256:3ed7500fa45634f1cb29eb007f4567709ca786c263afba55c7fd6dcdf591073c", size = 42589 } wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/d5/9f2d1cc01207108125b9f10d2af1c5c476385fa2998ac433e79e5990c3f8/digitalai_release_api_client-26.3.0b5-py3-none-any.whl", hash = "sha256:76ac7caa97adc15bc9cd54b03222bde10d4f36d6e4dedb3280c4ba05719c6cc7", size = 67601 }, + { url = "https://files.pythonhosted.org/packages/78/fd/c7a14e9da74642e0414371c38883805557d444511411d3b74a127ce5cac1/digitalai_release_api_client-26.3.1-py3-none-any.whl", hash = "sha256:ceb41222fd90cdc05bd3fec5731ed0fe476bb9402084a2d488f306a44c7e7702", size = 73844 }, ] [[package]] name = "digitalai-release-sdk" -version = "26.3.0b5" +version = "26.3.1" source = { editable = "." } dependencies = [ { name = "dataclasses-json" }, @@ -181,7 +181,7 @@ dev = [ [package.metadata] requires-dist = [ { name = "dataclasses-json", specifier = ">=0.6.7,<1.0.0" }, - { name = "digitalai-release-api-client", specifier = "==26.3.0b5" }, + { name = "digitalai-release-api-client", specifier = "==26.3.1" }, { name = "kubernetes", specifier = ">=35.0.0,<36.0.0" }, { name = "pycryptodomex", specifier = ">=3.23.0,<4.0.0" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0.0" },