İçindekiler
- Problem
- Repoda ne var
- Tasarım kararları ve alternatifler
- Gerçek bir sorun: GitHub Pages'e sığmayan bir dokümantasyon sitesi
- Kullanım
- Sınırlar
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: CI2 3on:4 push:5 branches: [main]6 pull_request:7 8permissions: {}9 10jobs:11 swift:12 permissions:13 contents: read14 uses: muhittincamdali/.github/.github/workflows/swift-ci.yml@<sha> # v115 with:16 platforms: '["iOS", "macOS", "tvOS", "watchOS", "visionOS"]'17 18 hygiene:19 permissions:20 contents: read21 uses: muhittincamdali/.github/.github/workflows/hygiene.yml@<sha> # v1Tasarı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 Xcode2 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 of4 SwiftUI View modifiers every view gets. A package with many views otherwise produces a5 site too large for GitHub Pages.6 type: boolean7 default: falseve 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
- Repoya
.github/workflows/ci.ymlgibi bir workflow dosyası ekleyin ve yukarıdaki örnekteki
job'ları yazın. README tablosundaki izinleri her çağıran job'da verin.
<sha>yerine istediğiniz tag'in commit'ini yazın, tag'i yorum olarak bırakın.- Dokümantasyon için reponun Pages kaynağını "GitHub Actions" yapın ve
docc-pages'itargetsile
deploy: ${{ github.event_name != 'pull_request' }} vererek çağırın; pull request'ler yalnızca
build alır.
- Yeni tag'ler pull request olarak gelsin diye çağıran repoda
github-actionsiç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.
v1vev1.0.0aynı commit'i gösteriyor vev1,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.
hygienedü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ğıranstrict: true
vermedikçe hata değil uyarı olarak raporluyor.
Kaynak kod: github.com/muhittincamdali/.github

