# 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 before_all do FIREBASE_DISTRIBUTION_INTERNAL_APP = "1:64659984801:ios:a9c4640d2a1960a5f43be0" FIREBASE_APP_DISTRIBUTION_GROUPS_QA = "ios-qa" KEYCHAIN_NAME = "temp_keychain" INTERNAL_APP_IDENTIFIER = ENV['CI_EVAL_INTERNAL_APP_IDENTIFIER'] PROD_APP_IDENTIFIER = ENV['CI_EVAL_PROD_APP_IDENTIFIER'] APP_TARGET = "InitProject" # Environment variable should be the full path to the firebase auth .json FIREBASE_DISTRIBUTION_AUTH_FILE = ENV['CI_EVAL_FIREBASE_DISTRIBUTION_AUTH_FILE'] # provisioning profiles, they are under a specific folder # filename come from environment variable provisioning_profile_folder = "#{ENV['HOME']}/Library/MobileDevice/Provisioning Profiles" internal_provisioning_profile_name = ENV['CI_EVAL_IOS_PROVISIONING_PROFILE_INTERNAL_FILENAME'] INTERNAL_PROVISIONING_PROFILE_FILE = "#{provisioning_profile_folder}/#{internal_provisioning_profile_name}" prod_provisioning_profile_name = ENV['CI_EVAL_IOS_PROVISIONING_PROFILE_PROD_FILENAME'] PROD_PROVISIONING_PROFILE_FILE = "#{provisioning_profile_folder}/#{prod_provisioning_profile_name}" # full path to the signing certificate. Created on the Apple Developer portal, then exported from keychain, usually as p12. IOS_CERT_FILE = ENV['CI_EVAL_IOS_CERT_FILE'] # password to the certificate CERTIFICATE_PASSWORD = ENV['CI_EVAL_IOS_CERT_PASSWORD'].strip # App Api Key File Path, created on https://appstoreconnect.apple.com/access/api APP_STORE_API_KEY_FILE = ENV['CI_EVAL_IOS_APP_STORE_KEY_FILE'] APP_STORE_API_KEY_ID = ENV['CI_EVAL_IOS_APP_STORE_KEY_ID'] APP_STORE_API_KEY_ISSUER_ID = ENV['CI_EVAL_IOS_APP_STORE_KEY_ISSUER_ID'] end desc "Creates Release Signed build and publishes it to firebase" desc ">Optionally release notes can be added like so:" desc "```sh" desc "[bundle exec] fastlane deployInternalToFirebase release_notes:\"testing notes\"" desc "```" lane :deployInternalToFirebase do |options| release_notes = options[:release_notes] if release_notes.nil? || release_notes.empty? commit = last_git_commit release_notes = "Last commit with hash: #{commit[:commit_hash]} and message: #{commit[:message]}" end ipa_name = "Internal.ipa" buildReleaseIPA( ipa_name: ipa_name, method: "ad-hoc", profile: INTERNAL_PROVISIONING_PROFILE_FILE, app_identifier: INTERNAL_APP_IDENTIFIER, ) firebase_app_distribution( service_credentials_file: FIREBASE_DISTRIBUTION_AUTH_FILE, app: FIREBASE_DISTRIBUTION_INTERNAL_APP, groups: FIREBASE_APP_DISTRIBUTION_GROUPS_QA, ipa_path: "builds/#{ipa_name}", release_notes: "#{release_notes}", ) end desc "Submit a new Production Build to TestFlight" desc "By Default it sets the version_code to last from TestFlight + 1." desc ">Optionally version code increase can be skipped via:" desc "```sh" desc "[bundle exec] fastlane deployInternalFirebase skip_build_number_increase:true" desc "```" lane :deployToTestFlight do |options| skip_build_number_increase = options[:skip_build_number_increase] # optional, if not set, it gets the last from TestFlight then adds + 1 app_store_connect_api_key( key_id: APP_STORE_API_KEY_ID, issuer_id: APP_STORE_API_KEY_ISSUER_ID, key_filepath: APP_STORE_API_KEY_FILE, is_key_content_base64: false, in_house: false # optional but may be required if using match/sigh ) if skip_build_number_increase.nil? || !skip_build_number_increase increment_build_number({ build_number: latest_testflight_build_number(app_identifier: PROD_APP_IDENTIFIER) + 1 }) end ipa_name = "Release.ipa" buildReleaseIPA( ipa_name: ipa_name, method: "app-store", profile: PROD_PROVISIONING_PROFILE_FILE, app_identifier: PROD_APP_IDENTIFIER, ) upload_to_testflight( skip_submission: true, ipa: "./builds/#{ipa_name}", skip_waiting_for_build_processing: true, ) end desc "Create new Release IPA" desc "Find it under ios/builds" lane :buildReleaseIPA do |options| ipa_name = options[:ipa_name] || "InternalBuild.ipa" method = options[:method] || "ad-hoc" profile = options[:profile] || INTERNAL_PROVISIONING_PROFILE_FILE app_identifier = options[:app_identifier] || INTERNAL_APP_IDENTIFIER setupCodeSigning( profile: profile, app_identifier: app_identifier, ) build_app( scheme: APP_TARGET, export_method: method, output_directory: "./builds", output_name: ipa_name ) end desc "Sets up the and initialises the required authentications and project configurations to sign a build" desc "Creates a temporary keychain which should be deleted at the end, see :cleanupKeyChain" lane :setupCodeSigning do |options| profile = options[:profile] app_identifier = options[:app_identifier] password = (0...50).map { ('a'..'z').to_a[rand(26)] }.join cleanupKeyChain() create_keychain( name: KEYCHAIN_NAME, default_keychain: false, unlock: true, timeout: 360000, lock_when_sleeps: false, add_to_search_list: true, password: password ) import_certificate( certificate_path: IOS_CERT_FILE, keychain_name: KEYCHAIN_NAME, keychain_password: password, certificate_password: CERTIFICATE_PASSWORD, log_output: true ) update_app_identifier( plist_path: "#{APP_TARGET}/Info.plist", app_identifier: app_identifier ) update_project_provisioning( xcodeproj: "#{APP_TARGET}.xcodeproj", target_filter: "#{APP_TARGET}", profile: profile, build_configuration: "Release" ) update_project_team( # Set the right team on your project teamid: CredentialsManager::AppfileConfig.try_fetch_value(:team_id) ) update_code_signing_settings( use_automatic_signing: false, code_sign_identity: "iPhone Distribution", path: "#{APP_TARGET}.xcodeproj", sdk: "iphoneos*" ) unlock_keychain( path: KEYCHAIN_NAME, password: password ) end desc "Deletes the temporary keychain if it exists" desc "The keychain is created via :setupCodeSigning" lane :cleanupKeyChain do begin delete_keychain(name: KEYCHAIN_NAME) if File.exist? File.expand_path("#{ENV['HOME']}/Library/Keychains/#{KEYCHAIN_NAME}-db") rescue => ex UI.important('Could not delete keychain!') end end after_all do cleanupKeyChain() end end