javascriptyoutrack

Update linked youtrack issue state in one project from state transition in another project


Any help with this would be greatly appreciated.

I have two youtrack projects 'Support' and 'Bug DB'. In the support project I have a workflow rule that a specific state transition to a state 'Awaiting Fix' automatically generates an issue in the 'Bug DB' project and links back to the original issue with an 'affects helpdesk log' link type.

In the 'Bug DB' project I want to add a rule to automatically update the state of the issue in the 'Support' project to 'Action Required' when a specific state transition occurs.

I can manage the state transition parts but I have two outstanding problems in my code for the 'Bug DB' project:

  1. Guard condition

Currently I have a function that (I hope) just checks that a link exists - ideally this should check that the link specifically points to an issue in the 'Support' project.

const issue_0 = ctx.issue;
...
function hasLinkedSupportIssue() {
  //I think this is equivalent to a C# .Any()
   return issue_0.links.added
   }

  1. Update

To apply the new state I am iterating the linked issues (because I don't know how to get a specific one)

issue_0.links['affects helpdesk log'].added.forEach(updateState)

and I then have a function that will do the actual update

const updateState = function(supportIssue) {
    //Check here that this is a 'Support' issue
    //because my guard is not sufficient
    if(supportIssue.project.key === 'Support') {
      //not sure I can do assignment like this
      supportIssue.state = ctx.SupportState.ActionRequired;
    }
  }
....
requirements: {
BugState: {
  name: "State",
  type: entities.State.fieldType,
  InProgress: {name: "In Progress"},
  Closed: {name: "Closed"}
},
SupportState: {
  name: "State",
  type: entities.State.fieldType,
  AwaitingFix: {name: "Awaiting Fix"},
  ActionRequired: {name: "Action Required"}
}


Solution

  • For anyone trying to do this, this was the eventual solution I came up with:

    var entities = require('@jetbrains/youtrack-scripting-api/entities');
    var workflow = require('@jetbrains/youtrack-scripting-api/workflow');
    
    exports.rule = entities.Issue.onChange({
      title: 'Support_bug_resolved',
      guard: (ctx) => {
        const logger = new Logger(ctx.traceEnabled);
     
        const thisIssue = ctx.issue;
    
        function checkFieldState() {
          //check that state is changing from closed to resolved
          return thisIssue.fields.isChanged(ctx.BugState) &&     thisIssue.fields.was(ctx.BugState, ctx.BugState.Resolved) && thisIssue.fields.becomes(ctx.BugState, ctx.BugState.Closed);
       }
    
        function hasLinkedSupportIssue() {
          //Check we have a linked issue from the support project
          return thisIssue.links["helpdesk log affected by"] != 0;
        }
    
        function checkFieldFn() {
          var check = checkFieldState();
          var hasLink = hasLinkedSupportIssue();
          return check && hasLink;
        };
    
       try {
          return checkFieldFn();
        } catch (err) {
          logger.error(err.message);
        }
      },
      action: function(ctx) {        
        const logger = new Logger(ctx.traceEnabled);
        
        const thisIssue = ctx.issue;  
        //Get the first linked support issue - we assume there is always only one
        const supportIssue = thisIssue.links['helpdesk log affected by'].first();
    
        try {
          //If the current state of the linked issue is 'Awaitingfix', make it 'ActionRequired'
          if(supportIssue.State.name == "AwaitingFix") {
            supportIssue.State = ctx.SupportState.ActionRequired;
          }
        } catch(err) {
          logger.error(err.message);
        }
        
        
      },
      requirements: {
        BugState: {
          name: "State",
          type: entities.State.fieldType,
          Resolved: {name: "Resolved"},
          Closed: {name: "Closed"}
        },
        SupportState: {
          name: "State",
          type: entities.State.fieldType,
          AwaitingFix: {name: "AwaitingFix"},
          ActionRequired: {name: "ActionRequired"}
        }
      }
    });
    
    function Logger(useDebug = true) {
      return {
        log: (...args) => useDebug && console.log(...args),
        warn: (...args) => useDebug && console.warn(...args),
        error: (...args) => useDebug && console.error(...args)
      }
    }