forked from eatvio/eatvio_app
184 lines
6.7 KiB
Ruby
184 lines
6.7 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(:ios)
|
|
|
|
platform :ios do
|
|
desc "Push a new beta build to TestFlight"
|
|
lane :beta do
|
|
UI.message "Current working directory: #{Dir.pwd}"
|
|
UI.message "Checking API key file..."
|
|
|
|
possible_paths = [
|
|
"../AuthKey.p8",
|
|
"./AuthKey.p8",
|
|
"../../AuthKey.p8",
|
|
File.expand_path("../AuthKey.p8"),
|
|
File.expand_path("./AuthKey.p8")
|
|
]
|
|
|
|
auth_key_path = nil
|
|
possible_paths.each do |path|
|
|
if File.exist?(path)
|
|
UI.message "Found AuthKey.p8 at: #{path}"
|
|
auth_key_path = File.expand_path(path)
|
|
break
|
|
end
|
|
end
|
|
|
|
if auth_key_path.nil?
|
|
UI.user_error!("API key file not found. Tried paths: #{possible_paths.join(', ')}")
|
|
end
|
|
|
|
UI.message "Using auth_key_path: #{auth_key_path}"
|
|
|
|
# Authenticate to App Store Connect early:
|
|
# needed here by latest_testflight_build_number, not only by upload_to_testflight.
|
|
app_store_connect_api_key(
|
|
key_id: "325JS9JCZH",
|
|
issuer_id: "dfa27d1d-2bb8-4d4d-847e-0b32f9b880b3",
|
|
key_filepath: auth_key_path,
|
|
duration: 1200,
|
|
in_house: false
|
|
)
|
|
|
|
# Configure Flutter for release mode
|
|
UI.message "Configuring Flutter for release mode..."
|
|
sh("cd .. && flutter build ios --config-only --release")
|
|
|
|
# Read version and build number from Flutter Generated.xcconfig.
|
|
# They are only a floor: the actual build number is derived from TestFlight below,
|
|
# so repeated CI runs on the same commit can never hit
|
|
# ENTITY_ERROR.ATTRIBUTE.INVALID.DUPLICATE ("bundle version must be higher").
|
|
generated_xcconfig_path = File.join("..", "Flutter", "Generated.xcconfig")
|
|
flutter_build_name = nil
|
|
flutter_build_number = nil
|
|
|
|
if File.exist?(generated_xcconfig_path)
|
|
File.foreach(generated_xcconfig_path) do |line|
|
|
if (m = line.match(/FLUTTER_BUILD_NAME=(.*)/))
|
|
flutter_build_name = m[1].strip
|
|
elsif (m = line.match(/FLUTTER_BUILD_NUMBER=(.*)/))
|
|
flutter_build_number = m[1].strip
|
|
end
|
|
end
|
|
end
|
|
|
|
if flutter_build_name.nil? || flutter_build_number.nil?
|
|
UI.user_error!("Could not find FLUTTER_BUILD_NAME/FLUTTER_BUILD_NUMBER in #{generated_xcconfig_path}")
|
|
end
|
|
|
|
UI.message "Flutter version from pubspec: #{flutter_build_name} (#{flutter_build_number})"
|
|
|
|
# Apple closes a version train once that version is approved/released.
|
|
# Uploading into a closed train wastes a full ~8 min build and fails only
|
|
# at the upload step with altool 90186 ("closed for new build submissions")
|
|
# / 90062 ("must be higher than the previously approved version").
|
|
# Fail fast here, before building.
|
|
closed_train_states = [
|
|
Spaceship::ConnectAPI::AppStoreVersion::AppVersionState::READY_FOR_DISTRIBUTION,
|
|
Spaceship::ConnectAPI::AppStoreVersion::AppVersionState::PROCESSING_FOR_DISTRIBUTION,
|
|
Spaceship::ConnectAPI::AppStoreVersion::AppVersionState::PENDING_DEVELOPER_RELEASE,
|
|
Spaceship::ConnectAPI::AppStoreVersion::AppVersionState::PENDING_APPLE_RELEASE
|
|
].join(",")
|
|
asc_app = Spaceship::ConnectAPI::App.find("com.eatvioapp.app")
|
|
closed_train = nil
|
|
if asc_app.nil?
|
|
UI.important("App com.eatvioapp.app not found in App Store Connect, skipping closed-train guard")
|
|
else
|
|
closed_train = asc_app.get_app_store_versions(
|
|
filter: {
|
|
appVersionState: closed_train_states,
|
|
platform: Spaceship::ConnectAPI::Platform::IOS
|
|
}
|
|
).find do |v|
|
|
(Gem::Version.new(v.version_string) >= Gem::Version.new(flutter_build_name))
|
|
rescue ArgumentError
|
|
false
|
|
end
|
|
end
|
|
if closed_train
|
|
UI.user_error!(
|
|
"Version train #{closed_train.version_string} is closed for new submissions " \
|
|
"(#{closed_train.app_version_state}), pubspec version is #{flutter_build_name}. " \
|
|
"Bump the version in pubspec.yaml above #{closed_train.version_string} and re-run."
|
|
)
|
|
end
|
|
|
|
asc_latest_build_number = latest_testflight_build_number(
|
|
app_identifier: "com.eatvioapp.app",
|
|
version: flutter_build_name,
|
|
initial_build_number: flutter_build_number.to_i
|
|
)
|
|
|
|
new_build_number = [flutter_build_number.to_i, asc_latest_build_number].max + 1
|
|
UI.message "Latest TestFlight build number: #{asc_latest_build_number} -> uploading build #{new_build_number}"
|
|
|
|
match(type: "appstore", readonly: true)
|
|
|
|
# Set build number explicitly instead of incrementing
|
|
increment_build_number(
|
|
xcodeproj: "Runner.xcodeproj",
|
|
build_number: new_build_number
|
|
)
|
|
|
|
update_code_signing_settings(
|
|
use_automatic_signing: false,
|
|
path: "Runner.xcodeproj",
|
|
team_id: "VL68C36HYS",
|
|
targets: ["Runner"],
|
|
code_sign_identity: "Apple Distribution",
|
|
profile_name: "match AppStore com.eatvioapp.app 1781098260"
|
|
)
|
|
|
|
build_app(
|
|
workspace: "Runner.xcworkspace",
|
|
scheme: "Runner",
|
|
export_method: "app-store",
|
|
# codesigning_identity: "Apple Distribution",
|
|
export_team_id: "VL68C36HYS"
|
|
)
|
|
|
|
begin
|
|
upload_to_testflight(
|
|
skip_waiting_for_build_processing: true,
|
|
skip_submission: true,
|
|
distribute_external: false,
|
|
notify_external_testers: false,
|
|
changelog: "TestFlight build #{new_build_number}",
|
|
verbose: true
|
|
)
|
|
rescue => ex
|
|
# Xcode 26 altool prints a harmless "ERROR: ... CDUploaderStateInfoResumeFilePath"
|
|
# line even when the package was delivered fine (UPLOAD SUCCEEDED appears in the
|
|
# same output). fastlane < 2.240.0 treats every ERROR line as a failure
|
|
# (fastlane#30130), so the lane would die after a successful upload.
|
|
# Real Apple rejections (90186 closed train, 90062 version too low, ...) always
|
|
# contain UPLOAD FAILED and/or iris-code - those must still fail the lane.
|
|
if ex.message.include?("CDUploaderStateInfoResumeFilePath") &&
|
|
!ex.message.include?("UPLOAD FAILED") &&
|
|
!ex.message.include?("iris-code")
|
|
UI.important("altool delivered the package but reported a bogus resume-file ERROR " \
|
|
"(fastlane#30130). Treating upload as successful - " \
|
|
"verify the build appears in TestFlight.")
|
|
else
|
|
UI.error "Upload to TestFlight failed: #{ex.message}"
|
|
UI.error "Full error: #{ex.backtrace.join("\n")}"
|
|
raise ex
|
|
end
|
|
end
|
|
end
|
|
end
|