ÖNEMLİ : Kendim için aldığım notlar. Umarım size de bir faydası olur. Bu yazı Jendrik Johannes’in Gradle’ı Anlamak İsimli Youtube içeriklerinin bir çevirisidir ve yazarın izni alınarak paylaşılmaktadır. Amacım hem aldığım notları sizinle paylaşmak hem de bilmeyenler için Jendrik’i size tanıtmaktır. Jendrik’in Gradle ile ilgili çok değerli içeriklere sahip olduğunu düşünüyorum. Türkçe kaynağa destek olmak için bu çevirileri sizinle paylaşmak istedim. Aşağıdaki yazı Jendrik’in kendi cümleleri olup, sadece turuncu blok içerisinde öne çıkardığım notlar bana aittir. Referanslara ise sayfa sonundan ulaşabilirsiniz.

Serinin Diğer İçerikleri:


Diğer içerikleri görüntülemek için linke tıklayın.

SIFIRDAN BİR GRADLE PROJESİ BAŞLATMAK - SETTINGS DOSYASI

Yeni bir gradle projesi oluşturmak için yapmamız gereken şey, ilk olarak boş bir klasör oluşturmak ve bu klasör içine ya settings.gradle dosyası ya da settings.gradle.kts dosyası yerleştirmektir. Bu bir gradle projesinin beyanı için yeterlidir.

Benim Notum: settings dosyası, her Gradle build’in giriş noktasıdır. 1

Bilmemiz ve hatırlamamız gereken 3 şey vardır.

1 - Gradle build’nizi adlandırın


1
rootProject.name = "my-project"

Benim Notum:


Bunun uzun yazımı şu şekildedir.

1
settings.rootProject.name = "root"

Birinci olarak rootProject.name özelliğini kullanarak projenize sabit bir isim vermelisiniz.

gradle'ı anlamak (understanding gradle)


2 - Gradle için, build’inizin bağlı olabileceği bileşenlerin konumlarını tanımlamaktır


İkinci olarak, Gradle’ın, build’inizin bağlı olabileceği diğer bileşenleri arayabileceği konumları tanımlayabilirsiniz. Bunlar, maven central gibi binary depolar (repositories) veya gradle’ın talep üzerine bileşenler oluşturmak için kullanabileceği diğer gradle build’ler olabilir.

Build’nizin bağlı olabileceği temelde iki farklı şeyin olduğunun farkına varmak önemlidir.

2.1 - Kütüphaneler (libraries) için diğer build’lerin depoları (repositories) ve lokasyonları


İlk şey, üretim (production) kodunuzun ihtiyaç duyabileceği kütüphanelerdir. Örneğin bir apache commons kütüphanesi gibi.

1
2
3
4
5
6
7
8
rootProject.name = "my-project"

dependencyResolutionManagement {
    repositories {
        mavenCentral()
    }
    includeBuild("../my-other-project")
}

Benim Notum:


dependencyResolutionManagement: tüm projeler için build’deki bağımlılık çözümlemesinin yapılandırılmasına izin verir. Yani tek tek build.gradle veyahut build.gradle.kts içinde repositories{} aracılığıyla bağımlılık çözümlemesi yapmak yerine; örneğin;

build.gradle.kts

1
2
3
4
5
6
7
8
9
10
11
12
13
plugins {
    `java-library`
}

repositories { 
    google() 
    mavenCentral()
}

dependencies { 
    implementation("com.google.guava:guava:32.1.2-jre") 
    testImplementation("junit:junit:4.13.2")
}

bütün projeler için aynı bağımlılık çözümlemesini settings.gradle veyahut settings.gradle.kts içinde dependencyResolutionManagement ile yapabiliriz. 2

settings.gradle.kts

1
2
3
4
5
dependencyResolutionManagement {
    repositories {
        mavenCentral()
    }
}

Bir diğer bilinmesi gereken şey ise şudur: Varsayılan olarak, build.gradle(.kts) içindeki bir proje tarafından bildirilen depolar(repositories), settings.gradle(.kts)‘de bildirilen her şeyi geçersiz kılacaktır:

settings.gradle.kts

1
2
3
dependencyResolutionManagement {
    repositoriesMode = RepositoriesMode.PREFER_PROJECT
}
gradle'ı anlamak (understanding gradle)


2.2 - Gradle eklentileri (plugin) için diğer build’lerin depoları (repositories) ve lokasyonları


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
rootProject.name = "my-project"

pluginManagement{
    repositories {
        gradlePluginPortal() // Artifact Repository
        google() // Maven Artifact Repository
    }
    includeBuild("../my-build-logic")
}

dependencyResolutionManagement {
    repositories {
        mavenCentral()
    }
    includeBuild("../my-other-project")
}

İkincisi ise gradle’ın kendisini genişleten eklentilerdir(plugin). Bunlar genellikle gradle eklenti(plugin) portalında bulunur. Ancak diğer binary(ikili) depolar aracılığıyla da sağlanabilir. Bunun yanı sıra, eklentileri diğer build’larda yerel olarak da tanımlayabilirsiniz.

gradle'ı anlamak (understanding gradle)


Benim Notum:


Burada pluginManagement{} kod bloğu içindeki includeBuild() 3, işaret edilen path’deki plugin build’ini composite build’a dahil eder. Benzer şekilde dependencyResolutionManagement kod bloğu içindeki includeBuild() 4 ise, işaret edilen path’deki build’i composite build’a dahil eder.

Bunun yanı sıra, “pluginManagement{}” bloğu yalnızca “settings.gradle(.kts)” dosyasında görünebilir; burada, dosyadaki veya bir “Initialization Script”‘deki ilk blok olmalıdır. 5

Bu arada Gradle topluluğunun çok projeli (multi-project) build yapıları için iki standardı vardır: bunlardan biri ìncludeBuild kullanan composite build, diğeri ise buildSrc kullanan Multi-Project Build‘lerdir.6

Multi-Project Build‘ler (yani buildSrc), projeleri birçok modülle düzenlemenize, bu modüller arasındaki bağlılıkları bağlamanıza ve bunlar arasında ortak yapı mantığını (build logic) kolayca paylaşmanıza olanak tanır. included builds olarak da adlandırılan Composite Build‘ler, build’ler (alt projeler değil) arasında mantığı (logic) paylaşmak veya paylaşılan yapı mantığına (build logic) erişimi izole etmek (yani, convention plugin’ler) için en iyisidir.

Bu arada Gradle, modülleri alt projeler (sub-projects) olarak ifade eder.

Jendrik’e göre pluginManagement & dependencyResolutionManagement Blokları Arasındaki Fark?

Bu, Gradle’ın Java uygulamaları oluşturmak için kullanılmasının yanı sıra aynı zamanda bir Java uygulaması (yazılım oluşturmak için bir uygulama) olmasından kaynaklanan yaygın bir kafa karışıklığıdır.

  • dependencyResolutionManagement repositories” öncelikli endişeniz olmalıdır. Bu, uygulamanıza entegre etmek istediğiniz bileşenlere hizmet veren repo’ları bildirmek içindir. Örneğin, “mavenCentral()” tarafından sunulan “org.Apache.commons:commons-lang3:3.14.0” kullanmak istiyorsunuz. Başka bir deyişle burası, yazılımınızın bağımlılıklarının çözümlenmesini yönetmekle ilgilidir.
  • pluginManagement repositories” yalnızca Gradle’ın kendisini genişletmek istiyorsanız gereklidir. Harici Gradle eklentilerini yönetmekle ilgilidir. Yalnızca Gradle ile birlikte gelen java-library gibi Gradle core eklentilerini kullanıyorsanız buna ihtiyacınız yoktur. Ancak “gradlePluginPortal()” veya “google()” gibi depolar tarafından sunulan “id(“com.autonomousapps.dependency-analiz”) version “1.30.0” “ gibi harici bir eklenti kullanmak istiyorsanız bunu kullanabilirsiniz.

Gradle eklentileri Jar dosyalarıdır (çünkü Gradle genişletilebilir bir Java uygulamasıdır). Dolayısıyla dışarıdan bakıldığında, “normal” Java kütüphaneleri (Java libraries) (commons-lang gibi) ve Gradle eklentileri (dependency-analysis gibi) benzer türde artifektlerdir. Ve bir Java kütüphanesi, Java’da da uygulandığı (implement edildiği için) için Gradle eklentisinin parçası olabilir. Bu nedenle DependencyResolutionManagement ve PluginManagement’te tanımladığınız şeyler örtüşebilir (ancak örtüşmek zorunda değildir).

3 - Build’in yapısı - alt projeler (subprojects)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
rootProject.name = "my-project"

pluginManagement{
    repositories {
        gradlePluginPortal() // Artifact Repository
        google() // Maven Artifact Repository
    }
    includeBuild("../my-build-logic")
}

dependencyResolutionManagement {
    repositories {
        mavenCentral()
    }
    includeBuild("../my-other-project")
}

include("app")
include("business-model")
include("data-model")

Üçüncü şey ise, settings dosyasında tanımlayacağınız projenizin gerçek yapısıdır. Proje, subproject (alt proje) adı verilen projelerden oluşur. Bir alt projeyi include() deyimini kullanarak tanımlarsınız. Örneğimizde üç alt proje tanımlıyoruz. Biri veri modelimiz (data-model) için, biri iş mantığı (business-logic) için ve biri de uygulama kodu (app) için olacak.

gradle'ı anlamak (understanding gradle) define subprojects


Bu alt projeleri nasıl içerikle dolduracağımızı bir sonraki bölümün konusu olacak. Şimdi settings dosyasıyla ilgili bahsetmek istediğim iki şey daha var.

Benim Notum:


my-project klasörü ile aynı dizinde bulunan my-build-logic ve my-other-project isimli iki boş klasörü eklediğimizi görüyorsunuz. Bu klasörlere henüz bir şey yazmadık. Ama pluginManagement ve dependencyResolutionManagement kod blokları içinde, includeBuild("../my-build-logic") ve includeBuild("../my-other-project") deyimleri aracılığı ile bu projeleri my-project isimli gradle projesine dahil ettiğimizi görüyorsunuz. Dilerseniz şimdilik bu kısımları yorum satırı ekleyerek pasif hale getirebilirsiniz. O kısımları ileriki içeriklerde kodlayacağız.

3.1 - settings eklentilerini (plugin) kullanma


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
rootProject.name = "my-project"

pluginManagement{
    repositories {
        gradlePluginPortal() // Artifact Repository
        google() // Maven Artifact Repository
    }
    includeBuild("../my-build-logic")
}

plugins{
    id("..")
}

dependencyResolutionManagement {
    repositories {
        mavenCentral()
    }
    includeBuild("../my-other-project")
}

include("app")
include("business-model")
include("data-model")

İlk şey, ayarlar (settings) dosyasının bir plugins {} bloğuna sahip olabilmesidir. Burada, konfigürasyonu çeşitli build’ler arasında paylaşmak için settings plugins adı verilen eklentileri uygulayabilirsiniz. Gelecek içeriklerin birinde bu konuyu ayrıntılı olarak konuşacağız.

gradle'ı anlamak (understanding gradle) settings plugins


3.2 - settings dosyasında script kodu


İkinci şey ise Kotlin (veya Groovy) kullandığımız için Kotlin dilinin tüm gücüne burada sahip olmamızdır. Bunu belirli konfigürasyonları daha kullanışlı hale getirmek için kullanabiliriz. Örneğin, root (kök) klasörümüzün tüm alt klasörlerini (sub folders) döngü içerisinde tekrarlayabilir ve her birini bir alt proje olarak dahil edebiliriz, böylece settings dosyasında bunlardan ayrı ayrı bahsetmemize gerek kalmaz.

1
2
3
4
5
6
7
- include("app")
- include("business-model")
- include("data-model")

+ rootDir.listFiles().filter { it.isDirectory && !it.isHidden  }.forEach {
+    include(it.name)
+ }

Benim Notum: Standard Settings properties


Settings nesnesi, settings script’inde standart bir properties kümesini ortaya çıkarır. Yukarıda bahsedilen rooDir bunlardan biridir. Aşağıdaki tabloda yaygın olarak kullanılan birkaç özellik listelenmiştir: 7

Name Description
buildCache - The build cache configuration.
plugins - The container of plugins that have been applied to the settings.
rootDir - The root directory of the build. The root directory is the project directory of the root project.
rootProject - The root project of the build.
settings - Returns this settings object.

Aşağıdaki tabloda yaygın olarak kullanılan birkaç metot listelenmiştir:

Name Description
include() - Adds the given projects to the build.
includeBuild() - Includes a build at the specified path to the composite build.

Settings File Scripting Settings nesnesinde, buildWinizi yapılandırmak için kullanabileceğiniz daha birçok properties ve metot vardır. Birçok Gradle betiği tipik olarak kısa Groovy veya Kotlin sözdizimiyle yazılmasına rağmen, settings script’indeki her öğenin esasen Gradle API’sindeki “Settings” nesnesinde bir yöntem çağırdığını hatırlamak önemlidir:

1
include("app")

Aslında budur:

1
settings.include("app")

Ek olarak, Groovy ve Kotlin dillerinin tüm gücü kullanımınıza açıktır. Örneğin, alt projeler eklemek için birçok kez dahil etmek yerine, proje kök klasöründeki dizinlerin listesini yineleyebilir ve bunları otomatik olarak dahil edebilirsiniz:

1
2
3
rootDir.listFiles().filter { it.isDirectory && (new File(it, "build.gradle.kts").exists()) }.forEach {
    include(it.name)
}

Not: Bu tür bir logic bir plugin’de geliştirilmelidir.

gradle'ı anlamak (understanding gradle) settings plugins


Benim Notum:


Gradle’a öncelikle yazılım projenizin yapısını tanımlayan bir araç olarak bakmak ve bunu Gradle’ın sunduğu DSL ile nasıl yapacağınızı öğrenmek yararlı olacaktır. Teknik olarak Gradle’ın DSL’i bir Java API‘sidir, dolayısıyla Kotlin, Groovy veya Java’nın kendisi gibi herhangi bir JVM tabanlı dil, potansiyel olarak bir yazılım projesini Gradle terimleriyle tanımlamak için kullanılabilir. Bunu kolaylaştırmak için Gradle, DSL’nin Kotlin versiyonunu ve DSL’nin Groovy versiyonunu sunuyor.

Settings (settings.gradle(.kts)) dosyası bulunduğunda, Gradle bir Settings nesnesi oluşturur. Settings nesnesinin amaçlarından biri, build’e dahil edilecek tüm projeleri bildirmenize izin vermektir. Gradle bir build için projeleri bir araya getirmeden önce, bir Settings örneği oluşturur ve settings dosyasını buna karşı yürütür.

gradle'ı anlamak (understanding gradle), Settings instance


settings script yürütülürken, Settings’i de yapılandırır. Bu nedenle, settings dosyası Settings nesnesini tanımlar. Bir Settings örneği ile bir settings.gradle(.kts) dosyası arasında bire bir yazışma (one-to-one correspondence) vardır.

Bununla birlikte, Settings nesnesi Gradle API‘sinin bir parçasıdır.

Benim Notum: Gradle wrapper nedir?


settings.gradle(.kts) çalıştığında dosyasını yüklediğimizde, IntelliJ’in bizim için bir sürü ekstra dosya eklediğini görebiliyoruz.

gradle'ı anlamak (understanding gradle), Gradle wrapper nedir?


Bu, Gradle sarmalayıcı (Gradle wrapper) olarak bilinen bir araçtır. Dikkat ettiyseniz, bu sayede gradle’ı bilgisayarınızda bir yere kurmanıza gerek kalmadı. Gradle sarmalayıcı (Gradle wrapper), bizim için bunu halleden küçük bir araçtır (small tool). Bu aracı projenize ekleyebilir, hatta git versiyon kontrol sistemine commit edebilirsiniz. Böylece bu projeyi build etmek isteyen herkes otomatik olarak doğru Gradle versiyonunu alır ve herhangi bir şey yüklemesine gerek kalmaz.

Şekilden de görüleceği üzere, Gradle sarmalayıcıyı başlatmak için biri unix için, diğeri windows için olmak üzere iki başlatma script’inin olduğunu görüyoruz. Ve sonrasında, sarmalayıcının gerçek implementasyonu olan bir “jar” dosyası (gradle-wrapper.jar) ve sarmalayıcıyı yapılandırmak için bir “wrapper.properties” dosyası (yani gradle-wrapper.properties) vardır.

Eğer properties dosyasını açarsanız, Intellij’in gradle’ın son sürümünü seçtiğini görürsünüz. Başka bir sürüm kullanmak istiyorsanız buradan değiştirebilirsiniz.

gradle-wrapper.properties

1
2
3
4
5
6
7
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

Benim Notum: Settings Script structure


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
pluginManagement {                     // 1                     
    repositories {
        gradlePluginPortal()
        google()
    }
}

plugins {                              //2   
    id("org.gradle.toolchains.fake") version "0.6.0"
}

rootProject.name = "root-project"      //3                     

dependencyResolutionManagement {       //4                  
    repositories {
        mavenCentral()
    }
}

include("sub-project-a")               //5                  
include("sub-project-b")
include("sub-project-c")
  1. plugin’lerin lokasyonunu tanımlar “Settings” dosyası, isteğe bağlı olarak, “Gradle Plugin Portalı” gibi binary repolar veya “includeBuild” kullanan diğer Gradle build’leri dahil olmak üzere projenizin pluginManagement” ile kullandığı pluginleri tanımlayabilir:

    1
    2
    3
    4
    5
    6
    
     pluginManagement {
         repositories {
             gradlePluginPortal()
             google()
         }
     }
    

    Bu bloğa pluginleri ve plugin bağımlılığı çözümleme (plugin dependency resolution) stratejilerini de dahil edebilirsiniz.

  2. plugin’leri uygular (apply).

    Settings dosyası, isteğe bağlı olarak daha sonra uygulanabilecek pluginleri bildirebilir; ki bu da, birkaç build/alt proje (subprojects) arasında paylaşılan konfigürasyon ekleyebilir:

    Settings’e uygulanan eklentiler yalnızca Settings nesnesini etkiler.

    1
    2
    3
    
     plugins {
         id("org.gradle.toolchains.fake") version "0.6.0"
     }
    

    Bu genellikle tüm alt projelerin aynı plugin sürümünü kullanmasını sağlamak için kullanılır.

  3. Kök projenin(root project) adını tanımlar Settings dosyası, rootProject.name özelliğini kullanarak proje adınızı tanımlar:
    1
    
     rootProject.name = "root-project"
    

    Build başına yalnızca bir kök proje vardır.

  4. build-wide repoları tanımlar.

    Aslında 4. madde dışındakiler net bir şekilde izah ediliyor. “Settings” dosyası isteğe bağlı olarak projenizin dayandığı bileşenlerin konumlarını (ve bunların nasıl çözüleceği), örneğin Maven Central gibi binary repoları, repositories kullanarak ve diğer Gradle build’leri includeBuild kullanarak tanımlayabilir:

    1
    2
    3
    4
    5
    
     dependencyResolutionManagement {
         repositories {
             mavenCentral()
         }
     }
    

    Bu bölüme sürüm kataloglarını da dahil edebilirsiniz.

  5. build’e alt projeler ekler.

    Settings dosyası, include ifadesini kullanarak tüm alt projeleri ekleyerek projenin yapısını tanımlar:

    1
    2
    3
    
     include("app")
     include("business-logic")
     include("data-model")
    

Detaylı bilgi için şu linki ziyaret edebilirsiniz.

Referanslar:

Daha Fazla Okuma: