Skip to main content
Version: Release 24.3

Webhook event tasks

Webhook event tasks are extensible automated tasks that wait for events from both webhooks endpoints and deployment provider webhook sources, and complete when the incoming event matches the specified condition.

Using the Wait For Json Event Task

In Digital.ai Release there is a supplied generic webhook task Webhook: Wait for Json event.

picture 3

The input options for the Webhook: Wait for Json event task are:

OptionDescription
Event SourceConfigured HTTP Endpoint for webhooks or webhook sources to listen on.
ConditionThe condition that must be satisfied to transition the task from in-progress to complete.
Received eventOutput property bound to a text variable that will store the JSON of the webhook event (optional).

Note: The task will listen for incoming events only while it is in the In progress state.

See Deployment Provider Event Source Properties to learn more about the properties you can use to build your condition for deployment provider event sources.

Condition Script

The webhook task condition is a Jython script that works similar to the Webhook event trigger filter rule:

If the script returns True, the task will complete.

If the script returns False, the task will stay in progress.

If there is an error with the script, the task will fail.

In the script, you can access the Release Jython API, and the following properties: event, headers, parameters. event is the parsed JSON body of the webhook event, while headers and parameters are the HTTP request headers and parameters.

The event, headers, parameters data is also accessible using dot access, e.g. event.commits[0].author, but the regular dict access is still available.

Using the Wait for Deployment Event Task

Use the generic Webhook: Wait for Deployment Event task to listen to deployment events from deployment provider event sources.

The input options for the Webhook: Wait for Deployment Event task are:

OptionDescription
Event SourceConfigured deployment provider event sources to listen to.
Application TitleThe title of the application to wait for.
Environment TitleThe title of the environment (the application will be deployed to) to wait for.
Application VersionThe version of the application to wait for.
Deployment StatusesThe deployment status to wait for. Default is success.

picture 1

This task, if configured, waits for the matching event on the deployment provider event source and completes when the event occurs.

picture 2

There are no output properties for this task.

Define a Custom Webhook Event Task

In order to reduce repetition of event matching logic, you can define your own webhook task type in the synthetic.xml. All webhook event tasks are a sub-type of Custom script task. All rules concerning custom script tasks are valid for webhook event tasks.

To define a custom webhook event task, you need to:

  1. Define new task type which extends webhook.ReactiveTask
  2. Define a webhookScriptLocation property which points to the condition script file

The synthetic.xml type definition:

<synthetic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.xebialabs.com/deployit/synthetic"
xsi:schemaLocation="http://www.xebialabs.com/deployit/synthetic synthetic.xsd">


<type type="jira.WaitForIssueStatus" extends="webhook.ReactiveTask">
<property category="input" name="issueKey" kind="string"/>
<property category="input" name="issueStatus" kind="string" default="Closed"/>

<property category="output" name="resolution" kind="string"/>
<property category="output" name="resolutionDate" kind="date"/>

<property hidden="true" transient="true" name="webhookScriptLocation" default="jira/WaitForIssueStatusWebhook.py" />
</type>
</synthetic>

The WaitForIssueStatusWebhook.py script:

global issueKey, issueStatus, resolution, resolutionDate

if not issueKey:
raise Exception("Issue key must be defined")

if not issueStatus:
raise Exception("Expected issue status to wait for must be defined")

print "Matching new event: %s" % payload

result = event.webhookEvent == "jira:issue_updated" and event.issue.key == issueKey and event.issue.fields.status.name == issueStatus
if result:
print "Issue %s has successfully transitioned to status %s" % (issueKey, issueStatus)
resolution = event.issue.fields.resolution.name
resolutionDate = event.issue.fields.resolutiondate
else:
print "Event did not match expected conditions"

Further, it is possible to design a custom webhook event task which, when starting, does an initial pull of the external system. If the condition has already been satisfied, the task will transition directly into the Completed state. Otherwise, it will stay In progress until a matching JSON event gets received on the configured HTTP endpoint event source.

We can quickly update the example jira.WaitForIssueStatus task and reuse some JIRA plugin base types and utility classes:

  1. Make jira.WaitForIssueStatus type extend jira.JiraScript
  2. Add back the properties previously provided by the webhook.ReactiveTask - the endpoint and waitForSignal properties
  3. Add a new WaitForIssueStatus.py script which will perform the initial poll

The synthetic.xml type definition:

<synthetic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.xebialabs.com/deployit/synthetic"
xsi:schemaLocation="http://www.xebialabs.com/deployit/synthetic synthetic.xsd">


<type type="jira.WaitForIssueStatus" extends="jira.JiraScript">
<property category="input" name="endpoint" kind="ci" referenced-type="events.WebhookEndpoint" />
<property category="input" name="issueKey" kind="string"/>
<property category="input" name="issueStatus" kind="string" default="Closed"/>

<property category="output" name="resolution" kind="string"/>
<property category="output" name="resolutionDate" kind="date"/>

<property category="script" name="waitForSignal" kind="boolean" default="false"/>

<property hidden="true" transient="true" name="scriptLocation" default="jira/WaitForIssueStatus.py" />
<property hidden="true" transient="true" name="webhookScriptLocation" default="jira/WaitForIssueStatusWebhook.py" />
</type>

</synthetic>

The WaitForIssueStatus.py script:

global issueKey, issueStatus, resolution, resolutionDate

import sys
import com.xhaus.jyson.JysonCodec as json
from jira import JiraServer

if not jiraServer:
raise Exception("JIRA server must be defined")

if not issueKey:
raise Exception("Issue key must be defined")

if not issueStatus:
raise Exception("Expected issue status to wait for must be defined")

ISSUE_RETREIVED_STATUS = 200

jira = JiraServer(jiraServer, username, password, apiToken)

request = jira._createRequest()

statusTask = jira._getVersionUri() + '/issue/' + issueKey

response = request.get(statusTask, contentType='application/json', headers=jira._createApiTokenHeader())

# if response received from Jira
if response.getStatus() == ISSUE_RETREIVED_STATUS:
# retrieve issue status
issueData = json.loads(response.getResponse())
currentStatus = issueData['fields']['status']['name']
print "\nThe status of issue %s is %s" % (issueKey, currentStatus)
if currentStatus == issueStatus:
print "\nIssue is in expected status, completing task now"
resolution = issueData['fields']['resolution']['name']
resolutionDate = issueData['fields']['resolutiondate']
waitForSignal = False
else:
print "\nIssue is not in expected status yet, will wait for matching event"
waitForSignal = True
else:
print "Error from JIRA, HTTP Return: %s" % (response.getStatus())
response.errorDump()
sys.exit(1)

Depending on the status of the ticket, the WaitForIssueStatus.py script will either complete the task by setting the waitForSignal flag to False or will stay in progress and pass the control to the WaitForIssueStatusWebhook.py script by setting the waitForSignal flag to True.