Steven
Steven6 dk okuma

Release'i CI'ye Koymak, İki Kez

GeekBye v1.8.4 release build'lerini macOS ve Windows için CI'ye taşıdı. Changelog'un söylemediği şey şu: bunu bir kez daha önce denedik, runner maliyetleri yüzünden bir ay sonra sildik, ve ancak ikinci seferde kalıcı kıldık — çünkü o zamana dek release script'i zaten elle çalışıyordu.

Mühendislik
CI/CD
Desktop
GeekBye Releases
Release'i CI'ye Koymak, İki Kez

v1.8.4 changelog'unda saf ev işi gibi görünen bir satır var: "Release build'leri artık hem macOS hem Windows için CI'den geliyor." Bir kez, temiz bir şekilde olan ve bir daha asla düşünülmeyen türden bir şey gibi okunuyor. Öyle değildi. Ekip release'leri CI'ye zaten bir kez koymuştu — ve söküp atmıştı. Bu release ikinci deneme, ve kalıcı olmasının nedeni asıl mühendislik dersi, o yüzden sırayla anlatalım.

İlk deneme, ve neden öldüğü

Ekim 2025'te bir release.yml vardı. Tag push'unda tetikleniyordu — bir v*.*.* tag'i it, bir macOS runner'ı ayağa kalkar, derler ve yayınlardı. Kendi imzalama kurulumunu elle yapıyordu: imzalama sertifikasını çözen, geçici bir keychain oluşturup kilidini açan, codesign'ın bulabilmesi için sertifikayı içe aktaran bir adım, ve sonda ona karşılık gelen bir temizlik adımı. Çalışıyordu. Ayrıca yalnızca macOS'tu — Windows release'leri hiç CI'de değildi.

4 Kasım'da silindi. Commit mesajı nedeni konusunda alışılmadık derecede açık sözlü: "remove GitHub Actions release workflow to conserve minutes / macOS runners cost 10x multiplier (100 billed minutes per 10-minute release). Releases will be done locally." İlk denemenin bütün hikâyesi tek cümlede bu. GitHub, macOS runner süresini Linux'un on katı ücretle faturalar, ve tag ile tetiklenen bir release demek her bir tag'in — usulüne uygun atılıp atılanlar, yeniden-tag'ler, "eyvah, sürüm yükseltmeyi unuttum"lar dahil — sessizce yüz faturalı dakika harcaması demek. Kontrol etmediğin otomasyon, sen uyurken para harcayan otomasyondur. Böylece release'ler sonraki üç buçuk ay boyunca bir geliştiricinin Mac'ine geri döndü.

Zor sorunların asıl nerede çözüldüğü

İkinci denemeyi çalıştıran kısım işte burada, ve tamamen CI'nin dışında oldu. O üç buçuk aylık yerel release boyunca, scripts/release.js — bir geliştiricinin elle çalıştırdığı sade Node script'i — uygulamanın sahip olduğu her paketleme sorununu, tek tek düzeltme olarak emdi:

  • White-label restore. Bu, GeekBye ve Pavleur'ün ikisini de tek kaynaktan derleyen white-label bir kod tabanı, yani bir release hedef ürün için package.json alanlarını ve icon asset'lerini takas eder. İki düzeltme script'e sonradan her şeyi geri koymayı öğretti, böylece Pavleur derlemek git ağacını Pavleur'ün kimliğiyle kirli bırakmadı.
  • Dual-arch Windows. Tek yerine hem x64 hem arm64 Windows installer'ı derlemek için bir düzeltme.
  • İmzasız-Windows geçici çözümü. Daha yeni electron-builder, Windows imzalamayı devre dışı bırakması gereken config flag'ini görmezden geldi, bu yüzden script bunun yerine ortama CSC_IDENTITY_AUTO_DISCOVERY=false koyarak imzasız bir build'i zorlamayı öğrendi — ancak çarpınca bulduğun bir kırışıklık.
  • Noterleme otomatik-algılaması. Script ortamına bakıp karar vermeyi öğrendi: imzalama kimlik bilgileri var mı? İmzala. Apple noterleme kimlik bilgileri de var mı? Noterle. Hiçbiri yok mu? İmzasız derle. Hatırlanacak flag yok; secret'ların varlığı kendisi yapılandırmadır.

Bunların hiçbiri gösterişli değil. Hepsi, eğer bir CI runner'ının içinde seni şaşırtırsa, deneme başına bir saatlik push-bekle-başarısız-ol-logları-oku'ya mal olan türden şeyler — 10x faturalamayla. Önünde oturduğun bir Mac'te çözülünce, her biri bir dakikaya mal olur.

İkinci deneme: altmış altı satır

CI v1.8.4'te geri geldiğinde, workflow 66 satırdı, ve onu tanımlayan nitelik ne kadar az iş yaptığı. Commit bunu açıkça anlatıyor: "Manual workflow_dispatch trigger that builds both platforms in parallel, reusing existing release.js script. macOS builds are signed and notarized, Windows builds are unsigned." İçindeki her tasarım kararı ilk denemenin acıyla öğrettiği bir ders:

  • workflow_dispatch, tag ile tetiklenmiyor. Bir release'i "Run workflow"a tıklayarak başlatırsın. Her ücretli macOS dakikasını bir insan kapıda tutar. İlk sürümü öldüren maliyet sorunu, tetikleyiciyi basitçe otomatikleştirmeyerek çözülüyor — otomasyonun etkin biçimde zararlı olduğu tek yer.
  • Bir product girdisi. Dispatch bir açılır menü alır — geekbye ya da pavleur — böylece aynı workflow iki markadan birini sevk eder. White-label dikişi ta release düğmesine kadar uzanıyor.
  • İki paralel job. macos-latest üzerinde build-mac, windows-latest üzerinde build-win, aynı anda çalışıyor. Burada CI'de Windows gerçekten yeni; Ekim workflow'u onu hiç derlemedi.
  • YAML'da imzalama mantığı yok. Bütün mesele bu. Keychain hokkabazlığı yok, sertifika içe aktarma adımı yok, temizlik yok. Mac job'ı node scripts/release.js <product> --publish çalıştırır ve Windows job'ı aynısını --no-sign ile çalıştırır. İlk workflow'un YAML'da elle yaptığı her şey artık zaten çalışan script'te yaşıyor. Workflow bir orkestratör, bir implementasyon değil.

İki platform zıt şeyler ister, ve job'lar bunu dürüstçe yansıtır. macOS, hardened runtime altında, electron-builder'ın yerleşik yolu (@electron/notarize) üzerinden, kimlik bilgileri repository secret'larından sağlanıp script tarafından otomatik algılanarak, imzalı ve noterli derler. Windows, x64 ve arm64 için imzasız NSIS installer'ları derler. Tek workflow, iki job, "bitti"nin tamamen farklı iki anlayışı.

Kanıt, olmayan şeyde

Sıralamanın doğru olduğunu şöyle anlarsın: çalıştırmalara ad veren ve bir token secret'ının adını düzelten aynı gün yapılan iki ince ayardan sonra, release.yml'e dört ay boyunca bir daha dokunulmadı. İmzalama-başarısızlığı hotfix'i yok. Noterleme-reddi telaşı yok. "Native binary runner'da eksik" paniği yok. Bir kod-imzalama-ve-noterleme pipeline'ı için — çırpınmasıyla en kötü ünlü CI türü — dört ay sessizlik neredeyse duyulmamış bir şey.

Sessizdi çünkü gürültü zaten daha ucuz bir yerde olmuştu. Genellikle bir CI logları sekmesinde, 10x faturalamayla, her seferinde bir force-push ile yaşanan kavgalar, yerel dönemde geliştiricilerin Mac'lerinde yaşanmıştı. Paketlemenin ayıklandığı yer CI olmak zorunda değildi, çünkü paketleme zaten ayıklanmıştı. Tek satırlık tez bu: build'i Mac'inden ancak Mac'in seni şaşırtmayı bıraktıktan sonra taşı.

Hâlâ canını yakabilecek tek bağlılık

Tamamen zayıf noktasız değil, ve incelikli olduğu için adını koymaya değer. macOS uygulamasının bağımlı olduğu Swift binary'leri — OCR, ekran yakalama, transkripsiyoncular — git'e commit'li. Ama release commit'li kopyaları sevk etmez; build onları runner'da yeniden derler. Ve bir check-swift-version.js kapısı, derleyici sabitlenmiş sürüm değilse tüm release'i sert biçimde başarısız kılar. Bu release'de o sabit sürüm Swift 6.2.x'ti, ve workflow'da hiçbir şey onu kurmuyor — job basitçe macos-latest'in varsayılan Swift'inin eşleştiğine güveniyor. GitHub runner imajını sabitlenmiş sürümün ötesine yükselttiği gün release durur, uygulamada bir sorun olduğu için değil, pipeline sessizce kontrol etmediği bir makine imajına bağlı olduğu için. Bu ince workflow'un sahip olduğu bir şeye aşağı itmediği tek implementasyon detayı bu.

Release'in diğer yarısı: daha küçük payload'lar

Release, anmaya değer alakasız bir özellik taşıdı, çünkü çıkarma yoluyla gecikme düzeltmesinin temiz bir örneği. Assist Me eylemi her istekte backend'e ihtiyacından fazla context gönderiyordu. Bir commit iki şeyi kırptı: birlikte gönderilen transcript geçmişi son 30 girdiden son 15 girdiye düştü, ve kullanıcının profil context dosyaları — her çağrıda system prompt'a enjekte edilen — bir kırpma işaretiyle 4,000 karaktere sert biçimde sınırlandı. Serileştirilecek daha az, yüklenecek daha az, modelin yanıtlamaya başlamadan önce okuyacağı daha az şey — ki commit'in optimize ettiği metrik de bu: time-to-first-token. Dürüstlük adına: commit hızlanmayı iddia ediyor ama ölçmüyor — geçmişte önce/sonra rakamı yok, o yüzden bunu ölçülmüş bir zafer değil, iyi gerekçelendirilmiş bir kırpma olarak değerlendir.

Bu release'in bize öğrettiği üç şey

  1. CI, zaten çalışan bir script üzerinde ince bir sarmalayıcıdır. 66 satırlık workflow'un kendine özgü imzalama mantığı yok; üç aylık yerel release'in zaten ayıkladığı bir script'i çağırır. Mekanizmayı elle çalıştırabileceğin bir şeye koy, ve CI'nin yalnızca onu ne zaman çalıştıracağına karar vermesine izin ver.
  2. İşi otomatikleştir, illa tetikleyiciyi değil. İlk deneme öldü çünkü tag ile tetiklenen release'ler 10x-faturalı runner dakikalarını otomatik harcadı. Manuel workflow_dispatch otomasyonu korur ve para harcayan kısmı kaldırır — bazen döngüdeki insan asıl özelliktir.
  3. Yinelemenin ucuz olduğu yerde ayıkla. Bir geliştiricinin Mac'inde çözülen her paketleme kavgası, on kat fiyata bir CI logları sekmesinde asla yaşanmayan bir kavgadır. Mac'ten en son çık, ilk değil.

v1 hikâyesinin bir önceki bölümü için, güvenlik ağı olmadan otuz dil sevk etmek (v1.8.3); tüm yay için de yazılımı kusursuzluğa kadar sevk etmenin anatomisi.

İlgili Makaleler

Web Audio'yu Hayatta Tutan Üç Fiil
Steven
Steven8 dk okuma

Web Audio'yu Hayatta Tutan Üç Fiil

İki ay arayla ve iki farklı dosyada, iki GeekBye nokta sürümü, ses kodumuza aynı dersi zıt uçlardan öğretti: tarayıcının AudioContext'ini tek kullanımlıkmış gibi ele almayı bırak. Bir sürüm, macOS'un kayıt ortasında sessizce askıya aldığı bir bağlamı resume() etmeyi öğrendi; diğeri, ardışık oturumların Chromium'un yaklaşık altı bağlamlık tavanına toslamayı bırakması için close() yerine suspend() yapmayı öğrendi. Resume, suspend, close — bütün olay örgüsü bu.

Mühendislik
Audio
Desktop
Bir Görüşmeyi Açık Bir Uygulamadan Ayırt Etmek
Steven
Steven7 dk okuma

Bir Görüşmeyi Açık Bir Uygulamadan Ayırt Etmek

GeekBye bir video görüşmesine katıldığınızı fark edip onu kaydetmeyi teklif edebilir. Tespit, kolay yarı olarak çıkıyor — her on saniyede pencere başlıklarını okuyan bir Swift ikili dosyası. Zor yarı kesinliktir: Zoom sadece açıkken tetiklenmemek, zaten kaydettiğiniz bir görüşme için sormamak, ve gerçekten içinde bulunduğunuz görüşmede mikrofonu susturmamak. Üç sürüm, ve her biri kendini yenmemeyi öğrenmek zorunda kalan bir korumadır.

Mühendislik
macOS
Desktop
Backend'i Yükleme Yolundan Çıkarmak
Steven
Steven7 dk okuma

Backend'i Yükleme Yolundan Çıkarmak

GeekBye ekranınızı kaydeder ve videoyu Google Drive'ınıza kaydeder. İlk sürüm her kaydı oraya giderken GeekBye'in kendi sunucuları üzerinden geçirdi; bir sürüm sonra, dosya makinenizden doğrudan Drive'a gitti, ve backend tek bir işaretçiyi tutmaya indirgendi. İlginç kısım, 'doğrudan, devam ettirilebilir' sürümün aslında ne kadar az kod içerdiğidir — çünkü devam ettirilebilirlik bir proxy yazmaktan değil, bir proxy'yi silmekten geldi.

Mühendislik
Mimari
Desktop