Otomatisasi tugas build sangat penting untuk setiap proyek perangkat lunak, dan Gradle, dengan DSL Kotlinnya, menawarkan fleksibilitas yang luar biasa. Selama percakapan kami, kami telah menjelajahi cara memusatkan dan menggunakan kembali logika build, khususnya untuk laporan pengujian, dengan memanfaatkanallprojects, sumber build, dan tugas khusus dalam Kotlin.

Pusatkan Konfigurasi dengan allprojects dan `subprojects

blok-blok`allprojects` et `subprojects`dalam Anda`build.gradle.kts`Akar merupakan dasar untuk menerapkan konfigurasi umum di seluruh proyek multi-modul Anda.

*allprojects { …​ }: Terapkan konfigurasi keproyek induk dan semua sub-proyeknya. Ideal untuk mendefinisikan`group`, sebuah`version`, atau beberapa`repositories`umum. *subprojects { …​ }`Terapkan konfigurasihanya ke sub-proyek, mengkecualikan proyek akar. Cocok untuk menerapkan plugin khusus modul (seperti`java ou kotlin-jvm) atau dependensi umum untuk perpustakaan Anda.

Berikut contoh ilustratif :

// 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`pisau Swiss logika Build

Saat logika dari tugas-tugas Anda menjadi kompleks atau perlu digunakan kembali,buildSrcIni adalah solusi yang diprioritaskan. Ini adalah modul Gradle khusus yang dikompilasi sebelum skrip build utama, sehingga kelasnya tersedia di classpath seluruh build Anda.

\=== Mengapa menggunakan`buildSrc`untuk Tugas ?

  • Kemampuan untuk digunakan kembali: Sebuah tugas yang didefinisikan di`buildSrc`bisa diterapkan pada setiap proyek build.

  • Organisasi: Memusatkan kode build, membuatnya lebih bersih dan dapat dipelihara.

  • Keamanan Tipe dan Penyelesaian Otomatis: Kode Kotlin di`buildSrc`dikompilas, menawarkan pemeriksaan kesalahan dan autocompletion IDE Anda, meningkatkan pengalaman pengembangan.

\=== Diagram Alur`buildSrc`(kode PlantUML)

Untuk menghasilkan diagram ini, salin kode di bawah ini dan tempelkan ke dalam alat yang mendukung PlantUML.

[source,plantuml]

@startuml skinparam tulis tangan benar skinparam monochrome true

persegi panjang "Gradle Build Process komponen "buildSrc" sebagai BS { file "MyCustomTask.kt" as T file "MyConventionPlugin.kt" sebagai P } komponen "Root Project" sebagai RP komponen "Subproject A" sebagai SA komponen "Subproject B" sebagai SB }

T --\> P : "didefinisikan dalam P --\> RP : "diterapkan pada P --\> SA : "diterapkan untuk P --\> SB : "diterapkan pada

RP --|\> SA : "contains RP --|\> SB : "mengandung

RP -up-\> BS : "tergantung pada (untuk logika build) SA -up-\> BS : "tergantung pada (untuk logika pembangunan) SB -up-\> BS : "tergantung pada (untuk logika build)

catatan di sebelah kanan T Kelas tugas kustom (ex: OpenTestReportTask) catatan akhir

catatan di sebelah kanan P Plugin konvensi yang mencatat tugas catatan akhir

@enduml

\== Pembuatan Tugas Laporan Abstrak

Untuk mengelola laporan tes, kami telah merancang pendekatan modular dengan menggunakan kelas tugas abstrak di`buildSrc`. Sesuai kebutuhan Anda, kelas ini dapat mewarisi dari`DefaultTask` ou de Exec.

\=== Tugas Abstrak`OpenTestReportTask`(mewarisi dari`DefaultTask`)

Pendekatan ini direkomendasikan jika Anda memerlukan logika Kotlin kustom yang berinteraksi dengan sistem file atau API Gradle lainnya, lalu menjalankan perintah eksternal.

[source,kotlin]

package com.yourpackage

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

kelas abstrak 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}")
}
----

## }

=== Implementasi konkret

Kelas-kelas ini mewarisi tugas abstrak dan menentukan jalur spesifik laporan.

## [source,kotlin]

paket com.paketAnda

abstract class ReportUnitTestsTask : OpenTestReportTask() { inisialisasi { description = "Membuka laporan tes unit di Firefox. reportPath = "build/reports/tests/test/index.html } }

package com.yourpackage

## kelas abstrak ReportFunctionalTestsTask : OpenTestReportTask() { init { deskripsi = "Membuka laporan tes fungsional di Firefox." jalurLaporan = "build/reports/tests/functionalTest/index.html" } }

Pencatatan Tugas

dalam`build.gradle.kts`dari proyek akar Anda :

## [source,kotlin]

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

\=== Diagram UML Tugas Laporan (Kode PlantUML)

Salin kode di bawah ini dan tempelkan ke dalam alat yang mendukung PlantUML.

## [source,plantuml]

@startuml skinparam tulisan tangan true skinparam monochrome true

classe abstraite DefaultTask { }

kelas abstrak Exec { \+ commandLine(args: String...) \+ exec() }

abstract class OpenTestReportTask extends DefaultTask { \+ group: String = "verifikasi \+ deskripsi: String \+ dependsOn("check") \+ abstract reportPath: String + openReport() : void }

kelas abstrak AbstractJbakeExecTask meng-extends Exec { \+ group: String = "verification \+ description: String \+ dependsOn("check") \+ abstrak jalurLaporanRelatif: 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 AbstrakJbakeTugasEksekusi \<-- LaporanJbakeTugasUjiFungsional

DefaultTask \<|-- OpenTestReportTask Exec \<|-- AbstractJbakeExecTask DefaultTask \<|-- Eksekusi

## @enduml

\== Tugas Abstrak`AbstractJbakeExecTask`(mewarisi dari`Exec`)

Jika tugas Anda terutama melibatkan eksekusi perintah eksternal dengan argumen yang berubah-ubah, wariskan secara langsung dari**Eksekusi**lebih langsung.

## [source,kotlin]

package com.yourpackage

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

kelas abstrak 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 }

## }

\=== Implementasi konkret untuk`Exec`

## [source,kotlin]

package com.yourpackage

abstract class ReportJbakeTestsTask : AbstractJbakeExecTask() { inisialisasi { Membuka laporan uji unit Jbake di Firefox. reportRelativePath = "build/reports/tests/test/index.html } }

package com.yourpackage

## abstract class ReportJbakeFunctionalTestsTask : AbstractJbakeExecTask() { init { description = "Membuka laporan tes fungsional di Firefox." reportRelativePath = "build/reports/tests/functionalTest/index.html" } }

\== Visibilitas Tugas`buildSrc`

Tugas dan kelas yang Anda tetapkan dalam**buildSrc**adalah :

***Terlihat dan dapat digunakan**oleh semua proyek build utama Anda (root dan sub-proyek). Itu sebabnya Anda dapat menggunakan`com.yourpackage.ReportUnitTestsTask`dalam`allprojects { ... }`. ***Tidak dapat dieksekusi**langsung sebagai tugas buildSrc (misalnya,`gradle :buildSrc:reportTests`tidak akan berfungsi jika tugas tidak tercatat secara khusus dalam`buildSrc/build.gradle.kts`).`buildSrc`adalah modul kompilasi, bukan modul aplikasi yang dapat dieksekusi untuk tugas-tugas build utama.

\=== Menjalankan laporan untuk pengujian`buildSrc`sendiri

Si `buildSrc`Ia memiliki tesnya sendiri dan menghasilkan laporan, Anda dapat merekam tugas laporan langsung di`buildSrc/build.gradle.kts`:

## [source,kotlin]

plugins { `kotlin-jvm` }

repositori { mavenCentral() }

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

import com.yourpackage.ReportJbakeTestsTask // Impor kelas tugas Anda

## tasks.register\<ReportJbakeTestsTask\>("reportBuildSrcTests") { // Jalur sudah didefinisikan di kelas, akan menunjuk ke laporan buildSrc }

Anda kemudian dapat mengeksekusi :`./gradlew :buildSrc:test`diikuti oleh`./gradlew :buildSrc:reportBuildSrcTests`.

Dengan mengadopsi praktik ini, Anda akan membangun sistem build Gradle dengan Kotlin DSL yang tidak hanya kuat, tetapi juga sangat modular, mudah dipelihara, dan mudah dipahami.

Artikel terkait