Derleme görevlerinin otomasyonu her yazılım projesinde kritik öneme sahiptir ve Gradle, Kotlin DSL’iyle muhteşem bir esneklik sunar. Konuşmamız sırasında, test raporları gibi şeyler için özellikle derleme mantığını nasıl merkezi hale getirip yeniden kullanabileceğimizi keşfettik.allprojects, buildSrc, ve özel görevler Kotlin’de.

allprojects` ve subprojects bloklarını kullanarak yapılandırmaları merkezileştirin

Bloklar`allprojects` et `subprojects`senin içinde`build.gradle.kts`Kökler, çok modüllü projenizde ortak konfigürasyonları uygulamada temel bir rol oynar.

*allprojects { …​ }`Yapılandırmayı uygulakök proje ve tüm alt projeleri. Tanım yapmak için ideal`group, bir`version`, veya bazı`repositories`ortak. *subprojects { …​ }`Konfigürasyonu uygulaYalnızca alt-projelere, kök projeyi hariç tutarak. Modüllere özel eklentiler uygulamak için idealdir (örnek`java ou kotlin-jvm) veya kitaplığınızdaki ortak bağımlılıklar.

İşte bir örnek gösterimi:

// 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`Derleme mantığının İsviçre çakısı

Görevlerinizin mantığı karmaşık hale geldiğinde ya da yeniden kullanılması gerektiğinde,buildSrctercih eden çözüm. Bu özel bir Gradle modülüdür, ana derleme scriptlerinden önce derlenir ve sınıflarını tüm derleme class path’ine erişilebilir kılar.

Neden kullanmak`buildSrc`Görevler için?

  • yeniden kullanabilirlikBir görev tanımlanmış innerhalb`buildSrc`herhangi bir derleme projesine uygulanabilir

  • Organizasyon: Derleme kodunu merkezileştirerek daha temiz ve sürdürülebilir hâle getirir.

  • Tip Güvenliği ve Otomatik Tamamlama: Kotlin kodu içinde`buildSrc`derlenir, hataları tespit ederek ve IDE’nizin otomatik tamamlamasını sağlayarak geliştirme deneyimini iyileştirir.

\=== Akış Diyagramı`buildSrc`(Kod PlantUML)

Bu diyagramı oluşturmak için aşağıdaki kodu kopyalayıp PlantUML destekleyen bir araca yapıştırın.

[source,plantuml]

@startuml skinparam handwritten true skinparam tekrenkli doğru

dikdörtgen "Gradle Build Process" { bileşen "buildSrc" olarak BS { dosya "MyCustomTask.kt" olarak T file "MyConventionPlugin.kt" as P } bileşen "Root Project" olarak RP bileşen "Subproject A" olarak SA bileşen "Subproject B" olarak SB }

tanımlanır P --\> RP : "is applied to P -→ SA : "is applied to P --\> SB : "uygulanır

RP --|\> SA : "contains RP --|\> SB : "içerir

RP -up→ BS : "depends on (for build logic) SA -up→ BS : "depends on (for build logic) SB -up→ BS : "depends on (for build logic)

not T’nin sağında Özel görev sınıfları (örnek: OpenTestReportTask) end note

P’nin sağ notu Konvansiyon eklentileri görevleri kaydedenler son not

@enduml

Soyut Rapor Görevlerinin Oluşturulması

Test raporlarını yönetmek için, soyut görev sınıfı kullanarak modüler bir yaklaşım tasarladık içinde`buildSrc`. İhtiyaçlarınıza göre, bu sınıf devralabilir`DefaultTask` ou de Exec.

\=== Soyut Görev`OpenTestReportTask`(devralan`DefaultTask`)

Bu yaklaşım, dosya sistemi veya diğer Gradle API’leriyle etkileşim kuran özel Kotlin mantığına ihtiyacınız varsa ve ardından dış bir komut çalıştırmanız gerekiyorsa önerilir.

[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}")
}
----

## }

Somut Uygulamalar

Bu sınıflar soyut görevden kalıtım alır ve raporun belirli yolunu tanımlar.

[source,kotlin]

package com.yourpackage

soyut sınıf ReportUnitTestsTask : OpenTestReportTask() init { Birim test raporunu Firefox'ta açar. reportPath = "build/reports/tests/test/index.html } }

paket com.yourpackage

abstract class ReportFunctionalTestsTask : OpenTestReportTask() {
    init {
        description = "Fonksiyonel test raporunu Firefox'ta açar."
        reportPath = "build/reports/tests/functionalTest/index.html"
    }
}

Görev Kayıtları

İçinde`build.gradle.kts`kök projeniz:

[source,kotlin]

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

\=== Rapor Görevleri UML Diyagramı (Code PlantUML)

Aşağıdaki kodu kopyalayıp PlantUML'i destekleyen bir araca yapıştırın.

## [source,plantuml]

@startuml skinparam elyazısı true skinparam monochrome true

soyut sınıf DefaultTask { }

soyut sınıf Exec { \+ commandLine(args: String...) \+ exec() }

abstract class OpenTestReportTask extends DefaultTask { + grup: String = "doğrulama + açıklama: String \+ dependsOn("check") \+ abstract reportPath: String \+ openReport() : void }

Soyut sınıf AbstractJbakeExecTask Exec'i genişletir. \+ group: String = "verification \> note:` No additional output needed beyond this line. \+ 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 }

sınıf ReportJbakeTestsTask AbstractJbakeExecTask'ı genişletir { \+ 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 Exec \<|-- AbstractJbakeExecTask DefaultTask \<|-- Exec

## @enduml

Soyut görev`AbstractJbakeExecTask`(devralan`Exec`)

Eğer görevinizin temel amacı dışarıdan bir komutu değişken argümanlarla çalıştırmaksa, doğrudan miras alın.**Exec**daha doğrudur.

## [source,kotlin]

package com.yourpackage

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

abstract class 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
}

}

\=== Somut Uygulamalar için`Exec`

[source,kotlin]

package com.yourpackage

abstract class ReportJbakeTestsTask : AbstractJbakeExecTask() init { description = "Jbake birim testi raporunu Firefox’ta açar. reportRelativePath = "build/reports/tests/test/index.html } }

paket com.yourpackage

abstract class ReportJbakeFunctionalTestsTask : AbstractJbakeExecTask() { init { description = "İşlevsel test raporunu Firefox’ta açar." reportRelativePath = "build/reports/tests/functionalTest/index.html" } }

Görevlerin Görünürlüğü`buildSrc`

Tanımladığınız görevler ve sınıflar içindebuildSrcoluralar :

(blank)Görünür ve KullanılabilirAna buildinizdeki tüm projelerde (kök ve alt-proje). Bu yüzden kullanabilirsiniz.com.yourpackage.ReportUnitTestsTask`içinde`allprojects { …​ }. (No text)Çalıştırılamayanlardoğrudan buildSrc görevleri olarak (örnek olarak,gradle :buildSrc:reportTests`Özel olarak kaydedilmediği takdirde çalışmazdı`buildSrc/build.gradle.kts)`buildSrc`Bir derleme zamanı modülüdür, ana derleme görevleri için yürütülebilir bir uygulama modülü değildir.

\=== Testler için bir rapor çalıştır`buildSrc`kendi

Si buildSrc`Kendi testlerini yürütür ve raporlar üretir, bir rapor görevi doğrudan kaydedebilirsiniz.`buildSrc/build.gradle.kts(empty)

[source,kotlin]

plugins { kotlin-jvm }

depolar { mavenCentral() }

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

import com.yourpackage.ReportJbakeTestsTask // Görev sınıfınızı içe aktarın

tasks.register<ReportJbakeTestsTask>("reportBuildSrcTests") { // Yol sınıf içinde zaten tanımlanmıştır ve buildSrc raporlarına işaret edecektir }

Sonra şu komutu çalıştırabilirsiniz :`./gradlew :buildSrc:test`ardından`./gradlew :buildSrc:reportBuildSrcTests`.

Bu uygulamaları benimsederek, sadece güçlü değil, aynı zamanda harika derecede modüler, sürdürülebilir ve anlaşılması kolay Kotlin DSL Gradle derleme sistemleri oluşturacaksınız.

İlgili Makaleler