fastlane 2.150.0.rc1 → 2.150.0.rc6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/deliver/lib/deliver/download_screenshots.rb +48 -26
  3. data/deliver/lib/deliver/runner.rb +0 -17
  4. data/deliver/lib/deliver/submit_for_review.rb +79 -32
  5. data/deliver/lib/deliver/upload_metadata.rb +92 -21
  6. data/deliver/lib/deliver/upload_price_tier.rb +9 -2
  7. data/deliver/lib/deliver/upload_screenshots.rb +61 -9
  8. data/fastlane/lib/fastlane/actions/.hockey.rb.swp +0 -0
  9. data/fastlane/lib/fastlane/actions/.slack.rb.swp +0 -0
  10. data/fastlane/lib/fastlane/actions/.update_project_provisioning.rb.swp +0 -0
  11. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +78 -85
  12. data/fastlane/lib/fastlane/actions/set_changelog.rb +23 -20
  13. data/fastlane/lib/fastlane/version.rb +1 -1
  14. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.xcworkspace/xcuserdata/josh.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  15. data/fastlane_core/lib/fastlane_core/build_watcher.rb +4 -4
  16. data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +89 -52
  17. data/pilot/lib/pilot/.manager.rb.swp +0 -0
  18. data/produce/lib/produce/itunes_connect.rb +43 -5
  19. data/spaceship/lib/spaceship/client.rb +4 -3
  20. data/spaceship/lib/spaceship/connect_api.rb +5 -1
  21. data/spaceship/lib/spaceship/{.DS_Store → connect_api/.DS_Store} +0 -0
  22. data/spaceship/lib/spaceship/connect_api/client.rb +50 -20
  23. data/spaceship/lib/spaceship/connect_api/file_uploader.rb +98 -0
  24. data/spaceship/lib/spaceship/connect_api/models/age_rating_declaration.rb +6 -2
  25. data/spaceship/lib/spaceship/connect_api/models/app.rb +35 -13
  26. data/spaceship/lib/spaceship/connect_api/models/app_info.rb +4 -11
  27. data/spaceship/lib/spaceship/connect_api/models/app_preview.rb +129 -0
  28. data/spaceship/lib/spaceship/connect_api/models/app_preview_set.rb +71 -0
  29. data/spaceship/lib/spaceship/connect_api/models/app_review_attachment.rb +18 -28
  30. data/spaceship/lib/spaceship/connect_api/models/app_screenshot.rb +88 -59
  31. data/spaceship/lib/spaceship/connect_api/models/app_screenshot_set.rb +26 -2
  32. data/spaceship/lib/spaceship/connect_api/models/app_store_version.rb +1 -0
  33. data/spaceship/lib/spaceship/connect_api/models/app_store_version_localization.rb +16 -0
  34. data/spaceship/lib/spaceship/connect_api/models/territory.rb +27 -0
  35. data/spaceship/lib/spaceship/connect_api/models/user.rb +2 -1
  36. data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +215 -74
  37. data/spaceship/lib/spaceship/connect_api/users/users.rb +13 -0
  38. metadata +16 -7
@@ -13,9 +13,16 @@ module Deliver
13
13
  app_id = legacy_app.apple_id
14
14
  app = Spaceship::ConnectAPI::App.get(app_id: app_id)
15
15
 
16
+ attributes = {}
17
+ territory_ids = []
18
+
16
19
  app_prices = app.fetch_app_prices
17
20
  if app_prices.first
18
- old_price = app_prices.first.id
21
+ old_price = app_prices.first.price_tier.id
22
+ else
23
+ UI.message("App has no prices yet... Enabling all countries in App Store Connect")
24
+ territory_ids = Spaceship::ConnectAPI::Territory.all.map(&:id)
25
+ attributes[:availableInNewTerritories] = true
19
26
  end
20
27
 
21
28
  if price_tier == old_price
@@ -23,7 +30,7 @@ module Deliver
23
30
  return
24
31
  end
25
32
 
26
- app.update_app_price_tier(app_price_tier_id: price_tier)
33
+ app.update(attributes: attributes, app_price_tier_id: price_tier, territory_ids: territory_ids)
27
34
  UI.success("Successfully updated the pricing from #{old_price} to #{price_tier}")
28
35
  end
29
36
  end
@@ -1,4 +1,5 @@
1
1
  require 'spaceship/tunes/tunes'
2
+ require 'digest/md5'
2
3
 
3
4
  require_relative 'app_screenshot'
4
5
  require_relative 'module'
@@ -34,13 +35,39 @@ module Deliver
34
35
 
35
36
  # Iterate over all screenshots for each set and delete
36
37
  screenshot_sets = localization.get_app_screenshot_sets
38
+
39
+ # Multi threading delete on single localization
40
+ threads = []
41
+ errors = []
42
+
37
43
  screenshot_sets.each do |screenshot_set|
38
44
  UI.message("Removing all previously uploaded screenshots for '#{localization.locale}' '#{screenshot_set.screenshot_display_type}'...")
39
45
  screenshot_set.app_screenshots.each do |screenshot|
40
46
  UI.verbose("Deleting screenshot - #{localization.locale} #{screenshot_set.screenshot_display_type} #{screenshot.id}")
41
- screenshot.delete!
47
+ threads << Thread.new do
48
+ begin
49
+ screenshot.delete!
50
+ UI.verbose("Deleted screenshot - #{localization.locale} #{screenshot_set.screenshot_display_type} #{screenshot.id}")
51
+ rescue => error
52
+ UI.verbose("Failed to delete screenshot - #{localization.locale} #{screenshot_set.screenshot_display_type} #{screenshot.id}")
53
+ errors << error
54
+ end
55
+ end
42
56
  end
43
57
  end
58
+
59
+ sleep(1) # Feels bad but sleeping a bit to let the threads catchup
60
+
61
+ unless threads.empty?
62
+ Helper.show_loading_indicator("Waiting for screenshots to be deleted for '#{localization.locale}'... (might be slow)") unless FastlaneCore::Globals.verbose?
63
+ threads.each(&:join)
64
+ Helper.hide_loading_indicator unless FastlaneCore::Globals.verbose?
65
+ end
66
+
67
+ # Crash if any errors happen while deleting
68
+ unless errors.empty?
69
+ UI.crash!(errors.map(&:message).join("\n"))
70
+ end
44
71
  end
45
72
  end
46
73
 
@@ -65,6 +92,16 @@ module Deliver
65
92
  localizations = version.get_app_store_version_localizations
66
93
  end
67
94
 
95
+ upload_screenshots(screenshots_per_language, localizations)
96
+ end
97
+
98
+ def upload_screenshots(screenshots_per_language, localizations)
99
+ # Check if should wait for processing
100
+ wait_for_processing = !FastlaneCore::Env.truthy?("DELIVER_SKIP_WAIT_FOR_SCREENSHOT_PROCESSING")
101
+ if wait_for_processing
102
+ UI.important("Set environment variable DELIVER_SKIP_WAIT_FOR_SCREENSHOT_PROCESSING=true to skip waiting for screenshots to process")
103
+ end
104
+
68
105
  # Upload screenshots
69
106
  indized = {} # per language and device type
70
107
 
@@ -88,7 +125,13 @@ module Deliver
88
125
  app_screenshot_sets_map[app_screenshot_set.screenshot_display_type] = app_screenshot_set
89
126
 
90
127
  # Set initial screnshot count
91
- indized[localization.locale][app_screenshot_set.screenshot_display_type] ||= app_screenshot_set.app_screenshots.size
128
+ indized[localization.locale][app_screenshot_set.screenshot_display_type] ||= {
129
+ count: app_screenshot_set.app_screenshots.size,
130
+ checksums: []
131
+ }
132
+
133
+ checksums = app_screenshot_set.app_screenshots.map(&:source_file_checksum).uniq
134
+ indized[localization.locale][app_screenshot_set.screenshot_display_type][:checksums] = checksums
92
135
  end
93
136
 
94
137
  UI.message("Uploading #{screenshots_for_language.length} screenshots for language #{language}")
@@ -107,21 +150,30 @@ module Deliver
107
150
  })
108
151
  app_screenshot_sets_map[display_type] = set
109
152
 
110
- indized[localization.locale][set.screenshot_display_type] = 0
153
+ indized[localization.locale][set.screenshot_display_type] = {
154
+ count: 0,
155
+ checksums: []
156
+ }
111
157
  end
112
158
 
113
- index = indized[localization.locale][set.screenshot_display_type]
159
+ index = indized[localization.locale][set.screenshot_display_type][:count]
114
160
 
115
161
  if index >= 10
116
- UI.error("Too many screenshots found for device '#{screenshot.formatted_name}' in '#{screenshot.language}', skipping this one (#{screenshot.path})")
162
+ UI.error("Too many screenshots found for device '#{screenshot.device_type}' in '#{screenshot.language}', skipping this one (#{screenshot.path})")
117
163
  next
118
164
  end
119
165
 
120
- indized[localization.locale][set.screenshot_display_type] += 1
166
+ bytes = File.binread(screenshot.path)
167
+ checksum = Digest::MD5.hexdigest(bytes)
168
+ duplicate = indized[localization.locale][set.screenshot_display_type][:checksums].include?(checksum)
121
169
 
122
- # Also.. what is the messages type even for?
123
- UI.message("Uploading '#{screenshot.path}'...")
124
- set.upload_screenshot(path: screenshot.path)
170
+ if duplicate
171
+ UI.message("Previous uploaded. Skipping '#{screenshot.path}'...")
172
+ else
173
+ indized[localization.locale][set.screenshot_display_type][:count] += 1
174
+ UI.message("Uploading '#{screenshot.path}'...")
175
+ set.upload_screenshot(path: screenshot.path, wait_for_processing: wait_for_processing)
176
+ end
125
177
  end
126
178
  end
127
179
  UI.success("Successfully uploaded screenshots to App Store Connect")
@@ -435,6 +435,10 @@ Omit `build_number` to let _fastlane_ automatically select the latest build numb
435
435
 
436
436
  Use the `submission_information` parameter for additional submission specifiers, including compliance and IDFA settings. Look at the Spaceship's [`app_submission.rb`](https://github.com/fastlane/fastlane/blob/master/spaceship/lib/spaceship/tunes/app_submission.rb) file for options. See [this example](https://github.com/artsy/eigen/blob/faa02e2746194d8d7c11899474de9c517435eca4/fastlane/Fastfile#L131-L149).
437
437
 
438
+ ```no-highlight
439
+ fastlane deliver submit_build --build_number 830 --submission_information "{\"export_compliance_uses_encryption\": false, \"add_id_info_uses_idfa\": false }"
440
+ ```
441
+
438
442
  # Credentials
439
443
 
440
444
  A detailed description about how your credentials are handled is available in a [credentials_manager](https://github.com/fastlane/fastlane/tree/master/credentials_manager).
@@ -494,33 +498,32 @@ Key | Editable While Live | Directory | Filename
494
498
 
495
499
  ### Available Categories
496
500
 
497
- You can always prefix the category using `MZGenre.` (e.g. `MZGenre.Book`). _deliver_ supports both notations.
498
-
499
- - `Book`
500
- - `Business`
501
- - `Apps.Catalogs`
502
- - `Education`
503
- - `Entertainment`
504
- - `Finance`
505
- - `Apps.Food_Drink`
506
- - `Games`
507
- - `Healthcare_Fitness`
508
- - `Lifestyle`
509
- - `Medical`
510
- - `Music`
511
- - `Navigation`
512
- - `News`
513
- - `Apps.Newsstand`
514
- - `Photography`
515
- - `Productivity`
516
- - `Reference`
517
- - `Apps.Shopping`
518
- - `SocialNetworking`
519
- - `Sports`
520
- - `Stickers`
521
- - `Travel`
522
- - `Utilities`
523
- - `Weather`
501
+ - `FOOD_AND_DRINK`
502
+ - `BUSINESS`
503
+ - `EDUCATION`
504
+ - `SOCIAL_NETWORKING`
505
+ - `BOOKS`
506
+ - `SPORTS`
507
+ - `FINANCE`
508
+ - `REFERENCE`
509
+ - `GRAPHICS_AND_DESIGN`
510
+ - `DEVELOPER_TOOLS`
511
+ - `HEALTH_AND_FITNESS`
512
+ - `MUSIC`
513
+ - `WEATHER`
514
+ - `TRAVEL`
515
+ - `ENTERTAINMENT`
516
+ - `STICKERS`
517
+ - `GAMES`
518
+ - `LIFESTYLE`
519
+ - `MEDICAL`
520
+ - `MAGAZINES_AND_NEWSPAPERS`
521
+ - `UTILITIES`
522
+ - `SHOPPING`
523
+ - `PRODUCTIVITY`
524
+ - `NEWS`
525
+ - `PHOTO_AND_VIDEO`
526
+ - `NAVIGATION`
524
527
 
525
528
  ### Available Game Subcategories
526
529
 
@@ -543,54 +546,40 @@ You can always prefix the category using `MZGenre.` (e.g. `MZGenre.Book`). _deli
543
546
  - `MZGenre.Trivia`
544
547
  - `MZGenre.Word`
545
548
 
546
- ### Available Magazines & Newspapers Subcategories
547
-
548
- - `MZGenre.Apps.Arts_Photography`
549
- - `MZGenre.Apps.Automotive`
550
- - `MZGenre.Apps.Brides_Weddings`
551
- - `MZGenre.Apps.Business_Investing`
552
- - `MZGenre.Apps.Childrens_Magazines`
553
- - `MZGenre.Apps.Computers_Internet`
554
- - `MZGenre.Apps.Cooking_Food_Drink`
555
- - `MZGenre.Apps.Crafts_Hobbies`
556
- - `MZGenre.Apps.Electronics_Audio`
557
- - `MZGenre.Apps.Entertainment`
558
- - `MZGenre.Apps.Fashion_Style`
559
- - `MZGenre.Apps.Health_Mind_Body`
560
- - `MZGenre.Apps.History`
561
- - `MZGenre.Apps.Home_Garden`
562
- - `MZGenre.Apps.Literary_Magazines_Journals`
563
- - `MZGenre.Apps.Mens_Interest`
564
- - `MZGenre.Apps.Movies_Music`
565
- - `MZGenre.Apps.News_Politics`
566
- - `MZGenre.Apps.Outdoors_Nature`
567
- - `MZGenre.Apps.Parenting_Family`
568
- - `MZGenre.Apps.Pets`
569
- - `MZGenre.Apps.Professional_Trade`
570
- - `MZGenre.Apps.Regional_News`
571
- - `MZGenre.Apps.Science`
572
- - `MZGenre.Apps.Sports_Leisure`
573
- - `MZGenre.Apps.Teens`
574
- - `MZGenre.Apps.Travel_Regional`
575
- - `MZGenre.Apps.Womens_Interest`
549
+ - `GAMES_SPORTS`
550
+ - `GAMES_WORD`
551
+ - `GAMES_MUSIC`
552
+ - `GAMES_ADVENTURE`
553
+ - `GAMES_ACTION`
554
+ - `GAMES_ROLE_PLAYING`
555
+ - `GAMES_CASUAL`
556
+ - `GAMES_BOARD`
557
+ - `GAMES_TRIVIA`
558
+ - `GAMES_CARD`
559
+ - `GAMES_PUZZLE`
560
+ - `GAMES_CASINO`
561
+ - `GAMES_STRATEGY`
562
+ - `GAMES_SIMULATION`
563
+ - `GAMES_RACING`
564
+ - `GAMES_FAMILY`
576
565
 
577
566
  ### Available Stickers Subcategories
578
567
 
579
- - `MZGenre.Apps.Stickers.Animals`
580
- - `MZGenre.Apps.Stickers.Art`
581
- - `MZGenre.Apps.Stickers.BirthdaysAndCelebrations`
582
- - `MZGenre.Apps.Stickers.Celebrities`
583
- - `MZGenre.Apps.Stickers.Characters`
584
- - `MZGenre.Apps.Stickers.FoodAndDrink`
585
- - `MZGenre.Apps.Stickers.Emotions`
586
- - `MZGenre.Apps.Stickers.Fashion`
587
- - `MZGenre.Apps.Stickers.Games`
588
- - `MZGenre.Apps.Stickers.KidsAndFamily`
589
- - `MZGenre.Apps.Stickers.MoviesAndTV`
590
- - `MZGenre.Apps.Stickers.Music`
591
- - `MZGenre.Apps.Stickers.People`
592
- - `MZGenre.Apps.Stickers.Places`
593
- - `MZGenre.Apps.Stickers.Sports`
568
+ - `STICKERS_PLACES_AND_OBJECTS`
569
+ - `STICKERS_EMOJI_AND_EXPRESSIONS`
570
+ - `STICKERS_CELEBRATIONS`
571
+ - `STICKERS_CELEBRITIES`
572
+ - `STICKERS_MOVIES_AND_TV`
573
+ - `STICKERS_SPORTS_AND_ACTIVITIES`
574
+ - `STICKERS_EATING_AND_DRINKING`
575
+ - `STICKERS_CHARACTERS`
576
+ - `STICKERS_ANIMALS`
577
+ - `STICKERS_FASHION`
578
+ - `STICKERS_ART`
579
+ - `STICKERS_GAMING`
580
+ - `STICKERS_KIDS_AND_FAMILY`
581
+ - `STICKERS_PEOPLE`
582
+ - `STICKERS_MUSIC`
594
583
 
595
584
  ### Available age rating groups
596
585
 
@@ -602,26 +591,30 @@ You can always prefix the category using `MZGenre.` (e.g. `MZGenre.Book`). _deli
602
591
  - 1: Infrequent/Mild
603
592
  - 2: Frequent/Intense
604
593
 
594
+ - `NONE`
595
+ - `INFREQUENT_OR_MILD`
596
+ - `FREQUENT_OR_INTENSE`
597
+
605
598
  **Keys**
606
599
 
607
- - `CARTOON_FANTASY_VIOLENCE`
608
- - `REALISTIC_VIOLENCE`
609
- - `PROLONGED_GRAPHIC_SADISTIC_REALISTIC_VIOLENCE`
610
- - `PROFANITY_CRUDE_HUMOR`
611
- - `MATURE_SUGGESTIVE`
612
- - `HORROR`
613
- - `MEDICAL_TREATMENT_INFO`
614
- - `ALCOHOL_TOBACCO_DRUGS`
615
- - `GAMBLING`
616
- - `SEXUAL_CONTENT_NUDITY`
617
- - `GRAPHIC_SEXUAL_CONTENT_NUDITY`
600
+ - `violenceCartoonOrFantasy`
601
+ - `violenceRealistic`
602
+ - `violenceRealisticProlongedGraphicOrSadistic`
603
+ - `profanityOrCrudeHumor`
604
+ - `matureOrSuggestiveThemes`
605
+ - `horrorOrFearThemes`
606
+ - `medicalOrTreatmentInformation`
607
+ - `alcoholTobaccoOrDrugUseOrReferences`
608
+ - `gamblingSimulated`
609
+ - `sexualContentOrNudity`
610
+ - `sexualContentGraphicAndNudity`
618
611
 
619
612
  #### Boolean
620
613
 
621
614
  **Keys**
622
615
 
623
- - `UNRESTRICTED_WEB_ACCESS`
624
- - `GAMBLING_CONTESTS`
616
+ - `unrestrictedWebAccess`
617
+ - `gamblingAndContests`
625
618
  </details>
626
619
 
627
620
  <br />
@@ -9,16 +9,18 @@ module Fastlane
9
9
  Spaceship::Tunes.select_team
10
10
  UI.message("Login successful")
11
11
 
12
- app = Spaceship::Application.find(params[:app_identifier]) || Spaceship::Application.find(params[:app_identifier], mac: true)
12
+ app = Spaceship::ConnectAPI::App.find(params[:app_identifier])
13
13
  UI.user_error!("Couldn't find app with identifier #{params[:app_identifier]}") if app.nil?
14
14
 
15
15
  version_number = params[:version]
16
- platform = params[:platform]
16
+ platform = Spaceship::ConnectAPI::Platform.map(params[:platform])
17
+
17
18
  unless version_number
18
19
  # Automatically fetch the latest version
19
20
  UI.message("Fetching the latest version for this app")
20
- if app.edit_version(platform: platform) && app.edit_version(platform: platform).version
21
- version_number = app.edit_version(platform: platform).version
21
+ edit_version = app.get_edit_app_store_version(platform: platform)
22
+ if edit_version
23
+ version_number = edit_version.version_string
22
24
  else
23
25
  UI.message("You have to specify a new version number: ")
24
26
  version_number = STDIN.gets.strip
@@ -42,31 +44,32 @@ module Fastlane
42
44
 
43
45
  UI.important("Going to update the changelog to:\n\n#{changelog}\n\n")
44
46
 
45
- if (v = app.edit_version(platform: platform))
46
- if v.version != version_number
47
+ edit_version = app.get_edit_app_store_version(platform: platform)
48
+ if edit_version
49
+ if edit_version.version_string != version_number
47
50
  # Version is already there, make sure it matches the one we want to create
48
- UI.message("Changing existing version number from '#{v.version}' to '#{version_number}'")
49
- v.version = version_number
50
- v.save!
51
+ UI.message("Changing existing version number from '#{edit_version.version_string}' to '#{version_number}'")
52
+ edit_version = edit_version.update(attributes: {
53
+ versionString: version_number
54
+ })
51
55
  else
52
- UI.message("Updating changelog for existing version #{v.version}")
56
+ UI.message("Updating changelog for existing version #{edit_version.version_string}")
53
57
  end
54
58
  else
55
59
  UI.message("Creating the new version: #{version_number}")
56
- app.create_version!(version_number)
57
- app = Spaceship::Application.find(params[:app_identifier]) # Replace with .reload method once available
58
- v = app.edit_version(platform: platform)
60
+ attributes = { versionString: version_number, platform: platform }
61
+ edit_version = Spaceship::ConnectAPI.post_app_store_version(app_id: app.id, attributes: attributes).first
59
62
  end
60
63
 
61
- v.release_notes.languages.each do |lang|
62
- v.release_notes[lang] = changelog
64
+ localizations = edit_version.get_app_store_version_localizations
65
+ localizations.each do |localization|
66
+ UI.message("Updating changelog for the '#{localization.locale}'")
67
+ localization.update(attributes: {
68
+ whatsNew: changelog
69
+ })
63
70
  end
64
71
 
65
- UI.message("Found and updated changelog for the following languages: #{v.release_notes.languages.join(', ')}")
66
- UI.message("Uploading changes to App Store Connect...")
67
- v.save!
68
-
69
- UI.success("👼 Successfully pushed the new changelog to #{v.url}")
72
+ UI.success("👼 Successfully pushed the new changelog to for #{edit_version.version_string}")
70
73
  end
71
74
 
72
75
  def self.default_changelog_path
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
- VERSION = '2.150.0.rc1'.freeze
2
+ VERSION = '2.150.0.rc6'.freeze
3
3
  DESCRIPTION = "The easiest way to automate beta deployments and releases for your iOS and Android apps".freeze
4
4
  MINIMUM_XCODE_RELEASE = "7.0".freeze
5
5
  RUBOCOP_REQUIREMENT = '0.49.1'.freeze
@@ -6,7 +6,7 @@ module FastlaneCore
6
6
  class BuildWatcher
7
7
  class << self
8
8
  # @return The build we waited for. This method will always return a build
9
- def wait_for_build_processing_to_be_complete(app_id: nil, platform: nil, train_version: nil, app_version: nil, build_version: nil, poll_interval: 10, strict_build_watch: false, return_when_build_appears: false, return_spaceship_testflight_build: true)
9
+ def wait_for_build_processing_to_be_complete(app_id: nil, platform: nil, train_version: nil, app_version: nil, build_version: nil, poll_interval: 10, strict_build_watch: false, return_when_build_appears: false, return_spaceship_testflight_build: true, select_latest: false)
10
10
  # Warn about train_version being removed in the future
11
11
  if train_version
12
12
  UI.deprecated(":train_version is no longer a used argument on FastlaneCore::BuildWatcher. Please use :app_version instead.")
@@ -23,7 +23,7 @@ module FastlaneCore
23
23
 
24
24
  showed_info = false
25
25
  loop do
26
- matched_build = matching_build(watched_app_version: app_version, watched_build_version: build_version, app_id: app_id, platform: platform)
26
+ matched_build = matching_build(watched_app_version: app_version, watched_build_version: build_version, app_id: app_id, platform: platform, select_latest: select_latest)
27
27
 
28
28
  if matched_build.nil? && !showed_info
29
29
  UI.important("Read more information on why this build isn't showing up yet - https://github.com/fastlane/fastlane/issues/14997")
@@ -55,7 +55,7 @@ module FastlaneCore
55
55
  return version.instance_of?(String) ? version.split('.').map { |s| s.to_i.to_s }.join('.') : version
56
56
  end
57
57
 
58
- def matching_build(watched_app_version: nil, watched_build_version: nil, app_id: nil, platform: nil)
58
+ def matching_build(watched_app_version: nil, watched_build_version: nil, app_id: nil, platform: nil, select_latest: false)
59
59
  # Get build deliveries (newly uploaded processing builds)
60
60
  watched_app_version = remove_version_leading_zeros(version: watched_app_version)
61
61
  watched_build_version = remove_version_leading_zeros(version: watched_build_version)
@@ -69,7 +69,7 @@ module FastlaneCore
69
69
 
70
70
  # Raise error if more than 1 build is returned
71
71
  # This should never happen but need to inform the user if it does
72
- if matched_builds.size > 1
72
+ if matched_builds.size > 1 && !select_latest
73
73
  error_builds = matched_builds.map do |build|
74
74
  "#{build.app_version}(#{build.version}) for #{build.platform} - #{build.processing_state}"
75
75
  end.join("\n")