JIRA Workflow - Modifying Fix Version Field Through Post Function Plugin

I need help with creating a workflow post function that can clear the Fix Version field (set it to empty).

What I’m trying to do: During a specific workflow transition, I want to automatically remove all fix versions from an issue.

Current approach: I built a custom plugin that works but I’m worried it might not follow best practices. Here’s what I implemented:

public class VersionClearingPostFunction extends AbstractJiraFunctionProvider {
    // Method 1: Create empty version list
    public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException {
        MutableIssue ticket = this.getIssue(transientVars);
        Collection<Version> emptyVersions = new ArrayList<Version>();
        ticket.setFixVersions(emptyVersions);
        ticket.store();
    }
}

public class AlternativeVersionClearer extends AbstractJiraFunctionProvider {
    // Method 2: Clear existing version collection
    public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException {
        MutableIssue ticket = this.getIssue(transientVars);
        Collection existingVersions = ticket.getFixVersions();
        existingVersions.clear();
        ticket.setFixVersions(existingVersions);
        ticket.store();
    }
}

My concerns: I think the proper way should involve using ChangeItemBean, ModifiedValue, and IssueChangeHolder classes similar to how CustomFieldImpl handles updates.

Question: What’s the correct way to implement a post function plugin that modifies the Fix Version field while following JIRA development standards?

You’re absolutely right about using ChangeItemBean and ModifiedValue. I hit this same problem when building workflow automation for version management. Your current approach bypasses JIRA’s field update framework completely. When you call ticket.store() directly, you miss the change tracking that keeps data consistent. What fixed it for me was using IssueService instead of IssueManager. IssueService handles change tracking automatically: java public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException { MutableIssue issue = getIssue(transientVars); ApplicationUser user = (ApplicationUser) transientVars.get("caller"); IssueInputParameters inputParams = ComponentAccessor.getIssueService().newIssueInputParameters(); inputParams.setFixVersionIds(new Long[0]); // Empty array clears versions IssueService.UpdateValidationResult validationResult = ComponentAccessor.getIssueService().validateUpdate(user, issue.getId(), inputParams); if (validationResult.isValid()) { ComponentAccessor.getIssueService().update(user, validationResult); } } This way you get proper change history and stay consistent with how JIRA handles field updates everywhere else.

the issue.store() method’s deprecated in newer JIRA versions anyway. I’d use the IssueService approach instead, but heads up - validation errors can fail silently if you don’t check the result properly. Also make sure your user has permission to modify fix versions, otherwise the update just ignores the change without throwing any errors.

Both approaches work, but you’re right to worry about proper JIRA practices. Your current code bypasses JIRA’s change tracking and event system - that’s the main problem.

I’ve hit similar requirements before. The proper way is using IssueManager to create actual change history. Here’s what worked better for me:

public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException {
    MutableIssue issue = getIssue(transientVars);
    Collection<Version> originalVersions = issue.getFixVersions();
    
    if (!originalVersions.isEmpty()) {
        issue.setFixVersions(Collections.<Version>emptyList());
        
        IssueManager issueManager = ComponentAccessor.getIssueManager();
        User user = (User) transientVars.get("caller");
        
        IssueUpdateBean updateBean = new IssueUpdateBean(issue, issue, EventType.ISSUE_UPDATED_ID, user);
        issueManager.updateIssue(user, updateBean);
    }
}

This way you get proper change history and trigger events that other plugins or listeners need. The direct ticket.store() method messes with JIRA’s internal state and won’t generate audit trails.