Stage 2: Implement Workflow Condition

Definition

In this tutorial you're going to implement the condition which prevents a user from closing a review when none of the reviewers have completed the review. 

How to start

Implement the com.atlassian.crucible.workflow.WorkflowCondition SPI class.  

@Named
public class CompletedReviewerWorkflowCondition implements WorkflowCondition {
    public ValidationResult validateTransition(WorkflowTransitionContext transitionContext) {
        return ValidationResult.ok();
    }
}

The condition in the current state doesn't do anything useful yet. To check for some conditions during the review transition, you must implement the validateTransition method. This method is called every time a review is being transitioned. It's up to you to verify that it's the transition type the condition should react to.

public ValidationResult validateTransition(WorkflowTransitionContext transitionContext) {
    if (isCloseReview(transitionContext.getTransitionAction())) {
        return doValidate(transitionContext.getReviewId());
    }
    return ValidationResult.ok();
}
 
private boolean isCloseReview(String transitionAction) {
    return ReviewService.Action.Close.getActionString().equals(transitionAction);
}

 

 The validateTransition method should return a ValidationResult, which can be of one of the following states:

  • OK - condition passes, review transition can be performed
  • WARN - condition fails, warnings can be skipped and the review transition performed
  • ERROR - conditions fails, review can't be transitioned without fixing validation errors

As soon as you defined the programmed condition to react only to closing a review you need to implement the condition check. For the purpose of this tutorial, the check verifies only if there's at least one reviewer who completed the review.

 

private ValidationResult doValidate(PermId<ReviewData> reviewId) {
    if (isAtLeastOneReviewerCompleted(reviewId)) {
        return ValidationResult.ok();
    }
    return ValidationResult.error(CompletedReviewerWorkflowCondition.class.getSimpleName(),
            new ResultMessage("No one completed the review",
                    "This review can't be closed until at least one reviewer completes it",
                    "This review can't be closed until at least one reviewer completes it"));
}
 
private boolean isAtLeastOneReviewerCompleted(PermId<ReviewData> reviewId) {
    return reviewService.getAllReviewers(reviewId).isEmpty()
            || !reviewService.getCompletedReviewers(reviewId).isEmpty();
}

 

A proper ValidationResult can be created using static factory methods and consists of:

  • result severity →  OK, WARN, ERROR
  • result key → which will be presented when the transition is invoked through the REST API and it fails
  • result message 
    • → Message which will be presented to an user once condition validation fails. Plugin developers are encouraged to write concise, short messages. Longer messages will be hidden under AUI Expander
    • → REST key which will be used to construct the REST call response
    • → REST message (optional) which will be used to construct the REST call response
    • → Optional list of actions to allow end user to interact with your plugin

Configuration

In previous step, you implemented CompletedReviewerWorkflowCondition, which defines the behaviour of your condition. Now, lis the condition in atlassian-plugin.xml in workflow-condition module to let FishEye/Crucible's plugin system know about it.

 

<workflow-condition
        key="completed-reviewers-condition"
        class="com.example.ampstutorial.CompletedReviewerWorkflowCondition">
</workflow-condition

 

The class is the class of the workflow condition, and the key are unique identifiers required by the plugin system. A single plugin can define multiple workflow-condition modules. Once the plugin module is configured, a review can't be closed it, until at least one reviewer completes it.

Invoking the transition using REST and JAVA APIs is also prohibited and will fail with an error. 

$ curl -u admin:admin -X POST http://localhost:3990/fecru/rest-service/reviews-v1/CR-2/transition.json\?action\=action:closeReview
{
  "reviewId": "CR-2",
  "message": "Some of workflow validation conditions have failed",
  "failedConditions": [
    {
      "resultKey": "CompletedReviewerWorkflowCondition",
      "message": "This review can't be closed until at least one reviewer completes it",
      "severity":"error"
    }
  ]
}

 

 

  Click here to see the complete Java class
CompletedReviewerWorkflowCondition.java
package com.example.ampstutorial;
 
import com.atlassian.crucible.spi.PermId;
import com.atlassian.crucible.spi.data.ReviewData;
import com.atlassian.crucible.spi.services.ReviewService;
import com.atlassian.crucible.workflow.ResultMessage;
import com.atlassian.crucible.workflow.ValidationResult;
import com.atlassian.crucible.workflow.WorkflowCondition;
import com.atlassian.crucible.workflow.WorkflowTransitionContext;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
 
import javax.inject.Inject;
import javax.inject.Named;
 
@Named
public class CompletedReviewerWorkflowCondition implements WorkflowCondition {
 
    private final ReviewService reviewService;
 
    @Inject
    public CompletedReviewerWorkflowCondition(@ComponentImport ReviewService reviewService,
                                              @ComponentImport SoyTemplateRenderer renderer) {
        this.reviewService = reviewService;
        this.renderer = renderer;
    }
 
    public ValidationResult validateTransition(PermId<ReviewData> reviewId, String transitionAction, @Nullable UserData currentUser) {
        if (isCloseReview(transitionAction)) {
            return doValidate(reviewId);
        }
        return ValidationResult.ok();
    }
 
    private boolean isCloseReview(String transitionAction) {
        return ReviewService.Action.Close.getActionString().equals(transitionAction);
    }
 
    private ValidationResult doValidate(PermId<ReviewData> reviewId) {
        if (isAtLeastOneReviewerCompleted(reviewId)) {
            return ValidationResult.ok();
        }
        return ValidationResult.error(CompletedReviewerWorkflowCondition.class.getSimpleName(),
                new ResultMessage("No one completed the review",
                        "This review can't be closed until at least one reviewer completes it",
                        "This review can't be closed until at least one reviewer completes it"));
    }
 
    private boolean isAtLeastOneReviewerCompleted(PermId<ReviewData> reviewId) {
        return reviewService.getAllReviewers(reviewId).isEmpty()
                || !reviewService.getCompletedReviewers(reviewId).isEmpty();
    }
}

 


 

Was this page helpful?

Have a question about this article?

See questions about this article

Powered by Confluence and Scroll Viewport