Langsung ke konten utama

Build dan Deploy Aplikasi iOS dengan Gitea Actions

Build, sign, dan upload aplikasi iOS ke TestFlight dari Gitea Actions: self-hosted Mac runner dengan act_runner, atau cloud builds dari Linux runner.

Workflow Gitea Actions membangun aplikasi iOS bertanda tangan untuk TestFlight

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://image menjalankan job di dalam container. Ini adalah default untuk runner Linux.
  • host menjalankan 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@v4 berjalan karena Gitea secara default me-resolve actions dari GitHub (pengaturan DEFAULT_ACTIONS_URL setting). 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 Gemfile dengan bundle 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 .env file-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. Konteks github.* juga berfungsi sebagai alias, yang membantu saat Anda memporting workflow.
  • Gitea sets CI=true di 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:

  1. Tag yang dilindungi. Hanya release manager yang dapat push v* tags, dan workflow tag akan dikirim.
  2. Build, lalu promote. Build di setiap push ke main dengan --ios-distribution ad_hoc atau upload ke TestFlight internal testing saja, lalu gunakan workflow_dispatch workflow (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.

Live updates untuk aplikasi Capacitor

Saat bug web-layer sudah live, kirim perbaikannya lewat Capgo alih-alih menunggu berhari-hari untuk persetujuan app store. Pengguna mendapat update di background, sementara perubahan native tetap mengikuti jalur review normal.

Terbaru dari Blog kami

Capgo memberikan insight terbaik yang Anda butuhkan untuk membuat aplikasi mobile yang benar-benar profesional.