Introduction

Jira Scripting Suite allows you to execute custom Jython script to evaluate workflow conditions, perform validations and post functions. Script is evaluated in the context, which differs for each type of script (see sections below for details).

Jython is a Python port to Java, visit http://www.python.org/doc/2.5/ for general info.

Be Careful

Be careful when using single script file in many workflow actions - when you change this script in one action, all other will also be affected!

Conditions

Context:

Variable

Description

result

Result of condition evaluation; boolean value, default is True

issue

Issue object

log

org.apache.log4j.Logger

transientVars

A map containing all context data passed to validator

The main context variable here is result. Validator expects it to contain boolean value - True or False.

result = True # this workflow action is enabled
result = False # and now it's disabled for everyone

You can get any attribute of the Issue object using its Java methods. For example, let's deny the action for all issues having word TEST in Summary:

summary = issue.getSummary() # note that summary is a python string, not Java String
result = summary.find('TEST') < 0 # find() returns -1 if string not found

# or simply in one string
result = issue.getSummary().find('TEST') < 0

Be Careful

Although issue is actually a MutableIssue object, you can not change any issue data in condition script.

Validation

Context:

Variable

Description

result

Result of validation; boolean value, default is True

invalid_fields

PyDictionary(), empty map by default

description

PyUnicode(), empty unicode string by default

originalIssue

Original (unmodified) Issueobject

issue

Modified Issueobject

log

org.apache.log4j.Logger

transientVars

A map containing all context data passed to validator

In validation script we use another two valiables along with result to reports an error to the user: invalid_fields and _description _. See example:

result = False
description = 'General error description'
invalid_fields['summary'] = u'Error description for the Summary field'

This script produces such a message for every issue with that workflow:

invalid_fields is initially an empty map. You can attach error messages both to standard and custom fields. In case of custom field you should use its ID like this:

result = False
invalid_fields['customfield_10010'] = u'This custom field is invalid!'

Post Functions

<TODO>

Code Snippets

Sending a Custom E-mail Notifier

sender = 'sender@somedomain.com'
to = 'recipient@somedomain.com'
subj = "SUBJECT"
body = "MESSAGE BODY"

server = 'smtp.somedomain.com'

from email.MIMEText import MIMEText
msg = MIMEText(body, 'plain', 'utf-8')
msg['Subject'] = subj
msg['To'] = to
msg['Importance'] = 'high'

import smtplib
s = smtplib.SMTP(server)

s.sendmail(sender, [to], msg.as_string())
s.quit()

More Complicated E-mail Notifier

Thanks to Jared Meeker for this code

# -*- coding: UTF-8 -*-

#import inspect

# Issue Details
key = issue.getKey()
status = issue.getStatusObject().name
summary = issue.getSummary()
project = issue.getProjectObject().name
resolution = issue.getResolutionObject().name
description = issue.getString("description")

# Get Requestor custom field (text, not user picker)
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.fields.CustomField
customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
customField = customFieldManager.getCustomFieldObjectByName("Requestor")
requestor = issue.getCustomFieldValue(customField)

# Verify that we have an email address in the text field
import re
if (re.match('[A-Za-z0-9._%+-]+@(?:[A-Za-z0-9-]+\.)+[A-Za-z]{2,4}',requestor)):
       # Get posted comment if it exists
       try:
               comment = dict(transientVars)['comment']
       except:
               trash = ''


       # Email Details
       sender = '*******@*************.***'
       to = requestor
       subject = '[JIRA] ' + status + ': (' + key + ') ' + summary

       # Build the body of the email
       body = ''
       if (status == "Closed"):
               body = body + "\r\nAccording to our records, your issue (" + key + ") has been resolved.\r\n\r\n"
       if (resolution == "Won't Fix"):
               body = body + "\r\nThis issue will not be fixed. A description of why should be below.\r\n"
       elif (resolution == "Duplicate"):
               body = body + "\r\nThis issue is a duplicate of another issue.\r\n"
       elif (resolution == "Incomplete"):
               body = body + "\r\nThis issue has been marked as incomplete. A description of why should be below.\r\n"
       elif (resolution == "Cannot Reproduce"):
               body = body + "\r\nThe developers have been unable to reproduce the error you describe.\r\n"
       elif (resolution == "Rejected"):
               body = body + "\r\nThis issue has been rejected. A description of why should be below.\r\n"
       body = body + "\r\n"
       try:
               body = body + "Comment:\r\n" + comment + "\r\n"
       except:
               body = body + "Comment:\r\nNo comment was entered\r\n"
       body = body + "\r\n"
       body = body + "> " + summary + "\r\n"

       barline = '>'
       while (len(barline) <= len(summary)+2): barline = barline + "-"

       body = body + barline + """
       >
       >
       >          Key: """ + key + """
       >      Project: """ + project + """
       >
       """ + description + """

       --
       This message is automatically generated by JIRA.
       -
               If you think it was sent incorrectly contact one of the administrators: https://jira.somedomain.com:8443/secure/Administrators.jspa
       -
       For more information on JIRA, see: http://www.atlassian.com/software/jira"""


       # Build mail message
       from email.MIMEText import MIMEText
       msg = MIMEText(body, 'plain', 'utf-8')
       msg['Subject'] = subject
       msg['To'] = to
       #msg['Importance'] = 'high'

       # Send the email
       import smtplib
       s = smtplib.SMTP('*****.*******.***') # ip or domain name of smtp server
       s.sendmail(sender, [to], msg.as_string())
       s.quit()
  • No labels

230 Comments

  1. Unknown User (tkrug0210)

    What I currently need is a validator to check if the user contained in a userpicker-field is member of a specific group.
    Is it possible to achieve this via the plugin?

    Cheers
    Thomas

    1. Thomas, sure you can.

      from com.atlassian.jira import ComponentManager
      cfm = ComponentManager.getInstance().getCustomFieldManager()
      
      user = issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10000")) # 'customfield_10000' your custom field id
      """ variable 'user' will hold a single User object or None if the field is Single User Picker
       or a list of User object - in case of Multi User Picker (even with a single value) """
      
      # let's suppose 'user' is a single User object
      if not user.inGroup('developers'):
        result = False
        description = "Field FFFF should contain a member of 'developers' group"
        invalid_fields['customfield_10000'] = u"This field should contain a member of 'developers' group"
      

      Of course, this is not a completely production code, you should add validation for None values and general error handling.

      BR, Alex

      1. Unknown User (tkrug0210)

        Hi Alex,

        works just fine, thanx.

        Cheers
        Thomas

      2. Unknown User (tkrug0210)

        Hi Alex,

        I am struggling with Python concerning the None values. I thought this might work

        if not user.inGroup('1_zeitkorrektur') and not user == "":

        which does not. Can you help me with the correct code?

        The error thrown is

        root cause: Traceback (most recent call last): File "d:\jira\data\jss\jython\workflow\zeitkorr_weiterleiten_fk.py", line 11, in <module> elif not user.inGroup('1_zeitkorrektur'): AttributeError: 'NoneType' object has no attribute 'inGroup'

        Cheers

        Thomas

        1. Hi Thomas,
          You should check for None first and after that you can safely access User object:

          if user != None and not user.inGroup('1_zeitkorrektur'):  ... 

          or shorter:

          if user and not user.inGroup('1_zeitkorrektur'): ... 

          because None is equivalent to False in boolean expression

          1. Unknown User (tkrug0210)

            Hi Alex,

            thanx, my script is running fine now. I have to userpickers ('fk' and 'fkvertretung'). Both users have to be in the '1_zeitkorrektur' group whereas the second userpicker is not mandatory:

            from com.atlassian.jira import ComponentManager
            cfm =  ComponentManager.getInstance().getCustomFieldManager()
            
            fk =  issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10103")) 
            fkvertretung =  issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10162")) 
            
            fkok = False
            fkvertretungok = False
            
            if fk.inGroup('1_zeitkorrektur'):
              fkok = True
              
            if not fkvertretung == None and fkvertretung.inGroup('1_zeitkorrektur'):
              fkvertretungok = True
            elif fkvertretung == None:  		
              fkvertretungok = True
              
            if not fkok and not fkvertretungok:
              result = False
              invalid_fields['customfield_10103'] = u"Die erfassten Personen duerfen nicht genehmigen"
              invalid_fields['customfield_10162'] = u"Die erfassten Personen duerfen nicht genehmigen"
              description = "Die erfassten Personen duerfen nicht genehmigen"
            elif not fkok and fkvertretungok:
              result = False
              invalid_fields['customfield_10103'] = u"Kein zugelassener Genehmiger"
              description = "Kein zugelassener Genehmiger"
            elif fkok and not fkvertretungok:
              result = False
              invalid_fields['customfield_10162'] = u"Kein zugelassener Genehmiger"
              description = "Kein zugelassener Genehmigervertreter"
            else:
              result = True
            
  2. Unknown User (darkoc)

    Hi to all,

    I just installed Jira Scripting Suite(following the instructions from the official page ) and added some Jython script as post function:

    if (issue.getParentId() > 0):
    issue.setComponents(issue.getParentObject().getComponents())
    issue.setFixVersions(issue.getParentObject().getFixVersions())
    issue.setAffectedVersions(issue.getParentObject().getAffectedVersions())
    issue.setPriority(issue.getParentObject().getPriority())
    

    so I can inherit the Priority, Versions and Components from the parent issue when I create a subtask

    works great!...

    Still, when I try to edit an existing issue I get the following error: Cannot create PyString from null!...

    This happens even when I try to edit some issue which doesn't have the Jython script attached as a post function... Any help???(sad)

     Thanks in advance

    1. Unknown User (tkrug0210)

      Hi Darko,

      I can't really help you on this one but Alex answered my questions very quickly.

      You maybe solved a long open problem I have. I am using a plugin to generate subtasks in a postfunction. This plugin does not copy FixVersion and AffectedVersion from the parent to the Subtask.

      Do you add the subtask in your postfunction and can supply me with the code snippet?

      Cheers
      Thomas

      1. Unknown User (darkoc)

        Hi Thomas,

        The thing that I do is adding the code I wrote in the previous post as a POST FUNCTION. So basically, when you open a task and u set Fix Version, Affected Version, Components and Priority, they will be applied to every subtask you create from that task. I tried that and it is working. Just add the code...

        Still, after I installed Jira Scripting Suite I get the error: Cannot create PyString from null! every time I try to edit ANY ISSUE... I really like the JSS but If I don't solve this issue I will have to disable it (sad) .

        Anyone knows something about this?

        Cheers,

        Darko

        1. Hi Darko,

          Did you add the code from above as a global post-function?

          Alex

        2. Unknown User (tkrug0210)

          Hi Darko,

          this works for me only if I EDIT a subtask, not while creating one.

          Did you change the "CreateSubTaskIssue" alias in the actions.xml? If yes maybe that's the problem you have.

          Cheers,
          Thomas

          1. Unknown User (darkoc)

            Hi guys,

            I was in a hurry these days so I didn't answer the questions. The problem was in the actions.xml... As it was described in the manual, I needed to:

            change "issue.EditSubTaskIssue" to "com.quisapps.jira.plugin.action.EditSubTaskIssue" and "issue.EditIssue" to "com.quisapps.jira.plugin.action.EditIssue"

            so that was the problem. I changed back to issue.EditSubTaskIssue and issue.EditIssue

            and the problem was fixed. Anyway, I was wondering if there is any way to use the Jython scripts on creating issues and not just as Post functions and Validators in workflows

            Regards,

            Darko

            1. Hi Darko,

              By doing that you disabled global jython on-edit validator and post-functions. I think your problem was in incorrect on-edit post-function script.

              And if you want to set a post-function on creating, you should add a jython postfunction to the "Create Issue" action of the corresponding workflow, just before the "Creates the issue originally." and place your code there.

              BR, Alex

              1. Unknown User (wufei)

                Hi Alexander,

                Hi have installed JSS 0.3.1 on JIRA 4.1.1.

                I found answers to my questions. It may help other people.

                I don't really understand how you can set a post-function on issue creation. Can you please give some more details on how you're doing this? Actually, how can you access to the "Create Issue" action of a workflow?

                Top menu "Administration", Left pane menu "Events" and then, select an inactive copy of your target workflow by selecting its "Create" link.

                How about validators? And would it be possible to apply these scripts to a certain type of issue only?

                Make sure your workflow is working on your specific type of issue if you just want to avoid applying the script globally. This works for Validators and Post-functions. To access to the custom field of the issue, I'm using "customFieldValue = issue.getCustomFieldValue(myCustomField)".

                Thanks in advance,

                Wufei

                1. Unknown User (brian)

                  I found answers to my questions. It may help other people.

                  I don't really understand how you can set a post-function on issue creation. Can you please give some more details on how you're doing this? Actually, how can you access to the "Create Issue" action of a workflow?

                  Go to the workflow, create a draft, click the initial step (Submitted/Open/etc), in the Workflow Browser click on the "Create" transition. From there you can add post functions.

              2. Unknown User (keith.lee)

                Thanks Alex,

                Your comment give me the answer for Cannot create PyString from null!  issue on issue editing.

                The reason was the global post function (Admin -> JSS -> Edit Postfunction) was set to 'Inline script' without any code in it.

                By changing it to default file 'File (......./edit_postfunction.py)' the problem has gone.

                I hope this will help others as well.

                BR, Keith

  3. Unknown User (darkoc)

    Hi guys,

    Can someone tell me how to check if a user belongs to a specific Project Role in specific project? Let's say in the project "Test Project" i want to check if a user belongs to the project role "Test Project Developers" and if he doesn't to restrict him to crate Developement issues.

    Regards,

    Darko

    1. Unknown User (chrome@stupendous.net)

      That really sounds like something Jira can do out of the box without messing with workflows?

    2. Hi Darko,

      I think it would be smth like this:

      project = issue.getProjectObject()
      projectRoleManager = ComponentManager.getComponentInstanceOfType(ProjectRoleManager)
      authenticationContext = ComponentManager.getInstance().getJiraAuthenticationContext()
      
      userInRole = projectRoleManager.isUserInProjectRole(
                      authenticationContext.getUser(),
                      projectRoleManager.getProjectRole("Test Project Developers"),
                      project )
      

      Anyway, a good point to start is ComponentManager javadoc - there are a lot of useful 'Managers' in JIRA

      Alex

  4. Unknown User (chrome@stupendous.net)

    This plugin is awesome. I can now implement all the weird functions I wanted, that I couldn't do with any other plugin.

    Here is a Post Function I am using to update a custom field with a string generated from the User's name. I needed to do this because I wanted it recorded in an easily accessible way, who performed a particular transition last.

    customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
    customField = customFieldManager.getCustomFieldObjectByName("Review Status")
    user = issue.getAssignee()
    issue.setCustomFieldValue(customField, "APPROVED by " + user.getFullName())
    customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
    
    customField = customFieldManager.getCustomFieldObjectByName("Review Status")
    
    user = issue.getAssignee()
    
    issue.setCustomFieldValue(customField, "APPROVED by " + user.getFullName())
    
    
  5. Unknown User (jira.support@ubisoft.com)

    I added the plugin but we keep getting this error : Error creating issue: root cause: IOError: (2, 'File not found - /mnt/jira/jira/jira58/jss/jython/_init_interpreter_.py (No such file or directory)') whereever I put scripts (Create post function etc)

    Do we miss something ?  I have the jss-0.2.jar in the installed-plugins and all the .py jython.jar (from the version 2.5.0 etc in the dir of homejira /jss/jython/

    But from this error he seem to dont find the .py from the bin dir of jss jython even to the path is there.

    Thanks!

    1. Hi! Look into jss-0.2.jar, and you will find the 'jython' folder - it contains some jython placeholders and sample files. Just copy this folder to /mnt/jira/jira/jira58/jss.

      BR, Alex

  6. Unknown User (stenech)

    Hi! How is it possible to set a specific component? I think I have to use "issue.setComponents()" but I have no clue how to setup the required list?!?

    Markus

    1. Hi Markus,

      This should be a Collection of GenericValue objects. You can use a getGenericValue() method of ProjectComponent to obtain a GenericValue needed.

      BR, Alex

      1. Unknown User (stenech)

        Yes, it works:

        componentManager = ComponentManager.getInstance()
        project = issue.getProjectObject()
        
        component = componentManager.getProjectComponentManager().findByComponentName(project.getId(), "Sample Component")
        issue.setComponents([component.getGenericValue()])
        

        Markus

  7. Unknown User (kubo@solvere.sk)

    Hi, I installed the JSS plugin and when testing I get this error:

    ERROR

    It seems that you have tried to perform an illegal workflow operation.

    If you think this message is wrong, please consult your administrators about getting the necessary permissions.

    Form Errors:

    General error description

    Maybe I don't understand exactly the last step form the installation: Add listener with any name (e.g. Jython) and class com.quisapps.jira.plugin.listener.JythonListener .

    Also what I did on previous step : Copy Jython file placeholders from plug-in jar file /jython to JIRA_HOME/jss/jython. Was that I just unzipped the jar and placed flder Jython from that jar to the path jss/jython in my Jira instance.

    My test script looks like this:

    result = False
    
    invalid_fields['summary'] = u'Error description for the Summary field'
    
    description = 'General error description'
    

    Thanks for help.

    1. Unknown User (kubo@solvere.sk)

      I found out where was my problem.

      The error was shown because I haven't setup any screen on transition. So if you want to have this thing showing errors correctly you have to have screen with fields that you want to check assigned to transition in Transition View field when editing transition.

      Also installation step Add listener with . . . means that you have to create a listener in Administration -> Listeners. 

  8. Unknown User (matt.bates)

    If you want to clear out your Fix Version (say when you Close - Won't Fix something) you need to pass an empty list.

    if (issue.getResolutionObject().getName() \!= 'Fixed'):
        issue.setFixVersions(\[\])
  9. Unknown User (hmenzi)

    I am trying to create a sub-task on a workflow transition the sub-task should have all basic properties of the issue. I can not seem to find any example other than java examples that do not seem to work.

    This is what I have (which is wrong) can someone please point me in the right direction?

    # Spawn a sub-task based on the current issue
    
    from com.atlassian.jira import ManagerFactory
    from com.atlassian.jira.util import JiraUtils
    stm = ComponentManager.getInstance().getSubTaskManager()
    assignee = issue.getAssignee()
    reporter = issue.getReporter()
    project = issue.getProject()
    priority = issue.getPriority()
    priority_id = priority.getString("id")
    summary = "Subtask for " + issue.getSummary()
    issueKey = issue.getKey()
    issueVals = { 'project':project, 'summary':summary, 'type':'10', 'reporter':reporter, 'assignee':assignee, 'priority':priority_id }
    subTask = issue.IssueImpl( issue, ComponentManager.getInstance().getIssueManager(), ComponentManager.getInstance().getProjectManager(), ComponentManager.getInstance().getVersionManager(), ComponentManager.getInstance().getIssueSecurityLevelManager(), ComponentManager.getInstance().getConstantsManager(), ComponentManager.getInstance().getSubTaskManager (), ComponentManager.getInstance().getAttachmentManager() )
    subTask.setIssueTypeId(10)
    
    1. Hi Hans,

      In JIRA sub-task is just an issue with corresponding issue type and a link of special type between itself and its parent.

      # add all required imports here
      
      issueManager = ComponentManager.getInstance().getIssueManager()
      issueFactory = ComponentManager.getInstance().getIssueFactory()
      authenticationContext = ComponentManager.getInstance().getJiraAuthenticationContext()
      subTaskManager = ComponentManager.getInstance().getSubTaskManager();
      
      issueObject = issueFactory.getIssue()
      issueObject.setProject(issue.getProject())
      issueObject.setIssueTypeId("5") # default sub-task issue type
      issueObject.setParentId(issue.getId())
      
      '''
         setting general issue attributes such as summary, assignee etc
      '''
      
      subTask = issueManager.createIssue(authenticationContext.getUser(), issueObject)
      subTaskManager.createSubTaskIssueLink(issue.getGenericValue(), subTask, authenticationContext.getUser())
      
      # Update search indexes
      ImportUtils.setIndexIssues(True);
      ManagerFactory.getCacheManager().flush(CacheManager.ISSUE_CACHE, subTask)
      ComponentManager.getInstance().getIndexManager().reIndex(subTask)
      ImportUtils.setIndexIssues(False)
      

      BR, Alex

      1. Unknown User (tkrug0210)

        Hi Alex,

        is it somehow possible to create multiple subtasks in on script?

        When duplicating the lines

        subTask = issueManager.createIssue(authenticationContext.getUser(), issueObject)
        subTaskManager.createSubTaskIssueLink(issue.getGenericValue(), subTask, authenticationContext.getUser())
        
        

        Jira throws a NullpointerException

        root cause: Traceback (most recent call last): File "d:\jira\data\jss\jython\workflow\kundenmanagement_subtasks.py", line 26, in <module> subTask2 = issueManager.createIssue(authenticationContext.getUser(), issueObject) at com.atlassian.jira.issue.managers.DefaultIssueManager.notifyTrackbacks(DefaultIssueManager.java:413) at com.atlassian.jira.issue.managers.DefaultIssueManager.createIssue(DefaultIssueManager.java:356) at sun.reflect.GeneratedMethodAccessor721.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.atlassian.util.profiling.object.ObjectProfiler.profiledInvoke(ObjectProfiler.java:70) at com.atlassian.jira.config.component.SwitchingInvocationHandler.invoke(SwitchingInvocationHandler.java:28) at $Proxy30.createIssue(Unknown Source) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) java.lang.NullPointerException: java.lang.NullPointerException

        1. Possibly you can't create an issue using the same issueObject again. You should create another issueObject, set its attributes and then call issueManager.createIssue() and subTaskManager.createSubTaskIssueLink(). Of course, you can do this, for instance, in a 'for' loop.

          1. Unknown User (tkrug0210)

            I tried that without success. The exception is no longer thrown, but jira only creates the first subtask.
            If I separate the code in two files and add two postfunctions to the workflow it works.

            \# add all required imports here
            from com.atlassian.jira.util import ImportUtils
            from com.atlassian.jira import ManagerFactory
            from com.atlassian.jira import ManagerFactory
            
            issueManager = ComponentManager.getInstance().getIssueManager()
            issueFactory = ComponentManager.getInstance().getIssueFactory()
            authenticationContext = ComponentManager.getInstance().getJiraAuthenticationContext()
            subTaskManager = ComponentManager.getInstance().getSubTaskManager();
            
            \# issueObject anlegen, das wird nachher die Unteraufgabe Realisierung
            issueObject = issueFactory.getIssue()
            issueObject.setProject(issue.getProject())
            issueObject.setIssueTypeId("5") # default sub-task issue type
            issueObject.setParentId(issue.getId())
            issueObject.setFixVersions(issue.getFixVersions())
            issueObject.setAffectedVersions(issue.getAffectedVersions())
            issueObject.setPriority(issue.getPriority())
            
            \# 1. Unteraufgabe "Realisierung"
            issueObject.setSummary("Realisierung")
            issueObject.setAssignee(issue.getAssignee())
            subTask = issueManager.createIssue(authenticationContext.getUser(), issueObject)
            subTaskManager.createSubTaskIssueLink(issue.getGenericValue(), subTask, authenticationContext.getUser())
            \# Update search indexes
            ImportUtils.setIndexIssues(True);
            ManagerFactory.getCacheManager().flush(CacheManager.ISSUE_CACHE, subTask)
            ComponentManager.getInstance().getIndexManager().reIndex(subTask)
            ImportUtils.setIndexIssues(False)
            
            \# 2. Unteraufgabe "Realisierung"
            issueObject2 = issueFactory.getIssue()
            issueObject2.setProject(issue.getProject())
            issueObject2.setIssueTypeId("5") # default sub-task issue type
            issueObject2.setParentId(issue.getId())
            issueObject2.setFixVersions(issue.getFixVersions())
            issueObject2.setAffectedVersions(issue.getAffectedVersions())
            issueObject2.setPriority(issue.getPriority())
            issueObject2.setSummary("Entwicklertest")
            issueObject2.setAssignee(issue.getAssignee())
            subTask2 = issueManager.createIssue(authenticationContext.getUser(), issueObject2)
            subTaskManager.createSubTaskIssueLink(issue.getGenericValue(), subTask, authenticationContext.getUser())
            
            \# Update search indexes
            ImportUtils.setIndexIssues(True);
            ManagerFactory.getCacheManager().flush(CacheManager.ISSUE_CACHE, subTask)
            ComponentManager.getInstance().getIndexManager().reIndex(subTask)
            ImportUtils.setIndexIssues(False)
            
            
            1. Thomas, in your script after the line

              subTask2 = issueManager.createIssue(authenticationContext.getUser(), issueObject2)
              

              there is 'subTask' everywhere when it should be 'subTask2'.

              1. Unknown User (tkrug0210)

                Another copy-and-paste bug :-)

                Thanks, it works now.

      2. Unknown User (hmenzi)

        Alex, worked like a charm. Thank you for your quick reply!

      3. Unknown User (muhammad_rahman@cable.comcast.com)

        Hi Alex,

        I am trying to write the script in post function to create a new ticket and link back to current ticket instead of sub-task. I have created a issue link manager as 

         issueLinkManager = ComponentManager.getInstance().getIssueLinkManager()

        then I wrote : 

        linkedIssue = issueManager.createIssue(authenticationContext.getUser(), issueObject)

        //The above line creates a new ticket, but return a org.ofbiz.core.entity.GenericValue

        The following  createIssueLink() method requres the destination ticket id as a type "Long". 

        issueLinkManager.createIssueLink(issue.getId(),linkedIssue.getId(),10032,1,authenticationContext.getUser())

        Can any one tell me me how to get the ID of "linkedIssue" to pass to createIssueLink() as destination ticket ID?

        Code snippet:

        from com.atlassian.jira import ManagerFactory
        from com.atlassian.jira.issue.link import DefaultIssueLinkManager
        from org.ofbiz.core.entity import GenericValue;
        issueManager = ComponentManager.getInstance().getIssueManager()
        issueFactory = ComponentManager.getInstance().getIssueFactory()
        projectManager = ComponentManager.getInstance().getProjectManager()
        issueLinkManager = ComponentManager.getInstance().getIssueLinkManager() 
        authenticationContext = ComponentManager.getInstance().getJiraAuthenticationContext()
        issueObject = issueFactory.getIssue()
        #issueObject.setProject(issue.getProject())
        issueObject.setProject(projectManager.getProject(10358))
        issueObject.setIssueTypeId("1")
        issueObject.setSummary(issue.getSummary())
        linkedIssue = issueManager.createIssue(authenticationContext.getUser(), issueObject)
        issueLinkManager.createIssueLink(issue.getId(),linkedIssue,10032,1,authenticationContext.getUser())
        ImportUtils.setIndexIssues(True)
        ComponentManager.getInstance().getIndexManager().reIndex(linkedIssue)
        ImportUtils.setIndexIssues(False)

        Thank 

        1. Unknown User (brian)

          Though this isn't an example of how to do it with the JIRA Scripting Suite, you may want to check out the JIRA Link New Issue Operation plug-in.  They offer a very well supported plug-in that allows creation of a linked issue as a post-function.

        2. Unknown User (muhammad_rahman@cable.comcast.com)

          I was been able to create and link by modifying the line:  issueLinkManager.createIssueLink(issue.getId(),linkedIssue.getId(),10032,1,authenticationContext.getUser())

          to : issueLinkManager.createIssueLink(issue.getId(),issueObject.getId(),10032,1,authenticationContext.getUser())

          Thanks

      4. Unknown User (lhawkes)

        As an FYI, the behavior is slightly different when using Jira 4.2.2. Since there's no explicit call to get the CacheManager, this line:

        ManagerFactory.getCacheManager().flush(CacheManager.ISSUE_CACHE, subTask)
        

        has to be replaced with

        ManagerFactory.getCacheManager().flush(ManagerFactory.getCacheManager().ISSUE_CACHE, subTask)
        
  10. Unknown User (mahku)

    Hi,

    By following the installation guide, i have added the plugin. But getting this error : "Error creating issue: root cause: LookupError: no codec search functions registered: can't find encoding"

    Don't know whether i have made any mistake. However, this is the way that i followed:

    1) I have set the 'JAVA_OPTS' Environment Variable with "-Dpython.home=C:\jython2.5.0;".

    2) Then, i have downloaded and kept the 'jss-0.2.jar' plugin jar in the 'homejira/plugins/installed-plugins' and also i have copied the whole 'jython' folder from 'jss-0.2.jar' plugin jar to 'homejira/jss' folder.

    3) And modified "/WEB-INF/classes/actions.xml": i.e, changed "issue.EditSubTaskIssue" to "com.quisapps.jira.plugin.action.EditSubTaskIssue" and "issue.EditIssue" to "com.quisapps.jira.plugin.action.EditIssue".

    4) Then restarted Jira and added listener by giving the name as 'Jython' with class "com.quisapps.jira.plugin.listener.JythonListener".

    Then, i have created a sample project. And created a 'copy of default jira workflow' by giving a name to that workflow. Also created a sample screen with few fields.

    Finally added 'JythonValidator' with the following script(a sample for testing) to 'CreateIssue' transition in that particular workflow and made the workflow active.

    ============================================================

    # -- coding: UTF-8 --

    summary = issue.getSummary()
    project = issue.getProjectObject().name

    print 'summary is '+summary
    print 'project is '+project

    if summary == 'hi':
    result = False
    description = 'Hi : Error'
    invalid_fields['summary'] = u'Error description for Summary in 'project' project.'

    ============================================================

    Thanks in advance!

    1. Hi mahku,

      Instead of setting an environment variable on step 1, you should modify bin\setenv.bat file in JIRA installation folder (on Windows). All other steps look good.

      Alex

      1. Unknown User (mahku)

        Hi Alex,

        Thanks for reply.

        Still getting the same error: "Error creating issue: root cause: LookupError: no codec search functions registered: can't find encoding"

        -mahku.

        1. It still seems to me that the plugin can not find Jython installation. Do you have Jython installed in C:\jython2.5.0? And is there a line in your setenv.bat that reads like this? (just to be sure)

          set JAVA_OPTS=%JAVA_OPTS% -Dpython.home=C:/jython2.5.0 -Xms128m -Xmx768m -Datlassian.standalone=JIRA -Dorg.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER=true -Dmail.mime.decodeparameters=true

          (please note backslash changed to forward slash in path)

          BR, Alex

          1. Unknown User (mahku)

            Hi Alex,

            I have changed backslash to forward slash in path. But still getting the same error on the screen: "Error creating issue: root cause: LookupError: no codec search functions registered: can't find encoding".

            This is all for 'Create Issue' operation.

            A few lines from the Log file: 

            http://LENOVO:8080/secure/CreateIssueDetails.jspa [jira.plugin.workflow.JythonValidator] Unrecognized exception while executing Jyphon script: null
            LookupError: no codec search functions registered: can't find encoding

             at org.python.core.PyException.fillInStackTrace(PyException.java:70)
             at java.lang.Throwable.<init>(Throwable.java:181)
             at java.lang.Exception.<init>(Exception.java:29)
             at java.lang.RuntimeException.<init>(RuntimeException.java:32)
             at org.python.core.PyException.<init>(PyException.java:46)
             at org.python.core.PyException.<init>(PyException.java:43)
             at org.python.core.PyException.<init>(PyException.java:61)
             at org.python.core.codecs.lookup(codecs.java:80)
             at org.python.core.codecs.getEncoder(codecs.java:209)
             at org.python.core.codecs.encode(codecs.java:187)
             at org.python.core.PyString.str_encode(PyString.java:2429)
             at org.python.core.PyString.encode(PyString.java:2420)
            .........
            .........
            so on.

            -mahku.

            1. Hi mahku,

              Please open a Support Request at https://studio.plugins.atlassian.com/browse/JSS.
              Enclose your script into the following code:

              import sys
              import traceback
              
              try:
                  ''' your script goes here, don't forget the indentation '''
              except:
                  print __name__, sys.exc_info()[0], sys.exc_info()[1]
                  traceback.print_tb(sys.exc_info()[2])
              

              and attach it to the issue along with the JIRA log file after script execution.

              Alex

              1. Unknown User (mahku)

                Hi Alex,

                Thanks for your support in resolving the previous issue.

                Now i am facing a new problem while creating a subtask. Actually, i have to validate few fields. And later, depending on a particular field, i have to create a subtask. So, at first, i have come across how to validate fields. And now, i am trying to create a sample subtask.

                Displaying the following error:

                Error creating issue: root cause: Traceback (most recent call last): File "C:\Program Files\Atlassian\Application Data\JIRA\jss\jython\workflow\smpValid2.py", line 26, in <module> subTask = issueManager.createIssue(authenticationContext.getUser(), issueObject) at com.atlassian.jira.workflow.SimpleWorkflowManager.createIssue(SimpleWorkflowManager.java:197) at com.atlassian.jira.issue.managers.DefaultIssueManager.createIssue(DefaultIssueManager.java:355) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.atlassian.util.profiling.object.ObjectProfiler.profiledInvoke(ObjectProfiler.java:70) at com.atlassian.jira.config.component.SwitchingInvocationHandler.invoke(SwitchingInvocationHandler.java:28) at $Proxy33.createIssue(Unknown Source) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) java.lang.NullPointerException: java.lang.NullPointerException

                And following is the sample code that i followed (i went through the scripting samples of this page):

                ======================================

                # -- coding: UTF-8 --
                from com.atlassian.jira import ComponentManager
                from com.atlassian.jira import ManagerFactory
                from com.atlassian.jira.util import ImportUtils

                cfm =  ComponentManager.getInstance().getCustomFieldManager()

                custIssueField =  issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10000"))

                if custIssueField != None:
                 result = True
                 
                 issueManager = ComponentManager.getInstance().getIssueManager()
                 issueFactory = ComponentManager.getInstance().getIssueFactory()
                 authenticationContext = ComponentManager.getInstance().getJiraAuthenticationContext()
                 subTaskManager = ComponentManager.getInstance().getSubTaskManager()
                 
                 issueObject = issueFactory.getIssue()
                 issueObject.setProject(issue.getProject())
                 issueObject.setIssueTypeId("5") # default sub-task issue type
                 issueObject.setParentId(issue.getId())
                 
                 #setting general issue attributes such as summary, assignee etc
                 issueObject.setSummary("Test a sample")
                 
                 subTask = issueManager.createIssue(authenticationContext.getUser(), issueObject)
                 subTaskManager.createSubTaskIssueLink(issue.getGenericValue(), subTask, authenticationContext.getUser())
                 
                 # Update search indexes
                 ImportUtils.setIndexIssues(True)
                 ManagerFactory.getCacheManager().flush(CacheManager.ISSUE_CACHE, subTask)
                 ComponentManager.getInstance().getIndexManager().reIndex(subTask)
                 ImportUtils.setIndexIssues(False)

                =========================================

                -mahku.

                1. Unknown User (mahku)

                  Hi Alex,

                  I have resolved the above problem by enabling the subtasks and making few modifications in the code by going through the Jira API. However, Thanks for your support.

                  -mahku.

                  1. Hi mahku, thanks for the hint. I've spent some time trying to reproduce that, but with no luck - I had subtasks enabled in my Jira.

                    Alex

                2. Unknown User (sunderhill)

                  If I can ask, how was the previous issue resolved?  I am experiencing the same error message while trying to run a jython post-function.

              2. Unknown User (gopherr)

                Alex,

                I am getting the same "no codec" error message as mahku, but the only relevant bug report I could find (JSS-5 ) is closed and marked invalid with no comments.

                I see that mahku was able to resolve the issue by enabling sub-tasks, but I already have sub-tasks enabled and I am getting this error message on the Create Issue transition for a standard issue, not a sub-task.

                I also now see that you have not been able to reproduce the problem on your side, so please let me know if there is any information I can provide that may help.

                Thanks!

                Geoffrey

  11. Unknown User (ohingardail)

    Brilliant plugin! Helps me fix all the niggly bits that other plugins leave behind.

    For instance, the workflow 'Copy Issue Function' which is part of the 'CustomWare JIRA Utilities' plugin does exactly what it says it does; this includes copying reporter fields from the old records to the new, even if that reporter is not the person doing the copying. JSS easily fixes this by including this JSS script in the 'create' transition of the new record :

    authenticationContext = ComponentManager.getInstance().getJiraAuthenticationContext()
    issue.setReporter(authenticationContext.getUser())

    However, one thing I've not worked out yet is how to work around other (non-JSS) plugins' problems with copying fixVersion, affectedVersion and component values where the version or component doesn't already exist in the target record's project.

    So, what I need to write is some JSS in the source record's workflow that, before cloning itself to a target record :

    1. works out what the source version and components are (which is easy)

    sourceAffectedVersions = issue.getAffectedVersions
    sourceFixVersions = issue.getFixVersions
    sourceComponents = issue.getComponents

    2. 'knows' what the target project is (in my case this will always be the same)
    [ I assume the com.atlassian.jira.bc.project package is used for this, but I don't know how ]

    3. works out if the source versions and components already exist in the target project
    [ some kind of looping is clearly required here; I know the looping syntax but not the JIRA functions required ]

    4. adds new versions and components to the target project
    [ I don't know how to do this either ]

    This will allow the workflow 'Copy Issue Function' (or JSS, if I give up using 'CustomWare JIRA Utilities') to directly clone a record from a source project to a target record in a different project, including source version and component fields.

    Without this fix, if you attempt to clone version and component fields from one project into another that doesn't know what these versions or components are, the target fields just say 'unknown'. This isn't a JSS problem; I think it's expected JIRA functionality (on my system, at least); you're supposed to set up versions and components at a project level before assigning records to them - but I'm sure JSS could add these version and component values to the project automatically it if only I could work out how.

    I think the problem, for me, is that most JSS scripting examples are at the issue rather than the project level, so I have little precedent I can use.

    Any and all help would be absurdly gratefully received.

    • Adam.
    1. Hi Adam, I'll try to give you some clues.

      # get a Project object (JRA is a project key)
      project = ManagerFactory.getProjectManager().getProjectObjByKey("JRA")
      
      # list of existing components; note this is a Collection of GenericValue objects
      components = project.getComponents()
      
      # list of existing versions - in this case, it's a list of Version objects
      versions = project.getVersions()
      
      # to create a version
      ComponentManager.getInstance().getVersionManager().createVersion(name, releaseDate, description, projectId, scheduleAfterVersion)
      
      # to create a component
      ComponentManager.getInstance().getProjectComponentManager().create(name, description, lead, assigneeType, projectId)
      

      Just look into JIRA javadocs for more details:
      VersionManager.createVersion()
      ProjectComponentManager.create()

      BR, Alex

      1. Unknown User (ohingardail)

        Thanks, Alex.

        For what its worth, here is an example of a post-function script designed to ensure that the fixVersion, affectedVersion and component values in the source record (in project 'A') are in the target project (project 'B'), thus allowing the subsequent copying of version values from record in project 'A' to a record in project 'B'. The script is put in the post-functions workflow for a transition that subsequently creates the new (project 'B') record.

        from com.atlassian.jira import ManagerFactory
        
        versionManager = ComponentManager.getInstance().getVersionManager()
        componentManager = ComponentManager.getInstance().getProjectComponentManager()
        
        #Get target project ('QA') values
        QAproject = ManagerFactory.getProjectManager().getProjectObjByKey("QA")
        QAcomponents = QAproject.getComponents()
        QAversions = QAproject.getVersions()
        QAid = QAproject.getId()
        
        #Find source values from current issue (in 'dev' project)
        devAffectedVersions = issue.getAffectedVersions()
        devFixVersions = issue.getFixVersions()
        devComponents = issue.getComponents()
        
        #If dev fixversions not in QA, then add it
        for version in devFixVersions:
         versionName = version.getName()
        
         found = 0
         for QAversion in QAversions:
          if (QAversion.getName() == versionName):
           found = 1
           break
           
         if (found == 0):
          versionDate = version.getReleaseDate()
          versionDescription = version.getDescription() 
          versionManager.createVersion(versionName, versionDate, versionDescription, QAid, None)
        
        #If dev affectedversions not in QA, then add it
        for version in devAffectedVersions:
         versionName = version.getName()
          
         found = 0
         for QAversion in QAversions:
          if (QAversion.getName() == versionName):
           found = 1
           break
           
         if (found == 0):
          versionDate = version.getReleaseDate()
          versionDescription = version.getDescription()  
          versionManager.createVersion(versionName, versionDate, versionDescription, QAid, None)
          
        #if dev component not in QA, then add it
        for component in devComponents:
         #print str(component.getAllFields)
         componentName = component.getString('name')
         
         found = 0
         for QAcomponent in QAcomponents:
          if (QAcomponent.getString('name') == componentName):
           found = 1
           break
           
         if (found == 0):
          componentDescription = component.getString('description')
          componentLead = component.getString('lead')
          componentAssigneeType = component.getLong('assigneetype')  
          componentManager.create(componentName, componentDescription, componentLead, componentAssigneeType, QAid)

        If you want to work out what the key names to use for GenericValues (in the example above, the 'component' value was a GenericValue, so I needed to use "component.getString('description')" rather than "component.getDescription()") then you can use the "print str(component.getAllFields)" construct to dump the key-value pairs out to {JIRA_HOME}/logs/catalina.out; in this example they looked like "[GenericEntity:Component][id,10003][project,10020][description,null][name,CNS][lead,null][assigneetype,0][url,null]" which was enough for me to work out how to extract component names etc.

        Hope this helps someone.

        1. Unknown User (brian)

          Extremely nice work!  Thanks for sharing!

  12. Unknown User (hmenzi)

    I want to set the assignee of an issue to the value of a user picker custom field. Below is the code I have so far. The script fails on issueObject.getCustomFieldValue(manager) with a null pointer exception. Can someone point me in the right direction?

    # Set the Assignee to the Manager
    from com.atlassian.jira import ManagerFactory
    from com.atlassian.jira import ComponentManager
    
    issueManager = ComponentManager.getInstance().getIssueManager()
    issueFactory = ComponentManager.getInstance().getIssueFactory()
    customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
    
    manager = customFieldManager.getCustomFieldObject("customfield_10092")
    
    #get assigneeManager on the issue
    issueObject = issueFactory.getIssue()
    assigneeManager = issueObject.getCustomFieldValue(manager)
    
    #set to assignee
    issueObject.setAssignee(assigneeManager)
    
    1. Hi Hans,

      If you are trying to write a postfunction script, instead of

      #get assigneeManager on the issue
      issueObject = issueFactory.getIssue()
      assigneeManager = issueObject.getCustomFieldValue(manager)
      

      you should use this

      #get assigneeManager on the issue
      assigneeManager = issue.getCustomFieldValue(manager)
      
      # and then to set an assignee
      issue.setAssignee(assigneeManager)
      

      JSS passes some context to the script, and issue variable is set the current issue for which the postfunction is being executed.

      BR, Alex

    2. Unknown User (mahku)

      Hi Hans,

      In this line of code, that is, 'issueObject = issueFactory.getIssue()', we will get a blank issue object of type 'com.atlassian.jira.issue.MutableIssue'(an interface) which extends 'com.atlassian.jira.issue.Issue'(an interface). As it gives us a blank issue object, we can't get any data/info.

      If you want any data/info from current issue, then you can directly use the context variable 'issue' in your code. For example, replace 'assigneeManager = issueObject.getCustomFieldValue(manager)' line with 'assigneeManager = issue.getCustomFieldValue(manager)' line. Also replace 'issueObject.setAssignee(assigneeManager)' line with 'issue.setAssignee(assigneeManager)' line. Please observe that i have just replaced 'issueObject' with context variable 'issue'. Finally you can remove 'issueObject = issueFactory.getIssue()' line, as there is no use of this line so far.

      This solution works fine only with current issue. But if you want to change the existing issues or create new issues, then you have to follow some other steps/ways.

      Issue objects may be obtained using 'IssueManager' or 'IssueFactory'. If you want, you can go through  'com.atlassian.jira.issue.IssueManager' and 'com.atlassian.jira.issue.IssueFactory' interfaces in Jira Latest API.

      I hope it helps you.

      Edit: Oops! Sorry, i haven't seen the reply from 'Alex'.

      While i was working on tasks/issues using JSS, I used to post the issues and receive replies from 'Alex'. Finally resolved those few tasks/issues. Nice support.

      However, don't get confused with the solutions. Both are same.

      BR, mahku.

    3. Unknown User (hmenzi)

      Thanks to both Alex and mahku. I now have it working properly and have a better understanding.

  13. Unknown User (kewwordtest)

    Hi Alex,

    jss is perfect. Now, I have a problem that I don't know how to debug. I worte a script but it didn't work. And nothing could be found at catalina.out.

    Best Regrads.

    1. Hi,

      Actually the only way to debug is to print out some intermediate values and watch console output (particularly catalina.out in JIRA Standalone; I use tail -f catalina.out under Linux). Also you can use injected log variable, but unless you have some special log configuration it's all the same.
      I suggest putting one of these in the beginning of your script just to be sure the script is executed:

      print "Hello world, this is ", issue
      # or
      log.debug(issue)
      

      The next step is using try and catch to get more info if smth goes wrong:

      import sys
      import traceback
      
      try:
        # do smth
        1 / 0 # this causes exception to be thrown
      except:
        # this code prints detailed info about the exception
        print sys.exc_info()[0], sys.exc_info()[1]
        traceback.print_tb(sys.exc_info()[2])
      

      Hope this helps.

      BR, Alex

      1. Unknown User (kewwordtest)

        Thank you.

  14. Unknown User (daregazi)

    Hi Alex,

    I would like to thank you for JSS. It's great!

    Now imagin that I have 4 steps in my workflow. From step 1 and 2 and 3 there is a transition to step 4 say 'Goto4'. From step 4 also there are transitions to go back to those steps e.g. Goto1, Goto2, Goto3 however from step 4 I want to be able to go exactly to the original step that it came from. For example if the transition was from step 1 to step4, in return in step 4 and on transition Goto1 I want to be able to check if the original step was step 1 then to show only Goto1. Without such control, all Goto1, Goto2, Goto3 would get displayed to the user which is not what I want!

    What is the best practice to do it?

    thanks

    1. Hi Beheshteh,

      I use JIRA Misc Workflow Extensions plugin, it contains Previous Status condition - that's exactly what you need.

      BR, Alex

      1. Unknown User (daregazi)

        Great!

        Helped me a lot! Exactly what we needed. Thanks.

  15. Unknown User (xerocube)

    Hi Alex,

    I am new to JSS, but it appears that it can solve my problem. In our workflow, we want to be able to check an issue on creation for it's Fix version. If the Fix Version is "unknown", we want to automatically set that field to the next project version set for release.

    My psuedocode is as follows:

    # Get the current Fix Version for the issue
    curr_fixversion = issue.getFixVersions()
    
    # list of existing versions - in this case, it's a list of Version objects
    versions = project.getVersions()
    
    # TODO - Find the next version slated for release in the versions collection
    
    # Check the curr_fixversion for Unknown
    #     If unknown, then set Fix version to next version
    if (curr_fixversion == ''):
        issue.setFixVersions(\[\])
    

    I am not certain how to iterate through the versions collection to find the next slated release, or if that is even possible.

    Could you please provide some assistance/advise?

    Thanks!

    1. Unknown User (hmenzi)

      Taking a look at this for reference, I would try something like this:

      for version in versions:
      	if !version.isReleased(): issue.setFixVersions(version)
      

      Hope that points you in the right direction.

      Hans

    2. Unknown User (hmenzi)

      Taking a look at this for reference, I would try something like this:

      for version in versions:
      	if !version.isReleased(): issue.setFixVersions(version)
      

      Hope that points you in the right direction.

      Hans

  16. Unknown User (brian)

    We are currently using JIRA 4.0.2 and used JSS version 0.2.  Mentioned here was that you could use JSS to copy a parent's components and fix version/s. This is all the Jython code I have in the sub-task workflow's create transition's post function, is this correct? I've tested one of the validations mentioned in the JSS validation code snippits so I know that I have installed Jython and the JSS plug-in correctly, but this snippet doesn't appear to be doing anything.

     	issue.setComponents(issue.getParentObject().getComponents())
     	issue.setFixVersions(issue.getParentObject().getFixVersions())
    

    Any help to be had out there?

  17. Unknown User (dariam)

    Hi all!!

    I'm trying to make a postfunction which fills a custom field (Department) depending on one of the user's groups (starting with GD_). The custom field is a "Select List".
    Something is wrong because the custom field is not updated.

    Any help??

    Thx!!!

    #Starting...
    issueManager = ComponentManager.getInstance().getIssueManager()
    customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
    authenticationContext = ComponentManager.getInstance().getJiraAuthenticationContext()
    
    #Getting user and user's groups
    jirauser = authenticationContext.getUser()
    jiragroups = jirauser.getGroups()
    
    #Getting custom field object
    departmentcf = customFieldManager.getCustomFieldObject("customfield_10050")
    
    
    for jiragroup in jiragroups:
        if jiragroup.find('GD_') == 0:
            #Getting jiragroup length
            longi = len(jiragroup)
            #Removing GD_ prefix
            jiradept = jiragroup[3:longi]
            #Setting Department value
            issue.setCustomFieldValue(departmentcf,jiradept)
            issue.store()
    
    
    1. Unknown User (e.kubascikova@corag.sk)

      Hi,

      try this

      actionParams = EasyMap.build("issue", issue.getGenericValue(), "issueObject", issue, "remoteUser", authenticationContext.getUser(), "dispatchEvent", 0)
      CoreFactory.getActionDispatcher().execute(ActionNames.ISSUE_UPDATE, actionParams)
      
      
  18. Adam, Brian, David,

    May I give you a little debugging hint: use simple print command in any case when you are not sure. Python is a scripting language and thus doesn't have any compile-time type checking. That's why sometimes it is very hard to know what is the actual type and value the method returns. So my advise is: use print often and look to JIRA log for its output. It will save you a lot of time.

    BR, Alex

    1. Unknown User (brian)

      Will do, thanks Alex!

  19. Unknown User (hmenzi)

    I am trying to automatically perform a workflow action if a released version is affected or not. I think the problem I am having is with the workflow transition utility. I get no errors or warnings in the logs. Can someone point me in the right direction? Thanks in advance.

    from com.atlassian.jira.project.version import VersionManager
    from com.atlassian.jira.util import JiraUtils
    from com.atlassian.jira.workflow import WorkflowTransitionUtil
    from com.atlassian.jira.workflow import WorkflowTransitionUtilImpl
    from com.opensymphony.workflow.loader import ActionDescriptor
    
    vm =  ComponentManager.getInstance().getVersionManager()
    wm = ComponentManager.getInstance().getWorkflowManager()
    jac= ComponentManager.getInstance().getJiraAuthenticationContext()
    wtu= JiraUtils.loadComponent(WorkflowTransitionUtilImpl)
    
    versions = issue.getAffectedVersions()
    releasedVersion = 0
    
    # Loop through versions
    for it in versions:
    	if it.isReleased(): releasedVersion = 1
    
    wtu.setIssue(issue)
    wtu.setUsername(jac.getUser().name)
    		
    if releasedVersion == 0 :
    	# Transition to "Dev Mgr Review" status
    	wtu.setAction(21)
    else :
    	# Transition to "Triage" status
    	wtu.setAction(11)
    
    # validate and transition issue
    wtu.validate()
    wtu.progress()
    
  20. Unknown User (wufei)

    Hi,

    I've installed the Jira 4.1 and the Scripting Suite plugin recently and I'm trying to script something to update a custom field value, but I'm encountering some problems.

    I was initially using the issue.setCustomFieldValue(customFieldObject1, 'None') to update the custom field value. It seems to work since I see the change in the History and the EAR page is refreshed with the new value.

    The problem is that I read from this link (http://confluence.atlassian.com/pages/viewpage.action?pageId=160835) that setCustomFieldValue does not actually set the custom field value of an issue. The doesn't apply the change to the database. To update a custom field value on an issue, I need to use the method updateValue on the CustomField object itself.

    Writing this in Java would be simple since there is a sample code on that page, but in Jython, it doesn't seem to recognize the ModifiedValue constructor method. The weird thing is that on this page, they are only using setCustomFieldValue and there are no example using the ModifiedValue class constructor.

    I would appreciate to have a sample code that would show me how to call the updateValue method with the ModifiedValue constructor in the context of Jira Scripting Suite.

    Thanks in advance,

    Wufei

    1. Hi Wufei,

      This is a bit tricky, but in Jython postfunction you should really use setCustomFieldValue. This works because you modify the issue object before it is actually committed to the database. It's just like setting the field's value in the "Create Issue" or "Edit Issue" page. And this won't work if you, for instance, try to move the postfunction beyond "Creates the issue originally." in the Create Issue action, because issue.setCustomFieldValue() really does not modify the database; if you are out of Jython context - you should use the method from that article.

      BR. Alex

      1. Unknown User (wufei)

        Thanks Alexander for your fast reply. I really appreciate it.

        I have some other issues. I've installed JSS 0.3.1 and Jira Standalone 4.1.1.

        1- I'm wondering if there is a way to add JSS script to validate some fields when the user is Editing or Creating a specific type of issue before updating the changes?

        2- I'm wondering if there is a way to add JSS post-function script when the user is Editing or Creating a specific type of issue?

        I've read the thread (http://forums.atlassian.com/thread.jspa?messageID=257343226) related to this issue, but since I want my script to be specific to a particular type of issue instead of applying it globally and because I want to add this on creation also, I thought I may get a different answer.

        Thanks in advance

        Wufei

        1. Hi Wufei,

          Both on-edit validator and on-edit post-function are global, that is, you should check issue type, project and other attributes inside your script.

          On-create validators and postfunctions are defined in the workflow. If you use a single workflow for many issue types, you should also check issue attributes inside your script.

          BR, Alex

  21. Unknown User (wufei)

    Hi,

    With the JSS "Edit Postfunction", how can I know if a specific field has been modified?

    The context is that I need to know if the "Description" field value has been modified during the any issue editing to automatically add a new Comment on its parent issue. If the Description didn't change during the Edit step, then no Comment should be added to the parent issue.

    How can you do this?

    Thanks in advance,

    1. I suppose you can get the original unmodified issue object by calling

      ManagerFactory.getIssueManager().getIssueObject(issue.getId())

      and then compare descriptions.
      BR, Alex

      1. Unknown User (wufei)

        I finally did this in my post-function, hoping that it may help someone else one day:

        modifiedValues = issue.getModifiedFields()

        if modifiedValues.containsKey("description"):

          modifiedDescrption = modifiedValues.get("description")

          if modifiedDescrption.getOldValue() != modifiedDescription.getNewValue():

            parentIssue = issue.getParentObject()

            commentManager = ComponentManager.getInstance().getCommentManager()

            comment = "Sub-issue's Description from \"" + issue.getSummary() + "\" has been updated to \"" + modifiedDescription.getNewValue() + "\""

            authenticationContext = ComponentManager.getInstance().getJiraAuthenticationContext()

            commentManager.create(parentIssue, authenticationContext.getUser().toString(), comment, True)

        Thanks again for your reply! :)

  22. Unknown User (tkrug0210)

    Would it be possible to contact a database and update custom fields based on sql resultsets and vice versa?

    1. Hi Thomas,

      I think this can be done with JDBC, but I can't provide any example right away.

      Alex

      1. Unknown User (tkrug0210)

        Hi Alex,

        i found a small example:

        from java.lang import *
        from java.sql import *
        driverName="com.mysql.jdbc.Driver"
        Class.forName(driverName)
        url = "jdbc:mysql://LENOVO/mydatabase?user=myuser&password=mypassword"
        con = DriverManager.getConnection(url)
        stmt = con.createStatement()
        sql = "select column from table where (column2='%s')" % 'columnvalue'
        rs = stmt.executeQuery(sql)
        list = []
        while (rs.next()):
            print rs.getString(1)
        rs.close()
        stmt.close()
        con.close()
        

        Executing this gives me a ClassNotFound Exception for com.mysql.jdbc.Driver. Do you know where I have to place the jar for Jython to find it?
        Simply copying it to the lib folder does not resolve this issue.

        Thomas

        1. Hi Thomas,

          Try to put it into tomcat's lib or common/lib folder. Furthermore, JIRA 4.1 seems to have mysql driver bundled into distribution. Which version of JIRA do you use?

          Alex

          1. Unknown User (tkrug0210)

            Hi Alex,

            I am using Jira 4.0.1.

            Jira itself uses a MySQL Database and thus the driver is already in tomcats lib.

            I extracted the JAR on put it the foldes directly into the /python/lib folder, without effect.
            The following exception is thrown:

            root cause: Traceback (most recent call last): File "d:\jira\data\jss\jython\workflow\mysql_test.py", line 12, in <module> Class.forName(driverName) at org.apache.felix.framework.searchpolicy.R4SearchPolicyCore.findClass(R4SearchPolicyCore.java:198) at org.apache.felix.framework.searchpolicy.R4SearchPolicy.findClass(R4SearchPolicy.java:45) at org.apache.felix.framework.searchpolicy.ContentClassLoader.loadClass(ContentClassLoader.java:109) at java.lang.ClassLoader.loadClass(ClassLoader.java:248) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:169) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) java.lang.ClassNotFoundException: java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

            root cause: Traceback (most recent call last): File "d:\jira\data\jss\jython\workflow\mysql_test.py", line 12, in <module> Class.forName(driverName) at org.apache.felix.framework.searchpolicy.R4SearchPolicyCore.findClass(R4SearchPolicyCore.java:198) at org.apache.felix.framework.searchpolicy.R4SearchPolicy.findClass(R4SearchPolicy.java:45) at org.apache.felix.framework.searchpolicy.ContentClassLoader.loadClass(ContentClassLoader.java:109) at java.lang.ClassLoader.loadClass(ClassLoader.java:248) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:169) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) java.lang.ClassNotFoundException: java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

          2. Unknown User (tkrug0210)

            Classpath Problem is solved. The JAR has to be placed within your JSS Jar (WEB-INF/Lib) in order for Apache Felix to find it.

            1. Thomas, thanks for the info!

            2. Unknown User (justforthee)

              Hi Thomas,

              I'm still stuck with the mysql jar classpath problem in JSS. I have tried putting the jdbc jar in everywhere, but no luck. By the way, I can call jdbc in jython's console because the jar was defined in classpath before executed. And surely jdbc driver has been in tomcat's lib since I can call jdbc in a JSP page within JIRA.

              Can you please explain exactly which folder the jar should be put in? I'm using JIRA4.0.0 and jython2.5.0 in Windows2003, and trying to get JSS working in post function where I want to connect MYSQL database... Thanks in advance!

  23. Unknown User (gturner)

    I have a workflow where a required field can start out at an initial value if submitted thru an external interface, but I want to make sure it never has that value from here on out.  I can place checks in each of the subsequent transitions, but I'd also like to validate it in the edit screen as well.  My experience with this plugin is showing that the issue object in the global 'edit_validator.py' file doesn't contain the changes made in the edit screen itself.  I'm using Jira v4.0.  The same code works great in individual workflow tasks.  Anyone else have any luck using this file?

    1. Hi Greg,

      There is a difference between the context of the workflow validator and the one of edit validator. In the edit validation script you should check parameters map to get values from the screen. You can compare with issue object which is a original one to find changed values.

      BR, Alex

  24. Unknown User (niki89g)

    Hi,

    I've only just started getting my hands dirty with JSS. I've tried Thomas's code to generate sub-tasks on the inititation of a workflow..but it doesn't seem to be doing anything at all? Will this be because i've just included this in inline script instead of a .py file?

    Also, How will Jira know that this post function needs to be fired off only when a particular workflow is initiated and not for every workflow transition? Pardon my possible ignorance. I've only installed JSS yesterday, and have been trying to achieve the automatic generation of sub-tasks when a workflow is initiated.

    Any help will be much appreciated.

    1. Hi Nikhita,

      If you want some script to be executed on issue creation, then you should add it to Create Issue action in you workflow. You can find it by navigating to the first status (usually Open) and looking to the incoming actions.

      BR, Alex

  25. Unknown User (hitthedrum)

    Hi there!

    I am all new to this plugin and wanted to ask, if it is possible to validate worklog entries (any fields)?

    Examples:

    1. if anyone enters 3h 55m to the "Time Spent" field I want to change the value to 4h  or
    2. if anyone enters more than 8h I want to show up an error message like "Just 8 hours per entry allowed".
    3. if anyone enters values into "Set estimated time remaining" or "Reduce estimated time remainin" I want to check, if modulo 4h = 0

    Thx and regards!

    Marc

    1. Hi Marc, 

      I think the only thing possible with JSS now is to add a listener for Issue Work Logged event (you can do some updates in that listener script), but there is no way for validating worklog values being entered.

      Alex

      1. Unknown User (toini)

        Hi!

        I would need perform some custom operations after a person has logged work on an issue. How can I add a listener for an Issue Work Logged event?

        Toni

  26. Unknown User (gisela.sn)

    Hi Alexander,

    could you help to create a code to post a work log?

    I find this code but I don´t know how to make in phyton...

    jiraServiceContext = new JiraServiceContextImpl(user)
    worklogService = (WorklogService) ComponentManager.getComponentInstanceOfType(WorklogService.class)
    worklogService.hasPermissionToCreate(jiraServiceContext, issue)

    worklog = worklogService.validateCreate(jiraServiceContext, issue, tsValue, new Date(), "Work logged while resolving issue", null, null)
    worklogWithRemainingEstimate = new WorklogService.WorklogNewEstimateResult(worklog, 0)
    worklogService.createWithNewRemainingEstimate(jiraServiceContext, worklogWithRemainingEstimate, true)

  27. Unknown User (dan.sexton)

    How can you use today's date and store it into a customfield of date data type?

    This is what I have:

    from com.atlassian.jira import ManagerFactory
    import com.atlassian.jira.issue.CustomFieldManager
    import datetime
    from datetime import date

    today = date.today()

    if date.weekday(today) < 3:
        nextSaturday = today + datetime.timedelta(days=(5-today.weekday()))
    elif date.weekday(today) < 6:
        nextSaturday = today + datetime.timedelta(days=(5-today.weekday()), weeks=1)
    else:
        nextSaturday = today + datetime.timedelta(days=-1, weeks=1)
    toTime = time.mktime(nextSaturday.timetuple())
    final = time.strftime("%Y-%m-%d %H:%M:%S.000000000", time.localtime(toTime))

    customFieldManager = ComponentManager.getInstance().getCustomFieldManager()

    sprintDateField = customFieldManager.getCustomFieldObjectByName("Sprint Date")
    issue.setCustomFieldValue(sprintDateField,final)

    1. Hi Dan,

      This may be a little bit late, but nevertheless - I think you should convert your final date to java.util.Date before setting the value to custom field.

      Alex

      1. Unknown User (robert)

        Hi Alex,

        How to convert final date to java.util.Date?

        thanks

  28. Unknown User (cdnexus)

    Any idea why this attempt to copy two custom fields from the parent issue in a post function fails? It runs but apparently has no effect.

     from com.atlassian.jira.issue import ModifiedValue
    from com.atlassian.jira.issue.util import DefaultIssueChangeHolder
    if (issue.getParentId() > 0):
     parentIssue = issue.getParentObject()
     customFieldName = "Reviewer" 
     componentManager = ComponentManager.getInstance()
     customFieldManager = componentManager.getCustomFieldManager()
     
     customField = customFieldManager.getCustomFieldObjectByName( customFieldName )
     fieldLayoutItem = ComponentManager.getInstance().getFieldLayoutManager().getFieldLayout(issue).getFieldLayoutItem( customField )
     
     parentValue = customField.getValue( parentIssue )
     currentValue = customField.getValue( issue )
     
     # Create a modified value object with the old value and the new value
     modifiedValue = ModifiedValue( currentValue, parentValue )
     
     # Update the value
     customField.updateValue( fieldLayoutItem, issue , modifiedValue, DefaultIssueChangeHolder() )
     
     parentIssue = issue.getParentObject()
     customFieldName = "Author" 
     componentManager = ComponentManager.getInstance()
     customFieldManager = componentManager.getCustomFieldManager()
     
     customField = customFieldManager.getCustomFieldObjectByName( customFieldName )
     fieldLayoutItem = ComponentManager.getInstance().getFieldLayoutManager().getFieldLayout(issue).getFieldLayoutItem( customField )
     
     parentValue = customField.getValue( parentIssue )
     currentValue = customField.getValue( issue )
     
     # Create a modified value object with the old value and the new value
     modifiedValue = ModifiedValue( currentValue, parentValue )
     
     # Update the value
     customField.updateValue( fieldLayoutItem, issue , modifiedValue, DefaultIssueChangeHolder() )
    

    Thanks for your time.

    1. Hi Chris,

      Try a simple issue.setCustomFieldValue(customField,newValue) call to set a value of custom field in a postfunction. Note that your postfunction should be called before "Update change history for an issue and store the issue in the database.".

      Alex

      1. Unknown User (cdnexus)

        Posting for future searchers: This is performed on the Subtask's create event post-events:Updates custom fields from the parent successfully:Thanks for your help Alex.

        from com.atlassian.jira.issue.util import DefaultIssueChangeHolder
        if (issue.getParentId() > 0):
         # Set Reviewer from Parent
         parentIssue = issue.getParentObject()
         customFieldName = "Reviewer"
         componentManager = ComponentManager.getInstance()
         customFieldManager = componentManager.getCustomFieldManager()
         
         customField = customFieldManager.getCustomFieldObjectByName( customFieldName )
         parentValue = customField.getValue( parentIssue )
         
         issue.setCustomFieldValue(customField, parentValue )
         # Set Author from Parent 
         parentIssue = issue.getParentObject()
         customFieldName = "Author"
         componentManager = ComponentManager.getInstance()
         customFieldManager = componentManager.getCustomFieldManager()
         
         customField = customFieldManager.getCustomFieldObjectByName( customFieldName )
         parentValue = customField.getValue( parentIssue )
         
         issue.setCustomFieldValue(customField, parentValue )
        
  29. Unknown User (cdnexus)

  30. Unknown User (gisela.sn)

    Hi, I´m trying to use the setComponents to copy the subtasks components to the parent issue, but don´t work, I found some samples but no one work, anyone know how to update this field? Other updates works, like setAssignee.

    import com.atlassian.jira.ComponentManager

    compManager = ComponentManager.getInstance()

    IssueManager = compManager.getIssueManager()

    commentManager = compManager.getCommentManager()

    IssueManager = compManager.getIssueManager()

    issuepai = issue.getParentObject()

    issuepai = IssueManager.getIssueObject(issuepai.getKey())

    subtasks = issuepai.getSubTaskObjects()

    componentes = issue.getComponents()

    issuepai.setAssignee(issue.getAssignee())

    issuepai.store()

    issuepai.setComponents(componentes)

    issuepai.store()

    1. Hi Gisela,

      This is actually not a good way of updating issues that are not in context. You can use setters on issue (and you don't even need to call store()) in a post-function, but you should find some other proper way of updating issuepai. In this case you've lost change history and search index becomes out of sync.

      Alex

  31. Unknown User (speimann@curtisswright.com)

    Folks,

    I am trying to build a transition that selects between one of two states depending on a logic tree based on various field values (both old and new).

    My understanding is that JIRA Scripting Suite is a very good way to accomplish this goal.

    The only example I see is the one that Hans posted on Jun 02.  I assume that this is being placed into a transition "post function".

    Is that the best way to go about implementing a computed transition?

    Thank You All,
    Scott

  32. Unknown User (gongqifang)

    Hi,Alex

    I have add a validator use  Jython Validator,"size" is a customfield of type Text Field(<255 characters) .I thought this might work

    from com.atlassian.jira import ComponentManager
    cfm = ComponentManager.getInstance().getCustomFieldManager()
    size=issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10057"))
    if not size:
    result = False
    description="Field FFFF should contain some characters"
    invalid_fields\['customfield_10057'\] = u"This field should not be empty"
    else:
    result = True
    

    which does not. Can you help me with the correct code?

    The error thrown is

    root cause: SyntaxError: ("mismatched input 'result' expecting INDENT", ('<string>', 5, 0, 'result = False\n'))

    1. Unknown User (speimann@curtisswright.com)

      gonggifang,

      You need to indent the consequent and alternate of the conditional statement (line 4)

      from com.atlassian.jira import ComponentManager
      cfm = ComponentManager.getInstance().getCustomFieldManager()
      size=issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10057"))
      if not size:
         result = False
         description="Field FFFF should contain some characters"
         invalid_fields\['customfield_10057'\] = u"This field should not be empty"
      else:
         result = True

      Good Luck!
      Scott

      1. Unknown User (gongqifang)

        Yes! It works,

        Thanks a lot, Scott.

  33. Unknown User (speimann@curtisswright.com)

    Folks,

    I thought my IT people had JYthon installed, but apparently not. Still, I need to use JYthon to do some conditional updates in a post-function, based on issue attributes.

    What I want to do is clear pairs of fields, based upon one of the values being 'Reject'.

    In my sample, the ss1 through ss5 fields are select-lists, and the su1 through su5 fields are user-pickers.

    Will this work, especially the string comparisons and the "null" assignments?

    ##
    ##  Clear only the rejections
    ##
    
    ##--general initialization
    from com.atlassian.jira.issue.util import DefaultIssueChangeHolder
    accept = 'Accept'
    reject = 'Reject'
    
    ##--get the field manager
    componentManager = ComponentManager.getInstance()
    customFieldManager = componentManager.getCustomFieldManager()
    
    ##--get the fields
    cfm = customFieldManager
    ss1 = cfm.getCustomFieldObjectByName('Signoff-status 1')
    su1 = cfm.getCustomFieldObjectByName('Signoff-user 1')
    ss2 = cfm.getCustomFieldObjectByName('Signoff-status 2')
    su2 = cfm.getCustomFieldObjectByName('Signoff-user 2')
    ss3 = cfm.getCustomFieldObjectByName('Signoff-status 3')
    su3 = cfm.getCustomFieldObjectByName('Signoff-user 3')
    ss4 = cfm.getCustomFieldObjectByName('Signoff-status 4')
    su4 = cfm.getCustomFieldObjectByName('Signoff-user 4')
    ss5 = cfm.getCustomFieldObjectByName('Signoff-status 5')
    su5 = cfm.getCustomFieldObjectByName('Signoff-user 5')
    
    ##--signature 1
    if (reject == issue.getCustomFieldValue(ss1)) :
      issue.setCustomFieldValue(ss1, null)
      issue.setCustomFieldValue(su1, null)
    
    ##--signature 2
    if (reject == issue.getCustomFieldValue(ss2)) :
      issue.setCustomFieldValue(ss2, null)
      issue.setCustomFieldValue(su2, null)
    
    ##--signature 3
    if (reject == issue.getCustomFieldValue(ss3)) :
      issue.setCustomFieldValue(ss3, null)
      issue.setCustomFieldValue(su3, null)
    
    ##--signature 4
    if (reject == issue.getCustomFieldValue(ss4)) :
      issue.setCustomFieldValue(ss4, null)
      issue.setCustomFieldValue(su4, null)
    
    ##--signature 5
    if (reject == issue.getCustomFieldValue(ss5)) :
      issue.setCustomFieldValue(ss5, null)
      issue.setCustomFieldValue(su5, null)
    
    1. Hi Scott,

      That should work, but in python (and jython as well) you should use None instead of null.

      BR, Alex

      1. Unknown User (speimann@curtisswright.com)

        Good Morning Alex,

        Thanks for looking through that for me.  I appreciate the second set of eyes, as I'm still working with my I.T. folks to get the server configured.

        Cheers!
        Scott

  34. Unknown User (gongqifang)

    hi, Alex

    I have wrote a postfunction to change the linked status during an transition,

    from com.atlassian.jira import ComponentManager
    from com.atlassian.jira.util import JiraUtils
    from com.atlassian.jira.workflow import WorkflowTransitionUtilImpl
    cfm=ComponentManager.getInstance().getCustomFieldManager()
    curuser=ComponentManager.getInstance().getJiraAuthenticationContext().getUser()

    reviewer1=issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10049"))
    reviewer1_output=issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10055"))
    reviewer2=issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10153"))
    reviewer2_output=issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10152"))
    if curuser==reviewer1:
       if reviewer1_output=="pass":
          if reviewer2 and reviewer2_output!="pass":
             workflowTransitionUtil = JiraUtils.loadComponent(WorkflowTransitionUtilImpl)
             workflowTransitionUtil.setAction(211)   ====>go to another status "fixed"
             workflowTransitionUtil.setIssue(issue)
             workflowTransitionUtil.setUsername(curuser.getName())
             workflowTransitionUtil.progress()    
       else:
          workflowTransitionUtil = JiraUtils.loadComponent(WorkflowTransitionUtilImpl)
          workflowTransitionUtil.setAction(151)     =====>go to another status "analysis"
          workflowTransitionUtil.setIssue(issue)
          workflowTransitionUtil.setUsername(curuser.getName())
          workflowTransitionUtil.progress()   

    elif curuser==reviewer2:
       if reviewer2_output=="pass":
          if reviewer1 and reviewer1_output!="pass":
             workflowTransitionUtil = JiraUtils.loadComponent(WorkflowTransitionUtilImpl)
             workflowTransitionUtil.setAction(211)
             workflowTransitionUtil.setIssue(issue)
             workflowTransitionUtil.setUsername(curuser.getName())
             workflowTransitionUtil.progress()   

       else:
          workflowTransitionUtil = JiraUtils.loadComponent(WorkflowTransitionUtilImpl)
          workflowTransitionUtil.setAction(151)
          workflowTransitionUtil.setIssue(issue)
          workflowTransitionUtil.setUsername(curuser.getName())
          workflowTransitionUtil.progress()

     It does not work. Can you help me with the correct code?

    The error thrown is

    root cause: Traceback (most recent call last): File "<string>", line 20, in <module> at com.atlassian.jira.workflow.OSWorkflowManager.getWorkflow(OSWorkflowManager.java:308) at com.atlassian.jira.permission.PermissionContextImpl.getRelevantStepDescriptor(PermissionContextImpl.java:69) at com.atlassian.jira.permission.WorkflowPermissionFactory.getWorkflowPermissions(WorkflowPermissionFactory.java:30) at com.atlassian.jira.security.WorkflowBasedPermissionManager.hasPermission(WorkflowBasedPermissionManager.java:75) at sun.reflect.GeneratedMethodAccessor368.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.atlassian.util.profiling.object.ObjectProfiler.profiledInvoke(ObjectProfiler.java:70) at com.atlassian.jira.config.component.SwitchingInvocationHandler.invoke(SwitchingInvocationHandler.java:28) at $Proxy32.hasPermission(Unknown Source) at com.atlassian.jira.issue.fields.AttachmentSystemField.isShown(AttachmentSystemField.java:104) at com.atlassian.jira.issue.fields.screen.AbstractFieldScreenLayoutItem.isShown(AbstractFieldScreenLayoutItem.java:82) at com.atlassian.jira.issue.fields.screen.FieldScreenRenderLayoutItemImpl.isShow(FieldScreenRenderLayoutItemImpl.java:68) at com.atlassian.jira.workflow.WorkflowTransitionUtilImpl.progress(WorkflowTransitionUtilImpl.java:262) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: Issue Type for issue with id '10150' is null.

    It seems that Issue Type is NULL,but actual the Issue Type is not null, the valuse is "Bug"

  35. Unknown User (tkrug0210)

    Hi,

    I am currently trying to modify the watcher list via jython script. The script looks like this:

    from com.atlassian.jira import ComponentManager
    from org.ofbiz.core.entity import GenericValue
    
    userUtil = ComponentManager.getInstance().getUserUtil()
    
    watcherUtil = ComponentManager.getInstance().getWatcherManager()
    
    user=userUtil.getUser("testuser")
    
    watcherUtil.startWatching(user, issue.getGenericValue())
    
    

    This code throws a NullPointerException

    com.atlassian.core.ofbiz.association.DefaultAssociationManager.createAssociation(DefaultAssociationManager.java:84) at com.atlassian.jira.issue.watchers.DefaultWatcherManager.startWatching(DefaultWatcherManager.java:111) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) java.lang.NullPointerException: java.lang.NullPointerException

    Can anybody help me on this?

    1. Possibly there is no user with login testuser.

      Alex

      1. Unknown User (tkrug0210)

        OMG. Typo in Username........

        At least we now have an example how to add watchers via JSS Plugin :-)

        Thomas

        1. Unknown User (speimann@curtisswright.com)

          So the question then becomes one of how to properly interrupt the processing sequence and roll back work, when there is an error like Thomas'. 

          Is the best answer to just let JIRA dump, or is there a more graceful recovery?

          1. Unknown User (tkrug0210)

            Letting Jira dump is definitely be no solution for me since I don't want my customers to see any stack traces. Jira does implement quite a lot checking methods returning boolean values (isInGroup() etc.). I just neglegted using them in my code.

            A message "User does not exist" is more helpfull than a NullPointerException.

  36. Unknown User (zoom.license@zoomint.com)

    HI,

    in JSS 1.0 this is not working:

    invalid_fields['Component/s'] = 'You do not have permission to select component!'

    i haven't got any error message, but "my error message" is not displayed on page.

    Thanks

    1. Hi Tibor,

      You should use fields' id, not their names:

      invalid_fields['components'] = 'You do not have permission to select component!'
      
  37. Unknown User (mbeaudoin)

    Everyone, wondering why I cannot get any value out of my nb_comments variable, yes there are comment on the issue, any help more than welcome

    Wondering if I use proiperly the getComments(issue) method...

    TIA, MB

    commentManager = ComponentManager.getInstance().getCommentManager()
    customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
    nb_comments = commentManager.getComments(issue) 
    customField = customFieldManager.getCustomFieldObjectByName("Quality index")
    issue.setCustomFieldValue(customField,"test:" + nb_comments.size.toString())

    1. Unknown User (speimann@curtisswright.com)

      Marc,

      It looks like you left out a pair of parentheses in the fifth line after "size".  Try:

      issue.setCustomFieldValue(customField,"test:" + nb_comments.size().toString())

      but I'm not all that good with Jython, yet.

      Cheers,
      Scott

      1. Unknown User (mbeaudoin)

        Thanks for your quick reply Scott,

        Those parentheses were definately missing but there is no such method as toString for int type here is what works for me now, hope this might help someone else ;)

        commentManager = ComponentManager.getInstance().getCommentManager()
        customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
        nb_comments = commentManager.getComments(issue) 
        customField = customFieldManager.getCustomFieldObjectByName("Quality index")
        issue.setCustomFieldValue(customField,"test:" + str(nb_comments.size()))

        1. Unknown User (speimann@curtisswright.com)

          Marc,

          Good observation on the int type.  For some reason, even though I checked the documentation, I was thinking Integer return type.

          I'm glad it's working.

  38. Unknown User (lucb)

    Hi,

    I have added custom fields to have some emails of person that are not jira user and send them email, I can have the events when the issue status change (workflow) or when the description change but I'm unable to have an event when a comment is added. Is there a possibility to have a script firing when a comment is added ?

    Thanks

    1. Unknown User (speimann@curtisswright.com)

      Luc,

      This capability exists in standard notifications.  There is no real need to use JSS for this capability.

      Cheers,
      Scott

      1. Unknown User (lucb)

        Thanks Scott but it's not helpfull in this case. Some peoples haven't a Jira Account, they can add a bug request in another system, an old system. In this system they can add a bug (for exemple) in a particular application and they will receive the statuses (fixed, on test, etc). I want to perform the work in Jira (time sheet, backlog, priorities, better events, worflow...) but have to send the comments the programmer do to the responsible of this entry. I can't use the notification because I must have one system per person... I can't use observer because the user must have a Jira login...So the idea is to send an email with this new comment to this person (Jira will receive all reply and add it to the comment issue).

        1. Unknown User (speimann@curtisswright.com)

          Luc, I see what you mean.  My fault in that I misunderstood what I was reading. 

          Sounds like you want to implement a scripted post-function that reads the appropriate field, and then uses the JIRA e-mail API to send the message you want. 

          Kind of a pain in the tail, because you have to drop a copy of your function on workflow transitions to deal with the obvious cases.

          As far as adding a notification handler, I don't think that Atlassian has gotten to the point where they allow developers to add new options through the plug-in system.  Perhaps you will want to file an upgrade suggestion?  Also, ask on the forums - there may be some one who can help.

          Of course, under Linux, you could send a message to a handler address.  You could then hang an e-Mail handler script, which broke down the message and forwarded it to the appropriate individuals.  It'll be a bit of a difficult undertaking, but as a stop-gap, it might work.

          Luck!

          1. Unknown User (lucb)

            Yes, I have started the application with a link of email...not so nice but working well. Thanks for your help Scott !

  39. Unknown User (cdnexus)

    Attempting to create a post function to modify the status of an issue after it is transitioned to the target state:

    from com.atlassian.jira import ComponentManager
    from com.atlassian.jira.util import JiraUtils
    
    cfm = ComponentManager.getInstance().getCustomFieldManager()
    
    # 'customfield_10290' is the state selector field.
    state = issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10290"))
    
    stateNumber = 0
    
    if state == 'Submitted':
        stateNumber = 1
    elif state == 'Analysis':
        stateNumber = 2
    elif state == 'Analysis Complete':
        stateNumber = 3
    elif state == 'Request Reject':
        stateNumber = 4
    elif state == 'Rejected':
        stateNumber = 5
    elif state == 'Update':
        stateNumber = 6
    elif state == 'Request Defer':
        stateNumber = 7
    elif state == 'Deferred':
        stateNumber = 8
    elif state == 'Closed':
        stateNumber = 9
    
    # Specify Transition
    issue.setStatus(stateNumber) #<-- this won't work due to type

    Have tried a number of different ways, the JIRA API is a little light on details in many areas.
    I tried issue.setStatusId('1') for instance will corrupt an issue.

    The end goal of this is to create an admin transition for a workflow with ~40 states.
    Creating an individual transition from each state to every other state would be both a burden to me and the user.

    http://www.customware.net/repository/pages/viewpage.action?pageId=8093744

    Also seemed to be of interest. But once again tha API on these classes was a bit light on for my level of experience with JIRA.

    1. Unknown User (speimann@curtisswright.com)

      Chris,

      I apprecitate what you want to do, as I have a similar scaling problem with a workflow that requires five approvals in any order. 

      I think you may need to open the cast the issue into a MutableIssue. 

      Lastly, and I don't know if this is the correct approach or not, try using something like:

           issue.setStatus(stateNumber.toString())

      Looking at the documentation (http://docs.atlassian.com/software/jira/docs/api/latest/com/atlassian/jira/issue/MutableIssue.html ) shows that MutableIssue.setStatus() wants a String, not an integer type

      Good Luck!
      Scott

      1. Unknown User (cdnexus)

        setStatus

        void setStatus(org.ofbiz.core.entity.GenericValue status)

        setStatusId

        void setStatusId(String statusId)
        Set issue's status by status id ("1", "2" etc).
        Parameters:statusId- the new StatusId.

        I think you meant statusId, and I did try that. After modifying this value using the SetStatusId value, I could no longer get the status for the issue (which caused all sorts of problems) and had to delete the record directly from the database. I will give it another shot.

        1. Unknown User (speimann@curtisswright.com)

          Chris,

          You're right.  The correct method is setStatusId.

          Did you try using strings in your Jython code, instead of small integer values.

          Looking back, on Dec 22, Mark used the str function to change an integer value to a string, so your code might be

          issue.setStatusId(str(stateNumber))

           The other issue may be that your stateNumber values may not all be correct.  You may have to look them up by "name".
          When I look through a XML dump of my development database, I see that "Status" values that I create (beyond the original five from Atlassian) are numbered sequentially from 10000.  That may be part of your problem.

          Cheers!
          Scott

        2. Unknown User (speimann@curtisswright.com)

          Chris,

          I just noticed that the status values are shown in the "History" at the bottom of the Issue View screen.

          So, if you run an issue through all states, you should have your mapping right there.

          I still think it would be much smarter to look up the statuses by name, though.  They are of class "IssueConstant", now all we have to do is find the manager that looks them up, or provides the whole set of them.

          Luck!
          Scott

          1. Unknown User (cdnexus)

            from com.atlassian.jira import ComponentManager
            from com.atlassian.jira.util import JiraUtils
            
            cfm = ComponentManager.getInstance().getCustomFieldManager()
            
            # 'customfield_10290' is the state selector field.
            state = issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10290"))
            
            stateNumber = 0
            
            if state == 'Submitted':
               stateNumber = 10009
            elif state == 'Analysis':
               stateNumber = 10010
            elif state == 'Analysis Complete':
               stateNumber = 10011
            elif state == 'Request Reject':
               stateNumber = 10012
            elif state == 'Update':
               stateNumber = 10013
            elif state == 'Request Defer':
               stateNumber = 10014
            elif state == 'Deferred':
               stateNumber = 10015
            elif state == 'Closed':
               stateNumber = 10016
            elif state == 'Rejected':
               stateNumber = 10017
            
            # Specify Transition
            if state != 0:
               issue.setStatusId(str(stateNumber))

            Progress! That was the issue. Was using the Workflow ID for the state rather than the Globally unique issue id.

            Has worked, however although the issue status changes, the options that are available and transitions suggest JIRA still thinks the issue is in the previous state.

            If I transition away from the initial state,
               no transition is recorded, as it still assumes the end state was the one set at the end of the transition.

            Questions:
               Why does JIRA still think the issue is in the previous state despite the issue field displaying the correct indended state, how can I change that?
               How can I get the transition history to be correct.

            Edit: It appears workflow state and issue state aren't directly linked. I assume this is handled by OSWorkflow in the background.
            The question becomes is it possilble to use the conditional results in OSWorkflow to achieve my goal in combination with JSS. Seaching the forums has given me around 5 people who have attempted to make this kind of transmission, none have a posted solution.

            Is it possible to direct an issue to a state in OS workflow without having seperate transitions to call in each case....?
            If not, it is going to make JIRA a PITA to use for workflows with a large number of states.

            Another possiblility that just occurred to me is to use a dummy state, containing all my transactions. An "admin transition" state if you will.
            All states use a common transition to this state, and automatically transition out again. The user won't even need to see this state as the post function on the common transition to this state could take care of this second transaction.

              

            1. Unknown User (speimann@curtisswright.com)

              Chris,

              This probably isn't the forum for this discussion, if we're considering workflow architecture.  As I understand it, this is a discussion forum for use of the JIRA Scripting Suite plug-in.

              Still, let me ask a question - what is the value in giving the ability to violate the workflow of your application? 

              Honestly, it sounds like you have a design problem, if you're providing an easy means of simply and arbitrarily coercing issue status.  The reason I mention this is that when such an ability exists, managers tend to ignore the application structure and data flows that they are asking every-one else to follow.  It starts out as an administrative feature, and one-by-one, management will have themselves added to the administrators list.  At some point, some one violates something, and data are lost, or worse.  At best, you have an internal audit failure, and your managers are held accountable.  At worst, you have a major problem, leaving you holding the stinky end of the stick.

              Please forgive my preaching, but a much better approach is to make sure that there is an appropriate permission structure, and all (including administrative) personel are required to follow the business rules.  [In my case, this means that no data are ever erased, meaning that all updates are audit-trailed, etc...]

              Needless to say, if there is a bug in the workflow, that can be rectified fairly quickly.  If there is a bug in a validation rule, its pretty easy to fix, too (except for ones that are hard-coded as part of plug-ins).  Data errors should be corrected by editing the data and supplying comments explaining the change, not by hacking the database. 

              One thing that I do in my workflows is give a special role "Administrator" permission to execute all transitions.  I do this, as sometimes it is strictly necessary to administratively force a transition or data edit.  However, this override does not void any of the data validation or other business rules that I have implemented in my applications.  The beauty here is that when an "Administrator" does force something, the audit trail records the activity.  Since "Administrator" is a separate role, and not an account, I can actually control who has override on any particular project.  This means that I do not have managers using a "jira-administrator" account to anonymously manipulate data. 

              All that said, this is what my management asked me to do.  They chafe about it sometimes, however we do not have the types of quality audit problems that we had in the past. 

              Ok, I'm sorry for descending into a lecture like that, it's just that I've seen this happen enough times to make me reluctant to build the capability to violate application structure.  If you have a architecture problem, fix it, instead.

              Cheers!
              Scott

  40. Unknown User (zoom.license@zoomint.com)

    Hi,

    statement invalid_fields doesn't work on affects version/s field for me. I tried a lot of combinations of field name but no success. If I tried it for summary field it worked fine/

    What I have to write inside?

    invalid_fields['XXXXXXXXXXX']

    thx

    1. Unknown User (speimann@curtisswright.com)

      Tibor,

      Try using invalid_fields['versions'], and see if that cures what ails you.

      Cheers,
      Scott

  41. Unknown User (mhuerta)

    Hi Alexander,

    I am hoping to use this plugin to create a post function that will let me dynamically set the Greenhopper Rank field to the "lowest" rank for the project upon closing the issue.  The Greenhopper API is not documented anywhere, but I am thinking this might be possible by retriveing all of ranks for the current project, and then finding the lowest rank and setting the current issue to this value.  Would this be possible?

    Cheers,

    Micah

  42. Unknown User (skloehr)

    I am new with python and trying to build a post script function based on the example. I have a custom field called Approver that is not initially required but will eventually be emailed at the Ready for Approval Step in the workflow so it needs to be populated when the transition occurs . I am getting this error:

    ERRORIt seems that you have tried to perform an illegal workflow operation. If you think this message is wrong, please consult your administrators about getting the necessary permissions.
    Form Errorroot cause: Traceback (most recent call last): File "/opt/jira/jss/jython/workflow/send_approval_notification_post.py", line 15, in <module> invalid_fields['customfield_10010'] = u'Issue does not contain a valid approver.' NameError: name 'invalid_fields' is not defined

    This is the code I have at the ready for approval transition as a post function.

    import com.atlassian.jira.ComponentManager
    import com.atlassian.jira.issue.CustomFieldManager
    import com.atlassian.jira.issue.fields.CustomField
    from urlparse import urlparse

    cfm = ComponentManager.getInstance().getCustomFieldManager()
    cf = cfm.getCustomFieldObjectByName("Approver")
    approver = issue.getCustomFieldValue(cf)
    assignee = issue.getAssignee()
    issuekey = str(issue.getKey())

    if not approver :
    result = False
    invalid_fields'customfield_10010' = u"Issue does not contain a valid approver."
    description = "Edit the issue and specify an Approver."

    o = urlparse('http://JiraServer01:8090/browse/' + issuekey)

    sender = assignee.getEmail()
    to = approver.getEmail()

    subj = "Issue %s is ready for approval" % issuekey
    body = """<b>Action is required to put this issue in production.</b><p>
    <b>Issue Key:</b> %s<p><b>Issue Description:</b> %s<p>
    Please click on the link below and after logging in with your network credentials, you will be
    able to get more details about the issue.<p>
    If you approve of the implementation, click on the
    Approve button near the top of the issue:<p>
    <a href=\"%s\">%s</a>""" % (issuekey, issue.getSummary(), o.geturl(), o.geturl())

    1. log.trace(to)
      server = 'smtp.mmplp.net'

    from email.MIMEText import MIMEText
    msg = MIMEText(body, 'html', 'utf-8')
    msg'Subject' = subj
    msg'To' = to
    msg'Importance' = 'high'

    import smtplib
    s = smtplib.SMTP(server)
    s.sendmail(sender, to, msg.as_string())
    s.quit()
    I have tried several different ways to gracefully notify when there is no approver but I am stuck. Any ideas?

    Thanks,
     Steve

    1. Hi Steve,

      You can't use invalid_fields in post-function. You should divide your script into two parts: a validator to check the fields, and a post-function to do actual work.

      BR, Alex

  43. Unknown User (rfrizzel)

    I'm sure I just am not seeing this, but I'm trying to write a global validator and I cannot seem to get the original value of a custom field back to me in the script through the issue object. In fact, the issue object returns the new value of the custom field.

    I want to make sure that the user comments if they change this particular date.

    It is a date custom field, so you know the gyrations you have to do to dates in Java to get it to a string. Here's the code:

     # Get the management objects from JIRA we need.
    cfm = ComponentManager.getInstance().getCustomFieldManager()
    
    # Get the custom field handles we will need.
    startDateID = cfm.getCustomFieldObjectByName("Scheduled Start Date").getIdAsLong()
    
    # Get the original values before the change. This is what I'm having trouble with.
    # This *also* gets me back the changed value rather than the original value.
    oldStartDate = issue.getCustomFieldValue(cfm.getCustomFieldObject(startDateID))
    
    # Since the original value is a java.util.Date, then convert to a string.
    the_formatter = SimpleDateFormat("MM/dd/yyyy");
    oldStartDateStr = the_formatter.format(oldStartDate)
    
    # This works to give me the new value...
    newStartDateStr = parameters.get("customfield_" + str(startDateID))[0]
    
    # But in this debug log statement, both old and new are the same.
    log.error("trace line 32: oldStartDateStr = " + oldStartDateStr + " newStartDateStr = " + newStartDateStr)
    

    See anything obviously wrong?

  44. Unknown User (brian)

    Change an issue's issue type as a post-function during a transition:

    I am fairly new to the JSS and my python is pretty basic, but I am trying to convert an issue to a bug during a transition and used the code below as my implementation.

    issue.setIssueTypeId("1") #Convert issue from ... to bug

    A question: is there anything wrong with this?  For instance, will the issue be indexed properly, or was there any obvious things I forgot to do when changing this issue type like this?

    1. Unknown User (speimann@curtisswright.com)

      Brian,

      Two things to consider - the issue type (bug) must be in the project and the goal state must be valid for the issue.  I'm not sure if JIRA will correctly transition it between workflows or not, although I suspect it does.

      Cheers,
      Scott

      1. Unknown User (brian)

        Scott,

        Thank you for your assistance!  I have verified that the issue type is valid for the project, and that the work flows between any potential issue types using this transition and the bug issue type are compatible.  We had to create a transition like this since JIRA does not really contain the concept of an "initial issue type".  Some day the grief may vanish, but for now JSS to the rescue!  Any other obvious errors for the trained eye?

        Brian

        1. Unknown User (speimann@curtisswright.com)

          Brian,

          In general it's awfully difficult to foul up one line of code, although I've done it on more than a few occasions.

          This link points to an example of an issue type change made by Alex.

          Hopefully it helps.

    2. Actually never tried this, but my experience says this won't work. This method definitely won't change the associated workflow, and there may other problems.

      You may try though, but not on the production JIRA instance.

      Alex

  45. Unknown User (mmccracken)

    Can anyone tell me the proper way to get the IssueSecurityLevelManager?  

    In 4.2.4 is looks like it should be a simple islm = ManagerFactory.getIssueSecurityLevelManager() call but that does not seem to work.

    Also, it appears to be depricated in 4.3.

    What is the proper way to get at issue security levels?

    Thanks

    Mike

  46. Unknown User (sylvainstg)

    I am trying to run this simple script in the global post edit.   It all works except the setting of the custom field value (the commented out line) I know the custom field object works as I am getting its description in the summary field. 

    if issue.getIssueTypeObject().isSubTask():

       customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
       customField = customFieldManager.getCustomFieldObjectByName("Effort")

       issue.setComponents(issue.getParentObject().getComponents())
       issue.setDescription(customField.getDescription())
    #issue.setCustomFieldValue(customField, new java.lang.Integer("10"))

    ----

    Any hints would be greatly appreciated.

    Thanks!

    Sylvain

    1. Unknown User (sylvainstg)

      I have experimented further along the lines of what I trying to achieve and found another blocker.

      In essence, I am trying to use this mechanism to update a numerical custom field that I will use as the data source of GreenHooper statistical marker.

      Once understand how to set the custom field (ref: post above) I will need to calculate the number of hours in the "remaining effort" field.  However, what should work according to the documentation simply does not.

      I tried:

      issue.getEstimate().toString()

      issue.getOriginalEstimate().toString()

      They both return an empty string... Any one know how I can get to the value of the remaining effort in the task?

      Thanks, 
        

  47. Unknown User (brian)

    Hello all.  I had a question about retrieving members of a JIRA group, and creating a JIRA sub-task for each member of that group.  There is a bit above about dynamically creating sub-tasks, but could anyone provide assistance/direction to get me started with respect to the groups part?  Specifically, I would be getting the group from a group selector custom field.  Thanks!

    1. Unknown User (brian)

      Heres the code to extract each of the members of a set of groups defined by a multi group selector custom field. Should provide a basic structure for anyone attempting to extract users from groups.

      # add all required imports here
      from com.atlassian.jira.util import ImportUtils
      from com.atlassian.jira import ManagerFactory
      from com.atlassian.jira import ComponentManager
      
      
      # create variables from imports here
      issueManager = ComponentManager.getInstance().getIssueManager()
      issueFactory = ComponentManager.getInstance().getIssueFactory()
      authenticationContext = ComponentManager.getInstance().getJiraAuthenticationContext()
      subTaskManager = ComponentManager.getInstance().getSubTaskManager()
      userUtil = ComponentManager.getInstance().getUserUtil() #get users and groups
      customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
      
      #Group(s) for tasks
      groups = issue.getCustomFieldValue(customFieldManager.getCustomFieldObject("customfield_XXXXX")) # multi group select custom field
      
      #Get the first and second group's members:
      membersStrList = []  #list for simple user string representations
      membersInGroups = [] #list for the actual user object
      for group in groups:
          for member in (group.getUsers()):
              if not(member in membersStrList ):
                  membersStrList = membersStrList + [member]
                  membersInGroups = membersInGroups + [userUtil.getUser(member)]
      
      
      #at this point, membersInGroups is a list of user objects
      
      
      #output members in first group
      #description = repr(dir(groups[0])) # HANDY DANDY WAY TO GET ALL OF A CLASS' VARIABLES/FUNCTIONS
      description = repr(membersInGroups)
      result = False
      
  48. Unknown User (brian)

    Does anyone know how to create an issue/sub-task that is already resolved?  Apparently this is not sufficient to do this during the creation of the issue:

    issueObject = issueFactory.getIssue() # the new issueObject to create
    #
    # ... set project, summary, issue type, etc...
    #
    issueObject.setResolutionId("9"); # closed (resolution)
    issueObject.setStatusId("6");     # closed (state)
    #
    # ... complete the creation/indexing...
    #
    

    (Using most of the code in an earlier comment in this topic) I have been able to create subtasks, but not create resolved tasks. During certain conditions, we want to have queryable sub-tasks, but have them created and closed during a workflow transition. Any guidance to be had? I am still quite new at creating these scripts around JIRA, so any help would be greatly appreciated. Thanks very much.

    1. Unknown User (matt.bates)

      I think you'll have to transition the issue:

      workflowTransitionUtil = JiraUtils.loadComponent(WorkflowTransitionUtilImpl)
      workflowTransitionUtil.setAction(207) # Resolved -> Closed
      workflowTransitionUtil.setIssue(issue)
      workflowTransitionUtil.setUsername(user.getName())
      result = workflowTransitionUtil.progress()
      if result.hasAnyErrors():
      	errorString = "Error Closing Issue '" + x.getKey() + "'. " + ", ".join(result.getErrorMessages())
      	logger.warn(errorString)
      	raise Exception(errorString)
      
  49. Unknown User (jbrinkley)

    I'm having an problem trying to query issues using JSS in the Jython runner. First, when I would try to import JqlQueryBuilder from com.atlassian.jira.jql.builder it would not find it. I appended WEB-INF/classes to sys.path and it now finds the name to import, but the resulting JqlQueryBuilder type does not have the newBuilder() or other JqlQueryBuilder methods.

    Does anyone have an example of querying for issues (preferably with JQL) from Jython?

    1. Unknown User (matt.bates)

      I use SearchProvider and DefaultJqlQueryParser, and it works really well:

      from com.atlassian.jira import ComponentManager
      from com.atlassian.jira.issue.search import SearchProvider
      from com.atlassian.jira.jql.parser import DefaultJqlQueryParser
      from com.atlassian.jira.user.util import DefaultUserManager
      from com.atlassian.jira.web.bean import PagerFilter
      
      user = DefaultUserManager.get().getUser('mattb')
      
      searchProvider = ComponentManager.getComponentInstanceOfType(SearchProvider)
      queryParser = DefaultJqlQueryParser()
      query = queryParser.parseQuery("updated >= -1d")
      issues = searchProvider.search(query, user, PagerFilter.getUnlimitedFilter()).getIssues()
      for issue in issues:
      	print issue.getKey()
      1. Unknown User (jbrinkley)

        Thanks for the reply!

        When I try this example in the Jython runner, I get:

        cannot create 'com.atlassian.jira.jql.parser.DefaultJqlQueryParser' instances
        

        (I added the following lines for the ComponentManager and SearchProvider types):

        from com.atlassian.jira import ComponentManager
        from com.atlassian.jira.issue.search import SearchProvider
        

        This is a really helpful reply, maybe you could show a short complete script that runs in the Jython runner?

        Thanks again!

        1. Unknown User (matt.bates)

          I've edited my reply above.

          Unfortunately uou need to do something different to get a user in different contexts.

      2. Unknown User (luca.andreatta)

        I tried your script in Jython Runner in Jira 4.4.3, but I get this error message:

        cannot import name DefaultJqlQueryParser

        Can you help me?

        1. Unknown User (thomas.krug)

          I have the same problem as Luca. The DefaultUserManager did not work as well.

          I kicked the Parser and used the JQLQueryBuilder instead. Workes like a charm:

          from com.atlassian.jira import ComponentManager
          from com.atlassian.jira.jql.builder import JqlQueryBuilder
          from com.atlassian.jira.issue.search import SearchProvider
          from com.atlassian.jira.web.bean import PagerFilter
          
          userUtil = ComponentManager.getInstance().getUserUtil()
          user = userUtil.getUser("user")
          
          searchProvider = ComponentManager.getComponentInstanceOfType(SearchProvider)
          queryBuilder = JqlQueryBuilder.newBuilder()
          queryBuilder.where().project(['FORM']).and().resolution(['Unresolved'])
          query = queryBuilder.buildQuery()
          issues = searchProvider.search(query, user, PagerFilter.getUnlimitedFilter()).getIssues()
          for issue in issues:
              print issue.getKey()
  50. Unknown User (zoom.license@zoomint.com)

    Hi,

    Please could someone tell me how Can I get information if user exists in custom filed of type "Participants of an issue". This field type comes from plugin JIRA Toolkit https://plugins.atlassian.com/plugin/details/5142?versionId=39062

    I need to return false in validation if users exists.

    I tried

    gerritUserName = 'gerrit'
    customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
    #ID of Participants field ios 10050
    customField = customFieldManager.getCustomFieldObject(10050)
    if (issue.getCustomFieldValue(customField).toString().contains(gerritUserName)):

    but I received

    root cause: Traceback (most recent call last): File "<string>", line 13, in <module> AttributeError: 'NoneType' object has no attribute 'toString'

    thanks

    1. Unknown User (speimann@curtisswright.com)

      Tibor,

      Probably your custom field returned a NULL value.  Since null doesn't have a toString() method, you'll probably have to assign the result to a variable and test for null before you can test for the username.

      Luck!
      Scott

  51. Unknown User (chintu)

    Hi Alex,

    I'm able to find whether the user selects "Automatic" in edit validator using parameters map. I got '-1' for parameters.get('assignee')[0].

    We do not have parameters map in edit postfunction. How can I find whether user selected "Automatic" option in edit postfunction?

    I tried to find whether the assignee field got changed using issue.getModifiedFields, even I did not touch assignee field, it got placed in ModifiedFields list.

    I tried to go with action object, I have command like print action.assigneeChanged(), it has got error as follows: 

    print action.assigneeChanged()

    AttributeError: 'com.quisapps.jira.plugin.action.EditIssue' object has no attribute 'assigneeChanged'

    Could you please let me know how can I get to know whether the assignee got changed in issue edit post function, and if possible let me know how can I get whether user selects "Automatic" option.

    Thanks in advance!

    Chintu

    1. Unknown User (matt.bates)

      In the Global Edit Postfunction you need to use:

      from webwork.action import ActionContext
      ...
      ActionContext.getParameters()...

      instead of just referencing the parameters variable

  52. Unknown User (matt.bates)

    Does anyone have an example of a working REST script they could share?
    I have encountered two problems so far:

    1. I can't work out how to pass args into the rest script. All the ways I have tried just has args (before it is passed to json.loads) = '{}'.
    2. I can't import Jira classes I want to work with.
      from com.atlassian.jira.issue.fields.renderer import IssueRenderContext
      causes the following:
      ImportError: cannot import name IssueRenderContext
      I've confirmed the class exists under WEB-INF/classes.
  53. Unknown User (zoom.license@zoomint.com)

    Hi all,

    I don't know if this is bug, or I badly wrote it, but my code returning me strange numbers.

    Script is VALIDATOR and should get username and look on comments for got username of current issue and check if size of array is bigger than 0. If yes it should not allow users to return issue with other then these resolutions.

    Problem is that script didn't return comments for given username but for my account and I don't understand why. So if I commented issue it will not allow me to return and it doesn't matter if given user did or not comments.

    Could somebody help me?

    Thanks

    from com.atlassian.jira import ComponentManager
    
    allowedResolutionsForCommitReturn = [ 'Info needed', 'Developer compile' ]
    commentManager = ComponentManager.getInstance().getCommentManager()
    userUtilManager = ComponentManager.getInstance().getUserUtil()
    
    gerritUser = userUtilManager.getUser('gerrit')
    gerritComments = commentManager.getCommentsForUser(issue, gerritUser)
    
    if (gerritComments.size() > 0):
      if resolution not in allowedResolutionsForCommitReturn:
        description = 'Cannot return issue with existing commits.'
        invalid_fields['resolution'] = u'Only Info needed, Developer compile are allowed for this transition.'
        result = False
    1. Unknown User (zoom.license@zoomint.com)

      sorry my mistake, i badly read description of getCommnetsForUser method

  54. Unknown User (glewe)

    Hi there,

    not sure if this script can help us.

    We use the Create & Link plugin to create issues in a different project. Both issues are then linked. Now we want a transition or field change in the linked issue to cause an automatic transition or field change in the parent issue. We are looking for a plugin to perform cross-project activities like that. Is this possible with this script?

    Regards,

    George

  55. Unknown User (gopherr)

    Great plugin! I'm learning a lot of this, including python/jython, as I go, but I thought I would post a short validation script that I have in place that will conditionally make one field required based on the value of another select list field. I apologize if a similar example is already included on this page, but I was not able to find it easily. If my code is not atrocious, maybe it could be added as a Code Snippet instead of here in the comments.

    Conditional Required Field
    from com.atlassian.jira import ComponentManager
    
    customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
    # Note that you can get a custom field by its name
    cf_TestPhase = customFieldManager.getCustomFieldObjectByName("Test Phase Found In")
    # Here, we get the value the user chose in the select list
    testPhase = issue.getCustomFieldValue(cf_TestPhase)
    cf_FuncGrp = customFieldManager.getCustomFieldObjectByName("Functional Group")
    funcGrp = issue.getCustomFieldValue(cf_FuncGrp)
    
    if testPhase == 'Product Test':
      if not funcGrp:
        result = False
        invalid_fields['customfield_10191'] = u'Functional Group is required when Product Test phase is selected'
        description = 'Please review the custom validation error message/s below'
    

    To include this validation in a particular workflow, simply create a draft of the workflow, find the appropriate Transition, click the Validators tab, click Add and select Jython Validator, and then place this code in the editor window.

    Feedback on how to improve this simple logic is welcome.

    1. Unknown User (muhammad_rahman@cable.comcast.com)

      Hi,

      What is "invalid_fields'customfield_10191'"  representing here? Seems like the following code is not working for me 

      # This ensure that if resolution field value is Duplicate, Dup Ticket Id is required
      from com.atlassian.jira import ComponentManager
      customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
      # get resolution field value selected by user
      Resolution_Field =issue.getResolution()
      # get a custom field by its name
      Cf_DupTicket = customFieldManager.getCustomFieldObjectByName("Dup Ticket ID")
      DupTicket = issue.getCustomFieldValue(Cf_DupTicket)
      if Resolution_Field=='Duplicate':
        if not DupTicket:
          result = False
          invalid_fields['customfield_ 10630'] = u'Duplicating ticket id is required  when Duplicate is selected'
          description = 'Please review the custom validation error message/s below'

      -MR

  56. Unknown User (csit.jira.support@list.db.com)

    Hi,

    We want to add a validation while a user creates a ticket. If Reporter and Assignee is same, jira should throw an error !!

    Anybody can help me with this ??

    Thanks !!

    Arpit

    1. Unknown User (matt.bates)

      I stand to be corrected but I think its the one case you can't do.

      You can do Post Functions on Create with a Listener, but I don't think there is any way to do validation.

  57. Unknown User (muhammad_rahman@cable.comcast.com)

    It seem like the plug-in is still not compatible with JIRA-4.4 ( By looking into compatibility list ).  

    We are using plug-in version -1.0 with JIRA-4.3.4 and in a process of upgrading JIRA to latest (JIRA-4.4). This is blocking us in doing so. So, will it be possible to test this against JIRA-4.4 and release newer version compatible withJIRA-4.4?

    We will appreciated if this can be done ( sooner ) so that the user community (like us) can continue using this great plug-in with latest JIRA..

    Thank you.

    1. Unknown User (eugenet)

      just tried: both 1.0 and 1.1 are not compatible with JIRA 4.4 :(

  58. Unknown User (korolkov)

    Hi! I'm new to Jira and the Jython.

    Could you please help me with the following:

    I'm trying to create a post-function that puts the Reporter's Email into a custom field named "E-Mail".

    I've installed your plugin but even without doing a thing I keep getting stuck at the "Edit" screen. I don't even get the name of the error, it just pops out an empty error.

    What did I do wrong?

    Also I wrote a script that is supposed to do the thing:

    from com.atlassian.jira import ComponentManager
    
    customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
    
    customField = customFieldManager.getCustomFieldObjectByName("E-Mail")
    
    user = issue.getReporter()
    
    issue.setCustomFieldValue(customField, user.getEmail())
    
    customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
    
    customField = customFieldManager.getCustomFieldObjectByName("E-Mail")
    
    user = issue.getReporter()
    
    issue.setCustomFieldValue(customField, user.getEmail())
    

    Is there smth wrong with the script?
    Big thanks for your future assistance.

    1. Unknown User (korolkov)

      Hi again!

      I solved the problem by editing the Jython Home Dir. It turned out just like this issue https://studio.plugins.atlassian.com/browse/JSS-1.

  59. Unknown User (korolkov)

    Hi again!

    Could you help me with this script:

    customField1 = customFieldManager.getCustomFieldObject("customfield_10731")
    projectmanager = ManagerFactory.getProjectManager()
    newproject = projectmanager.getProjectObjByName(customField1.getValue(issue))
    issue.setProjectId(newproject.getId())

    All I want to do is to change the project of the issue depending on a value from the custom field.

    But it does nothing, just changes the value of the field.

    Could you please tell me where is my mistake?

  60. Unknown User (jrubial)

    Hello,

    I'm new with JSS I´m trying to create a sub-task in a post-function in JIRA 4.3.4 and jython 2.5.0, I based the following example:

    from com.atlassian.jira.util import ImportUtils
    from com.atlassian.jira import ManagerFactory
    from org.ofbiz.core.entity import GenericValue
    from com.atlassian.jira import ComponentManager
    from com.atlassian.jira.issue import Issue

    issueManager = ComponentManager.getInstance().getIssueManager()
    issueFactory = ComponentManager.getInstance().getIssueFactory()
    authenticationContext = ComponentManager.getInstance().getJiraAuthenticationContext()
    subTaskManager = ComponentManager.getInstance().getSubTaskManager();
     
    issueObject = issueFactory.getIssue()
    issueObject.setProject(issue.getProjectObject()) --------------------> Have I missed something here??
    issueObject.setIssueTypeId("5") # default sub-task issue type
    issueObject.setParentId(issue.getId())
    issueObject.setFixVersions(issue.getFixVersions())
    issueObject.setAffectedVersions(issue.getAffectedVersions())
    issueObject.setPriority(issue.getPriority())
     
    issueObject.setSummary("Realisierung")
    issueObject.setAssignee(issue.getAssignee())
    subTask = issueManager.createIssue(authenticationContext.getUser(), issueObject)
    subTaskManager.createSubTaskIssueLink(issue.getGenericValue(), subTask, authenticationContext.getUser())

    The problem is that when I run the workflow transaction I get this error:

    ERROR

    root cause: Traceback (most recent call last): File "<string>", line 13, in <module> TypeError: setproject (): 1st arg can not be Coerced to org.ofbiz.core.entity.GenericValue

    Help please

    1. Unknown User (hmenzi)

      Jamie,

      I have the following JSS script that creates a sub-task in a post function working well in my jira (4.2.2). I hope this helps you out.

      # add all required imports here
      from com.atlassian.jira import ManagerFactory
      from com.atlassian.jira import ComponentManager
      from com.atlassian.jira.util import JiraUtils
      from com.atlassian.jira.util import ImportUtils
      from com.atlassian.jira.issue.cache import CacheManager
      
      issueManager = ComponentManager.getInstance().getIssueManager()
      issueFactory = ComponentManager.getInstance().getIssueFactory()
      authenticationContext = ComponentManager.getInstance().getJiraAuthenticationContext()
      subTaskManager = ComponentManager.getInstance().getSubTaskManager();
      
      issueObject = issueFactory.getIssue()
      issueObject.setProject(issue.getProject())
      issueObject.setIssueTypeId("10") # Subtask of type new customer server
      issueObject.setParentId(issue.getId())
      
      # set atributes
      issueObject.setAssignee(ComponentManager.getInstance().getJiraAuthenticationContext().getUser())
      issueObject.setReporter(ComponentManager.getInstance().getJiraAuthenticationContext().getUser())
      issueObject.setSummary("Server Implementation for " + issue.getSummary())
      issueObject.setPriority(issue.getPriority())
      
      subTask = issueManager.createIssue(authenticationContext.getUser(), issueObject)
      subTaskManager.createSubTaskIssueLink(issue.getGenericValue(), subTask, authenticationContext.getUser())
      
      # Update search indexes
      ImportUtils.setIndexIssues(True);
      ManagerFactory.getCacheManager().flush(CacheManager.ISSUE_CACHE, subTask)
      ComponentManager.getInstance().getIndexManager().reIndex(subTask)
      ImportUtils.setIndexIssues(False)
      
      1. Unknown User (felix.martineau)

        Since JIRA 4.3, you don't need to flush the CacheManager anymore, so the following will do the trick:

        # Update search indexes
        ImportUtils.setIndexIssues(True);
        ComponentManager.getInstance().getIndexManager().reIndex(subTask)
        ImportUtils.setIndexIssues(False)

        If you do not reindex the subtask, it will be created and will appear as a subtask when you view the parent issue, but it will not show up in searches until you do a full reindex

  61. Unknown User (jrubial)

    Is there any way to get data from a custom field that is a link issue from the parent issue?

    Data are available on a issue from other issues?

    Thanks

  62. Unknown User (maciek)

    Hello.

    i would to update worklog in post function with jss script. This is for absence in work, e.g. vacation.

    i must logwork absence on first day of absence and, if needed, on first day all next month where i'm out of work. (eg. if i have vacation beetween 20 September and 10 October, i have to logwork hours on 20/Sep/11 to end month, and 01/Oct/2011 to 10/Oct/11).

    i have this:

    issueManager =ComponentManager.getInstance().getIssueManager()
    wlm=ComponentManager.getInstance().getWorklogManager()
    #dateTable - dates to logwork, monthTable: days in month, weekendsTable: count of sundays and saturdays, holidaysTable: count of holidays
    for i_date in range (0, len(dateTable)):
      workingDays = monthTable[i_date] - weekendsTable[i_date] - holidaysTable[i_date]
      secondsToReport = long(workingDays * timeWork * 8 * 3600)
      worklogDate=str(dateTable[i_date])[0:4]+"/"+str(dateTable[i_date])[5:7]+"/"+str(dateTable[i_date])[8:10]
      parseIndex=ParsePosition(0)
      worklogDate = SimpleDateFormat("y/M/d").parse(worklogDate,parseIndex)
      wlcreate = com.atlassian.jira.issue.worklog.WorklogImpl(wlm,issue,None,CurrentUser.toString(),"Vacation",worklogDate,None,None,secondsToReport)
      wlm.create(CurrentUser, wlcreate,0,True)
      issueManager.updateIssue(CurrentUser, issue, EventDispatchOption.ISSUE_UPDATED, False)
    

    The problem is: time tracking (in the view issue) showing only the last worklog, however Worklog in activity show all worklogs. I'll try to update issue always after create worklog, but with no result.

    Somebody help?

    1. Unknown User (maciek)

      something news:

      when i try to execute

      TimeTrackingIssueUpdater.updateIssueOnWorklogCreate(CurrentUser,worklog, 0,False)
      

      i get error:

      TimeTrackingIssueUpdater.updateIssueOnWorklogCreate(CurrentUser,wl, 0,False) TypeError: updateIssueOnWorklogCreate(): expected 5 args; got 4

      but:

      updateIssueOnWorklogCreate(com.atlassian.crowd.embedded.api.User user, Worklog worklog, Long newEstimate, boolean dispatchEvent) 
  63. Unknown User (rpugal)

    Hi Alex,

             I have created one project role . I need to assign issue to that particular role while creating issue.

            First of all i need to get User from particular role.

            Is it possible in Jython script to get user of particular role and assign issue to that user.

            I tried using Jira soap call in JSS

    tokenKey = JiraSoapService.login("user", "user")
     project = JiraSoapService.getProjectByKey(token,ProjectKey)

    Exception i got is
    login(): expected 3 args; got 2

    Thanks
    Pugal.

  64. Unknown User (olivier.vandevoorde@securex.be)

    Hi,

    How to set a customfieldvalue of type com.atlassian.jira.issue.customfields.impl.NumberCFType

    issue.setCustomFieldValue(customfield, ????? )
    
    


    Thanks

  65. Unknown User (sundale)

    Greetings,

    reading through the documentation I'm slightly confused as to when the object is committed and at what transition we place the code.

    As a proof of concept and to understand the syntax and objects we are wishing to set the Summary and Add a Watcher based upon on the Project Role. We are wishing to do this on the initial user submission ie. initial create

    Gluing together a code skeleton based upon other people's invaluable contributions

    from com.atlassian.jira import ComponentManager
    from com.atlassian.jira.issue import MutableIssue
    
    issueFactory = ComponentManager.getInstance().getIssueFactory()
    issueManager = ComponentManager.getInstance().getIssueManager()
    authenticationContext = ComponentManager.getInstance().getJiraAuthenticationContext()
    
    # These work and can be written to a log file \*\* only after the initial create
    issueObject = issueFactory.getIssue()
    gIssue = issue.getSummary()
    jId = issue.getId()
    jKey = issue.getKey()
    jDesc = issue.getDescription()
    
    # Set Object to write \*\* THIS DOESN'T WORK as expected
    issueObject.setSummary("A different Summary to the one that was typed")
    issueObject.setDescription("A different description then that entered by the user")
    issueObject.store()
    

    The above does not give us the desired result ie. it still has the user entered text, we thought we would end up with an issue with the Summary and Description set as per above. Any insight would be greatly appreciated.

  66. Unknown User (hazbut)

    I was of the assumption that the Global Postfunction would work out of the box. I can initiate a simple script in the Jython runner, yet the same code fails to fire the Global Postfunction inline or file script when transitioning an issue.

    Is there a configuration I am missing here?

  67. Unknown User (tkrug0210)

    Hi,

    I started experimenting with the transientVars map. My problem is that the Map is always empty thus the above example (appending the comment to a mail) returns a key error.

    The same happens when iterating over the HashMap like

    java.util.Iterator<Object> iter = transientVars.keySet().iterator();
    while(iter.hasNext()) {
        Object key = iter.next();
        Object value = hashMap.get(key);
        body = body + "\nvalue"
    }

    Anything I missed here?

  68. Unknown User (srividhya)

    Hi Alex,

    I have been trying with the Global Edit function for the past 2 days .I am not even getting a sing log in the catalina.out even if I give , print some text.

    We are using jira4.2.4 with jss1.1 and and the add -on as jss42 _1.0.jar .I changed the actions.xml also.

    What else we can do ..Please help ..

    Thanks

    Srividhya

  69. Unknown User (awilson)

    Hi Alex,

    I wrote a post-function for a custom workflow that I implemented. I'm trying to update all the sub-tickets so they transition through the workflow when the parent ticket transitions, but when I call issue.getStatus() I get the starting state for the transition, and not the destination state. How do I get access to the destination state so that I can update all the sub-tickets?

    Andrew

    1. Unknown User (nakilon)

      My solution was: when editing Post Functions move your postfunction down after the 'Re-index an issue to keep indexes in sync with the database.'   and .getStatusObject().getId() (and must be .getStatus() also) would give you what you want.

  70. Unknown User (manik)

    Hello,

    I try to edit a customfield so I do that :

    import com.atlassian.jira.ComponentManager
    import com.atlassian.jira.issue.CustomFieldManager
    import com.atlassian.jira.issue.fields.CustomField
    
    customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
    customField = customFieldManager.getCustomFieldObject("customfield_10008")
    
    issue.setCustomFieldValue(customField, "15/02/2012 10:02")
    

     But I have an error cause by the ComponentManager, he's not defined (name 'ComponentManager' is not defined), I don't understand this error :s

    1. Unknown User (luca.andreatta)

      Hi,

      try to modify the import like this:

      from com.atlassian.jira import ComponentManager
      
      1. Unknown User (manik)

        It works, thank you. :D

  71. Unknown User (manik)

    I can edit a customfield in format text but not for a date, I push string like this "15/02/2012 10:02"and"2012-02-17 12:30:00.0" but I have this error :

    Error occurred while creating issue. This could be due to a plugin being incompatible with this version of JIRA. For more details please consult the logs, and see: http://confluence.atlassian.com/x/3McB class com.atlassian.jira.issue.customfields.impl.DateTimeCFType passed an invalid value of type: class java.lang.String
    

    Maybe I need to use a datetime format...

    Jira date settings :

    1. Unknown User (luca.andreatta)

      You can start from this script that I used some time ago:

      issue.setCustomFieldValue(cf , datetime.today())
      

      And search in Python documentation, you could find some examples.

      1. Unknown User (manik)

        Thank's you!

        correction > datetime.datetime.today()

        from com.atlassian.jira import ComponentManager
        import com.atlassian.jira.issue.CustomFieldManager
        import com.atlassian.jira.issue.fields.CustomField
        import datetime
        
        customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
        customField = customFieldManager.getCustomFieldObject("customfield_10008")
        
        issue.setCustomFieldValue(customField, datetime.datetime(2012, 5, 29, 10, 30, 45))
        

        Everything is ok, I can start to develop my function (big grin) Good afternoon

  72. Unknown User (manik)

    Hello,

    I write a script using JSS plugin, I get back a date from a customfield and I need to extract data like day, month, year, hour and minute to use my own function and then to update the customfield.

    But I have a problem to split the date in day, month, etc. I don't know how to use the object returned by "customField.getValue(issue)", I think it's a java.sql.Timestamp, I'm not sure and I'm getting nowhere :s

    from com.atlassian.jira import ComponentManager
    import com.atlassian.jira.issue.CustomFieldManager
    import com.atlassian.jira.issue.fields.CustomField
    import datetime
    import time
    import myLibrary
    
    customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
    customField = customFieldManager.getCustomFieldObject("customfield_10008")
    
    date = customField.getValue(issue)
    day = datetime.datetime.strptime(date, '%d')
    month = datetime.datetime.strptime(date, '%m')
    year = datetime.datetime.strptime(date, '%Y')
    hour = datetime.datetime.strptime(date, '%H')
    min = datetime.datetime.strptime(date, '%M')
    
    d = [int(day), int(month), int(year), int(hour), int(min)]
    
    d2, mo2, a2, h2, mi2 = myLibrary.myFunction(d)
    issue.setCustomFieldValue(customField, datetime.datetime(a2, mo2, j2, h2, mi2, 0))
    
    1. Unknown User (manik)

      I resolved my problem, the type return is 'java.sql.Timestamp' so I use this doc : http://docs.oracle.com/javase/6/docs/api/java/util/Date.html

      from com.atlassian.jira import ComponentManager
      import com.atlassian.jira.issue.CustomFieldManager
      import com.atlassian.jira.issue.fields.CustomField
      from datetime import datetime
      from datetime import date
      import java.sql.Timestamp
      
      customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
      customField = customFieldManager.getCustomFieldObject("customfield_10008") 
      
      dateBlocage = customField.getValue(issue)
      
      y = dateBlocage.getYear() + 1900
      mo = dateBlocage.getMonth() + 1
      d = dateBlocage.getDate()
      h = dateBlocage.getHours()
      mi = dateBlocage.getMinutes()
      
      issue.setCustomFieldValue(customField, datetime(y, mo, d, h, mi, 0))
      
  73. Unknown User (tsol)

    Hi everybody,

    i'm new to the plugin.

    I'm trying to create a subtask from a workflow post function but i want to set the sub task assignee another jira user.

    Could you please help me with the syntax?

    thanx

    1. Unknown User (thomas.krug)

      Hi Kostas,

      issueObject.setAssignee(userUtil.getUserObject("<username>"))
      
      
      1. Unknown User (tsol)

        Hi Thomas,

        Thanks a lot for the help

  74. Unknown User (bcohen)

    Trying to set the Assignee based on the value of a custom field. Th script is never hitting the if block, so my guess is the way I have set the variable "feature" is wrong. Could someone give me a hand with getting the "feature" variable set to the correct method?

    -Brian

    from com.atlassian.jira import ComponentManager
    from com.atlassian.jira.issue import MutableIssue
    from com.atlassian.jira import ManagerFactory
    import com.atlassian.jira.issue.CustomFieldManager
    #import com.atlassian.jira.issue.fields.CustomField
    
    userUtil = ComponentManager.getInstance().getUserUtil()
    cfm = ComponentManager.getInstance().getCustomFieldManager()
    feature = issue.getCustomFieldValue(cfm.getCustomFieldObject("customfield_10003"))
    if (feature == "Feature 1"):
    	issue.setAssignee(userUtil.getUserObject("testuser"))
    1. Unknown User (eugenet)

      if (str(feature)== "Feature 1")

      1. Unknown User (bcohen)

        Ugh, that's all I did wrong(tongue)   That's good of course.

        I forget I have to convert the objects to strings before 

        I compare.  Thanks Eugene!

  75. Unknown User (tkrug0210)

    Can I show nice error messages when using post functions just like for validation?

    If a NullPointerException is thrown the whole stack trace is shown as error message. I would like to catch the exeption and show a custom error message to the user.

    1. Unknown User (jrubial)

      If you figure out, let me know, please

  76. Unknown User (bcohen)

    Alex,

    Phenomenal plugin!  I would really like to start using this for all kinda of customizations, but I would like to know if you are working on Jira 5 support. I would hate to invest in all this scripting if I can't move to Jira 5 at some point in the future (wink)

  77. Unknown User (sundalejesse)

    Hi everybody,

    Could I please have some advice on my auto assign post function script which I am having issues with.

    I receive a notification via email saying that the issue has been correctly assigned according to the script although the assignee value within Jira and the database appears as "Unassigned". The person which the issue is meant to be assigned to also receives an email saying the issue has been assigned to them... I have placed the Jython script within the create issue step within the workflow as a post-function.

    from random import choice
     from com.atlassian.jira import ComponentManager
    
     userUtil = ComponentManager.getInstance().getUserUtil()
     staffArray = ['username1','username2','username3','username4']
     staffAssignee = choice(staffArray)
    
     issue.setAssignee(userUtil.getUserObject(staffAssignee))
    

    Edit: I should note my version of Jira is 4.4.4

  78. Unknown User (bcohen)

    from com.atlassian.jira import ComponentManager
    from org.ofbiz.core.entity import GenericValue
    from com.atlassian.jira import ManagerFactory
    from com.atlassian.jira.issue import MutableIssue
    import com.atlassian.jira.issue.CustomFieldManager
    
    reporter = issue.getReporter()
    project = issue.getProject()
    priority = issue.getPriority()
    user = issue.getAssignee()
    print user.getFullName()
    print 'can you see me'
    
    print reporter
    print project
    print priority
    
    
    

    When run as a post-function, why do I get the following error in the log:

    AttributeError: 'com.atlassian.crowd.embedded.ofbiz.OfBizUser' object has no attribute 'getFullName'

    I  am simply trying to get some real "string" value from the issue.getAssignee() to act on it.  If I print it out, I get "com.atlassian.crowd.embedded.ofbiz.OfBizUser@8b46cfe0".

    So I am trying to get the actual userid or full name from issue.Assignee().  Help!

    -Brian

    1. Unknown User (bcohen)

      Actually, looks like I want issue.getAssigneeId()   (tongue)

      Still wondering why the getFullName() didn't work.  I've seen it in others' sample code above in this thread.....

      -Brian

  79. Unknown User (yaron)

    Hi there,

    I'm, trying to write a script that will fetch a page from Confluence, the script works fine when i run it manually on the Linux server, but fails to run as a post script. The script:

    import sys, string, xmlrpclib, re
    spacekey = 'KEY'
    pagetitle = 'TITLE'
    server = 'https://your.confluence.server/rpc/xmlrpc'
    user = 'username'
    password = 'password'
    server = xmlrpclib.Server(server)
    token = server.confluence2.login(user, password)
    page = server.confluence2.getPage(token, spacekey, pagetitle)
    if page is not None:
            print page['content']

    the error messages:

    root cause: Traceback (most recent call last): File "/var/atlassian/application-
    data/jira/jss/jython/workflow/send_mail_template.py", line 8, in <module> token = server.confluence2.login(user, password) 
    File "/usr/local/bin/Lib/xmlrpclib.py", line 1147, in __call__ return self.__send(self.__name, args) File 
    "/usr/local/bin/Lib/xmlrpclib.py", line 1433, in _ServerProxy__request response = self.__transport.request( File 
    "/usr/local/bin/Lib/xmlrpclib.py", line 1201, in request return self._parse_response(h.getfile(), sock) File 
    "/usr/local/bin/Lib/xmlrpclib.py", line 1324, in _parse_response p, u = self.getparser() File 
    "/usr/local/bin/Lib/xmlrpclib.py", line 1210, in getparser return getparser(use_datetime=self._use_datetime) File 
    "/usr/local/bin/Lib/xmlrpclib.py", line 1023, in getparser parser = ExpatParser(target) File 
    "/usr/local/bin/Lib/xmlrpclib.py", line 536, in __init__ self._parser = parser = expat.ParserCreate(None, None) File 
    "/usr/local/bin/Lib/xml/parsers/expat.py", line 63, in ParserCreate return XMLParser(encoding, namespace_separator) File 
    "/usr/local/bin/Lib/xml/parsers/expat.py", line 91, in __init__ self._reader = XMLReaderFactory.createXMLReader(_xerces_parser) 
    java.lang.ClassNotFoundException: org.python.apache.xerces.parsers.SAXParser at 
    org.xml.sax.helpers.XMLReaderFactory.loadClass(XMLReaderFactory.java:213) at 
    org.xml.sax.helpers.XMLReaderFactory.createXMLReader(XMLReaderFactory.java:204) at 
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at 
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at 
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at 
    java.lang.reflect.Method.invoke(Method.java:616) org.xml.sax.SAXException: org.xml.sax.SAXException: 
    SAX2 driver class org.python.apache.xerces.parsers.SAXParser not found java.lang.ClassNotFoundException: 
    org.python.apache.xerces.parsers.SAXParser

    Thanks!

    -Yaron

  80. Unknown User (robert.wolf@abacus.ch)

    Hallo,

    could someone please provide simple example for jython script getting StartDate and EndDate from Version/Sprint of Greenhopper for Jython Runner. To get simple Jira Version information I can use following code:

    cm = ComponentManager.getInstance()
    pm = cm.getProjectManager()
    vm = cm.getVersionManager()
    
    ver = vm.getVersion(pm.getProjectObjByKey("ORDEU").getId(),"Sprint 2012 KW15-17")
    if ver:
        print "Version found"
        print "Version Name: %s" % ver.getName()
        print "Release Date: %s" % ver.getReleaseDate()
    

    I have found the Greenhopper API and there is GHVersion but I am not sure how to use it.

    I would like to do something like:

    cm = ComponentManager.getInstance()
    pm = cm.getProjectManager()
    vm = cm.getVersionManager()
    
    ver = vm.getVersion(pm.getProjectObjByKey("ORDEU").getId(),"Sprint 2012 KW15-17")
    if ver:
        print "Version found"
        print "Version Name: %s" % ver.getName()
        print "Release Date: %s" % ver.getReleaseDate()
        print "Start Date: %s" % ver.getStartDate()
        print "End Date: %s" % ver.getEndDate()
    

    But "ver" is simple Jira Version object. I think I need somehow access the GHVersion but I don't know how.

    I have tried to import com.atlassian.greenhopper, but it fails with "No module named greenhopper" and import com.pyxis.greenhopper fails with "No module named pyxis".

    Can someone give me some hint?

    Thank you.

    Regards,

    Robert Wolf.

  81. Unknown User (rpugal)

    Hi all,

    We tried Global Edit validation using this plugin .WE got our functionality correctly but the error thrown ,which is given by the "description" that highlights the error thrown on top of the screen does not show the error message at the top of the edit screen.It simply shows an error box without any error message set in the description.

    Thanks
    Pugal.

  82. Unknown User (bcohen)

    What's the plan for 5.1 support?  I was going to try it on my non-production server today, wondering if it's supported or forthcoming

  83. Unknown User (maciek)

    Hi all :)

    is here anyone who has problems with reindex in jira 5.1?

    In version 4 ewerything works fine, but now i can't find resolution for my problem (scenario):

    Issue in "Awainting for acceptance" status, and there is transition "Accept" to status "Closed". In JSS I try create subTask (code attached below). subTask was created succesfully, and i can see new subTask in Issue Navigator.

    After this (in the same transition in "post functions") issue resolution is updated to "Close", and when i view Issue i see correct status and resolution. But in Issue Navigator the issue is still in "Awaiting for acceptance" status. Now i have workaround with loop transition which do nothing but (i think) reindex issue. 

    Where i have error in the code? 

    from com.atlassian.jira import ComponentManager
    
    from com.atlassian.jira.util import ImportUtils
    import datetime
    
    from com.atlassian.jira.issue import IssueManager
    
    cfm = ComponentManager.getInstance().getCustomFieldManager()
    
    def getField(f, i=issue):
        try:
            return i.getCustomFieldValue(cfm.getCustomFieldObject(f))
        except:
            return None
    
    def setField(f, v=None, i=issue):
        try:
            i.setCustomFieldValue(cfm.getCustomFieldObject(f), v)
        except:
            raise Exception(v)
    
    def getFieldDate(f, i=issue):
        return datetime.datetime.strptime(str(getField(f)), "%Y-%m-%d %H:%M:%S")
    
    userUtil=ComponentManager.getInstance().getUserUtil()
    subTaskManager = ComponentManager.getInstance().getSubTaskManager()
    
    begintime = getFieldDate('customfield_10116')
    endtime = getFieldDate('customfield_10117')
    
    # if counter is set
    if getField('customfield_11495'):
    # get all users in participants (and create sub-tasks)
        users = getField('customfield_10270')
        for user in users:
            issueFactory = ComponentManager.getInstance().getIssueFactory()
            issueObject = issueFactory.getIssue()
            issueObject.setProject(issue.getProject())
            issueObject.setIssueTypeId("96")
            issueObject.setSecurityLevelId(10221)
            issueManager = ComponentManager.getInstance().getIssueManager()
            issueObject.setReporter(user)
            issueObject.setSummary("%s (%s %s) [%d]" % (user.getName(),  begintime.strftime("%Y-%m-%d"), endtime.strftime("%Y-%m-%d"), len(users)))
            issueObject.setAssignee(user)
            subTask = issueManager.createIssueObject(user, issueObject)
            subTaskManager.createSubTaskIssueLink(issue, subTask, userUtil.getUserObject(str(user)))
            ImportUtils.setIndexIssues(True)
            ComponentManager.getInstance().getIndexManager().reIndex(issue)
            ComponentManager.getInstance().getIndexManager().reIndex(subTask)ImportUtils.setIndexIssues(False)
    
    1. Unknown User (luca.andreatta)

      I have the same problem with a Java postfunction, did you find a solution?

      1. Unknown User (maciek)

        Yes, i found solution, but last week i've found a second solution. here is it:

        1. (not sure it works correct in any time)

        put the code (attached in my post below) in post functions just after Reindex

        - THEN
        Re-index an issue to keep indexes in sync with the database.
        — THEN
        Jython post-function script: file travel/businesstravel_pf_close.py is referenced. File content is listed below:

        It wasn't works at different project. So i had to find other solution.

        2. use release() function and put... before Re-index.

        — THEN
        Jython post-function script: file inv/updateAssigneeAndLinks.py is referenced. File content is listed below:
        (...)
        ImportUtils.setIndexIssues(True)
        ComponentManager.getInstance().getIndexManager().reIndex(issue)
        ComponentManager.getInstance().getIndexManager().release()
        (...)
        
        — THEN
        Re-index an issue to keep indexes in sync with the database.

        And now it works perfectly.

        Nevertheless the second solution is clearly for me, I don't understand how works the first solution exatly. But works. :)

  84. Unknown User (zoom.license@zoomint.com)

    Hi all,

    we are planning to upgrade to Jira 5.0.7 where the scripting suite is compatible. I tried it in sandbox but my old scripts didn't work.

    We have simple scripot which get user groups, but after removal classes we do not know how to rewrite it. Could I ask somebody with better development skills for help?

    from com.atlassian.jira import ComponentManager
    
    autoGroups = [ "SAS", "MT" ]
    reporterGroups = issue.reporter.groups
    
    reporterInGroup = False
    for g in reporterGroups:
      if ( g in autoGroups ):
        reporterInGroup = True
    ...
    ...
    ...

    I found that issue has new method '.getReporter()' but I cant find how to get reporter groups.

    Thanks a lot

    1. Unknown User (robert.wolf@abacus.ch)

      Hallo,

      you habe to get CrowdService ComponentManager.getInstance().getCrowdService() and then see Crowd API

      http://docs.atlassian.com/crowd/current/com/atlassian/crowd/embedded/api/CrowdService.html

      Regards,

      Robert Wolf.

      1. Unknown User (zoom.license@zoomint.com)

        thanks a lot.. it works..

        question: i have currently in sandbox also 5.1.4 jira. JSS works well but when I click on "EDIT" link on jython post-function I can see only 2 buttons but can't change file or content of file. I have uploaded plugin quick-edit for 5.0.4.. is it because it is not compatible?

        1. Unknown User (robert.wolf@abacus.ch)

          I am not sure, what do you exactly mean, but I found now, that I am not able to edit "Global Edit Validation" and "Global Edit Postfunction" (Jira shows 404 Not Found com.quisapps.jira.plugin.action.admin.JSSSysScriptEditor.getRemoteUser()Lcom/opensymphony/user/User(wink) and we cannot edit currently assined jython validator and jython postfunctions in workflow transition (it shows only

          Type: class
          Class: com.quisapps.jira.plugin.workflow.JythonValidator
          Arguments:
          jythonSource = @validate-close-issue.py

          - I habe to check log files for errors) and if I want to add new validator/postfunction, then the jython validator/postfunction shows only button "Add" and link "Cancel". I am going to check log files.

          Regards,

          Wolf.

          1. Unknown User (zoom.license@zoomint.com)

            my misstake, i found that JSS didn't update though UPM to version 2.0. I have to did it manually (i was running on 1.2)

            But on 1.2 when I had an error in post-function (not global) script I saw error. Now I'm 100% sure that I have error in script but no error message is displayed.

            I have only this in log

            2012-09-06 11:09:41,014 http-81-7 ERROR marchyn 669x1422x1 1egbl1y 192.168.10.210 /secure/QuickCreateIssue!default.jspa [jira.web.dispatcher.JiraWebworkActionDispatcher] Exception thrown from action 'QuickCreateIssue!default', returning 404
            java.lang.NoClassDefFoundError: com/atlassian/jira/quickedit/action/QuickCreateIssue
          2. Unknown User (robert.wolf@abacus.ch)

            OK, my problem solved by updating to version 2.0.0 (Jira does not update this plugin automatically).

            You are right, there is some problem with quickedit plugin in jira 5.1.X, but you can still select files (we use files checked in subversion repo so no problem for us).

            I have enabled the quick edit actions, but then it is impossible to edit issue because of error

            2012-09-06 13:14:44,917 TP-Processor16 ERROR wolf 794x1971x1 1jw92lu 172.16.2.20 /secure/QuickEditIssue!default.jspa [jira.web.dispatcher.JiraWebworkActionDispatcher] Exception thrown from action 'QuickEditIssue!
            default', returning 404
            java.lang.NoClassDefFoundError: com/atlassian/jira/quickedit/action/QuickEditIssue
                    at java.lang.ClassLoader.defineClass1(Native Method)
                    at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
                    at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
                    at org.apache.felix.framework.ModuleImpl$ModuleClassLoader.findClass(ModuleImpl.java:1829)
                    at org.apache.felix.framework.ModuleImpl.findClassOrResourceByDelegation(ModuleImpl.java:716)
                    at org.apache.felix.framework.ModuleImpl.access$200(ModuleImpl.java:73)
                    at org.apache.felix.framework.ModuleImpl$ModuleClassLoader.loadClass(ModuleImpl.java:1690)
                    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
                    at org.apache.felix.framework.ModuleImpl.getClassByDelegation(ModuleImpl.java:634)
                    at org.apache.felix.framework.Felix.loadBundleClass(Felix.java:1594)
                    at org.apache.felix.framework.BundleImpl.loadClass(BundleImpl.java:887)
                    at com.atlassian.plugin.osgi.util.BundleClassLoaderAccessor$BundleClassLoader.findClass(BundleClassLoaderAccessor.java:75)
                    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
                    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
                    at com.atlassian.plugin.classloader.PluginsClassLoader.loadClassFromPlugins(PluginsClassLoader.java:150)
                    at com.atlassian.plugin.classloader.PluginsClassLoader.findClass(PluginsClassLoader.java:110)
                    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
                    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
                    at com.atlassian.jira.config.webwork.JiraActionFactory$JiraPluginActionFactory.loadFromPluginClassLoader(JiraActionFactory.java:548)
                    at com.atlassian.jira.config.webwork.JiraActionFactory$JiraPluginActionFactory.getActionImpl(JiraActionFactory.java:437)
                    at webwork.action.factory.PrefixActionFactoryProxy.getActionImpl(PrefixActionFactoryProxy.java:99)
                    at webwork.action.factory.JspActionFactoryProxy.getActionImpl(JspActionFactoryProxy.java:59)
                    at webwork.action.factory.CommandActionFactoryProxy.getActionImpl(CommandActionFactoryProxy.java:60)
                    at com.atlassian.jira.config.webwork.LookupAliasActionFactoryProxy.getActionImpl(LookupAliasActionFactoryProxy.java:59)
                    at webwork.action.factory.CommandActionFactoryProxy.getActionImpl(CommandActionFactoryProxy.java:51)
                    at webwork.action.factory.ContextActionFactoryProxy.getActionImpl(ContextActionFactoryProxy.java:36)
                    at webwork.action.factory.PrepareActionFactoryProxy.getActionImpl(PrepareActionFactoryProxy.java:37)
                    at com.atlassian.jira.config.webwork.JiraActionFactory$SafeParameterSettingActionFactoryProxy.getActionImpl(JiraActionFactory.java:157)
                    at webwork.action.factory.ChainingActionFactoryProxy.getActionImpl(ChainingActionFactoryProxy.java:53)
                    at com.atlassian.jira.config.webwork.JiraActionFactory.getActionImpl(JiraActionFactory.java:357)  <+2> (GenericDispatcher.java:137) (JiraWebworkActionDispatcher.java:153)
                    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)  <+14> (ApplicationFilterChain.java:290) (ApplicationFilterChain.java:206) (ChainedFilterStepRunner.java:78) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (XContentTypeOptionsNoSniffFilter.java:22) (AbstractHttpFilter.java:31) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (HeaderSanitisingFilter.java:44) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66)
                    at com.atlassian.labs.botkiller.BotKillerFilter.doFilter(BotKillerFilter.java:36)  <+3> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66)
                    at com.atlassian.jira.tzdetect.IncludeResourcesFilter.doFilter(IncludeResourcesFilter.java:39)  <+24> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66) (ContextFilter.java:25) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (AccessLogFilter.java:103) (AccessLogFilter.java:87) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (XsrfTokenAdditionRequestFilter.java:54) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (SiteMeshFilter.java:129) (SiteMeshFilter.java:77) (SitemeshPageFilter.java:124) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66)
                    at com.atlassian.labs.remoteapps.modules.permissions.ApiScopingFilter.doFilter(ApiScopingFilter.java:71)  <+41> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (SecurityFilter.java:234) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (TrustedApplicationsFilter.java:98) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (BaseLoginFilter.java:157) (JiraLoginFilter.java:70) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66) (OAuthFilter.java:71) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (ProfilingFilter.java:99) (JIRAProfilingFilter.java:19) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (AbstractJohnsonFilter.java:71) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (UrlRewriteFilter.java:738) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (GzipFilter.java:74) (GzipFilter.java:51) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66)
                    at com.atlassian.labs.remoteapps.modules.oauth.OAuth2LOFilter.doFilter(OAuth2LOFilter.java:70)  <+44> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66) (JWDSendRedirectFilter.java:25) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (ChainedFilterStepRunner.java:78) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (AbstractCachingFilter.java:33) (AbstractHttpFilter.java:31) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (AbstractEncodingFilter.java:41) (AbstractHttpFilter.java:31) (PathMatchingEncodingFilter.java:49) (AbstractHttpFilter.java:31) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (ActiveRequestsFilter.java:346) (ActiveRequestsFilter.java:463) (ActiveRequestsFilter.java:173) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (JiraStartupChecklistFilter.java:75) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (MultiTenantServletFilter.java:91) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (ChainedFilterStepRunner.java:78) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (StandardWrapperValve.java:233) (StandardContextValve.java:191) (StandardHostValve.java:127) (ErrorReportValve.java:102) (StandardEngineValve.java:109) (AccessLogValve.java:554) (CoyoteAdapter.java:298)
                    at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:190)
                    at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:291)
                    at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:776)
                    at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:705)
                    at org.apache.jk.common.ChannelSocket$SocketConnection.runIt(ChannelSocket.java:898)
                    at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:690)
                    at java.lang.Thread.run(Thread.java:662)
            Caused by: java.lang.ClassNotFoundException: com.atlassian.jira.quickedit.action.QuickEditIssue
                    at org.apache.felix.framework.ModuleImpl.findClassOrResourceByDelegation(ModuleImpl.java:772)
                    at org.apache.felix.framework.ModuleImpl.access$200(ModuleImpl.java:73)
                    at org.apache.felix.framework.ModuleImpl$ModuleClassLoader.loadClass(ModuleImpl.java:1690)
                    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
                    ... 170 more
            

            Problem is that the global edit postfunction/validator do not run, because they are disabled, because of installation error.

            Summary:

            using old JSS version 1.2 - the jira shows error "404 not found - com.quisapps.jira.plugin.action.admin.JSSSysScriptEditor.getRemoteUser()Lcom/opensymphony/user/User; ) on JSS script editing AND the global postfunction/validator does not work

            using new JSS version 2.0.0 - the jira show error "Global Edit Validation & Postfunction scripts are disabled due to installation problem: incompatible Quick Edit plugin." on JSS script editing AND the global postfunction/validator does not work

            JSS developers, do you think there will be some update for Jira 5.1.X soon?

            Regards,

            Wolf.

            1. Unknown User (rfrizzel)

              I'm planning an update to Jira 5.1.x soon and this is a wonderful plug-in that is an integral part of our JIRA instance. 

              Just wanted to echo the reply of Mr. Wolf above and say that, at least for me and him, that the inline editing part of JSS is less important rather than just the base functionality. In fact, if JSS was written in a way where the quick edit plugin is an optional feature of the plug-in and if a user chose not to install it, then they would just be given a file selection dropdown and just a plain old read-only text area showing the script. For me, I would be perfectly fine with editing the file behind the scenes and just having a basic read-only view of the script if it meant getting a version of JSS that is 5.1.x compatible. Like Mr. Wolf above, we control our scripts with source control anyway, so this would not be any trouble for us at all.

              In fact, you could even make the argument that some companies may not feel comfortable having the ease of use of editing the scripts inside of JIRA due to strictly controlling their JIRA instance for audit purposes.

              Finally, and this is only a guess so correct me if I am wrong, it seems that the quick edit plug-in is a major source of heartburn for JSS. Having the editing feature as an optional feature may allow others who are less interested in that feature to continue to use JSS without having to wait on the edit plug-in getting in the way of the basic functionality of JSS.

              I am not discounting the edit feature within JSS and I realize that it is important to many others, but maybe either simplifying the edit feature or truly making it an optional feature in JSS for those not as interested in it may help with keeping JSS up-to-date with the latest JIRA releases now and in the future.

              Thanks for hearing me out and again, thanks for a well-crafted, well-written JIRA plug-in!

  85. Unknown User (zoom.license@zoomint.com)

    Hi again,

    have another issue with JSS 2.0 on Jira 5.x and 5.1

    We had a code:

    Custom field 10080 is of type Multi Group Picker
    
    customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
    customField = customFieldManager.getCustomFieldObject(10080)
    from java.util import HashSet
    values = HashSet()
    values.add("MT")
    issue.setCustomFieldValue(customField, values)

    I have problem on last line isue.setCustomFieldValue

    I found in API that better is use http://docs.atlassian.com/jira/latest/index.html?com/atlassian/jira/issue/MutableIssue.html

    setCustomFieldValue
     void setCustomFieldValue(CustomField customField,
                             Object value) Sets a custom field value on this Issue Object, but does not write it to the database. This is highly misleading.
    To actually set a custom field value, use OrderableField.updateIssue(com.atlassian.jira.issue.fields.layout.field.FieldLayoutItem, MutableIssue, java.util.Map)
    
    Parameters:customField - the CustomFieldvalue - the value.

    I do not understand how to use  OrderableField.updateIssue

    Thanks a lot for any advice

    1. Unknown User (dariam)

      Hi,

      You can use customField.getCustomFieldType().updateValue() instead.

      In your case:

      Custom field 10080 is of type Multi Group Picker
      
      customFieldManager = ComponentManager.getInstance().getCustomFieldManager()
      customField = customFieldManager.getCustomFieldObject(10080)
      from java.util import HashSet
      values = HashSet()
      values.add("MT")
      customField.getCustomFieldType().updateValue(customField,issue,values)
      
  86. Unknown User (maciek)

    Hi all,

     how i can set assignee user in other exists issue?

    issueObject = issueManager.getIssueObject("INV-4346")
    issueObject.setAssignee(currentUser)
    

    do nothing (also after reindex issueObject). All i can do is read fields from the issueObject.

  87. Unknown User (bcohen)

    Can you have more then one listener script?  Currently, I have the com.quisapps.jira.plugin.listener.JythonListener with name "Jython" defined in my Listeners configuration, and I use the default workflow_event.py script for my code.

    If  I want a different listener script, what would I do?

    -Brian