Насколько я понимаю, в данный момент вы используете allprojects {}
для настройки всех подпроектов. Хотя это было каноническим для настройки группы проектов в прошлом, сейчас это не рекомендуется. Кроме того, проекты должны использовать публикации для взаимодействия друг с другом, а не копировать файлы через границы проекта. Так что вам нужно сделать две вещи:
- Вместо настройки подпроектов из корневого корневого проекта вы должны создать плагин для настройки jacoco и создать конфигурацию, которая будет содержать отчеты.
Для этого создайте предварительно скомпилированный скрипт-плагин в вашем проекте. Идея состоит в том, чтобы создать скрипт сборки kotlin в проекте buildSrc
и создать плагин Gradle из этого файла на лету. Поэтому вам следует переместить логику, которая настраивает jacoco, в файл buildSrc/src/main/kotlin/jacoco-conventions.gradle.kts
:
plugins {
jacoco
}
val jacocoTestReport by tasks.getting(JacocoReport::class) {
// jacoco configuration
}
configurations.create("jacocoReports") {
isCanBeResolved = false
isCanBeConsumed = true
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class, "jacocoReports"))
}
outgoing.artifact(jacocoTestReport.reports.xml.destination) {
builtBy(jacocoTestReport)
}
}
Последняя часть создает новую конфигурацию в проекте, к которому применяется предварительно скомпилированный скрипт-плагин. В этой конфигурации в качестве исходящего артефакта используется файл назначения xml, созданный задачей отчета jacoco. Важной частью здесь является USAGE_ATTRIBUTE
, потому что это понадобится нам позже, чтобы использовать файлы.
Плагин скомпилированных скриптов теперь можно применять в проектах, в которых вы хотите собирать показатели jacoco:
// for example in c/build.gradle.kts
plugins {
`jacoco-conventions`
}
Теперь вы настроили подпроекты для размещения отчетов Jacoco xml в конфигурациях с атрибутом использования jacocoReports
.
- В корневом проекте создайте задачу, которая копирует отчет из конфигурации.
Для этого нам нужно настроить конфигурацию, которая использует варианты jacocoReports
, а затем зависит от вариантов подпроектов:
// main build file
val jacocoReports by configurations.creating {
isCanBeResolved = true
isCanBeConsumed = false
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class, "jacocoReports"))
}
}
dependencies {
jacocoReports(project(":b:c"))
jacocoReports(project(":b:d:e"))
// other jacocoReports you want to consume
}
tasks.register<Copy>("aggregateJacocoReports") {
from(jacocoReports)
into(file("$buildDir/jacoco"))
}
Как видите, конфигурация jacocoReports
имеет такой же атрибут использования, что позволяет использовать ее для разрешения файлов, которые находятся в конфигурациях с таким же атрибутом. Затем нам нужно определить, какие отчеты проекта мы хотим использовать. Это конус путем определения зависимостей проекта с использованием конфигурации jacocoReports
. Последний шаг - это простая задача копирования, которая копирует файлы в каталог сборки корневого проекта. Так что теперь, когда вы вызываете ./gradlew aggregateJacocoReports
, эта задача разрешает все файлы из конфигурации jacocoReports
, что, в свою очередь, создает отчет jacoco для всех проектов, от которых зависит корневой проект.
Почему это лучше, чем кросс-конфигурация? Если проекты не запутаны перекрестной конфигурацией и задачами, которые копируют данные между проектами, gradle может более эффективно планировать и распараллеливать работу, которую необходимо выполнить.
У меня есть минимальный пример, который должен помочь вам настроить ваш проект следующим образом: https://github.com/britter/gradle-jacoco-aggregate. Я удалил специальную конфигурацию Android, чтобы она была простой, но я уверен, что вы поймете это.