Gitea ActionsはiOSアプリのビルドに対応していますが、Giteaにはホスト型ランナーがなく、XcodeはmacOSでのみ動作するため、自分で登録したMacでのみ実行できます。現実的な構成は2つあり、1つはMacを act_runner ホストモードで実行する構成、もう1つは通常のリナックスランナーからiOSビルドをクラウドビルドサービスに送信する構成です。本ガイドでは、Capacitorアプリの両方の構成について、そのまま .gitea/workflows/.
チームがGiteaを選ぶのは、自分たちで管理するインフラ上に code を置きたいからです。アプリにXcodeが必要になったからといって、そこが変わるべきではありません。以下の2つの構成はどちらも、ソースコードを自社サーバーに保持します。
Gitea Actionsによるジョブの実行方法
Gitea Actions は GitHub Actions 互換の構文を使い、ジョブは act_runner Giteaサーバーに登録したインスタンス上で実行されます。各ランナーは次のようなラベルを公開します: ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest。コロンより後で、ジョブの実行方法が決まります:
docker://imageはコンテナ内でジョブを実行します。Linuxランナーではこれがデフォルトです。hostはマシンにインストールされているものを使って、ジョブを直接実行します。
macOS は Docker コンテナ内で実行できないため、Mac ランナーは host ラベルを使う必要があります。これには後述する注意点があります。
ワークフローを GitHub からコピーする前に、互換性の注意点が2つあります:
- Giteaは
.gitea/workflows/を読み取り、なければ次にフォールバックします:.github/workflows/最初のフォルダが存在しない場合。 uses: actions/checkout@v4デフォルトで GitHub からアクションを解決するため動作します(DEFAULT_ACTIONS_URL設定)。エアギャップ環境では、使用するアクションをミラーリングし、完全なURLで参照する必要があります。
オプション1: act_runner を備えた Mac ランナー
Mac の登録
ダウンロード act_runner Gitea のリリースページから macOS 用バイナリ(Apple Silicon なら arm64)をダウンロードし、 サイト管理 > Actions > Runners (インスタンス全体)または、組織またはリポジトリの設定から登録トークンを取得します。
./act_runner register --no-interactive \
--instance https://gitea.example.com \
--token <registration_token> \
--name mac-mini-01 \
--labels macos-arm64:host
./act_runner daemon
デーモンを専用ユーザーの launch agent として実行し、再起動後に自動で再起動されるようにし、独自のログインキーチェーンを持たせます。
ホストにツールチェーンをインストール
ホストモードでは、ジョブが Mac 自身のツールを使用します。以下をインストールします:
- Xcode 26(2026 年 4 月 28 日以降の App Store Connect アップロードに必須)をインストールし、
sudo xcodebuild -license accept - Node.js 22 以降と Bun(Capacitor 8 は Node 22 が必要)
- Ruby と fastlane、または
Gemfileを使用してbundle exec - CocoaPods は、iOS プロジェクトがまだ使っている場合のみ。新しい Capacitor 8 プロジェクトは Swift Package Manager を使います。
ワークフロー
# .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
この beta lane は証明書を一時キーチェーンにインポートし、プロジェクトを手動署名に切り替え、TestFlight のビルド番号をインクリメントしてアーカイブし、アップロードします。Capacitor プロジェクト向けの完全な Fastfile は Bitbucket Pipelines で iOS アプリをビルド・デプロイにあります。Gitea でもそのまま動作します。fastlane の背景については、 GitHub Actions iOS ガイド.
ホストモードのコスト
この act_runner ドキュメントはこの点について率直に述べています:ホストジョブは分離されていません。実際には:
- すべてのジョブが同じユーザー、ディスク、キーチェーンを共有します。途中で失敗したジョブが一時キーチェーンや古いプロビジョニングプロファイルを残し、次のジョブを壊すことがあります。
- そのラベルを対象とするワークフローは、その Mac 上でそのユーザーの権限で code を実行します。ホストランナーは信頼できるリポジトリにのみ登録し、フォークからのプルリクエストでは実行しないでください。
- DerivedData、アーカイブ、シミュレータランタイムが肥大化し、ディスクがいっぱいになります。
- Xcodeのアップグレードは自分で行う必要があり、Appleは毎年春に最低限のSDKを引き上げます。
- 1台のMacは一度に1つのジョブしかビルドできません。リリース日はキューが溜まります。
チームがすでにMacを運用し、管理者がいるならこれで大丈夫です。そうでなければ、次のオプションでインフラからMacを排除できます。
オプション2: Capgo BuildでLinuxランナーからiOSをビルド
Capgo のビルド はCapgoが管理するMac上でCapacitorアプリをコンパイル・署名します。Giteaジョブは既存のLinuxランナー上で実行されます。codeをチェックアウトし、Webレイヤーをビルドして cap sync iosを実行し、 build requestを呼び出します。Capgo CLIは準備されたネイティブプロジェクトをアップロードし、XcodeログをGiteaジョブログにストリーミングし、失敗時は非ゼロで終了します。
このモデルはセルフホストGiteaに最適です:
- 入站アクセス不要。 Capgoはリポジトリをクローンしません。ランナーがHTTPS経由で準備されたプロジェクトをプッシュするため、ファイアウォールやVPNの背後にあるGiteaサーバーも変更なしで動作します。
- リポジトリトークンなし。 Capgo 側で設定する Git 接続はありません。
- Web ソースはローカルに留まります。 ネイティブの
ios/フォルダ、Capacitor 設定、およびプラグインのネイティブ部分のみがアップロードされます。src/,.git/や.envファイルはアップロードされません。
ワンタイムセットアップ
開発者マシン上で:
bunx @capgo/cli@latest login
bunx @capgo/cli@latest app add
bunx @capgo/cli@latest build init --platform ios
build init 配布証明書と App Store プロビジョニングプロファイルを新規作成または再利用し、App Store Connect の API キーを保存します。すべてが署名されることを確認するために、ローカルで一度ビルドを実行してください:
bun run build && bunx cap sync ios
bunx @capgo/cli@latest build request com.example.app --platform ios --build-mode release
その後、認証情報をエクスポートします:
bunx @capgo/cli@latest build credentials manage --appId com.example.app --platform ios
# select "Export to .env"
Gitea にシークレットを追加
開く リポジトリ設定 > Actions > Secrets エクスポートしたファイルの各キーと、Capgo API キーを追加します:
| Secret | 目的 |
|---|---|
CAPGO_TOKEN |
アップロード権限を持つ Capgo API キー |
BUILD_CERTIFICATE_BASE64 |
配布証明書 (.p12) |
P12_PASSWORD |
証明書パスワード |
CAPGO_IOS_PROVISIONING_MAP_BASE64 |
プロビジョニングプロファイルの紐付け |
APPLE_KEY_ID |
App Store Connect API キーID |
APPLE_ISSUER_ID |
App Store Connect の発行者 ID |
APPLE_KEY_CONTENT |
Base64 .p8 キー |
APP_STORE_CONNECT_TEAM_ID |
AppleチームID |
Gitea は、次の文字で始まるシークレット名と変数名を拒否します。 GITEA_ または GITHUB_そのため、これらの名前はそのままにしてください。app ID などのシークレットではない値は、 変数 に設定し、次のコードで読み取ります ${{ vars.NAME }}。組織レベルで設定されたシークレットは、その組織内のすべてのリポジトリで共有されるため、1つの Apple チームから複数のアプリをリリースする場合に便利です。作業が終わったら、エクスポートしたファイルを削除してください。
タグ push でリリース
# .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 }}"
注意:
${{ gitea.ref_name }}がタグ名です。github.*context もエイリアスとして使えるため、ワークフローを移植する際に便利です。- Gitea は
CI=trueすべてのジョブで設定するため、Capgo CLI は対話入力を待ちません。 - Capgo は最新の TestFlight ビルドからビルド番号をインクリメントするため、連続する 2 つのタグが衝突することはありません。
- がないと
--submit-to-store-review、ビルドは TestFlight に届き、そこで停止します。CI で App Review にも提出したい場合は、フラグを追加してください。
リリースはこれで git tag v2.3.0 && git push origin v2.3.0。push できる人は誰でも v* tag を push してリリースできます。そのため、 v* 内の 設定 > タグ リリース管理者だけに制限できます。
テスター向け Ad hoc ビルド
登録済みデバイスに直接インストールする QA ビルドには、ad hoc モードでビルドしてダウンロードリンクを取得します:
# .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 ビルドには、テストデバイスを記載した ad hoc プロビジョニングプロファイルが必要です。そのプロファイルを base64 でエンコードしてシークレット(ADHOC_PROFILE_BASE64 上記)に保存し、ジョブ内でデコードして次のように渡します: --ios-provisioning-profile。 CLI フラグは環境変数より優先されるため、このビルドに限り App Store 用プロファイルを上書きします。UDID は次で収集します: iOS UDID 検索ツール。ほとんどのテスターにとっては、UDID が不要な TestFlight の内部テストの方が簡単です。
手動リリース承認
GitHub を使うと、環境にレビュアーを必須にできます。Gitea Actions は環境保護ルールを実装していないため、環境を指定したジョブでも承認待ちで停止しません。代わりに次の 2 つのパターンが使えます:
- 保護されたタグ。 リリースマネージャーだけがタグをpushでき、
v*タグのワークフローが配信します。 - ビルドして、プロモート。 pushのたびにビルドするか、
mainを使用して--ios-distribution ad_hocTestFlightの内部テストにのみアップロードし、その後workflow_dispatchワークフロー(現在のGiteaリリースで利用可能)を使って、承認されたコミットを再ビルドします。--submit-to-store-review.
新しいバイナリなしでWebの変更を配信
Capacitor アプリへのコミットの多くは、JavaScript、CSS、HTMLだけを変更します。そのたびにiOSを再ビルドするのは、数分とApp Reviewの時間を無駄にします。これなら、 Capgo Live Updates1つのジョブで適切なパスを選べます:
- 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 ネイティブ依存関係がチャネル上のライブ状態と一致する場合に 0、新しいバイナリが必要な場合に 1 を返します。また、以下のファイルが変更された場合はネイティブパスを強制します。 ios/ または capacitor.config.* これらは依存関係の比較対象に含まれないためです。詳細は live update か Native Build を自動選択.
Macランナー vs クラウドビルド
| Mac上のact_runner | LinuxからのCapgo Build | |
|---|---|---|
| ハードウェア | 購入してホストする | なし |
| Xcode アップグレード | 手動、マシンごと | Capgo が処理 |
| ジョブ間の分離 | ホストモードではなし | ジョブごとに新しいビルド環境 |
| 並列ビルド | Mac ごとに 1 つ | 任意のランナーから複数 |
| 署名ファイル | Gitea のシークレットに保存、Mac でデコード | Giteaのシークレットに、ビルドごとに送信 |
| ファイアウォールの背後でも動作 | はい | はい、アウトバウンドHTTPSのみ |
| ネイティブSwiftアプリ(Capacitorなし) | はい | いいえ、Capacitorアプリのみ |
| ビルド時間制限 | 設定はあなた次第 | 1ビルドあたり10分 |
トラブルシューティング
| 症状 | 解決策 |
|---|---|
| ジョブが永遠にキューに留まる | オンラインランナーにラベルがありません runs-on。ランナーリストとラベルのスペルを確認してください。 |
uses: actions/checkout@v4 ダウンロードに失敗します |
ランナーが GitHub に接続できません。Gitea上でアクションをミラーリングし、完全なURLで参照してください。 |
| ジョブ内のシークレット値が空です | 名前の先頭が GITEA_/GITHUB_、またはシークレットが別のリポジトリで定義されています。 |
security: SecKeychainItemImport: MAC verification failed |
誤り .p12 パスワード、または .p12 OpenSSL 3 によって、なしで作成されました -legacy。再エクスポートしてください。 |
No profiles for 'com.example.app' were found |
シークレットのプロファイルがバンドル ID または証明書と一致しません。再実行してください build init 再エクスポートしてください。 |
| SDK バージョンのアップロードが拒否されました | Mac ランナーにはまだ 26 より古い Xcode がインストールされています。 |
cap sync ios Linux での CocoaPods について警告します |
想定内の動作です。Capgo ビルドマシンが pods をインストールします。 |
その他の失敗モードについては、 Capacitor の CI/CD:よくある落とし穴 および Capgo Build トラブルシューティングガイドにあります.
まとめ
Gitea Actions は、Xcode をどこで実行するかを決めれば iOS にも対応します。ホストモードの Mac ランナーなら完全な制御と責任が得られます。Linux ジョブから Capgo Build を呼び出す場合、Gitea の構成はそのまま、入站アクセスも不要で、TestFlight リリースをタグプッシュに置き換えられます。どちらを選ぶ場合も、署名情報は Gitea のシークレットに保管し、リリースタグを保護し、Web 限定の変更はライブアップデートとして配信し、ネイティブパイプラインは必要なときだけ実行されるようにしてください。