8000 [core] Add new Metrics Report Format by maxwai · Pull Request #5166 · pmd/pmd · GitHub
[go: up one dir, main page]

Skip to content

[core] Add new Metrics Report Format #5166

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

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

maxwai
Copy link
@maxwai maxwai commented Aug 12, 2024

Describe the PR

This adds a new xml report format, used to show metrics of the project. This new format will be used by the jenkins coverage-plugin.

Currently 4 Metrics are in the default ruleset:

  • Cognitive Complexity
  • Cyclomatic Complexity
  • NPath Complexity
  • NCSS

For now only these 4 are added as a proof of concept but more can be added in the future.
No new metric is added, every metrics was already calculated in another rule but is now explicitly exported as a metric.

To be able to distinguish between normal Violations and Metrics, a new Interface MetricRule was created. This Interface provides a way to pass the necessary information to the renderer by putting them in the violation description and then reading them back out. This is open to discussion if there is a better way to do this without rewriting a lot of the core architecture.

Also open to discussion is the location of the XSD file for the report. Strictly speaking it is not necessary but maybe it is wanted.

Ready?

  • Added unit tests for fixed bug/feature
  • Passing all unit tests
  • Complete build ./mvnw clean verify passes (checked automatically by github actions)
  • Added (in-code) documentation (if needed)
  • XSD file

@jsotuyod jsotuyod changed the title Add new Metrics Report Format [core] Add new Metrics Report Format Aug 12, 2024
@jsotuyod
Copy link
Member

Thanks for the contribution.

Unfortunately, I don't think this is the right approach to exposing raw metric values…

  1. The new renderer may filter out non-"Metric Rules", but the opposite is not true. All other renderers will have to either be aware and deal with this. This is very error-prone and creates tight coupling.
  2. We now effectively have 2 different sets of "rules" that don't really play along with each other. Users need to be aware of this difference, and create their rulesets from one or the other, but never mixing them to avoid inconsistencies.
  3. This change effectively breaks most of PMD's semantics. For instance, PMD will always produce a status code of 4 as long as there is a single class to be analyzed, unless --no-fail-on-violation is used… although we are reporting metrics, not violations.

Exposing raw metrics has never been a goal for PMD, so if we were to do this, we would have to think about a more organic approach…

@uhafner
Copy link
uhafner commented Aug 15, 2024

Do you have a concrete idea on how to implement this so that it better fits into the existing PMD structure?

From an architectural standpoint, I understand that it would be cleaner if we would report metrics by using PMD as a library that is invoked by some other tool. Our approach was a pragmatic idea on how to reuse all the existing "infrastructure" elements (maven, groovy plugins, etc.) without duplicating those elements in an additional tool.

@adangel
Copy link
Member
adangel commented Aug 30, 2024

That's probably the result of the discussion earlier this year in the chat:
https://matrix.to/#/!HVodkthUYTfpKAbNmk:gitter.im/$3Pcssl8-RKTz99NWiKHUyBOGOlkH3DvoDVg78ZaH-Tg?via=gitter.im&via=matrix.org&via=hm.edu

Quoting it here for reference:

mihaidogaru2537 (mihaidogaru2537) 2022-07-06
Hello! Does anyone know if the report output can be configured to display the metric value
somehow distinctly? I am trying to use the PMD API to create some statistics using the
metrics measured by PMD. When outputting in JSON format, for example I get this: "The class
Factory has a total cyclomatic complexity of 13 (highest 12)." I am interested in getting
that 13 number in a separate json key. Also, there are some rules which do not output their
metric's value: "Avoid really long classes.". I would like to know how long is that class.
Thank you!


adangel (Andreas Dangel) 2022-07-07
Hi @mihaidogaru2537 , that's not possible out of the box. Regarding metrics - we created for
unit testing those metrics simple rules, that that report the metric value in the violation
message and then we verify the message (which contains the number). See https://github.com/
pmd/pmd/blob/master/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/impl/AllMetricsTest.java for an example.
Regarding some rules you mentioned - you'd need to change the rule, so that they output
whatever value they measured.
While calculating and reporting metrics is an interesting feature, it is not currently part of PMD.


Ulli Hafner 2022-07-08
One of my students implemented a small tool around those metric classes and integrated it
into a Jenkins plugin: https://github.com/jenkinsci/metrics-aggregation-plugin


Ulli Hafner 2024-02-23
We want to use PMD to gather different metrics of a software project. We successfully
integrated PMD into a Jenkins plugin (https://plugins.jenkins.io/metrics-aggregation/), but
this architecture approach is quite limited, as the configuration then needs to be done in
Jenkins and not in the build tool. Additionally, this approach cannot be used in native
GitHub oder GitLab pipelines. So I am wondering, if it would make sense to integrate the
reporting of metrics into the PMD build tools (e.g., maven-pmd-plugin) or if this should be
provided as a standalone tool or plugin? I am currently seeing the following approaches:

  1. Extend the existing maven-pmd-plugin and add a new goal pmd:metrics in the same way as
    pmd:pmd or pmd:cpd works. This goal would write the results to a new XML report format. In
    this case there is no need to specify source paths, etc., multiple times, we simply can reuse
    the existing PMD maven POM configuration.
  2. Fork the existing maven-pmd-plugin and replace the pmd:pmd goal with something similar
    that produces the metrics and deploy it as a new maven plugin. Here we would write the
    results to a new XML report format as well.
  3. Create a new standalone Java application that uses PMD to write such a report. This new
    application can be Docker based. Here we need to duplicate all the configuration options that
    are part of the maven plugin.

What do you think? Would there be interest in integrating option 1?


Andreas Dangel (adangel) 2024-02-25
Hi Ulli Hafner ,
I'm not sure whether extending maven-pmd-plugin is the way to go here. Ideally m-pmd-p would
only call PMD and wouldn't add functionality.
I'd prefer to add such functionality directly in PMD - then it could be used without m-pmd-p,
e.g. with ant/gradle or even cli.

As far as I see, the solution consists of a rule, that reports metric values as rule
violations with a custom report format/reporter.

I could imagine, that we add both components into main PMD codebase, e.g. each language
having such a special metrics producing "rule" and also provide a report format/renderer
specially for metrics, creating the report in XML or JSON.
Users should then be able to configure m-pmd-p in their projects using that rule and that
report format/renderer, creating a XML (or JSON) file. The Jenkins plugin can then read the
file, if it is present. And create the views for Jenkins.

Adding this functionality as a "rule" is currently the simplest approach. Longer term, there
should be better support in PMD, e.g. for other things than rules like statistics gatherers
or so. So that we don't need to use the workaround with producing RuleViolations to report
metric values. But such an abstraction doesn't exist yet. Please also note, that PMD is still
limited to single file analysis. Especially for metrics calculating statics over multiple
files would be interesting. This could actually be done in the renderer.

Feel free to create an issue in https://github.com/pmd/pmd/issues to track this idea.

@uhafner
Copy link
uhafner commented Sep 13, 2024

Thanks for resurrecting this old thread! I think the non-invasive implementation of @maxwai is (in a way) such an abstraction that you mentioned. We have a new interface that marks all rules that can produce metrics. These rules are also visible as violation rules, is this the problem you are seeing? Should the new metrics rules form a new hierarchy that stands side by side with the existing one?

@adangel
Copy link
Member
adangel commented Sep 17, 2024

I'm guessing now, but I see these potential issues: With this solution, you would call PMD on CLI e.g. with pmd check -d src -R category/java/metric.xml -f metrics-xml. That will work (except for the exit status, which will always be 4). But you could also use pmd check -d src -R category/java/quickstart.xml -f metrics-xml - and that won't work - it won't calculate the metrics.

The problem is, that we don't find violations now, we calculate metrics. That's why maybe a different command for the CLI interface is better, so that you can't mess up: pmd metrics -d src - which implicitly selects the metrics ruleset and the metrics format.
We also need to make sure, that the metrics ruleset is not in a common location, where users would search for - it is not intended to be used for finding violations. It might be better located in src/main/resources/rulesets/internal/java-metrics.xml. And the renderer should not be registered in RendererFactory, so that it cannot be accidentally used.

These changes would hide the implementation of this metrics solution and the only supported entry point from CLI would be via pmd metrics .... Then we can postpone the problem, that these metrics rules report violations currently and not metrics - as there is no direct support for reporting metrics. We misuse the rule processing to do this. It opens up the opportunity to directly call MetricsUtil.computeMetric instead of going through a rule, collecting RuleViolations, parsing the violation messages and such. We could directly collect the computed metrics.
It also opens up the possibility, to select the metrics you want, e.g. pmd metrics ATFD,Cyclo,NCSS -d src - without the need to create a custom ruleset.

Introducing pmd metrics ... will raise another problem. IIRC, you (or the users of your Jenkins plugin) call PMD via maven-pmd-plugin, in order to produce the metrics.xml report file, that the Jenkins plugin will then display. To make it properly, you would need to add this new "metrics" command also to the maven-pmd-plugin (e.g. a own goal "pmd:metrics" instead of "pmd:pmd"). As long as the implementation stays with the metrics-rule-violation-message roundtrip, then you won't need this additional goal at the beginning for maven-pmd-plugin, as you can configure the ruleset and you can configure a fully qualified classname for the format/renderer.

@uhafner
Copy link
uhafner commented Sep 18, 2024

I see, the current approach has several drawbacks. But touching the maven plugin is something I wanted to avoid. When we need to change it as well then we need to touch the Gradle plugin, etc. Maybe then it would be cleaner to write a new and simple maven plugin, that generates metrics by using PMD?

I've seen that you are located in Munich as well: Would it make sense to set up a meeting somewhere in the city (or in the university of applied sciences) to discuss the topic?

@adangel adangel changed the base branch from master to main September 26, 2024 14:31
@adangel
Copy link
Member
adangel commented Oct 12, 2024

I see, the current approach has several drawbacks. But touching the maven plugin is something I wanted to avoid. When we need to change it as well then we need to touch the Gradle plugin, etc. Maybe then it would be cleaner to write a new and simple maven plugin, that generates metrics by using PMD?

I think, the easiest way for you currently would be, to create a library, that contains the rules, that produce the metrics and the special metrics formatter. This can be added as an additional dependency to the maven-pmd-plugin/gradle, just like ordinary custom rules (see https://maven.apache.org/plugins/maven-pmd-plugin/examples/multi-module-config.html for the example with a "build-tools" module/library).

Using all this doesn't work out of the box anyway - if I understand this correctly: When a project wants to use Jenkins and use your Jenkins Plugin to display metrics reports/graphs, then the project needs to first add maven-pmd-plugin (or gradle pmd plugin), configure it to run the special metrics ruleset and use the special metrics formatter. If the project already uses PMD, then it needs to configure an additional/separate PMD execution.
The Jenkins plugin would then simply pick-up the metrics report, if it is available.

Ok, I've read now on https://github.com/jenkinsci/metrics-aggregation-plugin that this Jenkins plugin provides a post-build-step, that actually seems to call PMD... which is for Java a bit tricky, as it must calculate the correct project classpath for analysis (the auxiliary classpath) which you get for free from the build tools.

I've seen that you are located in Munich as well: Would it make sense to set up a meeting somewhere in the city (or in the university of applied sciences) to discuss the topic?

Maybe that could help. We could outline a bit more concretely what would need to be done for a long term solution ("proper solution" - that involves changing PMD, maven-pmd-plugin and potentially other parts) and what could be done for a short-term solution.

Update: related PR: jenkinsci/coverage-plugin#213

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

Successfully merging this pull request may close these issues.

4 participants
0