Skip to end of metadata
Go to start of metadata

Cprime Apps has been rebranded as Anova Apps. Please note the only effect is the company name - all of our products’ names, logos, functionalities, support, etc. is exactly the same. The new location to our documentation space is https://anovaapps.atlassian.net.

Scenario

  • "Our developers don't want to estimate hours, they prefer to work in story points"
  • "Our developers don't want to log work, and we don't want to force them to. We have a process allergy"
  • "...but we still want to see roughly how much time is being spent on an issue"
  • "Oh, and also, we want to enforce Story Points as a Fibonacci sequence"

We'll show you how to do all of this using Power Scripts™ for Jira - a powerful scripting tool to help automate your Jira.

What These Scripts Do

  • Restrict the Story Points values to 1, 2, 3, 5, 8, 13 or <NULL> and returns error messaging and disables the submit button if an invalid value is present
  • When Story Points field is populated with a valid value, checks the map to hours and sets the Original Estimate and Estimate fields to the associated number of hours. Provides confirmation messaging and enables the submit button.
  • When an issue workflow transitions to a "resolved" status, the value in the Estimate field is "taken as credit" via worklog entry by the user who invoked the transition. Remaining estimate is then depleted.

Disclaimer

Mapping Story Points to hours isn't technically "agile", but we see this request often enough to offer this solution.

Prerequisites

  1. You have Jira Software installed
  2. You have Power Scripts™ for Jira installed
  3. You have mapped the Story Points custom field to its customfield ID in the "sil.aliases" file.

Configure Live Field Listener

You should configure this script as a Live Field script for the relevant project.

/* This script checks for changes to the story points field and updates the 
Estimate and Original Estimate fields based on a Story Point to Hours Mapping

Use this script in conjunction with 
lfExecutor_CreateEstimatesFromStoryPoints.sil and SetWorklogToEstimatedHours.sil

Note that you have to map the field storyPoints to a customfield ID in
sil.aliases file.

And that the executor script is given as an absolute location
as opposed to relative because the listener was invoked via a subfolder.

You'd normally want to have your live field listeners and executors in your
root folder so you can call it by name only.
*/

if(argv["screen"] == "create" || argv["screen"] == "edit") {
    lfWatch("storyPoints", {"storyPoints"}, "/var/atlassian/application-data/jira/powerscripts.cprime.io/silprograms/!Examples-ModsRequired/lfExecutor_CreateEstimateFromStoryPoints.sil" , {"keyup"});
    }

Listener References Live Field Executor

/* This script takes the user's input for the Story Point field on create
or edit screens and immediately updates the Estimate and Original Estimate
fields based on a mapping of story points to hours. It also restricts
the storyPoints field such that only Fibonacci sequences are allowed.

Use in conjunction with lfListener_CreateEstimatesFromStoryPoints.sil and
SetWorklogToEstimatedHours.sil

Note that this requires a mapping for storyPoints custom field to customfield
ID in sil.aliases file
*/

interval timeEstimate;
interval timeOriginalEstimate;
string errorMsg;

if (argv["storyPoints"] != "") {
    number dataEntered = argv["storyPoints"];
    if (dataEntered == 1) {
        timeEstimate = "2h";
        timeOriginalEstimate = "2h";
        lfEnable("editSubmit");
        lfEnable("transitionSubmit");
        lfEnable("createIssueSubmit");
        lfEnable("issueCreateSubmit");
    }
    else if (dataEntered == 2) {
        timeEstimate = "4h";
        timeOriginalEstimate = "4h";
        lfEnable("editSubmit");
        lfEnable("transitionSubmit");
        lfEnable("createIssueSubmit");
        lfEnable("issueCreateSubmit");
    }
    else if (dataEntered == 3) {
        timeEstimate = "1d";
        timeOriginalEstimate = "1d";
        lfEnable("editSubmit");
        lfEnable("transitionSubmit");
        lfEnable("createIssueSubmit");
        lfEnable("issueCreateSubmit");
    }
    else if (dataEntered == 5) {
        timeEstimate = "2d";
        timeOriginalEstimate = "2d";
        lfEnable("editSubmit");
        lfEnable("transitionSubmit");
        lfEnable("createIssueSubmit");
        lfEnable("issueCreateSubmit");
    }
    else if (dataEntered == 8) {
        timeEstimate = "3d";
        timeOriginalEstimate = "3d";
        lfEnable("editSubmit");
        lfEnable("transitionSubmit");
        lfEnable("createIssueSubmit");
        lfEnable("issueCreateSubmit");
    }
    else if (dataEntered == 13) {
        timeEstimate = "5d";
        timeOriginalEstimate = "5d";
        lfEnable("editSubmit");
        lfEnable("transitionSubmit");
        lfEnable("createIssueSubmit");
        lfEnable("issueCreateSubmit");
    }
    else {
        errorMsg = "Please enter a valid value for Story Points";
        lfDisable("editSubmit");
        lfDisable("transitionSubmit");
        lfDisable("createIssueSubmit");
        lfDisable("issueCreateSubmit");
    }


  if (errorMsg != "") {
    lfShowFieldMessage("storyPoints", errorMsg, "ERROR");
  }
  else {
    lfSet("estimate", timeEstimate);
    lfSet("originalEstimate", timeOriginalEstimate);
    lfShowFieldMessage("storyPoints", "Estimated Hours changed to "+timeEstimate, "INFO");
  }
}

Configure "Resolved" Workflow Transition Post Function

In the relevant workflow, you should configure this script as a SIL™ Post Function when the issue is complete.

/* This script is called from a workflow transition post-function when an issue
closes with a successful resolution. It takes the estimated hours field, and uses
that value to generate a worklog for the exact same amount of time by the
users who invokes the transition.

This is used in conjunction with lfExecutor_CreateEstimateFromStoryPoints.sil
and lfListener_CreateEstimateFromStoryPoints.sil
*/

addWorklogAdjustEstimate(key, currentUser(), estimate, currentDate(), "automated worklog on successful resolution");

/* Of course, you'd want to add some logic or scripts that removes the worklog
if the issue is later reopened.. these things need to be thought through.
*/

See also