6. Continuous Delivery - Sürekli Teslimat
"Continuous Delivery doesn't mean every change is deployed to production ASAP.
It means every change is proven to be deployable at any time."
Carl Caum from the Puppet Blog
"Continuous Delivery means a team can deploy a feature whenever a product
owner approves the feature and wants to deploy it."
To be able to tell your product owner they can do this, does take time for the
team to institute the right practices to enable CD*.
Sürekli Teslimat, deploy etmek zorunda olmadığın ama her zaman buna hazır
olabildiğin andır.
7. Continuous Delivery
Continus Delivery aşağıdaki üç disiplinin kombinasyonu
demektir
- Continuous Integration
- Continuous Testing
- Continuous Deployment (istendiğinde)
Bu sürece konfigurasyon yönetimi de gelecek.
8. Continuous Delivery
Hedefler
Kullanıcıya çalışan yazılımı
olabildiğince hızlı verebilmek
Sıklıkla otomatize edilmiş sürümler
sunmak
Faydalar
Düşük risk, stres
Hızlı yatırımın geri dönüşü (ROI)
İş ihtiyaçlarına geliştirilmiş yanıt
verebilmek
İyileştirilmiş kalite
Hızlıca hataya düşmek (fail-fast)
Yüksek özgüven
9. Delivery vs. Deployment
Sırf yazılımcı yazdığı kodun
kullanıldığını görsün diye mutlu
etmek ama geri dönüşü olmayan
sonuçlardan dolayı patronu
endişelendirmek için yapılır*.
Daha çok cloud ortamında
sunucularını hızlıca geri
dönebilen, ortak componenti ve
veritabanları olmayan, işin hatasız
olacağını çok geniş verilerle,
regresyonlarla koşan, business’ın
“tüm sorumluluk bendedir, kesinti
mesinti hepsinin hesabını ben
veriyorum” diyebildiği şirketlerde
kullanılır*.
10. Continuous Delivery vs. Deployment
Sürekli Teslimat(cDelivery), başarılı olan bir yapıyı (build) bir ortama atmanın bir yoludur.
Burada teslimat ile dağıtım arasında bir nüans vardır.
- Teslimat manual olarak,
- dağıtım ise otomatik olarak yapılır.
Sürekli teslimat düzgün bir şekilde uygulandığında, müşteriler her zaman standartlaştırılmış bir test
sürecinden geçmiş hazır yapıya sahip olacaklardır.
Continus Delivery aşağıdaki üç disiplinin kombinasyonu demektir
- Continuous Integration
- Continuous Testing
- Continuous Deployment (istendiğinde)
Bu sürece konfigurasyon yönetimi de gelecek.
11. Delivery vs Deployment
Delivery ile yapılan sürüm sonuçları geri
alınamayacak ve hassas kararların
verilmesini gerektiren, elle yapılacak
sürümdür.
Deployment ile yapılan sürüm otomatik olduğu
için ya hassas kararların verilmesi gerekmeyen
ya da arkasında ciddi testlerin yapılarak
sonucun sorunsuz olacağına inanıldığı otomatik
yapılan sürümdür.
12. Continuous Integratıon
Kodu alıp kaynak yönetim sisteminde derleyerek üstünde unit
testleri ve otomatize edilmiş süreçlerden geçirip kodun
sorunsuz olduğunu gördüğümüz süreçtir.
Yazılan kodun, geliştirilen modülün — kısaca geliştirme ortamından çıka gelen bir parçanın — projeye
dahil edilmesi esnasında bir takım süreçlerden geçirilmesine verilen isim. Bağımlılıkların repolardan
indirilmesi, projeye dahil edilmesi, geliştirilen kod parçacığın testlerden (unit, integration, vs…)
geçirilmesi, olası durumlara göre geliştiriciye veya işin sorumlusuna bilgi verilmesi (push notification,
sms, mail, vs…), işin paketlenmesi gibi eylemlerin tamamı, genellikle bu kavramın bir parçası olarak
hayatımızda yer ediyor*.
13. Sürekli entegrasyon (Continuous Integration = CI), kod üzerinde yapılan her değişikliğin
ardından, tüm sistemin çalışır durumda olduğunu, yapılan değişikliğin sistemin bazı
bölümlerinde kırılmalara yol açmadığını tespit etmek için kullanılan yöntemdir.
Kırılmaları birim testlerle tespit ederiz. Bu testler, yapılan değişikliğin neticesi
olarak yeni bir yapı (build) hazırlandıktan sonra otomatik olarak çalıştırılır.
Yapılan değişiklik yeni yapının bir parçası olduğu için, testlerde oluşan hatalar, yapılan
değişikliğin sistemi kırdığı anlamına gelmektedir. Bu durumdan tüm programcılar haberdar
edilerek, hatanın bir an önce giderilmesi ve testlerin her zaman olumlu sonuç vermesi
sağlanır.
Sürekli entegrasyon ile programcılar tarafından kod üzerinde yapılan çalışmalar
neticesinde her zaman çalışır bir sürümün oluşması sağlanmış olur*.
Özcan Acar - Sürekli Entegrasyon
14. Özcan Acar - Neden Sürekli Entegre Edilmeli?
Oluşturduğunuz yazılım sistemini sürekli entegre etmiyorsanız, zamanı gelince toptan entegre etmek
zorundasınız. Bunun, neden yazılım hayatınızda karşılaşabileceğiniz en büyük sorun olabileceğini bir örnek
vererek açıklamak istiyorum.
Şimdi şunu hayal edin: Yeni bir otomobilin tasarlanması projesinde yer aldınız. Otomobil tasarlandı ve
otomobili oluşturan parçalar 5 değişik ülkede, 20 değişik firma tarafından üretildi. Bu ülkelerde kullanılan
uzunluk ve ağırlık birimleri (metre, kg vs.) değişik olabilir. Görev dağılımı esnasında yanlış anlamalardan
dolayı üretilen parçalar birbirine uyumlu olmayabilir. Eğer tüm parçalar üretildikten sonra bir çırpıda tüm
otomobili oluşturmak isterseniz, üretim sürecinde meydana gelen hataları daha önceden tespit edemediğiniz
için, yamuk yumuk bir otomobil ortaya çıkacaktır. Ama üretim esnasında koordineli bir şekilde otomobili parça
parça bir araya getirip, parçalar uyuşuyor mu diye kontrol etmiş olsaydınız, meydana gelen uyuşmazlıkları çok
erken tespit ederek, gerekli değişiklikleri yapabilirdiniz. Bu yazılım sektörü için de geçerli. Oluşturulan
sistem komponentleri ne kadar erken entegre edilirse, oluşan uyuşmazlıklar o kadar erken tespit edilir ve
gerekli değişiklikler yapılabilir.
Sürekli entegrasyon çevik süreçlerde çok önemli bir yazılım metodudur. Sistem üzerinde yapılan her değişiklik
sürekli entegrasyonu otomatik olarak gerçekleştiren sunucu tarafından kontrol edilir. Yazılımda kırılmalar
oluşması (compile hataları, eksik sınıflar vs.) durumunda, tüm ekip sürekli entegrasyon sunucusu tarafından
uyarılır. Bu geribildirim sayesinde entegrasyonun ne safhada olduğu anlaşılır.
17. Her iş bir diğerini tetikler, Eğer başarısız olan iş olursa tüm süreç başarısız olarak kesilir
18. Boru Hattı davranışını anlamak için nasıl yürütüldüğü hakkında birkaç noktayı anlamalısınız.
- Adımların (steps) dışında, tüm pipeline mantığı, Groovy koşulları, döngüler, vb. ister basit ister
karmaşık olsun, düğüm (node) bloğunun içinde bile olsa master Jenkins üstünde koşar.
- Adımlar (steps), uygun olan yerlerde iş yapmak için uygulayıcıları (executors) kullanabilirler, ancak her
adım küçük de olsa master’a ek yük yükler.
- Pipeline kodu Groovy olarak yazılır, ancak yürütme modeli derleme zamanında Devam Geçiş Stili'ne
(CPS -Continuation Passing Style-) dönüştürülür.
- Bu dönüşüm, pipeline için değerli güvenlik ve dayanıklılık sağlar, ancak bazı sıkıntılarla birlikte gelir:
- Adımlar (steps) Java kodunu çağırabilir ve Java kodu sayesinde hızlı ve verimli bir şekilde
çalışabilir, ancak Groovy normalden daha yavaş çalışır.
- Groovy çok daha fazla bellek gerektirir, çünkü nesne tabanlı bir sözdizimi bellekte tutulur.
- Boru hatları, master’ın fail olmasından kurtulabilmek için programı ve durumunu kalıcı hale getirir.
Pipeline & Groovy’e Dair Bilinmesi Gerekenler
22. Jenkins Mimarisi
- Jenkins, her yazılım gibi
bir işletim sistemi(host)
üstünde koşar.
- Java application container
veya application server
üstünde koşar (varsayılan
olarak Jetty kullanır)
- Jetty ve jenkinsi başlatma,
durdurma ve izlemek için
harici bir servis
uygulaması çalışır.
- Views ile projeleri(jobs
olarak da bilinir) ve
klasörleri gruplar Jenkins.
- Projeler iş kuyruklarını
(job queue) ve bunları
çalıştıracak executerları
tetikler.
23. Default Conf. jenkins ile gelir ve herhangi bir build
aşaması için kullanılabilir.
Extra Conf. kullanılan plugin tarafından isteniyor.
Maven Conf. sadece maven projeleri için kullanılır.
Freestyle Conf. herhangi bir proje tipi için
kullanılır. create new jobs ile ilk projemizi
oluştururken freestyle project tipiyle
başlayabiliriz.
24. Jenkins konteynırının host bilgisayarla bağlı olduğu /var/jenkins_home dizini
C:Userscem.topkayaDocumentsKitematicjenkinsvarjenkins_home olarak ayarlanmış. Projemiz olan ilk project-job olsun ise
host makinede “C:Userscem.topkayaDocumentsKitematicjenkinsvarjenkins_homeworkspaceilk project-job olsun” dizininde
görüntülenecek. Ve doğal olarak içi boş :)
Workspace
Projenin “Build Now”
düğmesine basıldığında sadece
workspace’in silinmesi ayarı
aşağıdaki Console Output
ekranındaki gibi silinecek.
Proje dosyalarının olduğu klasörü yani workspace’i
görebiliyoruz yukarıdaki çıktıda.
“/var/jenkins_home/workspace/ilk project-job olsun”
27. Scripted Vs. Declarative
Deklaratif ardışık düzen ile Komutlu ardışık düzen arasındaki temel fark, sözdizimleri ve
esneklikleriyle ilgilidir.
Deklaratif pipeline, pipeline’ı kod konsepti olarak destekleyen nispeten yeni bir
özelliktir. Pipeline kodunun okunmasını ve yazılmasını kolaylaştırır. Bu kod Git gibi bir
kaynak kontrol yönetim sistemine kontrol edilebilen bir Jenkinsfile içinde yazılmıştır.
Oysa (Scripted) kodlanmış pipeline, kodu yazmanın geleneksel bir yoludur. Bu satırda
Jenkinsfile Jenkins UI örneğine yazılır.
Bu boru hatlarının her ikisi de Groovy DSL'ye dayanmasına rağmen, scripted pipeline,
Groovy tabanlı daha katı sözdizimleri kullanır çünkü Groovy üzerine inşa edilen ilk
pipeline idi.
Bu Groovy komut dosyası genellikle kullanıcılar tarafından benimsenmediğinden, daha basit
ve daha seçenekli bir Groovy sözdizimi sunmak için deklaratif ardışık düzen eklendi.
Deklaratif (bildirimli) ardışık düzen, "pipeline" etiketli bir blok içinde tanımlanırken,
komut dosyası verilen ardışık düzen, bir "node" içinde tanımlanır.
28. Scripted
Scripted pipeline, Jenkins pipeline’ı kod
olarak yazmanın geleneksel bir yoludur.
İdeal olarak, Scripted pipeline Jenkins web
arayüzünde Jenkins dosyasında yazılır.
Deklaratif düzenden farklı olarak, scripted
pipeline katı bir sözdizimi kullanır. Bu
nedenle, scripted pipeline kodlanmış
pipeline üzerinde büyük denetim sağlar ve
komut dosyasının akışını kapsamlı bir
şekilde değiştirebilir.
Bu, geliştiricilerin kod olarak ileri ve
karmaşık boru hattı geliştirmelerine
yardımcı olur.
Node, Jenkins mimarisinin, node veya agent
projelerin iş yükünün bir kısmını
çalıştıracağı ve ana düğümün (master node)
işin yapılandırmasını (configuration)
işleyeceği kısmıdır.
Stage bloğu görev ilerledikçe tek bir aşama
veya çoklu olabilir. Ve ortak aşamaları
olabilir.
29. Kod güdümlü iş oluşturma
Scripted
- Nodes
- Stages
- DSL
- Groovy code
● groovy kodunu kullanabilirsin
● Hata kontrolü ve raporlaması
mevcut
Scripted Vs. Declarative
Declarative
- agent
- [environment]
- [option]
- stages
- stage
- [agent]
- [environment]
- [when]
- [option]
- [input]
- [parameter]
- steps
- DSL
- [post]
- [failure]
- [success]
- [always]
- [cleanup]
● Ön tanımlı kısımlar
● Kod mantığı kullanılamaz
● DSL- yönelimli kontrol ve raporlama mevcut
● Blue-Ocean uyumlu
31. Input & Parameters & Choice
Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
stages {
stage('Inputlu Aşama') {
input {
message "Devam edelim mi?"
ok "Evet lütfen :)"
submitter "alice,bob"
parameters {
string(name: 'PERSON', defaultValue: 'Mister Rabinsın',
description: 'Selamlarken buradaki değeri kullanacak')
}
}
steps {
echo "Merhaba ${PERSON}, ne güzel sizi görmek."
}
}
}
}
Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
parameters {
choice(
choices: ['greeting' , 'silence'],
description: '',
name: 'REQUESTED_ACTION')
}
stages {
stage ('Speak') {
when {
// Only say hello if a "greeting" is requested
expression {
params.REQUESTED_ACTION == 'greeting'
}
}
steps {
echo "Hello, bitwiseman!"
}
}
}
}
/*
* parameters ile okunan değerler strong type okunur
* Yani tip parametrenin tipi Boolean ise okunan değerin
* tipi de Boolean olduğu için toBoolan() ile dönüşüme
* gerek kalmaz.
* evironment (env.<degisken>) ise daima string döner!
*/
Soldaki üç türden, ilk ikisi var
olmayan bir parametre talep
ederseniz null döndürür -
daha sonra yeni bir parametre
eklemeye karar verdiğinizde
ve mevcut tüm projeleri
güncellemek istemediğinizde
çok yardımcı olur!
Ancak üçüncüsü, yapıyı
çökertecektir. (${parm})
32. INPUT ile Interaktif (etkileşimli) Parametre Tanımlıyoruz
Durdu çünkü input
bekletiyor!
34. Agent
Agent, tüm boru hattının (pipeline) veya özellikle bir aşamanın (stage)
çalıştığı yerdir. Örneğin, Docker. Agent aşağıdaki parametreleri alır:
● any: tüm pipeline’ın kullanılabilir herhangi bir agent üstünde çalışacağı
anlamına gelir.
● none: blok altındaki tüm aşamaların (stage) ayrı olarak agent ile
bildirilmesi gerektiği anlamına gelir.
● label: sadece Jenkins ortamı için bir etiket
● docker: Docker ortamında pipeline’ı çalıştırmak içindir.
Agent oluşturma başka sayfalarda anlatılacak!
35. - Groovy temelli
- Süreçlerin adımlarını orkestre eder
- Bir pipeline script gibi job içinde veyaa repository içinde tutulan harici
bir dosya olarak “Jekinsfile” adında saklanabilir
Jenkins Domain Specific Language
37. Yerel Makinaya Jenkins Kurulumu
Bu adresten adım adım takip edebilirsiniz.
- Bu adresten war dosyasını indir
- konsoldan şu komutu çalıştır
- java -jar jenkins.war --httpPort=8080
- internet gezgininden http://localhost:8080 adresini aç
jenkins.war çalıştırıldığında $user.home/.jenkins dizinini oluşturmak
ister. Hızlıca çalıştırmak için oluşturduğumuz run.bat dosyası çalışıp
uygulama ayaklandığında %USERPROFILE%.jenkins klasörü oluşur ve
pluginler bu klasöre yüklenir.
Farklı bir dizinde .jenkins klasörünü barındırmak istersek ortam
değişkenlerinden JENKINS_HOME anahtarına istediğimiz yeni dizinin
adresini girip .jenkins dizininin içeriğini taşıyabiliriz.
39. Hangi Komut Satırı?
İleride çalıştıracağımız “echo cem” işleminin çıktılarını
sağ tarafta incelediğimizde; jenkins’in docker yansısı
- eğer linux ise, echo işlemini /bin/sh üstünde
çalıştırmakta,
- windows ise cmd üstünde koşturmakta
Host olarak hangi işletim sistemi koşuyorsa buna uygun
command yazmamız veya docker yansısını komutlarımıza göre
seçmemiz gerek.
Linux host üstünde koşan Jenkins için sh ile çalışıyorken
bat ile komutlarımızı çalıştırıyoruz.
42. Hangi Docker Yansısı?
Birinci Jenkins düğümü için (eskiden master derdik) jenkins/jenkins yansısını kullanabilirken, ikinci yahut
işçi jenkins ajanları için jenkins/slave yansısını kullabiliriz (slave de yakında kaldırılır).
$ docker pull jenkins/jenkins
Not: jenkins ve jenkinsci/jenkins yansıları kullanımdan kaldırıldı.
$ docker pull jenkins/slave
43. Docker ile Master Jenkins Kurulumu - 1
Jenkins docker görüntünüzün (image) içinde docker görüntüleri
(images) oluşturmayı planlamıyorsanız, örneğimdeki --privileged
bayrağını göz ardı edebilirsiniz.
Reverse proxy olarak nginx çalıştırmak istersek, nginx
dosyasının default.conf içeriği:
upstream app {
server 127.0.0.1:49001;
}
server {
listen 80;
server_name hosts_a_ne_yazarsan;
location / {
proxy_pass http://app;
}
}
$ docker pull jenkins
$ docker run
--detach
--publish 49001:8080
--volume $PWD/jenkins:/var/jenkins_home
--tty
--privileged
--restart=always
jenkins/jenkins
44. Docker ile Master Jenkins Kurulumu - 2
Docker ile ister komut satırından ister kitematic ile jenkins/jenkins
isimli docker yansısını yükleyebiliriz.
Kurulum sonrasında docker attach <container-id> ile container konsol
ekranında neler olduğunu görebiliriz.
Komut satırında -d anahtarı olmada çalıştırırsak jenkins ön planda çalışır
ve işletilen komutların çıktılarını yani jenkins processinin I/O
çıktılarını kullandığımız konsol üstünde görebiliriz. Ama -d anahtarını
kullanırsak bu bilgileri görmek için docker attach <container-name>
komutunu çalıştırmamız gerekir.
47. Slave Jenkins Ajanı Üstünde İş Çalıştırmak
dpipeline {
agent {
label 'ajan'
}
stages {
stage('Test') {
steps {
sh 'pwd'
}
}
}
}
48. Jenkins Terminali Root İle Kullanmak
Konteyner ile terminal bağlantısı kurmak istediğimizde --user root argümanı
eklersek root yetkisiyle bash’e bağlanabiliriz. root Kullanıcısıyla apt
işlemlerini yapabilir ve sistem seviyesinde nodejs kurulumu sağlarız. --
privileged Argümanı da root ile bağlanmamızı sağlar.
Not: Resimde gördüğünüz gibi root yetkisi olmadan :/$ ile diğer kullanıcılar için
:/# ile terminale bağlanıyoruz.
- Dolar işareti ($), normal bir kullanıcı olduğunuz anlamına gelir.
- hash (#), sistem yöneticisi (root) olduğunuz anlamına gelir.
- C kabuğunda, komut satırı yüzde işaretiyle (%) biter.
roo@1ee9eb95c6bb:/$ <Kullanıcı Adı>@<makine adı>:<geçerli dizin><[$,#]>
Kullanıcı Adı: Bu örnekte root -veya- jenkins görünür. Oturum açtığınız kullanıcı
hesabını anlarız.
Makine Adı: Makine ana bilgisayar adı. İçinde bulunduğumuz makine adıdır. Docker
için kabın ID değeridir (1ee9eb95c6bb).
Geçerli Çalışma Dizini: Bağlandığımız makinede içinde bulunduğunuz dizini gösterir.
/ : Öne doğru eğik çizgi (/) Kök dizinini işaret eder. “cd /” komutuyla hızlıca kök dizine gidilebilir.
~ : Tilde işareti ana dizin anlamına gelir, yani ilk oturum açarken varsayılan dizin. jenkins kullanıcısı oturum açtığında
“jenkins@d7d9d29b565f:~$” dizinine düşer. Buradaki tilde işareti “/var/jenkins_home” dizinini işaret eder.
49. Jenkins’in Varsayılan Dilini Değiştirmek
Özetle:
- Locale eklentisini indir
- Jenkins -> Ayarlar/Configuration Kısmında “Varsayılan
Dil” yerine istediğiniz dili kısa koduyla yazın (tr,
en, fr gibi)
- İnternet gezgininizin diliyle görüntülenmemesi için
altındaki “ignore browser preference..” seçilir
50. Docker ile Master Jenkins Kurulumu - 3
Jenkins’in Şifresi
Kurulum sırasında jenkins ilk giriş için bir şifre
oluşturacak ve bunu konsolumuza yazacak.
jenkins_home Dizinini bağladığınız kendi diskinizdeki
klasörü silerseniz ve jenkins tekrar kurulurken yine
aynı konsolu göreceksiniz.
Eğer burayı kaçırırsanız docker stop <container-name> ile konteynerınızı durdurup başka bir konsol ekranından
docker attach <container-name|id> ile birazdan açacağınız docker container konsolunu takip edebilirsiniz.
Tekrar docker start <container-name> ile başlatırken attach olduğunu konsolda gizli anahtarı görebilirsiniz.
52. NodeJs Kurulumu - 1
Konteyner ile terminal bağlantısı kurmak istediğimizde --user root argümanı
eklersek root yetkisiyle bash’e bağlanabiliriz. root Kullanıcısıyla apt
işlemlerini yapabilir ve sistem seviyesinde nodejs kurulumu sağlarız.
Not: Resimde gördüğünüz gibi root yetkisi olmadan :/$ ile diğer türlü :/# ile terminale düşüyoruz.
NodeJs kurulumu için paket listesini güncelleyelim ve sistem
üstünde nodejs kurulumu yapalım ve sonunda node ve npm
versiyonunu görüntüleyelim:
apt-get update
&& apt-get upgrade -y
&& curl -sL https://deb.nodesource.com/setup_12.x | bash -
&& apt-get install -y nodejs
&& node --version
&& npm --version
Çıktımız:
53. Jenkins “NodeJS Plugin” eklentisiyle (plugin) nodejs çalıştırabilir. Bu eklentiyle
Nodejs’in farklı sürümlerini araç olarak (tools) kurabilir ve job içinde shell için
PATH’e kaydeder ve npm, node uygulamalarını çalıştırabilirsiniz.
NodeJs Kurulumu -2
Sistemde kurulu bir nodejs
varsa PATH içinde kurulu NodeJS
uygulamasının bin dizini
içindeki “node” uygulamasına
herhangi bir shell içinden
erişilebilir. Bu en genel ve
temiz çözümdür.
Ama sisteme NodeJS kurma
yetkiniz yok ve sadece
Jenkins’i yönetiyorsanız NodeJS
Plugin ile uygun versiyonu
seçerek
/var/jenkins_home/tools/nodejs.
. içinden kullanabilirsiniz.
pipeline {
agent any
// tools’la içeri alıp kullanıyoruz
tools {nodejs "node_14.14.0"}
stages {
stage('Example') {
steps {
sh 'npm config ls'
}
}
}
}
54. NodeJS İçin Tools Arka Planda Ne Yapar?
NodeJS eklentisi kurulduktan sonra Manage Jenkins > Global Tool
Configuration içinde hangi NodeJS sürümlerini kullanmak istiyorsanız
bir etiketle tanımını yaparsınız. Yandaki örnekte 3 farklı sürüm
için 3 etiket tanımlanmış. Hangisi job içinde kullanılırsa o sürüm
/var/jenkins_home/tools içine indirilir ve shell içinden
erişilebilmesi için geçici PATH içinde tanımlanır. Böylece node veya
npm çağrısı yapıldığında NodeJS uygulamalarına erişilebilinir.
55. Önce terminal ekranına giriş yapalım:
Paket listesini güncelleyip node kurulumu yapalım ve
unutmayalım setup_8.x deprecate olduğu için yerine 10 veya 12
kurmak daha iyi olacaktır:
Ve son çıktı:
Jenkins Konteyner İçine NodeJS Kurulumu
57. Docker Konteyner İçinde Jenkins Slave Çalıştırmak
docker run
-i
--rm
--name agent
--init
jenkins/agent
java -jar /usr/share/jenkins/agent.jar
-i : Keep STDIN open even if not attached
--rm: Docker automatically clean up the container
and remove the file system when the container
exits
--init : konteyner başlatıldığında çalıştırılsın
diye girdiğimiz komutu PID 1 olacak şekilde
başlat. Yani init process olarak başlat.
-v : (Volume Binding) Host makinamızdaki dizinleri
konteynere bağlıyoruz. --rm ile başlattığımız için
konteyner durduğunda içinde yaptığımız her şey
silinecek bu yüzden host makinamızdaki dizinleri
bağlayarak her docker slave başlatıldığında
windows makinamızdaki ssh anahtarları, calisma
dizinleri vs. docker konteynere bağlanacak.
$ docker run
-i --rm
--cpuset-cpus="0-3"
--name agent
-v /c/Users/cem.topkaya/.ssh:/root/.ssh
-v /c/Us../git/calismalar:/home/jenkins/calismalar
-v /c/User..lar/home_jenkins_agent:/home/jenkins/agent
--init
cemkins/agent
59. Git’i Tanıtalım
whereis git
diyerek konteyner içinde git’in yerini buluruz ve
node üstünde Tool Locations içine git’in dosya
yolunu gireriz, hepsi bu.
1
2
61. whereis npm
whereis npm
ile node yüklenmediğini görürüz. Sunum dosyasında node kurulumuyla ilgili komutlar
konteynerin konsoluna bağlanarak çalıştırabiliriz. Ancak unutmayalımki node
yüklemesini konteyner içine yapıyoruz ve eğer --rm anahtarıyla başlattığımız
konteyner, görevi bitince kaldırılır ve yeni konteyner başlattığımızda yine node
kurulumu gerekir.
Veya
jenkins/agent yansısını miras alarak içinde node yüklü yeni bir yansı yaratabiliriz.
FROM jenkins/agent
USER root
RUN apt-get update
&& apt-get upgrade -y
&& curl -sL https://deb.nodesource.com/setup_12.x | bash -
&& apt-get install -y nodejs
&& node --version
&& npm --version
EXPOSE 22 80
USER jenkins
CMD java -jar "/usr/share/jenkins/agent.jar"
#ENTRYPOINT java -jar "/usr/share/jenkins/agent.jar"
63. Jenkins Admin Kullanıcısı Oluşturmak
İlk ekrana girdiğiniz gizli kelimeden sonra önerilen
pluginleri kurar ve ardından kullanıcı tanımlarsınız. Ve
artık jenkins hizmetinize sizin tayin ettiğiniz (örn. 8080)
porttan başlatılır.
69. Github Authentication
Bilgisayarınızda lokalde çalışan bir jenkins olsun.
Kodlarınızı barındırdığınız git adresini projenizin
Source Code Management sekmesine girdiniz.
Jenkins arka tarafta HEAD metoduyla ilgili adrese bir
istek yapacak.
Eğer kullanıcı bilgileriniz geçerli değilse yandaki
hatayı verecek.
Failed to connect to repository : Command "git.exe ls-remote -h -- https://github.com/cemtopkaya/angular-module.git HEAD" returned status code 128:
stdout:
stderr: Logon failed, use ctrl+c to cancel basic credential prompt.
remote: Invalid username or password.
fatal: Authentication failed for 'https://github.com/cemtopkaya/angular-module.git/'
Bu durumda artık github için bir kullanıcı doğrulama yöntemi seçerek devam etmeliyiz.
- Windows Kimlik Yöneticisinde kullanıcı bilgilerinin depolanması
- Username ve Password ikilisi olan credential
- Github Token kullanmak
70. Kullanıcı Bilgileri Yöneticisi
Konsol üstünden github reposunun clone ile çekilmesi sağlandığında Windows
Kimlik Bilgileri Yöneticisi kullanıcı bilgilerini depolayacak ve eğer
Credentials açılır kutusundan bir seçim yapılmamışsa, Jenkins her github
için arka planda yapacağı istekte sistemde kayıtlı olan bu bilgileri
kullanacak.
Github için yapılacak istek başarısızsa aşağıdaki gibi, başarılıysa boş
gövdeli cevap döner:
71. Github Kullanıcı Adı & Şifresi
Sistemde kayıtlı kullanıcı bilgileri yerine belirlediğimiz
credential ile bağlanmak istediğimiz durumdur.
Github reposunu yazdığımız yerde Add düğmesiyle (veya Jenkins
Credential menüsünden) Username with Password tipinde bir
tanımlama yaparız. Kullanıcı adı ve şifresiyle bir credential
oluşturup projenin Source Code Management sekmesinde
Credentials açılır kutusunda seçili hale getirebiliriz.
72. Github Token ile Webhook
(1) Github üstünden bir Token yaratıp Jenkins içinde
yeni bir Credential olarak tanımlarız. (2) Bu kez
Jenkins’in tüm projeleri tarafından kullanılabilecek
şekilde token bilgisini ayarlayacağız
Manage Jenkins / Configure System / Github
içinde az önce oluşturduğumuz TOKEN seçilerek Github
server ile webhook için kullanılacak token ayarlanır.
Oluşturduğumuz token’ın testi için curl -u
username:token https://api.github.com/user komutunu
konsoldan çalıştırabiliriz.
73. Github Ayarı
Github üstündeki bir repoya bağlanmak istersek github sunucu
ayarlarına hangi token ile bağlanacağımızı söylememiz gerekiyor.
Sonrasında projemizin General ayarlarında bu projenin bir Github
projesi olduğunu seçmeli ve Source Code Management içinde git
seçeneğini işaretleyip hangi adresten veri çekeceksek projenin bağlı
olduğu github kaynak kodunun adresini ve hangi branch üstünde
koşacağımızı belirtmeliyiz.
Build ettiğimizde kodun indiğini görürüz.
74. Github Public Repo Ayarı
Projenin (burada ng_form adında freestyle tipinde),
Configure sekmesinden Source Code Management kısmında
Git seçilip, clone yapmak için kullandığımız adresini
yapıştıralım. Projeyi build ettiğimizde kodlar
çekilerek workspace içine dosyalarımız konulacak.
1 2
3
4
5
75. Github Private Repo Ayarı
Önce kayıtlı şifreyi silelim ki; github üstünde private repomuza
giderken şifre sorulur hale gelsin ve yerelde çalışan jenkins için de
şifre istensin. Böylece Github token yaratma yoluna gidelim.
git config --global credential.helper store ile kullanıcı adı ve
şifresini bilgisayara depolayacağız demiş oluruz. Kullanıcı adı ve
şifresini ilk girdiğimiz anda önce %USERPROFILE.git-credentials
dosyasına https://gitKullaniciAdi:gitSifresi@github.com bilgisi
yazılır ardından Windows Kimlik Bilgileri Yöneticisi bu bilgileri ön
bellekler.
Eğer Windows Kimlik Bilgileri Yöneticisi üstünden siler tekrar git
clone ile yerele kodları çekmek istediğimizde kullanıcı bilgileri
WinKimlikBilgYöneticisi üstünden okunmak istenir, bulunamayınca .git-
credentials dosyasından veriler okunur ve WinKimlikBilgYöneticisi
üstüne tekrar yazılır.
Bir sonraki clone işleminde WinKimlikBilgYöneticisi kullanıcı
bilgilerini servis eder ve .git-credentials dosyasına gerek kalmadan
kullanıcı girişi sağlanmış olur.
82. Sıralı Olarak Projeleri Build Etmek
1. Görevi build
ettiğimizde konsol
çıktısında 2.nin sıraya
girdiğini yazar.
Aynı şekilde ana ekranda
“Build Queue” kısmında da
sıradaki görevleri
görebiliriz.
86. Gerekenler
- VirtualBox veya VMware Player kurula
- En hafifinden linux kurulu bir disk indirilip sanal
makine (virtual machine) çalıştırıla
- Sanal makine içine java kurula
- openssh-server linux içine kurulup dışarıdan erişilebilir
hale getirile
- jenkins içinde yeni vm’in bilgileriyle bir node/agent
oluşturula
88. VirtualBox Ağ Ayarları
VirtualBox üstünde 3 ağ tanımlı. Sanal
makinamızın 1. ağ bağdaştırıcı NAT ile internete
bağlanması için iken 2. ağ bağdaştırıcı host ile
doğrudan bağlantı kurması için.
Not: Farklı ayarlar da yapılabilir
89. Linux Ağ Ayarları
nmtui kullanıcı arayüzü, dhclient veya ifconfig ile ağ
işlemlerini yapabiliriz
Ağ Ayarlarını Görüntülemek
DHCP Sunucusuna “merhaba” gönderip iletişimi görelim
$ dhclient -v
$ ifconfig -a
Ağ Ayarlarını Tazelemek
$ sudo dhclient -v -r
$ ifconfig ağ_adı down
$ ifdown ağ_adı
$ ifconfig ağ_adı up
$ ifup ağ_adı
Ağ Servisini Yeniden Başlatmak
$ /etc/init.d/nscd restart
90. Sadece Openjdk’yı kaldırmak istiyorsak:
$ sudo apt-get remove openjdk*
Openjdk’yı tüm bağımlılıklarıyla kaldırmak istiyorsak:
$ sudo apt-get remove --auto-remove openjdk*
Openjdk ve ayar dosyalarını kaldırmak istiyorsak:
$ sudo apt-get purge openjdk*
Openjdk, bağımlılıkları ve ayar dosyalarını kaldırmak
istiyorsak:
$ sudo apt-get purge --auto-remove openjdk*
Java Yüklemek & Kaldırmak
Repoyu güncelleyerek java indirebileceğimiz adresleri
çekeriz:
$ apt-get update
$ apt install oracle-java11-installer
$ apt install default-jre
$ apt install openjdk-11-jre-headless
$ apt install openjdk-8-jre-headless
$ apt install openjdk-8-jdk-headless
Sadece openjdk-8-jdk-headless paketinin kurulması hem
java hem javac için yeterli olacaktır.
Sürüm Kontrolü
java Runtime (JRE) : $ java -version
Java Development Kit (JDK): $ javac -version
91. Yeni Kullanıcı Tanımlamak
Master olan Jenkins projelerin
tanımlandığı, ayarlarının yapılıp
yapılandırmak için tetiklendiği ve
çıktıların gözlemlendiği ilk
kurulumumuzdur.
Diğer sunucular (node/agent’lar) ise
agent.jar isimli dosyanın sürekli çalışıp
master jenkins tarafından gelen işlerin
yapıldığı düğümlerdir. Bu düğümlere
job’ların yüklenmesi için bir kullanıcı
tanımlanır ve master jenkins, ssh
marifetiyle bağlanarak ilgili agent.jar
dosyasını yükler ve çalıştırır.
agent.jar Dosyası tabiatı gereği Java
kurulumu da gerektirdiği için önceden
yüklenmiş olması gerekir.
Kullanıcı Silmek
Silinmek istenen kullanıcı aktif bir processleri killall ile
durdurulur veya zorla (force) silmek istediğimizi -f argümanı ile
veririz.
$ killall -u kullanıcı_adı
$ userdel -f --remove-home kullanıcı_adı
Yeni Kullanıcı Oluşturmak
$ useradd -m cemkins
Yeni Kullanıcıya Şifre Atamak
cemkins kullanıcısının yeni şifresini iki kez girilir ve yeni
kullanıcıyla sisteme giriş yapılar.
$ passwd cemkins
Yeni Kullanıcı Profilinde Jenkinse Özel Dizin Oluşturmak
Yeni kullanıcının profili /home/kullanıcıAdı dizininde oluşacaktır.
Jenkins bu klasörün altına remote.jar dosyası ve remote dizini
oluşturacağı için derli toplu olsun diye biz jenkinsKokDizini diye
bir klasör oluşturalım.
$ mkdir jenkinsKokDizini
92. SSH Kurulumu
ssh Server Kurulur
$ sudo apt-get install openssh-server
ssh Servisi Faal Edilir
$ sudo systemctl enable ssh
ssh Servisi Başlatılır
$ sudo systemctl start ssh
Servisin Durumu Kontrol Edilir
$ sudo systemctl status ssh
ssh Bağlantısı Test Edilir
$ ssh root@makina-adı|ip
Dışarıdan Bağlanmak İçin Ayar Yapılandırılır
# ile başlayan satırlar yorum satırı demektir. Bazı komutların yorum
satırı olmadığı belirtmemiz gerekecek:
$ vi /etc/ssh/sshd_config
#PermitRootLogin prohibit-password
satırı aşağıdaki hale getirilir
PermitRootLogin yes
#PasswordAuthentication yes
yorum satırı olmaktan çıkarılır
PasswordAuthentication yes
Eğer ssh key ile giriş yapılabilsin istiyorsak aşağıdaki satırlar
yorum satırı olmaktan çıkarılır
#PubkeyAuthentication yes
#AuthorizedKeysFile .ssh/authorized_keys
ssh Secure Shell anlamıa gelir ve telnetin şifrelenmiş halidir.
sshd ise servis (daemon) halinde çalışan ssh sunucusudur.
sshd_config içinde yapılan değişikliklerin etkili olması için servisin
tekrar başlatılması gerekir.
93. ssh Sorun Giderme
SSH bağlantısı sırasında “Host key verification
failed.*” hatası alınırsa, bağlantı kurulacak
makina için “bilinen hostlar” dosyasında
güncelleme yapmak için $ ssh-keygen -R
192.168.99.102 komutu çalıştırılır. IP adresi,
bağlantı kurmak istediğiniz uzak makinanın adresi
veya ismidir.
known_hosts dosyası .ssh dizini altındadır.
$ ssh-keygen -R <ip | host_adı>
Komutuyla her uzak bağlantı için bir key üreterek
güvenilir bağlantılar listesine ekler.
SSH servisini otomatik üretiyorduk ve
diyelimki ayarlar dosyası çalışmaz hale
geldi ve aşağıdaki hatayı almaya
başladık:
Unit sshd.service could not be found
Tüm openssh-server’ı kaldırmak yerine
konfigurasyon dosyalarını kaldırıp tekrar
kurulum yapmak yeterli olacaktır.
$ apt-get purge openssh-server
$ apt-get install openssh-server
Elbette tüm ssh server’ın kaldırılıp
tekrar kurulmasında da sakınca yok
$ apt-get remove --purge openssh-server
$ apt-get install openssh-server
$ service ssh restart
$ service ssh status
94. Docker Jenkins İçin Plug-In Kurulumunda Hata
Docker versiyonu jenkins/jenkins yansısını
kullanıyor ve plugin güncellemesi yapamadığını
görüyorsanız jenkinsin pluginleri indirebileceği
adresi ortam değişkeni olarak jenkins kabınıza
vermeniz gerekiyor.
Bunu 3 farklı adresi verip deneyebilirsiniz:
1. http://ftp-nyc.osuosl.org/pub/jenkins
2. http://mirrors.jenkins-ci.org
3. https://updates.jenkins.io/download/plugins
Kitematik ile veya docker kabınızı çalıştırırken
yapabilirsiniz
docker run --name jenkinscim
....
-e JENKINS_UC_DOWNLOAD 'http://ftp-
nyc.osuosl.org/pub/jenkins' jenkins/jenkins
95. Agent Launch Sorun Giderme
Slave node üstünde ssh kurulu ancak
java yok!
> Java kurulur ve tekrar denenir.
Checking java version of /home/cemkins/jenkins_kok_dizini/jdk/bin/java
Couldn't figure out the Java version of /home/cemkins/jenkins_kok_dizini/jdk/bin/java
bash: /home/cemkins/jenkins_kok_dizini/jdk/bin/java: No such file or directory
Çalıştırmak istediği komuş aşağıda göreceğiniz üzere remoting.jar dosyasını
ayaklandırarak master üstünden slave ile konuşabileceği bir iletişim kanalı açmak:
[SSH] Starting agent process:
cd "/home/cemkins/jenkins_kok_dizini" && /usr/bin/java -jar remoting.jar -workDir /home/cemkins/jenkins_kok_dizini -
jar-cache /home/cemkins/jenkins_kok_dizini/remoting/jarCache
- Yukarıdan anlayacağınız üzere /usr/bin/java ile çalıştırılabilir java dosyasına erişmek ve -jar argümanı ile
remoting.jar dosyasını ayaklandırmak istediğini söyleyecek.
- remoting.jar dosyasına çalışılacak dizini ve -jar-cache ile ön bellek dizinini vermek istiyor
Java yolunu öğrenmek için $ whereis java konsola yazılır ve uygun dosya yolu bulunur ve Advanced düğmesiyle açılan bölümde
JavaPath etiketli alana java’nın yolu yazılır.
Not: Eğer yüklü değilse java yükleme kısmına bakabilirsiniz.
97. Jenkins çeşitli formlarda saklanabilen tüm
credential bilgilerini Credentials menüsünde
saklıyor.
Node tanımında login olacağımız linux
makinasındaki cemkins kullanıcısının bilgilerini
Credentials satırında Add düğmesiyle(1) açılan
ekranda(2) tanımlıyoruz.
SSH yaptığımızda, sunucu makine /etc/ssh içinde
tanımlı kendi HOST KEY’ini gönderir, SSH istemci
makinesi ise known_hosts dosyasında bu anahtarı
bulursa bağlantı kurulur. Bulamazsa uzak makinenin
HOST KEY bilgisini known_hosts dosyasına eklemek
istermiyiz diye sorar. Böylece daha sonraki
bağlantılarda ssh server doğrulanır.
1
3
2
103. openssh-server Kurulum Detayları
$ apt-get install openssh-server
…
The following additional packages will be installed:
openssh-sftp-server ssh-import-id
Suggested packages:
molly-guard monkeysphere rssh ssh-askpass
The following NEW packages will be installed:
openssh-server openssh-sftp-server ssh-import-id
...Fetched 389 kB ...Unpacking openssh-sftp-server …
Preparing to unpack .../openssh-server_1%3a7.6p1-4ubuntu0.3_amd64.deb ...
...Preparing to unpack .../ssh-import-id_5.7-0ubuntu1.1_all.deb ...
...Creating config file /etc/ssh/sshd_config with new version
...Creating SSH2 RSA key; this may take some time ...
2048 SHA256:Fy/9w38/BzTJCVEdu7czKDg5DcwHSrQT/2/fpTnHufc root@osboxes (RSA)
Creating SSH2 ECDSA key; this may take some time ...
256 SHA256:oZaVFTz0Eh4PtY4pTFkoAjlcjoqb+YJJppDLtQiUtl8 root@osboxes (ECDSA)
Creating SSH2 ED25519 key; this may take some time ...
256 SHA256:TSmPKhMlzRDys5GQSK9mC8fLaRmDEO7dIlLLGdZDPAw root@osboxes...
Created symlink /etc/systemd/system/sshd.service → /lib/systemd/system/ssh.service.
Created symlink /etc/systemd/system/multi-user.target.wants/ssh.service → /lib/systemd/system/ssh.service.
...Processing triggers for systemd (237-3ubuntu10.39) ...
105. ssh Anahtarları Oluşturmak ve Kullanıma Açmak
1) SSH Anahatarı Oluşturmak: ssh-keygen komutu
çalıştırıldığında, yeni ssh anahtarının adını soracak.
- Eğer enter ile geçersek $HOME dizini içinde .ssh
klasörünü ve içerisine id_rsa dosyasını gizli anahtarı
(private key), id_rsa.pub dosyasını da public anahtarı
saklayacak şekilde oluşturur.
- Eğer bir dosya adı girersek bu kez $HOME dizini içinde
dosyaAdi adında private, dosyaAdi.pub adında public
anahtarları oluşturur.
- Mesela github’a bağlanmak için bir ssh anahtarı
yaratıyor olalım ve dosya adına github_cemtopkaya
diyelim. Bu durumda $HOME/github_cemtopkaya ve
$HOME/github_cemtopkaya.pub adında private ve
public anahtarları oluşturacak.
Tabi bu dosyaları şifreleyecek ve sadece bizim bileceğimiz bir
passphrase (parola) girmemizi iki kez istedikten sonra dosyalar
oluşturulmuş olacak.
$ ssh-keygen -t rsa -b 4096 -C "cem.topkaya@hotmail.com"
2) SSH Agent’a SSH Anahtarlarını Kaydetmek: ssh-keygen
komutuyla oluşan anahtarları ssh-agent üstüne kaydederek
kullanıma sunmalıyız. Ama önce ssh-agent çalışıyor mu diye
bakalım.
$ eval "$(ssh-agent -s)"
Şimdi ürettiğimiz anahtarları ekleyeceğiz. Örneğin github,
gitlab ve bitbucket için farklı public ve private
anahtarlar üretmiş olalım ve hepsini bir kerede ekleyelim.
$ ssh-add github_cemtopkaya bbCemTopkaya .ssh/id_rsa
$ sudo -su giris_yapilan_kullanici_adi
$ ssh-keygen -t rsa -b 4096 -C "cem.topkaya@hotmail.com"
$ eval "$(ssh-agent -s)"
$ ssh-add github_cemtopkaya bbCemTopkaya .ssh/id_rsa
106. Github & Jenkins SSH Anahtar Ayarları
Jenkins üstünde Global Credential oluşturuyoruz.
- SSH Username with private key seçeneğiyle
- Username ile bağlanacağımız sistemin kullanıcı adı,
- ID bilgisini biz yazarsak anlamlı ve eşsiz bir tanımlama, boş bırakırsak UUID değer atanır,
- Private Key kısmına bir önceki sayfada hazırladığımız SSH anahtarının private kısmını
yapıştırırız. Böylece Jenkins privte anahtar içeren dosyayı aramak, dosya yoluna bağlı
kalmak zorunda olmayacaktır.
- Passphrase ise ssh-keygen ile SSH anahtarını oluştururken bize gizli bir parola girmemizi
istediğinde yazdığımız metin.
Github üstünden kişisel ayarlardan SSH and GPG keys sekmesinde ise Key kısmına SSH
anahtarımızın public anahtarının içeriğini yapıştırıyoruz ve tanımlama için title alanına ayrıştırılabilir bir
metin girilir.
117. String
Java'da olduğu gibi, karakter verileri çoğunlukla
java.lang.String sınıfı kullanılarak işlenir.
Groovy strings iki çeşittir:
- plain strings,
- GStrings.
Düz dizeler java.lang.String ve GStrings
ise groovy.lang.GString örnekleridir.
GStrings, ifadeleri (genellikle birçok komut
dosyası dilinde dize enterpolasyonu olarak
adlandırılır) çalışma zamanında çözümlenmesine
ve değerlendirilmesine olanak tanır.
Dizeler tek, çift, üçlü tek tırnak veya üçlü çift
tırnak kullanılarak tanımlanabilir. Yalnızca çift (“)
(çift ve üçlü çift) alıntı dizeler enterpolasyonu
destekler.
Üçlü tırnaklı (üçlü tekli ve üçlü çiftli) dizeler çok
satırlıdır ve dizenin içeriğini, çizgi veya yeni satır
kaçış karakterleri olmadan birkaç parçaya
bölmeye gerek kalmadan, çizgi sınırlarına
dağıtabilirsiniz.
Çift tırnak (“) (çift tırnak ve üçlü çift tırnak) ile
tanımlanan dizeler enterpolasyonu destekler. Bu,
herhangi bir Groovy ifadesini belirtilen konumdaki
bir string ile değiştirmenize olanak tanır. Bunlara
GStrings denir.
Bu, ${} sözdizimi kullanılarak gerçekleştirilir.
GStrings, sabit ve dinamik parçaları (değerleri)
aşağıdaki örnekte gösterildiği gibi ayrı ayrı
yakalamak için farklı şekilde uygulanır.
120. String Manipulasyonları
+ Operator
'My name is ' + first + ' ' + last
GString
"My name is $name"
Interpolasyon
"My name is ${name}"
concat() Fonksiyonu
'My name is '.concat(first).concat(' ').concat(last)
leftShift() veya << Operator
'My name is ' << first << ' ' << last
StringBuilder() Tipi
new StringBuilder().append('My name is ').append(first).append(' ').append(last)
StringBuffer() Tipi
new StringBuffer().append('My name is ').append(first).append(' ').append(last)
Çok Satırlı String
name.first = '''
Joe
Smith
''';
name.last = 'Junior'
.split()
String[] arr = metin.split()
arr.each { b -> println(b) }
122. List
Liste, veri öğelerinin bir koleksiyonunu
saklamak için kullanılan bir yapıdır.
Groovy'de Liste, bir dizi nesne başvurusu
içerir. Listedeki nesne başvuruları,
dizideki bir konumu işgal eder ve bir
tamsayı dizini ile ayırt edilir.
Dizin esasına göre öğe ekleme ve silme
yöntemlerini içeren Koleksiyonun bir alt
arabirimidir.
Groovy listeleri düz JDK
java.util.List dir, çünkü Groovy
kendi koleksiyon sınıflarını tanımlamaz.
Çok boyutlu listeler de oluşturabilirsiniz.
Değerleri virgülle sınırlayan ve köşeli
parantez içine alan bir liste
başlatabilirsiniz. Heterojen türlerin
değerlerini içeren listeler de
oluşturabilirsiniz.
- Listenin ilk öğesine sıfır tabanlı sayım üzerinden
erişebilirsiniz: hetero [0]
- Listenin son öğesine negatif bir dizinle erişebilirsiniz: hetero [-
1]
- Listeye bir öğe ekleyin: numbers [3] = 5
- Listenin boyutu: numbers.size () == 4
126. Loop
for Loop
for (i = 0; i <3; i++) {
System.out.println("Hello World")
}
for Loop With Collection
List<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
for (String item : list) {
System.out.println(item)
}
For Loop with Upto
def c = {
println it
}
1.upto(4, c)
Çıktı
1
2
3
4
1.upto(4, {
println "Number ${it}"
})
For Loop with Step
0.step 5, 1, {
println it
}
Çıktı
0
2
4
0.step 5, 2, {
println it
}
For Loop with Times
3.times {
println "Hi ${it}"
}
Çıktı
Hi 0
Hi 1
Hi 2
def n = 3
n.times {
println "Hello ${it}"
}
For in
for(item in ["A", "B"])
{
println item
}
Çıktı
1
2
3
for (number in 1..3 )
{
println number
}
For map
def map = [a1:'b1', a2:'b2']
for ( item in map ) {
println item.key
println item.value
println
}
Çıktı
a1
b1
a2
b2
collectEntries Loop
def index = 0
def result = ["bir":1,"iki":2].collectEntries { key, val->
return ["${key}_${++index}": val]
// veya aşağıdaki gibi return olmaksızın dönüş sağlanabilinir.
// ["${key}_${++index}": val]
}
println result // [bir_1:1, iki_2:2]
127. Düzenli İfadeler RegExp
~// ile Düzenli İfade Tanımlamak
def ipAddress = ~/([0-9]+.[0-9]+.[0-9]+.[0-9]+)/
println ipAddress.class.name // java.util.regex.Pattern
ipAddress değişkeni otomatik olarak regex.Pattern olmuş!
Eşleşti mi?
def nameRegex = ~’john’
println nameRegex.matcher("john").matches() // true
def ipAddressRegex = ~/([0-9]+.[0-9]+.[0-9]+.[0-9]+)/
println ipAddressRegex.matcher("127.0.0.1").matches() // true
129. SH
sh Komutu
script (opt.boolean):
returnStdout (opt.boolean): Returns the standard output stream with a default encoding
of UTF-8 (alternative encoding is optional)
returnStatus (opt. boolean): Returns the exit status (integer) of the PowerShell
script
0 Olmayan exit kodları hatalı olarak script sonlandı demektir. Buna göre tüm jenkins
build’i hakkında işaretleme yapabilir, sonraki işlere devam edebilir ya da
kesebiliriz.
def statusCode = sh script:script, returnStatus:true
currentBuild.result = 'FAILURE'
currentBuild.result = 'UNSTABLE'
label (opt. string): Label to be displayed in the pipeline step view and blue ocean
details for the step instead of the step type. So the view is more meaningful and
domain specific instead of technical.
encoding (opt. string): Eğer returnStdout: true olarak işaretlenmişse sh’ın çıktısını
okuyacağız demektir ve okunacak metnin kodlaması default olarak UTF-8 olmasına rağmen
değiştirilebilir (encoding: 'UTF-8')
For Loop with Upto
def c = {
println it
}
1.upto(4, c)
Çıktı
1
2
3
4
1.upto(4, {
println "Number ${it}"
})
For map
def map = [a1:'b1', a2:'b2']
for ( item in map ) {
println item.key
println item.value
println
}
Çıktı
a1
b1
a2
b2
try {
npmViewOutput = sh(returnStdout: true, script: "npm view olmayan_paket")
} catch (Exception e) {
echo "${e.message}"
}
135. Environment Variable
İşletim sisteminin ortam değişkenlerine windows için
%DeğişkenAdı% , linux için $DeğişkenAdı ile erişiyoruz.
Ortam değişkenleri tüm hat içerisinden erişilebilen yerel ve
global değişkenlerdir.
İşletim sistemi seviyesinde tanımlı env. vars’a erişmek için
windows os üstünde koşan bir batch için $env.PATH,
136. Nasıl ve hangi sırayla eziliyor env vars?
def PATH = "En üstte tanımlı global degisken"
pipeline {
agent any
stages {
stage("a"){
environment{ PATH = "local env. var. PATH" }
steps{
/**
* $env.XXX ile değişkenler;
* varsa
* önce local env,
* sonra Jenkins env
* sonra OS env
* seviyesinde PATH değişkenin arar
*
* localde env.PATH bulur ve onu yazar **/
echo "$env.PATH"
}
}
stage("b"){
// önce değikenlerde arar ve globalde PATH değişkeni bulur
steps{ echo "$PATH" }
}
stage("c"){
environment { PATH = "yerel env içinde tanımlı" }
// env.PATH olmadığı için önce değikenlerde arar. Local'de PATH adında değişken yok!
// globalde (en üstte) tanımlı PATH değişkenini bulur
steps{ echo "$PATH" }
}
stage("ç"){
// Local env de PATH yok. Jenkins seviyesinde env.PATH bulur onu yazar
steps{ echo "$env.PATH" }
}
stage("d"){
environment{ PATH = "Ezdi mi ne?" }
// local env.PATH bulur ve onu yazar
steps{ echo "$env.PATH" }
}
}
Env Var Sıralaması
$env.XXX ile erişilmek istenen ortam
değişkenleri aşağıdaki sıralama ile
aranır. İlk bulunduğu yerde değeri
kullanılır. Bulunamazsa değer olara null
kullanılır.
stage("a"){
environment{
PATH = "local env. var. PATH"
}
steps{
/**
* $env.XXX ile değişkenler;
* varsa
* önce local env,
* sonra Jenkins env
* sonra OS env
* seviyesinde PATH değişkenin arar
**/
echo "$env.PATH"
}
137. Global ve Local Değişkenler ve Local Ortam Değişkenleri
def global_degisken = "En üstte tanımlı global degisken"
pipeline {
agent any
stages {
stage("a"){
environment{
aDegiskeni = "A"
}
steps{
echo "------- STAGE A >>>>>>>>>>>"
echo "global_van: $global_degisken"
echo "local env aDegiskeni: “
echo "$aDegiskeni = $env.aDegiskeni = ${env.aDegiskeni} = ${aDegiskeni}"
/** bDegiskeni tanımlı olmadığı için hata verir
* groovy.lang.MissingPropertyException:
* No such property: bDegiskeni for class: groovy.lang.Binding
* echo "local env bDegiskeni: $bDegiskeni - $env.bDegiskeni"
*/
echo "<<<<<<<<<< STAGE A --------------"
}
}
stage("b"){
environment{
bDegiskeni = "B"
}
steps{
echo "------- STAGE B >>>>>>>>>>>"
echo "global_van: $global_degisken"
/** aDegiskeni yerelde veya globalde tanımlı bir değişken olsa erişilebilir.
* Oysa A aşamasında env'e bağlı yaratlıyor ancak burada env olmadan
* yani $aDegiskeni veya = ${aDegiskeni} diyerek erişilmek isteniyor
* Bu yüzden istisna fırlatacak ve build son bulacak.
* groovy.lang.MissingPropertyException:
* No such property: aDegiskeni for class: groovy.lang.Binding
*/
echo "local env aDegiskeni: $env.aDegiskeni = ${env.aDegiskeni}"
echo "local env bDegiskeni: $bDegiskeni - $env.bDegiskeni"
echo "<<<<<<<<<< STAGE B --------------"
}
}
}
}
138. env-vars.html
${YOUR_JENKINS_HOST}/env-vars.html
shell Komutuyla
pipeline {
agent any
stages {
stage("Env Variables") {
steps {
sh "printenv"
}
}
}
}
ortam değişkenlerine değer atamak
pipeline {
agent any
environment { FOO = "bar" }
stages {
stage("Env Variables") {
environment { NAME = "Alan" }
steps {
echo "FOO = ${env.FOO}"
script {
env.TEST_VARIABLE = "some test value"
}
echo "TEST_VARIABLE = ${env.TEST_VARIABLE}"
withEnv(["BASKA_ENV_VAR=başka değer"]) {
echo "BASKA_ENV_VAR = ${env.BASKA_ENV_VAR}"
}
} } } }
ortam değişkenlerinde BOOLEAN
script {
if (env.IS_BOOLEAN) {
echo ""false" String Boolean.TRUE değerine dönüşür"
}
if (env.IS_BOOLEAN.toBoolean() == false) {
echo ""false".toBoolean() ise Boolean.FALSE olur"
}
}
ortam değişkenlerine shell’den değer atamak
pipeline {
agent any
environment {
LS = "${sh(script:'ls -lah', returnStdout: true)}"
}
stages {
stage("Env Variables") {
steps {
echo "LS = ${env.LS}"
}
}
}
}
ortam değişkenlerini okumak
Yerelde tanımlı olmayan değişkeni global de ve en üstte ortam değişkenlerinde arar.
pipeline {
agent any
stages {
stage("Env Variables") {
steps {
echo "1. Yöntem: ${env.BUILD_NUMBER}"
echo "2. Yöntem: ${BUILD_NUMBER} -> ${BUILD_NUMBER}"
sh 'echo "3. Yöntem: $BUILD_NUMBER"'
} } } }
139. pipeline {
agent any
environment {
FOO = "bar"
NAME = "Joe"
}
stages {
stage("Env Variables") {
environment {
NAME = "Alan" // overrides pipeline level NAME env variable
BUILD_NUMBER = "2" // overrides the default BUILD_NUMBER
}
steps {
echo "FOO = ${env.FOO}" // prints "FOO = bar"
echo "NAME = ${env.NAME}" // prints "NAME = Alan"
echo "BUILD_NUMBER = ${env.BUILD_NUMBER}" // prints "BUILD_NUMBER = 2"
script { env.SOMETHING = "1" // creates env.SOMETHING variable }
}
}
stage("Override Variables") {
steps {
script {
env.FOO = "IT DOES NOT WORK!" // it can't override env.FOO declared at the pipeline (or stage) level
env.SOMETHING = "2" // it can override env variable created imperatively
}
echo "FOO = ${env.FOO}" // prints "FOO = bar"
echo "SOMETHING = ${env.SOMETHING}" // prints "SOMETHING = 2"
withEnv(["FOO=foobar"]) { // it can override any env variable
echo "FOO = ${env.FOO}" // prints "FOO = foobar"
}
withEnv(["BUILD_NUMBER=1"]) {
echo "BUILD_NUMBER = ${env.BUILD_NUMBER}" // prints "BUILD_NUMBER = 1"
}
}
}
}
}
140. Globalde Tanımlı Özel Env. Var.
Jobların erişmesini istediğiniz
temel değerleri global env.
vars. içinde
tanımlayabilirsiniz. Örneğin
sprint koşunuzun numarası,
üretilecek projenin versiyon
numarası vs. için değerleri
globalde bir kere tanımlayıp
tüm projeler için globaldeki
değişkenler gibi (örneğin
BUILD_NUMBER’a WORKSPACE’e
erişir gibi) erişebilirsiniz.
142. Declrative Jenkins
Yeni bir proje
başlatıyor ve
pipeline
türünde seçerek
adını
yazıyoruz.
Daha sade bir yapıda gelecek. Pipeline
içinde scriptimizi yazıyoruz. Yardıma
ihtiyacımız olduğu yerlerde “Pipeline
Syntax” bağlantısından bizim için script
üretmesini isteyebiliriz.
143. pipeline {
}
İlk ifademiz pipeline olacak
ve tüm yönergelerimiz
pipeline bloğunun içinde
olmalıdır
Declarative Pipeline’ı Anlamak
pipeline {
agent any
}
Herhangi uygun agent üstünde
çalışacak diye işaretledik.
Etikete göre agent seçmek:
agent { label '!windows' }
pipeline {
agent any
tools {
git ‘localGit’
jdk ‘localJava’
nodejs ‘localNode’
}
}
Jenkins'te kullanılacak
araçları tools ile belirtiriz.
Araçlar (tools), Jenkins
düğümünde yüklü olan
yapılandırma (build)
araçlarından başka bir şey
değildir.
Global Tool Configuration
altında belirttiğimiz
çalıştırılabilir uygulamaların
yollarını takma adlarla
tanımlamıştık. tools Altındaki
araçlar için bu takma adları
kullanıyoruz.
pipeline {
agent any
environment {
global_degisken = 'true'
}
stages {
stage ('derle') {
environment {
yerel_degisken = '12'
}
steps {
echo 'Değer: '+yerel_degisken
}
}
}
}
Ortam değişkenleri global veya stage
özelinde ayarlanabilir. Stage başına
ayarlanmış değişkenler sadece tanımlı
olunan stage için geçerli olacaktır.
Global Tool Configuration altında
belirttiğimiz çalıştırılabilir
uygulamaların yollarını takma adlarla
tanımlamıştık. tools Altındaki
araçlar için bu takma adları
kullanıyoruz.
DSL ile Jenkins Script arasındaki fark;
daha kolay kodlama yapabileceğimiz
Domain Specific Language olarak
tanımlayabiliriz.
144. Declarative Jenkins Pipeline
(1) Pipeline türünde bir proje
başlatalım. İçinde Jenkinsfile (4)
adında dosya ve aşamaları
barındıran bir script dosyası da
olacak github projesi (2)
oluşturalım. Jenkins job’ının
içinde Pipeline kısmında bir
Source Control Management (3)
üstünden Jenkinsfile dosyasını
çekeceğimizi belirtelim.
Çalıştırdığımızda git çekilir ve
Jenkinsfile çalıştırılır(5).
1
2
3
4
5
145. bat 'powershell -noexit "& "".run-tests.ps1"""'
steps {
echo "build içindeki steps"
bat "echo %path%"
bat "sh --help"
bat "npm --version && npm
start"
}
'cmd' is not recognized as an internal or external command, operable program
or batch file.
İster stage içinde ister tüm pipeline içindeki environment ayarına
cmd.exe dosyasını erişilebilir hale getirmeli:
environment {
PATH = "C:WINDOWSSYSTEM32;"
}
'npm' is not recognized as an internal or external command, operable program
or batch file.
npm adında çalıştırılabilir dosyayı erişilebilir hale getirmek için
NodeJS aracını tools altına eklemeli:
tools {
nodejs "node_js" // Global Conf. Tools altında tanımlı araç adı
}
Ok-Cancel Sorusu sormak için input message kullanılır
input message: "Devam etmek için Proceed bağlantısına tıkla, iptal için Abort'a tıkla"
pipeline {
agent none
stages {
stage('Integration Test') {
agent { label
'windows_agent' }
steps {
script {
docker.image('mongo:3.4').withRun(' -p
27017:27017') { c ->
sh "echo
ayaklandı"
}
}
}
}
}
}
148. try-catch-finally
stage('checkout') {
try {
…
if (your condition) {
autoCancelled = true
error('Kritik hata oluştu')
}
} catch (e) {
if (e.message == "Devam edilecek istisna") {
currentBuild.result = 'ABORTED'
echo('return yaparsak sonraki stage çalışır')
return
}
echo('throw yaparsak sonraki stage çalışmaz')
throw e
} finally {
echo('her şeye rağmen çalıacak satır')
}
}
149. retry(n)
retry(2) {
try {
prepareEnvironment()
setupBuildEnvironment()
// sets up environment if it is not present yet
runBuild()
} catch (e) {
echo 'Err: Build failed with Error: ' +
e.toString()
echo ' Trying to build with a clean Workspace'
removeOldBuildEnvironment()
throw e
} finally {
cleanupEnvironment()
}
}
150. catchError
Birden fazla projenin kullandığı ortak kütüphanede mi değişiklik yaparak hepsini etkilemek istersiniz yoksa
tek tek her projeye gidip değişiklik mi yapmak istersiniz?
152. Neden Shared library?
Birden fazla projenin kullandığı ortak kütüphanede mi değişiklik yaparak hepsini etkilemek istersiniz yoksa
tek tek her projeye gidip değişiklik mi yapmak istersiniz?
Paylaşılan kitaplık deposu klasör yapısına sahiptir.
(root)
+- src # Groovy source files
| +- org
| +- foo
| +- Bar.groovy # for org.foo.Bar class
+- vars
| +- foo.groovy # for global 'foo' variable
+- resources # resource files
| +- org
| +- foo
| +- bar.json # static helper data for org.foo.Bar
https://www.computerhope.com/unix/uifconfi.htm
https://www.computerhope.com/unix/ifup.htm
-a Display information for all network interfaces, even if they are down.
-s Display a short list in a format identical to the command "netstat -i".
-v Verbose mode; display additional information for certain error conditions.
interface The name of the interface. This is usually a driver name followed by a unit number, for example "eth0" for the first Ethernet interface. If your kernel supports alias interfaces, you can specify them with eth0:0 for the first alias of eth0. You can use them to assign a second address. To delete an alias interface, use ifconfig eth0:0 down. Note: for every scope (i.e. same net with address/netmask combination) all aliases are deleted, if you delete the first (primary).
up This flag causes the interface to be activated. It is implicitly specified if an address is assigned to the interface.
down This flag causes the driver for this interface to be shut down.
[-]arp Enable (or disable, if the "-" prefix is specified) the use of the ARP protocol on this interface.
[-]promisc Enable (or disable, if the "-" prefix is specified) the promiscuous mode of the interface. If promiscuous mode is enabled, all packets on the network will be received by the interface.
[-]allmulti Enable or disable all-multicast mode. If multicast mode is enabled, all multicast packets on the network will be received by the interface.
metric N This parameter sets the interface metric, which is used by the interface to make routing decisions. N must be an integer between 0 and 4294967295. If you're not sure what a network metric is, or whether you should change it, you can safely leave this setting alone.
mtu N This parameter sets the MTU (maximum transfer unit) of an interface. This setting is used to limit the maximum packet size transferred by the interface. If you're not sure about it, you can safely leave this setting alone.
dstaddr address Set the remote IP address for a point-to-point link (such as PPP). This keyword is now obsolete; use the pointopoint keyword instead.
netmask address Set the IP network mask for this interface. This value defaults to the usual class A, B or C network mask (as derived from the interface IP address), but it can be set to any value.
add address/prefixlen Add an IPv6 address to an interface.
del address/prefixlen Remove an IPv6 address from an interface.
tunnel aa.bb.cc.dd Create a new SIT (IPv6-in-IPv4) device, tunnelling to the given destination.
irq address Set the interrupt line used by this device. Not all devices can dynamically change their IRQ setting.
io_addr address Set the start address in I/O space for this device.
mem_start address Set the start address for shared memory used by this device. Only a few devices need this.
media type Set the physical port or medium type to be used by the device. Not all devices can change this setting, and those that can vary in what values they support. Typical values for type are 10base2 (thin Ethernet), 10baseT (twisted-pair 10Mbps Ethernet), AUI (external transceiver), etc. The special medium type of auto can be used to tell the driver to auto-sense the media. Again, not all drivers can do this.
[-]broadcast [address] If the address argument is given, this will set the protocol broadcast address for this interface. Otherwise, it will set (or clear, if the "-" prefix is used) the IFF_BROADCAST flag for the interface.
[-]pointopoint [address] This keyword enables the point-to-point mode of an interface, meaning that it is a direct link between two machines with nobody else listening on it. If the address argument is also given, set the protocol address of the other side of the link, just like the obsolete dstaddr keyword does. Otherwise, set or clear the IFF_POINTOPOINT flag for the interface.
hw class address Set the hardware address of this interface, if the device driver supports this operation. The keyword must be followed by the name of the hardware class and the printable ASCII equivalent of the hardware address. Hardware classes currently supported include ether (Ethernet), ax25 (AMPR AX.25), ARCnet and netrom (AMPR NET/ROM).
multicast Set the multicast flag on the interface. This should not normally be needed as the drivers set the flag correctly themselves.
address The IP address to be assigned to this interface.
txqueuelen length Set the length of the transmit queue of the device. It is useful to set this to small values for slower devices with a high latency (such as a connection over a modem, or over ISDN) to prevent fast bulk transfers from disturbing interactive traffic like telnet too much.
Examples
ifconfig
Running ifconfig with no options displays the configuration of all active interfaces.
ifconfig -a
Displays the configuration of all interfaces, both active and inactive.
ifconfig eth0
View the network settings on the interface eth0, which (under Linux) is the first Ethernet adapter installed in the system.
ifconfig eth1 up
Activate the network interface eth1.
ifconfig wlan0 down
Deactivate the network interface wlan0.
ifconfig wlan1 122.140.201.66
Configure the network interface wlan1 to use the static IP address 122.140.201.66.
ifconfig wlan0 netmask 255.255.255.0
Configure the network interface wlan0 to use the network mask 255.255.255.0.
ifconfig eth0 192.168.1.102 netmask 255.255.255.0 broadcast 192.168.1.255
Configure eth0 to use the static IP address 192.168.1.102 using the network mask 255.255.255.0, and the broadcast address 192.168.1.255.
https://thishosting.rocks/install-java-ubuntu/
UNINSTALL ORACLE JDK
Remove The Link
First of all remove the alternatives by executing the following commands:
$ sudo update-alternatives --remove "java" "/usr/lib/jvm/jdk[version]/bin/java"
$ sudo update-alternatives --remove "javac" "/usr/lib/jvm/jdk[version]/bin/javac"
$ sudo update-alternatives --remove "javaws" "/usr/lib/jvm/jdk[version]/jre/bin/javaws"
Note: Replace the [version] with any version number that’s contained in jdk folder’s name. For example: jdk1.8.0_131.
Remove The Package
After removing link, remove the package inside /usr/lib/jvm/jdk[version] by executing following command:
$ sudo rm -r /usr/lib/jvm/jdk[version]
UNINSTALL OPENJDK
If you want to remove Openjdk only, execute the following command on terminal:
$ sudo apt-get remove openjdk*
If you want to remove Openjdk along with dependencies, execute the following command on terminal:
$ sudo apt-get remove --auto-remove openjdk*
If you want to remove Openjdk and it’s configuration files, execute the following command on terminal:
$ sudo apt-get purge openjdk*
If you want to remove Openjdk along with dependencies and it’s configuration files, execute the following command on terminal:
$ sudo apt-get purge --auto-remove openjdk*
This is how you can uninstall JDK.
https://support.cloudbees.com/hc/en-us/articles/115000073552-Host-Key-Verification-for-SSH-Agents
Detaylı ve güzel anlatımı yukarıdaki adreste.
Know Hosts file Verification Strategy: use the Known Host file, configuration outside Jenkins
Manually provided Verification Strategy: provide the host key directly from Jenkins
Manually trusted Verification Strategy: trust the host key from Jenkins
Non verifying Verification Strategy: legacy behavior, no host key verification
UNINSTALL ORACLE JDK
Remove The Link
First of all remove the alternatives by executing the following commands:
$ sudo update-alternatives --remove "java" "/usr/lib/jvm/jdk[version]/bin/java"
$ sudo update-alternatives --remove "javac" "/usr/lib/jvm/jdk[version]/bin/javac"
$ sudo update-alternatives --remove "javaws" "/usr/lib/jvm/jdk[version]/jre/bin/javaws"
Note: Replace the [version] with any version number that’s contained in jdk folder’s name. For example: jdk1.8.0_131.
Remove The Package
After removing link, remove the package inside /usr/lib/jvm/jdk[version] by executing following command:
$ sudo rm -r /usr/lib/jvm/jdk[version]
UNINSTALL OPENJDK
If you want to remove Openjdk only, execute the following command on terminal:
$ sudo apt-get remove openjdk*
If you want to remove Openjdk along with dependencies, execute the following command on terminal:
$ sudo apt-get remove --auto-remove openjdk*
If you want to remove Openjdk and it’s configuration files, execute the following command on terminal:
$ sudo apt-get purge openjdk*
If you want to remove Openjdk along with dependencies and it’s configuration files, execute the following command on terminal:
$ sudo apt-get purge --auto-remove openjdk*
This is how you can uninstall JDK.
groovy-net
Build a URI or URL
Convert query string from map
Get webpage content form URL
Make a get request to a URI or URL
https://www.leveluplunch.com/groovy/examples/#groovy-string
groovy-string
Count number of chars in string
Left pad string with spaces
Remove first char from string
Remove last char from string
Remove part of a string
Right pad string with spaces
Split string on comma
Split string on white space
https://stackoverflow.com/a/1716699/104085
ternary ve null check
https://groovy-lang.org/closures.html
https://stackoverflow.com/a/1716699/104085
ternary ve null check
https://groovy-lang.org/closures.html
https://dzone.com/articles/concatenate-strings-in-groovy
https://innovalog.atlassian.net/wiki/spaces/JMWE/pages/152568042/Data+types+in+Groovy#DatatypesinGroovy-Arrays
https://www.leveluplunch.com/groovy/examples/
groovy-collections
Calculate average of list
Combine two lists
Convert list to map
Count non empty strings in arraylist
Count occurrences of element in list
Count occurrences of key or value in map
Count true values in list
Filter list by class field
Find max value in arraylist
Find min value in arraylist
Get First/Last element in ArrayList
Get a subset of a map
Get longest string in list
Get smallest string in list
Limit number of elements in arraylist
Partition / Split / Collate arraylist
Remove null from list
Sort map dictionary by key
Sort map dictionary by value
Sum elements of arraylist
def global_degisken = "En üstte tanımlı global degisken"
pipeline {
agent any
stages {
stage("a"){
environment{
aDegiskeni = "A"
}
steps{
echo "------- STAGE A >>>>>>>>>>>"
echo "global_van: $global_degisken"
echo "local env aDegiskeni: $aDegiskeni = $env.aDegiskeni = ${env.aDegiskeni} = ${aDegiskeni}"
/** bDegiskeni tanımlı olmadığı için hata verir
* groovy.lang.MissingPropertyException: No such property: bDegiskeni for class: groovy.lang.Binding
* echo "local env bDegiskeni: $bDegiskeni - $env.bDegiskeni"
*/
echo "<<<<<<<<<< STAGE A --------------"
}
}
stage("b"){
environment{
bDegiskeni = "B"
}
steps{
echo "------- STAGE B >>>>>>>>>>>"
echo "global_van: $global_degisken"
/** aDegiskeni yerelde veya globalde tanımlı bir değişken olsa erişilebilir.
* Oysa A aşamasında env'e bağlı yaratlıyor ancak burada env olmadan
* yani $aDegiskeni veya = ${aDegiskeni} diyerek erişilmek isteniyor
* Bu yüzden istisna fırlatacak ve build son bulacak.
* groovy.lang.MissingPropertyException: No such property: aDegiskeni for class: groovy.lang.Binding
*/
echo "local env aDegiskeni: $env.aDegiskeni = ${env.aDegiskeni}"
echo "local env bDegiskeni: $bDegiskeni - $env.bDegiskeni"
echo "<<<<<<<<<< STAGE B --------------"
}
}
}
}
pipeline {
agent any
stages {
stage('kaynak kodu çek'){
steps {
echo "kod çekildi başarılı"
}
}
stage('derle'){
steps {
echo "Derleme başarılı"
}
}
stage('test et'){
steps {
echo "Test sorunsuz başarılı"
}
}
stage('Sürüm yap'){
steps {
echo "versiyonlandı"
}
}
stage('UAT için yükle'){
steps {
echo "Kullanıcı Kabul Testi için yükleme başarılı"
}
}
}
post{
always {
echo "post - Her zaman bunu yazacak"
}
success {
echo "post - SUCCESS olduğunda bunu yazacak"
}
failure {
echo "post - FAIL olduğunda bunu yazacak"
}
unstable {
echo "post - UNSTABLE olduğunda bunu yazacak"
}
changed {
echo "post - CHANGED olduğunda bunu yazacak"
}
}
}