Gitea Actions dapat membangun aplikasi iOS, tetapi hanya di Mac yang Anda daftarkan sendiri, karena Gitea tidak memiliki runner hosted dan Xcode hanya berjalan di macOS. Dua setup praktis adalah Mac yang menjalankan act_runner dalam mode host, atau runner Linux biasa yang mengirim build iOS ke layanan build cloud. Panduan ini membahas keduanya untuk aplikasi Capacitor, dengan file workflow yang bisa Anda letakkan di .gitea/workflows/.
Tim memilih Gitea karena mereka ingin code mereka berada di infrastruktur yang mereka kendalikan. Hal ini tidak seharusnya berubah hanya karena aplikasi membutuhkan Xcode. Kedua setup di bawah ini tetap menyimpan sumber kode Anda di server Anda.
Cara Gitea Actions menjalankan job
Gitea Actions menggunakan sintaks yang kompatibel dengan GitHub Actions, dan job berjalan di act_runner instance yang Anda daftarkan ke server Gitea Anda. Setiap runner mengiklankan label seperti ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest. Bagian setelah titik dua menentukan cara job dijalankan:
docker://imagemenjalankan job di dalam container. Ini adalah default untuk runner Linux.hostmenjalankan job langsung di mesin, dengan apa pun yang sudah terinstal di sana.
macOS tidak bisa dijalankan di dalam container Docker, jadi runner Mac harus menggunakan host label. Hal ini memiliki konsekuensi yang akan kita bahas.
Dua catatan kompatibilitas sebelum Anda menyalin workflow dari GitHub:
- Gitea membaca
.gitea/workflows/dan fallback ke.github/workflows/saat folder pertama tidak ada. uses: actions/checkout@v4berjalan karena Gitea secara default me-resolve actions dari GitHub (pengaturanDEFAULT_ACTIONS_URLsetting). Instance air-gapped perlu mencerminkan actions yang digunakan dan merujuknya menggunakan URL lengkap.
Opsi 1: Mac runner dengan act_runner
Daftarkan Mac
Download the act_runner binary untuk macOS (arm64 untuk Apple Silicon) dari halaman release Gitea, lalu ambil registration token dari Administrasi Situs > Actions > Runners (untuk seluruh instance), atau dari pengaturan organisasi atau repositori.
./act_runner register --no-interactive \
--instance https://gitea.example.com \
--token <registration_token> \
--name mac-mini-01 \
--labels macos-arm64:host
./act_runner daemon
Jalankan daemon sebagai launch agent di bawah user khusus agar otomatis restart setelah reboot dan memiliki login keychain sendiri.
Instal toolchain di host
Mode host berarti job menggunakan tool bawaan Mac. Instal:
- Xcode 26 (wajib untuk upload ke App Store Connect sejak 28 April 2026) dan jalankan
sudo xcodebuild -license accept - Node.js 22 atau lebih baru dan Bun (Capacitor 8 membutuhkan Node 22)
- Ruby dan fastlane, atau gunakan
Gemfiledenganbundle exec - CocoaPods, hanya jika proyek iOS Anda masih menggunakannya. Proyek Capacitor 8 baru menggunakan Swift Package Manager.
Alur kerja
# .gitea/workflows/ios-mac.yaml
name: iOS release (Mac runner)
on:
push:
tags:
- 'v*'
jobs:
ios:
runs-on: macos-arm64
env:
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
APP_STORE_CONNECT_TEAM_ID: ${{ vars.APP_STORE_CONNECT_TEAM_ID }}
PROFILE_NAME: ${{ vars.IOS_PROFILE_NAME }}
steps:
- uses: actions/checkout@v4
- run: bun install --frozen-lockfile
- run: bun run build
- run: bunx cap sync ios
- name: Decode signing files
run: |
echo "${{ secrets.IOS_CERTIFICATE_BASE64 }}" | base64 --decode > dist.p12
echo "${{ secrets.IOS_PROFILE_BASE64 }}" | base64 --decode > profile.mobileprovision
- run: bundle exec fastlane ios beta
- name: Clean up
if: always()
run: rm -f dist.p12 profile.mobileprovision
Panduan beta lane mengimpor sertifikat ke keychain sementara, mengubah proyek ke penandatanganan manual, menaikkan nomor build dari TestFlight, mengarsipkan, dan mengunggah. Fastfile lengkap untuk proyek Capacitor ada di Build dan deploy aplikasi iOS dengan Bitbucket Pipelines; berfungsi tanpa perubahan di Gitea. Untuk latar belakang fastlane, lihat panduan iOS GitHub Actions.
Biaya mode host
Panduan act_runner dokumentasinya langsung tentang hal ini: host jobs tidak terisolasi. Dalam praktiknya:
- Setiap job berbagi user, disk, dan keychain yang sama. Job yang mati di tengah jalan bisa meninggalkan keychain sementara atau provisioning profile yang usang yang merusak job berikutnya.
- Setiap workflow yang menargetkan label tersebut menjalankan code di Mac tersebut dengan akses user tersebut. Hanya daftarkan host runners untuk repositori yang Anda percaya, dan hindari menjalankannya pada pull request dari fork.
- DerivedData, arsip, dan runtime simulator terus membesar hingga disk penuh.
- Upgrade Xcode jadi tanggung jawabmu, dan Apple menaikkan minimum SDK setiap musim semi.
- Satu Mac hanya memproses satu job sekaligus. Antrean panjang di hari rilis.
Jika timmu sudah menjalankan Mac dan ada yang mengelolanya, ini bisa jalan. Jika tidak, opsi berikutnya menghilangkan Mac dari infrastrukturmu.
Opsi 2: Build iOS dari runner Linux dengan Capgo Build
Build Capgo mengompilasi dan menandatangani aplikasi Capacitor di Mac yang dikelola Capgo. Job Gitea Anda tetap berjalan di runner Linux yang sudah Anda pakai. Ia melakukan checkout code, mem-build layer web, menjalankan cap sync ios, dan memanggil build request. Capgo CLI mengunggah proyek native yang sudah disiapkan, mengirim log Xcode kembali ke log job Gitea, dan exit dengan kode non-zero jika gagal.
Model ini cocok untuk Gitea self-hosted:
- Tanpa akses inbound. Capgo tidak meng-clone repositori Anda. Runner Anda push proyek yang sudah disiapkan lewat HTTPS, jadi server Gitea di balik firewall atau VPN tetap jalan tanpa perubahan.
- Tanpa token repositori. Tidak ada koneksi Git yang perlu dikonfigurasi di sisi Capgo.
- Source web Anda tetap di infrastruktur Anda sendiri. Hanya native
ios/folder, konfigurasi Capacitor, dan bagian native dari plugin yang diunggah.src/,.git/, dan.envfile-file tersebut tidak.
Setup satu kali
Di mesin developer:
bunx @capgo/cli@latest login
bunx @capgo/cli@latest app add
bunx @capgo/cli@latest build init --platform ios
build init membuat atau menggunakan ulang sertifikat distribusi dan profil provisioning App Store, serta menyimpan kunci App Store Connect API. Jalankan satu build secara lokal untuk memastikan semuanya ditandatangani dengan benar:
bun run build && bunx cap sync ios
bunx @capgo/cli@latest build request com.example.app --platform ios --build-mode release
Lalu ekspor kredensialnya:
bunx @capgo/cli@latest build credentials manage --appId com.example.app --platform ios
# select "Export to .env"
Tambahkan secrets ke Gitea
Buka Pengaturan Repository > Actions > Secrets dan tambahkan setiap key dari file yang diekspor, plus key Capgo API Anda:
| Secret | Tujuan |
|---|---|
CAPGO_TOKEN |
Key Capgo API dengan izin upload |
BUILD_CERTIFICATE_BASE64 |
Sertifikat distribusi (.p12) |
P12_PASSWORD |
Kata sandi sertifikat |
CAPGO_IOS_PROVISIONING_MAP_BASE64 |
Pemetaan profil provisioning |
APPLE_KEY_ID |
ID key App Store Connect API |
APPLE_ISSUER_ID |
ID issuer App Store Connect |
APPLE_KEY_CONTENT |
Base64 .p8 key |
APP_STORE_CONNECT_TEAM_ID |
Apple team ID |
Gitea menolak nama secret dan variable yang diawali dengan GITEA_ atau GITHUB_, jadi biarkan nama-nama ini apa adanya. Letakkan nilai non-secret seperti app ID di bawah Variabel dan baca nilainya dengan ${{ vars.NAME }}. Secret yang diset di level organisasi dibagikan ke semua repository di dalamnya, yang berguna saat Anda merilis beberapa app dari satu Apple team. Hapus file yang diekspor setelah selesai.
Release saat push tag
# .gitea/workflows/ios-release.yaml
name: iOS release
on:
push:
tags:
- 'v*'
jobs:
release-ios:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- run: bun run build
- run: bunx cap sync ios
- name: Build, sign, and upload to TestFlight
env:
CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }}
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
CAPGO_IOS_PROVISIONING_MAP_BASE64: ${{ secrets.CAPGO_IOS_PROVISIONING_MAP_BASE64 }}
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }}
run: |
bunx @capgo/cli@latest build request ${{ vars.APP_ID }} \
--platform ios \
--build-mode release \
--ios-distribution app_store \
--store-release-name "${{ gitea.ref_name }}"
Catatan:
${{ gitea.ref_name }}adalah nama tag. Konteksgithub.*juga berfungsi sebagai alias, yang membantu saat Anda memporting workflow.- Gitea sets
CI=truedi setiap job, sehingga Capgo CLI tidak pernah menunggu input interaktif. - Capgo menaikkan nomor build dari build TestFlight terbaru, sehingga dua tag berurutan tidak akan bentrok.
- Tanpa
--submit-to-store-review, build akan masuk ke TestFlight dan berhenti. Tambahkan flag ini jika Anda ingin CI juga mengirim untuk App Review.
Releasing sekarang git tag v2.3.0 && git push origin v2.3.0. Siapa pun yang bisa push v* tag bisa merilis, jadi tambahkan aturan protected tag untuk v* di bawah Pengaturan > Tags dan batasi hanya untuk release manager.
Ad hoc build untuk tester
Untuk QA build yang diinstal langsung di perangkat terdaftar, build dalam mode ad hoc dan dapatkan link download:
# .gitea/workflows/ios-adhoc.yaml
name: iOS ad hoc build
on:
workflow_dispatch:
jobs:
adhoc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile && bun run build
- run: bunx cap sync ios
- name: Ad hoc build
env:
CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }}
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }}
run: |
echo "${{ secrets.ADHOC_PROFILE_BASE64 }}" | base64 --decode > adhoc.mobileprovision
bunx @capgo/cli@latest build request ${{ vars.APP_ID }} \
--platform ios \
--ios-distribution ad_hoc \
--ios-provisioning-profile ./adhoc.mobileprovision \
--output-upload --output-retention 3d \
--output-record /tmp/build.json
bunx @capgo/cli@latest build last-output --path /tmp/build.json --field outputUrl
Ad hoc build membutuhkan ad hoc provisioning profile yang mencantumkan perangkat uji. Simpan profil tersebut ter-encode base64 sebagai secret (ADHOC_PROFILE_BASE64 di atas), decode di job, dan lewati dengan --ios-provisioning-profile. Flag CLI memiliki prioritas lebih tinggi daripada variabel lingkungan, sehingga ini menimpa profil App Store hanya untuk build ini. Kumpulkan UDID dengan Pencari UDID iOS. Untuk kebanyakan tester, internal testing TestFlight lebih sederhana karena tidak membutuhkan UDID.
Persetujuan release manual
GitHub memungkinkan Anda mewajibkan reviewer pada environment. Gitea Actions tidak mengimplementasikan aturan perlindungan environment, jadi job yang menyebut environment tidak akan berhenti untuk persetujuan. Dua pola bekerja sebagai gantinya:
- Tag yang dilindungi. Hanya release manager yang dapat push
v*tags, dan workflow tag akan dikirim. - Build, lalu promote. Build di setiap push ke
maindengan--ios-distribution ad_hocatau upload ke TestFlight internal testing saja, lalu gunakanworkflow_dispatchworkflow (tersedia di rilis Gitea saat ini) untuk rebuild commit yang disetujui dengan--submit-to-store-review.
Deploy perubahan web tanpa binary baru
Sebagian besar commit ke aplikasi Capacitor hanya mengubah JavaScript, CSS, dan HTML. Rebuild iOS untuk perubahan itu membuang-buang menit dan waktu App Review. Dengan Live updates Capgo, satu job bisa memilih jalur yang tepat:
- name: Live update or native build
env:
CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }}
# plus the iOS signing secrets from above
run: |
if bunx @capgo/cli@latest build needed ${{ vars.APP_ID }} --channel production; then
bunx @capgo/cli@latest bundle upload ${{ vars.APP_ID }} --channel production
else
bunx cap sync ios
bunx @capgo/cli@latest build request ${{ vars.APP_ID }} --platform ios --build-mode release
fi
build needed berhenti dengan 0 jika dependensi native cocok dengan yang live di channel, dan 1 jika binary baru diperlukan. Paksa juga jalur native ketika file di bawah ios/ atau capacitor.config.* berubah, karena file tersebut tidak termasuk dalam perbandingan dependensi. Lihat Pilih otomatis live update atau native build.
Mac runner vs cloud build
| act_runner di Mac Anda | Capgo Build dari Linux | |
|---|---|---|
| Hardware | Anda beli dan host sendiri | Tidak ada |
| Upgrade Xcode | Manual, per mesin | Ditangani oleh Capgo |
| Isolasi antar job | Tidak ada di mode host | Lingkungan build baru per job |
| Build paralel | Satu per Mac | Banyak, dari runner mana pun |
| File penandatanganan | Di secrets Gitea, didekode di Mac | Di secrets Gitea, dikirim per build |
| Bisa berjalan di balik firewall | Ya | Ya, hanya HTTPS outbound |
| Aplikasi Native Swift (tanpa Capacitor) | Ya | Tidak, hanya aplikasi Capacitor |
| Batas waktu build | Bebas Anda atur | 10 menit per build |
Pemecahan Masalah
| Gejala | Perbaikan |
|---|---|
| Job tetap mengantre selamanya | Tidak ada runner online dengan label itu runs-on. Periksa daftar runner dan ejaan label. |
uses: actions/checkout@v4 gagal mengunduh |
Runner tidak dapat mengakses GitHub. Mirror action di Gitea Anda dan referensikan dengan URL lengkap. |
| Nilai secret kosong di job | Nama dimulai dengan GITEA_/GITHUB_, atau secret didefinisikan di repository lain. |
security: SecKeychainItemImport: MAC verification failed |
Salah .p12 password, atau .p12 dibuat oleh OpenSSL 3 tanpa -legacy. Ekspor ulang. |
No profiles for 'com.example.app' were found |
Profil di secrets tidak cocok dengan bundle ID atau sertifikat. Jalankan ulang build init dan ekspor ulang. |
| Upload ditolak untuk versi SDK | Mac runner masih menggunakan Xcode versi di bawah 26. |
cap sync ios memperingatkan tentang CocoaPods di Linux |
Sudah sesuai. Mesin build Capgo menginstal pods. |
Untuk mode kegagalan lainnya, lihat CI/CD untuk Capacitor: kesalahan umum dan Panduan troubleshooting Capgo Build.
Ringkasan
Gitea Actions menangani iOS dengan baik setelah Anda memutuskan di mana Xcode dijalankan. Mac runner mode host memberi Anda kontrol penuh dan tanggung jawab penuh. Job Linux yang memanggil Capgo Build menjaga setup Gitea Anda tetap tidak berubah, tidak memerlukan akses inbound, dan mengubah rilis TestFlight menjadi tag push. Apapun yang Anda pilih, simpan materi signing di Gitea secrets, lindungi tag rilis Anda, dan kirim perubahan web-only sebagai live updates agar pipeline native hanya berjalan saat diperlukan.