Tüm Yazılar
KategoriDevOps
Okuma Süresi
8 dk
Yayın Tarihi
2026-10-15
Kelime Sayısı
1.237kelime

Kahveni hazırla - bu içerikli bir makale!

Diğer repoların CI'ı tek bir repoda: reusable GitHub workflow tasarımı

Özet

muhittincamdali/.github, Swift, Node.js ve Flutter repolarının CI'ını SHA ile sabitlenen ve tag ile sürümlenen yedi reusable workflow'da topluyor.

  • muhittincamdali hesabında arşivlenmemiş 57 public repo var.
  • Composite action yerine reusable workflow.
  • Repo kendini ci.yml ile kontrol ediyor: SHA-256 ile doğrulanarak indirilen actionlint 1.7.12 ve göreli yolla çağrılan kendi hygiene ve links workflow'ları.
  • Kaynak kod: [github.com/muhittincamdali/.github](https://github.com/muhittincamdali/.github)
Diğer repoların CI'ı tek bir repoda: reusable GitHub workflow tasarımı

İçindekiler


Problem

muhittincamdali hesabında arşivlenmemiş 57 public repo var. Birçoğu Swift package, ikisi

Node.js komut satırı aracı. Hepsinin ihtiyacı aşağı yukarı aynı: build ve test, paketin desteklediğini

söylediği her Apple platformu için build, DocC dokümantasyonunu yayımlamak, README'deki bağlantıların

ve #anchor'ların hâlâ çalıştığını ve çevrilmiş README'lerin İngilizce sürümle uyumlu olduğunu

kontrol etmek.

Bu kontrolleri her repoya ayrı ayrı yazmak, her repoda bir kopya demek. Birindeki bir düzeltme, yeni

bir runner imajı ya da sabitlenmiş bir action'ın güvenlik güncellemesi her yerde elle uygulanmak

zorunda kalıyor ve kopyalar zamanla birbirinden ayrışıyor. .github reposu buna verilen cevap:

kontroller tek bir yerde duruyor, her repo yalnızca onları çağıran kısa bir dosya tutuyor.

15 Ekim 2026 itibarıyla 18 repo bu workflow'ları çağırıyor: 16 Swift package swift-ci ve

docc-pages'i, iki Node.js aracı node-ci'yi kullanıyor; 18'inin hepsi links, hygiene ve

readme-i18n-sync'i çalıştırıyor. Hesabın geri kalanı, her repo yeniden kuruldukça ekleniyor.

Repoda ne var

İki tür dosya.

Topluluk dosyaları. GitHub, .github adlı bir repodaki CONTRIBUTING.md, CODE_OF_CONDUCT.md,

SECURITY.md, SUPPORT.md, issue formları ve pull request şablonunu aynı sahibin kendi kopyası

olmayan her reposunda kullanıyor. Bunun için hiçbir bağlantı kurmak gerekmiyor; bir repo ancak farklı

bir şey istediğinde kendi dosyasını ekliyor.

Reusable workflow'lar. .github/workflows/ altında, her biri workflow_call ile tetiklenen yedi

dosya:

Workflow
Ne yapıyor
swift-ci
swift build --build-tests, swift test, platform başına isteğe bağlı xcodebuild
docc-pages
xcodebuild docbuild ile DocC, birden fazla modül tek sitede, GitHub Pages'e yayın
flutter-ci
dart format, flutter analyze, coverage ile testler, isteğe bağlı dart pub publish --dry-run
node-ci
lockfile'dan npm ya da pnpm kurulumu, ardından varsa lint, typecheck, test, build
links
bir günlük cache ile lychee bağlantı ve anchor kontrolü
readme-i18n-sync
her README.<lang>.md çevirdiği İngilizce sürümü belirtiyor
hygiene
dosyalarda ve commit mesajlarında araç adlarını, doğrulanamayan üstünlük iddialarını reddediyor

Bir Swift package ikisini şöyle çağırıyor (repo README'sinden):

yaml
1name: CI
2 
3on:
4 push:
5 branches: [main]
6 pull_request:
7 
8permissions: {}
9 
10jobs:
11 swift:
12 permissions:
13 contents: read
14 uses: muhittincamdali/.github/.github/workflows/swift-ci.yml@<sha> # v1
15 with:
16 platforms: '["iOS", "macOS", "tvOS", "watchOS", "visionOS"]'
17 
18 hygiene:
19 permissions:
20 contents: read
21 uses: muhittincamdali/.github/.github/workflows/hygiene.yml@<sha> # v1

Tasarım kararları ve alternatifler

Composite action yerine reusable workflow. Composite action, çağıranın job'ı içinde adım olarak

çalışıyor; runner'ı, matrisi ve izinleri yine çağıran belirliyor. Reusable workflow ise job'ların

tamamına sahip. Burada bu fark önemli: swift-ci'da bir SwiftPM job'ı ve platformlar üzerinde

fail-fast: false matrisiyle çalışan ayrı bir xcodebuild job'ı var; docc-pages'te

contents: read izinli bir build job'ı ve pages: write ile id-token: write izinli bir deploy

job'ı var. Bu yapılar bir adım listesiyle ifade edilemiyor.

Yaygın durumu karşılayan varsayılanlarla tipli girdiler. Çağıranların çoğu bir girdi veriyor ya da

hiç vermiyor. swift-ci, platforms'u JSON liste olarak alıp fromJSON ile matrise çeviriyor; boş

liste ("[]", varsayılan) platform job'ını tamamen atlıyor. scheme verilmediğinde

xcodebuild -list -json çıktısından paketin -Package scheme'ini, yoksa tek scheme'i seçiyor.

node-ci yalnızca var olan package script'lerini çalıştırıyor; typecheck script'i olmayan bir araç

için ayrı ayar gerekmiyor.

Girdiler shell koduna yalnızca ortam değişkeniyle ulaşıyor. Bir komutta kullanılan her girdi önce

env: altına alınıyor ve script'te tırnak içinde kullanılıyor:

yaml
1- name: Select Xcode
2 if: inputs.xcode != ''
3 env:
4 XCODE_VERSION: ${{ inputs.xcode }}
5 run: sudo xcode-select --switch "/Applications/Xcode_${XCODE_VERSION}.app"

Doğrudan run: içine yazılan bir ${{ }} ifadesi shell görmeden önce script metnine yapıştırılıyor;

ortam değişkeni ise her zaman yalnızca veri olarak kalıyor.

Varsayılan olarak en az yetki. Her workflow en üstte permissions: {} tanımlıyor ve izinleri job

bazında veriyor. Her checkout persist-credentials: false kullanıyor; böylece token sonraki adımlar

için yerel git ayarlarında kalmıyor. Çağıran repo aynı izinleri çağıran job'da vermek zorunda; README

tablosu bunları workflow başına listeliyor.

Her şey bir commit'e sabit. Workflow'ların içindeki her uses: tam commit SHA'sını ve yorum

olarak sürümü yazıyor, örneğin

actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1. Tag taşınabilir, commit

taşınamaz. Reponun dependabot.yml dosyası tüm action güncellemelerini ci önekiyle haftada bir tek

pull request'te topluyor. Çağıranlar aynı kuralı bir seviye yukarıda uyguluyor: swift-ci.yml@<sha> # v1

şeklinde sabitliyorlar; README'ye göre güncellemeleri bundan sonra Dependabot öneriyor.

Yeniden kullanıldığını bilen concurrency. Her workflow'un kendi grubu var, örneğin

reusable-swift-ci-${{ github.repository }}-${{ github.ref }}. reusable-<ad> öneki, grubun çağıran

workflow'un kendi tanımladığı bir grupla çakışmasını önlüyor. Pull request çalıştırmaları aynı

branch'in eski çalıştırmasını iptal ediyor; main'e yapılan push'lar hiç iptal edilmiyor.

docc-pages hiç iptal etmiyor; böylece bir yayın yarıda kesilmiyor.

Script'ler ikinci bir repoda değil, workflow'un içinde. hygiene ve readme-i18n-sync,

shell: python3 -I {0} ile gömülmüş Python programları. Isolated mode sayesinde Python, checkout

edilen reponun dizininden hiçbir şey import etmiyor. hygiene aradığı her kelimeyi w[o]rd gibi bir

karakter sınıfıyla yazıyor; böylece workflow dosyası kendi kurallarına takılmıyor. links, çağıran

reponun .lychee.toml dosyası yoksa varsayılan bir tane yazıyor; repo, ayar dosyası kopyalamadan makul

istisnaları ve bir günlük cache'i alıyor.

Gerçek bir sorun: GitHub Pages'e sığmayan bir dokümantasyon sitesi

İlk tag v1.0.0 (aynı commit'te v1 ile birlikte) 14 Ekim 2026'da atıldı. Aynı gün ilerleyen

saatlerde docc-pages, SwiftUI-Components için başarısız oldu. Düzeltmeyi yapan 5998767 commit'i

olanları kaydediyor: DocC, bir tipin protocol extension'lardan miras aldığı her üyeyi belgeliyor; bir

SwiftUI view'ı için bu yaklaşık 850 View modifier'ı demek. 220 public view ile arşiv 380.000

dosyada 2,5 GB'a ulaştı. GitHub Pages 101 MB'lık artifact'i 10 dakikalık yayın süresi içinde

işleyemedi; site zaten 1 GB'lık Pages sınırının üzerindeydi.

Çözüm tek bir build ayarı. docc-pages'e bir girdi eklendi:

yaml
1skip-synthesized-members:
2 description: >-
3 Leave out members a type only inherits from protocol extensions, such as the hundreds of
4 SwiftUI View modifiers every view gets. A package with many views otherwise produces a
5 site too large for GitHub Pages.
6 type: boolean
7 default: false

ve xcodebuild docbuild'e DOCC_SKIP_SYNTHESIZED_MEMBERS="$SKIP_SYNTHESIZED" geçiliyor. Bu ayarla

aynı arşiv 3.158 dosyadan (18 MB) oluşuyor; tiplerin kendi initializer'ları ve property'leri

değişmiyor.

Varsayılan değer false; yani mevcut her çağıran daha önce ürettiği siteyi aynen üretiyor. Bu yüzden

değişiklik v1'e yapılan bir müdahale değil, küçük bir sürüm oldu: v1.1.0. SwiftUI-Components artık

docc-pages.yml@85ec2fa… # v1.1.0 ile sabitleniyor ve girdiyi nedenini açıklayan bir yorumla

açıyor; diğer çağıranlar ihtiyaç duyana kadar v1'de kalıyor.

Paylaşılan bir workflow için çıkan ders: yeni davranış, varsayılanı eski davranışı koruyan bir girdinin

arkasından geliyor; sürüm numarası da çağıranın bakması gerekip gerekmediğini söylüyor.

Kullanım

  1. Repoya .github/workflows/ci.yml gibi bir workflow dosyası ekleyin ve yukarıdaki örnekteki

job'ları yazın. README tablosundaki izinleri her çağıran job'da verin.

  1. <sha> yerine istediğiniz tag'in commit'ini yazın, tag'i yorum olarak bırakın.
  2. Dokümantasyon için reponun Pages kaynağını "GitHub Actions" yapın ve docc-pages'i targets ile

deploy: ${{ github.event_name != 'pull_request' }} vererek çağırın; pull request'ler yalnızca

build alır.

  1. Yeni tag'ler pull request olarak gelsin diye çağıran repoda github-actions için Dependabot'u

açın.

Repo kendini ci.yml ile kontrol ediyor: SHA-256 ile doğrulanarak indirilen actionlint 1.7.12 ve

göreli yolla çağrılan kendi hygiene ve links workflow'ları.

Sınırlar

  • flutter-ci'ın henüz bir çağıranı yok. Yazılmış ve actionlint'ten geçiyor, ama bu hesaptaki gerçek

bir Flutter reposunda çalışmadı.

  • Tag'ler GitHub Release ya da changelog dosyası olmayan git tag'leri; neyin değiştiği commit

mesajlarında.

  • v1 ve v1.0.0 aynı commit'i gösteriyor ve v1, v1.1.0'a taşınmadı. Yeni girdiyi isteyen bir

çağıranın yeni commit'e sabitlemesi gerekiyor.

  • Workflow'lar GitHub'ın barındırdığı runner'ları varsayıyor: Apple işleri için macos-26,

diğerleri için ubuntu-24.04.

  • hygiene düzenli ifadelerle eşleştiriyor. Alıntılanmış bir hata mesajı gibi meşru bir eşleşme için

reponun .github/hygiene-allow.txt dosyasına bir satır gerekiyor.

  • readme-i18n-sync, İngilizce README'nin gerisinde kalan bir çeviriyi çağıran strict: true

vermedikçe hata değil uyarı olarak raporluyor.

Kaynak kod: github.com/muhittincamdali/.github

Etiketler

#github-actions#ci#reusable-workflows#swift#docc#devops
Muhittin Çamdalı

Muhittin Çamdalı

Senior Mobile Engineer

12+ yıllık deneyime sahip Senior Mobile Engineer. iOS, Flutter ve React Native ile mobil ürünler geliştiriyorum; full-stack ve AI-native çalışıyorum.

iOS Geliştirme Haberleri

Haftalık Swift tips, SwiftUI tricks ve iOS best practices. Spam yok, sadece değerli içerik.

Onay e-postasındaki bağlantıyı açıp “Aboneliğimi onayla” düğmesine bastığında aboneliğin başlar. Bültende açılma/tıklama istatistikleri tutulur; dilediğin an tek tıkla ayrılabilirsin. Gizlilik

Paylaş

İlgili İçerik