package hudson.plugins.redmine;
import hudson.Extension;
import hudson.MarkupText;
import hudson.MarkupText.SubText;
import hudson.model.AbstractBuild;
import hudson.scm.ChangeLogAnnotator;
import hudson.scm.ChangeLogSet.Entry;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
/**
* Annotates <a href="http://www.redmine.org/wiki/redmine/RedmineSettings#Referencing-issues-in-commit-messages">RedmineLink</a>
* notation in changelog messages.
*
* @author gaooh
* @date 2008/10/13
*/
@Extension
public class RedmineLinkAnnotator extends ChangeLogAnnotator {
@Override
public void annotate(AbstractBuild<?, ?> build, Entry change, MarkupText text) {
RedmineProjectProperty rpp = build.getProject().getProperty(RedmineProjectProperty.class);
if(rpp == null || rpp.redmineWebsite == null) { // not configured
return;
}
String url = rpp.redmineWebsite;
for (LinkMarkup markup : MARKUPS) {
markup.process(text, url);
}
}
static final class LinkMarkup {
private final Pattern pattern;
private final String href;
LinkMarkup(String pattern, String href) {
pattern = NUM_PATTERN.matcher(pattern).replaceAll("([\\\\d|,| |&|#]+)"); // \\\\d becomes \\d when in the expanded text.
pattern = ANYWORD_PATTERN.matcher(pattern).replaceAll("((?:\\\\w|[._-])+)");
this.pattern = Pattern.compile(pattern);
this.href = href;
}
void process(MarkupText text, String url) {
for(SubText st : text.findTokens(pattern)) {
String[] message = st.getText().split(" ", 2);
if (message.length > 1) {
String[] nums = message[1].split(",|&| ");
String splitValue = ",";
if(message[1].indexOf("&") != -1) {
splitValue = "&";
} else if(message[1].indexOf("#") != -1) {
splitValue = "#";
} else if(message[1].indexOf(" ") != -1) {
splitValue = " ";
}
if(nums.length > 1) {
int startpos = 0;
int endpos = message[0].length() + nums[0].length() + 1;
nums[0] = nums[0].replace("#", "");
st.addMarkup(startpos, endpos, "<a href='"+url+ "issues/show/"+nums[0]+"'>", "</a>");
startpos = endpos + splitValue.length();
endpos = startpos;
for(int i = 1 ; i < nums.length ; i++) {
endpos += nums[i].length() ;
if(i != 1) {
endpos += splitValue.length();
}
if(endpos >= st.getText().length()) {
endpos = st.getText().length();
}
if(StringUtils.isNotBlank(nums[i])) {
nums[i] = nums[i].replace("#", "");
st.addMarkup(startpos, endpos, "<a href='"+url+"issues/show/"+nums[i].trim()+"'>", "</a>");
}
startpos = endpos + splitValue.length();
}
} else {
st.surroundWith("<a href='"+url+href+"'>","</a>");
}
} else {
st.surroundWith("<a href='"+url+href+"'>","</a>");
}
}
}
private static final Pattern NUM_PATTERN = Pattern.compile("NUM");
private static final Pattern ANYWORD_PATTERN = Pattern.compile("ANYWORD");
}
static final LinkMarkup[] MARKUPS = new LinkMarkup[] {
new LinkMarkup(
"(?:#|refs |references |IssueID |fixes |closes )NUM",
"issues/show/$1"),
new LinkMarkup(
"((?:[A-Z][a-z]+){2,})|wiki:ANYWORD",
"wiki/$1$2"),
};
}