class Spaceship::Tunes::BuildTrain
Represents a build train of builds from App
Store Connect A build train is all builds for a given version number with different build numbers
Attributes
@return (Spaceship::Tunes::Application
) A reference to the application this train is for
@return (Array
) An array of all builds that are inside this train (Spaceship::Tunes::Build
)
@return (Bool) Is external beta testing enabled for this train? Only one train can have enabled testing.
@return (Bool) Is internal beta testing enabled for this train? Only one train can have enabled testing.
@return (Array
) An array of all invalid builds that are inside this train
@return (String
) Platform (e.g. “ios”)
@return (Array
) An array of all processing builds that are inside this train (Spaceship::Tunes::Build
) Does not include invalid builds.
I never got this to work to properly try and debug this
@return (Spaceship::Tunes::VersionSet
) A reference to the version set
this train is for
@return (String
) The version number of this train
Public Class Methods
@param application (Spaceship::Tunes::Application
) The app this train is for @param app_id (String
) The unique Apple ID of this app
# File spaceship/lib/spaceship/tunes/build_train.rb, line 51 def all(application, app_id, platform: nil) trains = [] trains += client.build_trains(app_id, 'internal', platform: platform)['trains'] trains += client.build_trains(app_id, 'external', platform: platform)['trains'] result = {} trains.each do |attrs| attrs[:application] = application current = self.factory(attrs) if (!platform.nil? && current.platform == platform) || platform.nil? result[current.version_string] = current end end result end
Public Instance Methods
@return (Spaceship::Tunes::Build
) The latest build for this train, sorted by upload time.
# File spaceship/lib/spaceship/tunes/build_train.rb, line 114 def latest_build @builds.max_by(&:upload_date) end
Setup all the builds and processing builds
# File spaceship/lib/spaceship/tunes/build_train.rb, line 69 def setup super @builds = (self.raw_data['builds'] || []).collect do |attrs| attrs[:build_train] = self Tunes::Build.factory(attrs) end @invalid_builds = @builds.select do |build| build.processing_state == 'processingFailed' || build.processing_state == 'invalidBinary' end # This step may not be necessary anymore - it seems as if every processing build will be caught by the # @builds.each below, but not every processing build makes it to buildsInProcessing, so this is redundant @processing_builds = (self.raw_data['buildsInProcessing'] || []).collect do |attrs| attrs[:build_train] = self Tunes::Build.factory(attrs) end # since buildsInProcessing appears empty, fallback to also including processing state from @builds @builds.each do |build| # What combination of attributes constitutes which state is pretty complicated. The table below summarizes # what I've observed, but there's no reason to believe there aren't more states I just haven't seen yet. # The column headers are qualitative states of a given build, and the first column is the observed attributes # of that build. # NOTE: Some of the builds in the build_trains.json fixture do not follow these rules. I don't know if that is # because those examples are older, and the iTC API has changed, or if their format is still a possibility. # The second part of the OR clause in the line below exists so that those suspicious examples continue to be # accepted for unit tests. # +---------------------+-------------------+-------------------+-----------------+--------------------+---------+ # | | just after upload | normal processing | invalid binary | processing failed | success | # +---------------------+-------------------+-------------------+-----------------+--------------------+---------+ # | build.processing = | true | true | true | true | false | # | build.valid = | false | true | false | true | true | # | .processing_state = | "processing" | "processing" | "invalidBinary" | "processingFailed" | nil | # +---------------------+-------------------+-------------------+-----------------+--------------------+---------+ if build.processing_state == 'processing' || (build.processing && build.processing_state != 'invalidBinary' && build.processing_state != 'processingFailed') @processing_builds << build end end self.version_set = self.application.version_set_for_platform(self.platform) end
@param (testing_type) internal or external
# File spaceship/lib/spaceship/tunes/build_train.rb, line 119 def update_testing_status!(new_value, testing_type, build = nil) build ||= latest_build if testing_type == 'external' platform = build ? build.platform : self.application.platform testing_key = "#{testing_type}Testing" data = client.build_trains(self.application.apple_id, testing_type, platform: platform) # Delete the irrelevant trains and update the relevant one to enable testing data['trains'].delete_if do |train| if train['versionString'] != version_string true else train[testing_key]['value'] = new_value # also update the builds train['builds'].delete_if do |b| if b[testing_key].nil? true elsif build && b["buildVersion"] == build.build_version b[testing_key]['value'] = new_value false elsif b[testing_key]['value'] == true b[testing_key]['value'] = false false else true end end false end end begin result = client.update_build_trains!(application.apple_id, testing_type, data) rescue Spaceship::Tunes::Error => ex if ex.to_s.include?("You must provide an answer for this question") # This is a very common error message that's raised by TestFlight # We want to show a nicer error message with instructions on how # to resolve the underlying issue # https://github.com/fastlane/fastlane/issues/1873 # https://github.com/fastlane/fastlane/issues/4002 error_message = [""] # to have a nice new-line in the beginning error_message << "TestFlight requires you to provide the answer to the encryption question" error_message << "to provide the reply, please add the following to your Info.plist file" error_message << "" error_message << "<key>ITSAppUsesNonExemptEncryption</key><false/>" error_message << "" error_message << "Afterwards re-build your app and try again" error_message << "App Store Connect reported: '#{ex}'" raise error_message.join("\n") else raise ex end end self.internal_testing_enabled = new_value if testing_type == 'internal' self.external_testing_enabled = new_value if testing_type == 'external' result end