TDD ενός προσαρμόσιμου plugin Gradle Kotlin με JBake και JGit
Publié le 09 July 2025
Αυτό το άρθρο παρουσιάζει τη πλήρη διαδικασία σχεδίασης και δοκιμών (TDD) ενός plugin Gradle γραμμένου σε Kotlin DSL. Αυτό το plugin αυτοματοποιεί τη δημιουργία στατικών ιστότοπων με το JBake και τη διαδικασία ανάπτυξης Git μέσω του JGit, όλα από ένα αρχείο YAML ρυθμίσεων.
Στόχος
Δημιουργήστε ένα πρόσθετό Gradle:
-
ρυθμίσιμο σε Kotlin DSL ;
-
Μπορεί να :
-
δημιουργήστε ένα στατικό ιστότοπο από το JBake ;
-
ανάπτυξη σε ένα απομακρυσμένο αποθετήριο Git μέσω JGit ;
-
συμβατός με ένα workflow CI/CD;
-
ελεγμένο σύμφωνα με μια προσέγγιση TDD.
Δηλωτική Διαμόρφωση
Αυτό είναι ένα παράδειγμα ρύθμισης YAML που θα μοντελοποιηθεί στον DSL μας :
bake:
srcPath: "./site/jbake"
destDirPath: "bake"
pushPage:
from: "bake"
to: "cvs"
repo:
name: "trainings"
repository: "https://github.com/pages-content/trainings.git"
credentials:
username: "USERNAME"
password: "SECRET_TOKEN"
branch: "main"
message: "cheroliv.com"
Αυτή η ρύθμιση παρουσιάζεται μέσω μιας επέκτασης Gradle που είναι δηλώσιμη σε Kotlin DSL.
Αρχιτεκτονική του plugin
Ορισμός της επέκτασης DSL
open class WorkspaceEngineExtension {
var outputDir: String = "build/site"
var template: String = "freemarker"
var repoUrl: String = ""
var branch: String = "main"
var message: String = "Generated by engine"
}
Ορισμός προσαρμοσμένης εργασίας
abstract class GenerateSiteTask : DefaultTask() {
lateinit var gitAdapter: GitAdapter
@get:Input abstract val repoUrl: Property<String>
@get:InputDirectory abstract val outputDir: DirectoryProperty
@get:Input abstract val branch: Property<String>
@get:Input abstract val message: Property<String>
@TaskAction
fun run() {
val repo = gitAdapter.cloneRepository(repoUrl.get(), outputDir.get().asFile)
gitAdapter.commitAndPush(repo, branch.get(), message.get())
}
}
Διεπαφή GitAdapter
interface GitAdapter {
fun cloneRepository(uri: String, directory: File): Repository
fun commitAndPush(repo: Repository, branch: String, message: String)
}
Συγκεκριμένη υλοποίηση με το JGit
class JGitAdapter : GitAdapter {
override fun cloneRepository(uri: String, directory: File): Repository {
return Git.cloneRepository()
.setURI(uri)
.setDirectory(directory)
.call()
.repository
}
override fun commitAndPush(repo: Repository, branch: String, message: String) {
Git(repo).use {
it.add().addFilepattern(".").call()
it.commit().setMessage(message).call()
it.push().call()
}
}
}
Διαμόρφωση DSL Kotlin
workspaceEngine {
outputDir = "build/out"
template = "freemarker"
repoUrl = "https://github.com/cheroliv/trainings.git"
branch = "main"
message = "deploy from plugin"
}
Μονάδες δοκιμών με Mockito
εξαρτήσεις
testImplementation("org.mockito:mockito-core:5.12.0")
testImplementation("org.mockito.kotlin:mockito-kotlin:5.2.1")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
Δοκιμή της συμπεριφοράς του Git
class GenerateSiteTaskMockitoTest {
@TempDir
lateinit var tempDir: File
@Test
fun `task should call clone and commitAndPush`() {
val project = ProjectBuilder.builder().build()
val task = project.tasks.create("generateSite", GenerateSiteTask::class.java)
val mockGitAdapter = mock<GitAdapter>()
val mockRepo = mock<Repository>()
whenever(mockGitAdapter.cloneRepository(any(), any())).thenReturn(mockRepo)
task.gitAdapter = mockGitAdapter
task.repoUrl.set("https://github.com/cheroliv/test.git")
task.outputDir.set(project.layout.projectDirectory.dir(tempDir.name))
task.branch.set("main")
task.message.set("test commit")
task.run()
verify(mockGitAdapter).cloneRepository(eq("https://github.com/cheroliv/test.git"), any())
verify(mockGitAdapter).commitAndPush(eq(mockRepo), eq("main"), eq("test commit"))
}
}
Συμπέρασμα
Η διαχωρισμός των ευθυνών μέσω`GitAdapter`επιτρέπει την πλήρη εφαρμογή του TDD στην ανάπτυξη προσθέτων Gradle :
-
Οι κλήσεις Git είναι αφηρημένες και δοκιμάσιμες;
-
Η ρύθμιση DSL είναι καθαρή και σαφής;
-
το plugin παραμένει αγνωστικό της πραγματικής υλοποίησης.
Αυτή η προσέγγιση εξασφαλίζει υψηλή δοκιμασιμότητα και επεκτασιμότητα (π.χ. GitHub API, GitLab, κλπ.).
Επόμενα βήματα
-
Ενσωμάτωση της γεννήσης JBake ως ένα`BakeAdapter`
-
Προσθέστε δοκιμές ενσωμάτωσης με`GradleRunner`
-
Υποστήριξη αυτόματης φόρτωσης αρχείων`site.yml`Μέσω SnakeYAML