Scapegoat support #8
Comments
Hi, Did you know that scapegoat can generate an "scalastyle" report? Maybe it's possible to integrate the results of scapegoat with the scalastyle sensor, and probably that is easier than updating the old scapegoat sonar plugin that you are using. |
That's interesting and definitely worth looking into. I've never seen this setting before, but if that's really the case, then it would save us a lot of effort. My idea originally was to integrate the sonar-scala-extra plugin and set up two additional quality profiles - standalone Scapegoat and Scalastyle + Scapegoat for those who would like to use rules from both. I'm not sure if that would be possible though if we were to use scapegoat to generate a Scalastyle report. |
By now I'm thinking the best option is to address #35 first, and that will give us confidence about what to do with this. |
After looking at the SonarQube documentation and the source code of the scapegoat plugin and the scalastyle plugin. I realized that to create the new Rules Repository I propose two alternatives:
@mwz, What do you think?, do you had any other idea? Sensor Thanks for reading; I'll be waiting for your thoughts. |
Just a few thoughts on generating the rules while I have a minute and I'll probably have a think about the rest tomorrow. It might be worth to investigate writing an sbt task which downloads the scapegoat jar and using the I've never done this before but here is a reference - https://stackoverflow.com/a/3429366/3551902. I'd probably also look into the fast-classpath-scanner or a similar project which allows you to lookup subclasses at runtime e.g. Finding subclasses or superclasses - if this approach actually works and if you can just get a list of subclasses of the Inspection class, it might turn out that this could be the cleanest solution. |
Ok, I'll take a look a those links tomorrow. |
I've playing a while with scala-macros and with the FastClasspathScanner, and my conclusion is that the easiest way to go is to create a custom SBT Now, for managing the generated code, I see two options:
@mwz what do you think ? |
That's nice @BalmungSan - FastClasspathScanner stuff looks promising! Thanks for exploring some of the options. Having given this some thought, I'm totally pro automating the whole process, ideally, relying on the compilation as much as possible without having to run any manual sbt tasks and generating any source code which you then need to compile separately. I think that scalameta might be just what we're looking for given the rather poor state of macros in Scala (with the old-style macros being really disgusting and getting phased out and an unknown future of the new scala.macros). With scalameta we should be able to generate all the code that we need at compile-time without any sources. Unfortunately scalameta paradise and the inline macros are no longer under development, but I found them working well for me in the past and they're definitely way easier to work with and understand than the old macros. The paradise docs have been removed from the online scalameta documentation This sounds to me like the best way we can approach this, although if you have any other ideas I'm happy to discuss them. |
@mwz, well I was looking to macros to get the sub-classes of the inspection class, but I couldn't make a simple demo of that, so that’s why I ended proposing FastClasspathScanner. Regarding the code generation, I was thinking that we could simple write the files using standard Scala/Java IO APIs and using interpolated strings to fill up a template with the information we extract from scapegoat, and the compile that files together with the plugin sources. I think that is simple and useful enough, but of course it could go out of hand when we start to implement it. I have no experience with scala-meta either, but I had view it a few times. Correct me if I am wrong, but for using scala-meta, we would end with those templates in scala files that will modify their ASTs in compile time given the information extracted from scapegoat. The problem here is that those files had to be compiled first and in a sub-module and then the main module will be compiled using this sub-module as a dependency. So, I don’t know which approach will be more simple and more maintainable. PS: I hope I made clear what my thoughts are |
Just to clarify more what I had in mind, I'm thinking in something like this //this file is automatically generated, don't modify it.
package mwz.sonar.scala.scapegoat.inspections
/** Represent an scapegoat [[Inspection]] */
final case class ScapegoatInspection (id: Int, name: String, description: String, defaultLevel = Level)
/** All Scapegoat inspections available */
val AllScapegoatInspections = List(
ScapegoatInspection(id = 0, name = "ArrayEquals", description = "Checks for ...", defaultLevel = Level.Info),
...
) And thats all, we would then import this file in the source code, we only need to iterate over the I'm open to discuss this architectural decision. |
I see what you mean and perhaps that's the easiest and cleanest solution and as a plus, it avoids using macros - which is always good unless there is no other way and you absolutely have to use macros! :) So in that case, if you're thinking about generating the sources using an sbt task we should definitely check this file into git once generated initially and we should make sure that we run this manually as and when required when we upgrade scapegoat dependency, which doesn't seem to get updated too often, so I think we can get away with doing that - my scalameta proposel was probably a bit too heavyweight. We'll still probably want some sort of a blacklist of inspections so that we can skip those which are either not working or are simply not implemented yet like some of those that I mentioned earlier. Regarding the collection used for the repository itself, probably a Map indexed by the inspection name would be a better fit than a List as we'll need to do a lookup for each issue from the Scapegoat report, so it makes sense to me to use a Map in this case. |
Oh, yeah yeah, I just wanted to show a draft of the generated file, we should discuss with more detail what it should have. In any case I was thinking in a Map too, but by name, because we need to retrieve the index by name. But I was thinking in building that map in the source code by using the list of the generated file. Update: Oh, Sorry I misread your comment the first time, and understood that the map was by the id of the rule.
Maybe the blacklist idea would be useful, but we need to review it carefully, for example the two rules you mentioned earlier do not extend the Inspection class yet, so the scanner will omit them anyways. But I'm aware that we could need to blacklist some inspections in the future, so implementing the mechanism now would be nice.
Well, I was looking about how to generate the files, and I found this, as you can see there, it is pretty simple to add a task that will be executed before compile automatically, and thus we can leave the file outside the repo, to avoid any human error (like my dyslexia haha Conclusion: First I'll continue the PoC I showed you earlier, to add the sbt task that generates the files in the "src_managed" folder, and some code that uses the generated files. After that we should make a draft of the high level tasks to implement this, so instead of having another massive PR (that we saw is not the best idea), we will have many relative small PRs. Maybe we should create another branch for this development, and make the PRs to that branch, and only when the branch is production ready we merge it into master. What do you think ? |
Let's see if there is anything that we need to blacklist from the current version of Scapegoat, but if there isn't then we can probably reduce the scope for now and come back to this and implement it when we actually need it. +1 for generating the managed sources - that's probably a better way than I suggested because it automates the whole process.
Feel free to do this directly on a branch in this project as it might save you some time later when you want to port the code.
Yeah, that's definitely a good idea.
I'd be quite happy to integrate those small PRs into master as long as we keep the new sensor behind a feature flag so it's switched off in the future releases until we're ready to release it. |
I really like to do PoCs in empty projects when I'm learning something new (as this is the case), latter to integrate it here it will be just copy pasting with minor changes so not a big deal. Regarding the feature flag, I think it can be done here, then if we don't add the scapegoat plugin there until it is ready, everything should be work without any problem (I hope so). So, for now I'll be working in the PoC, I will ping you when it is ready. Additionally, I think we should start to discuss the high level design for this, like what will be the initial set of tasks (and maybe open them as issues?), what should the generated file contain, where should be define the map from name to id, etc. I don't know if you have any other concerns ? |
That's awesome, thanks!
Yeah, we can come up with a task list and I could add it to the description of this issue - that way we can keep track of the work. |
Ok, I have the following task list (ordered) in mind, please modify it as you consider:
Extras: I consider these tasks useful, but not priority to make a first release.
|
Hi @BalmungSan, I've slightly tweaked your list and added it to the description - please let me know if I missed anything. I think that it would be good to provide a default Scapegoat quality profile, otherwise, the rules won't appear in Sonar as active which might make the initial set-up a bit more difficult for some of the inexperienced Sonar users. Ideally, in addition to the default Scapegoat quality profile, we should also provide Scalastyle + Scapegoat and our recommended profile, but as you mentioned, those are probably not necessary for the first release and we can implement those afterwards. |
Hi @mwz, everything looks perfect to me. |
Yes, unit tests and manual e2e tests obviously go without saying :) |
Hello @mwz, I'm pleased to announce that the PoC was a completely *Success. Now, before proceeding to implement the generation task in this project, and making the respective PR, I would like to discuss some things related to the implementation.
|
That's great news @BalmungSan!
Both of those are library dependencies, so
I'd definitely extract your task definition to a separate file, preferebly containing
Yeah, that sounds good
I think the structure which you suggested previously works fine, although you might need to wrap the map in a companion object as vals are not allowed at the top-level. |
Oh yes, I forgot that little detail I'll make the PR in the next few hours. |
Hello @mwz, sorry for taking too long. But, I finally finished my little investigation for addressing the second task (Scapegoat Rules Repository). For adding the Scapegoat Rules Repository to the plugin we need to create a class that extends the RulesDefinition interface, and override the define method. In this method we will create all rules of the repository using the NewRule builder class.
Additionally, I have two more questions about the implementation of the repository in general.
If you have ideas for more or better test, I will be happy to hear them. The second one is about the activation of the repository, IMHO we should leave it deactivated in production for now (I don’t see any value in having rules that don’t do nothing for now displayed in the web interface). However, we would need to activate it for manual testing. To make the last one easier I propose to add the code that activates the repository, but have it commented in production. Nevertheless, I will just leave this decision up to you. Edit |
Hi @BalmungSan, thanks for doing the research and capturing the outcome along with all of your questions. I hope that you don't mind if I add quick comments here while they are fresh in my head before I address your latest PR?
We should come up with a naming convention for both new versions of scalastyle and scapegoat rules which doesn't collide with the existing names, so maybe something like this:
Not as far as I'm aware.
I would be tempted to activate all of the rules by default so it's easier to get started for users who set it up the first time.
Yes, let's start with that and if we discover that something should be labeled differently we can always tweak it later.
I guess the way to go about it would be to provide a guesstimate on how long it might take to fix a particular issue, but this isn't that important from my point of view and I wouldn't worry about it for now - we can come back to this in the future.
Another thing you can check is if there are no rules without a name, etc.
Yeah I agree - a feature flag would be a good way to go about this. I'd put this behind |
Sure, no problem
Yeah, absolutely! They provide a good scoping, and make it easier to search for an specific rule.
Oh ok, I thought you would prefer the opposite. But well, that was the idea of making questions instead of assumptions.
Yeah I totally agree that it should be done latter in a separate issue.
Ok, I will add a few more tests, latter when you review the PR you could give me more specific feedback about the tests.
Uhm... I see what you mean, and it is absolutely worth it. But what I can't see is how it will work without needing a recompilation of the plugin (which since an end-user perspective wouldn't be very convenient). Also it should enable/disable the entire scapegoat module (obviously it doesn't make any sense to activate the rules repository but deactivate the sensor for example). And if we add such functionality it should be available for each module of this plugin (ScalaSensor, ScoverageSensor, ScalastyleSensor & ScapegoatSensor). I'll make another push to the PR with you suggestions tomorrow in the morning |
Hello @mwz, Continuing with task 3 - Scapegoat Quality Profile. After a brief research I can conclude it is a pretty simple and straightforward task. We only need to create a class that extends the BuiltInQualityProfilesDefinition interface and override the Just a few questions:
That's all, I will be pushing a first draft of the PR in a few hours. |
Hello @mwz, now for almost finishing this, I'll proceed with a first draft of the Sensor. As already mentioned here, the basic functioning of Sensor is somewhat simple.
Do you have any other situation to considerate?
|
By the way, while implementing the Scapegoat Sensor, I found this. This may be simplest way to add a runtime feature flag to the modules of the plugin. |
Hi @BalmungSan,
Maybe we should log a warning only for those rules which don't exist in the profile? This would be a good indication that either the user needs to upgrade sonar-scala or we need to update to the latest version of Scapegoat.
I think that your SonarQube configuration should be driving the rule severity. If you configured your profile and changed the severity of some rules, you probably wouldn't want it to be overwritten by the default scapegoat severity.
Yes I agree - that's correct because your report might not contain a particular issue or might not even have any issues, so there is no reason to log anything in that case.
No, nothing else comes to my mind at this moment.
Sure, whatever works best for you
I think the easiest way to put the whole Scapegoat functionality behind a feature flag would be to call |
Hi @mwz, I think the main difference in our opinions is what we're considering the source of trust, for you its SonarQube and for me is the Scapegoat report. To be honest, I have mixed feelings about this. If the user wants to configure everything in sonar and just import a plain report, the best is to do what you're proposing. Regarding the feature flag, I think we should discuss it after finishing the sensor. |
You make a valid point and it's definitely worth having a think about how we want to handle this. I personally think there are more pros than cons of treating the Sonar rules as a source of truth for rule severity, but I'd be interested to hear your thoughts on this and why you think that using a report will work better for you. In my opinion overriding the severity of Sonar rules with what is in the report might work well for individual projects, but if you have multiple projects, having to do the same changes separately in each project will make it hard to maintain and ensure consistency across your projects - changing the severity in the UI will not have any effect in your analysis unless you make those changes in each project. I think that it's much more convenient to review the rules and enable/disable them and adjust the severity in SonarQube rather than having to do this in the build config. In fact, making the changes to Scalastyle rules is only possible via the UI, so if we were to do it in a different way for Scapegoat, that would be most likely confusing to users. It also appears that the old If you do insist on having it the other way round because it makes it convenient for you and your team, perhaps we could add this functionality as another config flag and make it an opt-in feature e.g. What do you think?
|
Well, the main reason I though about it was that from a "devops" perspective, you should have all your configurations in "code". Thus the UI is not best place for defining the parameters of the rules. But I agree that it is easier and, probably, better to configure those rules in sonar instead of in the build config. Especially, because, it is inconsistent with the current scapegoat plugins and with the scalastyle module. Finally, I think the idea of adding a config flag to determine this behavior is interesting, but to be realistic it probably will not add too much value now; maybe latter, if more users suggest it, we could implement it. |
Hi @mwz, If you need some help with something, have any problem or want to discuss something else before releasing don't hesitate in writing me here. |
That's great, thanks @BalmungSan for doing all of the work by yourself! |
Hey @mwz , I come up with (what I think is) a great idea for implementing the sonar-scala recommended Quality Profile. The first idea I had, was to write and xml file with all the profile's rules and their properties, and load it. <!-- Example of the structure of the file -->
<profile name="sonar-scala recommended way">
<scapegoat-rules>
<rule id="" severity="[INFO|MINOR|MAJOR|CRITICAL|BLOCKER]"/>
(...)
</scapegoat-rules>
<scalastyle-rules>
<rule id="" severity="[INFO|MINOR|MAJOR|CRITICAL|BLOCKER]" isTemplate="[true|false]">
<!-- only if isTemplate is true -->
<param key="" value=""/>
(...)
</rule>
(...)
</scalastyle-rules>
</profile> The big problem with it, is that if we modify the file and introduce and invalid value, it will only fail in runtime instead of in compile-time (of course a good set of test could catch a good amount of mistakes/bugs). What do you think about it?, or what other ideas do you have? |
Hi @BalmungSan, I've been looking into the "Scalastyle + Scapegoat" quality profile and I haven't given this too much thought yet, but I don't think we should use XML for configuring our recommended profile - as you said it's too error prone and adds unnecessary loading/parsing steps - we should aim to have the config managed in the code. There are two different approaches we could take for determining which rules should be activated in our profile - a whitelist or a blacklist. I would personally prefer blacklisting because I think there would be fewer rules to exclude than to include from the collection of all the rules from Scapegoat and Scalastyle repositories. The second aspect of it is overwriting rule severity - this could be as simple as a mapping from a rule key to the new severity for those rules which we want to have a different severity level. The last part is probably defining custom rules from the Scalastyle templates. I think we should create rules from all of the existing Scalastyle templates with default parameters and enable them all in the Scalastyle profile. If we want to make any changes to those rules in the sonar-scala profile, we should create new rules and activate them only in that profile. After having briefly looked at implementing the "Scalastyle + Scapegoat" profile, I think the Scalastyle config parser needs to be refactored to make it easier for us to reference the predefined rules without having to duplicate some of the parsing/processing logic in the new quality profile definitions, e.g. keys of the Scalastyle rules are generated at the time of creating the rules and are not exposed anywhere, so this is the key thing that needs to be improved. @BalmungSan, you made it very easy to activate all of the Scapegoat rules since we keep the list of inspections in memory and we convert them all into rules, however the old Scalastyle module doesn't make it easy and needs some |
I'll release it over the weekend @BalmungSan, since I already started looking into Scalastyle, it probably doesn't make sense for us both trying to work on the same thing unless you really want to pick it up? |
Oh, sorry, I read wrong and did not realize you were going to look into it. I would really like to refactor all the scalastyle module at once (probably in a couple of consequent PRs). If you want we can have a discussion about it in #35 |
Here is a task list with high-level items so we can keep track of implementation progress:
Here is an example of an existing Scapegoat plugin https://github.com/arthepsy/sonar-scala-extra.
The text was updated successfully, but these errors were encountered: