Worklog Scripts

We can't implement every customer requirements in WorklogPRO, we don't have necessary resources, but also our customers has conflicting requirements. For this reason we have decided to allow our customers to customize WorklogPRO behaviors with Groovy scripts. You can execute various scripts when logging work, approving timesheets. These scripts can be run before an action is performed like logging work, after an action. When scripts are run before an action, you can cancel the action by returning a non-null result from worklog script. 

When writing your scripts please refer to our Java API to see available methods and data structures.

Consider the case when logging work or deleting work. Worklog verification highly depends on customers' requirements. To allow each customer to build his own verification logic we have decided to create a scripting interface for worklog verification. You can now write your own Groovy script to verify worklog entry, update, move or delete operation. "Create/Update" script is executed every time when some tries to log work on WorklogPRO's 'Log Work Dialog' or 'Log Work Custom Field'.  "Delete" script is executed every time when someone tries to delete a worklog. When moving worklog from an issue to another first "Delete" script is executed and after that "Create/Update" script is executed.

"Pre-Worklog Entry" is not a verification script, it is provides opportunity to modify worklog dialog content or worklog custom field content before it is displayed to user. Using this script you can hide some attributes depending on custom conditions or show preset values to user. This script is passed "worklogPreEntryParameters" which is an instance of "com.deniz.jira.worklog.scripting.WorklogPreEntryParameters" and your script should also return an instance of this object. 

You can also access various Jira services and WorklogPRO services using com.atlassian.jira.component.ComponentAccessor. You can check JavaDoc of WorklogPRO classes from here. Please check example scripts for more detailed usage scenarios.

Configuring worklog scripts requires Jira Administrator, Jira System Administrator. Due to security constraints WorklogPRO Administrators can't update script. Since you can write arbitrary code and use all Jira services inside the script a script can do anything to your Jira instance although it is executed with privilege of logged in user (the user creating/updating/deleting worklog). 


Debugging Your Scripts

You can use println statements to log values to Jira process's standard output for debugging purposes, not atlassian-jira.log file. You can use SLF4J logging to log to atlassian-jira.log file if you want. If you want to use logging please set debug level for the package "com.deniz.jira.worklog.scripting" and use following code to add debug messages to your script.

import org.slf4j.*;

//please enable logging for package "com.deniz.jira.worklog.scripting" from Administration/System/Logging and Profiling
Logger log = LoggerFactory.getLogger(com.deniz.jira.worklog.scripting.ScriptingService.class);
log.debug("This is debug message");


Accessing Various Jira and WorklogPRO Services

This script access various Jira and WorklogPRO services using ComponentAccessor class. Note that to access WorklogPRO services you need to use "getOSGiComponentInstanceOfType" method. This script checked whether a "Billable" boolean attribute exist. If it doesn't exist logging work is allowed. If it exists, check worklog is marked as billable. If it is billable, it checks whether the current user has "Service Desk Team" role in the project. If the user doesn't have "Service Desk Team" role, logging work is disallowed.

Error rendering macro 'code': Invalid value specified for parameter 'firstline'
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.security.JiraAuthenticationContext;
import com.atlassian.jira.security.roles.ProjectRoleManager;
import com.deniz.jira.worklog.services.attr.AttrTypeService;

def authenticationContext = ComponentAccessor.getJiraAuthenticationContext();
def projectRoleManager = ComponentAccessor.getComponent(ProjectRoleManager.class);

//We need to load WorklogPRO classes differently using getOSGiComponentInstanceOfType
def attrTypeService = ComponentAccessor.getOSGiComponentInstanceOfType(AttrTypeService.class);

def billableAttrType = attrTypeService.getAttrTypeWithName("Billable").get();
if (billableAttrType == null) {
  return; //there is no billable attribute
}

def isBillable = worklogAttributes.get(billableAttrType.getID());
def loggedInUser = authenticationContext.getLoggedInUser();
def serviceDeskTeamRole = projectRoleManager.getProjectRole("Service Desk Team");
def project = worklog.getIssue().getProjectObject();

println(worklogAttributes);

if (isBillable == "yes") { //boolean attributes are has either "no" or "yes" value.
  if (!projectRoleManager.isUserInProjectRole(loggedInUser, serviceDeskTeamRole, project)) {
    return "Only Service Desk Team can register billable worklogs!"
  }
}


Accessing Other Apps's Components

Error rendering macro 'code': Invalid value specified for parameter 'firstline'
import com.deniz.jira.versioning.CmpVersionMappingService;
import com.deniz.jira.worklog.scripting.WithPlugin;
import com.atlassian.jira.component.ComponentAccessor;

@WithPlugin("com.deniz.jira.versioning")  //this is the plugin key. you can get it from "manage apps" screen
def cmpVersionMappingService = ComponentAccessor.getOSGiComponentInstanceOfType(CmpVersionMappingService.class);

Accessing Database within Scripts

Error rendering macro 'code': Invalid value specified for parameter 'firstline'
import com.atlassian.jira.component.ComponentAccessor
import org.slf4j.*;
import com.deniz.jira.worklog.*;
import com.atlassian.jira.issue.CustomFieldManager;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.Issue;
import groovy.sql.Sql;
import java.sql.*;


def issueId = worklog.getIssue().getId().toString();
def issueKey = worklog.getIssue();
def project = issue.getProjectObject().getId();


String SQLStmt = """INSERT INTO mydb.schema.table VALUES (""" + issueId + """, '""" + issueKey + """', """ + project + """) """;

   // username and passowrd
    def props = new Properties();
    props.setProperty("user", "theuser");
    props.setProperty("password", "thepassword");

    def driver = Class.forName('net.sourceforge.jtds.jdbc.Driver').newInstance() as Driver;
    def conn = driver.connect("jdbc:jtds:sqlserver://SERVERNAME:1433/INSTANCE", props);
    
     if (conn) {
        def sql = new Sql(conn)
        try {
            def result = sql.executeQuery(SQLStmt);
            sql.close()
            conn.close()
        }
        catch (Exception e){
            log.error(e.toString())
        }

    } else {
        log.error("Could not connect to SQL database.")
    }