Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatic parser detection #148

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft

Conversation

pyieh
Copy link

@pyieh pyieh commented May 13, 2024

Change to the plugin behavior when no parser is provided in the tool field. Previous behavior was to error out. Now, the following scenarios can occur with their corresponding behavior:

Note Simplified error message is in the format: Attempted parser <PARSER> with pattern <PATTERN>, but was unsuccessful.

  1. No tool is defined (i.e. no parser or pattern) & at least 1 parser is successful:

    • ex call)recordCoverage(tools: [])
    • Try each possible parser with its corresponding default pattern
    • Print the successful parsers' logs and a simplified error message for each parser that failed.
      Snippet of example output [Successful Go coverage, rest fail]:
      image
  2. No tool is defined (i.e. no parser or pattern) & all parsers fail

    • ex call) recordCoverage(tools: [])
    • Try each possible parser with its corresponding default pattern
    • Print the logs of each parser tried.
      Snippet of example output [All fail]:
      image
  3. At least 1 pattern is defined, but none of them have a corresponding parser:

    • ex call) recordCoverage(tools: [[pattern: '*coverage.out'], [pattern: '*coverage.xml']])
    • Try each input pattern with each possible parser.
    • Follows same ruling as above:
      • 1+ successful -> print verbose logs of successful combination, simplified error message of other combinations
      • All fail -> print verbose logs of all
        Snippet of example output [2 patterns for Go & Python coverage successfully get auto detected]:
        image

Note Scenario 3 can occur even if another tool with a Parser is defined. Treats the expansion of that tool as 1 set.
ex call) recordCoverage(tools: [[parser: 'JACOCO'], [pattern: '*coverage.xml']])

Testing done

Tested on a local instance of Jenkins running the plugin version. Ran the aforementioned scenarios via pipeline jobs and recorded their builds' console output.
Also created unit tests that test the same thing.

Submitter checklist

@pyieh pyieh marked this pull request as draft May 13, 2024 23:28
throw exception;
}
}
if (localLog != null) {

Check warning

Code scanning / CodeQL

Useless null check Warning

This check is useless.
localLog
cannot be null at this check, since
new FilteredLog(...)
always is non-null.
@uhafner
Copy link
Member

uhafner commented May 14, 2024

Can you please elaborate why this is useful? Is specifying the parser too complicated in your setup?

@pyieh
Copy link
Author

pyieh commented May 14, 2024

Can you please elaborate why this is useful? Is specifying the parser too complicated in your setup?

Yeah, our usecase is that we have a number of pipelines (1000+) migrating over that currently just upload their coverage files to a server/service that determines the type of coverage file it is for them, so users aren't specifying anything about the coverage file type. We want to make the migration to using the recordCoverage() call in their pipelines as hands-off and minimal steps as possible, which involved moving the "What type of coverage is this?" determination functionality into the coverage-plugin.

@uhafner uhafner changed the title Default Parser Automatic parser detection May 16, 2024
@uhafner uhafner added the enhancement Enhancement of existing functionality label May 16, 2024
* Expands a list of given {@link CoverageTool}'s into the actual CoverageTool's set that {@link CoverageRecorder} uses when attempting to look for and parse coverage files.
* <p>
* The CoverageTool to its working set mapping use the following rules:
* - Empty or null tool set -&gt; set of all possible coverage parsers with null patterns (which will default to their default patterns)
Copy link
Member

Choose a reason for hiding this comment

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

Please check the coding style and the broken build

Suggested change
* - Empty or null tool set -&gt; set of all possible coverage parsers with null patterns (which will default to their default patterns)
* - Empty or null tool set: set of all possible coverage parsers with null patterns (which will default to their default patterns)

@@ -46,7 +46,7 @@ public class CoverageTool extends AbstractDescribableImpl<CoverageTool> implemen
private JenkinsFacade jenkins = new JenkinsFacade();

private String pattern = StringUtils.EMPTY;
private Parser parser = Parser.JACOCO;
private Parser parser;
Copy link
Member

Choose a reason for hiding this comment

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

null values are not allowed in my code base

@@ -471,52 +466,109 @@ private static void failStage(final ResultHandler resultHandler, final LogHandle
logHandler.log(log);
}

/**
* Iterates over the expansions of the {@code tools} items. For a given tool's expanded set it does the following logging behavior:
* - All fail -&gt; Logs all messages
Copy link
Member

Choose a reason for hiding this comment

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

Fix JavaDoc

parser.getDefaultPattern());
}
CoverageToolExpander covToolExpander = new CoverageToolExpander(this.tools, log, logHandler);
HashMap<CoverageTool, FilteredLog> parsersErrLogs = new HashMap<>();
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
HashMap<CoverageTool, FilteredLog> parsersErrLogs = new HashMap<>();
Map<CoverageTool, FilteredLog> parsersErrLogs = new HashMap<>();

localLog.logException(exception, "Exception while parsing with tool " + tool);
parsersErrLogs.put(tool, localLog);
}
catch (InterruptedException | RuntimeException exception) {
Copy link
Member

Choose a reason for hiding this comment

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

Never catch a RuntimeException

project.getPublishersList().add(new CoverageRecorder());

verifyNoParserError(project);
}
Copy link
Member

Choose a reason for hiding this comment

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

Did you check Freestyle jobs and the UI configuration if the jobs?

You might also need to adapt the help files

WorkflowJob job = createPipeline();
job.setDefinition(new CpsFlowDefinition(
"node {\n"
+ " recordCoverage tools: []\n"
Copy link
Member

Choose a reason for hiding this comment

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

Does it work with recordCoverage without tools as well? Then please add a test.


assertThat(getConsoleLog(run))
.contains("No tool defined, trying all possible parsers.")
.containsPattern("Successfully parsed file .*/jacoco.xml")
Copy link
Member

Choose a reason for hiding this comment

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

Does it say something about JaCoCo? Then please verify that text as well.

copyFilesToWorkspace(job, "cobertura-higher-coverage.xml");
job.setDefinition(new CpsFlowDefinition(
"node {\n"
+ " recordCoverage(tools: [[pattern: '*jacoco.xml'], [pattern: '*cobertura*.xml']])\n"
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure if it is really worth to the skip the parser names here.

While this approach works in general, I wonder what does the output look like when you merge the results of different parsers?

{
this.isExpanded = true;
for (Parser parser: Parser.values()) {
if (!(parser == Parser.JUNIT || parser == Parser.NUNIT || parser == Parser.XUNIT)) {
Copy link
Member

Choose a reason for hiding this comment

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

If you want to skip non-coverage files then use ParserType. And why do you want to skip these? Because your teams do not use them? This somehow is unexpected to users.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Enhancement of existing functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants