Merge pull request #8309 from BlueWallet/cccc

OPS: Catalyst
This commit is contained in:
GLaDOS 2026-02-26 01:21:35 +00:00 committed by GitHub
commit 248182c1f6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 527 additions and 6 deletions

174
.github/workflows/build-mac-catalyst.yml vendored Normal file
View File

@ -0,0 +1,174 @@
name: Build Mac Catalyst
on:
workflow_dispatch:
pull_request:
branches:
- master
types: [labeled, synchronize]
concurrency:
group: catalyst-build-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
jobs:
build:
if: >
github.event_name == 'workflow_dispatch' ||
(github.event.action == 'labeled' && (github.event.label.name == 'mac-dmg' || github.event.label.name == 'testflight')) ||
github.event.action == 'synchronize'
runs-on: macos-15
timeout-minutes: 120
steps:
- name: Check PR labels
if: github.event_name == 'pull_request'
id: labels
env:
GH_TOKEN: ${{ github.token }}
run: |
LABELS=$(gh api "repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels" --jq '.[].name' | tr '\n' ',')
echo "all=${LABELS}" >> $GITHUB_OUTPUT
if [[ "$LABELS" == *"mac-dmg"* ]]; then
echo "has_mac_dmg=true" >> $GITHUB_OUTPUT
else
echo "has_mac_dmg=false" >> $GITHUB_OUTPUT
fi
if [[ "$LABELS" == *"testflight"* ]] && [[ "$LABELS" == *"mac-dmg"* ]]; then
echo "upload_testflight=true" >> $GITHUB_OUTPUT
else
echo "upload_testflight=false" >> $GITHUB_OUTPUT
fi
echo "Labels on PR: ${LABELS}"
- name: Skip if mac-dmg label not present
if: github.event_name == 'pull_request' && steps.labels.outputs.has_mac_dmg != 'true'
run: |
echo "mac-dmg label not found on PR — skipping build."
exit 0
- name: Checkout project
if: github.event_name == 'workflow_dispatch' || steps.labels.outputs.has_mac_dmg == 'true'
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup Node.js
if: github.event_name == 'workflow_dispatch' || steps.labels.outputs.has_mac_dmg == 'true'
uses: actions/setup-node@v6
with:
node-version: 24
cache: npm
cache-dependency-path: package-lock.json
- name: Setup Xcode
if: github.event_name == 'workflow_dispatch' || steps.labels.outputs.has_mac_dmg == 'true'
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest
- name: Set up Ruby
if: github.event_name == 'workflow_dispatch' || steps.labels.outputs.has_mac_dmg == 'true'
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.1.6
bundler-cache: true
- name: Install Node modules
if: github.event_name == 'workflow_dispatch' || steps.labels.outputs.has_mac_dmg == 'true'
run: npm ci
- name: Install CocoaPods dependencies
if: github.event_name == 'workflow_dispatch' || steps.labels.outputs.has_mac_dmg == 'true'
run: bundle exec fastlane ios install_pods
env:
SKIP_APP_STORE_CONNECT_AUTH: '1'
- name: Create temporary keychain for signing
if: (github.event_name == 'workflow_dispatch' || steps.labels.outputs.has_mac_dmg == 'true') && steps.labels.outputs.upload_testflight == 'true'
run: |
security create-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" build.keychain
security set-keychain-settings -t 3600 -u build.keychain
- name: Build Mac Catalyst app with Fastlane
if: github.event_name == 'workflow_dispatch' || steps.labels.outputs.has_mac_dmg == 'true'
id: build_catalyst
run: bundle exec fastlane ios build_catalyst_app_lane
env:
SKIP_APP_STORE_CONNECT_AUTH: '1'
SKIP_CLEAR_DERIVED_DATA: '1'
CATALYST_SIGNING_IDENTITY: ${{ steps.labels.outputs.upload_testflight == 'true' && secrets.CATALYST_SIGNING_IDENTITY || '' }}
CATALYST_TEAM_ID: ${{ steps.labels.outputs.upload_testflight == 'true' && secrets.CATALYST_TEAM_ID || '' }}
GIT_URL: ${{ steps.labels.outputs.upload_testflight == 'true' && secrets.GIT_URL || '' }}
GIT_ACCESS_TOKEN: ${{ steps.labels.outputs.upload_testflight == 'true' && secrets.GIT_ACCESS_TOKEN || '' }}
MATCH_READONLY: ${{ steps.labels.outputs.upload_testflight == 'true' && 'false' || 'true' }}
KEYCHAIN_NAME: ${{ steps.labels.outputs.upload_testflight == 'true' && 'build' || '' }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
- name: Upload Mac Catalyst DMG
id: upload_dmg
if: success() && (github.event_name == 'workflow_dispatch' || steps.labels.outputs.has_mac_dmg == 'true')
uses: actions/upload-artifact@v6
with:
name: BlueWallet-Mac-Catalyst
path: ${{ steps.build_catalyst.outputs.catalyst_dmg_path }}
if-no-files-found: warn
- name: Create App Store Connect API Key JSON
if: success() && steps.labels.outputs.upload_testflight == 'true'
run: echo '${{ secrets.APPLE_API_KEY_CONTENT }}' > ./appstore_api_key.json
- name: Upload to TestFlight
if: success() && steps.labels.outputs.upload_testflight == 'true'
run: bundle exec fastlane ios upload_catalyst_to_testflight
env:
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER_ID: ${{ secrets.APPLE_API_ISSUER_ID }}
CATALYST_TEAM_ID: ${{ secrets.CATALYST_TEAM_ID }}
TEAM_ID: ${{ secrets.TEAM_ID }}
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
LATEST_COMMIT_MESSAGE: ${{ github.event.pull_request.title || 'Manual build' }}
- name: Cleanup App Store Connect API Key JSON
if: always() && steps.labels.outputs.upload_testflight == 'true'
run: rm -f ./appstore_api_key.json
- name: Cleanup temporary keychain
if: always() && steps.labels.outputs.upload_testflight == 'true'
run: security delete-keychain build.keychain || true
- name: Comment on PR with DMG link
if: success() && github.event_name == 'pull_request' && steps.labels.outputs.has_mac_dmg == 'true'
env:
GH_TOKEN: ${{ github.token }}
UPLOADED_TO_TF: ${{ steps.labels.outputs.upload_testflight }}
run: |
ARTIFACT_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts/${{ steps.upload_dmg.outputs.artifact-id }}"
COMMENT_TAG="<!-- catalyst-dmg-link -->"
TF_LINE=""
if [[ "$UPLOADED_TO_TF" == "true" ]]; then
TF_LINE=$'\n\n**Also uploaded to TestFlight.** Check [App Store Connect](https://appstoreconnect.apple.com) for the build.'
fi
COMMENT_FILE="$(mktemp)"
{
printf '%s\n' "${COMMENT_TAG}"
printf '### Mac Catalyst Build\n\n'
printf 'The Mac Catalyst DMG is ready for download:\n\n'
printf '[Download BlueWallet-Mac-Catalyst.dmg](%s)\n' "${ARTIFACT_URL}"
if [[ -n "$TF_LINE" ]]; then
printf '%s\n' "${TF_LINE}"
fi
printf '<sub>Built from `%s`"
} >"${COMMENT_FILE}"
gh api "repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" \
--paginate --jq '.[] | select(.body | contains("<!-- catalyst-dmg-link -->")) | .id' | \
while read -r comment_id; do
gh api -X DELETE "repos/${{ github.repository }}/issues/comments/${comment_id}" || true
done
gh pr comment "${{ github.event.pull_request.number }}" --body-file "${COMMENT_FILE}"

View File

@ -82,10 +82,17 @@ def cached_app_store_connect_login
end
before_all do |lane, options|
skip_auth_lanes = ['register_devices_from_txt']
if ENV['SKIP_APP_STORE_CONNECT_AUTH'] == '1'
UI.message('Skipping App Store Connect authentication (SKIP_APP_STORE_CONNECT_AUTH=1)')
next
end
skip_auth_lanes = ['register_devices_from_txt', 'build_catalyst_app_lane', 'install_pods', 'clear_derived_data_lane']
lane_name = lane.to_s
should_skip_auth = skip_auth_lanes.any? { |skip_lane| lane_name == skip_lane || lane_name.end_with?(" #{skip_lane}") }
# Check if we need App Store Connect for this lane
unless skip_auth_lanes.include?(lane)
unless should_skip_auth
begin
# Try to authenticate once at the beginning
require 'spaceship'
@ -386,12 +393,20 @@ platform :ios do
log_success("All provisioning profiles set up")
end
# Only these targets support Mac Catalyst (watch/stickers do not)
def catalyst_app_identifiers
[
"io.bluewallet.bluewallet",
"io.bluewallet.bluewallet.MarketWidget"
]
end
desc "Fetch development certificates and provisioning profiles for Mac Catalyst"
lane :fetch_dev_profiles_catalyst do
match(
type: "development",
platform: "catalyst",
app_identifier: app_identifiers,
app_identifier: catalyst_app_identifiers,
readonly: true,
clone_branch_directly: true
)
@ -402,15 +417,15 @@ platform :ios do
match(
type: "appstore",
platform: "catalyst",
app_identifier: app_identifiers,
app_identifier: catalyst_app_identifiers,
readonly: true,
clone_branch_directly: true
)
end
desc "Setup provisioning profiles for Mac Catalyst"
desc "Create provisioning profiles for Mac Catalyst (first-time setup)"
lane :setup_catalyst_provisioning_profiles do
app_identifiers.each do |app_identifier|
catalyst_app_identifiers.each do |app_identifier|
match(
type: "development",
platform: "catalyst",
@ -459,6 +474,338 @@ platform :ios do
clean_install: true)
end
desc "Build Mac Catalyst app, handle code signing, create DMG with multilingual README, and set GitHub outputs"
lane :build_catalyst_app_lane do
Dir.chdir(project_root) do
UI.message("Building Mac Catalyst application from: #{Dir.pwd}")
workspace_path = File.join(project_root, "ios", "BlueWallet.xcworkspace")
derived_data_path = File.join(project_root, "ios", "build", "catalyst-derived-data")
output_dir = File.join(project_root, "ios", "build", "catalyst-output")
if ENV['SKIP_CLEAR_DERIVED_DATA'] == '1'
UI.message('Skipping clear_derived_data_lane (SKIP_CLEAR_DERIVED_DATA=1)')
else
clear_derived_data_lane
end
FileUtils.mkdir_p(derived_data_path)
FileUtils.mkdir_p(output_dir)
# Only these targets support Mac Catalyst
catalyst_identifiers = [
"io.bluewallet.bluewallet",
"io.bluewallet.bluewallet.MarketWidget"
]
has_signing_creds = ENV['CATALYST_SIGNING_IDENTITY'] && !ENV['CATALYST_SIGNING_IDENTITY'].empty? &&
ENV['CATALYST_TEAM_ID'] && !ENV['CATALYST_TEAM_ID'].empty?
has_match_creds = ENV['GIT_URL'] && !ENV['GIT_URL'].empty? &&
ENV['GIT_ACCESS_TOKEN'] && !ENV['GIT_ACCESS_TOKEN'].empty?
should_sign = has_signing_creds && has_match_creds && ENV['CATALYST_SKIP_CODESIGNING'] != '1'
signing_identity = ENV['CATALYST_SIGNING_IDENTITY'] || "Apple Distribution"
xcargs_str = "ARCHS=arm64 ONLY_ACTIVE_ARCH=YES"
if should_sign
UI.message("Setting up Mac Catalyst provisioning profiles via match...")
team_id = ENV['CATALYST_TEAM_ID']
match_readonly = ENV['MATCH_READONLY'] != 'false'
# Create/fetch provisioning profiles for catalyst targets
catalyst_identifiers.each do |app_id|
match(
type: "appstore",
platform: "catalyst",
app_identifier: app_id,
team_id: team_id,
git_url: ENV['GIT_URL'],
git_basic_authorization: ENV['GIT_ACCESS_TOKEN'],
readonly: match_readonly,
clone_branch_directly: true,
keychain_name: ENV['KEYCHAIN_NAME'] || "login",
keychain_password: ENV['KEYCHAIN_PASSWORD'] || ""
)
end
xcargs_str += " DEVELOPMENT_TEAM=#{team_id}"
xcargs_str += " CODE_SIGN_IDENTITY=\"#{signing_identity}\""
xcargs_str += " CODE_SIGN_STYLE=Manual"
# Set provisioning profile specifiers per catalyst target
catalyst_identifiers.each do |app_id|
profile_name = "match AppStore #{app_id} catalyst"
# Convert bundle ID to xcodebuild target setting key
# e.g., io.bluewallet.bluewallet -> PROVISIONING_PROFILE_SPECIFIER for that target
xcargs_str += " PROVISIONING_PROFILE_SPECIFIER_#{app_id.gsub('.', '_')}=\"#{profile_name}\""
end
UI.success("Provisioning profiles configured for Mac Catalyst")
else
# Disable code signing entirely so xcodebuild doesn't look for provisioning profiles
xcargs_str += " CODE_SIGN_IDENTITY=- CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO"
UI.message("No signing credentials provided — building without code signing")
end
build_app(
scheme: "BlueWallet",
workspace: workspace_path,
configuration: "Release",
destination: "generic/platform=macOS,variant=Mac Catalyst",
xcargs: xcargs_str,
clean: true,
skip_codesigning: !should_sign,
skip_package_ipa: true,
derived_data_path: derived_data_path,
buildlog_path: File.join(project_root, "ios", "build_logs")
)
archive_path = lane_context[SharedValues::XCODEBUILD_ARCHIVE]
if archive_path.nil? || archive_path.empty?
archive_path = Dir.glob(File.join(Dir.home, "Library/Developer/Xcode/Archives/**/*.xcarchive")).max_by { |path| File.mtime(path) }
end
candidate_paths = []
candidate_paths << File.join(archive_path, "Products/Applications/BlueWallet.app") if archive_path
candidate_paths << Dir.glob(File.join(derived_data_path, "Build/Products/Release-maccatalyst/*.app")).first
candidate_paths << Dir.glob(File.join(derived_data_path, "Build/Intermediates.noindex/ArchiveIntermediates/BlueWallet/BuildProductsPath/Release-maccatalyst/*.app")).first
catalyst_app_path = candidate_paths.compact.find { |path| File.exist?(path) }
UI.user_error!("Mac Catalyst app was not found after build") if catalyst_app_path.nil?
UI.success("Mac Catalyst app found at: #{catalyst_app_path}")
if should_sign && ENV['CATALYST_SIGNING_IDENTITY'] && !ENV['CATALYST_SIGNING_IDENTITY'].empty?
UI.message("Re-signing app with: #{signing_identity}")
sh("codesign",
"--deep",
"--force",
"--options", "runtime",
"--sign", signing_identity,
catalyst_app_path)
sh("codesign",
"--verify",
"--deep",
"--strict",
catalyst_app_path)
UI.success("App signed and verified")
else
# Ad-hoc sign so macOS doesn't treat the app as "damaged"
UI.message("Ad-hoc signing app to avoid Gatekeeper quarantine issues...")
sh("codesign",
"--deep",
"--force",
"--sign", "-",
catalyst_app_path)
UI.success("App ad-hoc signed")
end
dmg_path = File.join(output_dir, "BlueWallet-Mac-Catalyst.dmg")
UI.message("Creating DMG at: #{dmg_path}")
dmg_staging = File.join(output_dir, "dmg-staging")
FileUtils.rm_rf(dmg_staging)
FileUtils.mkdir_p(dmg_staging)
FileUtils.cp_r(catalyst_app_path, dmg_staging)
sh("ln", "-s", "/Applications", "#{dmg_staging}/Applications")
# Add README with first-launch instructions
readme_path = File.join(dmg_staging, "README - Read Before Opening.txt")
File.write(readme_path, <<~README)
╔══════════════════════════════════════════════════════════════╗
║ BlueWallet for macOS ║
╚══════════════════════════════════════════════════════════════╝
═══ ENGLISH ═══════════════════════════════════════════════════
INSTALLATION: Drag "BlueWallet.app" into "Applications".
FIRST LAUNCH — macOS may show a warning. To open:
• Right-click the app → Open → click "Open" in the dialog.
• Or: System Settings → Privacy & Security → Open Anyway.
• Or (Terminal): xattr -cr /Applications/BlueWallet.app
You only need to do this once.
═══ ESPAÑOL ════════════════════════════════════════════════════
INSTALACIÓN: Arrastra "BlueWallet.app" a "Aplicaciones".
PRIMER INICIO — macOS puede mostrar una advertencia. Para abrir:
• Haz clic derecho en la app → Abrir → clic en "Abrir".
• O: Ajustes del Sistema → Privacidad y Seguridad → Abrir igualmente.
• O (Terminal): xattr -cr /Applications/BlueWallet.app
Solo necesitas hacerlo una vez.
═══ 中文 ═══════════════════════════════════════════════════════
安装:将 "BlueWallet.app" 拖入 "应用程序" 文件夹。
首次启动 — macOS 可能会显示警告。打开方法:
• 右键点击应用 → 打开 → 在对话框中点击"打开"。
• 或:系统设置 → 隐私与安全性 → 仍要打开。
• 或终端xattr -cr /Applications/BlueWallet.app
只需操作一次。
═══ PORTUGUÊS ══════════════════════════════════════════════════
INSTALAÇÃO: Arraste "BlueWallet.app" para "Aplicativos".
PRIMEIRA ABERTURA — o macOS pode exibir um aviso. Para abrir:
• Clique com o botão direito → Abrir → clique em "Abrir".
• Ou: Ajustes do Sistema → Privacidade e Segurança → Abrir Mesmo Assim.
• Ou (Terminal): xattr -cr /Applications/BlueWallet.app
Você só precisa fazer isso uma vez.
═══ РУССКИЙ ════════════════════════════════════════════════════
УСТАНОВКА: Перетащите "BlueWallet.app" в "Программы".
ПЕРВЫЙ ЗАПУСК — macOS может показать предупреждение. Чтобы открыть:
• Нажмите правой кнопкой → Открыть → нажмите «Открыть».
• Или: Системные настройки → Конфиденциальность → Подтвердить открытие.
• Или (Терминал): xattr -cr /Applications/BlueWallet.app
Это нужно сделать только один раз.
═══ 日本語 ═════════════════════════════════════════════════════
インストール「BlueWallet.app」を「アプリケーション」にドラッグ。
初回起動 — macOS が警告を表示する場合があります。開くには:
• アプリを右クリック →「開く」→ ダイアログで「開く」をクリック。
• または:システム設定 → プライバシーとセキュリティ →「このまま開く」。
• またはターミナルxattr -cr /Applications/BlueWallet.app
この操作は一度だけ必要です。
═══ DEUTSCH ════════════════════════════════════════════════════
INSTALLATION: Ziehe „BlueWallet.app" in den Ordner „Programme".
ERSTER START — macOS zeigt möglicherweise eine Warnung. Zum Öffnen:
• Rechtsklick auf die App → Öffnen → „Öffnen" klicken.
• Oder: Systemeinstellungen → Datenschutz & Sicherheit → Dennoch öffnen.
• Oder (Terminal): xattr -cr /Applications/BlueWallet.app
Dies ist nur beim ersten Mal nötig.
═══ FRANÇAIS ═══════════════════════════════════════════════════
INSTALLATION : Glissez « BlueWallet.app » dans « Applications ».
PREMIER LANCEMENT — macOS peut afficher un avertissement. Pour ouvrir :
• Clic droit sur l'app → Ouvrir → cliquez sur « Ouvrir ».
• Ou : Réglages Système → Confidentialité et sécurité → Ouvrir quand même.
• Ou (Terminal) : xattr -cr /Applications/BlueWallet.app
Cette opération n'est nécessaire qu'une seule fois.
═══ العربية ════════════════════════════════════════════════════
التثبيت: اسحب "BlueWallet.app" إلى مجلد "التطبيقات".
التشغيل الأول — قد يعرض macOS تحذيرًا. لفتح التطبيق:
• انقر بزر الماوس الأيمن → افتح → انقر "فتح" في مربع الحوار.
• أو: إعدادات النظام → الخصوصية والأمان → فتح على أي حال.
• أو (الطرفية): xattr -cr /Applications/BlueWallet.app
تحتاج للقيام بذلك مرة واحدة فقط.
────────────────────────────────────────────────────────────────
https://bluewallet.io
README
UI.message("Added multilingual README with first-launch instructions to DMG")
FileUtils.rm_f(dmg_path)
sh("hdiutil", "create", "-volname", "BlueWallet", "-srcfolder", dmg_staging, "-ov", "-format", "UDZO", dmg_path)
UI.user_error!("DMG was not created at #{dmg_path}") unless File.exist?(dmg_path)
UI.success("DMG created at: #{dmg_path}")
FileUtils.rm_rf(dmg_staging)
ENV['CATALYST_APP_PATH'] = catalyst_app_path
ENV['CATALYST_DMG_PATH'] = dmg_path
if ENV['GITHUB_OUTPUT']
File.open(ENV['GITHUB_OUTPUT'], 'a') do |f|
f.puts "catalyst_app_path=#{catalyst_app_path}"
f.puts "catalyst_dmg_path=#{dmg_path}"
end
end
UI.success("macOS app built at: #{catalyst_app_path}")
UI.success("macOS DMG at: #{dmg_path}")
end
end
desc "Upload Mac Catalyst app to TestFlight"
lane :upload_catalyst_to_testflight do
Dir.chdir(project_root) do
# Locate the xcarchive
archive_path = lane_context[SharedValues::XCODEBUILD_ARCHIVE]
if archive_path.nil? || archive_path.empty?
archive_path = Dir.glob(File.join(Dir.home, "Library/Developer/Xcode/Archives/**/*.xcarchive")).max_by { |path| File.mtime(path) }
end
UI.user_error!("No xcarchive found for TestFlight upload") if archive_path.nil? || !File.exist?(archive_path)
UI.message("Using archive: #{archive_path}")
output_dir = File.join(project_root, "ios", "build", "catalyst-output")
FileUtils.mkdir_p(output_dir)
# Export the archive as a .pkg for Mac Catalyst
team_id = ENV['CATALYST_TEAM_ID'] || ENV['TEAM_ID']
export_plist_path = File.join(output_dir, "ExportOptions.plist")
# Build provisioning profiles mapping for manual signing
profiles_xml = catalyst_app_identifiers.map do |app_id|
profile_name = "match AppStore #{app_id} catalyst"
"\t\t\t<key>#{app_id}</key>\n\t\t\t<string>#{profile_name}</string>"
end.join("\n")
File.write(export_plist_path, <<~PLIST)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store</string>
<key>destination</key>
<string>upload</string>
<key>teamID</key>
<string>#{team_id}</string>
<key>signingStyle</key>
<string>manual</string>
<key>provisioningProfiles</key>
<dict>
#{profiles_xml}
</dict>
</dict>
</plist>
PLIST
pkg_path = File.join(output_dir, "BlueWallet.pkg")
sh("xcodebuild",
"-exportArchive",
"-archivePath", archive_path,
"-exportOptionsPlist", export_plist_path,
"-exportPath", output_dir)
# Find the exported pkg
exported_pkg = Dir.glob(File.join(output_dir, "*.pkg")).first
UI.user_error!("No .pkg found after export") if exported_pkg.nil? || !File.exist?(exported_pkg)
UI.success("Exported pkg: #{exported_pkg}")
# Build changelog
branch_name = ENV['BRANCH_NAME'] || "unknown-branch"
last_commit_message = ENV['LATEST_COMMIT_MESSAGE'] || "No commit message found"
changelog = "Build Information:\n"
changelog += "- Branch: #{branch_name}\n" if branch_name != 'master'
changelog += "- Commit: #{last_commit_message}\n"
# Upload to TestFlight
upload_to_testflight(
api_key_path: "./appstore_api_key.json",
pkg: exported_pkg,
skip_waiting_for_build_processing: true,
changelog: changelog
)
UI.success("Successfully uploaded Mac Catalyst app to TestFlight!")
end
end
desc "Upload IPA to TestFlight"
lane :upload_to_testflight_lane do