Skip to content

Commit d6e82da

Browse files
Merge pull request #925 from cbusillo/fix/generic-post-deploy-failure-evidence
Preserve generic post-deploy failure evidence
2 parents fc05365 + 54e7e7d commit d6e82da

2 files changed

Lines changed: 117 additions & 28 deletions

File tree

control_plane/workflows/generic_web_deploy.py

Lines changed: 60 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -366,22 +366,21 @@ def execute_generic_web_deploy(
366366
)
367367
deploy_completed = True
368368
if post_deploy_executor is not None:
369-
post_deploy_update = _terminal_post_deploy_update(
370-
post_deploy_executor(
371-
control_plane_root,
372-
record_store,
373-
GenericWebPostDeployContext(
374-
product=resolved_profile.product,
375-
context=resolved_lane.context,
376-
instance=resolved_lane.instance,
377-
deployment_record_id=record_id,
378-
target_name=resolved_target.target_name,
379-
target_type=resolved_target.target_type,
380-
target_id=resolved_target.target_id,
381-
artifact_id=ship_request.artifact_id,
382-
source_git_ref=ship_request.source_git_ref,
383-
),
384-
)
369+
post_deploy_update = _run_post_deploy_extension(
370+
control_plane_root=control_plane_root,
371+
record_store=record_store,
372+
context=GenericWebPostDeployContext(
373+
product=resolved_profile.product,
374+
context=resolved_lane.context,
375+
instance=resolved_lane.instance,
376+
deployment_record_id=record_id,
377+
target_name=resolved_target.target_name,
378+
target_type=resolved_target.target_type,
379+
target_id=resolved_target.target_id,
380+
artifact_id=ship_request.artifact_id,
381+
source_git_ref=ship_request.source_git_ref,
382+
),
383+
post_deploy_executor=post_deploy_executor,
385384
)
386385
if post_deploy_update.status == "fail":
387386
raise click.ClickException(
@@ -396,18 +395,36 @@ def execute_generic_web_deploy(
396395
status="fail",
397396
detail=str(exc),
398397
)
399-
record_store.write_deployment_record(
400-
build_deployment_record(
401-
request=ship_request,
402-
record_id=record_id,
403-
deployment_id="control-plane-dokploy",
404-
deployment_status=deployment_status,
405-
started_at=started_at,
406-
finished_at=finished_at,
407-
resolved_target=resolved_target,
408-
post_deploy_update=post_deploy_update,
398+
runtime_identity = (
399+
_build_runtime_identity(
400+
profile=resolved_profile,
401+
lane=resolved_lane,
402+
ship_request=ship_request,
403+
deployment_record_id=record_id,
404+
deployed_at=finished_at,
409405
)
406+
if deploy_completed
407+
else None
410408
)
409+
deployment_record = build_deployment_record(
410+
request=ship_request,
411+
record_id=record_id,
412+
deployment_id="control-plane-dokploy",
413+
deployment_status=deployment_status,
414+
started_at=started_at,
415+
finished_at=finished_at,
416+
resolved_target=resolved_target,
417+
post_deploy_update=post_deploy_update,
418+
runtime_identity=runtime_identity,
419+
)
420+
record_store.write_deployment_record(deployment_record)
421+
if deploy_completed:
422+
record_store.write_environment_inventory(
423+
build_environment_inventory(
424+
deployment_record=deployment_record,
425+
updated_at=finished_at,
426+
)
427+
)
411428
return GenericWebDeployResult(
412429
deployment_record_id=record_id,
413430
deploy_status=deployment_status,
@@ -479,3 +496,20 @@ def _terminal_post_deploy_update(
479496
"Generic web post-deploy extensions must return terminal evidence."
480497
)
481498
return post_deploy_update
499+
500+
501+
def _run_post_deploy_extension(
502+
*,
503+
control_plane_root: Path,
504+
record_store: GenericWebDeployStore,
505+
context: GenericWebPostDeployContext,
506+
post_deploy_executor: GenericWebPostDeployExecutor,
507+
) -> PostDeployUpdateEvidence:
508+
try:
509+
return _terminal_post_deploy_update(
510+
post_deploy_executor(control_plane_root, record_store, context)
511+
)
512+
except click.ClickException:
513+
raise
514+
except Exception as exc:
515+
raise click.ClickException(str(exc)) from exc

tests/test_generic_web_deploy.py

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,60 @@ def post_deploy(
268268
self.assertEqual(result.error_message, "post deploy failed")
269269
self.assertEqual(store.deployments[0].deploy.status, "pass")
270270
self.assertEqual(store.deployments[0].post_deploy_update.status, "fail")
271-
self.assertEqual(store.inventories, [])
271+
self.assertIsNotNone(store.deployments[0].runtime_identity)
272+
self.assertEqual(len(store.inventories), 1)
273+
self.assertEqual(store.inventories[0].post_deploy_update.status, "fail")
274+
self.assertEqual(
275+
store.inventories[0].deployment_record_id,
276+
store.deployments[0].record_id,
277+
)
278+
279+
def test_execute_generic_web_deploy_records_unexpected_post_deploy_exception(
280+
self,
281+
) -> None:
282+
store = _GenericWebDeployStore(_profile())
283+
284+
def post_deploy(
285+
_root: Path,
286+
_store: GenericWebDeployStore,
287+
_context: GenericWebPostDeployContext,
288+
) -> PostDeployUpdateEvidence:
289+
raise RuntimeError("unexpected post deploy failure")
290+
291+
with (
292+
patch(
293+
"control_plane.workflows.generic_web_deploy.control_plane_dokploy.read_control_plane_dokploy_source_of_truth",
294+
return_value=_source_of_truth(),
295+
),
296+
patch(
297+
"control_plane.workflows.generic_web_deploy.control_plane_runtime_environments.resolve_runtime_environment_values",
298+
return_value={},
299+
),
300+
patch(
301+
"control_plane.workflows.generic_web_deploy.control_plane_dokploy.read_dokploy_config",
302+
return_value=("https://dokploy.example", "token"),
303+
),
304+
patch("control_plane.workflows.generic_web_deploy.execute_dokploy_artifact_deploy"),
305+
):
306+
result = execute_generic_web_deploy(
307+
control_plane_root=Path("."),
308+
record_store=store,
309+
request=_request(),
310+
post_deploy_executor=post_deploy,
311+
)
312+
313+
self.assertEqual(result.deploy_status, "pass")
314+
self.assertEqual(result.post_deploy_status, "fail")
315+
self.assertEqual(result.error_message, "unexpected post deploy failure")
316+
self.assertEqual(store.deployments[0].deploy.status, "pass")
317+
self.assertEqual(store.deployments[0].post_deploy_update.status, "fail")
318+
self.assertEqual(
319+
store.deployments[0].post_deploy_update.detail,
320+
"unexpected post deploy failure",
321+
)
322+
self.assertIsNotNone(store.deployments[0].runtime_identity)
323+
self.assertEqual(len(store.inventories), 1)
324+
self.assertEqual(store.inventories[0].post_deploy_update.status, "fail")
272325

273326
def test_execute_generic_web_deploy_treats_returned_post_deploy_failure_as_failed_extension(
274327
self,
@@ -314,7 +367,9 @@ def post_deploy(
314367
self.assertEqual(store.deployments[0].deploy.status, "pass")
315368
self.assertEqual(store.deployments[0].post_deploy_update.status, "fail")
316369
self.assertEqual(store.deployments[0].post_deploy_update.detail, "returned failure")
317-
self.assertEqual(store.inventories, [])
370+
self.assertIsNotNone(store.deployments[0].runtime_identity)
371+
self.assertEqual(len(store.inventories), 1)
372+
self.assertEqual(store.inventories[0].post_deploy_update.status, "fail")
318373

319374
def test_execute_generic_web_deploy_uses_qualified_bare_tag(self) -> None:
320375
store = _GenericWebDeployStore(_profile())

0 commit comments

Comments
 (0)