diff --git a/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/engine/WorkflowEngineImpl.kt b/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/engine/WorkflowEngineImpl.kt index 8068842823..ead0f1ebf3 100644 --- a/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/engine/WorkflowEngineImpl.kt +++ b/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/engine/WorkflowEngineImpl.kt @@ -125,7 +125,8 @@ class WorkflowEngineImpl( instance.errorNode( node.id, throwable = null, - message = result.message + message = result.message, + output = result.output, ) ) stopWorkflow(workflowInstanceId) @@ -154,7 +155,7 @@ class WorkflowEngineImpl( } } catch (any: Throwable) { // Stores the node error status - workflowInstanceStore.store(instance.errorNode(node.id, throwable = any, message = null)) + workflowInstanceStore.store(instance.errorNode(node.id, throwable = any, message = null, output = null)) // Stopping the workflow stopWorkflow(workflowInstanceId) } diff --git a/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/engine/WorkflowInstance.kt b/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/engine/WorkflowInstance.kt index 8f6ff63877..051690d4d9 100644 --- a/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/engine/WorkflowInstance.kt +++ b/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/engine/WorkflowInstance.kt @@ -84,8 +84,8 @@ data class WorkflowInstance( node.success(output) } - fun errorNode(nodeId: String, throwable: Throwable?, message: String?) = updateNode(nodeId) { node -> - node.error(throwable, message) + fun errorNode(nodeId: String, throwable: Throwable?, message: String?, output: JsonNode?) = updateNode(nodeId) { node -> + node.error(throwable, message, output) } fun progressNode(nodeId: String, output: JsonNode) = updateNode(nodeId) { node -> diff --git a/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/engine/WorkflowInstanceNode.kt b/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/engine/WorkflowInstanceNode.kt index 0a8f0d4a84..5a22e09b53 100644 --- a/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/engine/WorkflowInstanceNode.kt +++ b/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/engine/WorkflowInstanceNode.kt @@ -65,12 +65,12 @@ data class WorkflowInstanceNode( error = null, ) - fun error(throwable: Throwable?, message: String?, time: LocalDateTime = Time.now) = WorkflowInstanceNode( + fun error(throwable: Throwable?, message: String?, output: JsonNode?, time: LocalDateTime = Time.now) = WorkflowInstanceNode( id = id, status = WorkflowInstanceNodeStatus.ERROR, startTime = startTime, endTime = time, - output = null, + output = output ?: this.output, error = message ?: throwable?.message ?: "Unknown error in $id node", ) } diff --git a/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/execution/WorkflowNodeExecutorResult.kt b/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/execution/WorkflowNodeExecutorResult.kt index 334f1a17ba..ddd2d98db2 100644 --- a/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/execution/WorkflowNodeExecutorResult.kt +++ b/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/execution/WorkflowNodeExecutorResult.kt @@ -9,10 +9,10 @@ data class WorkflowNodeExecutorResult( ) { companion object { - fun error(message: String) = WorkflowNodeExecutorResult( + fun error(message: String, output: JsonNode?) = WorkflowNodeExecutorResult( type = WorkflowNodeExecutorResultType.ERROR, message = message, - output = null, + output = output, ) fun success(output: JsonNode?) = WorkflowNodeExecutorResult( diff --git a/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/notifications/WorkflowNotificationChannelNodeExecutor.kt b/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/notifications/WorkflowNotificationChannelNodeExecutor.kt index f0ba7acf60..e5690ed4da 100644 --- a/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/notifications/WorkflowNotificationChannelNodeExecutor.kt +++ b/ontrack-extension-workflows/src/main/java/net/nemerosa/ontrack/extension/workflows/notifications/WorkflowNotificationChannelNodeExecutor.kt @@ -86,14 +86,14 @@ class WorkflowNotificationChannelNodeExecutor( return if (result != null) { when (result.type) { NotificationResultType.OK -> WorkflowNodeExecutorResult.success(result.output?.asJson()) - NotificationResultType.ONGOING -> WorkflowNodeExecutorResult.error("Notification is still ongoing") - NotificationResultType.NOT_CONFIGURED -> WorkflowNodeExecutorResult.error("Notification is not configured") - NotificationResultType.INVALID_CONFIGURATION -> WorkflowNodeExecutorResult.error("Notification configuration is invalid") - NotificationResultType.DISABLED -> WorkflowNodeExecutorResult.error("Notification is disabled") - NotificationResultType.ERROR -> WorkflowNodeExecutorResult.error(result.message ?: "Unknown error") + NotificationResultType.ONGOING -> WorkflowNodeExecutorResult.error("Notification is still ongoing", result.output?.asJson()) + NotificationResultType.NOT_CONFIGURED -> WorkflowNodeExecutorResult.error("Notification is not configured", result.output?.asJson()) + NotificationResultType.INVALID_CONFIGURATION -> WorkflowNodeExecutorResult.error("Notification configuration is invalid", result.output?.asJson()) + NotificationResultType.DISABLED -> WorkflowNodeExecutorResult.error("Notification is disabled", result.output?.asJson()) + NotificationResultType.ERROR -> WorkflowNodeExecutorResult.error(result.message ?: "Unknown error", result.output?.asJson()) } } else { - WorkflowNodeExecutorResult.error("Notification did not return any result") + WorkflowNodeExecutorResult.error("Notification did not return any result", null) } } } \ No newline at end of file diff --git a/ontrack-kdsl-acceptance/src/test/java/net/nemerosa/ontrack/kdsl/acceptance/tests/workflows/ACCDSLWorkflowNotificationChannel.kt b/ontrack-kdsl-acceptance/src/test/java/net/nemerosa/ontrack/kdsl/acceptance/tests/workflows/ACCDSLWorkflowNotificationChannel.kt index 525101ec6a..a80a368c86 100644 --- a/ontrack-kdsl-acceptance/src/test/java/net/nemerosa/ontrack/kdsl/acceptance/tests/workflows/ACCDSLWorkflowNotificationChannel.kt +++ b/ontrack-kdsl-acceptance/src/test/java/net/nemerosa/ontrack/kdsl/acceptance/tests/workflows/ACCDSLWorkflowNotificationChannel.kt @@ -95,6 +95,88 @@ class ACCDSLWorkflowNotificationChannel : AbstractACCDSLWorkflowsTestSupport() { } } + @Test + fun `Workflow node must still contain the build URL in its output when the remote job fails`() { + // Job to call + val job = uid("job_") + // Jenkins configuration + val jenkinsConfName = uid("j_") + ontrack.configurations.jenkins.create( + JenkinsConfiguration( + name = jenkinsConfName, + url = "any", + user = "any", + password = "any", + ) + ) + // Defining a workflow + val workflowName = uid("w-") + val yaml = """ + name: $workflowName + nodes: + - id: start + executorId: notification + data: + channel: mock-jenkins + channelConfig: + config: $jenkinsConfName + job: /mock/$job + callMode: SYNC + parameters: + - name: result + value: FAILURE + - name: waiting + value: 1000 + """.trimIndent() + + project { + // Subscribe to new branches + subscribe( + name = "Test", + channel = "workflow", + channelConfig = mapOf( + "workflow" to WorkflowTestSupport.yamlWorkflowToJson(yaml) + ), + keywords = null, + events = listOf( + "new_branch", + ), + ) + // Creating a branch to trigger the workflow + branch {} + + // Gets the workflow instance ID from the output of the notification + + + waitUntil( + task = "Getting the workflow instance id", + timeout = 30_000L, + interval = 500L, + ) { + val instanceId = getWorkflowInstanceId() + instanceId.isNullOrBlank().not() + } + + // Getting the instance ID + val instanceId = getWorkflowInstanceId() ?: fail("Cannot get the workflow instance ID") + + // Waits until the workflow is finished + val instance = waitUntilWorkflowFinished( + instanceId = instanceId, + returnInstanceOnError = true, + ) + + // Checks that the node is marked as success & contains the build URL + assertNotNull(instance.getWorkflowInstanceNode("start"), "Node accessed") { node -> + assertTrue(!node.error.isNullOrBlank(), "There is an error") + assertNotNull(node.output) { output -> + val buildUrl = output.path("buildUrl").asText() + assertTrue(buildUrl.isNotBlank(), "Build URL must not be blank") + } + } + } + } + @Test fun `Workflow node contains the build URL while the node is running`() { // Job to call @@ -146,9 +228,8 @@ class ACCDSLWorkflowNotificationChannel : AbstractACCDSLWorkflowsTestSupport() { branch {} // Gets the workflow instance ID from the output of the notification - - waitUntil( + task = "Getting the workflow instance id", timeout = 30_000L, interval = 500L, ) { diff --git a/ontrack-kdsl/src/main/java/net/nemerosa/ontrack/kdsl/spec/extension/workflows/WorkflowInstance.kt b/ontrack-kdsl/src/main/java/net/nemerosa/ontrack/kdsl/spec/extension/workflows/WorkflowInstance.kt index 702795f76e..5d93585b3b 100644 --- a/ontrack-kdsl/src/main/java/net/nemerosa/ontrack/kdsl/spec/extension/workflows/WorkflowInstance.kt +++ b/ontrack-kdsl/src/main/java/net/nemerosa/ontrack/kdsl/spec/extension/workflows/WorkflowInstance.kt @@ -7,7 +7,10 @@ data class WorkflowInstance( val finished: Boolean, val nodesExecutions: List, ) { - fun getExecutionOutput(nodeId: String): JsonNode? { - return nodesExecutions.firstOrNull { it.id == nodeId }?.output + fun getWorkflowInstanceNode(nodeId: String): WorkflowInstanceNode? { + return nodesExecutions.firstOrNull { it.id == nodeId } } + + fun getExecutionOutput(nodeId: String): JsonNode? = + getWorkflowInstanceNode(nodeId)?.output }