Evet sevgili yazılımperver dostlarım son güncellemem ile birlikte, uEngine4 motorumuz da artık Github Actions marifeti ile CI/CD üzerinden otomatik olarak oluşturulabilmekte. Bir kaç yazı öncesinde, Github Actions’I kendi uygulamalarınızda da kullanabilmeniz için örnek betikleri şablon projeme eklemiştim. Aşağıda ilgili repoya ve yazıma ulaşabilirsiniz:
uEngine 4 Son Güncellemeler – II
uEngine4’e de bu yeteneği kazandırmış bulunuyorum. Daha önce Azure Devops, gitlab, jenkins ve appvayeour’dan birini kullandıysanız, Github Actions da aslında bunlardan çok farklı değil. En önemli özelliği ise, Github ile sunuluyor olması (aslında bir benzeri gitlab repoları için de uzun bir süredir sunulmaktaydı).
Peki, GitHub Actions ile sağlanan CI/CD de ne diyor olabilirsiniz. Aslında temelde, Sürekli Entegrasyon (CI), kodunuzda yapmış olduğunuz değişiklikler sonrasında yazılım bileşenleriniz/uygulamanın halen derlenebilir/kullanılabilir durumda olduğunu gösteren, eğer bir sıkıntı var ise de hızlıca bunu ortaya koymak için kullanılan yöntemdir. Sürekli Teslimat (CD) ise, sürekli entegrasyon adımları sonrasında oluşturulmuş olan yazılımı ya da yazılım parçasını, hedef ortama otomatik olarak konuşlandırmaya denilmektedir. Sizlerin de tahmin edeceği üzere, özellikle bu güncel web ve mobil yazılımlar için gömülü yazılımlara göre daha sık olmaktadır ama C++ uygulamaları için de çok güzel örnekler bulunmakta deyip hemen sizler konun detaylarını aktardığım yazıma bakmaya davet ediyorum, keza bundan sonra azcık GitHub Actions’a bakıyor olacağız.
https://www.yazilimperver.com/index.php/2021/01/25/uygulama-izleme-yazilimi-serisi-3-birim-test/
Gelelim yazımızın asıl konuğuna, Github Actions’a. Peki nedir GitHub Actions? GitHub Actions, github üzerinde konuşlandırmış olduğunuz yazılımlarınıza ilişkin otomatik iş akışları oluşturmanıza, bu vesile derleme, test ve konuşlandırmanıza yardımcı olan bir altyapıdır. Yukarıda da bahsettiğim gibi, aslında github repolarınızda bulunan projelerinize kolay bir şekilde CI/CD alt yapısı kazandıracak bir hizmettir.
İçerik
Temel Kavramlar
Girizgahtan sonra şimdi temel kavramlara bakmaya başlayalım. Bu arada daha detayları ve referans aldığım kaynakları yazımın sonunda her zaman olduğu gibi paylaşacağım. Temel kavramlara, GitHub Action’ın temel bileşenlerine yönelik aşağıdaki gibi bir grafik buldum. Grafikte her bir kavram, kısaca ilgili aşamaya göre anlatılmış.
İş Akışları (Workflows)
İlk kavramımız, İş Akışları. İş akışları, belirli olaylar gerçekleştiğinde otomatik olarak çalışan bir ya da daha fazla işten oluşur. Örneğin, kod devredildiğinde (checkin), kod derlenir ve testler koşturulur. İş akışları ve diğer bileşenler YAML dosyası ile tanımlanır. Bu iş akışı, bir olay ile (event) ile tetiklenerek, tanımlanan işleri yapmaya başlar. Bir olay yanında el ile ya da tanımlanmış zamanlarda da çalıştırılabilir.
GitHub Actions için en üst seviye tanımlamalar, İş Akışları vesilesi ile .github/workflows dizini içerisinde tanımlanır. Bir GitHub reposunda birden fazla iş akışı olabilir. Bunların her bir farklı işleri içeriyor (yazılım oluşturma, test koşumu, konuşlandırma, vb.) ve farklı olaylar ile tetikleniyor olabilir. Bunun ile birlikte iş akışlarını tekrar ve bir diğerinin içerisinde kullanabilirsiniz, bu tarz detayları için https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions sayfasına göz atabilirsiniz.
Olaylar (Events)
İş akışlarının işleme başlaması için kullanılan şeylere de olay/iş akışı tetikleyicisi denir. Bunlar gerçekleştiğinde ilgili iş akışları gerçekleştirilmeye başlar. Peki bunlar ne olabilir?
• Manuel tetik,
• Zamanlanmış olaylar,
• Github reposuna dair olaylar (commit, add, pull request, vb) gibi.
Bunların detayları ve diğer tetikler için https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows sayfasına göz atabilirsiniz. Oldukça farklı ve çeşitli tetik mekanizmaları sunulmakta.
İşler (Jobs)
İş akışları ve bunları tetikleyen olaylara baktıktan sonra, iş akışları kapsamında yapılacak işlere göz atalım. Bir İş (Job), aynı Çalıştırıcıda (runner) yürütülen bir iş akışındaki bir ya da daha fazla Adımdan (step) oluşan kümeye verilen isimdir. Her bir adım ya bir shell betiğinden ya da bir aksiyondan oluşabilir. Bir iş içerisindeki adımlar verilen sırada ve diğerine bağımlı bir şekilde koşturulur.
Her bir adım aynı çalıştırıcıda (buna da yakında değineceğim) koştuğu için veriler bir adımdan diğerine paylaşılmaktadır. Örneğin bir adımda yazılımı derledikten sonra, diğer adımda oluşan çalıştırılabilir dosya ile testleri koşturabilirsiniz.
İşler birbirinden bağımsız olarak koşabildikleri gibi bir diğerine bağımlı da olabilirler. Bağımsız işler aynı zamanda paralel de koşturulabilirler. Örneğin paketleme için farklı işletim sistemleri üzerinde derleme yapan birden fazla işiniz olabilir, bunların sonuçlarını bekleyen bir işiniz olabilir ve bu da paketlemeyi yapabilir. İşlere yönelik detaylı bilgiler için https://docs.github.com/en/actions/using-jobs sayfasına göz atabilirsiniz.
Bu başlığı kapatmadan önce aksiyonlara ufak bir parantez açmak istiyorum. Aksiyonlar, Github Actions için uyarlanabilir uygulamalardır. Bunlar genel olarak bir çok iş için gerek duyulan ortak işlere yönelik tanımlanmıştır. Azure Devops’taki Task’lara benzer bir işlev görürler. Bu sayede, tekrar eden işler için halihazırdaki aksiyonları kullanabilirsiniz. Bu noktada, Github Marketplace’te bulunan bir çok aksiyona göz atılabilir ya da kendi aksiyonlarınızı tanımlıyor olabilirsiniz. Daha detaylı bilgi için https://docs.github.com/en/actions/creating-actions adresine göz atılabilir.
Çalıştırıcı (Runner)
Çalıştırıcı, basitçe iş akışlarının koşturulduğu ortam olarak düşünebilirsiniz. Bu ortam tahmin edebileceğiniz üzere sanal ya da fiziksel bir bilgisayar olabilmektedir. Azure Devops’ta agent diye isimlendirilen, gitlab’ta da yine benzer şekilde çalıştırıcı (runner olarak ifade edilmektedir).
Çalıştırıcılara, olayları/tetikleyicileri dinlerler ve tetiklendikleri anda ilgili iş akışlarını başlatırlar. Çalıştırıcıyı kullanabilmek için bir yazılım kurmanız yeterlidir.
Her çalıştırıcı aynı anda tek bir işi (job) yapar. Github’ın kendi sunduğu çalıştırıcılar yanında sizler de kendi çalıştırıcılarınızı kullanabilirsiniz. Bunun için https://docs.github.com/en/actions/hosting-your-own-runners sayfasına göz atabilirsiniz.
Evet çalıştırıcı ile birlikte aslında GitHub Actions’a ilişkin temel kavramlara bakmış olduk. Aşağıda bu kavramları gösteren başka bir figür görebilirsiniz:
Örnekler
Şimdi de GitHub Actions’ın sayfasındaki bir dosyay önce bakalım sonra da uEngine için kullandığımıza bakalım.
Daha önce de bahsettiğimiz gibi GitHub Actions iş akışını tanımlamak için YAML sentaksını kullanmakta ve bunlar ayrı dosyalar olarak tutulmaktalar.
Şimdi örnek bir iş akışı dosyasına bakacağız, detaylar için https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions#create-an-example-workflow sayfasına göz atabilirsiniz. Referans alacağımız dosya şu şekilde:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
name: learn-github-actions run-name: Yazılımperver is learning GitHub Actions on: [push] jobs: check-bats-version: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' - run: npm install -g bats - run: bats -v |
Bu dosyayı, .github/workflows/ altına learn-github-actions.yaml olarak ekleyebilirsiniz. Şimdi bu adımlara, daha detaylı bakalım:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# Opsiyonel- GitHub deposunun "Eylemler" sekmesinde görüneceği şekilde iş akışının adı. Bu alan vermezseniz, bunun yerine iş akışı dosyasının adı kullanılır. Verilmesinde fayda var. <strong>name: learn-github-actions </strong> # İsteğe bağlı - İş akışından oluşturulan ve repoda "Eylemler" sekmesindeki iş akışı çalıştırmaları listesinde görünecek iş akışı çalıştırmalarının adı. Bu örnek, iş akışı çalıştırmasını tetikleyen aktörün kullanıcı adını görüntülemek için `github` bağlamıyla bir ifade kullanır. Daha fazla bilgi için bkz. https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#run-name <strong>run-name: Yazılımperver GitHub Eylemlerini öğreniyor </strong> # Bu iş akışı için tetikleyiciyi belirtir. Burada, `push` olayı ile tetikleniyor, böylece birisi repoya bir değişiklik gönderdiğinde veya bir çekme isteğini birleştirdiğinde bir iş akışı çalıştırması tetiklenir. Bu, her dala yapılan bir push'la tetiklenir; yalnızca belirli dallara, yollara veya etiketlere yapılan pushlarda çalışan örnekler için https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#onpushpull_requestpull_request_targetpathspaths-ignore <strong>on: [push] </strong> # `learn-github-actions` iş akışında çalışan tüm işleri bir araya getirir. <strong>jobs: </strong> # `check-bats-version` adlı bir iş tanımlar. Alt anahtarlar işin özelliklerini tanımlar. <strong>check-bats-version:</strong> # İşi, Ubuntu Linux çalıştırıcısının en son sürümünde çalışacak şekilde ayarlama yapılır. Bu, işin GitHub tarafından barındırılan yeni bir sanal makinede yürütüleceği anlamına gelir. Diğer çalıştırıcıları kullanan örnekler için bkz. https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idruns-on <strong>runs-on: ubuntu-latest</strong> # `check-bats-version` işinde çalışan tüm adımları bir araya getirir. Bu bölümün altına yerleştirilen her öğe ayrı bir eylem veya shell betiğidir. <strong>steps:</strong> # `uses` anahtar sözcüğü, bu adımın `actions/checkout` eyleminin `v4` sürümünü çalıştıracağını belirtir. Bu, reponuzu çalıştırıcıya kontrol eden ve kodunuza karşı betikler veya diğer aksiyonları (derleme ve test araçları gibi) çalıştırmanıza olanak tanıyan bir aksiyondur. İş akışınız reponuzdaki kodu kullanmak istediğiniz her durumda "checkout" aksiyonunu kullanmalısınız. <strong>- uses: actions/checkout@v4</strong> # Bu adım, Node.js'nin belirtilen sürümünü yüklemek için `actions/setup-node@v4` aksiyonunu kullanır. (Bu örnek sürüm 20'yi kullanır.) Bu, hem `node` hem de `npm` komutlarını `PATH`'inize koyar. <strong>- uses: actions/setup-node@v4</strong> with: <strong>node-version: '20'</strong> # `run` anahtar sözcüğü, işe çalıştırıcıda bir komut yürütmesini söyler. Bu durumda, `bats` yazılım test paketini yüklemek için `npm` kullanıyorsunuz. <strong>- run: npm install -g bats</strong> # Son olarak, `bats` komutunu yazılım sürümünü çıktı olarak veren bir parametreyle çalıştıracaksınız. <strong>- run: bats -v</strong> |
Bu iş akışı aşağıdaki gibi görselleştirilebilir:
Sıra geldi, uEngine4 için kullandığımız iş akışı betiğine, hadi hızlıca ona da bakalım. Bu arada koşan uEngine4 iş akışlarına ve diğer detaylara https://github.com/yazilimperver/uEngine4/actions adresinden ulaşabilirsiniz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
name: uEngine CMake Multiplatform Github Actions Template on: push: branches: - main # Aşağıda verilen dizin ve dosyalardaki commit'ler iş akışını tetiklemeyecek. .gitignore'a benzer bir mantık paths-ignore: - '**/**.md' # İş akışı içerisinde ortam değişkenleri de tanımlayabilirsiniz env: CMAKE_VERSION: "3.29.6" NINJA_VERSION: "1.12.1" jobs: build: # Özellikle farklı işletim sistemi veya konfigürasyonlar için "strategy"/matrix" yapısı kullanılabiliyor # matrix GitHub Actions'ta anahtar bir kelime. Aşağıda bunu Windows ve Ubuntu buildleri için kullanıyoruz # Detaylar için https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/using-a-matrix-for-your-jobs e göz atabilirsiniz # Buna ayrı bir yazı da ayırabiliriz :) name: ${{ matrix.config.name }} runs-on: ${{ matrix.config.os }} strategy: # Herhangi bir hata durumunda hemen akış durmasın diye eklenen bir flag fail-fast: false matrix: # Aşağıda konfigürasyonları tanımlıyoruz. Bir tane windows, bir tane ubuntu için # işletim sistemleri docker aracılığı ile kullanılıyor, ayrıca c/c++ derleyicileri de belirtiliyor config: - { name: "Windows Latest MSVC", artifact: "Windows-MSVC", os: windows-latest, cc: "cl", cxx: "cl", environment_script: "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvars64.bat" } - { name: "Ubuntu Latest GCC", artifact: "Linux", os: ubuntu-latest, cc: "gcc", cxx: "g++" } steps: # Checkout'lamak için kullanılan GitHub Action - uses: actions/checkout@v4 # Aşağıda uEngine için ihtiyaç duyulan adımlar sıralanmış durumda. Genelde isimler ne yaptıklarını ifade ediyor olduğu için çok detaylara girmeyeceğim # Adımlardan biri - name: Greeting-Windows # Aşağıdaki gibi kontroller ile işletim sistemine özel, uyarlamalar yapabilirsiniz if: runner.os == 'Windows' run: | echo "Yazilimperver Github Actions started from Windows!" - name: Greeting-Linux if: runner.os == 'Linux' run: | echo "Yazilimperver Github Actions started from Linux!" - name: Linux Dependencies if: runner.os == 'Linux' run: | sudo apt install clang-tidy -y - name: Download Ninja and CMake # CMake ve ninja'yı indirmek için kullanılacak betik shell: cmake -P {0} run: | set(cmake_version $ENV{CMAKE_VERSION}) set(ninja_version $ENV{NINJA_VERSION}) message(STATUS "Using host CMake version: ${CMAKE_VERSION}") if ("${{ runner.os }}" STREQUAL "Windows") set(ninja_suffix "win.zip") set(cmake_suffix "windows-x86_64.zip") set(cmake_dir "cmake-${cmake_version}-windows-x86_64/bin") elseif ("${{ runner.os }}" STREQUAL "Linux") set(ninja_suffix "linux.zip") set(cmake_suffix "linux-x86_64.tar.gz") set(cmake_dir "cmake-${cmake_version}-linux-x86_64/bin") elseif ("${{ runner.os }}" STREQUAL "macOS") set(ninja_suffix "mac.zip") set(cmake_suffix "macos-universal.tar.gz") set(cmake_dir "cmake-${cmake_version}-macos-universal/CMake.app/Contents/bin") endif() set(ninja_url "https://github.com/ninja-build/ninja/releases/download/v${ninja_version}/ninja-${ninja_suffix}") file(DOWNLOAD "${ninja_url}" ./ninja.zip SHOW_PROGRESS) execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf ./ninja.zip) set(cmake_url "https://github.com/Kitware/CMake/releases/download/v${cmake_version}/cmake-${cmake_version}-${cmake_suffix}") file(DOWNLOAD "${cmake_url}" ./cmake.zip SHOW_PROGRESS) execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf ./cmake.zip) # Add to PATH environment variable file(TO_CMAKE_PATH "$ENV{GITHUB_WORKSPACE}/${cmake_dir}" cmake_dir) set(path_separator ":") if ("${{ runner.os }}" STREQUAL "Windows") set(path_separator ";") endif() file(APPEND "$ENV{GITHUB_PATH}" "$ENV{GITHUB_WORKSPACE}${path_separator}${cmake_dir}") if (NOT "${{ runner.os }}" STREQUAL "Windows") execute_process( COMMAND chmod +x ninja COMMAND chmod +x ${cmake_dir}/cmake ) endif() - name: Download ccache id: ccache run: | if [ "$RUNNER_OS" == "Linux" ]; then sudo apt install ccache fi shell: bash # uEngine4 için linux bağımlılıklarını kurduğumuz adım - name: Install Other 3rd Party Dependencies - Linux id: external_libraries_linux if: runner.os == 'Linux' run: | chmod 700 install_for_linux.sh install_for_linux.sh shell: bash - name: Configure build for amd64 if: runner.os == 'Windows' # Komut satırından MSVC çağırmak için kullanılan bir GitHub Action uses: ilammy/msvc-dev-cmd@v1 with: arch: amd64 # uEngine4 için windows bağımlılıklarını kurduğumuz adım - name: Install Other 3rd Party Dependencies - Windows id: external_libraries_win if: runner.os == 'Windows' run: | install_for_windows.bat shell: cmd # uEngine4'ü linux için derlediğimiz adım - name: Build uEngine4 Linux id: build_uengine4_linux if: runner.os == 'Linux' run: | git submodule update --init --recursive cd code chmod 700 ./scripts/buildLinux.sh ./scripts/buildLinux.sh shell: bash - name: VcPkg Installation if: runner.os == 'Windows' run: | git clone https://github.com/microsoft/vcpkg.git cd vcpkg bootstrap-vcpkg.bat vcpkg integrate install vcpkg install opengl glew --triplet=x64-windows-static # uEngine4'ü windows için derlediğimiz adım - name: Build uEngine4 Windows id: build_uengine4_windows if: runner.os == 'Windows' run: | git submodule update --init --recursive cd code cmake -S . -B build_ninja -G "Ninja" cd build_ninja ninja cd .. shell: cmd |
Evet sevgili yazılımperver dostlarım, uzunca bir yazımın daha sonuna geldik. Bu yazı ile birlikte artık Github repolarınızı CI/CD ile tanıştırabilirsiniz.
Bir sonraki yazımda görüşmek dileğiyle, kendinize çok iyi bakın.