b0VIM 8.0̫]<)*hjoshJoshs-MacBook-Pro.local~josh/Projects/fastlane/fastlane/fastlane/lib/fastlane/actions/download_dsyms.rbutf-8 3210#"! UtpWWXALad$WyE*xS,+ @ 4 3  o * b  v u e 8 Sv87={>21gRdcqIH end end next UI.verbose("Version #{version} doesn't match: #{train.version_string}") if version && version != train.version_string UI.verbose(message.join(" ")) message << ", comparing to supplied version: #{version}" if version message << "Found train (version): #{train.version_string}" message = [] app.tunes_all_build_trains(platform: platform).each do |train| UI.message(message.join(" ")) message << "(#{build_number})" if build_number message << "v#{version}" if version message << "Looking for dSYM files for '#{params[:app_identifier]}' on platform #{platform}" message = [] # Write a nice message end output_directory += '/' if output_directory && !output_directory.end_with?('/') # Make sure output_directory has a slash on the end end version = version.split(".").map(&:to_i).join(".") if version # Remove leading zeros from version string (eg. 1.02 -> 1.2) end build_number = live_version.build_version version = live_version.version # No need to search for candidates, because released App Store version should only have one build UI.user_error!("Could not find live version for your app, please try setting 'latest' or a specific version") if live_version.nil? live_version = app.live_version(platform: platform) UI.message("Looking for live version...") elsif version == 'live' end build_number = latest_candidate_build.build_version version = latest_candidate_build.train_version # The build_version of a candidate build does not always match the one in latest_version so get the version and build number from the same place. else build_number = latest_version.build_version version = latest_version.version if latest_candidate_build.nil? latest_candidate_build = latest_version.candidate_builds.max_by(&:upload_date) UI.user_error!("Could not find latest version for your app, please try setting a specific version") if latest_version.version.nil? latest_version = app.edit_version(platform: platform) || app.live_version(platform: platform) UI.message("Looking for latest version...") # Try to grab the edit version first, else fallback to live version if version == 'latest' # Set version if it is latest min_version = Gem::Version.new(params[:min_version]) if params[:min_version] wait_timeout = params[:wait_timeout] wait_for_dsym_processing = params[:wait_for_dsym_processing] output_directory = params[:output_directory] platform = params[:platform] build_number = params[:build_number] version = params[:version] # Process options end UI.user_error!("Could not find app with bundle identifier '#{params[:app_identifier]}' on account #{params[:username]}") unless app app = Spaceship::Application.find(params[:app_identifier]) # Get App UI.message("Login successful") Spaceship::Tunes.select_team Spaceship::Tunes.login(params[:username]) UI.message("Login to App Store Connect (#{params[:username]})") require 'net/http' require 'spaceship' def self.run(params) # rubocop:disable Metrics/PerceivedComplexity class DownloadDsymsAction < Action end DSYM_PATHS = :DSYM_PATHS module SharedValues module Actionsmodule FastlaneadLBV  T  ^ & b } B x@bf+:~}g]uG=< YOED,end end end end :app_store_connect def self.category end ] 'download_dsyms(min_version: "1.2.3")' 'download_dsyms(version: "live")', 'download_dsyms(version: "1.0.0", build_number: "345")', 'download_dsyms', [ def self.example_code end [:ios, :appletvos].include?(platform) def self.is_supported?(platform) end ["KrauseFx"] def self.authors end nil def self.return_value end ] ['DSYM_PATHS', 'An array to all the zipped dSYM files'] [ def self.output end ] type: Integer) default_value: 300, optional: true, description: "Number of seconds to wait for dSYMs to process", env_name: "DOWNLOAD_DSYMS_WAIT_TIMEOUT", short_option: "-t", FastlaneCore::ConfigItem.new(key: :wait_timeout, type: Boolean), default_value: false, optional: true, description: "Wait for dSYMs to process", env_name: "DOWNLOAD_DSYMS_WAIT_FOR_DSYM_PROCESSING", short_option: "-w", FastlaneCore::ConfigItem.new(key: :wait_for_dsym_processing, optional: true), description: "Where to save the download dSYMs, defaults to the current path", env_name: "DOWNLOAD_DSYMS_OUTPUT_DIRECTORY", short_option: "-s", FastlaneCore::ConfigItem.new(key: :output_directory, optional: true), description: "The minimum app version for dSYMs you wish to download", env_name: "DOWNLOAD_DSYMS_MIN_VERSION", short_option: "-m", FastlaneCore::ConfigItem.new(key: :min_version, optional: true), description: "The app build_number for dSYMs you wish to download", env_name: "DOWNLOAD_DSYMS_BUILD_NUMBER", short_option: "-b", FastlaneCore::ConfigItem.new(key: :build_number, optional: true), description: "The app version for dSYMs you wish to download, pass in 'latest' to download only the latest build's dSYMs or 'live' to download only the live verion dSYMs", env_name: "DOWNLOAD_DSYMS_VERSION", short_option: "-v", FastlaneCore::ConfigItem.new(key: :version, default_value: :ios), optional: true, description: "The app platform for dSYMs you wish to download (ios, appletvos)", env_name: "DOWNLOAD_DSYMS_PLATFORM", short_option: "-p", FastlaneCore::ConfigItem.new(key: :platform,ad(HAbXW@N !  z , + ! c ~ A  [ # h#g>B~F C RuHG end), ENV["FASTLANE_ITC_TEAM_NAME"] = value.to_s verify_block: proc do |value| default_value_dynamic: true, default_value: CredentialsManager::AppfileConfig.try_fetch_value(:itc_team_name), code_gen_sensitive: true, optional: true, description: "The name of your App Store Connect team if you're in multiple teams", env_name: "DOWNLOAD_DSYMS_TEAM_NAME", short_option: "-e", FastlaneCore::ConfigItem.new(key: :team_name, end), ENV["FASTLANE_ITC_TEAM_ID"] = value.to_s verify_block: proc do |value| default_value_dynamic: true, default_value: CredentialsManager::AppfileConfig.try_fetch_value(:itc_team_id), code_gen_sensitive: true, is_string: false, # as we also allow integers, which we convert to strings anyway optional: true, description: "The ID of your App Store Connect team if you're in multiple teams", env_name: "DOWNLOAD_DSYMS_TEAM_ID", short_option: "-k", FastlaneCore::ConfigItem.new(key: :team_id, default_value_dynamic: true), default_value: CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier), code_gen_sensitive: true, optional: false, description: "The bundle identifier of your app", env_name: "DOWNLOAD_DSYMS_APP_IDENTIFIER", short_option: "-a", FastlaneCore::ConfigItem.new(key: :app_identifier, default_value_dynamic: true), default_value: user, description: "Your Apple ID Username for App Store Connect", env_name: "DOWNLOAD_DSYMS_USERNAME", short_option: "-u", FastlaneCore::ConfigItem.new(key: :username, [ user ||= CredentialsManager::AppfileConfig.try_fetch_value(:apple_id) user = CredentialsManager::AppfileConfig.try_fetch_value(:itunes_connect_id) def self.available_options end ].join("\n") sample "This action downloads dSYM files from App Store Connect after the ipa gets re-compiled by Apple. Useful if you have Bitcode enabled.".markdown_preserve_newlines, [ SAMPLE ``` end clean_build_artifacts # Delete the local dSYM files upload_symbols_to_crashlytics # Upload them to Crashlytics download_dsyms # Download dSYM files from iTC lane :refresh_dsyms do ```ruby sample = <<-SAMPLE.markdown_sample def self.details end "Download dSYM files from App Store Connect for Bitcode apps" def self.description #####################################################ad WUD65m ? ,   c b N : x @ e  7 " qa`D<,I=3m^ ]AN # @!group Documentation ##################################################### end res.body res = http.get(uri.request_uri) http.use_ssl = (uri.scheme == "https") http = Net::HTTP.new(uri.host, uri.port) uri = URI.parse(url) def self.download_file(url) end file_name File.binwrite(file_name, data) end file_name = output_directory + file_name if output_directory file_name = "#{bundle_id}-#{train_number}-#{build_number}.dSYM.zip" def self.write_dsym(data, bundle_id, train_number, build_number, output_directory) end Actions.lane_context[SharedValues::DSYM_PATHS] << File.expand_path(path) Actions.lane_context[SharedValues::DSYM_PATHS] ||= [] UI.success("🔑 Successfully downloaded dSYM file for #{train_number} - #{build_version} to '#{path}'") path = write_dsym(result, bundle_id, train_number, build_version, output_directory) result = self.download_file(download_url) def self.download(download_url, bundle_id, train_number, build_version, output_directory) # rubocop:enable Metrics/PerceivedComplexity end end UI.error("No dSYM files found on App Store Connect - this usually happens when no recompiling has happened yet") if (Actions.lane_context[SharedValues::DSYM_PATHS] || []).count == 0 end end end UI.message("No dSYM URL for #{build.build_version} (#{train.version_string})") else break if build_number self.download(download_url, app.bundle_id, train.version_string, build.build_version, output_directory) if download_url end break end end next sleep(30) UI.message("Waiting for dSYM file to appear...") else UI.message("Could not find any dSYM for #{build.build_version} (#{train.version_string})") # In some cases, AppStoreConnect does not process the dSYMs, thus no error should be thrown. if !wait_for_dsym_processing || (Time.now - start) > wait_timeout unless download_url end UI.error("Error accessing dSYM file for build\n\n#{build}\n\nException: #{ex}") rescue Spaceship::TunesClient::ITunesConnectError => ex UI.verbose("dsym_url: #{download_url}") download_url = build_details.dsym_url build_details = app.tunes_build_details(train: train.version_string, build_number: build.build_version, platform: platform) begin loop do download_url = nil start = Time.now UI.verbose("Build_version: #{build.build_version} matches #{build_number}, grabbing dsym_url") if build_number end next UI.verbose("build_version: #{build.build_version} doesn't match: #{build_number}") if build_number && build.build_version != build_number UI.verbose(message.join(" ")) message << ", comparing to supplied build_number: #{build_number}" if build_number message << "Found build version: #{build.build_version}" message = [] app.tunes_all_builds_for_train(train: train.version_string, platform: platform).each do |build| end next UI.verbose("Min version #{min_version} not reached: #{train.version_string}") if min_version && min_version > Gem::Version.new(train.version_string)