diff --git a/cmd/workflow/deploy/deploy.go b/cmd/workflow/deploy/deploy.go index ba6c37c6..c7fd8184 100644 --- a/cmd/workflow/deploy/deploy.go +++ b/cmd/workflow/deploy/deploy.go @@ -237,6 +237,9 @@ func (h *handler) Execute(ctx context.Context) error { h.workflowArtifact.WorkflowID, ) if err != nil { + if errors.Is(err, errWorkflowUnchanged) { + return err + } return fmt.Errorf("failed to check if workflow exists: %w", err) } h.existingWorkflowStatus = existingStatus diff --git a/cmd/workflow/deploy/private_registry_test.go b/cmd/workflow/deploy/private_registry_test.go index 7ba1047b..714b2918 100644 --- a/cmd/workflow/deploy/private_registry_test.go +++ b/cmd/workflow/deploy/private_registry_test.go @@ -232,7 +232,7 @@ func TestCheckWorkflowExists_PrivateRegistry(t *testing.T) { wantErr: false, }, { - name: "found workflow with same ID returns error", + name: "found workflow with same ID returns unchanged error", serverStatus: http.StatusOK, response: map[string]any{ "data": map[string]any{ @@ -254,10 +254,10 @@ func TestCheckWorkflowExists_PrivateRegistry(t *testing.T) { }, }, workflowID: "00a2b96d2f06961c3e0cf6fbba5cfa30d3b577026de094e5202d5fc3e3aabb87", - wantExists: false, - wantStatus: nil, + wantExists: true, + wantStatus: uint8Ptr(0), wantErr: true, - errMsg: "workflow with id 00a2b96d2f06961c3e0cf6fbba5cfa30d3b577026de094e5202d5fc3e3aabb87 already exists", + errMsg: "workflow with id 00a2b96d2f06961c3e0cf6fbba5cfa30d3b577026de094e5202d5fc3e3aabb87 is already registered and unchanged; re-deployment skipped: workflow unchanged", }, { name: "not found returns no error and no status", @@ -320,6 +320,9 @@ func TestCheckWorkflowExists_PrivateRegistry(t *testing.T) { if tt.errMsg != "" { assert.Equal(t, tt.errMsg, err.Error()) } + if tt.wantExists { + assert.ErrorIs(t, err, errWorkflowUnchanged) + } } else { require.NoError(t, err) } diff --git a/cmd/workflow/deploy/registry_deploy_strategy.go b/cmd/workflow/deploy/registry_deploy_strategy.go index 434b62de..34a5c431 100644 --- a/cmd/workflow/deploy/registry_deploy_strategy.go +++ b/cmd/workflow/deploy/registry_deploy_strategy.go @@ -11,6 +11,10 @@ import ( // re-running the command). var errDeployHalted = errors.New("deploy halted") +// errWorkflowUnchanged is a sentinel returned by CheckWorkflowExists when a +// registered workflow has the same ID as the artifact being deployed. +var errWorkflowUnchanged = errors.New("workflow unchanged") + // registryDeployStrategy encapsulates target-specific deployment logic. // The orchestrator calls these methods in a fixed sequence with common steps // (artifact upload) between RunPreDeployChecks and Upsert. @@ -22,6 +26,8 @@ type registryDeployStrategy interface { // CheckWorkflowExists returns whether a same-name workflow exists for this // registry target and includes the existing workflow status for updates. + // When the existing workflow ID matches workflowID, exists is true and + // errWorkflowUnchanged is returned to block redeployment of identical artifacts. CheckWorkflowExists(workflowOwner, workflowName, workflowTag, workflowID string) (bool, *uint8, error) // Upsert registers or updates the workflow in the target registry diff --git a/cmd/workflow/deploy/registry_deploy_strategy_onchain.go b/cmd/workflow/deploy/registry_deploy_strategy_onchain.go index ea6f1583..0d1943cd 100644 --- a/cmd/workflow/deploy/registry_deploy_strategy_onchain.go +++ b/cmd/workflow/deploy/registry_deploy_strategy_onchain.go @@ -77,7 +77,8 @@ func (a *onchainRegistryDeployStrategy) CheckWorkflowExists(workflowOwner, workf return false, nil, err } if workflow.WorkflowId == [32]byte(common.Hex2Bytes(workflowID)) { - return false, nil, fmt.Errorf("workflow with id %s already exists", workflowID) + status := workflow.Status + return true, &status, fmt.Errorf("workflow with id %s is already registered and unchanged; re-deployment skipped: %w", workflowID, errWorkflowUnchanged) } if workflow.WorkflowName == workflowName { status := workflow.Status diff --git a/cmd/workflow/deploy/registry_deploy_strategy_private.go b/cmd/workflow/deploy/registry_deploy_strategy_private.go index dc14b21c..dee39315 100644 --- a/cmd/workflow/deploy/registry_deploy_strategy_private.go +++ b/cmd/workflow/deploy/registry_deploy_strategy_private.go @@ -37,7 +37,7 @@ func (a *privateRegistryDeployStrategy) CheckWorkflowExists(_, workflowName, _, workflow, err := a.prc.GetWorkflowByName(workflowName) if err == nil { if workflow.WorkflowID == workflowID { - return false, nil, fmt.Errorf("workflow with id %s already exists", workflowID) + return true, offchainStatusToUint8(workflow.Status), fmt.Errorf("workflow with id %s is already registered and unchanged; re-deployment skipped: %w", workflowID, errWorkflowUnchanged) } return true, offchainStatusToUint8(workflow.Status), nil }