upToDateWhen {false} does not rerun task

Hi,

I am writing a custom task to run lint’er on “modified files”.

tasks.register("ktlintCheck", JavaExec::class.java) { javaExec ->
            javaExec.classpath(ktlintConfig)
            javaExec.mainClass.set("com.pinterest.ktlint.Main")
            javaExec.group = "verification"

            val modifiedFiles = getKtModifiedFiles()
            if (modifiedFiles.isEmpty()) {
                project.logger.info("Ktlint: No files modified.")
                javaExec.enabled = false
            } else {
                project.logger.info("Ktlint: Files modified. Running Ktlint")
                javaExec.enabled = true
            }
            modifiedFiles.forEach { eachFile ->
                javaExec.args(eachFile)
            }
           
            javaExec.outputs.upToDateWhen { false }
        }

I am explicitly setting upToDateWhen = false, so that Gradle can re-run task everytime I run ktlintCheck. But somehow Gradle identifies that there is no change in the task and does not run the task though there are changes to modified files.

If I run ./gradlew ktlintCheck --rerun it works fine. I also want to make my custom task to rerun when I run ./gradlew ktlintCheck.

If you want to disable Gradle’s up-to-date checks, better use doNotTrackState("I don't want to") instead of upToDateWhen.

1 Like

Added doNotTrackState("I don't want to")

tasks.register("ktlintCheck", JavaExec::class.java) { javaExec ->
            javaExec.classpath(ktlintConfig)
            javaExec.mainClass.set("com.pinterest.ktlint.Main")
            javaExec.group = "verification"
            javaExec.doNotTrackState("Refresh needed everytime!")

            val modifiedFiles = getKtModifiedFiles()
            if (modifiedFiles.isEmpty()) {
                project.logger.info("Ktlint: No files modified.")
                javaExec.enabled = false
            } else {
                project.logger.info("Ktlint: Files modified. Running Ktlint")
                javaExec.enabled = true
            }
            modifiedFiles.forEach { eachFile ->
                javaExec.args(eachFile)
            }
        }

Still the same error: > Task :app:ktlintCheck SKIPPED Skipping task ':app:ktlintCheck' as task onlyIf 'Task is enabled' is false.

If “how I apply this task to my build.gradle” is important: I am adding this task as a gradle custom plugin to my build.gradle.

Well, first time you mention the “error” message.
If you have an onlyIf that says false, there is no way to run the task anyway.
Even though you said so, not even --rerun can achieve that, it will still be skipped.
That it worked with --rerun for you was most probably just a coincidence.
But you can override any set only if specs using for example setOnlyIf { true }.

I am not explicitly setting setOnlyIf {false}, based on enabled flag something is happening in the task and is not getting out of that state.

And yes, infact “–rerun” worked as a coincidence.

 if (modifiedFiles.isEmpty()) {
                project.logger.info("Ktlint: No files modified.")
                javaExec.enabled = false
            } else {
                project.logger.info("Ktlint: Files modified. Running Ktlint")
                javaExec.enabled = true
            }

I tried to setOnlyIf { true } but nothing changed.

I changed my logic from enabled to change values like this

val modifiedFiles = getKtModifiedFiles()
            if (modifiedFiles.isEmpty()) {
                project.logger.info("Ktlint: No files modified.")
                javaExec.args("invalid/unknown.txt")
            } else {
                project.logger.info("Ktlint: Files modified. Running Ktlint")
                modifiedFiles.forEach { eachFile ->
                    javaExec.args(eachFile)
                }
            }

I set javaExec.doNotTrackState("Not needed") but still my modifiedFiles are always having the same list whatever I have during first run. Is there a property that I can set to force-rerun?

I am not explicitly setting setOnlyIf {false}

I did not say you do.
I said you need to do setOnlyIf { true } to replace all set onlyIf actions with the always-true on.
But actually, I misread, sorry.
Somehow my brain stopped reading at onlyIf.
As it is the “Task is enabled” onlyIf, why would you expect the task to run if you set it to enabled = false?

Or is it, that the calculation of the enabled is what you assume to be wrong?

Do you have configuration cache enabled?
Because then the task’s configuration is persisted and if recognized configuration cache inputs did not change will not be reevaluated.
Depending on what getKtModifiedFiles does this might be a shortcoming of the recognition or you just need to declare it explicitly.

Or maybe it is even better to not calculate enabled at configuration time, potentially when it is not even possible the task needs to run, but instead use onlyIf { ... ] to do you decision, then it is done at execution time.