31 Temmuz 2023 Pazartesi

Gradle Daemon Nedir?

Giriş
Açıklaması şöyle. Gradle Daemon arka planda çalışır. Çünkü Gradle'ı ayağa kaldırmak ve ilklendirmek çok uzun sürüyor. 
Gradle runs on the Java Virtual Machine (JVM) and uses several supporting libraries that require a non-trivial initialization time. As a result, it can sometimes seem a little slow to start. The solution to this problem is the Gradle Daemon: a long-lived background process that executes your builds much more quickly than would otherwise be the case. We accomplish this by avoiding the expensive bootstrapping process and leveraging caching by keeping data about your project in memory.
Gradle Daemon Aşamaları
Açıklaması şöyle. 
Once the Gradle Client JVM establishes a connection with an idle daemon that is compatible, it transmits the required build data, such as command line arguments, project directory, and environment variables. The daemon then initiates the build process and returns the build output, including logs and standard output/error, to the client via a local socket connection.
Gradle Daemon 3 aşamada çalışır
1. Initialization Phase
2. Configuration Phase
3. Execution Phase

1. Initialization Phase
Yapılandırma aşamasında kullanılacak Java nesneleri ilklendirilir

2. Configuration Phase
Projenin gradle script'i yüklenir

3. Execution Phase
Task ve ona bağlı action'lar çalıştırılır

6 Aralık 2022 Salı

jib plugin

Örnek
Şöyle yaparız
plugins {
...
  id 'com.google.cloud.tools.jib' version '3.3.0' //You just need to add a plugin
}

jib {
  from {
    image = 'openjdk:alpine' //You may leave it empty to use a default image
  }
  to {
    image = 'alekseinovikov/jib-example' //By default Jib pushes images into Docker Hub
    tags = ['0.1', 'latest']
    auth {
      username = 'username' //Docker Hub requires authentication
      password = 'password'
    }
  }
  container {
    jvmFlags = ['-Xms128m'] //You may pass additional flags
    ports = ['8080'] //Open ports
    format = 'OCI' //Even choose a format of the image you are building
  }
}

5 Aralık 2022 Pazartesi

avro plugin

Örnek
Şöyle yaparız. .avsc dosyalarından kotlin kodu üretir.
plugins {
  ... 
  id("com.github.davidmc24.gradle.plugin.avro") version ("1.2.0")
}

tasks.withType<com.github.davidmc24.gradle.plugin.avro.GenerateAvroJavaTask> {
    source(file("${projectDir}\\src\\main\\resources\\avro"))
    setOutputDir(file("${projectDir}\\src\\main\\kotlin"))
}

avro {
    fieldVisibility.set("private")
    customConversion(org.apache.avro.Conversions.UUIDConversion::class.java)
}


3 Aralık 2022 Cumartesi

Software Bill Of Materials - SBOM

Giriş
Software Bill Of Materials - SBOM yazısına bakabilirsiniz.

1. CycloneDX
Şu satırı dahil ederiz. 
plugins {
  id 'org.cyclonedx.bom' version '1.7.2'
}
Şöyle yaparız. build işlemi sonucunda SBOM da üretilir.
cyclonedxBom {
  includeConfigs = ["runtimeClasspath"]
  skipConfigs = ["compileClasspath", "testCompileClasspath"]
  projectType = "application"
  schemaVersion = "1.4"
  destination = file("build/reports")
  outputName = "CycloneDX-Sbom"
  outputFormat = "all"
  includeBomSerialNumber = true
  componentVersion = "2.0.0"
}
...
build.finalizedBy('cyclonedxBom'

2 Ekim 2022 Pazar

unbroken-dome plugin - Integration Test İçindir

Şöyle yaparız
id 'org.unbroken-dome.test-sets' version '4.0.0'

testSets {
   integrationTest
}
Çalıştırmak için şöyle yaparız
./gradlew integrationTest




28 Eylül 2022 Çarşamba

run Task

Örnek
Şöyle yaparız
gradle run

sonar plugin

Plugin Tanımlama
Şöyle yaparız
plugins { ... id "org.sonarqube" version "3.3" }
Plugin Properties
Property değeleri gradle.properties veya build.gradle dosyalarında tanımlanabilir.

1. gradle.properties
Şöyle yaparız
systemProp.sonar.host.url=http://localhost:9000 systemProp.sonar.login=<sonar-key>
2. build.gradle
Eğer Sonar master'dan farklı branch'lere bakabilen paralı sürümse şöyle yaparız
sonarqube { properties { property "sonar.branch.name", System.getenv('BRANCH_NAME') } }
Örnek
Şöyle yaparız
sonarqube { properties { property "sonar.projectKey", "luizgustavocosta_16-bits-zero-to-hero" property "sonar.organization", "luizgustavocosta" property "sonar.host.url", "https://sonarcloud.io" } }
Plugin Targetları
sonarqube target
Static code analysis işlemini başlatır. Projeyi derlemek için şöyle yaparız
./gradlew clean build
Test sonuçlarını Sonar'a göndermek için şöyle yaparız
./gradlew sonarqube -Dsonar.projectKey=spring-boot-simple
-Dsonar.host.url=http://localhost:9000
-Dsonar.login=da55e6a2a39868ae22bd77aaf48e61c26b19d8b7

9 Haziran 2022 Perşembe

distribution plugin - Projeyi Zip veya Tar'lar

Giriş
.sh, .bash, Word belgesi gibi şeyleri zip'leyerek dağıtmak için kullanılabilir

Örnek
Şöyle yaparız
plugins {
    id 'distribution'
}

distributions {
  main {
    contents {
      from(projectDir) {
        include 'scripts/**'
        include 'doc/**'
      }
    }
  }
}

jar.enabled = false
distTar.enabled = false
"gradle build" komutunu çalıştırınca "build\distributions" dizini altında proje ismine sahip bir zip oluşur

30 Mayıs 2022 Pazartesi

checkstyle plugin

Giriş
Bu eklentinin ana sayfası burada. Şöyle yaparız
plugins {
  // Apply the java-library plugin for API and implementation separation.
  id 'java-library'
  id 'checkstyle' 
}
Modulün bulunduğu yerde şöyle bir dosya oluşturulur
config\checkstyle\checkstyle.xml
Sonra şöyle yaparız
checkstyle {
  configFile = file("${rootDir}/config/checkstyle/checkstyle.xml") 
}
checkstyleMain {
  source ='src/main/java'
}
checkstyleTest {
  source ='src/test/java'
}
Daha sonra şöyle yaparız. 
gradle check
Açıklaması şöyle
The Checkstyle plugin adds the following dependencies to tasks defined by the Java plugin.

check
Depends on: All Checkstyle tasks, including checkstyleMain and checkstyleTest.

veya şöyle yaparız
gradle build





27 Mayıs 2022 Cuma

eclipse plugin

Giriş
Açıklaması şöyle. Yani Eclipse tarafından kullanılan ".project" dosyasını üretir
The Eclipse plugins generate files that are used by the Eclipse IDE, thus making it possible to import the project into Eclipse (File - Import…​ - Existing Projects into Workspace).
Örnek
Şöyle yaparız    
plugins {
  id 'eclipse'
}

eclipse {
  classpath {
    downloadJavadoc = false
    downloadSources = true
  }
}

7 Nisan 2022 Perşembe

Custom Task Örnekleri

Örnek
Elimizde şöyle bir xml vardı
<dependencyManagement>
  <dependencies>
    <dependency>
      ...
    </dependency>
  <dependencies>
<dependencyManagement>

<dependencyManagement>
  <dependencies>
    <dependency>
      ...
    </dependency>
  <dependencies>
<dependencyManagement>
Bu ikisini birleştirmek için şöyle yaptım. Aslında kod buradan geldi
import java.util.regex.Matcher
task fixPom { doLast { File file = new File("$buildDir/publications/maven_1/pom-default.xml") if (!file.exists()) { return; } println("Fixing pom for " + file.getPath()) def text = file.text def pattern = "(?s)(<dependencyManagement>.+?<dependencies>)(.+?)(</dependencies>.+?</dependencyManagement>)" Matcher matcher = text =~ pattern if (matcher.find()) { //Remove the first <dependencyManagement> tag text = text.replaceFirst(pattern, "") //Get all all <dependency> tags def firstDeps = matcher.group(2) //Get (<dependencyManagement>.+?<dependencies>)(.+?) part //add new dependencies and close the tag text = text.replaceFirst(pattern, '$1$2' + firstDeps + '$3') } file.write(text) } }
Bu yeni task'ı şöyle kullandım
generatePomPropertiesFile.dependsOn("fixPom")
Çünkü asemble için sıra şöyleydi
ompileJava
processResources
classes
createPropertiesFileForJar
generatePomFileForMaven_1Publication

fixPom //Burada araya girdim

generatePomPropertiesFile
writeManifestProperties
jar
createPropertiesFileForSourcesJar
sourcesJar
assemble




maven-publish Plugin - Artifactory veya Nexus'a Yükler

Giriş
Herhangi bir Maven repository sunucusuna jar ve pom dosyalarını yüklemek içindir. 

Tasks
Gradle menüsü altında şu menüleri görürüz
publishing
  publish : Artifactory veya Nexus'a Yükler
  publishToMavenLocal : Yerel Maven'a yükler

Örnek
Şöyle yaparız
plugins {
  id 'java-library'
  id 'maven-publish'
}
publications alanına
- earLibrary(MavenPublication)
- warLibrary(MavenPublication)
- mavenJava(MavenPublication)
gibi şeyler yazılır. Böylece neyi publish edeceğini anlar

repositories alanına
url ve authentication yazılır

Ear Dosyası
Örnek
Şöyle yaparız
plugins {
    id 'java-library'
    id 'maven-publish'
    id 'ear'
}

//Configure maven-publish plugin to publish ear file
publishing {

  publications {
    earLibrary(MavenPublication) {
      artifact ear
    }
  }
}

jar.enabled = false
War Dosyası
Örnek
Şöyle yaparız
plugins {
  id 'java-library'
  id 'maven-publish'
  id 'war'
}


//Configure maven-publish plugin to publish war file
publishing {

  publications {
    warLibrary(MavenPublication) {
      from components.web
    }
  }
}
jar.enabled = false
Jar Dosyası
Örnek
Şöyle yaparız
publishing {
  publications {

    mavenJava(MavenPublication) {
      artifactId = 'ms-commons'
      from components.java
      versionMapping {
        usage('java-api') {
          fromResolutionOf('runtimeClasspath')
        }
        usage('java-runtime') {
          fromResolutionResult()
        }
      }
      pom {
        name = 'MS Commons'
        description = 'A concise description of my library'
        url = 'http://www.example.com/library'
        licenses {
          license {
            name = 'The Apache License, Version 2.0'
            url =       'http://www.apache.org/licenses/LICENSE-2.0.txt'
          }
        }
        developers {
          developer {
            id = 'johnd'
            name = 'John Doe'
            email = 'john.doe@example.com'
          }
        }
      }
    }
  } //publications

  repositories {
    maven {
      name = "MyJfrog" //  optional target repository name
      url = "https://foo.jfrog.io/artifactory/my-repo"
      credentials {
        username = System.getenv('ARTIFACTORY_USERNAME')
        password = System.getenv('ARTIFACTORY_USER_PASSWORD')
      }
    }
  }
}
1. Seçenekler
publish
Jenkins ile şöyle yaparız
def shouldDeployToArtifactory() {
  return "${params.ARTIFACTORY_PUBLISH}" == "true"
}

if (shouldDeployToArtifactory()) {
  stage("Push to Artifactory") {
    echo "Publishing to Artifactory..."
    withCredentials([usernamePassword(
      credentialsId: 'ARTIFACTORY_PUBLISH',
      passwordVariable: 'ARTIFACTORY_PASSWORD', 
      usernameVariable: 'ARTIFACTORY_USER')
    ]) {
      runGradleSteps("publish")
    }
  }
}


2. Alanlar
repositories Alanı
Örnek
Şöyle yaparız
publishing {
  publications {
  }
  repositories {
    maven {
      name = "MyRepo" //  optional target repository name
      url = "http://my.org.server/repo/url"
      credentials {
        username = 'alice'
          password = 'my-password'
        }
      }
  }
}
Örnek
Şöyle yaparız
allprojects { 
  apply plugin: 'java' 
  apply plugin: 'maven-publish' 
  publishing { 
    publications { 
	     (MavenPublication) { 
	    from components.java 
	  } 
	} //publications 
	repositories { 
	  maven { 
	    url "s3://my.private.maven" 
		authentication { 
		  awsIm(AwsImAuthentication) 
		} //authentication 
	  } //maven" 
	} /repositories
  } //publishing 
} //allprojects
Çalıştırmak için şöyle yaparız
cp init-client.gradle build/client/init-client.gradle cd build/client && 
./gradlew --init-script init.gradle publish && 
cd -

1 Nisan 2022 Cuma

Zip Task

Giriş
Açıklaması şöyle
Sometimes we might need to replace one or more files in an existing archive file. The archive file could be a zip, jar, war or other archive. Without Gradle we would unpack the archive file, copy our new file into the destination directory of the unpacked archive and archive the directory again. To achieve this with Gradle we can simply create a single task of type Zip. To get the content of the original archive we can use the project.zipTree method. We leave out the file we want to replace and define the new file as replacement. As extra safeguard we can let the tsak fail if duplicate files are in the archive, because of our replacement.
archiveBaseName Alanı
Modul ismi ile aynıdır. Property olduğu için get() olarak kullanılmalıdır

Örnek
Şöyle yaparız. Böylece eğer module ismi foo ise "foo.zip" içinde "foo/scripts" diye bir dizin oluşur
//Create a new zip file
task scriptsZip(type: Zip) {
  archiveAppendix = 'scripts'
  from 'scripts'
  into "${archiveBaseName.get()}/scripts"
}
assemble.dependsOn('scriptsZip')
Örnek
Açıklaması şöyle
The following code shows an example of a task to replace a README file in an archive sample.zip using Groovy and Kotlin DSL.
Şöyle yaparız
// Register new task replaceZip of type org.gradle.api.tasks.bundling.Zip.
tasks.register("replaceZip", Zip) {
  archiveBaseName = "new-sample"
  destinationDirectory = file("${buildDir}/archives")

  // Include the content of the original archive.
  from(zipTree("${buildDir}/archives/sample.zip")) {
    // But leave out the file we want to replace.
    exclude("README")
  }

  // Add files with same name to replace.
  from("src/new-archive") {
    include("README")
  }

  // As archives allow duplicate file names we want to fail
  // the build when that happens, because we want to replace
  // an existing file.
  duplicatesStrategy = "FAIL"
}
archiveFileName Alanı
Zip dosyasının ismini belirtir
Örnek
resources dizinini zip'lemek için şöyle yaparız
task packageDistribution(type: Zip) {
  archiveFileName = "vitesstestservertemplate.zip"
  destinationDirectory = file("$buildDir/libs")
  from "$buildDir/resources/main"

}

assemble.dependsOn packageDistribution
archiveAppendix Alanı
"module ismi + archiveAppendix " şeklinde yeni bir zip dosyası oluşturur. Açıklaması şöyle. 
The appendix part of the archive name, if any.
Örnek
Şöyle yaparız
task scriptsZip(type: Zip) {
  archiveAppendix = 'scripts'
  from 'scripts'
  into "${archiveBaseName}/scripts"
}
assemble.dependsOn('scriptsZip')


Copy Task

Giriş
Açıklaması şöyle
The Copy task is a task type provided by core Gradle. At execution, a copy task copies files into a destination directory from one or more sources, optionally transforming files as it copies. You tell the copy task where to get files, where to put them, and how to filter them through a configuration block. 
from ve into Alanları
Örnek
Şöyle yaparız
task copyPoems(type: Copy) {
  from 'text-files'
  into 'build/poems'
}
duplicatesStrategy Alanı
Açıklaması şöyle
EXCLUDE
Do not allow duplicates by ignoring subsequent items to be created at the same path.
FAIL
Throw a DuplicateFileCopyingException when subsequent items are to be created at the same path.
INCLUDE
Do not attempt to prevent duplicates.
INHERIT
The default strategy, which is to inherit the strategy from the parent copy spec, if any, or INCLUDE if the copy spec has no parent.
WARN
Do not attempt to prevent duplicates, but log a warning message when multiple items are to be created at the same path.
Açıklaması şöyle. Yani Gradle 7'den itibaren duplicatesStrategy açıkça atanmalı
If there is already rebel.xml present among the source files then the behavior will depend on Gradle version. Versions below 7.0 do not require any additional configuration and the generated rebel.xml will be included to the build result by default. Since Gradle 7.0, duplicatesStrategy must be configured in build.gradle in order to prevent a duplicate entry error at build time:
...
The value 'include' will force the generated rebel.xml to be copied to the build result. Contrariwise, 'exclude' will favor rebel.xml that is present among the source files.
Örnek
Şöyle yaparız
tasks.withType<Jar>() {

  duplicatesStrategy = DuplicatesStrategy.EXCLUDE

  manifest {
    attributes["Main-Class"] = "MainKt"
  }

  configurations["compileClasspath"].forEach { file: File ->
    from(zipTree(file.absoluteFile))
  }
}

15 Mart 2022 Salı

Parent BOM

Örnek
Şöyle yaparız
implementation platform('org.testcontainers:testcontainers-bom:1.16.3') //import bom
testImplementation ('org.testcontainers:junit-jupiter')
testImplementation('org.testcontainers:mysql') //no version specified
testImplementation 'mysql:mysql-connector-java'
Örnek
Şöyle yaparız
testImplementation(platform('org.junit:junit-bom:5.8.1'))
testImplementation("org.junit.jupiter:junit-jupiter") //no version specified testImplementation ("org.junit.vintage:junit-vintage-engine") //no version specified

22 Şubat 2022 Salı

buildscript Block

Giriş
Açıklaması şöyle
The buildScript block determines which plugins, task classes, and other classes are available for use in the rest of the build script. Without a buildScript block, you can use everything that ships with Gradle out-of-the-box. If you additionally want to use third-party plugins, task classes, or other classes (in the build script!), you have to specify the corresponding dependencies in the buildScript block.
Yani buraya plugin ve diğer bağımlılıklar tanımlarnı

Örnek - plugin tanımlama
Şöyle yaparız
buildscript {

  dependencies {
    classpath(group: 'com.foo', name: 'my-plugin', version: '3.3.0') {
      transitive = true
    }
  }
}

23 Ocak 2022 Pazar

axion-release plugin

Giriş
Şöyle yaparız
plugins {
    id 'pl.allegro.tech.build.axion-release' version '1.11.0'
}
1. Seçenekler
Seçenekler Intellij Gradle menüsü altında release ve help menüleri altında görünüyor. Şöyle

help/currentVersion
release/createRelease
release/markNextVersion
release/pushRelease
release/release
release/verifyRelease 

Kullanım şöyle
$ git tag
project-0.1.0

# En son commit ve tag aynı
$ ./gradlew currentVersion
0.1.0

$ git commit -m "Some commit."

# En son commit tagden ileride
$ ./gradlew currentVersion
0.1.1-SNAPSHOT

# Yeni tag yarat ve remote'a pushla
$ ./gradlew release

# Yeni tagi gitte görebiliriz 
$ git tag
project-0.1.0 project-0.1.1

# En son commit ve tag aynı
$ ./gradlew currentVersion
0.1.1

# Burada maven-publish plugin kullanılıyor
$ ./gradlew publish
published project-0.1.1 release version

# Yeni versiyonu elle ata ve remote'a push'la
$ ./gradlew markNextVersion -Prelease.version=1.0.0

$ ./gradlew currentVersion
1.0.0-SNAPSHOT


currentVersion seçeneği
Açıklaması şöyle
Prints current project version extracted from SCM
Örnek
Şöyle yaparız
./gradlew currentVersion ... Project version: 0.1.0-SNAPSHOT
release seçeneği
Açıklaması şöyle
Performs release - creates tag and pushes to remote
Örnek
Şöyle yaparız
./gradlew release
...
Creating tag: v0.1.0
Changes made to local repository
markNextVersion seçeneği
Açıklaması şöyle
Create next-version marker tag, that affects current version resolution. Tag is pushed to remote.
2. Alanlar
tag alanı
Açıklaması şöyle
Only tags which match the predefined prefix are taken into account when calculating current version. Prefix can be set using scmVersion.tag.prefix property:

scmVersion {
    tag {
        prefix = 'my-prefix'
    }
}
Default prefix is release.

Örnek
Eğer  SCM tag alanı v ile başlamıyorsa kullanılır. Şöyle yaparız
scmVersion {
  tag {
    prefix = 'release'
  }
}
Örnek
Şöyle yaparız. Burada "release-" ile başlayan tag'ler dikkate alınıyor. "release-a" gibi tag'ler simple olarak işaretli olduğu için es geçilir.
scmVersion {
  tag {
    //Only tags which match the predefined prefix are taken into account when calculating
    //current version. use "git tag" to list tags
    prefix = 'release'
  }
  //You can also set decorators per branches that match specific regular expression
  //simple : This is the default version creator that does nothing
  branchVersionCreator = [
    'release[/-].+': 'simple',
  ]
  versionCreator {versionFromTag, position ->
    return "${versionFromTag}-${position.shortRevision}"
  }
}

10 Ocak 2022 Pazartesi

GRADLE_HOME Ortam Değişkeni

Giriş
Intellij ile çalışırken gradle kurulumunu otomatik yapıyor. Ancak komut satırında "gradle" yazınca hata alıyoruz. Bu durumda GRADLE_HOME ortam değişkenini tanımlamak gerekiyor.

Örnek - Windows
Şöyle yaparız
Ortam değişkenleri penceresinden GRADLE_HOME ortam değişkeni IntelliJ'in kurulum yaptığı yere gösterecek şekilde düzenleriz. Bu yer şöyle
C:\Users\user\.gradle\wrapper\dists\gradle-6.3-bin\8tpu6egwsccjzp10c1jckl0rx\gradle-6.3
Daha sonra PATH ortam değişkenine şunu ilave ederiz
%GRADLE_HOME%\bin


25 Aralık 2021 Cumartesi

assemble Task - Sadece Yapılandırır Testleri Çalıştırmaz

Giriş
Açıklaması şöyle. Base plugin ile geliyor
assemble - Assembles the outputs of this project.
Testleri çalıştırmadığı için
gradle build -x test
komutuna tercih edilebilir




24 Aralık 2021 Cuma

gradle.properties Dosyası

Giriş
Açıklaması şöyle
Gradle provides several options that make it easy to configure the Java process that will be used to execute your build. While it’s possible to configure these in your local environment via GRADLE_OPTS or JAVA_OPTS, it is useful to be able to store certain settings like JVM memory configuration and Java home location in version control so that an entire team can work with a consistent environment. To do so, place these settings into a gradle.properties file committed to your version control system.
JVM Parametreleri
Açıklaması şöyle
Specifies the JVM arguments used for the Gradle Daemon. The setting is particularly useful for configuring JVM memory settings for build performance. This does not affect the JVM settings for the Gradle client VM. The default is -Xmx512m "-XX:MaxMetaspaceSize=256m".
Örnek
"Check the JVM memory arguments defined for the gradle process"
diye bir hata alıyordum. gradle.properties dosyasına şu satırı ekledim
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=1024m 
  -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
JDK 17 için şöyle yaparız
org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=1024m 
  -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

Gradle Daemon Nedir?

Giriş Açıklaması  şöyle . Gradle Daemon arka planda çalışır. Çünkü Gradle'ı ayağa kaldırmak ve ilklendirmek çok uzun sürüyor.  Gradle ru...