
Leidimų perkėlimas į CI, dukart
GeekBye v1.8.4 perkėlė leidimų buildus į CI, skirtus macOS ir Windows. Ko changelog nesako — kad jau kartą tai bandėme anksčiau, po mėnesio ištrynėme dėl runnerių kainos ir prigijo tik antrą kartą, nes iki to laiko leidimo skriptas jau veikė rankiniu būdu.
v1.8.4 changelog turi eilutę, kuri skamba kaip grynas tvarkymasis: „Leidimų buildai dabar ateina iš CI ir macOS, ir Windows". Skaitosi kaip tai, kas nutinka vieną kartą, švariai, ir apie ką daugiau niekada negalvoji. Taip nebuvo. Komanda jau kartą buvo įdėjusi leidimus į CI — ir išplėšė atgal. Šis leidimas yra antras bandymas, o priežastis, kodėl jis prigijo, ir yra tikroji inžinerinė pamoka, tad papasakokime iš eilės.
Pirmas bandymas ir kodėl jis žuvo
2025 spalį egzistavo release.yml. Jis buvo paleidžiamas įkeliant tagą — mesk v*.*.* tagą, ir macOS runneris pakils, sukurs ir publikuos. Jis pats darė savo pasirašymo sąranką rankomis: žingsnis, kuris dekodavo pasirašymo sertifikatą, sukūrė ir atrakino laikiną keychain, importavo sertifikatą, kad codesign jį rastų, ir atitinkamas valymo žingsnis pabaigoje. Veikė. Buvo ir tik macOS — Windows leidimų CI nebuvo visai.
Lapkričio 4 jis buvo ištrintas. Commito žinutė neįprastai atvira dėl priežasties: „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." Tai visa pirmo bandymo istorija viename sakinyje. GitHub tarifikuoja macOS runnerio laiką dešimt kartų brangiau nei Linux, o tagu paleidžiamas leidimas reiškia, kad kiekvienas iki vieno tagas — įskaitant vienkartinius, pakartotinius tagus, tuos „oi, pamiršau pakelti versiją" — tyliai išleidžia šimtą tarifikuojamų minučių. Automatizacija, kurios nekontroliuoji, yra automatizacija, kuri leidžia pinigus, kol miegi. Tad leidimai grįžo į kūrėjo Mac kitiems trims su puse mėnesio.
Kur iš tikrųjų buvo išspręstos sunkios problemos
Štai dalis, dėl kurios antras bandymas veikia, ir įvyko ji visa už CI ribų. Per tuos tris su puse mėnesio vietinių leidimų scripts/release.js — paprastas Node skriptas, kurį kūrėjas paleidžia rankomis — sugėrė kiekvieną pakavimo problemą, kurią programa turėjo, po vieną pataisą:
- White-label atkūrimas. Tai white-label kodo bazė, kuri kuria ir GeekBye, ir Pavleur iš vieno šaltinio, o tai reiškia, kad leidimas pakeičia
package.jsonlaukus ir piktogramų assetus į tikslinį produktą. Dvi pataisos išmokė skriptą paskui viską grąžinti atgal, tad Pavleur kūrimas nepalikdavo tavo git medžio purvino su Pavleur tapatybe. - Dviejų architektūrų Windows. Pataisa, kad būtų kuriamos abi Windows diegyklės, x64 ir arm64, o ne viena.
- Apėjimas nepasirašytam Windows. Naujesnis electron-builder ignoravo konfigūracijos vėliavėlę, kuri turėjo išjungti Windows pasirašymą, tad skriptas išmoko priverstinai daryti nepasirašytą buildą, vietoj to aplinkoje nustatydamas
CSC_IDENTITY_AUTO_DISCOVERY=false— raukšlė, kurią randi tik ant jos užkliuvęs. - Notarizacijos automatinis aptikimas. Skriptas išmoko pažvelgti į savo aplinką ir nuspręsti: yra pasirašymo kredencialai? Pasirašyk. Yra ir Apple notarizacijos kredencialai? Notarizuok. Nei vienų? Kurk nepasirašytą. Jokių vėliavėlių, kurias reikia atsiminti; secrets buvimas ir yra konfigūracija.
Nieko iš to nėra prabangaus. Visa tai yra to sorto dalykai, kurie, jei nustebina tave viduje CI runnerio, kainuoja tau valandą ciklo push-lauk-nesėkmė-skaityk-logus už bandymą — su 10x tarifikacija. Išspręsta ant Mac, prieš kurį sėdi, kiekvienas kainuoja minutę.
Antras bandymas: šešiasdešimt šešios eilutės
Kai CI grįžo v1.8.4, workflow buvo 66 eilučių, ir jo apibrėžianti savybė yra tai, kaip mažai jis daro. Commitas tai aprašo tiesiai: „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." Kiekvienas dizaino sprendimas jame yra randas iš pirmo bandymo:
workflow_dispatch, o ne paleidimas tagu. Leidimą pradedi paspausdamas „Run workflow". Žmogus pro vartus praleidžia kiekvieną mokamą macOS minutę. Kainos problema, kuri užmušė pirmą versiją, išsprendžiama tiesiog neautomatizuojant trigerio — vienintelė vieta, kur automatizacija buvo aktyviai žalinga.productįvestis. Dispatch priima išskleidžiamą sąrašą —geekbyearbapavleur— tad tas pats workflow išleidžia bet kurį prekės ženklą. White-label siūlė nusidriekia iki pat leidimo mygtuko.- Dvi lygiagrečios užduotys.
build-macantmacos-latest,build-winantwindows-latest, veikiančios tuo pačiu metu. Windows CI čia iš tikrųjų naujas; spalio workflow jo niekada nekūrė. - Jokios pasirašymo logikos YAML. Čia visa esmė. Nėra žongliravimo keychain, nėra sertifikato importo žingsnio, nėra valymo. Mac užduotis paleidžia
node scripts/release.js <product> --publish, o Windows užduotis tą patį su--no-sign. Viskas, ką pirmas workflow darė rankomis YAML, dabar gyvena skripte, kuris jau veikia. Workflow yra orkestratorius, o ne realizacija.
Abi platformos nori priešingų dalykų, ir užduotys tai atspindi sąžiningai. macOS kuriamas po hardened runtime, pasirašytas ir notarizuotas įmontuotu electron-builder keliu (@electron/notarize), su kredencialais, tiekiamais iš repozitorijaus secrets ir automatiškai aptinkamais skripto. Windows kuria nepasirašytas NSIS diegykles, skirtas x64 ir arm64. Vienas workflow, dvi užduotys, dvi visiškai skirtingos „atlikta" sampratos.
Įrodymas yra tame, kas neįvyko
Štai kaip supranti, kad seka buvo teisinga: po dviejų tos pačios dienos pataisų, kurios pavadino paleidimus ir pataisė tokeno secreto pavadinimą, release.yml nebuvo liestas dar keturis mėnesius. Jokios skubios pasirašymo nesėkmės pataisos. Jokio blaškymosi dėl notarizacijos atmetimo. Jokios panikos „natyvaus dvejetainio failo trūksta runneryje". Pasirašymo-ir-notarizacijos pipeline — CI žanrui, labiausiai pagarsėjusiam savo blaškymusi — keturi mėnesiai tylos yra beveik negirdėtas dalykas.
Buvo tylu, nes triukšmas jau įvyko kažkur pigiau. Kovos, kurios paprastai vyksta CI logų kortelėje, su 10x tarifikacija, po vieną force-push kiekvieną kartą, įvyko ant kūrėjų Mac vietinėje eroje. CI neprivalėjo būti vieta, kur derinamas pakavimas, nes pakavimas jau buvo suderintas. Štai tezė vienoje eilutėje: perkelk buildą iš savo Mac tik tada, kai tavo Mac nustos tave stebinti.
Vienas susietumas, kuris vis dar gali įkąsti
Ne visai be silpnos vietos, ir verta ją įvardyti, nes ji subtili. Swift dvejetainiai failai, nuo kurių priklauso macOS programa — OCR, ekrano fiksavimas, transkriberiai — yra įkelti į git. Bet leidimas nesiunčia įkeltų kopijų; buildas perkompiliuoja juos runneryje. O check-swift-version.js vartai griežtai nutraukia visą leidimą, jei kompiliatorius nėra prisegtos versijos. Šiame leidime tas prisegimas buvo Swift 6.2.x, ir niekas workflow jo neįdiegia — užduotis tiesiog pasitiki, kad numatytasis macos-latest Swift sutampa. Tą dieną, kai GitHub pakels savo runnerio atvaizdą virš prisegimo, leidimas sustos — ne todėl, kad su programa kažkas negerai, o todėl, kad pipeline tyliai susietas su mašinos atvaizdu, kurio nekontroliuoja. Tai vienintelė realizacijos detalė, kurios šis plonas workflow nenustūmė žemyn į kažką savo.
Kita leidimo pusė: mažesni payloadai
Leidimas nešė vieną nesusijusią funkciją, vertą paminėjimo, nes tai švarus delsos taisymo atimant pavyzdys. Assist Me veiksmas kiekvienoje užklausoje siuntė į backendą daugiau konteksto, nei jam reikėjo. Vienas commitas apkarpė du dalykus: pridedama transkripto istorija nukrito nuo paskutinių 30 įrašų iki paskutinių 15, o naudotojo profilio konteksto failai — įterpiami į sisteminį promptą kiekvieno iškvietimo metu — gavo griežtą 4,000 simbolių lubą su nukirpimo žymekliu. Mažiau serializuoti, mažiau įkelti, mažiau skaityti modeliui, kol jis pradės atsakinėti, o tai ir yra metrika, kurią commitas optimizuoja: time-to-first-token. Sąžiningumo dėlei: commitas pagreitėjimą teigia, bet jo nematuoja — istorijoje nėra prieš/po skaičiaus, tad traktuok tai kaip gerai pagrįstą apkarpymą, o ne benchmarku patvirtintą pergalę.
Trys dalykai, kurių mus išmokė šis leidimas
- CI yra plonas apvalkalas virš skripto, kuris jau veikia. 66 eilučių workflow neturi savos pasirašymo logikos; jis kviečia skriptą, kurį trys mėnesiai vietinių leidimų jau nugludino. Įdėk mechanizmą į tai, ką gali paleisti rankomis, ir tegul CI tik nusprendžia, kada jį paleisti.
- Automatizuok darbą, nebūtinai trigerį. Pirmas bandymas žuvo, nes tagu paleidžiami leidimai automatiškai eikvojo 10x tarifikuojamas runnerio minutes. Rankinis
workflow_dispatchišlaiko automatizaciją ir pašalina dalį, kuri kainavo pinigus — kartais žmogus kilpoje ir yra ta funkcija. - Derink ten, kur iteracija pigi. Kiekviena pakavimo kova, išspręsta ant kūrėjo Mac, yra kova, kuri niekada nevyksta CI logų kortelėje už dešimteriopą kainą. Palik Mac paskutinis, o ne pirmas.
Ankstesniam v1 istorijos skyriui — trisdešimties kalbų išleidimas be apsauginio tinklo (v1.8.3); o visai istorijos linijai — programinės įrangos tobulybės pristatymo anatomija.