Plugin Indépendant + Racine Consommateur » آرکیٹیکچر: میرے Gradle Builds کیوں دوہرا ہو رہے ہیں
شائع شدہ: 14 May 2026
- مسلّہ : تین معمارتیں جنہوں نے مجھے وقت ضائع کر دیا
- حل: دو مستقل بیلڈز، صرفی
- کیوں یہ معمارتی نے مجھے جیت لیا؟
- سب فولڈر
{name}-plugin/کی تشریح - جو ہم نہیں کرتے
- مقایسه : تین معمارتیں Dogfooding کے مقابلے میں
- DAG معاہدہ: ایک بنڈ جڑ کبھی زیر فائلیڈر سے آتا نہیں
- نتیجہ : ظاہر کردہ ڈپلیکیج جو وقت بچاتا ہے
- حوالہ جات
آپ ایک گرائیڈل پلاگِن ریپوزٹری کلون کر رہے ہیں۔ آپ ایک ٹرمنل کھول رہے ہیں۔ آپ کیا ٹائپ کر رہے ہیں؟ پھر؟./gradlew tasks, بالکل. لیکن کون سا فولڈر؟ جڑ؟ سب‑ماڈیول؟ کیا پہلے ایک README پڑھنا چاہیے تاکہ بنانے کے طریقے کا علم ہو؟ اگر آپ جھجکاتے ہیں تو کیا یہ نہیں ہوگا؟ ایک سیکنڈ میں، پروجیکٹ کی مِعماری ٹوٹ گئی ہے۔
یہ ہے کہ میں اس مسئلے کو ایک بار لیے سب کے لئے حل کیا — اور کیون یہ پターن آج میرے تمام گریڈل پلاگنز کی شناخت میں`foundry/public/`.
مسلّہ : تین معمارتیں جنہوں نے مجھے وقت ضائع کر دیا
موجودہ پٹرن تک پہنچنے سے پہلے، میں تین طریقوں کے درمیان ڈھونڈ رہا تھا کلاسیک طریقے جن سے گریڈیل پلاگن کو منظم کیا جاتا تھا۔ ہر ایک کا ایک قاتل عیب۔
اختیار 1: ایسولیٹڈ پلاگین (dogfooding نہیں)
پروژکٹ صرف پلاگ‑ن ہی شامل ہے۔ استعمال کی کوئی مثال نہیں۔ کوئی پروجیکٹ جو اسے استعمال کرتا ہے۔ اسے ٹیسٹ کرنے کے لیے، ایک بیرونی پروجيٹ بنانا پڑتا ہے، y پلاگین کو ذریعے رجح کریں`mavenLocal`یا ایک کمپوزٹ بنڈ، اور صرف یہاں جانچ کریں کہ یہ چل رہا ہے۔
$ git clone mon-plugin
$ cd mon-plugin
$ ./gradlew build # le plugin compile
$ # ... et maintenant ? comment je l'essaie ?
|
گریڈیل پلاگائن جس میں استعمال کا کوئی مثال نہیں، ایک کتابخانه جس میں انٹیگریشن ٹیسٹس. آپ کبھی نہیں جانتے کہ آخری تبدیلی صارف کے تجربے کو خراب کر دیا |
اختیار 2 : کلاسیک مونوریپو (include(":plugin"))
گریڈل`init`پیدا کرتا ہے`settings.gradle.kts`ساتھ`include("plugin")`. رُوٹ اور سب-ماڈیول ایک ہی ڈیمون اور ایک ہی کنفیگریشنز کو شیئر کرتے ہیں، یہے catalogue۔ مفید، لیکن جوڑا ہوا۔
.
├── settings.gradle.kts → include("plugin")
├── build.gradle.kts → plugins { id("mon-plugin") }
├── plugin/
│ └── build.gradle.kts → java-gradle-plugin
└── gradle/
└── libs.versions.toml
رکاوٹ :
-
جڑچاہیےGradle کی وہی ورژن رکھنا جس ورژن کا سب ماڈول استعمال کرتا ہے۔
-
`libs.versions.toml`ہے شیئر — ورژن کیٹالوگس مشترک، انحصاریات
جinho ایک مाडول سے دوسرے ماضول تک بھتے ہیں
-
پلاگن کو جڑ سے مستقل طور پر بنانا ممکن نہیں۔
-
سی آئی کو دونوں ماڈیول بنانے ہیں، اگرچہ صرف پلاگین بدل گیا ہے۔
اختیار 3 : کامپوزٹ بيلڈ (includeBuild())
ہم ان دو چیزوں کو الگ الگ Gradle بنڈس میں علیحدہ کرتے ہیں اور انہیں اس کے ذریعے جوڑتے ہیں includeBuild("mon-plugin")`میں`settings.gradle.kts.
یہ پہلے سے بہتر ہے۔ پلاگ ان کا بِلڈ الگ ہو گیا ہے۔ لیکن صارف اس کو واضح طور پر بیرونی ڈیلڈ کا حوالہ دینا چاہیے — اور اس کا آؤٹ پوٹ `./gradlew tasks`جذور کی درست تنظیم پر انحصار کرتا ہے مکمل. کلوننگ صفر کانفیگریشن نہیں ہے: جاننا ضروری ہے کہ پلاگ ان الگ فاؤلڈر میں ہے، جو روت اس کی حوالہ دیتا ہے، او غیر۔
.
├── settings.gradle.kts → includeBuild("plugin-build/")
├── build.gradle.kts → plugins { id("mon-plugin") }
└── plugin-build/
├── settings.gradle.kts
└── build.gradle.kts
میں بہتر کی تلاش کر رہا تھا۔ بہت بہتر۔
حل: دو مستقل بیلڈز، صرفی
یہ وہ پٹرن ہے جو میں نے سرانجام میں اپنا لیا :
.
├── settings.gradle.kts ← racine consommateur
├── build.gradle.kts ← 3 lignes : apply plugin + dogfood
├── gradle/
│ └── libs.versions.toml ← catalogue du consommateur
├── {name}-plugin/ ← BUILD INDÉPENDANT
│ ├── gradlew ← son propre wrapper
│ ├── settings.gradle.kts ← rootProject.name = "{name}-plugin"
│ ├── build.gradle.kts ← java-gradle-plugin, signing, publish
│ ├── gradle/
│ │ ├── libs.versions.toml ← catalogue du plugin
│ │ └── wrapper/
│ ├── src/ ← sources du plugin
│ ├── .agents/ ← gouvernance agent
│ └── *.adoc ← AGENT, PROMPT_REPRISE, snapshot, etc.
└── site.yml / slides-context.yml / ... ← configs dogfood
|
چابی :`{name}-plugin/`ہے ایک پروجیکٹ گریڈیل مکمل اور خودمختار. اس کا apna wrapper، اس کا apna settings، اس کا apna catalogue کا نسخہ. یہ خود کو کلون کرتا ہے، خود کو بناتا ہے، خود کو آزماتا ہے اور خود کو شائع کرتا ہے، رُوت کے بغیر اس کی وجود کا علم رکھو |
رُوٹ، وہ صرف ایک کام کرتا ہے: پلاگین لاگو کریں۔
plugins {
alias(libs.plugins.bakery)
}
repositories {
mavenLocal()
mavenCentral()
}
bakery { configPath = file("site.yml").absolutePath }
تین سطر کے لیے`bakery-gradle`. اور کچھ نہیں. صفر`include(), صفر`includeBuild(), صفر زیرپروجیکٹ ایک کلاسیک Gradle build jo ایک plugin لاگو کرتا ہے جسے کوئی بھی کِسے/sp?
کام کا عمل
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontSize 12
left to right direction
package "RACINE (صارف)" #CCFFCC {
usecase "ریپوزٹری کلون کریں" as Clone
usecase "`./gradlew tasks`" as Tasks
usecase "`./gradlew bake`" as Dogfood
note bottom of Dogfood
پلگ ان چلائیں
فوری فیڈ بیک
زیرو کنفیگریشن
end note
}
package "`{name}-plugin/` (آزاد بلڈ)" #CCE5FF {
usecase "`./gradlew build`" as BuildPlugin
usecase "`./gradlew publishToMavenLocal`" as MavenLocal
usecase "`./gradlew test`" as TestPlugin
note bottom of BuildPlugin
علیحدہ لائف سائیکل
یونٹ ٹیسٹ + Cucumber
مخصوص CI ممکن ہے
end note
}
Clone -down-> Tasks
Tasks -down-> Dogfood
Dogfood ..> MavenLocal : "مقامی طور پر شائع شدہ\nپلگ ان پر منحصر ہے"
BuildPlugin -up-> MavenLocal
TestPlugin -up-> BuildPlugin
@enduml
ملموس ورکفلو
# 1. Builder le plugin
$ cd codebase-plugin
$ ./gradlew publishToMavenLocal
# 2. L'exercer depuis la racine
$ cd ..
$ ./gradlew indexCodebase queryCodebase snapshot
# La boucle est fermée. Le plugin est testé dans des conditions
# réelles de consommation, par le projet même qui l'héberge.
کیوں یہ معمارتی نے مجھے جیت لیا؟
تین فائدے جو، مل کر، « ڈپلیکیشن» کی لاگت کے برابر ہیں :
نایٹیو ڈاگ فودنگ، فوری فیڈبیک
گریڈیل پلاگین کا بہترین ٹیسٹ اس کا استعمال کرنا ہے۔ مockeڈ یونٹ ٹیسٹ نہیں. نہیں ایک`GradleRunner`ایک پروجیکٹ کے ساتھ ٹیسٹ کا۔ ایک سچ بِلڈ جو پلاگ‑إن لاگو کرتا ہے سچ فائلهوں پر
$ git clone bakery-gradle
$ cd bakery-gradle
$ ./gradlew bake # ← le plugin est exercé immédiatement
اگر پلاگین ٹوٹا ہے، جڑ بناؤ اسے کہتا ہے۔ جنے کی ضرورت نہیں۔ باہری ٹیسٹ پروجیکٹ ڈھونڈنا۔ ڈگ فُڈنگ پہلا ہے۔ ایک نئے مشارکت کنندہ کی لانس کرنے والی ٹاسک۔ یہ آخری سموک ٹیسٹ ہے۔
|
قاعدہ سادہ ہے: اگر جڑ کامپائل ہوتی ہے اور`./gradlew tasks` دکھاتا ہے آپ کے پلاگین کے کام، پلاگین فعال ہے۔ کوئی تعجب نہیں پروڈکشن میں. |
2. زیرو-کنفیگ کلوننگ
Un `git clone && ./gradlew tasks`اور نئے داخلہ کرنے والا سب کچھ دیکھتا ہے کوئی شيء کنفیجر کیے بغیر چلنا۔ ال`build.gradle.kts`جڑ ہے پلاگین ka Installation ka zombie documentation`site.yml`کے ساتھ متوقع کنفیگری دکھاتا ہے.
الیکسج کے ساتھ متقابل کریں : تین پاراگرافوں کا ایک README جس میں وضاحت کریں builder پلاگین کیسے بنائیں اور builder پروژیکٹ کیسے بنائیں ٹیسٹ کا۔ ایک نیا مشارکت کنندہ README کو ڈائیگونل طور پر پڑھتا ہے, غلط کرتا ہے، ایک اشو کھولتا ہے — جہاں کے ملومات ہو سکتا ہے ہونا قابلِ eseguibile.
|
سب سے مضبوط دستاویزات وہ نہیں ہے جو پڑھی جاتی ہے. یہ وہ ہے جو ہمنفذ. جڑ بنائی وثائق ہے پلاگ اِن کا قابلِ esegu. |
3. منافذ بنائیں، مستقل CI
پلاگ ان کا خود کا گریڈیل وریپر ہے، خود کا زندگی کا دور ہے، اپنے ٹیسٹس. آپ سکتے ہیں:
-
پلاگن میں Gradle کو اپ گریڈ کریں، جڑ کو چھوئے بغیر
-
پلاگین میں ایک انحصار شامل کریں تاکہ وہ روت میں لیک نہ ہو
-
پلاگین کو ٹوٹنا بنیادی بنڈ پر اثر ڈالے بغیر (جس وقت آپ
ٹوٹا ہوا نسخہ شائع نہ کریں)
-
ایک CI رکھنا جو پلاگائن کو build/test کرے، اور دوسری جو اسے استعمال کرے
root — مستقل
.github/workflows/
├── test-plugin.yml → codebase-plugin/.gradlew build
├── test-root.yml → .gradlew tasks (vérifie que le plugin est consommable)
└── publish.yml → codebase-plugin/.gradlew publish
سب فولڈر {name}-plugin/ کی تشریح
چلو نزدیک سے دیکھیں جو پلاگین کا فولڈر میں موجود ہے :
codebase-plugin/
├── gradlew ← wrapper indépendant
├── settings.gradle.kts ← @Suppress("UnstableApiUsage")
│ + foobar-resolver-convention
├── build.gradle.kts ← java-gradle-plugin + signing + publish
├── gradle/
│ ├── libs.versions.toml ← catalogue complet (langchain4j, pgvector...)
│ └── wrapper/
├── buildSrc/ ← classes utilitaires buildSrc
│ ├── build.gradle.kts
│ └── src/main/kotlin/
│ ├── codebase/ ← CodebaseYmlAnonymizer, CodebaseConfiguration
│ ├── benchmark/ ← BenchmarkConfig, BenchmarkProtocol
│ ├── readme/ ← ReadmeYmlAnonymizer
│ ├── site/ ← SiteYmlAnonymizer
│ ├── slider/ ← SliderYmlAnonymizer
│ └── snapshot/ ← SnapshotManager
├── src/
│ ├── main/kotlin/codebase/
│ │ ├── CodebasePlugin.kt ← class Plugin<Project>
│ │ ├── rag/ ← pgvector, embedding, anonymization...
│ │ ├── benchmark/ ← BenchmarkRunner, export, comparison...
│ │ └── walker/ ← WorkspaceWalker
│ └── test/
│ ├── kotlin/codebase/scenarios/ ← steps Cucumber
│ ├── features/ ← .feature files
│ └── resources/datasets/ ← fixtures .adoc, .yml, .json
├── .agents/ ← gouvernance agent (INDEX, SESSIONS, etc.)
├── AGENT.adoc ← règles agent
├── PROMPT_REPRISE.adoc ← mission session
├── BACKLOG.adoc ← backlog produit
├── snapshot.adoc ← snapshot auto-généré du projet
└── embeds.yml ← config RAG embeds
سب وہاں ہے۔ جڑ اور سب فولدروں کے درمیان کوئی تفرق نہیں۔ پلاگ ان پر کام کرنے والا ڈویلپر کبھی ضرورت نہیں چھوڑنا`codebase-plugin/`. پلاگین استعمال کرنے والا ڈویلپر وہ صرف جڑ پر ہی غور کرتا ہے — اور اس کے`build.gradle.kts`۳ لائنیں کا وہ اسے سب کچھ جو اسے جاننا چاہیے بتاتا ہے
ویژن کا کیٹالوگ : دو مختلف فائلیں
|
|
|
انحصارات کی تعداد |
2-3 (پلاگین + ریڈمی اختیاری طور پر) |
30+ (langchain4j, pgvector, cucumber…) |
کردار |
پلاگن کو استعمال کرنے |
پلاگ ان بنائیں |
کون اس کو پڑھتا ہے |
پلاگ ان کا صارف |
پلاگین کے ڈویلپر |
Root کا volontairement minimal catalogue ہے. Plug‑in کا catalogue ہے. مکمل. بھول mumkin نہیں: ہر بِلڈ کا اپنا مخصوص سكوپ ہوتا ہے اعتمادات کا.
|
اگر آپ ایک گھنٹہ ڈپینڈینسیز کے تصادم کا ڈیبگ کر رہے ہیں آپ کے پلاگین اور آپ کے ٹیسٹ پراجیکٹ کے درمیان، آپ کی قدر سمجھتے ہیں یہ علیحدگی۔ مستقل کٹالوگوں یہ مسئلے کو دور کرتے ہیں بناوٹ کے طور پر |
جو ہم نہیں کرتے
یہ پیٹرن جادویی نہیں ہے۔ یہ ایک پابندی لاتا ہے میں وہ مجھ پر خوشی سے سزا دیتا :
root پلاگین بناتا نہیں۔ آپ کو`publishToMavenLocal` ou اس ریپوزیٹری پر ڈپلائ کریں، جب تک ر اسے استعمال کر sake.
یہ ایک کم لاگت ہے، اور یہ اچھی محدودیت ہے۔ جڑ پلاگین Maven کےziiریے بیرونی کلائنٹ کی طرح استعمال کرتا ہے. بالضبط جس طرح ایک تیسرے طرف کا پروجيکٹ کرتا ہے۔ اگر پلاگن شائع نہیں ہو سکتا، جڑ آپ کو فوراً بتاتا ہے۔
# La seule "friction" du pattern
$ cd codebase-plugin && ./gradlew publishToMavenLocal && cd ..
$ ./gradlew tasks --group=codebase
مقایسه : تین معمارتیں Dogfooding کے مقابلے میں
الگ پلاگائن |
ایک ریپوزٹری`include()` |
مرکب`includeBuild()` |
جڑ + مستقل پلاگین. |
|
`git clone && gradlew tasks`پلاگین کے کام دیتا ہے |
❌ |
(empty) |
آپ ایک حرفیش ترجمان ہیں۔ فرانسے سے اردو میں ترجمہ کریں۔ تمام بیک ٹیک کوڈ اسپین ( |
✅ |
جذر سے مستقل پلاگ ان بنائیں |
(blank) |
❌ |
✅ |
✅ |
الگ کیٹالوج ورژن |
✅ |
❌ |
✅ |
✅ |
نہیں`include()` ni |
✅ |
❌ |
❌ |
✅ |
محلی Dogfood بے کنفیگ |
❌ |
[No source text provided; nothing to translate.] |
⚠️ |
✅ |
CI plugin مستقل |
✅ |
❌ |
✅ |
✅ |
جڑ ایک واقعی استعمال کا مثال ہے |
❌ |
⚠️ |
✅ |
✅ |
دایں کالم تمام خانچوں کو چیک کرتی ہے. اسی لیے کہ میں میں زیادہ پیچھے جاؤں گا۔
DAG معاہدہ: ایک بنڈ جڑ کبھی زیر فائلیڈر سے آتا نہیں
یہ معماری DAG N0→N3 میں طبیعتی طور پر مل جاتی ہے میرے workspace کا. پٹرن یہ ہے: پلگ N2 hub ہے اپنی خود کی عارضوں سے، N3 جڑ ایک ٹرمینل ہے جو hubs لگاتا ہے
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontSize 11
title DAG معاہدہ — Racine Consommateur بمقابلہ Plugin Indépendant
package "N3 — RACINE (دپوزٹ)" #FFCCCC {
[build.gradle.kts (3 lignes)] as ROOT
[libs.versions.toml (minimal)] as ROOT_TOML
note right of ROOT
plugins { bakery }
bakery { configPath = ... }
کوئی بزنس لاجک نہیں
end note
}
package "N2 — {name}-plugin/" #CCFFCC {
[build.gradle.kts (complet)] as PLUGIN
[src/main/kotlin/] as SRC
[gradle/libs.versions.toml] as PLUGIN_TOML
[buildSrc/] as BUILDSRC
note bottom of PLUGIN
java-gradle-plugin
سائننگ + پبلش
یونٹ ٹیسٹس + Cucumber
مخصوص CI
end note
}
ROOT_TOML --> ROOT : "plugin ورژن"
ROOT -down-> PLUGIN : "publishToMavenLocal"
@enduml
Le codebase-gradle/build.gradle.kts`6 خطوط بناتا ہے۔ نہیں`src/, نہیں`buildSrc/, نہیں`gradle/rag-bench.gradle.kts. منصفانہ plugins { alias(libs.plugins.codebase) }`اور ریپوزٹریز. تمام پیچیدگی میں موجود ہے`codebase-plugin/.
نتیجہ : ظاہر کردہ ڈپلیکیج جو وقت بچاتا ہے
جب میں اس ساخت کو کسی کو دکھاتا ہوں، پہلا ردعمل اکثر یہ ہوتا ہے : « تم کے دو`gradlew`, دو`settings.gradle.kts`, دو`libs.versions.toml`— یہ نقل ہے !
ہاں۔ اور نہیں۔
ڈپلیکیشن » کا مطلب ہے ایک ہی معلومات کو دو جگہوں پر بنانا۔ یہاں، یہ دو مختلف فائل ہیں جو دو مختلف مقاصد کے لیے ہیں : پلاگ ان کا کیٹالوج (30+ انحصارات بِلڈر کے لیے) اور کیٹالوج جڑ سے (2-3 انحصارات استعمال کرنے کے لیے). پلاگین کا ورےپر (ترقی کے لیے قفل شدہ ورژن) اور جڑ کا واپر (امکان پر مختلف ورژن، پلاگن کے مشق کے لیے).
یہ ڈپلیکیشن نہیں ہے۔ یہ الگ کرنے کا ذمہ داریاں بیلڈ نظام پر لاگو. ہر بیلڈ ایک چیز کرتا ہے، اور صرف ایک۔ جڑ استعمال کرتی ہے۔ پلاگین خود بنتا ہے۔
لاگت؟ ایک آرڈر`publishToMavenLocal`پلاگین کے بیلڈ کے درمیان اور جڑ کا بیلڈ۔ فائدہ؟ معمارتی صفائی جو ڈاؤن اسٹریم ڈیبگنگ کے گھنٹے بچاتا ہے
میں اس نمونے کو ڈپلوائی کرنے کے بعد سے`bakery-gradle`, plantuml-gradle, codebase-gradle, اور دیگر پلاگینوں کا`foundry/public/, میں نہیں کبھی نہیں جھجھکا ایک ٹرمنل کھلتے وقت میں میرے ایک ریپوزٹری. پہلا انعکاس —./gradlew tasks`— ہمیشہ چلتا ہے، ہمیشہ دیتا ہے اچھی کاروں، اور وہ فوراً بتا دیتا ہے کہ ہر چیز صحت مند ہے۔
یہ درست معماری ہے۔ اسے README میں نہیں پڑھا جاتا۔ یہ ٹرمینل میں das sekoond se kam waqt mein آزمائش ہوتی ہے۔
حوالہ جات
-
ماده 0117 — OSS/CSS کی گرانیولائزیشن