Estimated time to read: 15 minutes
TL; DR:
Let's find a random sample of work items, such as for an internal audit, from a lookup result set. There are many internet sources for spreadsheet tools to randomly sample. This article is not trying to replace those. Instead, we have an example of how a problem may be split into pieces and solved one chunk at a time.
As a disclaimer we will use complicated, list operations, building upon techniques from two earlier articles on dynamic list searching and using created variables as numbers. So, "enjoy" or "beware": take your pick ;^)
What if my team leader wants to review completed work from the last few months...with a random sampling of 10 items:
GIVEN a set of N work items completed in the last few months
WHEN it is the first day of the quarter
THEN provide a review list of 10 work items randomly selected from the completed ones
SO THAT internal audit can compare the work to prior quarters
With the spreadsheet approach I noted earlier, one could identify and export the work items, and use a random selection without replacement approach. That is, we want 10 distinct work items from the set without duplicates.
How might we do that with an automation rule; what do we need?
We see some of our needs are directly supported with rule components, while others require us to get creative. Let's outline the approach:
Rules do not have a random sampling without replacement feature. We mitigate that by creating a large pool of random numbers within the range of our lookup results size (i.e., the count), removing any duplicates, and grabbing the first 10 of them for our sample. Those numbers represent an index into the lookup results. To get the actual work items' keys, we build a dynamic regular expression to extract the "winners". Finally, we compose that into a JQL expression for use by the requestor.
Using the rule for context, we explain how the pieces work, particularly the Create Variable actions. First, let's see the entire rule.
Other than the trigger and Lookup Work Items action at the beginning, the steps are essentially a series of Create Variable actions. These incrementally use each prior result to get to the answer.
Let's step through our earlier "needs" list to meet the goal.
Select source work items from which to draw the sampleWe create and test the JQL for the source work items. My example rule only looks for completed items for a single project: project = TOOLS AND statusCategory="Done" ORDER BY Key ASC You could add additional criteria, such as the work items completed within the last quarter using JQL functions, such as startOfMonth() and endOfMonth() with adjustment parameters. Remember this rule action can return up to 100 work items. Please see "Exercises for the reader" at the end of this article when you have more than 100 items.
|
Create a source list with index valuesWe gather information from the lookup results, keeping only the work item key and the position in the list: the index. That is stored in a variable for the final filtering later.
{{#debug}}{{#lookupIssues}}{{index}}:{{key}}{{^last}},{{/}}{{/}}{{/}} How does that work...
This produces a value such as this:
|
Generate a large pool of random numbersWe will need two variables to generate the large pool of numbers...
{{#debug}}{{null}}{{/}} Variables cannot be created empty in the rule editor, but we need an empty one as a starting point for our next expression. There is no smart value {{null}} and when an unknown smart value is used, that evaluates to an actual null value. And that then creates an empty string: a string with a length of 0. We covered this technique in the earlier article on using variables as numbers.
{{#debug}}{{#varNull.rightPad(2000, "X,").substringBeforeLast(",").replace("X", lookupIssues.size.format("###")).split(",")}}{{#=}}ROUND(({{.}}-1)*RANDOM(),0){{/}}{{^last}},{{/}}{{/}}{{/}} How does that work...
Whew! Yes, that is a complicated expression, and we used the same technique in the article on dynamic list searching. It produces a value such as this:
|
QUESTION: Why generate 1000 random numbers to sample 10 work items?
Although my testing indicates the built-in RANDOM() function produces a good-enough distribution, if your lookup result contains 100 work items, I would not recommend generating only 100 random numbers. The cost is small to generate a larger pool, and assuming the distribution is valid, you could easily reduce that range to a few hundred. Personally, I erred on the side of avoiding the possibility of too many duplicates, which would reduce the sample size.
Remove duplicate numbers from the poolThe sample we created has no limitations, and as we see above, it contains duplicate values. We need to eliminate those with the distinct function, and then get just the first 10 distinct values. And so, we run into the next challenge: although the {{index}} smart value would seem to help accomplish this, it cannot be used inside of a list filtering, conditional expression. We will defer this: check if a number is in the sample, but do no filtering yet.
{{#debug}}{{#varOneThousandRandomNumbers.split(",").distinct}}{{index.lt(10)}}:{{.}}{{^last}},{{/}}{{/}}{{/}} How does that work...
That produces a value which looks like this:
|
Gather the sample index valuesThen with one more variable, we get the actual list of indices in the sample:
{{#debug}}{{#varDistinctRandomNumbersWithIndexTest.split(",")}}{{#if(equals(substringBefore(":"),"true"))}}{{substringAfter(":")}},{{/}}{{/}}{{/}} How does that work...
|
Build a regular expression to filter for the work item keysWe have our list of indices, and we need to filter for the work item keys. We do that with a regular expression and the match() function.
{{#debug}}(^({{varSelectedRandomList.substringBeforeLast(",").split(",").join("|")}}):.*){{/}} How does that work...
This will find the 12th, 9th, 7th...and so on records and the work item keys.
|
Filter keys to build a JQL expressionApplying that regular expression to our very first variable from the Lookup Work Items result, we get what we wanted: JQL for Random Sample: How does that work...
The example rule only writes the JQL to the audit log. Your own sampling rule could instead send it as an email, Slack message, or perform additional processing on the sample work items.
|
Our rule is complete, and we can test it immediately (as it has a scheduled trigger). Here is a sample of the audit log with the results. I added the names of the Created Variables so you can see what the intermediate results look like...all the way up to the final JQL expression to return our sample. And, I expanded each debug section to show the details; by default, those are not visible in the log.
Wow, are you still reading? Awesome! If so, here are some additional things to try as exercises.
Exercises / discussion topics for the reader's teamWould you really ever use this rule, or only review it to learn techniques to help with other rules? Hint: Only you know the answer to that one :^)
How could I find more than 10 work items in the sample? Hint: You may change one single number for the variable varDistinctRandomNumbersWithIndexTest to impact the sample size. Can you find it?
How could I make the sample size (e.g., 10 items) configurable, such as with a manual trigger with user inputs? Hint: Consider the method with variables to dynamically generate the list of random numbers using rightPad() as a text string. Now consider the filtering done with a regular expression and match(). What if the configurable size of the sample was used to generate a regular expression with rightPad(), and that was then later used to filter instead of using the technique with true / false in varDistinctRandomNumbersWithIndexTest?
How could I sample from more than 100 work items? Hint: This rule uses the work item keys and the Lookup Work Items action. What if instead the work item ID values were used with the new REST API endpoint for enhanced search to get up to 5000 ID values? How would the rule change?
|
Yes, this was a very long, and very complicated rule scenario. I hope you found something of value to help your rule problem solving, even if you did not actually need to sample anything. I welcome any feedback you have on the scenario and article. And as always...
Happy rule writing!
Bill Sheboy
agile coach, idling
None
Atlassian Community
3,133 accepted answers
0 comments