diff --git a/.github/workflows/assign-pr.yml b/.github/workflows/assign-pr.yml index 4da9319e5..17426665c 100644 --- a/.github/workflows/assign-pr.yml +++ b/.github/workflows/assign-pr.yml @@ -7,6 +7,6 @@ jobs: name: 'Auto Assign PR' runs-on: ubuntu-latest steps: - - uses: kentaro-m/auto-assign-action@v1.2.5 + - uses: kentaro-m/auto-assign-action@v1.2.6 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/README.md b/README.md index 1e8d9fc58..63fb97ad1 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,18 @@ [![CodeQL](https://github.com/jenkinsci/analysis-model/workflows/CodeQL/badge.svg)](https://github.com/jenkinsci/analysis-model/actions/workflows/codeql.yml) [![Line Coverage](https://raw.githubusercontent.com/jenkinsci/analysis-model/main/badges/line-coverage.svg)](https://app.codecov.io/gh/jenkinsci/analysis-model) [![Branch Coverage](https://raw.githubusercontent.com/jenkinsci/analysis-model/main/badges/branch-coverage.svg)](https://app.codecov.io/gh/jenkinsci/analysis-model) -[![Warnings](https://raw.githubusercontent.com/jenkinsci/analysis-model/main/badges/style.svg)](https://github.com/jenkinsci/analysis-model/actions/workflows/quality-monitor.yml) -[![Bugs](https://raw.githubusercontent.com/jenkinsci/analysis-model/main/badges/bugs.svg)](https://github.com/jenkinsci/analysis-model/actions/workflows/quality-monitor.yml) - -This library provides a Java object model to read, aggregate, filter, and query static analysis reports. -It is used by [Jenkins' warnings plug-in](https://github.com/jenkinsci/warnings-ng-plugin) to visualize -the warnings of individual builds. Additionally, this library is used by a -[GitHub action](https://github.com/uhafner/autograding-github-action) and [GitLab action](https://github.com/uhafner/autograding-gitlab-action) to autograde student software projects based -on a given set of metrics (unit tests, code and mutation coverage, static analysis warnings). + +This library provides a Java API to read, aggregate, filter, and query static analysis reports. +It is used by my [Jenkins' warnings plug-in](https://github.com/jenkinsci/warnings-ng-plugin) to visualize +the warnings of individual builds. + +![Jenkins Warnings Plug-in](doc/jenkins.png) + +Additionally, this library is used by my additional [Quality Monitor GitHub Action](https://github.com/uhafner/quality-monitor), that monitors the quality of projects based on a configurable set of metrics and gives feedback on pull requests (or single commits) in GitHub. +There are also two additional actions available, to autograde student software projects based +on these metrics: [GitHub Autograding action](https://github.com/uhafner/autograding-github-action) and [GitLab Autograding action](https://github.com/uhafner/autograding-gitlab-action). + +![Quality Monitor GitHub Action](doc/quality-monitor.png) This library consists basically of three separate parts: diff --git a/SUPPORTED-FORMATS.md b/SUPPORTED-FORMATS.md index 474d3151a..36ad33db6 100644 --- a/SUPPORTED-FORMATS.md +++ b/SUPPORTED-FORMATS.md @@ -1,4 +1,4 @@ - + # Supported Report Formats The static analysis model supports the following report formats. diff --git a/doc/dependency-graph.puml b/doc/dependency-graph.puml index f60ed35b3..9059146be 100644 --- a/doc/dependency-graph.puml +++ b/doc/dependency-graph.puml @@ -6,8 +6,8 @@ skinparam rectangle { BackgroundColor<> lightBlue BackgroundColor<> lightGray } -rectangle "analysis-model\n\n11.14.0-SNAPSHOT" as edu_hm_hafner_analysis_model_jar -rectangle "jsoup\n\n1.17.1" as org_jsoup_jsoup_jar +rectangle "analysis-model\n\n11.15.0-SNAPSHOT" as edu_hm_hafner_analysis_model_jar +rectangle "jsoup\n\n1.17.2" as org_jsoup_jsoup_jar rectangle "commons-io\n\n2.11.0" as commons_io_commons_io_jar rectangle "commons-digester3\n\n3.2" as org_apache_commons_commons_digester3_jar rectangle "cglib\n\n2.2.2" as cglib_cglib_jar @@ -36,7 +36,7 @@ rectangle "pmd-java\n\n6.55.0" as net_sourceforge_pmd_pmd_java_jar rectangle "json\n\n20231013" as org_json_json_jar rectangle "json-smart\n\n2.5.0" as net_minidev_json_smart_jar rectangle "accessors-smart\n\n2.5.0" as net_minidev_accessors_smart_jar -rectangle "slf4j-api\n\n2.0.9" as org_slf4j_slf4j_api_jar +rectangle "slf4j-api\n\n2.0.11" as org_slf4j_slf4j_api_jar rectangle "spotbugs-annotations\n\n4.8.2" as com_github_spotbugs_spotbugs_annotations_jar rectangle "error_prone_annotations\n\n2.23.0" as com_google_errorprone_error_prone_annotations_jar rectangle "streamex\n\n0.8.2" as one_util_streamex_jar diff --git a/doc/jenkins.png b/doc/jenkins.png new file mode 100644 index 000000000..a0f09ba3d Binary files /dev/null and b/doc/jenkins.png differ diff --git a/doc/quality-monitor.png b/doc/quality-monitor.png new file mode 100644 index 000000000..3df65359f Binary files /dev/null and b/doc/quality-monitor.png differ diff --git a/pom.xml b/pom.xml index 691b5322e..e733d0489 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ 1.9.4 1.11.0 1.4.0 - 2.0.10 + 2.0.11 1.156.7 1.17.2 20231013 diff --git a/src/main/java/edu/hm/hafner/analysis/parser/EmbeddedEngineerParser.java b/src/main/java/edu/hm/hafner/analysis/parser/EmbeddedEngineerParser.java index fedd4ced8..8ebae1a91 100644 --- a/src/main/java/edu/hm/hafner/analysis/parser/EmbeddedEngineerParser.java +++ b/src/main/java/edu/hm/hafner/analysis/parser/EmbeddedEngineerParser.java @@ -1,20 +1,13 @@ package edu.hm.hafner.analysis.parser; import java.io.UncheckedIOException; -import java.util.Iterator; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; - +import edu.hm.hafner.analysis.*; +import edu.hm.hafner.util.LookaheadStream; import org.apache.commons.lang3.StringUtils; -import edu.hm.hafner.analysis.IssueBuilder; -import edu.hm.hafner.analysis.IssueParser; -import edu.hm.hafner.analysis.ParsingException; -import edu.hm.hafner.analysis.ReaderFactory; -import edu.hm.hafner.analysis.Report; -import edu.hm.hafner.analysis.Severity; - /** * A parser for the EmbeddedEngineer EA Code Generator tool log files. * @@ -22,46 +15,58 @@ */ public class EmbeddedEngineerParser extends IssueParser { private static final long serialVersionUID = -1251248150731418714L; + + private static final String LOG_BEGINNING_PATTERN = "^\\[.*?\\].*"; private static final Pattern HEADER_PATTERN = Pattern.compile( "^([^\\(Start)]*)(Starting code generation for)\\s(?.*\\})"); private static final Pattern SPECIAL_WARNING_PATTERN = Pattern.compile( "^\\[([^\\]]*)\\]\\s(?Warn)\\s-\\s(?[^']*)'(?[^']*)" + "'\\s(?
\\(?[^{]*)(?[^)]*\\})"); + private static final Pattern WARNING_PATTERN = Pattern.compile( - "^\\[([^\\]]*)\\]\\s(?Error|Warn)\\s-\\s(?.+):\\s(?.+)"); + "^\\[([^\\]]*)\\]\\s(?Error|Warn)\\s-\\s(?[^:]*)" + "(:\\s|\\s\\()(?.+)"); @Override public Report parse(final ReaderFactory reader) throws ParsingException { try (Stream lines = reader.readStream()) { - return parse(lines); + try (LookaheadStream lookahead = new LookaheadStream(lines, reader.getFileName())) { + return parse(lookahead); + } } catch (UncheckedIOException e) { throw new ParsingException(e); } } - private Report parse(final Stream lines) { + private String readMultipleLines(final LookaheadStream lookahead) { + StringBuilder multipleLines = new StringBuilder(lookahead.next()); + while (lookahead.hasNext() && !lookahead.hasNext(LOG_BEGINNING_PATTERN)) { + multipleLines.append(" ").append(lookahead.next()); + } + return multipleLines.toString(); + } + + private Report parse(final LookaheadStream lookahead) { try (IssueBuilder builder = new IssueBuilder()) { - Iterator lineIterator = lines.iterator(); - String file = parseFileName(lineIterator); + String file = parseFileName(lookahead); Report report = new Report(); - - while (lineIterator.hasNext()) { - String line = lineIterator.next(); - Matcher matcher = SPECIAL_WARNING_PATTERN.matcher(line); - Matcher warningMatcher = WARNING_PATTERN.matcher(line); + while (lookahead.hasNext() && lookahead.hasNext(LOG_BEGINNING_PATTERN)) { + String lines = this.readMultipleLines(lookahead); + Matcher matcher = SPECIAL_WARNING_PATTERN.matcher(lines); + Matcher warningMatcher = WARNING_PATTERN.matcher(lines); if (matcher.matches() || warningMatcher.matches()) { String group; String description; if (matcher.matches()) { group = matcher.group("severity"); + description = String.format("%s'%s' %s%s", matcher.group("description"), matcher.group("module"), matcher.group("details"), matcher.group("serial")); - builder.setCategory(setCategory(line)); + builder.setCategory(setCategory(lines)); builder.setModuleName(matcher.group("module")); } else { @@ -71,7 +76,7 @@ private Report parse(final Stream lines) { warningMatcher.group("category"), warningMatcher.group("description")); } - Severity priority = mapPriority(line, group); + Severity priority = mapPriority(lines, group); builder.setDescription(description); builder.setFileName(file); builder.setSeverity(priority); @@ -82,7 +87,7 @@ private Report parse(final Stream lines) { } } - private String parseFileName(final Iterator lineIterator) { + private String parseFileName(final LookaheadStream lineIterator) { while (lineIterator.hasNext()) { String line = lineIterator.next(); Matcher matcher = HEADER_PATTERN.matcher(line); @@ -121,4 +126,4 @@ else if (group.contains("Error")) { } return Severity.WARNING_NORMAL; } -} +} \ No newline at end of file diff --git a/src/test/java/edu/hm/hafner/analysis/parser/EmbeddedEngineerParserTest.java b/src/test/java/edu/hm/hafner/analysis/parser/EmbeddedEngineerParserTest.java index 7cc8df9da..72374ee82 100644 --- a/src/test/java/edu/hm/hafner/analysis/parser/EmbeddedEngineerParserTest.java +++ b/src/test/java/edu/hm/hafner/analysis/parser/EmbeddedEngineerParserTest.java @@ -22,7 +22,7 @@ protected EmbeddedEngineerParser createParser() { @Override protected void assertThatIssuesArePresent(final Report report, final SoftAssertions softly) { - softly.assertThat(report).hasSize(8); + softly.assertThat(report).hasSize(10); softly.assertThat(report.get(0)) .hasModuleName("index_module") .hasDescription("Complex type definition without referenced element found 'index_module' (uint8_t); {98CF1FE6-EC9C-43f1-e476-40EFCD63cA8D}") @@ -45,6 +45,34 @@ protected void assertThatIssuesArePresent(final Report report, final SoftAsserti .hasCategory("Error loading plugins from") .hasDescription("Error loading plugins from C:\\file1\\idc\\sample_ext.x64.dll") .hasSeverity(Severity.ERROR); + softly.assertThat(report.get(8)) + .hasCategory("Out parameters") + .hasDescription("Out parameters 'Model_ptr_2345') are not supported. Please use 'return' or 'inout' parameters; {98CF1FE6-EC9C-43f1-e476-40EFCD63cA8D}") + .hasSeverity(Severity.WARNING_NORMAL); + softly.assertThat(report.get(9)) + .hasCategory("Error loading plugins from") + .hasDescription("Error loading plugins from C:\\file1\\idc\\sample_ext.x64.dll File name: " + + "'file:///C:\\AA\\BB\\System.Text.Json.dll' ---> System.NotSupportedException: " + + "An attempt was made to load an assembly from a network location which would have caused the " + + "assembly to be sandboxed in previous versions of the .NET Framework. " + + "This release of the .NET Framework does not enable CAS policy by default, " + + "so this load may be dangerous. If this load is not intended to sandbox the assembly," + + " please enable the loadFromRemoteSources switch. " + + "See http://go.microsoft.com/fwlink/?LinkId=155569 for more information. " + + " at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase," + + " Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, " + + "IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, " + + "Boolean suppressSecurityChecks) at System.Reflection.RuntimeAssembly." + + "InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, " + + "RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, " + + "Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) " + + "at System.Reflection.RuntimeAssembly.InternalLoadFrom(String assemblyFile, " + + "Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, " + + "Boolean forIntrospection, Boolean suppressSecurityChecks, StackCrawlMark& stackMark) " + + " at System.Reflection.Assembly.LoadFrom(String assemblyFile) " + + "at A.A`1.a(String , Predicate`1 , Object[] ) " + + "at A.A`1.A(String , Predicate`1 , Object[] )") + .hasSeverity(Severity.ERROR); } } diff --git a/src/test/resources/edu/hm/hafner/analysis/parser/ea.log b/src/test/resources/edu/hm/hafner/analysis/parser/ea.log index a6d27c0dc..f159b3594 100644 --- a/src/test/resources/edu/hm/hafner/analysis/parser/ea.log +++ b/src/test/resources/edu/hm/hafner/analysis/parser/ea.log @@ -7,4 +7,13 @@ [2023-03-10 12:04:25.0777] Warn - Code generation for element 'Module1' failed. Could not start code generation ; {ffeee99-9BD1-12345678} [2023-03-10 12:04:25.0777] Warn - Code generation for element 'Module1' passed. Could not start code generation ; {ffeee99-9BD1-12345678} [2023-03-10 12:04:25.1377] Warn - SampleValidation: no requirement linked to final node 'Module1_Node'. -[2023-03-10 12:04:22.1045] Error - Error loading plugins from: C:\file1\idc\sample_ext.x64.dll \ No newline at end of file +[2023-03-10 12:04:22.1045] Error - Error loading plugins from: C:\file1\idc\sample_ext.x64.dll +[2024-01-05 10:52:27.3199] Warn - Out parameters ('Model_ptr_2345') are not supported. Please use 'return' or 'inout' parameters; {98CF1FE6-EC9C-43f1-e476-40EFCD63cA8D} +[2023-04-10 12:04:22.1045] Error - Error loading plugins from: C:\file1\idc\sample_ext.x64.dll +File name: 'file:///C:\AA\BB\System.Text.Json.dll' ---> System.NotSupportedException: An attempt was made to load an assembly from a network location which would have caused the assembly to be sandboxed in previous versions of the .NET Framework. This release of the .NET Framework does not enable CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly, please enable the loadFromRemoteSources switch. See http://go.microsoft.com/fwlink/?LinkId=155569 for more information. + at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) + at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) + at System.Reflection.RuntimeAssembly.InternalLoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, Boolean forIntrospection, Boolean suppressSecurityChecks, StackCrawlMark& stackMark) + at System.Reflection.Assembly.LoadFrom(String assemblyFile) + at A.A`1.a(String , Predicate`1 , Object[] ) + at A.A`1.A(String , Predicate`1 , Object[] )