atlascamp 2015: jira service desk: scale your team with build-it-yourself automation rules

48
JIRA Service Desk Scale your team with build-it-yourself automation rules ADAM HYNES & CLEMENT CAPIAUX DEVELOPERS ATLASSIAN

Upload: atlassian

Post on 14-Aug-2015

252 views

Category:

Technology


1 download

TRANSCRIPT

JIRA Service Desk Scale your team with

build-it-yourself automation rules

ADAM HYNES & CLEMENT CAPIAUX • DEVELOPERS • ATLASSIAN

A U TO M AT I O N

J I R A S E RV I C E D E S K

Scale your team with build-it-yourself automation rules

D E M O

L E T ’ S E X T E N D !

JIRA Service Desk Past, Present and Future

C O L U M N T I T L E C O L U M N T I T L E

The Customer PortalC O L U M N T I T L E C O L U M N T I T L E C O L U M N T I T L E

JIRA Service Desk key featuresC O L U M N T I T L E C O L U M N T I T L E C O L U M N T I T L E

Customer portal

Queues

SLAs

Reports

Knowledge Base

Big cool statistic

3,000JIRA Service Desk customers

Service desks agents are overwhelmed:

But wait… there’s a problem

• doing repetitive tasks• forgetting important stuff

Introducing…

Automation for

JIRA Service Desk

Automation?

Automation!

We’ve got all sorts of needs

We’ve got all sorts of needs

We’ve got all sorts of needs

Automation in IT

and JIRA Service Desk?

All this time lost…

Doing repetitive tasks

Making sure things don’t slip through the cracks

Updating other applications

Commenting on tickets

Granting access to a system

Closing tickets

Alerting support when SLAs are getting critical

Escalating inactive issues

Pinging customers for input

W H E N A , I F B , T H E N C

Imagine a world where

exists for your service desk

Like…

… this?

It would be…

… AUTOMAGIC !

A U TO M AT I O N

J S D : PA S T, P R E S E N T, F U T U R E

Scale your team with build-it-yourself automation rules

D E M O

L E T ’ S D E V !

Anatomy of a rule

Rule Component

Rule

A U TO M AT I O N

J S D : PA S T, P R E S E N T, F U T U R E

Scale your team with build-it-yourself automation rules

D E M O

L E T ’ S D E V !

What can we extend?

• Any JIRA event• Issue events• User events

• Any other event• Webhook

• Custom field value

• User property• Webhook URL

param

• REST API call• Close a bunch of

issues• Send an email• Send an SMS

Service Desk

Agent

atlassian-plugin.xml<atlassian-plugin key="com.atlassian.plugins.atlascamp.sdautomation.atlascamp-sdautomation-demo" name="${project.name}" plugins-version="2"> <plugin-info> <description>${project.description}</description> <version>${project.version}</version> <vendor name="${project.organization.name}" url="${project.organization.url}" /> <param name="plugin-icon">images/pluginIcon.png</param> <param name="plugin-logo">images/pluginLogo.png</param> </plugin-info>

<automation-rule-then-action key="call-number-then-action" class="com.atlassian.plugins.atlascamp.sdautomation.CallMeMaybe" name="Call number" name-i18n-key="call.number.name"> <icon-class>user-status</icon-class> <requires> <require>issue</require> </requires> <visualiser class="com.atlassian.plugins.atlascamp.sdautomation.CallNumberVisualiser"/> <validator class="com.atlassian.plugins.atlascamp.sdautomation.PhoneNumberValidator"/> <web-form-module>atlascamp/automation/demo/modules/call-number-form</web-form-module> </automation-rule-then-action>

<!-- Specify the location of our client resources --> <client-resource key="atlascamp-automation-resources"> <context>sd.agent.view</context> <directory location="atlascamp/automation/demo/modules" /> </client-resource> <!-- Add our i18n resource --> <resource type="i18n" name="i18n" location="i18n/atlascamp-sdautomation"/></atlassian-plugin>

Define the module

<automation-rule-then-action key="call-number-then-action" class="com.atlassian.plugins.atlascamp.sdautomation.CallMeMaybe" name="Call number" name-i18n-key="call.number.name"> <icon-class>user-status</icon-class> <requires> <require>issue</require> </requires> <visualiser class="com.atlassian.plugins.atlascamp.sdautomation.CallNumberVisualiser"/> <validator class="com.atlassian.plugins.atlascamp.sdautomation.PhoneNumberValidator"/> <web-form-module>atlascamp/automation/demo/modules/call-number-form</web-form-module> </automation-rule-then-action>

Implement the actionpublic final class CallMeMaybe implements ThenAction{ // Variables and constructor

@Overridepublic Either<ThenActionError, RuleMessage> invoke(final ThenActionParam thenActionParam){ //TODO: Implement}

private PhoneCallTranscript generateTranscriptForIssue(final Issue issue) { final String reporter = issue.getReporter().getDisplayName(); final String priority = issue.getPriorityObject().getName(); final String summary = issue.getSummary(); final String transcriptLine1 = "Welcome to Service Desk"; final String transcriptLine2 = new StringBuilder() .append(reporter) .append(" has raised a ").append(priority).append(" issue with the following summary ") .toString(); final String transcriptLine3 = summary; return new PhoneCallTranscript( newArrayList( transcriptLine1, transcriptLine2, transcriptLine3 ) ); } }

public interface ThenAction{ Either<ThenActionError, RuleMessage> invoke(ThenActionParam thenActionParam); public static interface ThenActionParam { ApplicationUser getUser(); ThenActionConfiguration getConfiguration(); RuleMessage getMessage(); } }

@Overridepublic Either<ThenActionError, RuleMessage> invoke(final ThenActionParam thenActionParam){ //TODO: Implement}

@Overridepublic Either<ThenActionError, RuleMessage> invoke(final ThenActionParam thenActionParam){ }

Implement invoke()

// Get the phone number we want to callfinal Option<String> phoneNumberOpt = thenActionParam.getConfiguration().getData().getValue(PHONE_NUMBER_KEY);if (phoneNumberOpt.isEmpty()){ return thenActionErrorHelper.error("No " + PHONE_NUMBER_KEY + " property in config data"); } final String numberToCall = phoneNumberOpt.get();

// Get the issue for which we want make a callfinal Either<AnError, Issue> issueEither = issueMessageHelper.getIssue(thenActionParam.getMessage());if (issueEither.isLeft()){ // We don't perform any task if we can't get the issue from the rule message return thenActionErrorHelper.error(issueEither.left().get());} final Issue issueToMakeCallFor = issueEither.right().get();

// Make the callphoneCaller.call( new InternationalPhoneNumber(numberToCall), generateTranscriptForIssue(issueToMakeCallFor));

return right(thenActionParam.getMessage());

Define the module

<automation-rule-then-action key="call-number-then-action" class="com.atlassian.plugins.atlascamp.sdautomation.CallMeMaybe" name="Call number" name-i18n-key="call.number.name"> <icon-class>user-status</icon-class> <requires> <require>issue</require> </requires> <visualiser class="com.atlassian.plugins.atlascamp.sdautomation.CallNumberVisualiser"/> <validator class="com.atlassian.plugins.atlascamp.sdautomation.PhoneNumberValidator"/> <web-form-module>atlascamp/automation/demo/modules/call-number-form</web-form-module> </automation-rule-then-action>

Provides -> Requires

Issue commented

Issue

User

Comment

Issue created

Issue

User

SLA time remaining Issue

Issue matches

Issue

Comment visibility

Comment

Issue

User typeUser

Comment contains

Comment

Transition issue

Issue

Add comment

Issue

Alert userIssue

When If Then

Define the module

<automation-rule-then-action key="call-number-then-action" class="com.atlassian.plugins.atlascamp.sdautomation.CallMeMaybe" name="Call number" name-i18n-key="call.number.name"> <icon-class>user-status</icon-class> <requires> <require>issue</require> </requires> <visualiser class="com.atlassian.plugins.atlascamp.sdautomation.CallNumberVisualiser"/> <validator class="com.atlassian.plugins.atlascamp.sdautomation.PhoneNumberValidator"/> <web-form-module>atlascamp/automation/demo/modules/call-number-form</web-form-module> </automation-rule-then-action>

public final class CallNumberVisualiser implements RuleComponentVisualiser{ private final I18nHelper i18nHelper; @Autowired public CallNumberVisualiser(final I18nHelper i18nHelper) { this.i18nHelper = i18nHelper; } @Override public String getName(final RuleComponentVisualiserParam ruleComponentVisualiserParam) { } @Override public Option<String> getLabel(@Nonnull final RuleComponentVisualiserParam ruleComponentVisualiserParam) { }}

final Option<String> configuredLabelOpt = ruleComponentVisualiserParam.ruleConfiguration().getValue(PHONE_NUMBER_KEY); if (configuredLabelOpt.isDefined()) { return some("\"" + configuredLabelOpt.get() + "\""); } else { return none(String.class); }

return i18nHelper.getText("call.number.name");

Implement the visualiser

public interface RuleComponentVisualiser{ String getName(RuleComponentVisualiserParam ruleComponentVisualiserParam); Option<String> getLabel(RuleComponentVisualiserParam ruleComponentVisualiserParam); public static interface RuleComponentVisualiserParam { ApplicationUser getUser(); ConfigurationData ruleConfiguration(); }}

Implement the validator

final Option<String> configuredPhoneNumber = thenActionValidationParam.getConfiguration().getData().getValue(PHONE_NUMBER_KEY); final ApplicationUser userToValidateWith = thenActionValidationParam.getUserToValidateWith(); // For tutorial purposes, we just check the phone number is not blank if (configuredPhoneNumber.isEmpty() || isBlank(configuredPhoneNumber.get())) { return createResultWithFieldError( userToValidateWith, "call.number.missing"); } return ValidationResult.PASSED();

public final class PhoneNumberValidator implements ThenActionValidator{ private final I18nHelper.BeanFactory i18nFactory; @Autowired public PhoneNumberValidator(final I18nHelper.BeanFactory i18nFactory) { this.i18nFactory = i18nFactory; } public ValidationResult validate(final ThenActionValidationParam thenActionValidationParam) { } private ValidationResult createResultWithFieldError(@Nonnull ApplicationUser user, @Nonnull String errorI18nKey) { final I18nHelper i18nHelper = i18nFactory.getInstance(user); Map<String, List<String>> errorList = newHashMap(); errorList.put(PHONE_NUMBER_KEY, newArrayList(i18nHelper.getText(errorI18nKey))); return ValidationResult.FAILED(errorList); }}

public interface ThenActionValidator{ ValidationResult validate(ThenActionValidationParam thenActionValidationParam); interface ThenActionValidationParam { ApplicationUser getUserToValidateWith(); ThenActionConfiguration getConfiguration(); Option<ProjectContext> getProjectContext(); }}

<automation-rule-then-action key="call-number-then-action" class="com.atlassian.plugins.atlascamp.sdautomation.CallMeMaybe" name="Call number" name-i18n-key="call.number.name"> <icon-class>user-status</icon-class> <requires> <require>issue</require> </requires> <visualiser class="com.atlassian.plugins.atlascamp.sdautomation.CallNumberVisualiser"/> <validator class="com.atlassian.plugins.atlascamp.sdautomation.PhoneNumberValidator"/> <web-form-module> </web-form-module> </automation-rule-then-action>

atlascamp/automation/demo/modules/call-number-form

Define the module

define(“ ", [ "servicedesk/jQuery", "servicedesk/underscore"], function ( $, _) {

return { render: function(config, errors) { ... }, serialize : function () { ... } } }

atlascamp/automation/demo/modules/call-number-form

Implement the front-end

.automation-servicedesk-call-number-header { padding-bottom: 5px; }

<div class=“automation-servicedesk-call-number-container"> <div class="automation-servicedesk-call-number-header"><b>{getText('call.number.prompt')}</b></div> <input type="text" class="text" name="phoneNumber" value="{$phoneNumber}" placeholder="{getText('call.number.placeholder')}">

</div>

Service Desk is growing.

Automation is a priority.

You can extend automation.

Automate the shit out of everything.

Thank you!

ADAM HYNES & CLEMENT CAPIAUX • DEVELOPERS • ATLASSIAN

(any questions?)bit.ly/jsdcode

Demo source code

bit.ly/jsdguide

Developer guide

JIRA Service Desk: Scale your team with build-it-yourself automation rules

Submit your feedback: go.atlassian.com/acjsdscale