v0.2.2: BUILD_FAILED pull failure aborts redeploy with clear message
Remove contextlib.suppress from the image pull step in the BUILD_FAILED redeploy path. A failed pull (e.g. non-existent tag) now immediately returns an actionable error pointing to update_image_tag instead of silently continuing and starting the project with stale/missing image. Also bumps version 0.2.1 → 0.2.2 and adds CHANGELOG entry. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,14 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [0.2.2] - 2026-04-21
|
||||
|
||||
### Fixed
|
||||
|
||||
- `redeploy_project` (BUILD_FAILED): Pull errors are no longer silently suppressed.
|
||||
If the image pull fails (e.g. the tag in compose.yaml does not exist on the registry),
|
||||
redeploy aborts immediately with a clear message pointing to `update_image_tag`.
|
||||
|
||||
## [0.2.1] - 2026-04-21
|
||||
|
||||
### Fixed
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "mcp-synology-container"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
description = "MCP server for Synology Container Manager"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
|
||||
@@ -167,8 +167,15 @@ def register_projects(mcp: FastMCP, config: AppConfig, client: DsmClient) -> Non
|
||||
await client.request("SYNO.Docker.Project", "stop", params={"id": project_id})
|
||||
results.append(" Build stopped.")
|
||||
results.append("Step 2/4: Pulling updated images...")
|
||||
with contextlib.suppress(Exception):
|
||||
try:
|
||||
await client.request("SYNO.Docker.Image", "pull", params={"id": project_id})
|
||||
except Exception as pull_err:
|
||||
results.append(f" Pull failed: {pull_err}")
|
||||
results.append(
|
||||
"Aborted: image pull failed — the image tag in compose.yaml may not exist. "
|
||||
"Fix the tag with update_image_tag, then retry redeploy_project."
|
||||
)
|
||||
return "\n".join(results)
|
||||
results.append(" Images pulled.")
|
||||
results.append("Step 3/4: Starting project...")
|
||||
await client.request("SYNO.Docker.Project", "start", params={"id": project_id})
|
||||
|
||||
@@ -286,13 +286,13 @@ async def test_redeploy_build_failed_project():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_redeploy_build_failed_stop_error_nonfatal():
|
||||
"""BUILD_FAILED: stop/pull failures must not abort the redeploy."""
|
||||
"""BUILD_FAILED: stop failure is non-fatal and must not abort the redeploy."""
|
||||
from mcp_synology_container.dsm_client import SynologyError
|
||||
|
||||
client, _ = make_stateful_redeploy_mock(
|
||||
"BUILD_FAILED",
|
||||
stop_raises=SynologyError("already stopped", code=2101),
|
||||
pull_raises=SynologyError("pull failed", code=2102),
|
||||
pull_raises=None, # pull succeeds
|
||||
)
|
||||
tools = make_projects_tools(client)
|
||||
|
||||
@@ -302,6 +302,29 @@ async def test_redeploy_build_failed_stop_error_nonfatal():
|
||||
assert "redeployed successfully" in result
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_redeploy_build_failed_pull_error_aborts():
|
||||
"""BUILD_FAILED: pull failure must abort redeploy with a clear message."""
|
||||
from mcp_synology_container.dsm_client import SynologyError
|
||||
|
||||
client, calls = make_stateful_redeploy_mock(
|
||||
"BUILD_FAILED",
|
||||
stop_raises=None,
|
||||
pull_raises=SynologyError("image not found", code=114),
|
||||
)
|
||||
tools = make_projects_tools(client)
|
||||
|
||||
with patch("mcp_synology_container.modules.projects.asyncio.sleep"):
|
||||
result = await tools["redeploy_project"]("myapp", confirmed=True)
|
||||
|
||||
assert "redeployed successfully" not in result
|
||||
assert "Aborted" in result or "pull failed" in result.lower()
|
||||
assert "compose.yaml" in result or "update_image_tag" in result
|
||||
# start must NOT have been called after a pull failure
|
||||
methods = [m for _, m in calls]
|
||||
assert "start" not in methods
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_redeploy_poll_timeout():
|
||||
"""If project never reaches RUNNING after start, a warning is emitted."""
|
||||
|
||||
Reference in New Issue
Block a user