issue.comment.delete_confirm_title=Delete Comment
issue.comment.delete_confirm_message=Do you want to delete this comment?
issue.comment.delete_confirm_button=Delete
+issue.transition.confirm=Confirm
+issue.transition.unconfirm=Unconfirm
issue.transition.resolve=Resolve
issue.transition.falsepositive=False-Positive
issue.transition.reopen=Reopen
issue.status.REOPENED=Reopened
issue.status.RESOLVED=Resolved
issue.status.OPEN=Open
+issue.status.CONFIRMED=Confirmed
issue.status.CLOSED=Closed
issue.resolution.OPEN=Open
issue.resolution.FALSE-POSITIVE=False-positive
public class IssueWorkflow implements BatchComponent, ServerComponent, Startable {
- private StateMachine machine;
private final FunctionExecutor functionExecutor;
private final IssueUpdater updater;
+ private StateMachine machine;
public IssueWorkflow(FunctionExecutor functionExecutor, IssueUpdater updater) {
this.functionExecutor = functionExecutor;
machine = StateMachine.builder()
// order is important for UI
- .states(Issue.STATUS_OPEN, Issue.STATUS_REOPENED, Issue.STATUS_RESOLVED, Issue.STATUS_CLOSED)
+ .states(Issue.STATUS_OPEN, Issue.STATUS_CONFIRMED, Issue.STATUS_REOPENED, Issue.STATUS_RESOLVED, Issue.STATUS_CLOSED)
+ .transition(Transition.builder(DefaultTransitions.CONFIRM)
+ .from(Issue.STATUS_OPEN).to(Issue.STATUS_CONFIRMED)
+ .functions(new SetResolution(null))
+ .build())
+ .transition(Transition.builder(DefaultTransitions.CONFIRM)
+ .from(Issue.STATUS_REOPENED).to(Issue.STATUS_CONFIRMED)
+ .functions(new SetResolution(null))
+ .build())
+ .transition(Transition.builder(DefaultTransitions.UNCONFIRM)
+ .from(Issue.STATUS_CONFIRMED).to(Issue.STATUS_OPEN)
+ .functions(new SetResolution(null))
+ .build())
.transition(Transition.builder(DefaultTransitions.RESOLVE)
.from(Issue.STATUS_OPEN).to(Issue.STATUS_RESOLVED)
.functions(new SetResolution(Issue.RESOLUTION_FIXED))
.from(Issue.STATUS_REOPENED).to(Issue.STATUS_RESOLVED)
.functions(new SetResolution(Issue.RESOLUTION_FIXED))
.build())
+ .transition(Transition.builder(DefaultTransitions.RESOLVE)
+ .from(Issue.STATUS_CONFIRMED).to(Issue.STATUS_RESOLVED)
+ .functions(new SetResolution(Issue.RESOLUTION_FIXED))
+ .build())
.transition(Transition.builder(DefaultTransitions.REOPEN)
.from(Issue.STATUS_RESOLVED).to(Issue.STATUS_REOPENED)
.functions(new SetResolution(null))
.conditions(new IsManual(false))
.functions(new SetResolution(Issue.RESOLUTION_FALSE_POSITIVE))
.build())
+ .transition(Transition.builder(DefaultTransitions.FALSE_POSITIVE)
+ .from(Issue.STATUS_CONFIRMED).to(Issue.STATUS_RESOLVED)
+ .conditions(new IsManual(false))
+ .functions(new SetResolution(Issue.RESOLUTION_FALSE_POSITIVE))
+ .build())
// automatic transitions
return machine.state(issue.status()).outManualTransitions(issue);
}
-
public void doAutomaticTransition(DefaultIssue issue, IssueChangeContext issueChangeContext) {
Transition transition = stateOf(issue).outAutomaticTransition(issue);
if (transition != null) {
import org.sonar.core.issue.IssueUpdater;
import javax.annotation.Nullable;
+
import java.util.Collection;
import java.util.Date;
import java.util.List;
workflow.start();
assertThat(workflow.machine()).isNotNull();
assertThat(workflow.machine().state(Issue.STATUS_OPEN)).isNotNull();
+ assertThat(workflow.machine().state(Issue.STATUS_CONFIRMED)).isNotNull();
assertThat(workflow.machine().state(Issue.STATUS_CLOSED)).isNotNull();
assertThat(workflow.machine().state(Issue.STATUS_REOPENED)).isNotNull();
assertThat(workflow.machine().state(Issue.STATUS_RESOLVED)).isNotNull();
public void should_list_statuses() throws Exception {
workflow.start();
// order is important for UI
- assertThat(workflow.statusKeys()).containsSequence(Issue.STATUS_OPEN, Issue.STATUS_REOPENED, Issue.STATUS_RESOLVED, Issue.STATUS_CLOSED);
+ assertThat(workflow.statusKeys()).containsSequence(Issue.STATUS_OPEN, Issue.STATUS_CONFIRMED, Issue.STATUS_REOPENED, Issue.STATUS_RESOLVED, Issue.STATUS_CLOSED);
}
@Test
- public void should_list_out_manual_transitions() throws Exception {
+ public void should_list_out_manual_transitions_from_status_open() throws Exception {
workflow.start();
DefaultIssue issue = new DefaultIssue().setStatus(Issue.STATUS_OPEN);
List<Transition> transitions = workflow.outTransitions(issue);
- assertThat(transitions).hasSize(2);
- assertThat(keys(transitions)).containsOnly("falsepositive", "resolve");
+ assertThat(transitions).hasSize(3);
+ assertThat(keys(transitions)).containsOnly("confirm", "falsepositive", "resolve");
+ }
+
+ @Test
+ public void should_list_out_manual_transitions_from_status_confirmed() throws Exception {
+ workflow.start();
+
+ DefaultIssue issue = new DefaultIssue().setStatus(Issue.STATUS_CONFIRMED);
+ List<Transition> transitions = workflow.outTransitions(issue);
+ assertThat(transitions).hasSize(3);
+ assertThat(keys(transitions)).containsOnly("unconfirm", "falsepositive", "resolve");
+ }
+
+ @Test
+ public void should_list_out_manual_transitions_from_status_resolved() throws Exception {
+ workflow.start();
+
+ DefaultIssue issue = new DefaultIssue().setStatus(Issue.STATUS_RESOLVED);
+ List<Transition> transitions = workflow.outTransitions(issue);
+ assertThat(transitions).hasSize(1);
+ assertThat(keys(transitions)).containsOnly("reopen");
+ }
+
+ @Test
+ public void should_list_out_manual_transitions_from_status_reopen() throws Exception {
+ workflow.start();
+
+ DefaultIssue issue = new DefaultIssue().setStatus(Issue.STATUS_REOPENED);
+ List<Transition> transitions = workflow.outTransitions(issue);
+ assertThat(transitions).hasSize(3);
+ assertThat(keys(transitions)).containsOnly("confirm", "resolve", "falsepositive");
}
@Test
* @since 3.6
*/
public interface DefaultTransitions {
+ String CONFIRM = "confirm";
+ String UNCONFIRM = "unconfirm";
String REOPEN = "reopen";
String RESOLVE = "resolve";
String FALSE_POSITIVE = "falsepositive";
int MESSAGE_MAX_SIZE = 4000;
String STATUS_OPEN = "OPEN";
+ String STATUS_CONFIRMED = "CONFIRMED";
String STATUS_REOPENED = "REOPENED";
String STATUS_RESOLVED = "RESOLVED";
String STATUS_CLOSED = "CLOSED";