mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-13 15:51:00 +00:00
e59af6dcb3
A watchOS app embedded in the iPhone app: today's next stop with its countdown, the next booking with reference, seat and platform, the trip with its days and places (Directions into Apple Maps), and the packing list and to-dos to tick off. The phone sends the snapshot through WatchConnectivity; ticks go back as queued user info. Three complications (next stop, countdown, trip day) in every accessory family, scored for the Smart Stack. 28 languages. The native workflow captures every screen from watchOS simulators in a screenshot mode, on the largest and the smallest watch.
120 lines
4.8 KiB
Ruby
120 lines
4.8 KiB
Ruby
# iOS release signing and TestFlight upload, driven by .github/workflows/native-release.yml.
|
|
#
|
|
# Automatic signing cannot work on a CI runner with no registered devices: it signs
|
|
# the archive for development and then needs a development provisioning profile, which
|
|
# requires a device. So this signs manually for distribution instead. The distribution
|
|
# certificate and the App Store provisioning profile are created (or reused) through the
|
|
# App Store Connect API key, which means no certificate or profile has to be stored as a
|
|
# secret: the key the workflow already holds is enough.
|
|
#
|
|
# The lane expects these in the environment (the workflow sets them):
|
|
# ASC_KEY_ID, ASC_ISSUER_ID, ASC_KEY_PATH — the App Store Connect API key
|
|
# APPLE_TEAM_ID — the developer team
|
|
# MARKETING_VERSION, CURRENT_PROJECT_VERSION — the version and build number
|
|
# RUNNER_TEMP — a writable scratch directory
|
|
|
|
default_platform(:ios)
|
|
|
|
APP_IDENTIFIER = "com.liketrek.trek"
|
|
PROJECT = "ios/App/App.xcodeproj"
|
|
|
|
# Every signed target with its bundle identifier: the app and its extensions
|
|
# (ios/scripts/add-extension.rb put them in the project). Each gets its own App
|
|
# Store profile, created or reused through the API key like the app's.
|
|
SIGNED_TARGETS = {
|
|
"App" => APP_IDENTIFIER,
|
|
"NotificationService" => "com.liketrek.trek.notifications",
|
|
"TREKWidgets" => "com.liketrek.trek.widgets",
|
|
"ShareExtension" => "com.liketrek.trek.share",
|
|
"TREKWatch" => "com.liketrek.trek.watchkitapp",
|
|
"TREKWatchWidgets" => "com.liketrek.trek.watchkitapp.widgets",
|
|
}
|
|
|
|
platform :ios do
|
|
desc "Build the signed Release app and upload it to TestFlight (internal testing)."
|
|
lane :beta do
|
|
key = app_store_connect_api_key(
|
|
key_id: ENV.fetch("ASC_KEY_ID"),
|
|
issuer_id: ENV.fetch("ASC_ISSUER_ID"),
|
|
key_filepath: ENV.fetch("ASC_KEY_PATH"),
|
|
in_house: false,
|
|
)
|
|
|
|
# A throwaway keychain with a known password, so fastlane can unlock the imported
|
|
# private key for code signing (without the password it cannot set the key's access
|
|
# list and the certificate is never usable).
|
|
keychain_name = "trek_ci.keychain"
|
|
keychain_password = "trek-ci-#{ENV.fetch('GITHUB_RUN_ID', 'local')}"
|
|
create_keychain(
|
|
name: keychain_name,
|
|
password: keychain_password,
|
|
default_keychain: true,
|
|
unlock: true,
|
|
timeout: 3600,
|
|
lock_when_sleeps: false,
|
|
)
|
|
keychain_path = File.expand_path("~/Library/Keychains/#{keychain_name}-db")
|
|
|
|
# Import the one distribution certificate from its stored .p12, rather than
|
|
# minting a new one each run — Apple caps distribution certificates at two, so
|
|
# a fresh one per build would quickly hit the limit. The matching App Store
|
|
# profile is created (or reused) through the API key.
|
|
import_certificate(
|
|
certificate_path: ENV.fetch("CERT_P12_PATH"),
|
|
certificate_password: ENV.fetch("CERT_P12_PASSWORD"),
|
|
keychain_name: keychain_name,
|
|
keychain_path: keychain_path,
|
|
keychain_password: keychain_password,
|
|
)
|
|
profiles = {}
|
|
SIGNED_TARGETS.each do |target, identifier|
|
|
get_provisioning_profile(
|
|
api_key: key,
|
|
app_identifier: identifier,
|
|
development: false,
|
|
)
|
|
profiles[identifier] = lane_context[SharedValues::SIGH_NAME]
|
|
|
|
# Pin each target to its profile for this build; automatic signing stays the
|
|
# default a developer sees when they open the project in Xcode.
|
|
update_code_signing_settings(
|
|
path: PROJECT,
|
|
use_automatic_signing: false,
|
|
team_id: ENV.fetch("APPLE_TEAM_ID"),
|
|
code_sign_identity: "Apple Distribution",
|
|
bundle_identifier: identifier,
|
|
profile_name: profiles[identifier],
|
|
targets: [target],
|
|
)
|
|
end
|
|
|
|
build_app(
|
|
project: PROJECT,
|
|
scheme: "App",
|
|
configuration: "Release",
|
|
export_method: "app-store",
|
|
output_directory: File.join(ENV.fetch("RUNNER_TEMP"), "export"),
|
|
xcargs: [
|
|
"MARKETING_VERSION=#{ENV.fetch('MARKETING_VERSION')}",
|
|
"CURRENT_PROJECT_VERSION=#{ENV.fetch('CURRENT_PROJECT_VERSION')}",
|
|
].join(" "),
|
|
export_options: {
|
|
signingStyle: "manual",
|
|
provisioningProfiles: profiles,
|
|
},
|
|
)
|
|
|
|
# Upload to App Store Connect; it shows up in TestFlight after Apple finishes processing.
|
|
# Internal testing needs no App Review, so nothing here submits the app for review.
|
|
# "What to Test" comes from the release tag's message (native-release.yml). Apple only
|
|
# takes it once the build is processed, so with notes the lane waits for that.
|
|
notes = ENV.fetch("TESTFLIGHT_NOTES", "").strip
|
|
upload_to_testflight(
|
|
api_key: key,
|
|
changelog: notes.empty? ? nil : notes,
|
|
skip_waiting_for_build_processing: notes.empty?,
|
|
skip_submission: true,
|
|
)
|
|
end
|
|
end
|