DevOps için Semantik Versiyon Üreten Script

Umut Boz
KoçSistem
Published in
5 min readJun 29, 2019

Şirketimizde native ios ve native android ve cross platform(flutter) mobil kütüphaneleri geliştirmekteyiz. Paketleri, dağıtım ve geriye dönük kullanım kolaylığı için süreçlerimizde belirli bir standart versiyonlama çerçevesi üzerinde yapılandırmalıyız. Sürümlerin dağıtımı için semantik versiyonlama yöntemini tercih ediyoruz. Paketlerin, CI (Continuous Integration) & CD(Continuous Delivery) hatlarında belirli bir standart versiyon yönetimiyle yolculuğuna devam etmesi önemli bir nokta olarak karşımıza çıkmaktadır. Bu yazımda, uygulamaların ya da paketlerin build veya release hatlarında ayrı noktalarda el ile vermiş olduğumuz versiyonlamanın git tag değeri üzerinden otomatik olarak üretilerek, hat boyunca tüm noktalarda variable olarak kullanılması için geliştirmiş olduğum script çözümünü anlatacağım. Üretilen script çözümünü sizlerde farklı noktalarda farklı ihtiyaçlar için özelleştirebilirsiniz.

Kütüphanenin yeni bir versiyonuna ait her yolculuk için, paketimize verdiğimiz bilet numarası ile birlikte, paketin aktarma yaptığımız her istasyonda bu bilet numarasını kullanıp bir sonraki yolculuğuna devam etmesini bekliyoruz. Örneği gerçekleştirmek istersek; swift ile yazmış olduğumuz bir ios paketinin build hattından geçerken ve sonrasında Sonarqube üzerinde kod analizi yapılması ardından unit test coverage hattından geçmesi sonrasında ise cocoapods üzerinde paketin yayınlanma aşamasındaki kullanacağımız bilet numarasıdır: semantik versiyonlama.

🚂 — 🚉 — 🚇— ✈️ Yani her aşamada paketimizin her versiyonunu semantik olarak versiyonladığımız numara ile işaretlemeliyiz. Peki bu işaretlemeyi nasıl uygulayacağız?

journey of swift library

Yeni bir paket çıkacağız major, minor ya da patch. Peki, versiyon numarasını neye göre belirleyeceğiz? Tamam, semantik versiyonlama kurallarına göre! Minor bir paket çıkacağız. Bu çıkacağımız minor versiyonun son çıktığımız versiyonun üzerinden türemesi gerekiyor.

Bu durumda versiyon numaralarımızı git üzerinde tag ile eşlememiz şart. Ve bu tag üzerinden son versiyona bakarak yeni bir minör versiyon ile yolculuğa başlıyoruz. Tag üzerinde son versiyonumuzun 1.1.0 olarak işaretlenmiş olması durumunda minor paket istediğimizde 1.2.0 ile tüm yolculuğa başlamalıyız. Tamda burada major, minor ve ya patch paketimizin git üzerinden alınarak CI ve CD hatlarında otomatik olarak semantik versiyonlama üreten bir script’in nasıl yazılabileceğini anlatacağım.

Mevcut teknolojilere göre script’in entegre olacağı yapılar farklılık gösterebilir. ios ve android paketlerin code repository’si olarak Azure Devops(namı diğer TFS) platformu üzerinde Git ile kullanmaktayız. Bu üretilen çözümü JIRA ya da farklı bir platform API’ları sayesinde entegrasyon oluşturarak gerçekleştirebilirsiniz. Araç ve gereçlerimizle başlayalım.⚒⛏

📌 Python ile Shell Script : İşletim sistemi üzerinde terminal ortamında python environment’ı ile python nimetlerinden faydalanarak shell kütüphanelerini de kullanarak bash script üretebiliriz.

Unix, Linux, Ubuntu ve macOS gibi işletim sistemleri üzerinde Perl ve Python’un sistem üzerindeki varsayılan environment’larını kullanarak geliştirebileceğiniz örnek için burayı incelemenizi tavsiye ediyorum. Python ile shell command’ları çalıştırmak hatta bu response’ları parse ederek işlemek içinse burayı inceleyebilirsiniz.

Örnek Python Shell Script

#! /bin/sh""":"exec python $0 ${1+"$@"}"""

Yazacağımız script bloğu header’ında mutlaka yukardaki gibi başlıyoruz. Artık script dosyasına terminal üzerinden argüman göndererek işlem gerçekleştirebilirsiniz.

#! /bin/sh""":"exec python $0 ${1+"$@"}"""import sysprint "merhaba " + str(sys.argv[1])

yukarıda test.sh uzantılı olarak kaydettiğimiz dizin üzerinde script’i argüman ile çağırdığımzıda aşağıdaki gibi bir çıktı alabiliriz. 💃🏾

python shell script

Eğer offline olarak varolan tag listesini çekip işlem yapacak olursak; çalıştıracağımız shell script git init’in gerçekleştiği proje root dizinde olmalı ve git tag komutu shell script içinde çağrılıp en son tag parse edilip işleme alınmalı.

📟 Eğer, bu tag bilgisi online ortam üzerinden beslenilmeli diyorsanız git, github, azure devops gibi ortamlar üzerinden bu platformların api’larını kullanabilirsiniz. Bunun için python http kütüphanelerini shell script’e import ederek en son tag bilgisini parse etmelisiniz.

🏋 Ya da her iki yöntemi kullanan çözüm ile birlikte süreci ilerletebilirsiniz.

Her iki yöntemi de çözümlerimizde kullandım. Bu yazımda offline yöntem üzerinden çözümü paylaşacağım.

import packages

import osimport sysimport reimport urllib2import sslimport shutilimport commandsimport datetimeimport json

Dışarıdan argüman olarak major,minor,patch parametrelerini bekliyoruz. Bu değerde bizim için aşağıdaki script’te semantic olarak tanımlanmaktadır.

semantic = str(sys.argv[1]).lower()#set env template sourcestags=commands.getstatusoutput('git tag')if len(tags) == 0 or len(tags[1]) == 0:   print 'tag not found'tags=commands.getstatusoutput('git tag')[1]last_tag = commands.getstatusoutput('git describe --tags $(git rev-list --tags --max-count=1)')if len(last_tag[1].split('.')) == 0:   showErrorMessages(MESSAGE.INFO,"current semantic tag not found")   sys.exit(0)if len(last_tag[1].split('.')) == 3:   major_number = str(last_tag[1].split('.')[0])   minor_number = str(last_tag[1].split('.')[1])   patch_number = str(last_tag[1].split('.')[2])elif len(last_tag[1].split('.')) == 2:   major_number = str(last_tag[1].split('.')[0])   minor_number = str(last_tag[1].split('.')[1])   patch_number = '0'elif len(last_tag[1].split('.')) == 1:   major_number = str(last_tag[1].split('.')[0])   minor_number = '0'   patch_number = '0'

Yukarıdaki işlemlerde mevcut tag listesi üzerindeki en son tag değeri alınarak major, minor, patch değerleri memory’de tutulmaktadır. Sonrasında ise, istenen major,minor,patch argümanına göre bu değerin üretilmesi ve version.json olarak yazılması işlemleri bulunmaktadır.

if semantic != major and semantic != minor and semantic != patch:   print "semantic keyword is should be major or minor or patch"   showErrorMessages(MESSAGE.INFO,"auto-semantic-version semantictType")   sys.exit(0)if intern(semantic) is intern(major):   finalize_tag = str(int(major_number) + 1) + ".0.0"elif intern(semantic) is intern(minor):   temp_minor_number = int(minor_number) + 1   if temp_minor_number > 99:      finalize_tag = str(int(major_number) + 1) + ".0.0"   else:      finalize_tag = major_number + "." + str(temp_minor_number) + ".0"elif intern(semantic) is intern(patch):   temp_patch_number = int(patch_number) + 1   if temp_patch_number > 999:      temp_minor_number = int(minor_number) + 1      finalize_tag = major_number + "." + str(temp_minor_number) + ".0"   else:      finalize_tag = major_number + "." + minor_number + "." + str(temp_patch_number)
date = datetime.datetime.now().strftime("%d-%m-%Y %H:%M")tagDictObject = { "tag":finalize_tag, "semantic":semantic, "date": str(date) }serializedJson= json.dumps(tagDictObject, sort_keys=True, indent=3)print serializedJson
auto semantic script gen output version.json

Eğer bir build ya da release pipeline hattınız var ise version.json dosyasına yazılmış olan yukarıdaki tag değerini variable olarak okuyup tüm süreçlerinizde kullanabilirsiniz. Argüman olarak ise -projectName -branch ve -semantic parametleri alınarak dev ve master ortamlarına göre ayrı süreçler uygulayabilirsiniz.

Aşağıdaki örnek üzerinde Azure Devops pipeline hattında bu işlem gösterilmektedir.

Azure Devops — auto semantic versioning

Farklı teknolojilerde, konularda, yazılarda buluşmak üzere..ツ

go head

--

--