diff --git a/pom.xml b/pom.xml index 5f9267abe..d8a3d3adf 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ warnings hpi Warnings Plug-in - 4.61 + 4.63-SNAPSHOT http://wiki.jenkins-ci.org/x/G4CGAQ This plug-in reads the compiler warnings from the console log file and generates a trend report. @@ -44,7 +44,12 @@ org.jvnet.hudson.plugins analysis-core - 1.82 + 1.86 + + + org.jenkins-ci.plugins + script-security + 1.25 org.jenkins-ci.plugins @@ -57,11 +62,6 @@ commons-digester3 3.2 - - org.jenkins-ci.plugins - script-security - 1.17 - org.jenkins-ci.plugins.workflow workflow-scm-step diff --git a/src/main/java/hudson/plugins/warnings/GroovyParser.java b/src/main/java/hudson/plugins/warnings/GroovyParser.java index e6e27e813..f8675c28f 100644 --- a/src/main/java/hudson/plugins/warnings/GroovyParser.java +++ b/src/main/java/hudson/plugins/warnings/GroovyParser.java @@ -12,12 +12,16 @@ import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; -import groovy.lang.GroovyShell; +import jenkins.model.Jenkins; import hudson.Extension; import hudson.model.AbstractDescribableImpl; import hudson.model.Descriptor; -import hudson.plugins.warnings.parser.*; +import hudson.plugins.warnings.parser.AbstractWarningsParser; +import hudson.plugins.warnings.parser.DynamicDocumentParser; +import hudson.plugins.warnings.parser.DynamicParser; +import hudson.plugins.warnings.parser.GroovyExpressionMatcher; +import hudson.plugins.warnings.parser.Warning; import hudson.util.FormValidation; import hudson.util.FormValidation.Kind; @@ -28,7 +32,6 @@ * @author Ulli Hafner */ public class GroovyParser extends AbstractDescribableImpl { - private static final int MAX_EXAMPLE_SIZE = 4096; private final String name; @@ -223,6 +226,7 @@ public AbstractWarningsParser getParser() { public static class DescriptorImpl extends Descriptor { private static final String NEWLINE = "\n"; private static final int MAX_MESSAGE_LENGTH = 60; + private static final FormValidation NO_RUN_SCRIPT_PERMISSION_WARNING = FormValidation.warning(Messages.Warnings_GroovyParser_Warning_NoRunScriptPermission()); private FormValidation validate(final String name, final String message) { if (StringUtils.isBlank(name)) { @@ -293,13 +297,16 @@ public FormValidation doCheckRegexp(@QueryParameter(required = true) final Strin * @return the validation result */ public FormValidation doCheckScript(@QueryParameter(required = true) final String script) { + if (!canRunScripts()) { + return NO_RUN_SCRIPT_PERMISSION_WARNING; + } try { if (StringUtils.isBlank(script)) { return FormValidation.error(Messages.Warnings_GroovyParser_Error_Script_isEmpty()); } - GroovyShell groovyShell = new GroovyShell(WarningsDescriptor.class.getClassLoader()); - groovyShell.parse(script); + GroovyExpressionMatcher matcher = new GroovyExpressionMatcher(script, null); + matcher.compile(); return FormValidation.ok(); } @@ -308,6 +315,10 @@ public FormValidation doCheckScript(@QueryParameter(required = true) final Strin } } + private boolean canRunScripts() { + return Jenkins.getInstance().getACL().hasPermission(Jenkins.RUN_SCRIPTS); + } + /** * Parses the example message with the specified regular expression and script. * @@ -321,6 +332,9 @@ public FormValidation doCheckScript(@QueryParameter(required = true) final Strin */ public FormValidation doCheckExample(@QueryParameter final String example, @QueryParameter final String regexp, @QueryParameter final String script) { + if (!canRunScripts()) { + return NO_RUN_SCRIPT_PERMISSION_WARNING; + } if (StringUtils.isNotBlank(example) && StringUtils.isNotBlank(regexp) && StringUtils.isNotBlank(script)) { FormValidation response = parseExample(script, example, regexp, containsNewline(regexp)); if (example.length() <= MAX_EXAMPLE_SIZE) { diff --git a/src/main/java/hudson/plugins/warnings/WarningsDescriptor.java b/src/main/java/hudson/plugins/warnings/WarningsDescriptor.java index 684ea322c..4adeb6558 100644 --- a/src/main/java/hudson/plugins/warnings/WarningsDescriptor.java +++ b/src/main/java/hudson/plugins/warnings/WarningsDescriptor.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.util.Collection; +import org.jenkinsci.Symbol; import org.kohsuke.stapler.Ancestor; import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.QueryParameter; @@ -28,7 +29,7 @@ * * @author Ulli Hafner */ -@Extension(ordinal = 100) // NOCHECKSTYLE +@Extension(ordinal = 100) @Symbol("warnings") public final class WarningsDescriptor extends PluginDescriptor implements StaplerProxy { /** The ID of this plug-in is used as URL. */ static final String PLUGIN_ID = "warnings"; diff --git a/src/main/java/hudson/plugins/warnings/WarningsPublisher.java b/src/main/java/hudson/plugins/warnings/WarningsPublisher.java index 1143a2caf..acc849e94 100644 --- a/src/main/java/hudson/plugins/warnings/WarningsPublisher.java +++ b/src/main/java/hudson/plugins/warnings/WarningsPublisher.java @@ -9,6 +9,9 @@ import java.util.Set; import org.apache.commons.lang.StringUtils; +import org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException; +import org.jenkinsci.plugins.scriptsecurity.scripts.ApprovalContext; +import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; @@ -367,19 +370,29 @@ private List parseConsoleLog(final Run run, final FilePath w String parserName = parser.getParserName(); logger.log("Parsing warnings in console log with parser " + parserName); - Collection warnings = new ParserRegistry(ParserRegistry.getParsers(parserName), - getDefaultEncoding()).parse(run.getLogFile()); - if (!workspace.isRemote()) { - guessModuleNames(workspace, warnings); - } - ParserResult project = new ParserResult(workspace, canResolveRelativePaths()); - project.addAnnotations(warnings); + try { + Collection warnings = new ParserRegistry(ParserRegistry.getParsers(parserName), + getDefaultEncoding()).parse(run.getLogFile()); + if (!workspace.isRemote()) { + guessModuleNames(workspace, warnings); + } + ParserResult project = new ParserResult(workspace, canResolveRelativePaths()); + project.addAnnotations(warnings); - results.add(annotate(run, workspace, filterWarnings(project, logger), parserName)); + results.add(annotate(run, workspace, filterWarnings(project, logger), parserName)); + } + catch (RejectedAccessException exception) { + handleRejectedException(logger, parserName, exception); + } } return results; } + private void handleRejectedException(final PluginLogger logger, final String parserName, final RejectedAccessException exception) { + logger.log(Messages.Warnings_GroovyParser_Warning_Rejected(parserName, exception.getMessage())); + ScriptApproval.get().accessRejected(exception, ApprovalContext.create()); + } + private ParserResult filterWarnings(final ParserResult project, final PluginLogger logger) { WarningsFilter filter = new WarningsFilter(); if (filter.isActive(getIncludePattern(), getExcludePattern(), getMessagesPattern(), getCategoriesPattern())) { @@ -410,11 +423,17 @@ private List parseFiles(final Run run, final FilePath worksp FilesParser parser = new FilesParser(PLUGIN_NAME, filePattern, new FileWarningsParser(ParserRegistry.getParsers(parserName), getDefaultEncoding()), shouldDetectModules(), isMavenBuild(run), canResolveRelativePaths()); - ParserResult project = workspace.act(parser); - logger.logLines(project.getLogMessages()); + ParserResult project = null; + try { + project = workspace.act(parser); + logger.logLines(project.getLogMessages()); - returnIfCanceled(); - results.add(annotate(run, workspace, filterWarnings(project, logger), configuration.getParserName())); + returnIfCanceled(); + results.add(annotate(run, workspace, filterWarnings(project, logger), configuration.getParserName())); + } + catch (RejectedAccessException exception) { + handleRejectedException(logger, parserName, exception); + } } return results; } diff --git a/src/main/java/hudson/plugins/warnings/parser/AbstractWarningsParser.java b/src/main/java/hudson/plugins/warnings/parser/AbstractWarningsParser.java index 92ce2aa7e..65e951475 100644 --- a/src/main/java/hudson/plugins/warnings/parser/AbstractWarningsParser.java +++ b/src/main/java/hudson/plugins/warnings/parser/AbstractWarningsParser.java @@ -8,10 +8,10 @@ import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringEscapeUtils; +import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.Whitelisted; import org.jvnet.localizer.Localizable; import hudson.ExtensionPoint; - import hudson.plugins.analysis.util.model.FileAnnotation; import hudson.plugins.analysis.util.model.Priority; import hudson.plugins.warnings.Messages; @@ -189,6 +189,7 @@ protected String getId() { * the message of the warning * @return the warning */ + @Whitelisted public Warning createWarning(final String fileName, final int start, final String category, final String message) { return new Warning(fileName, start, getGroup(), category, message); } @@ -205,6 +206,7 @@ public Warning createWarning(final String fileName, final int start, final Strin * the message of the warning * @return the warning */ + @Whitelisted public Warning createWarning(final String fileName, final int start, final String message) { return createWarning(fileName, start, StringUtils.EMPTY, message); } @@ -224,6 +226,7 @@ public Warning createWarning(final String fileName, final int start, final Strin * the priority of the warning * @return the warning */ + @Whitelisted public Warning createWarning(final String fileName, final int start, final String category, final String message, final Priority priority) { return new Warning(fileName, start, getGroup(), category, message, priority); } @@ -246,6 +249,7 @@ public Warning createWarning(final String fileName, final int start, final Strin * @return the warning * @since 4.24 */ + @Whitelisted public Warning createWarning(final String fileName, final int start, final String type, final String category, final String message, final Priority priority) { return new Warning(fileName, start, type, category, message, priority); } @@ -264,6 +268,7 @@ public Warning createWarning(final String fileName, final int start, final Strin * the priority of the warning * @return the warning */ + @Whitelisted public Warning createWarning(final String fileName, final int start, final String message, final Priority priority) { return createWarning(fileName, start, StringUtils.EMPTY, message, priority); } @@ -295,6 +300,7 @@ public String getLargeImage() { * the line number (as a string) * @return the line number */ + @Whitelisted protected final int getLineNumber(final String lineNumber) { return convertLineNumber(lineNumber); } @@ -309,6 +315,7 @@ protected final int getLineNumber(final String lineNumber) { * @return the line number * @since 4.37 */ + @Whitelisted public static int convertLineNumber(final String lineNumber) { if (StringUtils.isNotBlank(lineNumber)) { try { @@ -328,6 +335,7 @@ public static int convertLineNumber(final String lineNumber) { * @return the escaped text * @see StringEscapeUtils#escapeXml11 */ + @Whitelisted protected String escapeXml(final String text) { return StringEscapeUtils.escapeXml10(text); } diff --git a/src/main/java/hudson/plugins/warnings/parser/GroovyExpressionMatcher.java b/src/main/java/hudson/plugins/warnings/parser/GroovyExpressionMatcher.java index 0faf3de2e..980360769 100644 --- a/src/main/java/hudson/plugins/warnings/parser/GroovyExpressionMatcher.java +++ b/src/main/java/hudson/plugins/warnings/parser/GroovyExpressionMatcher.java @@ -1,11 +1,15 @@ package hudson.plugins.warnings.parser; import java.io.Serializable; +import java.util.concurrent.Callable; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import org.codehaus.groovy.control.CompilationFailedException; +import org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException; +import org.jenkinsci.plugins.scriptsecurity.sandbox.Whitelist; +import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox; import groovy.lang.Binding; import groovy.lang.GroovyShell; @@ -26,7 +30,6 @@ public class GroovyExpressionMatcher implements Serializable { private transient Script compiled; - /** * Creates a new instance of {@link GroovyExpressionMatcher}. * @@ -43,19 +46,30 @@ public GroovyExpressionMatcher(final String script, final Warning falsePositive) private void compileScriptIfNotYetDone() { synchronized (script) { if (compiled == null) { - GroovyShell shell = new GroovyShell(WarningsDescriptor.class.getClassLoader()); try { - compiled = shell.parse(script); + compiled = compile(); } catch (CompilationFailedException exception) { LOGGER.log(Level.SEVERE, "Groovy dynamic warnings parser: exception during compiling: ", exception); } - - compiled.getBinding().setVariable("falsePositive", falsePositive); } } } + /** + * Compiles the script. + * + * @return the compiled script + * @throws CompilationFailedException if the script contains compile errors + */ + public Script compile() throws CompilationFailedException { + ClassLoader loader = GroovySandbox.createSecureClassLoader(WarningsDescriptor.class.getClassLoader()); + Binding binding = new Binding(); + binding.setVariable("falsePositive", falsePositive); + GroovyShell shell = new GroovyShell(loader, binding, GroovySandbox.createSecureCompilerConfiguration()); + return shell.parse(script); + } + /** * Creates a new annotation for the specified match. * @@ -64,16 +78,20 @@ private void compileScriptIfNotYetDone() { * @param lineNumber * the current line number * @return a new annotation for the specified pattern + * @throws RejectedAccessException if the Groovy sandbox rejected the parsing script */ - public Warning createWarning(final Matcher matcher, final int lineNumber) { + public Warning createWarning(final Matcher matcher, final int lineNumber) throws RejectedAccessException { try { Object result = run(matcher, lineNumber); if (result instanceof Warning) { return (Warning)result; } } + catch (RejectedAccessException exception) { + throw exception; // Groovy sandbox rejected the parsing script: needs to be presented to the user + } catch (Exception exception) { // NOPMD NOCHECKSTYLE: catch all exceptions of the Groovy script - LOGGER.log(Level.SEVERE, "Groovy dynamic warnings parser: exception during parsing: ", exception); + LOGGER.log(Level.SEVERE, "Groovy dynamic warnings parser: exception during execution: ", exception); } return falsePositive; } @@ -86,15 +104,29 @@ public Warning createWarning(final Matcher matcher, final int lineNumber) { * @param lineNumber * the current line number * @return unchecked result of the script + * @throws RejectedAccessException if the Groovy sandbox rejected the parsing script */ - public Object run(final Matcher matcher, final int lineNumber) { + public Object run(final Matcher matcher, final int lineNumber) throws RejectedAccessException { compileScriptIfNotYetDone(); Binding binding = compiled.getBinding(); binding.setVariable("matcher", matcher); binding.setVariable("lineNumber", lineNumber); - return compiled.run(); + try { + return GroovySandbox.runInSandbox(new Callable() { + @Override public Object call() throws Exception { + return compiled.run(); + } + }, Whitelist.all()); + } + catch (RejectedAccessException exception) { + throw exception; // Groovy sandbox rejected the parsing script: needs to be presented to the user + } + catch (Exception exception) { + LOGGER.log(Level.SEVERE, "Groovy dynamic warnings parser: exception during execution: ", exception); + return falsePositive; + } } /** diff --git a/src/main/java/hudson/plugins/warnings/parser/GroovyWhiteList.java b/src/main/java/hudson/plugins/warnings/parser/GroovyWhiteList.java new file mode 100644 index 000000000..649e447e4 --- /dev/null +++ b/src/main/java/hudson/plugins/warnings/parser/GroovyWhiteList.java @@ -0,0 +1,22 @@ +package hudson.plugins.warnings.parser; + +import java.io.IOException; + +import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.ProxyWhitelist; +import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.StaticWhitelist; + +import hudson.Extension; + +/** + * Registers a whitelist from the plug-in resource {@link #WHITELIST_FILE_NAME}. + * + * @author Ullrich Hafner + */ +@Extension +public class GroovyWhiteList extends ProxyWhitelist { + private static final String WHITELIST_FILE_NAME = "groovy.whitelist"; + + public GroovyWhiteList() throws IOException { + super(StaticWhitelist.from(GroovyWhiteList.class.getResource(WHITELIST_FILE_NAME))); + } +} diff --git a/src/main/java/hudson/plugins/warnings/parser/JavacParser.java b/src/main/java/hudson/plugins/warnings/parser/JavacParser.java index f8f2192bb..1f1387798 100644 --- a/src/main/java/hudson/plugins/warnings/parser/JavacParser.java +++ b/src/main/java/hudson/plugins/warnings/parser/JavacParser.java @@ -17,7 +17,7 @@ public class JavacParser extends RegexpLineParser { static final String JAVA_LARGE_ICON = WarningsDescriptor.IMAGE_PREFIX + "java-48x48.png"; private static final long serialVersionUID = 7199325311690082782L; - private static final String JAVAC_WARNING_PATTERN = "^(?:\\[WARNING\\]\\s+)?([^\\[]*):\\[(\\d+)[.,;]*(\\d+)?\\]\\s*(?:\\[(\\w+)\\])?\\s*(.*)$"; + private static final String JAVAC_WARNING_PATTERN = "^(?:\\[\\p{Alnum}*\\]\\s+)?(?:\\[WARNING\\]\\s+)?([^\\[]*):\\[(\\d+)[.,;]*(\\d+)?\\]\\s*(?:\\[(\\w+)\\])?\\s*(.*)$"; /** * Creates a new instance of {@link JavacParser}. diff --git a/src/main/java/hudson/plugins/warnings/parser/RFLintParser.java b/src/main/java/hudson/plugins/warnings/parser/RFLintParser.java new file mode 100644 index 000000000..d0ff30fe5 --- /dev/null +++ b/src/main/java/hudson/plugins/warnings/parser/RFLintParser.java @@ -0,0 +1,85 @@ +package hudson.plugins.warnings.parser; + +import hudson.Extension; +import hudson.console.ConsoleNote; +import hudson.plugins.analysis.util.model.FileAnnotation; +import hudson.plugins.analysis.util.model.Priority; +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.LineIterator; + +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A parser for Robot Framework + * Parse output from robotframework-lint + * To generate rflint file + * cmd$ pip install robotframework-lint + * cmd$ rflint path/to/test.robot + * Created by traitanit on 3/27/2017 AD. + */ +@Extension +public class RFLintParser extends RegexpLineParser { + + private static final String RFLINT_ERROR_PATTERN = "([W|E|I]): (\\d+), (\\d+): (.*) \\((.*)\\)"; + private static final String RFLINT_FILE_PATTERN = "\\+\\s(.*)"; + private String fileName; + + public RFLintParser(){ + super(Messages._Warnings_RFLint_ParserName(), + Messages._Warnings_RFLint_LinkName(), + Messages._Warnings_RFLint_TrendName(), + RFLINT_ERROR_PATTERN); + } + + @Override + public Collection parse(Reader file) throws IOException { + List warnings = new ArrayList(); + LineIterator iterator = IOUtils.lineIterator(file); + Pattern filePattern = Pattern.compile(RFLINT_FILE_PATTERN); + try { + while (iterator.hasNext()) { + String line = ConsoleNote.removeNotes(iterator.nextLine()); + // check if line contains file name. + Matcher matcher = filePattern.matcher(line); + if (matcher.find()) { + fileName = matcher.group(1); + } + findAnnotations(line, warnings); + } + } + finally { + iterator.close(); + } + return warnings; + } + + @Override + protected Warning createWarning(Matcher matcher) { + String message = matcher.group(4); + String category = classifyIfEmpty(matcher.group(1), message); + Priority priority = Priority.LOW; + switch (category.charAt(0)){ + case 'E': + priority = Priority.HIGH; + category = "ERROR"; + break; + case 'W': + priority = Priority.NORMAL; + category = "WARNING"; + break; + case 'I': + priority = Priority.LOW; + category = "IGNORE"; + break; + default: + break; + } + return createWarning(fileName, getLineNumber(matcher.group(2)), category, message, priority); + } +} diff --git a/src/main/java/hudson/plugins/warnings/parser/RegexpLineParser.java b/src/main/java/hudson/plugins/warnings/parser/RegexpLineParser.java index c6eef5738..357a2b49d 100644 --- a/src/main/java/hudson/plugins/warnings/parser/RegexpLineParser.java +++ b/src/main/java/hudson/plugins/warnings/parser/RegexpLineParser.java @@ -8,10 +8,10 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.io.LineIterator; +import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.Whitelisted; import org.jvnet.localizer.Localizable; import hudson.console.ConsoleNote; - import hudson.plugins.analysis.util.model.FileAnnotation; /** @@ -119,6 +119,7 @@ protected Collection postProcessWarnings(final List warnings = parse("javac-parallel-pipeline.txt"); + + assertEquals(WRONG_NUMBER_OF_WARNINGS_DETECTED, 2, warnings.size()); + + String fileName = "C:/Build/Results/jobs/ADT-Base/workspace/com.avaloq.adt.ui/src/main/java/com/avaloq/adt/ui/elements/AvaloqDialog.java"; + Iterator expectedWarnings = Arrays.asList( + new Warning(fileName, 12, WARNING_TYPE, "Deprecation", "org.eclipse.jface.contentassist.SubjectControlContentAssistant in org.eclipse.jface.contentassist has been deprecated"), + new Warning(fileName, 40, WARNING_TYPE, "Deprecation", "org.eclipse.ui.contentassist.ContentAssistHandler in org.eclipse.ui.contentassist has been deprecated") + ).iterator(); + + Iterator iterator = warnings.iterator(); + while (iterator.hasNext()) { + assertTrue(WRONG_NUMBER_OF_WARNINGS_DETECTED, expectedWarnings.hasNext()); + Warning expectedWarning = expectedWarnings.next(); + checkWarning(iterator.next(), expectedWarning.getPrimaryLineNumber(), expectedWarning.getMessage(), expectedWarning.getFileName(), expectedWarning.getType(), expectedWarning.getCategory(), expectedWarning.getPriority()); + } + } + private Collection parse(final String fileName) throws IOException { return new JavacParser().parse(openFile(fileName)); } diff --git a/src/test/java/hudson/plugins/warnings/parser/ParserRegistryIntegrationTest.java b/src/test/java/hudson/plugins/warnings/parser/ParserRegistryIntegrationTest.java index 1cf2df6b2..9f5dd6294 100644 --- a/src/test/java/hudson/plugins/warnings/parser/ParserRegistryIntegrationTest.java +++ b/src/test/java/hudson/plugins/warnings/parser/ParserRegistryIntegrationTest.java @@ -13,12 +13,14 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.io.input.ReaderInputStream; -import org.junit.Rule; +import org.junit.ClassRule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.TestExtension; import org.jvnet.localizer.Localizable; +import com.google.common.collect.Lists; + import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import static org.junit.Assert.*; @@ -26,6 +28,8 @@ import hudson.plugins.analysis.util.model.AnnotationContainer; import hudson.plugins.analysis.util.model.DefaultAnnotationContainer; import hudson.plugins.analysis.util.model.FileAnnotation; +import hudson.plugins.warnings.GroovyParser; +import hudson.plugins.warnings.GroovyParserTest; /** * Tests the class {@link ParserRegistry} in context of a running Jenkins instance. @@ -34,7 +38,7 @@ */ public class ParserRegistryIntegrationTest { /** If you add a new parser then this value needs to be adapted. */ - private static final int NUMBER_OF_AVAILABLE_PARSERS = 65; + private static final int NUMBER_OF_AVAILABLE_PARSERS = 66; private static final String OLD_ID_ECLIPSE_JAVA_COMPILER = "Eclipse Java Compiler"; private static final String JAVA_WARNINGS_FILE = "deprecations.txt"; private static final String OLD_ID_JAVA_COMPILER = "Java Compiler"; @@ -42,8 +46,34 @@ public class ParserRegistryIntegrationTest { private static final String NEW_API = "New Parser API"; private static final String OLD_API = "Old Parser API"; - @Rule - public JenkinsRule jenkins = new JenkinsRule(); + @ClassRule + public static JenkinsRule jenkins = new JenkinsRule(); + + /** + * Tests the construction of dynamic parsers. + */ + @Test + public void testDynamicParsers() { + GroovyParser multi = new GroovyParser("name", GroovyParserTest.MULTI_LINE_REGEXP, "empty"); + GroovyParser single = new GroovyParser("name", GroovyParserTest.SINGLE_LINE_REGEXP, "empty"); + + List allParsers = ParserRegistry.getDynamicParsers(Lists.newArrayList(single, multi)); + + int multiNumber = 0; + int singleNumber = 0; + + for (AbstractWarningsParser parser : allParsers) { + if (parser.getClass() == DynamicParser.class) { + singleNumber++; + } + else if (parser.getClass() == DynamicDocumentParser.class) { + multiNumber++; + } + } + + assertEquals("Wrong number of single line parsers" , 1, singleNumber); + assertEquals("Wrong number of multi line parsers" , 1, multiNumber); + } /** * Parses a warning log with 7 warnings, 2 have no category. diff --git a/src/test/java/hudson/plugins/warnings/parser/ParserRegistryTest.java b/src/test/java/hudson/plugins/warnings/parser/ParserRegistryTest.java index 5577ee6b5..b9a824905 100644 --- a/src/test/java/hudson/plugins/warnings/parser/ParserRegistryTest.java +++ b/src/test/java/hudson/plugins/warnings/parser/ParserRegistryTest.java @@ -20,8 +20,6 @@ import hudson.plugins.analysis.core.ParserResult; import hudson.plugins.analysis.util.NullLogger; import hudson.plugins.analysis.util.model.FileAnnotation; -import hudson.plugins.warnings.GroovyParser; -import hudson.plugins.warnings.GroovyParserTest; /** * Tests the class {@link ParserRegistry}. @@ -242,31 +240,5 @@ protected Reader createReader(final File file) throws FileNotFoundException { }; return parserRegistry; } - - /** - * Tests the construction of dynamic parsers. - */ - @Test - public void testDynamicParsers() { - GroovyParser multi = new GroovyParser("name", GroovyParserTest.MULTI_LINE_REGEXP, "empty"); - GroovyParser single = new GroovyParser("name", GroovyParserTest.SINGLE_LINE_REGEXP, "empty"); - - List allParsers = ParserRegistry.getDynamicParsers(Lists.newArrayList(single, multi)); - - int multiNumber = 0; - int singleNumber = 0; - - for (AbstractWarningsParser parser : allParsers) { - if (parser.getClass() == DynamicParser.class) { - singleNumber++; - } - else if (parser.getClass() == DynamicDocumentParser.class) { - multiNumber++; - } - } - - assertEquals("Wrong number of single line parsers" , 1, singleNumber); - assertEquals("Wrong number of multi line parsers" , 1, multiNumber); - } } diff --git a/src/test/java/hudson/plugins/warnings/parser/RFLintParserTest.java b/src/test/java/hudson/plugins/warnings/parser/RFLintParserTest.java new file mode 100644 index 000000000..339b96309 --- /dev/null +++ b/src/test/java/hudson/plugins/warnings/parser/RFLintParserTest.java @@ -0,0 +1,78 @@ +package hudson.plugins.warnings.parser; + +import hudson.plugins.analysis.util.model.FileAnnotation; +import hudson.plugins.analysis.util.model.Priority; +import org.junit.Test; + +import java.io.IOException; +import java.util.Collection; +import java.util.Iterator; +import java.util.Locale; + +import static org.junit.Assert.assertEquals; + +/** + * Tests the class {@link RFLintParser}. + * Created by traitanit on 3/27/2017 AD. + */ +public class RFLintParserTest extends ParserTester { + private static final String WARNING_TYPE = Messages._Warnings_RFLint_ParserName().toString(Locale.ENGLISH); + + /** + * Parses a txt file, containing 6 warnings. + * + * @throws IOException + * if the file could not be read + */ + @Test + public void rfLintTest() throws IOException { + Collection warnings = new RFLintParser().parse(openFile()); + + assertEquals(WRONG_NUMBER_OF_WARNINGS_DETECTED, 6, warnings.size()); + Iterator iterator = warnings.iterator(); + FileAnnotation warning; + + warning = iterator.next(); + checkWarning(warning, + 25, + "Line is too long (exceeds 100 characters)", + "./Login_to_web.robot", + WARNING_TYPE, "WARNING", Priority.NORMAL); + warning = iterator.next(); + checkWarning(warning, + 40, + "No keyword documentation", + "./Login_to_web.robot", + WARNING_TYPE, "ERROR", Priority.HIGH); + warning = iterator.next(); + checkWarning(warning, + 24, + "Line is too long (exceeds 100 characters)", + "./Merchant_Signup.robot", + WARNING_TYPE, "WARNING", Priority.NORMAL); + warning = iterator.next(); + checkWarning(warning, + 378, + "No keyword documentation", + "./Merchant_Signup.robot", + WARNING_TYPE, "ERROR", Priority.HIGH); + warning = iterator.next(); + checkWarning(warning, + 73, + "Too few steps (1) in keyword", + "./merchant_common_keyword.txt", + WARNING_TYPE, "WARNING", Priority.NORMAL); + warning = iterator.next(); + checkWarning(warning, + 123, + "Ignore Error", + "./merchant_common_keyword.txt", + WARNING_TYPE, "IGNORE", Priority.LOW); + + } + + @Override + protected String getWarningsFile() { + return "rflint.txt"; + } +} diff --git a/src/test/resources/hudson/plugins/warnings/parser/javac-parallel-pipeline.txt b/src/test/resources/hudson/plugins/warnings/parser/javac-parallel-pipeline.txt new file mode 100644 index 000000000..4c918199f --- /dev/null +++ b/src/test/resources/hudson/plugins/warnings/parser/javac-parallel-pipeline.txt @@ -0,0 +1,77 @@ +[ParallelStep] started +[ParallelStep] [workspace] $ mvn.bat clean compile -DeclipseTarget=C:/Build/Results/jobs/ADT-Base-Target/workspace/eclipse +[ParallelStep] [INFO] [clean:clean] +[ParallelStep] [INFO] Deleting directory C:\Build\Results\jobs\ADT-Base\workspace\com.avaloq.adt.ui\target +[ParallelStep] [INFO] Deleting directory C:\Build\Results\jobs\ADT-Base\workspace\com.avaloq.adt.ui\target\classes +[ParallelStep] [INFO] Deleting directory C:\Build\Results\jobs\ADT-Base\workspace\com.avaloq.adt.ui\target\test-classes +[ParallelStep] [INFO] Deleting directory C:\Build\Results\jobs\ADT-Base\workspace\com.avaloq.adt.ui\target\site +[ParallelStep] [INFO] [resources:resources] +[ParallelStep] [INFO] Using default encoding to copy filtered resources. +[ParallelStep] [INFO] [psteclipse:update {execution: update}] +[ParallelStep] [INFO] Defaulting prefixes to the single prefix 'com.avaloq.'. +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant/1.7.0/org.apache.ant-1.7.0.jar +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant/1.7.0/org.apache.ant-1.7.0.jar +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant/1.7.0/org.apache.ant.ant-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant/1.7.0/org.apache.ant.ant-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-antlr/1.7.0/org.apache.ant.ant-antlr-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-antlr/1.7.0/org.apache.ant.ant-antlr-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-apache-bcel/1.7.0/org.apache.ant.ant-apache-bcel-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-apache-bcel/1.7.0/org.apache.ant.ant-apache-bcel-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-apache-bsf/1.7.0/org.apache.ant.ant-apache-bsf-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-apache-bsf/1.7.0/org.apache.ant.ant-apache-bsf-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-apache-log4j/1.7.0/org.apache.ant.ant-apache-log4j-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-apache-log4j/1.7.0/org.apache.ant.ant-apache-log4j-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-apache-oro/1.7.0/org.apache.ant.ant-apache-oro-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-apache-oro/1.7.0/org.apache.ant.ant-apache-oro-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-apache-regexp/1.7.0/org.apache.ant.ant-apache-regexp-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-apache-regexp/1.7.0/org.apache.ant.ant-apache-regexp-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-apache-resolver/1.7.0/org.apache.ant.ant-apache-resolver-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-apache-resolver/1.7.0/org.apache.ant.ant-apache-resolver-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-commons-logging/1.7.0/org.apache.ant.ant-commons-logging-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-commons-logging/1.7.0/org.apache.ant.ant-commons-logging-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-commons-net/1.7.0/org.apache.ant.ant-commons-net-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-commons-net/1.7.0/org.apache.ant.ant-commons-net-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-jai/1.7.0/org.apache.ant.ant-jai-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-jai/1.7.0/org.apache.ant.ant-jai-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-javamail/1.7.0/org.apache.ant.ant-javamail-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-javamail/1.7.0/org.apache.ant.ant-javamail-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-jdepend/1.7.0/org.apache.ant.ant-jdepend-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-jdepend/1.7.0/org.apache.ant.ant-jdepend-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-jmf/1.7.0/org.apache.ant.ant-jmf-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-jmf/1.7.0/org.apache.ant.ant-jmf-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-jsch/1.7.0/org.apache.ant.ant-jsch-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-jsch/1.7.0/org.apache.ant.ant-jsch-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-junit/1.7.0/org.apache.ant.ant-junit-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-junit/1.7.0/org.apache.ant.ant-junit-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-launcher/1.7.0/org.apache.ant.ant-launcher-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-launcher/1.7.0/org.apache.ant.ant-launcher-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-netrexx/1.7.0/org.apache.ant.ant-netrexx-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-netrexx/1.7.0/org.apache.ant.ant-netrexx-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-nodeps/1.7.0/org.apache.ant.ant-nodeps-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-nodeps/1.7.0/org.apache.ant.ant-nodeps-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-starteam/1.7.0/org.apache.ant.ant-starteam-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-starteam/1.7.0/org.apache.ant.ant-starteam-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-stylebook/1.7.0/org.apache.ant.ant-stylebook-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-stylebook/1.7.0/org.apache.ant.ant-stylebook-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-swing/1.7.0/org.apache.ant.ant-swing-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-swing/1.7.0/org.apache.ant.ant-swing-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-trax/1.7.0/org.apache.ant.ant-trax-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-trax/1.7.0/org.apache.ant.ant-trax-1.7.0.pom +[ParallelStep] Downloading: http://download.java.net/maven/2//com/avaloq/adt/org.apache.ant.ant-weblogic/1.7.0/org.apache.ant.ant-weblogic-1.7.0.pom +[ParallelStep] Downloading: http://repo1.maven.org/maven2/com/avaloq/adt/org.apache.ant.ant-weblogic/1.7.0/org.apache.ant.ant-weblogic-1.7.0.pom +[ParallelStep] [INFO] [compiler:compile] +[ParallelStep] [INFO] Compiling 981 source files to C:\Build\Results\jobs\ADT-Base\workspace\com.avaloq.adt.ui\target\classes +[ParallelStep] +[ParallelStep] [WARNING] C:\Build\Results\jobs\ADT-Base\workspace\com.avaloq.adt.ui\src\main\java\com\avaloq\adt\ui\elements\AvaloqDialog.java:[12,39] [deprecation] org.eclipse.jface.contentassist.SubjectControlContentAssistant in org.eclipse.jface.contentassist has been deprecated +[ParallelStep] +[ParallelStep] [WARNING] C:\Build\Results\jobs\ADT-Base\workspace\com.avaloq.adt.ui\src\main\java\com\avaloq\adt\ui\elements\AvaloqDialog.java:[40,36] [deprecation] org.eclipse.ui.contentassist.ContentAssistHandler in org.eclipse.ui.contentassist has been deprecated +[ParallelStep] +[ParallelStep] [FINDBUGS] Collecting findbugs analysis files... +[ParallelStep] [FINDBUGS] No annotations have been found. +[ParallelStep] [PMD] Collecting pmd analysis files... +[ParallelStep] [PMD] No annotations have been found. +[ParallelStep] [TASKS] Scanning workspace files for tasks... +[ParallelStep] [TASKS] A total of 555 annotations have been found. +[ParallelStep] [WARNINGS] Parsing warnings of log file... +[ParallelStep] [WARNINGS] A total of 105 annotations have been found. +[ParallelStep] finished: SUCCESS diff --git a/src/test/resources/hudson/plugins/warnings/parser/rflint.txt b/src/test/resources/hudson/plugins/warnings/parser/rflint.txt new file mode 100644 index 000000000..2e43f2b4d --- /dev/null +++ b/src/test/resources/hudson/plugins/warnings/parser/rflint.txt @@ -0,0 +1,10 @@ ++ ./Login_to_web.robot +W: 25, 100: Line is too long (exceeds 100 characters) (LineTooLong) +E: 40, 0: No keyword documentation (RequireKeywordDocumentation) ++ ./Merchant_Signup.robot +W: 24, 100: Line is too long (exceeds 100 characters) (LineTooLong) +E: 378, 0: No keyword documentation (RequireKeywordDocumentation) ++ ./merchant_common_keyword.txt +W: 73, 0: Too few steps (1) in keyword (TooFewKeywordSteps) +I: 123, 0: Ignore Error (Ignore Error) +K: 222, 0: Invalid Warning Type (Invalid Warning) diff --git a/warnings.iml b/warnings.iml index 59c4e9fff..6a64a9a83 100644 --- a/warnings.iml +++ b/warnings.iml @@ -1,6 +1,6 @@ - + @@ -9,26 +9,20 @@ - - - - - - - - - + - - - + + + + + @@ -36,8 +30,6 @@ - - @@ -208,7 +200,7 @@ - +