Βελτιστοποίηση της Διαχείρισης Εργασιών Gradle με Kotlin DSL και buildSrc
Publié le 11 July 2025
Η αυτοματοποίηση των εργασιών κατασκευής είναι καθοριστική για κάθε λογισμικό έργο, και το Gradle, με το DSL Kotlin του, προσφέρει εξαιρετική ευελιξία. Κατά τη διάρκεια της συζήτησής μας, διερευνήσαμε πώς να κεντροποιήσουμε και να επαναχρησιμοποιήσουμε την λογική κατασκευής, ειδικά για τα αναφορές δοκιμής, εκμεταλλευόμενοι τοόλες οι έργα, buildSrc, και προσαρμοσμένες εργασίες στην Kotlin.
Κεντροποίηση των Διαμορφώσεων με allprojects και `subprojects
Τα μπλοκ`allprojects` et `subprojects`στο σας`build.gradle.kts`Η ρίζα είναι θεμελιώδης για την εφαρμογή κοινών διαμορφώσεων σε όλο το πολυ-μοναδικό σας έργο.
*allprojects { … }: Εφαρμόζει τη ρύθμιση στοτο ριζικό έργο και όλα τα υποέργα του. Ιδανικό για να ορίσετε ένα`group`, μ </think> , μ`version`, ή τις`repositories`κοινά. *subprojects { … }: Εφαρμόζει τη ρύθμισημόνο στους υποέργα, εκτός του ριζικού project. Ιδανικό για την εφαρμογή προσαρμοσμένων plugins για τα modules (όπως`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`Το σβιγκλιό της λογικής του Build
Όταν η λογική των εργασιών σας γίνεται πολύπλοκη ή πρέπει να επαναχρησιμοποιηθεί,buildSrcείναι η προτιμημένη λύση. Είναι ένα ειδικό module Gradle που μεταγλωττίζεται πριν τα κύρια scripts του build, καθιστώντας τις κλάσες του διαθέσιμες στο classpath του ολόκληρου του build σου.
Γιατί να χρησιμοποιήσετε;`buildSrc`για τις Εργασίες ?
-
Επαναχρησιμοποίηση: Μια εργασία που ορίζεται στο`buildSrc`μπορεί να εφαρμοστεί σε οποιοδήποτε project του build.
-
Οργάνωση: Κεντρίζει τον κώδικα κατασκευής, τον καθιστώντας πιο καθαρό και διατηρήσιμο.
-
Ασφάλεια Τύπου και Αυτοσυμπλήρωση: Ο κώδικας Kotlin στο`buildSrc`Είναι μεταγλωττισμένο, προσφέροντας τον έλεγχο σφαλμάτων και το autocompletion του IDE σας, βελτιώνοντας την εμπειρία ανάπτυξης.
\=== Διάγραμμα ροής`buildSrc`(Κώδικας PlantUML)
Για να δημιουργήσετε αυτό το διάγραμμα, antigrapse ton kwdika parakato kai epikolleste ton se ena ergaleio poyypostirizei to PlantUML.
[source,plantuml]
@startuml skinparam χειρογραφημένο αληθές skinparam monochrome true
rectangle "Gradle Build Process" { συστατικό "buildSrc" ως BS { αρχείο "MyCustomTask.kt" ως T file "MyConventionPlugin.kt" as P } συστατικό "Root Project" ως RP σταθερό "Subproject A" ως SA συστατικό "Subproject B" ως SB }
T --\> P : "ορίζεται σε P -→ RP : "εφαρμόζεται σε P --\> SA : "εφαρμόζεται σε P --\> SB : "εφαρμόζεται σε
RP --|\> SA : "περιέχει RP --|\> SB : "περιέχει
RP -up→ BS : "εξαρτάται από (για τη λογική κατασκευής) SA -up-\> BS : "εξαρτάται από (για τη λογική κατασκευής) SB -up-\> BS : "εξαρτάται από (για τη λογική χτίσης)
σημειώμα δεξιά του T Κλάσεις προσαρμοσμένων εργασιών (π.χ.: OpenTestReportTask) τέλος σημείωσης
σημειώνημα δεξιά του P Πλαγκιν σύμβασης οι καταγράφουν τις εργασίες τελική σημείωση
@enduml
\== Δημιουργία αβστράκτων εργασιών αναφοράς
Για να διαχειριστούμε τα αναφορές δοκιμών, σχεδιάσαμε μια μοデュλική προσέγγιση χρησιμοποιώντας μια αφηρημένη κλάση εργασίας σε`buildSrc`. Ανάλογα με τις ανάγκες σας, αυτή η κλάση μπορεί να κληρονομήσει`DefaultTask` ou de Exec.
\=== Αβστράκτη Εργασία`OpenTestReportTask`(κληρονόμενος από`DefaultTask`)
Αυτή η προσέγγιση συνιστάται αν χρειάζεστε μια προσαρμοσμένη λογική Kotlin που αλληλεπιδρά με το σύστημα αρχείων ή άλλες APIs του Gradle, και στη συνέχεια εκτελεί μια εξωτερική εντολή.
[source,kotlin]
package com.yourpackage
import org.gradle.api.DefaultTask εισαγωγή org.gradle.api.tasks.Input import org.gradle.api.tasks.TaskAction import java.io.File
καθαρή κλάση 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}")
}
----
## }
\=== Συγκεκριμένες υλοποιήσεις
Αυτές οι κλάσεις κληρονομούν από την αφηρημένη εργασία και προσδιορίζουν το συγκεκριμένο μονοπάτι της αναφοράς.
## [source,kotlin]
πακέτο com.yourpackage
abstract class ReportUnitTestsTask : OpenTestReportTask() { init { Άnoiγμα της αναφοράς ελέγχου μονάδας στο Firefox. reportPath = "build/reports/tests/test/index.html } }
package com.yourpackage
## abstract class ReportFunctionalTestsTask : OpenTestReportTask() { init { description = "Opens the functional test report in Firefox." reportPath = "build/reports/tests/functionalTest/index.html" } }
Καταγραφή των Εργασιών
Στον`build.gradle.kts`του ρίζα του έργου σας :
## [source,kotlin]
tasks.register<com.yourpackage.ReportUnitTestsTask>("reportTests") {} tasks.register<com.yourpackage.ReportFunctionalTestsTask>("reportFunctionalTests") {}
\=== UML διάγραμμα των εργασιών της αναφοράς (κώδικας PlantUML)
Αντιγράψτε τον κώδικα που βρίσκεται παρακάτω και επικολλήστε τον σε ένα εργαλείο που υποστηρίζει το PlantUML.
## [source,plantuml]
@startuml skinparam χειρόγραφο true skinparam μονοχρωמטικό αληθές
κλάση αφαίρεσης DefaultTask { }
άβαρη κλάση Exec { \+ commandLine(args: String...) \+ exec() }
αφηρετική κλάση OpenTestReportTask εκτείνει DefaultTask { \+ group: String = "επαλήθευση \+ περιγραφή: Συμβολο sequência? Wait I wrote Σ? Let's correct: "Συμβολοσειρά"
Final:
</think>
\+ περιγραφή: Συμβολοσειρά \+ dependsOn("check") \+ συνοψη reportPath: String \+ openReport() : void }
αφηρημένη κλάση AbstractJbakeExecTask επέκταση Exec { + ομάδα: String = "επαλήθευση \+ description: String \+ dependsOn("check") + abstract reportRelativePath: String \+ exec() : κενό }
class ReportUnitTestsTask extends OpenTestReportTask { \+ reportPath: String = "build/reports/tests/test/index.html }
κλάση ReportFunctionalTestsTask επεκτείνει 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 Εκτέλεση \<|-- AbstractJbakeExecTask DefaultTask \<|-- Exec
## @enduml
\== αβστrakτική εργασία`AbstractJbakeExecTask`(κληρονόμενος από`Exec`)
Αν η εργασία σας συνιστά κυρίως στην εκτέλεση μιας εξωτερικής εντολής με μεταβλητά ορίσματα, κληρονομείτε άμεσα από**Exec**είναι πιο άμεσο.
## [source,kotlin]
πακέτο 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 }
## }
\=== Συγκριμένες υλοποιήσεις για`Exec`
## [source,kotlin]
package com.yourpackage
abstract class ReportJbakeTestsTask : AbstractJbakeExecTask() { αρχικοποίηση { description = "Άνοιγμα της αναφοράς δοκιμών μονάδας Jbake στο Firefox. reportRelativePath = "build/reports/tests/test/index.html } }
πακέτο com.yourpackage
## abstract class ReportJbakeFunctionalTestsTask : AbstractJbakeExecTask() { init { description = "Ανοίγει την αναφορά των λειτουργικών δοκιμών στο Firefox." reportRelativePath = "build/reports/tests/functionalTest/index.html" } }
\== Ορατότητα των Εργασιών`buildSrc`
Οι εργασίες και οι κλάσεις που καθορίζετε σε**buildSrc**είναι :
***όρατα και χρησιμοποιήσιμα**γι' όλα τα έργα της κύριας κατασκευής σας (ρίζα και υπο-έργα). Για αυτό μπορείτε να χρησιμοποιήσετε`com.yourpackage.ReportUnitTestsTask`σε`allprojects { ... }`. ***Μη εκτελέσιμα**ευθείας ως εργασίες του buildSrc (για παράδειγμα,`gradle :buildSrc:reportTests`Δεν θα λειτουργούσε εάν η εργασία δεν καταγραφεί συγκεκριμένα στην`buildSrc/build.gradle.kts`).`buildSrc`είναι ένα module σύνθεσης, όχι ένα εκτελέσιμο module εφαρμογής για αυτές τις εργασίες του κύριου build.
\=== Εκτέλεση αναφοράς για τα τεστ του`buildSrc`τον εαυτό του
Si `buildSrc`έχει τα δικά του test και παράγει αναφορές, μπορείτε να καταχωρήσετε μια εργασία αναφοράς κατευθείαν στο`buildSrc/build.gradle.kts`(No output, as the input text to translate is empty)
## [πηγή,kotlin]
π러γκινς { `kotlin-jvm` }
repositories { mavenCentral() }
tasks.withType\<Test\> { useJUnitPlatform() reports.html.outputLocation.set(layout.buildDirectory.dir("reports/tests")) }
import com.yourpackage.ReportJbakeTestsTask // Εισάγετε την κλάση εργασίας σας
tasks.register<ReportJbakeTestsTask>("reportBuildSrcTests") { // Le chemin est déjà défini dans la classe, il pointera vers les rapports de buildSrc }
Θα μπορείτε να εκτελέσετε:`./gradlew :buildSrc:test`ακολουθούμενο από`./gradlew :buildSrc:reportBuildSrcTests`.
Αποδέχοντες αυτές τις πρακτικές, θα δημιουργήσετε συστήματα κατασκευής Gradle σε Kotlin DSL που είναι όχι μόνο ισχυρά, αλλά και έξυπνα, μοναδικά, συντηρήσιμα και εύκολα να κατανοηθούν.