hammer-editor/fastlane/Fastfile
Wavesonics 8acee3835c Fix iOS and MacOS fastlane
They need their changelog written
2026-06-05 00:06:21 -07:00

262 lines
8.5 KiB
Ruby

# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
# https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
# https://docs.fastlane.tools/plugins/available-plugins
#
# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane
default_platform(:android)
# Returns an App Store Connect API key hash for use in mac lanes.
# The .p8 is gitignored in desktop/secrets/.
private_lane :appstore_api_key do
app_store_connect_api_key(
key_id: "F8BSZ7LC8Q",
issuer_id: "a49b927f-0f0e-4d4c-85c6-ffddfac9125a",
key_filepath: File.expand_path("../desktop/secrets/AuthKey_F8BSZ7LC8Q.p8", __dir__),
in_house: false,
)
end
# Marketing version (CFBundleShortVersionString / packageVersion). Single source
# of truth is libs.versions.toml `app`; prepareForRelease syncs it into Info.plist.
def app_marketing_version
toml = File.read(File.expand_path("../gradle/libs.versions.toml", __dir__))
toml[/^app\s*=\s*"([^"]+)"/, 1] || UI.user_error!("Could not read `app` version from libs.versions.toml")
end
# Run deliver with a bounded retry. Right after upload the build is processed in
# TestFlight but can lag propagating to the App Store version API, so deliver
# crashes with "Could not find build". That crash happens during build lookup —
# before anything is attached or submitted — so retrying the whole call is safe.
# https://github.com/fastlane/fastlane/issues/9012
def deliver_with_retry(params, attempts: 6, wait_seconds: 60)
try = 0
begin
try += 1
deliver(params)
rescue => e
raise if try >= attempts
UI.important("deliver attempt #{try}/#{attempts} failed: #{e.message.to_s.lines.first&.strip}")
UI.important("Build may still be propagating to App Store Connect; retrying in #{wait_seconds}s…")
sleep(wait_seconds)
retry
end
end
platform :mac do
desc "Build a sandboxed .pkg and upload to TestFlight only (beta; does not submit for review)."
lane :desktop_testflight do
desktop_build_and_upload(wait: false)
end
desc "Full Mac App Store release: build, upload, wait for processing, submit for review, auto-release on approval."
lane :desktop_release do
build_number = desktop_build_and_upload(wait: true)
desktop_submit(build_number: build_number)
end
desc "Submit an already-processed TestFlight build for review + auto-release. build_number defaults to latest."
lane :desktop_submit do |options|
params = {
api_key: appstore_api_key,
app_identifier: "com.darkrockstudios.apps.hammer",
platform: "osx",
app_version: app_marketing_version,
skip_binary_upload: true,
skip_screenshots: true,
metadata_path: "fastlane/metadata/osx",
submit_for_review: true,
automatic_release: true,
run_precheck_before_submit: false,
force: true,
}
params[:build_number] = options[:build_number] if options[:build_number]
deliver_with_retry(params)
end
# Build number is the latest in TestFlight + 1 — per-platform, always above
# what's shipped, and self-correcting on re-runs. Set BUILD_NUMBER to override.
# Returns the build number so the release lane can submit that exact build.
private_lane :desktop_build_and_upload do |options|
api_key = appstore_api_key
build_number = ENV["BUILD_NUMBER"]
if build_number.nil? || build_number.empty?
latest = latest_testflight_build_number(
api_key: api_key,
app_identifier: "com.darkrockstudios.apps.hammer",
platform: "osx",
initial_build_number: 0,
)
build_number = (latest.to_i + 1).to_s
end
UI.message("Mac App Store build number: #{build_number}")
sh("cd \"#{File.expand_path('..', __dir__)}\" && ./desktop/scripts/build-appstore.sh #{build_number}")
pkg_path = Dir.glob(File.expand_path("../desktop/build/installers/main-release/pkg/*.pkg", __dir__)).first
UI.user_error!("Build produced no .pkg") unless pkg_path
UI.message("Uploading #{pkg_path}")
# When releasing we must wait for App Store Connect to finish processing the
# build before deliver can attach it to the version and submit it.
upload_to_testflight(
api_key: api_key,
app_identifier: "com.darkrockstudios.apps.hammer",
app_platform: "osx",
pkg: pkg_path,
skip_waiting_for_build_processing: !options[:wait],
)
build_number
end
end
platform :ios do
desc "Build a signed .ipa and upload to TestFlight only (beta; does not submit for review)."
lane :ios_testflight do
ios_build_and_upload(wait: false)
end
desc "Full iOS App Store release: build, upload, wait for processing, submit for review, auto-release on approval."
lane :ios_release do
build_number = ios_build_and_upload(wait: true)
ios_submit(build_number: build_number)
end
desc "Submit an already-processed TestFlight build for review + auto-release. build_number defaults to latest."
lane :ios_submit do |options|
params = {
api_key: appstore_api_key,
app_identifier: "com.darkrockstudios.apps.hammer.ios",
platform: "ios",
app_version: app_marketing_version,
skip_binary_upload: true,
skip_screenshots: true,
metadata_path: "fastlane/metadata/ios",
submit_for_review: true,
automatic_release: true,
run_precheck_before_submit: false,
force: true,
}
params[:build_number] = options[:build_number] if options[:build_number]
deliver_with_retry(params)
end
# Same pattern as :mac — build number is the latest in TestFlight + 1.
# Set BUILD_NUMBER to override. Returns the build number.
private_lane :ios_build_and_upload do |options|
api_key = appstore_api_key
build_number = ENV["BUILD_NUMBER"]
if build_number.nil? || build_number.empty?
latest = latest_testflight_build_number(
api_key: api_key,
app_identifier: "com.darkrockstudios.apps.hammer.ios",
platform: "ios",
initial_build_number: 0,
)
build_number = (latest.to_i + 1).to_s
end
UI.message("iOS App Store build number: #{build_number}")
# Bump CFBundleVersion in Info.plist before archiving. CI runners are
# ephemeral so dirty state doesn't matter; locally, commit or revert
# the resulting Info.plist change after the lane runs.
set_info_plist_value(
path: File.expand_path("../ios/ios/Info.plist", __dir__),
key: "CFBundleVersion",
value: build_number,
)
build_app(
project: File.expand_path("../ios/ios.xcodeproj", __dir__),
scheme: "ios",
configuration: "Release",
output_directory: File.expand_path("../ios/build", __dir__),
output_name: "Hammer.ipa",
export_method: "app-store",
export_options: {
method: "app-store",
teamID: "8P3G3HT4J5",
signingStyle: "manual",
provisioningProfiles: {
"com.darkrockstudios.apps.hammer.ios" => "Hammer AppStore iOS",
},
},
clean: true,
silent: true,
)
# When releasing we must wait for App Store Connect to finish processing the
# build before deliver can attach it to the version and submit it.
upload_to_testflight(
api_key: api_key,
app_identifier: "com.darkrockstudios.apps.hammer.ios",
app_platform: "ios",
ipa: lane_context[SharedValues::IPA_OUTPUT_PATH],
skip_waiting_for_build_processing: !options[:wait],
)
build_number
end
end
platform :android do
desc "Runs all the tests"
lane :test do
gradle(
task: "test",
gradle_path: "./gradlew"
)
end
desc "Submit a new Build to Google Play Internal"
lane :internal do
gradle(
task: ":android:bundleRelease",
gradle_path: "./gradlew"
)
upload_to_play_store(track: 'internal')
end
desc "Submit a new Alpha Build to Google Play Close"
lane :alpha do
gradle(
task: ":android:bundleRelease",
gradle_path: "./gradlew"
)
upload_to_play_store(track: 'alpha')
end
desc "Submit a new Beta Build to Google Play Open"
lane :beta do
gradle(
task: ":android:bundleRelease",
gradle_path: "./gradlew"
)
upload_to_play_store(track: 'beta')
end
desc "Deploy a new version to the Google Play"
lane :release do
gradle(
task: "clean bundleRelease",
gradle_path: "./gradlew"
)
upload_to_play_store(
root_url: "https://androidpublisher.googleapis.com/",
skip_upload_images: true,
skip_upload_screenshots: true
)
end
end