Automatizacija zadataka za build je ključna za svaki softverski projekat, a Gradle, uz svoj Kotlin DSL, nudi izuzetnu fleksibilnost. Tokom naše rasprave, istražili smo kako centralizovati i ponovo koristiti logiku builda, posebno za izveštaje o testiranju, korišćenjemallprojects, buildSrc, и прилагођени задатаци у Kotlin

Centralizirati konfiguracije sa allprojects i `subprojects

Blokovi`allprojects` et `subprojects`у вашем`build.gradle.kts`Koreni su osnovni za primenu zajedničkih konfiguracija kroz vaš multimodularni projekat.

*allprojects { …​ }: Примени конфигурацију накорени пројекат и свим његовим подпројектима. Idealno za definisanje jednom? Wait, I need to check: I wrote "jednom" incorrectly. Should be "jednog". So final: ". Idealno za definisanje jednog". Ensure correct.

</think>

  1. Idealno za definisanje једног`group`, jedna`version`, ili neke`repositories`заједницки. *subprojects { …​ }: Primeni konfiguracijusamo podprojektima, isključujući korenjski projekat. Idealno za primenu specifičnih pluginova za module (kao`java` ou kotlin-jvm)或 заједничке зависности у вашим библиотекама.

Ово је илустративан пример :

// build.gradle.kts (projet racine)
plugins {
    base // Appliqué au projet racine
}

allprojects {
    group = "com.example"
    version = "1.0.0"

    repositories {
        mavenCentral()
    }

    tasks.withType<org.gradle.api.tasks.testing.Test> {
        useJUnitPlatform() // Configuration commune des tests pour tous les projets
    }
}

subprojects {
    apply(plugin = "java")
    apply(plugin = "org.jetbrains.kotlin.jvm")

    dependencies {
        implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    }

}

\==buildSrc: Švicarski nož logike gradnje

Kada logika vaših zadataka postaje kompleksna ili mora biti ponovo korišćena,buildSrcОво је предпочелно решење. Ово је посебан Gradle модул који се компајлира пре главних скриптова за градње, чинећи његове класе доступним на класапат у целином вашем градње.

Zašto koristiti`buildSrc`за задачи ?

  • Ponovna upotreba: Задатак дефинисан у`buildSrc`Можемо да се примени на било који пројекат грађења.

  • Organizacija: Centralizuje kod gradnje, čineći ga čistijim i lakše održivim.

  • Sigurnost tipova i autodopunjavanje: Код у Kotlin у`buildSrc`kompajlira se, nudući provjeru grešaka i autocompletion vašeg IDE-a, poboljšavajući iskustvo razvoja.

\=== Dijagram toka`buildSrc`(Код PlantUML)

Da biste generisali ovaj dijagram, kopirajte kod ispod i zalepite ga u alat koji podržava PlantUML.

[source,plantuml]

@startuml skinparam handwritten true skinparam monochrome true

правоугаоник "Gradle Build Process" { component "buildSrc" as BS { fajl "MyCustomTask.kt" kao T fajl "MyConventionPlugin.kt" kao P } komponenta "Root Project" as RP komponenta "Subproject A" kao SA komponenta "Subproject B" kao SB }

T --\> P : "je definirano u P --\> RP : "primenjuje se na P --\> SA : "primenjuje se na P --\> SB : "primenjuje se na

RP --|\> SA : "sadrži RP --|\> SB : "sadrži

RP -up-\> BS : "зависи од (за логику грађења) SA -up→ BS : "zavisi od (za logiku gradnje) SB -up-\> BS : "zavisi od (za logiku gradnje)

белешка десно од T Prilagođene klase zadataka OpenTestReportTask završna beleška

белешка десно од P Konvencija plugini koji beleže zadatke белешка на крај

@enduml

\== Kreiranje apstraktnih zadataka izveštaja

Za upravljanje izveštajima o testovima, smo koncipirali modularni pristup korišćenjem apstraktne klase zadatka u`buildSrc`. Po vašim potrebama, ova klasa može da nasledi`DefaultTask` ou de Exec.

\=== Abstraktni zadatak`OpenTestReportTask`(наслеђујући од`DefaultTask`)

Ovaj pristup se preporučuje ako vam je potrebna prilagođena Kotlin logika koja interaguje sa sistemom datoteka ili drugim Gradle API-jevima, a zatim pokreće vanjsku komandu.

[source,kotlin]

paket com.yourpackage

import org.gradle.api.DefaultTask import org.gradle.api.tasks.Input import org.gradle.api.tasks.TaskAction import java.io.File

abstract class OpenTestReportTask : DefaultTask() {

----
----
init {
    group = "verification"
    description = "Opens a test report in Firefox."
    dependsOn("check") // Assure que les rapports sont générés
}

@get:Input
abstract var reportPath: String

@TaskAction
fun openReport() {
    val separator = File.separator
    val reportFile = project.layout.projectDirectory.asFile.toPath()
        .resolve(reportPath.replace("/", separator))
        .toAbsolutePath()
        .toFile()

    if (!reportFile.exists()) {
        logger.warn("Report file does not exist: $reportFile. Ensure 'check' ran.")
        return
    }

    project.exec {
        commandLine("firefox", "--new-tab", reportFile.absolutePath)
    }
    logger.lifecycle("Opened test report: ${reportFile.absolutePath}")
}
----

## }

\=== Implementacije Konkretne

Ove klase nasleđuju iz apstraktnog zadatka i definišu specifičnu putanju izveštaja.

[source,kotlin]

package com.yourpackage

apstraktna klasa ReportUnitTestsTask : OpenTestReportTask() { init { description = "Отвара извештај о юнит тесту у Firefox. reportPath = "build/reports/tests/test/index.html } }

paket com.vasepaket

## abstract class ReportFunctionalTestsTask : OpenTestReportTask() { init { description = "Отвара извештај о функционалним тестовима у Firefox-у." reportPath = "build/reports/tests/functionalTest/index.html" } }

\=== Запис задатака

U`build.gradle.kts`вашег коренског пројекта :

## [source,kotlin]

tasks.register\<com.yourpackage.ReportUnitTestsTask\>("reportTests") {} tasks.register\<com.yourpackage.ReportFunctionalTestsTask\>("reportFunctionalTests") {}

\=== UML dijagram zadataka izveštaja (Code PlantUML)

Копирајте код испод и залепите га у алатка која подржава PlantUML.

## [source,plantuml]

@startuml skinparam handwritten true skinparam monochrome true

apstraktna klasa DefaultTask { }

apstraktna klasa Exec { \+ commandLine(args: String...) \+ exec() }

apstraktna klasa OpenTestReportTask extends DefaultTask { \+ grupa: String = "verifikacija \+ opis: String \+ dependsOn("check") + abstract reportPath: String \+ openReport() : void }

apstraktna klasa AbstractJbakeExecTask extends Exec { \+ group: String = "проверка \+ opis: String \+ dependsOn("check") \+ abstract reportRelativePath: String \+ exec() : void }

class ReportUnitTestsTask extends OpenTestReportTask { \+ reportPath: String = "build/reports/tests/test/index.html }

class ReportFunctionalTestsTask extends OpenTestReportTask { \+ reportPath: String = "build/reports/tests/functionalTest/index.html }

class ReportJbakeTestsTask extends AbstractJbakeExecTask { \+ reportRelativePath: String = "build/reports/tests/test/index.html }

class ReportJbakeFunctionalTestsTask extends AbstractJbakeExecTask { \+ reportRelativePath: String = "build/reports/tests/functionalTest/index.html }

OpenTestReportTask \<-- ReportUnitTestsTask OpenTestReportTask \<-- ReportFunctionalTestsTask

AbstractJbakeExecTask \<-- ReportJbakeTestsTask AbstractJbakeExecTask <-- ReportJbakeFunctionalTestsTask

DefaultTask \<|-- OpenTestReportTask Izvrši \<|-- AbstractJbakeExecTask DefaultTask \<|-- Exec

## @enduml

\== апстрактан задатак`AbstractJbakeExecTask`(nasleđujući od`Exec`)

Ako je vaša uloga uglavnom izvršavanje vanjske komande sa varijablenim argumentima, nasledujte direktno**Izvrši**је бежији.

## [source,kotlin]

пакет com.yourpackage

import org.gradle.api.tasks.Exec import org.gradle.api.tasks.Input import java.io.File

apstraktna klasa AbstractJbakeExecTask : Exec() {

----

init { group = "verification" description = "Opens a Jbake project report in Firefox." dependsOn("check") }

@get:Input abstract var reportRelativePath: String

override fun exec() { val separator = File.separator val reportFile = project.layout.projectDirectory.asFile.toPath() .resolve(reportRelativePath.replace("/", separator)) .toAbsolutePath() .toFile()

if (!reportFile.exists()) { logger.warn("Report file does not exist: $reportFile. Ensure 'check' ran.") return }

commandLine("firefox", "--new-tab", reportFile.absolutePath) logger.lifecycle("Attempting to open report: ${reportFile.absolutePath}") super.exec() // Appelle la méthode exec() de la super-classe Exec }

## }

\=== Конкретне имплементације за`Exec`

## [source,kotlin]

paket com.yourpackage

abstract class ReportJbakeTestsTask : AbstractJbakeExecTask() { inicijalizacija { Otvara izveštaj Jbake jediničnih testova u Firefox-u. reportRelativePath = "build/reports/tests/test/index.html } }

package com.yourpackage

## abstract class ReportJbakeFunctionalTestsTask : AbstractJbakeExecTask() { init { description = "Otvara izveštaj funkcionalnih testova u Firefox-u." reportRelativePath = "build/reports/tests/functionalTest/index.html" } }

\== Vidljivost zadataka`buildSrc`

Задаци и класе које definiшете у**buildSrc**су:

***Vidljivi i upotrebljivi**по свим пројектима вашег главног билда (корен и подпројекти). Због тога можете да користите`com.yourpackage.ReportUnitTestsTask`у`allprojects { ... }`. * **Neizvršni**одноставно као задатке у buildSrc (на пример,`gradle :buildSrc:reportTests`Ne bi radilo ako zadatak nije specifično beležen u`buildSrc/build.gradle.kts`).`buildSrc`je modul kompilacije, ne modul izvršne aplikacije za ove zadatke glavnog builda.

Izvršite izveštaj za testove`buildSrc`сам

Si `buildSrc`ima sopstveni testovi i generiše izveštaje, vi mozete da registrovate zadatak izveštaja direktno u`buildSrc/build.gradle.kts`:

## [source,kotlin]

plugins { `kotlin-jvm` }

repozitorijumi { mavenCentral() }

tasks.withType<Test> { useJUnitPlatform() reports.html.outputLocation.set(layout.buildDirectory.dir("reports/tests")) }

import com.yourpackage.ReportJbakeTestsTask // Uvezite svoju klasu zadatka

tasks.register\<ReportJbakeTestsTask\>("reportBuildSrcTests") { // Putanja je već definisana u klasi, ona će pokazivati na izveštaje iz buildSrc }

Затим можете да извршите :`./gradlew :buildSrc:test`praćen od`./gradlew :buildSrc:reportBuildSrcTests`.

Primenjivanjem ovih praksi, ćete izgraditi Gradle build sisteme u Kotlin DSL koji su ne samo moćni, nego i izuzetno modularni, održivi i laki za razumevanje.

Повезани чланци