Skip to content
This repository has been archived by the owner on Apr 6, 2022. It is now read-only.

Commit

Permalink
[JENKINS-12307] Make GroovyParser a describable object.
Browse files Browse the repository at this point in the history
  • Loading branch information
uhafner committed May 29, 2012
1 parent 41890f1 commit 0c94865
Show file tree
Hide file tree
Showing 22 changed files with 468 additions and 493 deletions.
5 changes: 3 additions & 2 deletions clean.sh
@@ -1,7 +1,8 @@
rm -rf $HUDSON_HOME/plugins/warnings*

mvn clean install
mvn clean install || { echo "Build failed"; exit 1; }

cp -f target/*.hpi $HUDSON_HOME/plugins/

cd $HUDSON_HOME
java -jar jenkins.war
./debug.sh
8 changes: 8 additions & 0 deletions src/clean.sh
@@ -0,0 +1,8 @@
rm -rf $HUDSON_HOME/plugins/warnings*

mvn install || { echo "Build failed"; exit 1; }

cp -f target/*.hpi $HUDSON_HOME/plugins/

cd $HUDSON_HOME
java -jar jenkins.war
261 changes: 191 additions & 70 deletions src/main/java/hudson/plugins/warnings/GroovyParser.java
@@ -1,23 +1,31 @@
package hudson.plugins.warnings;

import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import hudson.Extension;
import hudson.model.AbstractDescribableImpl;
import hudson.model.Descriptor;
import hudson.plugins.warnings.parser.Warning;
import hudson.util.FormValidation;
import hudson.util.FormValidation.Kind;

import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import org.apache.commons.lang.StringUtils;
import org.codehaus.groovy.control.CompilationFailedException;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;

/**
* Defines the properties of a warnings parser that uses a Groovy script to
* parse the warnings log.
*
* @author Ulli Hafner
*/
public class GroovyParser {
public class GroovyParser extends AbstractDescribableImpl<GroovyParser> {
private final String name;
private final String regexp;
private final String script;
Expand Down Expand Up @@ -47,6 +55,8 @@ public class GroovyParser {
@DataBoundConstructor
public GroovyParser(final String name, final String regexp, final String script, final String example,
final String linkName, final String trendName) {
super();

this.name = name;
this.regexp = regexp;
this.script = script;
Expand Down Expand Up @@ -92,9 +102,10 @@ private Object readResolve() {
* otherwise
*/
public boolean isValid() {
return doCheckScript(script).kind == FormValidation.Kind.OK
&& doCheckRegexp(regexp).kind == FormValidation.Kind.OK
&& doCheckName(name).kind == FormValidation.Kind.OK;
DescriptorImpl d = new DescriptorImpl();
return d.doCheckScript(script).kind == FormValidation.Kind.OK
&& d.doCheckRegexp(regexp).kind == FormValidation.Kind.OK
&& d.validate(name, Messages.Warnings_GroovyParser_Error_Name_isEmpty()).kind == FormValidation.Kind.OK;
}

/**
Expand Down Expand Up @@ -159,90 +170,200 @@ public String getExample() {
* multiple lines
*/
public boolean hasMultiLineSupport() {
return StringUtils.isNotBlank(regexp) && regexp.contains("\\n");
return containsNewline(regexp);
}

private static FormValidation validate(final String name, final String message) {
if (StringUtils.isBlank(name)) {
return FormValidation.error(message);
}
return FormValidation.ok();
private static boolean containsNewline(final String expression) {
return StringUtils.contains(expression, "\\n");
}

/**
* Performs on-the-fly validation on the name of the parser that needs to be unique.
* Descriptor to validate {@link GroovyParser}.
*
* @param name
* the name of the parser
* @return the validation result
* @author Ulli Hafner
*/
public static FormValidation doCheckName(final String name) {
return validate(name, Messages.Warnings_GroovyParser_Error_Name_isEmpty());
}
@Extension
public static class DescriptorImpl extends Descriptor<GroovyParser> {
private static final String NEWLINE = "\n";
private static final int MAX_MESSAGE_LENGTH = 60;

/**
* Performs on-the-fly validation on the link name of the parser.
*
* @param name
* the name of the link
* @return the validation result
*/
public static FormValidation doCheckLinkName(final String name) {
return validate(name, Messages.Warnings_GroovyParser_Error_LinkName_isEmpty());
}
private FormValidation validate(final String name, final String message) {
if (StringUtils.isBlank(name)) {
return FormValidation.error(message);
}
return FormValidation.ok();
}

/**
* Performs on-the-fly validation on the trend name of the parser.
*
* @param name
* the name of the trend
* @return the validation result
*/
public static FormValidation doCheckTrendName(final String name) {
return validate(name, Messages.Warnings_GroovyParser_Error_TrendName_isEmpty());
}
/**
* Performs on-the-fly validation on the name of the parser that needs to be unique.
*
* @param name
* the name of the parser
* @return the validation result
*/
public FormValidation doCheckName(@QueryParameter(required = true) final String name) {
return validate(name, Messages.Warnings_GroovyParser_Error_Name_isEmpty());
}

/**
* Performs on-the-fly validation on the regular expression.
*
* @param regexp
* the regular expression
* @return the validation result
*/
public static FormValidation doCheckRegexp(final String regexp) {
try {
if (StringUtils.isBlank(regexp)) {
return FormValidation.error(Messages.Warnings_GroovyParser_Error_Regexp_isEmpty());
}
Pattern.compile(regexp);
/**
* Performs on-the-fly validation on the project action link name.
*
* @param linkName
* the link name
* @return the validation result
*/
public FormValidation doCheckLinkName(@QueryParameter(required = true) final String linkName) {
return validate(linkName, Messages.Warnings_GroovyParser_Error_LinkName_isEmpty());
}

return FormValidation.ok();
/**
* Performs on-the-fly validation on the trend graph title.
*
* @param trendName
* the title of the trend graph
* @return the validation result
*/
public FormValidation doCheckTrendName(@QueryParameter(required = true) final String trendName) {
return validate(trendName, Messages.Warnings_GroovyParser_Error_TrendName_isEmpty());
}
catch (PatternSyntaxException exception) {
return FormValidation.error(Messages.Warnings_GroovyParser_Error_Regexp_invalid(exception.getLocalizedMessage()));

/**
* Performs on-the-fly validation on the regular expression.
*
* @param regexp
* the regular expression
* @return the validation result
*/
public FormValidation doCheckRegexp(@QueryParameter(required = true) final String regexp) {
try {
if (StringUtils.isBlank(regexp)) {
return FormValidation.error(Messages.Warnings_GroovyParser_Error_Regexp_isEmpty());
}
Pattern.compile(regexp);

return FormValidation.ok();
}
catch (PatternSyntaxException exception) {
return FormValidation.error(Messages.Warnings_GroovyParser_Error_Regexp_invalid(exception.getLocalizedMessage()));
}
}
}

/**
* Performs on-the-fly validation on the Groovy script.
*
* @param script
* the script
* @return the validation result
*/
public static FormValidation doCheckScript(final String script) {
try {
if (StringUtils.isBlank(script)) {
return FormValidation.error(Messages.Warnings_GroovyParser_Error_Script_isEmpty());
/**
* Performs on-the-fly validation on the Groovy script.
*
* @param script
* the script
* @return the validation result
*/
public FormValidation doCheckScript(@QueryParameter(required = true) final String script) {
try {
if (StringUtils.isBlank(script)) {
return FormValidation.error(Messages.Warnings_GroovyParser_Error_Script_isEmpty());
}

GroovyShell groovyShell = new GroovyShell(WarningsDescriptor.class.getClassLoader());
groovyShell.parse(script);

return FormValidation.ok();
}
catch (CompilationFailedException exception) {
return FormValidation.error(Messages.Warnings_GroovyParser_Error_Script_invalid(exception.getLocalizedMessage()));
}
}

/**
* Parses the example message with the specified regular expression and script.
*
* @param example
* example that should be resolve to a warning
* @param regexp
* the regular expression
* @param script
* the script
* @return the validation result
*/
public FormValidation doCheckExample(@QueryParameter final String example,
@QueryParameter final String regexp, @QueryParameter final String script) {
if (StringUtils.isNotBlank(example) && StringUtils.isNotBlank(regexp) && StringUtils.isNotBlank(script)) {
return parseExample(script, example, regexp, containsNewline(regexp));
}
else {
return FormValidation.ok();
}
}

GroovyShell groovyShell = new GroovyShell(WarningsDescriptor.class.getClassLoader());
groovyShell.parse(script);
/**
* Parses the example and returns a validation result of type
* {@link Kind#OK} if a warning has been found.
*
* @param script
* the script that parses the expression
* @param example
* example text that will be matched by the regular expression
* @param regexp
* the regular expression
* @param hasMultiLineSupport
* determines whether multi-lines support is activated
* @return a result of {@link Kind#OK} if a warning has been found
*/
private FormValidation parseExample(final String script, final String example, final String regexp, final boolean hasMultiLineSupport) {
Pattern pattern;
if (hasMultiLineSupport) {
pattern = Pattern.compile(regexp, Pattern.MULTILINE);
}
else {
pattern = Pattern.compile(regexp);
}
Matcher matcher = pattern.matcher(example);
if (matcher.find()) {
Binding binding = new Binding();
binding.setVariable("matcher", matcher);
GroovyShell shell = new GroovyShell(WarningsDescriptor.class.getClassLoader(), binding);
Object result = null;
try {
result = shell.evaluate(script);
}
catch (Exception exception) { // NOCHECKSTYLE: catch all exceptions of the Groovy script
return FormValidation.error(
Messages.Warnings_GroovyParser_Error_Example_exception(exception.getMessage()));
}
if (result instanceof Warning) {
StringBuilder okMessage = new StringBuilder(Messages.Warnings_GroovyParser_Error_Example_ok_title());
Warning warning = (Warning)result;
message(okMessage, Messages.Warnings_GroovyParser_Error_Example_ok_file(warning.getFileName()));
message(okMessage, Messages.Warnings_GroovyParser_Error_Example_ok_line(warning.getPrimaryLineNumber()));
message(okMessage, Messages.Warnings_GroovyParser_Error_Example_ok_priority(warning.getPriority().getLongLocalizedString()));
message(okMessage, Messages.Warnings_GroovyParser_Error_Example_ok_category(warning.getCategory()));
message(okMessage, Messages.Warnings_GroovyParser_Error_Example_ok_type(warning.getType()));
message(okMessage, Messages.Warnings_GroovyParser_Error_Example_ok_message(warning.getMessage()));
return FormValidation.ok(okMessage.toString());
}
else {
return FormValidation.error(Messages.Warnings_GroovyParser_Error_Example_wrongReturnType(result));
}
}
else {
return FormValidation.error(Messages.Warnings_GroovyParser_Error_Example_regexpDoesNotMatch());
}
}

return FormValidation.ok();
private void message(final StringBuilder okMessage, final String message) {
okMessage.append(NEWLINE);
int max = MAX_MESSAGE_LENGTH;
if (message.length() > max) {
int size = max / 2 - 1;
okMessage.append(message.substring(0, size));
okMessage.append("[...]");
okMessage.append(message.substring(message.length() - size, message.length()));
}
else {
okMessage.append(message);
}
}
catch (CompilationFailedException exception) {
return FormValidation.error(Messages.Warnings_GroovyParser_Error_Script_invalid(exception.getLocalizedMessage()));

@Override
public String getDisplayName() {
return StringUtils.EMPTY;
}
}
}
Expand Down
20 changes: 19 additions & 1 deletion src/main/java/hudson/plugins/warnings/ParserConfiguration.java
@@ -1,13 +1,18 @@
package hudson.plugins.warnings;

import hudson.Extension;
import hudson.model.AbstractDescribableImpl;
import hudson.model.Descriptor;

import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.DataBoundConstructor;

/**
* Defines the configuration to parse a set of files using a predefined parser.
*
* @author Ulli Hafner
*/
public class ParserConfiguration {
public class ParserConfiguration extends AbstractDescribableImpl<ParserConfiguration> {
private final String pattern;
private final String parserName;

Expand Down Expand Up @@ -42,5 +47,18 @@ public String getParserName() {
public String getPattern() {
return pattern;
}

/**
* Dummy descriptor for {@link ParserConfiguration}.
*
* @author Ulli Hafner
*/
@Extension
public static class DescriptorImpl extends Descriptor<ParserConfiguration> {
@Override
public String getDisplayName() {
return StringUtils.EMPTY;
}
}
}

0 comments on commit 0c94865

Please sign in to comment.