Hi Tor,
this issue is becoming more and more important. And I believe not only for us.
For our CI builds we are running lint on variety of modules that didn't change at all accross builds, branches, flavors, etc and it's useless. Or CI builds take too much time and lint is a very big contributor to them.
Add inputs, outputs, making the lint task cacheable would really be ideal for us. I believe it should not take a lot of time to make the change.
Hi Tor,Our lint more than quadrupled in duration when we upgraded to 3.0.
I remember seeing an issue during the alphas about lint processing the same module multiple times due to how the dependency graph was setup - is that still a thing? Ie. the following dependency setup would cause A to be checked multiple times (-> = depends on)
AB->AC->AD->BD->AD->CE->D
Also, based on the current version of lint, are there any performance best practices?
:FitbitAndroid:lintWorldNormalProdDebug > Resolve files of :FitbitAndroid:worldFastQa2DebugAndroidTestRuntimeClasspath
Hi Tor,By turning off checkDependencies, don't we cripple the UnusedResources check? As an aside: which direction does checkDependencies look (in the case of UnusedResources)? If I'm interested in seeing if there are resources in my library modules that are not being used in my app, should I run the UnusedResources check on the app, or the library modules?
Something else I noticed: when I run lint on a specific variant, I noticed that the task is still resolving the files that it needs for all variants. This can take a significant amount of time for us, as we have a fairly large flavor matrix.Example::FitbitAndroid:lintWorldNormalProdDebug > Resolve files of :FitbitAndroid:worldFastQa2DebugAndroidTestRuntimeClasspath
We our flavor matrix is [2x, 8x, 4x]; and then we have 5 build-types (not counting androidTest) - which results in stupidly large number of variants... I'm working on shrinking that, but in the meantime it doesn't seem quite right that linting a specific variant would need to fully resolve the files of all the others. Thoughts?
Thanks for the detailed explanation, Tor!Regarding resources that are used only in tests, I'm wondering whether that's a use case that justifies the default extra cost in lint - especially since it may be so large and many users may not realize they can use the flag safely to save the cost. Also, I'm not sure Lint should not flag these resources by default:
- If it's an androidTest test, the resources can be moved to androidTest/res.
- If a unit test using Robolectric, there are probably better options than packaging the resources in a production module: either updating AGP to parse resources under test/res, or just ignoring them explicitly (in order to acknowledge that they are only meant for use in tests).
Would it make sense to ignore test sources by default, and instead add a "includeTestSources" flag for those folks that explicitly want to be able to bundle test resources in their app?
Trying to improve my last suggestion, and after spending a couple of hours trying to understand both:
https://android.googlesource.com/platform/tools/build/+/master/gradle/src/main/groovy/com/android/build/gradle/tasks/Lint.groovy
The important thing to `LintCliClient` is the `LintRequest` that you are extending on the Gradle plugin, I didn't get to list all the details of the request used for Lint to analyze, but I think the Input for the (new) task `lintAnalyze` should be exactly the `LintGradleRequest`, but it's not that simple.Gradle Task inputs need to be one of:
- `Serialzable`- `File *` ( folder or file )
- `Iterable<File>*` ( files, classpath, compileClasspath )
- `Nested`.. this could be the key, if you cannot make `LintGradleRequest` serializable.If generating the `LintGradleRequest` it's too complex we could have another task, and use the output of this first non-cacheable task as the input for `lintAnalyze`.In that way, without breaking backwards compatibility we would have:
lintGenerateRequest: fast, non-cacheable
lintAnalyze: slow but cacheable, not yet incremental, is the one that runs `LintCliClient`
lint: depends on both, and just analyze the `lintAnalyze` xml report to show warnings/errors on the console, and may make the build fail.What I haven't found yet is the baseline, but I guess is more related to the reporter than the analyzer. Is it in anyway sent through the same `LintRequest`?Does it make any sense to you?
Thanks for noticing.
About adding the gradle files sees easy but any other file... It seems it would make the issue harder.
I would assume the list of files could only be computed after loading the classes on AST, isn't it?
Could you point me to the right place to look how this: AST, exploration, run linters work?
I want to see if that can be split in steps (at least exploration and analysis) and if it's worth, because I guess just loading the class on AST to explore it would consume most of the time, and that currently the linter doesn't need to load anything because you reuse everything from the exploration phase.
In our case we ended using `./gradlew build --exclude-task lint` and running lint in another worker on the CI. It's not amazing but our builds are times faster now.
We'll work with the Gradle enterprise trial hopefully next week, but I think lint will still be out biggest issue.