Closed aishfenton closed 11 months ago
@aishfenton have you tried one of the following?
As a source set:
dependencies {
scalafix sourceSets.scalafix.output
}
As a separate sub-project:
dependencies {
scalafix project(':scalafix')
}
I'm not sure these work, but I'd assume so.
None of the options suggested above work at the moment. We are looking into ways to support them.
Any update on this @marcelocenerine ?
Would love to be able to use local rules.
Unfortunately, there's been no progress made on this issue, @Habitats. The project has been in the ice box since my last comment due to a lack of available time to work on it. I do intend to address the outstanding issues in this project, but cannot promise when.
understood!
any guidances you could give on how to approach implementing this myself?
Yes, of course. Please allow me a couple of days to remember what the problem is and what needs to be done so I can give you some pointers. Thank you for offering help!
@Habitats I set up a test project that you can use to play around and test your changes: https://github.com/marcelocenerine/test-gradle-scalafix
It has the following structure:
test-gradle-scalafix
├── .scalafix.conf
├── build.gradle
├── gradle.properties
├── scala-module
│ ├── build.gradle
│ └── src
│ ├── customScalafixRule
│ │ ├── resources
│ │ │ └── META-INF
│ │ │ └── services
│ │ │ └── scalafix.v1.Rule
│ │ └── scala
│ │ └── scalafixrules
│ │ └── SourceSetDummyRule.scala
│ └── main
│ └── scala
│ └── foo
│ └── Foo.scala
├── scalafix-dummy-rule
│ ├── build.gradle
│ └── src
│ └── main
│ ├── resources
│ │ └── META-INF
│ │ └── services
│ │ └── scalafix.v1.Rule
│ └── scala
│ └── scalafixrules
│ └── SubprojectDummyRule.scala
└── settings.gradle
gradle-scalafix
plugin to support:
SubprojectDummyRule
: in the scalafix-dummy-rule
subprojectSourceSetDummyRule
: in the customScalafixRule
source set inside the scala-module
subproject.scalafix.conf
file (root directory). You can comment/uncomment lines to play around with different setups (I left comments there to make it easier for you)scala-module/build.gradle
you will find more instructions. Again, you can comment/uncomment lines to try out different setups:
buildscript > dependencies
is where you will update the version of the gradle-scalafix
plugin to test your changesdependencies
you will find various ways to import custom rules.scalafix-dummy-rule
subproject as a jar (after it was installed to .m2 -> cheating!)gradle.properties
I turned off the Gradle daemon. This is to ensure that Gradle will start fresh in every execution. This is important because the plugin caches classloaders and you wouldn't see new changes being picked up between executionsBefore you test anything, I would recommend you change this log message from debug
to warn
so that you can see the inputs that the plugin is passing to Scalafix without having to search for it in the middle of all the debug noise.
When you define the rule dependency like this:
scalafix project(':scalafix-dummy-rule')
...and run ./gradlew checkScalafix
, you will see that the plugin creates a classloader (here) with the following path:
Running Scalafix with the following arguments:
- ...
- External rules classpath: /Users/marcelo/dev/projects/test-gradle-scalafix/scalafix-dummy-rule/build/libs/scalafix-dummy-rule-1.0-SNAPSHOT.jar
However, if you ls
that path, you will notice that the jar doesn't exist:
$ ll /Users/marcelo/dev/projects/test-gradle-scalafix/scalafix-dummy-rule/build/libs/scalafix-dummy-rule-1.0-SNAPSHOT.jar
ls: /Users/marcelo/dev/projects/test-gradle-scalafix/scalafix-dummy-rule/build/libs/scalafix-dummy-rule-1.0-SNAPSHOT.jar: No such file or directory
So the issue here is that there is a dependency between the ScalafixTask
task and the Jar
task of the subproject where the local rule is defined, but the two are not explicitly defined. While setting up the test project I realised that there is a workaround for that:
tasks.withType(io.github.cosmicsilence.scalafix.ScalafixTask) {
dependsOn project(':scalafix-dummy-rule').tasks.withType(Jar)
}
For the time being, we could document this workaround. But it would be nice if the plugin could figure this out and automatically create the dependency between the two tasks (not sure if there's a better alternative to that). It already does a similar thing in a few places (example). However, in this case it needs to determine whether the dependency is on a project.
When you define the rule dependency like this:
scalafix sourceSets.customScalafixRule.output
...and run ./gradlew checkScalafix
, you will see that the plugin creates a classloader (here) with the following paths:
Running Scalafix with the following arguments:
- ...
- External rules classpath: /Users/marcelo/dev/projects/test-gradle-scalafix/scala-module/build/classes/java/customScalafixRule:
/Users/marcelo/dev/projects/test-gradle-scalafix/scala-module/build/classes/scala/customScalafixRule:
/Users/marcelo/dev/projects/test-gradle-scalafix/scala-module/build/resources/customScalafixRule
This looks ok, but I think there is a catch: the javadoc for URLClassLoader
says the following:
This class loader is used to load classes and resources from a search path of URLs referring to both JAR files and directories. Any URL that ends with a '/' is assumed to refer to a directory. Otherwise, the URL is assumed to refer to a JAR file which will be opened as needed.
I suspect the part I highlighted in bold has the answer ;)
If you are interested in contributing a fix, please give it a go and let me know if you have further questions.
I suspect the part I highlighted in bold has the answer ;)
Actually, it seems unrelated. Both issues are likely related to undefined dependencies between tasks
It is possible to use rules defined locally (within the same repo), such as https://scalacenter.github.io/scalafix/docs/developers/local-rules.html