Hacktoberfest 2026: as issues que os mantenedores marcaram para outubro, abertas e boas para iniciantes. Ver issues do Hacktoberfest

`targetExclude("**/build/**")` makes configuration cache store and reuse walk the entire project directory

Aberta
#3,147 0 comentários 1 reação 0 responsáveis Ver no GitHub

Mantenedores costumam responder em até 1 dia

Ninguém assumiu esta issue ainda.

Avaliação

Dificuldade
4/5
Tempo estimado
3-5 dias
Facilidade para iniciantes
43/100
Tipo de issue
Bug
Clareza
Claramente especificada
Status de atividade
Ativa
Stack de tecnologia
java, kotlin

Direção de pesquisa

Start with FormatExtension.java around lines 314 and 329, then trace target subtraction and the lineEndingsPolicy input around lines 1096 and 1114. Read GitAttributesLineEndings.java around line 92 and inspect the supplied configuration cache stack trace to understand when the file tree is traversed. Done means string targetExclude("**/build/**") avoids walking and fingerprinting unrelated project files during configuration cache store and reuse while preserving the exclusion behavior; the issue provides TestKit timing comparisons to reproduce and assess the change.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

bug
Summary

A targetExclude string pattern that starts with ** makes configuration-cache store and reuse scale with the total number of files under the project directory. This happens even when target is already scoped to a few subfolders, as recommended in #2717 and #833.

spotless {
    kotlin {
        ktlint()
        target(
            "build-logic/**/*.kt",
            "build-logic/**/*.kts",
            "settings-logic/**/*.kt",
            "settings-logic/**/*.kts",
        )
        targetExclude("**/build/**")
    }
}

Measured with TestKit, Gradle 9.8.1, project dir containing ~100k unrelated files, spotlessKotlinCheck --dry-run:

Configuration CC store CC reuse
target(...) only ~70 ms ~50 ms
target(...) + targetExclude("**/build/**") ~1000 ms ~1250 ms
target(fileTree(".") { include(...); exclude("**/build/**") }) ~90 ms ~45 ms

With --no-configuration-cache all three configurations take under 100 ms at configuration time. In a real repo the walk covers .git, .gradle and every module's build output, so the cost grows with the size of the repo.

Root cause
  1. A string targetExclude becomes project.fileTree(projectDir).include("**/build/**") (FormatExtension.java:314). Gradle cannot prune a leading **, and the exclude branch returns before the default .git / .gradle / build-dir excludes are added (L329). So resolving this tree means walking the whole project directory.
  2. The task target is target.minus(targetExclude) (L1096).
  3. With the default GIT_ATTRIBUTES_FAST_ALLSAME, the lineEndingsPolicy task input is LazyAllTheSame (L1114). When the configuration cache serializes that input, LazyForwardingEquality.writeObject calls calculateState(), which runs toFormat.get().iterator() (GitAttributesLineEndings.java:92) just to get the first file. Iterating the SubtractingFileCollection resolves right.getFiles(), which walks the whole tree.
  4. Because this happens during configuration, Gradle records the collection as a configuration input (ConfigurationCacheFingerprintWriter.fileCollectionObserved) and snapshots the whole tree. On every later build the fingerprint check snapshots it again, so CC reuse is slow too.

Relevant stack excerpt from the store phase:

at org.gradle.internal.cc.impl.fingerprint.ConfigurationCacheFingerprintWriter.fileCollectionObserved
at org.gradle.api.internal.file.collections.DefaultConfigurableFileTree.getFiles
...
at com.diffplug.spotless.extra.GitAttributesLineEndings$LazyAllTheSame.calculateState
at com.diffplug.spotless.LazyForwardingEquality.state
at com.diffplug.spotless.LazyForwardingEquality.writeObject
at org.gradle.internal.serialize.codecs.core.jos.JavaObjectSerializationCodec$WriteObjectEncoding.encode
at org.gradle.internal.serialize.codecs.core.ProviderCodec.encode
at org.gradle.internal.serialize.codecs.core.TaskNodeCodec.writeTask

Replacing minus with filter { !targetExclude.contains(it) } is not enough: it only brings store to ~350 ms and reuse to ~640 ms. DefaultConfigurableFileTree.contains() also reports fileCollectionObserved during configuration, so the whole exclude tree still gets fingerprinted.

Related to

  • #833
  • #2717
Linguagem predominante
Java
Estrelas
5.7k
Forks
562
Merge médio
3d 2h
PRs com merge (30d)
30

Preparar o ambiente

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de diffplug/spotless

Todas as issues de diffplug/spotless

Issues semelhantes

Mais issues de Java

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.