Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
Expand Down
62 changes: 47 additions & 15 deletions src/main/java/org/jenkinsci/plugins/jiraext/view/Transition.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,19 @@
**************************************************************************/
package org.jenkinsci.plugins.jiraext.view;

import com.google.inject.Inject;
import hudson.Extension;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import org.apache.commons.lang.StringUtils;
import org.jenkinsci.plugins.jiraext.GuiceSingleton;
import org.jenkinsci.plugins.jiraext.domain.JiraCommit;
import org.jenkinsci.plugins.jiraext.svc.JiraClientSvc;
import org.kohsuke.stapler.DataBoundConstructor;
import java.util.logging.Logger;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/**
* Transition a JIRA issue
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a big enough change to warrant a new class. The previous behavior was determinate and easily communicated: try to call a transition on a ticket. If there's errors or it wasn't possible, log it and continue.

This new behavior is to try a transition on a ticket, and if that fails, call the next one until one works. Then go back and try all transitions.

What is the use-case here? Is it to get all tickets to a similar state (i.e closed)? IMO that is best solved with an update to Jira issue schema to allow such that as a single transition. Is there a reason that does not work, or is this for a different use-case entirely?

Expand All @@ -39,6 +40,7 @@
public class Transition
extends JiraOperationExtension
{
private Logger logger = Logger.getLogger(getClass().getSimpleName());

public String transitionName;

Expand All @@ -52,24 +54,54 @@ public Transition(String transitionName)
public void perform(List<JiraCommit> jiraCommitList,
AbstractBuild build, Launcher launcher, BuildListener listener)
{
try
{
for (JiraCommit jiraCommit : JiraCommit.filterDuplicateIssues(jiraCommitList))
{
try {
for (JiraCommit jiraCommit : JiraCommit.filterDuplicateIssues(jiraCommitList)) {
listener.getLogger().println("Transition a ticket: " + jiraCommit.getJiraTicket());
listener.getLogger().println("transitionName: " + transitionName);
try

//Make a copy of all transitions since we will be removing the ones that are done
List<String> transitions = Arrays.stream(StringUtils.split(transitionName, ","))
.map(t -> t.trim())
.collect(Collectors.toList());
boolean didAnyTransition = false;

//Loop through all transitions until one works
while (transitions.size() > 0)
{
getJiraClientSvc().changeWorkflowOfTicket(jiraCommit.getJiraTicket(), transitionName);
Iterator<String> transitionIter = transitions.iterator();
boolean didTransition = false;
while (transitionIter.hasNext())
{
String transition = transitionIter.next();
try
{
getJiraClientSvc().changeWorkflowOfTicket(jiraCommit.getJiraTicket(), transition);

//Transition worked. Remove it from the list, and try the next one
listener.getLogger().println("Performed transition: " + transition);
transitionIter.remove();
didAnyTransition = true;
didTransition = true;
} catch (Throwable t)
{
//Ignore and try next transition
logger.fine("JIRA transition " + transition + " failed on ticket " + jiraCommit.getJiraTicket());
}
}
if (!didTransition)
{
//Did not perform any transitions this round. We are done!
transitions.clear();
}
}
catch (Throwable t)

if (!didAnyTransition)
{
listener.getLogger().println("ERROR Updating JIRA, continuing");
t.printStackTrace(listener.getLogger());
//No transitions were done. Show error message
listener.getLogger().println("ERROR Updating JIRA with transitions [" + transitionName + "]. No transitions were valid. Continuing");
}

}
}
catch (Throwable t)
} catch (Throwable t)
{
listener.getLogger().println("ERROR Updating JIRA");
t.printStackTrace(listener.getLogger());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">

<f:entry title="Transition Name" field="transitionName">
<f:entry title="Transition Name(s)" field="transitionName">
<f:textbox />
</f:entry>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<div>
The name of the transition to use. For example: Close, Re-Open, or Resolve
The name(s) of one or more transition(s), separated by a comma. For example: Close, Re-Open, Resolve
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@
import hudson.model.FreeStyleProject;
import hudson.model.StreamBuildListener;
import hudson.model.TaskListener;
import net.rcarz.jiraclient.JiraException;
import org.jenkinsci.plugins.jiraext.MockChangeLogUtil;
import org.jenkinsci.plugins.jiraext.domain.JiraCommit;
import org.jenkinsci.plugins.jiraext.svc.JiraClientSvc;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import java.nio.charset.Charset;
import java.util.ArrayList;
Expand Down Expand Up @@ -88,6 +91,29 @@ public void testTransition()
verify(jiraClientSvc, times(1)).changeWorkflowOfTicket(eq("SSD-101"), eq("Resolve"));
}

/**
* Test multiple transitions when some are invalid.
*/
@Test
public void testMultipleTransition()
throws Exception
{
Transition transition = new Transition("Develop,Resolve,Closed");
transition.setJiraClientSvc(jiraClientSvc);
AbstractBuild mockBuild = mock(AbstractBuild.class);
when(mockBuild.getEnvironment(any(TaskListener.class))).thenReturn(new EnvVars());

doThrow(new JiraException("Invalid Transition")).when(jiraClientSvc).changeWorkflowOfTicket(eq("SSD-101"), eq("Develop"));

List<JiraCommit> jiraCommits = new ArrayList<>();
jiraCommits.add(new JiraCommit("SSD-101", MockChangeLogUtil.mockChangeLogSetEntry("Test Comment")));

transition.perform(jiraCommits, mockBuild, mock(Launcher.class), new StreamBuildListener(System.out, Charset.defaultCharset()));
verify(jiraClientSvc, times(2)).changeWorkflowOfTicket(eq("SSD-101"), eq("Develop"));
verify(jiraClientSvc, times(1)).changeWorkflowOfTicket(eq("SSD-101"), eq("Resolve"));
verify(jiraClientSvc, times(1)).changeWorkflowOfTicket(eq("SSD-101"), eq("Closed"));
}

/**
* An exception adding the first label add should not disrupt the next label
*/
Expand Down