Macアプリのリリース手順が煩わしかったので、GitHub Actionsを利用してリリースを自動化しました。 その際の知見(Q&A)と実際の構成を共有します。
Q&A
Q: fastlane, bundlerはデフォルトで利用できる?
利用できる。(bundle installをしなくてもfastlane利用可能。)
Q: passwordやp12ファイルなど機密情報はどのように扱う?
この資料にパスワードやp12ファイルなどの機密情報の設定方法およびワークフローファイルからの参照方法について記載されています。(以下は抜粋)
シークレットの設定方法(リポジトリ単位)
ワークフローファイルからのシークレットの参照方法
Q: workflowは手動起動できる?
できる。 パラメータも設定可能。
手動起動の際にbranchの指定も可能。
設定例
on:
# Workflowの手動起動の設定です。
# version_numberを入力できるようにしています。
workflow_dispatch:
inputs:
version_number:
description: 'アプリのバージョン番号。入力例 0.3.0, 1.0.0 など。'
required: true
# 中略
#version_numberの参照方法
bundle exec fastlane release version_number:${{ github.event.inputs.version_number }}
上の定義をすると、workflowの起動画面は下のようになります。
また手動起動のほか、pullreqのタイミングやbranchがpush時などに自動起動が可能です。
ワークフローをトリガーするイベント
同資料中のworkflow_dispatch
GitHub Actionsのメタデータ構文
Q: actions/checkout@v2 でcheckoutされるブランチは?
デフォルトではworkflowを実行したブランチ
Q: ワークフローファイルの環境変数とコンテキストの違いは?
以下の通り
Q: git tagの作成の仕方は?
一例
- name: Create git tag
run: |
git tag v${{github.event.inputs.version_number}}
git push origin v${{github.event.inputs.version_number}}
Q: GitHubのリリースページの作成の仕方は?
一例
※ actions/create-release@v1はarchivedされていてメンテナンスされていない。
- name: Create release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
tag_name: v${{github.event.inputs.version_number}}
release_name: Release v${{github.event.inputs.version_number}}
body: |
Changes in this Release
- First Change
- Second Change
draft: true
prerelease: false
Q: GitHubのリリースページにzipファイルなどの成果物をアップロードするには
下の例は、action/create-release@v1を前提としている。
- name: Upload Release Assets
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ./build/DokodemoDrag.app.zip
asset_name: DokodemoDrag.app.zip
asset_content_type: application/zip
Q: on: workflow_dispatchを設定しても, Actionsタブでワークフローが表示されない。
私の場合、GitHubから直接.github/workflow/aaa.yamlファイルを作成した場合に上の事象が発生しています。
(mainブランチ以外にワークフローファイルを作成すると表示されないかもしれない)
結構表示されないケースがある模様。
Q: expression中での三項演算子的なものは?
${{ val1 ? val1 : "B" }}
的なことをしたい。
ドキュメント的には見当たらない。
動作検証の限りでは、||と&&はRubyやJavaScriptと同様の動作をするので、
${{ val1 || "B" }} # val1の値が偽になるなら"B"を返す.
や
${{ (val1 && val2) || "B" }} # val1 && val2が偽でなければval2を返し、 偽なら"B"を返す。
といったことができる。
下記は実際の利用イメージ
- name: 'Test'
env:
# github.event.inputs.version_nameは 1.0.0などを想定
TAG_NAME: v${{ github.event.inputs.version_name }}
run: |
# 式の結果が偽なら""を出力する。真なら v1.0.0などを返す。
echo ${{ (github.event.inputs.version_name && env.TAG_NAME) }}
Q: ${{expression}}の評価がいまいち分からない
別記事を作成しました。
Q: GitHub Actionsの完了時のメール通知を止めたい
Account Settings -> Notifications -> Actionsのセクションから設定を変更できる。
宣伝(DokodemoDragについて)
DokodemoDragは、個人的に作成中のアプリでMacのWindow移動を楽に行えるようにするツールです。よければ触ってみてください
※現時点ではnotarizationができておらず、macOSのGateKeeperに検出されます)。
実装の概要もこちらで公開しています。
https://zenn.dev/hmu/articles/4c17afaaf5012e
宣伝は以上で、以下は実際に自動化したGitHub Actionsの構成についてです。
実際のworkflowの構成
前提
- GitHubのランナー上のXcode versionは12.4
- プロジェクトの構成はworkspace下にprojectが2つ存在する
DokodemoDrag.xcworkspace/
|-DokodemoDrag.xcodeproj/
|-DokodemoDragLauncher/DokodemoDragLauncher.xcodeproj/
- リリース形式は、GitHub上のリリースページにappname.app.zipという形式で公開(Storeへの公開ではない)
- リリース対象のMac AppのCertificateは、Developer IdではなくDevelopmentを利用
- 証明書のimportにmatchは利用せず手動で行う
- プロジェクトのビルドにはfastlaneを利用する
- 現時点ではprovisioning profileは未使用
- 現時点ではfastlaneの設定はGitHub Actionsでの利用前提となってしまっています
ワークフローの概要
1.ワークフローは実行者が手動で起動する
2.アプリのバージョンはWorkflow起動時に指定する
3.ビルド時にワークフロー起動時に指定されたバージョン番号を付与する
4.ビルドに成功したら バージョンに対応するgitのtagを生成する
5.GitHubのリリースページをドラフトで作成する
6.後始末
workflowファイル
説明は直接コメントに記載しました。
name: Release app
on:
# Allows you to run this workflow manually from the Actions tab
# Workflowの手動起動の設定です。
# version_numberを入力できるようにしています。
workflow_dispatch:
inputs:
version_number:
description: 'アプリのバージョン番号。入力例 0.3.0, 1.0.0 など。'
required: true
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
release:
# 実行環境をmacに設定。
runs-on: macos-latest
steps:
- name: Show Xcode version
run: xcodebuild -version
# defaultでWorkflowを実行したbranchがcheckoutされる。
- uses: actions/checkout@v2
- name: Show Git Branch
run: git symbolic-ref --short HEAD
# https://docs.github.com/ja/actions/guides/installing-an-apple-certificate-on-macos-runners-for-xcode-development
# 上記のドキュメントにcertificateをGitHub Actionsのランナーにimport
# する方法が記載されています。
# 下の設定では、GitHubのsecretに設定したp12ファイルの内容を復元しています。
# 実際のcertificateのkeychainへのimportは、fastlaneで行っています。
- name: Generate p12 file
env:
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
# 以下で定義しているP12_PATHは、${{ runner.temp }}を利用することで、
# env: 内で定義可能かもしれません。(未検証)
run: |
P12_PATH=$RUNNER_TEMP/build_certificate.p12
echo $P12_PATH
# シークレットから証明書とプロビジョニングプロファイルをインポートする
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode --output $P12_PATH
# commitに利用する情報を設定しています。
- name: git config
run: |
echo github.actor: ${{github.actor}}
git config user.name ${{github.actor}}
# fastlaneをbundle execで利用するためにbundlerを利用しています。
- name: bundle install
run: |
bundle install
# アプリのビルド処理です。
- name: Build DokodemoDragLauncher & DokodemoDrag
# ここもP12_PATHは ${{ runner.temp }} を利用した方が良いかもしれません。
env:
# これらの環境変数はfastlaneの処理で利用します。
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
export P12_PATH=$RUNNER_TEMP/build_certificate.p12
echo $P12_PATH
# certificateのimport, アプリのビルド, 成果物用のzipファイル生成を行います。
bundle exec fastlane release version_number:${{github.event.inputs.version_number}}
# .はかなり雑かもしれません。
git add .
git commit -m "Release v${{github.event.inputs.version_number}}"
git push origin
# タグ付けをします。
- name: Create git tag
run: |
echo Create tag ${{github.event.inputs.version_number}}
git tag v${{github.event.inputs.version_number}}
git push origin v${{github.event.inputs.version_number}}
# GitHubのリリースページを作成します。(draftで作成します)
# actions/create-release@v1は既にメンテ終了しているので、
# 他のアクションを利用した方が良いです。
- name: Create release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
tag_name: v${{github.event.inputs.version_number}}
release_name: Release v${{github.event.inputs.version_number}}
body: |
Changes in this Release
- First Change
- Second Change
draft: true
prerelease: false
# リリースページに成果物のzipファイルをアップロードします。
- name: Upload Release Assets
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ./build/DokodemoDrag.app.zip
asset_name: DokodemoDrag.app.zip
asset_content_type: application/zip
fastfile
こちらも説明は直接コメントに記載しました。
default_platform(:mac)
XCODE_PROJ_PATH = %w(./DokodemoDragLauncher/DokodemoDragLauncher.xcodeproj ./DokodemoDrag.xcodeproj)
BUILD_PATH="build"
APP_NAME="DokodemoDrag.app"
KEYCHAIN_NAME="map_app_keychain" # macのtypo...
OUTPUT_PATH="build"
platform :mac do
after_all do |lane|
# GitHubホストランナーの場合は不要です。
# create_keychainが呼ばれずにdelete_keychainを呼ぶと
# エラーになってしまいます。
delete_keychain(name: KEYCHAIN_NAME)
end
error do |lane|
# GitHubホストランナーの場合は不要です。
# create_keychainが呼ばれずにdelete_keychainを呼ぶと
# エラーになってしまいます。
delete_keychain(name: KEYCHAIN_NAME)
end
desc "release. option version: 0.3.0 ..."
lane :release do |options|
# プロジェクトにversion_numberを設定します。
set_version_number(
version_number: options[:version_number]
)
increment_all_app_build_numbers
build
end
desc "set version number"
lane :set_version_number do |options|
# increment_version_numberだと主のschemeに対してのみ
# 実行されるようなので、プロジェクト毎に設定しています。
XCODE_PROJ_PATH.each do |path|
increment_version_number(
xcodeproj: "#{path}",
version_number: options[:version_number]
)
end
end
desc "increment all app's build_numbers"
lane :increment_all_app_build_numbers do
# increment_xxx_numberだと主のschemeに対してのみ
# 実行されるようなので、プロジェクト毎に設定しています。
XCODE_PROJ_PATH.each do |path|
increment_build_number(
xcodeproj: "#{path}"
)
end
end
desc "build and zip app-file"
lane :build do
# certificateをimportしています。
# ここはciの時のみ実行するなど分岐があったほうが良さそうです。
import_my_certificate
build_mac_app(
workspace: "DokodemoDrag.xcworkspace",
configuration: "Release",
scheme: "DokodemoDrag",
export_method: "development",
clean: true,
output_directory: BUILD_PATH,
skip_package_pkg: true,
output_name: APP_NAME
)
zip(
path: "#{BUILD_PATH}/#{APP_NAME}",
output_path: "#{OUTPUT_PATH}/#{APP_NAME}.zip"
)
end
# ワークフローファイル側で設定しても問題ないと思いますが、fastlaneで設定しています。
# 参考: https://note.com/hayabusabusa/n/nbf4a1a095bf5
private_lane :import_my_certificate do
create_keychain(
name: KEYCHAIN_NAME,
password: ENV["KEYCHAIN_PASSWORD"],
timeout: 1800
)
import_certificate(
certificate_path: ENV["P12_PATH"],
certificate_password: ENV["P12_PASSWORD"],
keychain_name: KEYCHAIN_NAME,
keychain_password: ENV["KEYCHAIN_PASSWORD"]
)
end
end
参考資料
fastfileとワークフローファイルを作成時に参考したページです。
上の内容と一部重複しています。
GitHub Actions
GitHub Actionsについて学ぶ
GitHub Actionsの概要を把握するために一読をお勧めします。
Xcode 開発用の macOS ランナーに Apple 証明書をインストールする
Github Actions上でCertificateのインストールする手順が記載されています。
今回はp12ファイルをGithub Actions上で生成するところを参考にし、keychainへの証明書のimportは、fastlaneを利用しています。
アクションの入力パラメータの設定方法等が記載されています。
今回はworkflowを手動実行する際入力パラメータの設定の参考にしています。
GitHub Actionsのworkflowのyamlファイルのリファレンスです。
pullreqのタイミングやbranchがpushされた時などをtriggerとしてworkflowを起動できます。
手動でworkflowを実行する設定(on: workflow_dispatch)も記載されています。
GitHub Actionsで利用可能な環境変数についての説明。
ワークフローの定義ファイル中には環境変数とコンテキストの2種類の変数がありますが、その違いについても
記載されています。
パスワードやp12ファイルなどの機密情報の設定方法およびワークフローファイルからの参照方法について記載されています。
シークレットの設定方法(リポジトリ単位)
ワークフローファイいるからのシークレットの参照方法
通常ワークフローは、GitHub管理下で実行されますが、独自のワークフローのランナー環境が構築できるようです。
ドキュメント内では、GitHub管理下のランナーをGitHubホストランナー、独自のランナーをセルフホストランナーと表記されています。
Action
Gitのリポジトリをcheckoutするアクション。
デフォルトでは、workflowを実行したbranchを参照するようです。
GitHubのreleaseページを作成するために利用したのですが、
このリポジトリはarchivedされていてメンテナンスされていない模様。
GitHubのリリースページに成果物をアップロードするアクションです。
Fastlane
increment_build_numberは、デフォルトだと1projectにしか適用されないので
increment_build_number(
build_number: 75, # specify specific build number (optional, omitting it increments by one)
xcodeproj: "./path/to/MyApp.xcodeproj" # (optional, you must specify the path to your main Xcode project if it is not in the project root directory)
)
のようにxcodeprojを明示しています。
workflow実行時に入力したバージョンを設定しています。
increment_version_numberは、デフォルトだと1projectのみ適用なので、全プロジェクトに
適用するようにしています。
今回の設定では、お行儀よくfastlaneの最後にkeychainを削除しました。
GitHubホストランナー上で実行する場合、この設定は不要です。
参考:Xcode 開発用の macOS ランナーに Apple 証明書をインストールする
Technical Q&A QA1827
Automating Version and Build Numbers Using agvtool
Github Actionsとは直接関係ありませんが、fastlaneのincrement_build_no, increment_version_numberは、Appleが提供しているagvtoolに依存しています。
またそのための設定をXcode のプロジェクトに行う必要があるため、その手順が記載されています。
注意点として、同一ディレクトリにxcodeprojが複数あるとagvtoolは動作しません。
(私の場合、過去にproject名をリネームしていてその残骸のxcodeprojが残っていたため、知らぬ間に同一ディレクトリに複数のxcodeprojが存在していて、agvtoolが実行できないというポカをしていました)
先人の知見
GitHub ActionsでReleaseを自動化する方法としたときに得た学び
Github Actions と fastlane で iOS アプリをアーカイブしてビルドを提出する
Github ActionsでiOSアプリのデプロイを自動化する
以上です。分かってしまえば1つ1つの設定は単純ですが、Actionsのデバッグに想像以上の時間がかかりました。 デバッグ時にはワークフロー中のcommitを省略するなどの仕組みが必要だったなぁとか、キャッシュは先に有効にしておくべきだったとか...改善の余地は多々あります。