Jira automation - Is it possible to create nested lists?

Brandon Fish April 15, 2024

I'm not sure that my summary is descriptive enough, so here is my use case.

Issues are created in the project via an external form.  Part of that form allows submitters to select a department and one or more countries.  When multiple countries are selected, they are separated by a carriage return "\n".

The created task is then assigned based on the selected department and subtasks created for each selected country. Here's what my automation (triggered on issue create) does:

  1. Scrapes the description for the department
  2. Looks up the department in a lookuptable and returns a userID
  3. Assigns the issue to the ID
  4. Scrapes the description for the countries {{countryList}}
  5. For each country: {{countryList.split("\n")}}
    1. Lookup the country in a lookup table for a userID
    2. If the userID is the assignee of the task, then add the country as a label
    3. If the userID does not match the assignee of the task, create a subtask

Note, steps 5-2 and 5-3 are two separate For each: Smart value loops.

So basically, if a user is assigned to a tasks department and one or more countries, they will only be assigned the original task and no subtasks will be generated.  Users that aren't assigned to the department will get a subtask for each selected country for which they are responsible.

That all works great, but here is what I need to figure out:

Is it possible to create just one sub-task for each unique sub-task assignee instead of multiple?

For example, user1 is assigned to countries Spain, France and Italy. user 2 is assigned to UK, Canada.  A task is created that isn't assigned to either one of them.  Two subtasks should be created, The first one assigned to user 1 with the labels "Spain", "France" and "Italy", the second subtask assigned to user2 with the labels "UK" and "Canada".  As of right now, my automation creates a subtask for each.

I can't think of a reliable method to do this because of the limited options inside the For each loop.


Screenshot 2024-04-15 191144.pngScreenshot 2024-04-15 191114.png

1 answer

1 vote
Bill Sheboy
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
April 16, 2024

Hi @Brandon Fish 

For your step 5.2 if the userID is the assignee of the task, then add the country as a label, to which issue are you adding the label: 

  • the trigger issue
  • something else

If it is to the trigger issue, I suspect you could collapse the logic to one branch, always updating the trigger issue with either no change or use conditional logic in a JSON edit for the label.

 

If I have misunderstood your scenario, please let me know.  Thanks!

 

Kind regards,
Bill

Brandon Fish April 17, 2024

Hi Bill,

In 5.2 I'm adding a label to the trigger issue instead of creating a subtask.  That part is already working.  The tough part is creating the subtasks so that there is a unique assignee for each subtasks with the associated labels.

I actually have a solution in mind but it will be a bit of a hassle to get it tested and working, but basically, I'll convert the <new line> separated countries found in the description to a comma-separated list

countryList = country1,country2,country3,country4

Then do a series of replacements, one for each country that iterates the list and pre-pends the assignee to each country or consolidates the country list under an existing user in the string eventually ending up with something like

countryList = user1|country1|country3,user2|country2,user3|country4

Then my For each loop will have all the information it needs (user and countries) to create the subtasks.

I have a start already using if() but still working through it.  I just noticed that "|" is doing something strange, at least in the logs, so I may have to select an alternate secondary delimiter.

Bill Sheboy
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
April 17, 2024

Thanks for that information, and...I'll admit I spent a long time trying to get your scenario to work yesterday before I deleted my long-ish post to ask that question instead :^)

I also decided a delimited variable would be better than the table for the country-to-user mapping and the branch should iterate at the user level, not the country level from the trigger issue.

That being noted, some tips to help you are:

  • For variables, always add a prefix such as var to avoid the possibility of matching a field in an issue / object.  For example, use varCountryList instead of countryList
  • When parsing a field like Description into a list of values, like countries, explicitly provide the delimiter rather than allowing the rule to implicitly do so.  For example, assuming all of your countries are listed after the word "Countries", this forces the delimiter to a single comma:
    • {{issue.description.substringAfter("Countries:").split("\n").join(",")}}
  • Nested branching obviously does not work, or this scenario would be easy
  • Once inside of an iterator (e.g., your countryList) no other data is visible to filter / select
  • But, there is a workaround with dynamic regular expression matching and inline iteration
    • create a variable with the regular expression, built from the things to find, perhaps named varRegEx
    • split your country list from the Description, and use match(), such as
      • {{varListOfCountriesFromDescription.split(",").match(varRegEx)}}
    • add additional text functions to parse out the user
    • create the subtask with the needed labels

Good luck!

Brandon Fish April 17, 2024

Thanks @Bill Sheboy  Sounds like we are arriving at roughly the same conclusion.

Can you flesh out an example of dynamic regular expression matching and inline iteration?  I'm intrigued.  :D

Bill Sheboy
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
April 18, 2024

Certainly!  A basic example would be this:

  • When a field / data is needed in a regular expression, first create a variable
    • name: varRegEx
    • smart value: (value1|value2)
  • Then when searching a field / list, the varRegEx may be used in a match
    • {{issue.someField.match(varRegEx)}}

There are some extra steps if the search values could contain characters normally used in regular expressions, such as those found in date / time values.  In that case, the values need to be escaped first using another variable.

 

Back to your scenario, how could this be used?

  • Assuming the user-to-country data is stored like this:

User1;(CountryA|CountryB)~~User2;(CountryC)~~User3;(CountryD|CountryE)

  • That could be split on the ~~ to drive the advanced branch
  • Inside, split the branch variable into two variables: the user and the varRegEx
  • Create another variable to perform the match with varRegEx against the countries from the Description
  • Test if any were found, and...continue with your conditions to add the subtasks, add the labels, etc.

 

To ease maintenance, the user-to-country data could still be stored in lookup table in a people-friendly format, and then iterated to create the input to the advanced branch.

Brandon Fish April 19, 2024

My preference is to store the Country to user in a lookup table {{countryMap}} so that the project admin can update as needed.

I have it all working but I'd like a more elegant solution if I can find one.  Here's how it works:

Scrape the description for the list of countries and store in a comma delimited list {{countryList}} (adding an extra comma at the end)

{{issue.description.substringAfter("|*Countries*|").substringBefore("|").trim().split("\n").join(",")}},

Then, this is the clunky part, I iterate over the list by creating a variable {{varC}} with a country like "Spain" or "Italy" and updating {{countryList}}

{{if(countryList.indexOf(varC.concat(",")).gte(0), if(equals(taskAssignee,countryMap.get(varC).trim()), countryList.replace(varC.concat(","),""), if(countryList.indexOf(countryMap.get(varC).trim().concat("&&")).gte(0), countryList.replace(varC.concat(","),"").replace(countryMap.get(varC).trim().concat("&&"), countryMap.get(varC).trim().concat("&&").concat(varC).concat("&&")), countryList.replace(varC.concat(","), countryMap.get(varC).trim().concat("&&").concat(varC).concat(",")))), countryList)}}

That means I need two automation components for each country, one to set the country, one to apply it to the list.

To summarize the {{countryList}} iteration, it would look something like this

- If "country," is not found, return {{countryList}} unchanged
- Otherwise, if "country," is found:
- If the task assignee matches the country assignee, remove "country," from string
- Otherwise ,If the task assignee doesn't match then:
- If the country assignee is found in the string, then remove "country," and insert "country&&" after the found user ID + "$$"
- Otherwise, insert the user ID + "&&" before the country

The result is that

Spain,Italy,France,Argentina,

becomes

useraaaa&&Spain%%Argentina,userbbbb&&Italy,userccc%%France,

Then the subtask creation is easy by splitting on commas and then splitting on "&&" inside the For Each loop.

Of course the requesting user has changed there mind about not creating a separate subtask for the the assignee of the main ticket so I'll have to make some adjustments.  I also need to replace the country names with abbreviations to add to the subtask summary, but that is fairly easy with a long series of .replace("Italy","IT").replace("Argentina","AR") etc unless someone has a better idea.   :)

Bill Sheboy
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
April 19, 2024

Wow; I am glad to learn you found something that works!

Please consider...any approach that requires a lot of rule changes for updates to your user-to-country list could lead to errors.  Be on the lookout for other approaches to solve this in the future.

Suggest an answer

Log in or Sign up to answer
DEPLOYMENT TYPE
CLOUD
PRODUCT PLAN
STANDARD
TAGS
AUG Leaders

Atlassian Community Events