Administration
- 1 Global settings
- 1.1 Create additional customfield(s)
- 1.2 Simple Example of a definition
- 1.3 Simple Example with additional user infos
- 1.4 Dynamic Rule(s) for more complex but flexible approaches
- 1.5 Complex Example with different syntax: use a customfield (multi-user or user picker) to dynamically specify voters
- 1.6 Complex Example with different syntax: a set of conditional definitions depending on issue's data
- 1.7 Different configurations depending on the value of a referenced custom field
- 1.8 Complex Example accessing issue's functions to dynamically retrieve approver name(s), here: issue's reporter
- 1.9 Complex Example display a Group Sign-Off field depending on its issue's status
- 1.10 Concat of multiple custom fields' contents
- 1.11 Different configurations depending on the value of a referenced custom field
- 1.12 Concat of multiple custom fields' contents (also: some maybe empty)
- 1.13 Approver of stories are determined by their epic's customfield 'Approvers'
- 1.14 Approver of stories are determined by their epic's customfield 'Approvers'
- 1.15 Additional Options
- 1.15.1 Vote/decide multiple times revoking prior one
- 1.15.2 Vote/decide multiple times revoking prior one - but limited to revert declines, only
- 1.15.3 Disable delegation of decisions
- 1.15.4 Confirm decision by entering password again (re-authenticate)
- 1.15.5 Disable forcing a comment if having declined
- 1.15.6 Mandatory comment if having declined (since version 2.10.4 for Jira 10 or 2.8.24 for older Jira version before 10)
- 1.15.7 Mandatory comment if having approved/signed-off (since version 2.10.6 for Jira 10 or 2.9.6 for Jira 9)
- 1.15.8 Overwrite standard behavior to reload an issue after deciding
- 1.15.9 Disable displaying individual users
- 1.15.10 Display decision buttons for deciders only if their decision has got an immediate and direct effect on the total result
- 1.15.11 Option for "maybe/uncertain" (available since version 2.8.6)
- 1.15.12 Force sequentially voting, one after the other, instead of parallel (available since version 2.8.19)
- 1.16 Simple Example of a definition with additional option in bold
- 1.17 Special Function(s)
- 2 Create additional listener(s) for automatic workflow transition(s)
- 3 Modify your workflow(s) with new Condition(s)
- 4 Modify your workflow(s) with new Validator(s)
- 5 Modify your workflow(s) with new Post Function(s)
- 6 Email-Notifications (available since v2.4.1)
- 7 Custom Events "Issue Signed-Off Event" and "Issue Declined Event" for automatic Notifications/Emails
- 8 Issue Property “jira.issue.editable“ depending on status
- 9 Using Jira Automation
- 10 JQL functions
- 11 Reporting
Jira system admins have to do a lot within larger companies and cannot take care about individual projects out of hundreds. Therefore, you can setup and configure all necessary sign-off/approval-rules for my app "Group Sign-Off/Multi-Approvals for Jira" as project administrator, now: such rule for sign-off/approval will be stored as a default value within a new context of the related custom field for the maintained project only. Additionally, all screens will be adjusted to also contain this Group Sign-Off field except for the screen of the issue-create-operation.
Global settings
Within the app's global configuration, you can specify some overall behaviors/features as shown below:
As a system admin, you can reach that panel by clicking on the button "Configure" of the expanded section "Group Sign-Off for JIRA" on your Jira page "Manage apps".
Create additional customfield(s)Please create any many new customfields of type "Group Sign-Off" as you need, like "Steering Committee", "Product Board" etc. Within this documentation, I am focussing on one new customfield named "Sign-Off". If you are not familiar with creation of new customfields, please have a look at the Atlassian documentation for this standard feature of JIRA. | |
In order to get the related unique ID of your new customfield, please click on the "configure" menu item as visible on the screenshot. | |
Within the URL, you will find the unique ID of your customfield as parameter, here: 10100. Please write it down to remember. You will need it while configuring listeners later. | |
You have to determine, who is allowed to make a decision. Using the feature of setting a default value of a customfield, you can define it once and it will be taken over while creating a new issue automatically.
Simple Example of a definitionfpolscheit If you want to put additional information in front of the user name, you can add this as comment straight after the user name without any spacing and enclosed by /* and */. Attention: you have to use the combination of name and comment as a unique identifier within the sign-off rule. Background: you may have different roles and act in different contexts. Simple Example with additional user infosfpolscheit/*Manager*/ | |
Dynamic Rule(s) for more complex but flexible approachesInstead of explicitly declaring a list of users and a sign-off rule using boolean algebra, you can specify a dynamic rule coded in JavaScript and using provided helper functions, which extract the users out of referred other custom fields like single- or multi-user pickers, etc. A dynamic rule MUST start with a first line just containing "// conditional rule". Then, users and a rule have to be defined as described below. The reserved words in blue within the following complex example are mandatory within a dynamic rule!
If you are using getUsersByCustomfield(), getUsersByProjectRole(), getUsersByGroup() the name of the referred element (custom field, project role or group) will be displayed in front of the retrieved user name since Group Sign-Off version 1.4.0. Complex Example with different syntax: use a customfield (multi-user or user picker) to dynamically specify voters// conditional rule users =""+helper.getUsersByCustomfield(issue,"Board Members",","); Please use the exact syntax above for dynamically specifying the list of user(s) based on the referred custom field. Users must be a comma separated list, that why the operand is a comma. The rule must be a sequence of users, concatenated by a boolean operand (AND or OR). By the first voting, the content of the customfield, referenced by name as parameter, will be taken over and the members will become a fix list. Instead of using the custom field's name, you can also use it's ID: please put that number into the quotes like "10023" instead of "Board Members". Complex Example with different syntax: a set of conditional definitions depending on issue's data// conditional rule Or you can get the value of a cascading-select-customfield and determine the deciders and their logic per field value: Within this sample, the custom field named „myCascadingSelection“ has got the options A-1, A-2, B-I, B-II … Different configurations depending on the value of a referenced custom field/// conditional rule var users = ""; var rule = ""; var yourCustomfieldName = "myCascadingSelection"; var data = helper.getCF(issue, yourCustomfieldName); if (data.get(null) == "A") { You can also access the following functions of an issue (similar to the functions officially provided by the Atlassian Java API):
Within the following sample, the issue's reporter is automatically retrieved and used as a decider this for approval: Complex Example accessing issue's functions to dynamically retrieve approver name(s), here: issue's reporter// conditional rule Often, you do not want to see a group sign-off field and its approvals through the complete life-cycle of an issue: you can limit displaying a group sign-off field only if its issue is within a certain status. Complex Example display a Group Sign-Off field depending on its issue's status// conditional rule
Suppose you use multiple custom fields to retrieve all users, who have to decide all together: in this case, you have to concatenate the custom fields' content and use a logical operator within the dynamic rule. The sample below illustrates a proper definition. Concat of multiple custom fields' contents// conditional rule users =""+helper.getUsersByCustomfield(issue,"Board Members",",") + helper.concat(helper.getUsersByCustomfield(issue,"Managers", ","), ","); All members of the custom field "Managers" will be appended but if there is at least one user, only. Since Group Sign-Off version 2.8, you can access an issue's fields a bit easier, just using Javascript-llike JSON-notation like issue.status.name. Or you can get the value of a single-select-customfield and determine the deciders and their logic per field value: Different configurations depending on the value of a referenced custom field// conditional rule var users = ""; var rule = ""; var yourCustomfieldName = "mySelection"; var yourCustomfieldValue = helper.getCF(issue, yourCustomfieldName); if (yourCustomfieldValue == "XYZ") { users += helper.getUsersByProjectRole(issue,"Deciders",","); rule += helper.getUsersByProjectRole(issue,"Deciders","OR"); } else if (yourCustomfieldValue == "ABC") { users += helper.getUsersByGroup(issue,"Approvers",","); rule += helper.getUsersByGroup(issue,"Approvers","AND"); } Or you can get the value of a cascading-select-customfield and determine the deciders and their logic per field value: Within this sample, the custom field named „myCascadingSelection“ has options A-1, A-2, B-I, B-II … Concat of multiple custom fields' contents (also: some maybe empty)// conditional rule users = "" + helper.getUsersByCustomfield(issue, "myApprovers1",",") rule = "" + helper.getUsersByCustomfield(issue, "myApprovers1","AND") + helper.concat(helper.getUsersByCustomfield(issue, "myApprovers2","AND"), "OR") + helper.concat(helper.getUsersByCustomfield(issue, "myApprovers3","AND"), "OR“); // in case that the first customfield 'myApprovers1' is empty: get rid of leading ',' users = users.replace(/^\s*,\s*/,"“); rule = rule.replace(/^\s*AND\s*/,"");
The following code sample is a generic template to concat all members of referenced custom fields (single- or mutli-user pickers) as well as referenced Jira group(s): Concat of multiple user-picker custom fields as well as Jira group(s): // conditional rule users = ""; rule = ""; const space = " "; // list off all multi-/single-user custom fields, participating in this decision ["Customfield-1", "Customfield-2", "Customfield-3"].forEach(customField => { if (customField) { const approvers = helper.getUsersByCustomfield(issue, customField, ","); if (approvers.length > 1) { users += helper.concat(approvers, users.length ? "," : ""); rule += helper.concat(helper.getUsersByCustomfield(issue, customField, "OR"), rule.length ? "AND" : space ); } } }); // list off all Jira groups, participating in this decision ["Jira-Group-1", "Jira-Group-2"].forEach(group => { if (group) { const approvers = helper.getUsersByGroup(issue, group, ","); if (approvers.length > 1) { users += helper.concat(approvers, users.length ? "," : ""); rule += helper.concat(helper.getUsersByGroup(issue, group, "OR"), rule.length ? "AND" : space ); } } });
Advanced feature for experienced power-user: DEPRECATED due to security aspects and removed in Group Sign-Off version 2.8:
Using these advanced features, you can configure suitable solutions for even more complex business scenarios. Approver of stories are determined by their epic's customfield 'Approvers'// conditional rule INSTEAD, please use: Approver of stories are determined by their epic's customfield 'Approvers'// conditional rule | Pay attention: using a dynamic rule, it's resulting set of deciders will be automatically turned into a static equivalent by the first decision for integrity reasons! Background information: if someone has voted (declined or signed-off) and the members of a decision would be changed later, you can manipulate the total result by removing deciders with unwanted votes or add additional deciders. To avoid this, an automatic transition into a fix set of deciders will be done together with the first vote. |
Additional OptionsAdditional options can be added at the end of the definition like shown below. Vote/decide multiple times revoking prior one
Vote/decide multiple times revoking prior one - but limited to revert declines, only
Disable delegation of decisions
Confirm decision by entering password again (re-authenticate)
Disable forcing a comment if having declined
Mandatory comment if having declined (since version 2.10.4 for Jira 10 or 2.8.24 for older Jira version before 10)
Mandatory comment if having approved/signed-off (since version 2.10.6 for Jira 10 or 2.9.6 for Jira 9)
Overwrite standard behavior to reload an issue after deciding
Disable displaying individual users
Display decision buttons for deciders only if their decision has got an immediate and direct effect on the total result
Option for "maybe/uncertain" (available since version 2.8.6)
Force sequentially voting, one after the other, instead of parallel (available since version 2.8.19)
Example(s) of using an option within the rule definition: Simple Example of a definition with additional option in boldfpolscheit | Re-authenticate by entering password to confirm decision if configured as option. |
Special Function(s)check(param1, param2, param-3, ..., param-n) for a certain amount of specified decisions: at least x deciders …with param-1: Boolean value TRUE or FALSE, whereas true indicates sign-off and false indicates decline Advanced Sample: sign-Off rule based on function calls and boolean algebra fpolscheit sign-off=check(true, 2, fpolscheit,representative,anotherPerson) OR check(false, 1, fpolscheit,representative,anotherPerson) If at least one decider declines, the sign-off will be "declined" or if at least two deciders have voted for sign-off, the result will be "signed-off". Based on 3 possible results of function check(null, true, false), the sequence of both function calls combined with OR is important: if you change both, it will not work properly! Based on boolean logic, false OR null results in null, whereas null OR false results in false which is what you would like to get. So, the check for declined votes via check(false,...) has to be the second part after the OR-connector. A more complex sample combines the check-function with other dynamic helper-functions retrieving sets of deciders: at least 2 deciders out of the project roles "Developers" and "Administrators" have to sign-off, so that this rule switches into the state "signed-off". But if 1 decider declines, it results into "declined", immediately. Complex Sample: combination of check-function with dyn. helper-functions // conditional rule Expanation: using a dynamic rule, that rule must get a string in quotes like rule = "check(true, 2, x, y, z) OR check(false, 1, x, y, z)", whereas x, y, z is build by helper-functions like a concat of getUsersByProjectRole().
wait_for_all( ... ): no straight-through processingwith a list of related deciders as comma-separated params as shown within the sample below: expand your sign-off rule by prepending a call to the function wait_for_all() if you want to overrule the default behavior of switching into the final state as soon as possible. Using a dynamic rule, you have to prepend a call to "wait_for_all()" by concat your original rule like illustrated within the following sample: Sample: Conditional rule using the function "wait_for_all()" // conditional rule
users = ""+helper.getUsersByCustomfield(issue,"Approvers",",");
rule = "wait_for_all(" + users+ ") " + helper.concat(helper.getUsersByCustomfield(issue,"Approvers","AND"), "AND");
majority( ... ): the final result is the majority decisionwith a list of related deciders as comma-separated params, as shown in the sample dynamic rule below: as soon as the majority of all deciders have either signed off/approved or declined, this becomes finally signed off resp. declined and will not wait until all deciders have voted to get the best straight-through processing (the pending decisions have no effect and are irrelevant, then). Sample: Conditional rule using the function "majority()" // conditional rule
users =""+helper.getUsersByProjectRole(issue,"Board Members",",");
rule = "majority(" + users + ")";You can also combine multiple special functions like: wait until all deciders have voted and set the final result to the majority one … // conditional rule
users =""+helper.getUsersByProjectRole(issue,"Board Members",",");
rule = "wait_for_all(" + users + ") AND majority(" + users + ")"; | |
Create additional listener(s) for automatic workflow transition(s)You can add multiple listeners to define a switch within your workflow. In case of a signed-off issue, the automatically executed workflow transition should be different from the one in case of declining that issue. As soon as enough individual decisions have been done to determine the final result of the overall decision, these listeners will execute the specified workflow transition immediately like JIRA's event system. Nobody has to check decisions manually! Since version 2.7.6 of Group Sign-Off, you can configure listeners which trigger the related workflow transition if all specified Group Sign-Off fields are all together within the referenced, final state "signed-off" or "declined": see screen copies on the right, too. To determine the overall result, all final decisions of these multi-fields are aggregated using AND-logical operations | |
After having created a new listener, you must edit it: just click on the related button on the right side of the listener.
|