Skip to content
Open
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
12 changes: 7 additions & 5 deletions deepset_cloud_sdk/_service/pipeline_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,11 +398,13 @@ async def _overwrite_pipeline(self, name: str, pipeline_yaml: str) -> Response:
return await self._create_pipeline(name=name, pipeline_yaml=pipeline_yaml)

version_body = version_response.json()
latest_version = version_body["data"][0]
version_id = latest_version["version_id"]
is_draft = latest_version.get("is_draft", False)
versions = version_body["data"]

if is_draft:
# The pipeline exists but may have no saved versions yet (e.g. created but never
# versioned) -- there's then no draft to patch, same as when the latest version
# simply isn't a draft.
if versions and versions[0].get("is_draft", False):
version_id = versions[0]["version_id"]
# Patch existing draft version
logger.debug(f"Patching existing draft version '{version_id}' of pipeline '{name}'.")
return await self._api.patch(
Expand All @@ -412,7 +414,7 @@ async def _overwrite_pipeline(self, name: str, pipeline_yaml: str) -> Response:
)

# Create a new version
logger.debug(f"Latest version '{version_id}' of pipeline '{name}' is not a draft, creating new version.")
logger.debug(f"Pipeline '{name}' has no draft version, creating new version.")
return await self._api.post(
workspace_name=self._workspace_name,
endpoint=f"pipelines/{name}/versions",
Expand Down
46 changes: 46 additions & 0 deletions tests/unit/service/test_pipeline_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,52 @@ async def test_import_pipeline_with_overwrite_true_creates_new_version_when_not_
assert create_version_call.kwargs["endpoint"] == "pipelines/test_pipeline_overwrite/versions"
assert "config_yaml" in create_version_call.kwargs["json"]

@pytest.mark.asyncio
async def test_import_pipeline_with_overwrite_true_creates_new_version_when_no_versions_exist(
self, pipeline_service: PipelineService, index_pipeline: Pipeline, mock_api: AsyncMock
) -> None:
"""Test importing a pipeline with overwrite=True creates a new version when the pipeline has no versions.

A pipeline can exist (GET /versions returns 200) with an empty `data` list -- e.g. it was
created but never versioned. This must not raise an IndexError; it should create a new
version the same way it would if the latest version simply wasn't a draft.
"""
config = PipelineConfig(
name="test_pipeline_overwrite",
inputs=PipelineInputs(query=["retriever.query"]),
outputs=PipelineOutputs(documents="meta_ranker.documents"),
strict_validation=False,
overwrite=True,
)

# Mock successful validation response
validation_response = Mock(spec=Response)
validation_response.status_code = HTTPStatus.NO_CONTENT.value

# Mock versions response: pipeline exists, but has zero saved versions
versions_response = Mock(status_code=HTTPStatus.OK.value)
versions_response.json.return_value = {"data": []}

# Mock successful "create new version" response
new_version_response = Mock(spec=Response)
new_version_response.status_code = HTTPStatus.CREATED.value

# First POST is validation, second POST is "create new version"
mock_api.post.side_effect = [validation_response, new_version_response]
mock_api.get.return_value = versions_response

await pipeline_service.import_async(index_pipeline, config)

# validation + GET versions + POST versions (new version)
assert mock_api.post.call_count == 2
assert mock_api.get.call_count == 1
assert mock_api.patch.call_count == 0

# Check create-version POST call
create_version_call = mock_api.post.call_args_list[1]
assert create_version_call.kwargs["endpoint"] == "pipelines/test_pipeline_overwrite/versions"
assert "config_yaml" in create_version_call.kwargs["json"]

@pytest.mark.asyncio
async def test_import_pipeline_with_overwrite_fallback_to_create(
self, pipeline_service: PipelineService, index_pipeline: Pipeline, mock_api: AsyncMock
Expand Down