fastlane 2.138.0 → 2.143.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +75 -62
  4. data/cert/lib/cert/options.rb +12 -5
  5. data/cert/lib/cert/runner.rb +13 -0
  6. data/deliver/lib/deliver/options.rb +2 -2
  7. data/deliver/lib/deliver/runner.rb +13 -2
  8. data/deliver/lib/deliver/submit_for_review.rb +7 -1
  9. data/fastlane/lib/fastlane/action.rb +2 -2
  10. data/fastlane/lib/fastlane/actions/.hockey.rb.swp +0 -0
  11. data/fastlane/lib/fastlane/actions/.slack.rb.swp +0 -0
  12. data/fastlane/lib/fastlane/actions/.update_project_provisioning.rb.swp +0 -0
  13. data/fastlane/lib/fastlane/actions/README.md +2 -0
  14. data/fastlane/lib/fastlane/actions/app_store_build_number.rb +13 -5
  15. data/fastlane/lib/fastlane/actions/build_app.rb +157 -6
  16. data/fastlane/lib/fastlane/actions/build_ios_app.rb +28 -132
  17. data/fastlane/lib/fastlane/actions/build_mac_app.rb +46 -0
  18. data/fastlane/lib/fastlane/actions/cocoapods.rb +2 -2
  19. data/fastlane/lib/fastlane/actions/create_pull_request.rb +71 -2
  20. data/fastlane/lib/fastlane/actions/docs/{build_ios_app.md → build_app.md} +1 -1
  21. data/fastlane/lib/fastlane/actions/docs/frame_screenshots.md +22 -6
  22. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +20 -4
  23. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +10 -0
  24. data/fastlane/lib/fastlane/actions/ensure_git_branch.rb +1 -1
  25. data/fastlane/lib/fastlane/actions/ensure_xcode_version.rb +35 -7
  26. data/fastlane/lib/fastlane/actions/frame_screenshots.rb +2 -1
  27. data/fastlane/lib/fastlane/actions/get_github_release.rb +3 -0
  28. data/fastlane/lib/fastlane/actions/gradle.rb +43 -2
  29. data/fastlane/lib/fastlane/actions/gym.rb +3 -7
  30. data/fastlane/lib/fastlane/actions/import_from_git.rb +4 -0
  31. data/fastlane/lib/fastlane/actions/last_git_tag.rb +14 -5
  32. data/fastlane/lib/fastlane/actions/latest_testflight_build_number.rb +9 -3
  33. data/fastlane/lib/fastlane/actions/notarize.rb +183 -0
  34. data/fastlane/lib/fastlane/actions/run_tests.rb +5 -22
  35. data/fastlane/lib/fastlane/actions/s3.rb +5 -291
  36. data/fastlane/lib/fastlane/actions/set_github_release.rb +1 -1
  37. data/fastlane/lib/fastlane/actions/setup_ci.rb +14 -8
  38. data/fastlane/lib/fastlane/actions/spm.rb +8 -0
  39. data/fastlane/lib/fastlane/actions/swiftlint.rb +17 -2
  40. data/fastlane/lib/fastlane/actions/update_plist.rb +37 -2
  41. data/fastlane/lib/fastlane/actions/upload_symbols_to_crashlytics.rb +13 -3
  42. data/fastlane/lib/fastlane/actions/upload_to_app_store.rb +1 -0
  43. data/fastlane/lib/fastlane/actions/upload_to_play_store_internal_app_sharing.rb +78 -0
  44. data/fastlane/lib/fastlane/fast_file.rb +13 -3
  45. data/fastlane/lib/fastlane/helper/adb_helper.rb +1 -1
  46. data/fastlane/lib/fastlane/helper/s3_client_helper.rb +56 -0
  47. data/fastlane/lib/fastlane/plugins/plugin_manager.rb +1 -1
  48. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +2 -0
  49. data/fastlane/lib/fastlane/runner.rb +23 -18
  50. data/fastlane/lib/fastlane/server/socket_server_action_command_executor.rb +1 -1
  51. data/fastlane/lib/fastlane/version.rb +1 -1
  52. data/fastlane/swift/Deliverfile.swift +1 -1
  53. data/fastlane/swift/DeliverfileProtocol.swift +3 -3
  54. data/fastlane/swift/Fastlane.swift +429 -50
  55. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.xcworkspace/xcuserdata/josh.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  56. data/fastlane/swift/Gymfile.swift +1 -1
  57. data/fastlane/swift/GymfileProtocol.swift +17 -1
  58. data/fastlane/swift/Matchfile.swift +1 -1
  59. data/fastlane/swift/MatchfileProtocol.swift +23 -3
  60. data/fastlane/swift/Precheckfile.swift +1 -1
  61. data/fastlane/swift/RubyCommand.swift +1 -1
  62. data/fastlane/swift/Scanfile.swift +1 -1
  63. data/fastlane/swift/ScanfileProtocol.swift +21 -1
  64. data/fastlane/swift/Screengrabfile.swift +1 -1
  65. data/fastlane/swift/Snapshotfile.swift +1 -1
  66. data/fastlane/swift/SnapshotfileProtocol.swift +9 -1
  67. data/fastlane_core/lib/fastlane_core/build_watcher.rb +6 -2
  68. data/fastlane_core/lib/fastlane_core/cert_checker.rb +28 -0
  69. data/fastlane_core/lib/fastlane_core/device_manager.rb +20 -0
  70. data/fastlane_core/lib/fastlane_core/helper.rb +7 -1
  71. data/fastlane_core/lib/fastlane_core/ipa_file_analyser.rb +1 -0
  72. data/fastlane_core/lib/fastlane_core/keychain_importer.rb +2 -0
  73. data/fastlane_core/lib/fastlane_core/project.rb +27 -0
  74. data/frameit/lib/frameit/commands_generator.rb +25 -0
  75. data/frameit/lib/frameit/config_parser.rb +31 -9
  76. data/frameit/lib/frameit/device.rb +90 -0
  77. data/frameit/lib/frameit/device_types.rb +121 -5
  78. data/frameit/lib/frameit/editor.rb +31 -40
  79. data/frameit/lib/frameit/offsets.rb +8 -1
  80. data/frameit/lib/frameit/options.rb +81 -54
  81. data/frameit/lib/frameit/runner.rb +17 -7
  82. data/frameit/lib/frameit/screenshot.rb +35 -47
  83. data/frameit/lib/frameit/template_finder.rb +15 -12
  84. data/gym/lib/gym/code_signing_mapping.rb +32 -3
  85. data/gym/lib/gym/detect_values.rb +34 -2
  86. data/gym/lib/gym/generators/build_command_generator.rb +1 -0
  87. data/gym/lib/gym/generators/package_command_generator.rb +4 -0
  88. data/gym/lib/gym/generators/package_command_generator_xcode7.rb +47 -17
  89. data/gym/lib/gym/module.rb +8 -0
  90. data/gym/lib/gym/options.rb +25 -1
  91. data/gym/lib/gym/runner.rb +64 -24
  92. data/match/lib/match/change_password.rb +1 -1
  93. data/match/lib/match/encryption.rb +4 -0
  94. data/match/lib/match/encryption/openssl.rb +1 -1
  95. data/match/lib/match/generator.rb +17 -3
  96. data/match/lib/match/importer.rb +2 -2
  97. data/match/lib/match/module.rb +5 -2
  98. data/match/lib/match/nuke.rb +59 -17
  99. data/match/lib/match/options.rb +38 -15
  100. data/match/lib/match/runner.rb +24 -8
  101. data/match/lib/match/setup.rb +1 -1
  102. data/match/lib/match/spaceship_ensure.rb +19 -9
  103. data/match/lib/match/storage.rb +4 -0
  104. data/match/lib/match/storage/git_storage.rb +5 -2
  105. data/match/lib/match/storage/google_cloud_storage.rb +2 -2
  106. data/match/lib/match/storage/s3_storage.rb +162 -0
  107. data/pilot/lib/pilot/.manager.rb.swp +0 -0
  108. data/pilot/lib/pilot/build_manager.rb +55 -15
  109. data/pilot/lib/pilot/options.rb +3 -1
  110. data/scan/lib/scan/detect_values.rb +6 -1
  111. data/scan/lib/scan/manager.rb +18 -1
  112. data/scan/lib/scan/options.rb +28 -1
  113. data/scan/lib/scan/runner.rb +11 -3
  114. data/scan/lib/scan/slack_poster.rb +1 -1
  115. data/scan/lib/scan/test_command_generator.rb +9 -5
  116. data/screengrab/lib/screengrab/runner.rb +31 -18
  117. data/snapshot/lib/snapshot/fixes/simulator_shared_pasteboard.rb +16 -0
  118. data/snapshot/lib/snapshot/options.rb +12 -1
  119. data/snapshot/lib/snapshot/simulator_launchers/launcher_configuration.rb +2 -0
  120. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +13 -0
  121. data/spaceship/lib/spaceship/connect_api/.DS_Store +0 -0
  122. data/spaceship/lib/spaceship/connect_api/models/beta_feedback.rb +4 -0
  123. data/spaceship/lib/spaceship/connect_api/models/build.rb +4 -0
  124. data/spaceship/lib/spaceship/connect_api/models/build_beta_detail.rb +5 -0
  125. data/spaceship/lib/spaceship/connect_api/models/certificate.rb +2 -0
  126. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +6 -0
  127. data/spaceship/lib/spaceship/portal/.certificate.rb.swp +0 -0
  128. data/spaceship/lib/spaceship/portal/app.rb +11 -2
  129. data/spaceship/lib/spaceship/tunes/iap.rb +11 -11
  130. data/spaceship/lib/spaceship/tunes/iap_detail.rb +7 -3
  131. data/spaceship/lib/spaceship/tunes/iap_families.rb +12 -1
  132. data/spaceship/lib/spaceship/tunes/iap_family_details.rb +26 -17
  133. data/spaceship/lib/spaceship/tunes/iap_status.rb +5 -1
  134. data/spaceship/lib/spaceship/tunes/tunes_client.rb +2 -2
  135. data/supply/lib/supply/client.rb +26 -0
  136. data/supply/lib/supply/uploader.rb +28 -0
  137. metadata +64 -20
@@ -73,8 +73,11 @@ module Match
73
73
  self.working_directory = Dir.mktmpdir
74
74
 
75
75
  command = "git clone #{self.git_url.shellescape} #{self.working_directory.shellescape}"
76
- command << " -c http.extraheader='AUTHORIZATION: basic #{self.git_basic_authorization}'" unless self.git_basic_authorization.nil?
77
- command << " -c http.extraheader='AUTHORIZATION: bearer #{self.git_bearer_authorization}'" unless self.git_bearer_authorization.nil?
76
+ # HTTP headers are supposed to be be case insensitive but
77
+ # Bitbucket requires `Authorization: Basic` and `Authorization Bearer` to work
78
+ # https://github.com/fastlane/fastlane/pull/15928
79
+ command << " -c http.extraheader='Authorization: Basic #{self.git_basic_authorization}'" unless self.git_basic_authorization.nil?
80
+ command << " -c http.extraheader='Authorization: Bearer #{self.git_bearer_authorization}'" unless self.git_bearer_authorization.nil?
78
81
 
79
82
  if self.shallow_clone
80
83
  command << " --depth 1 --no-single-branch"
@@ -181,7 +181,7 @@ module Match
181
181
  end
182
182
 
183
183
  def generate_matchfile_content
184
- return "bucket_name(\"#{self.bucket_name}\")"
184
+ return "google_cloud_bucket_name(\"#{self.bucket_name}\")"
185
185
  end
186
186
 
187
187
  private
@@ -349,7 +349,7 @@ module Match
349
349
  UI.message("\t\t 1. Click on your bucket to open it".cyan)
350
350
  UI.message("\t\t 2. Click 'Permissions'".cyan)
351
351
  UI.message("\t\t 3. Click 'Add members'".cyan)
352
- UI.message("\t\t 4. Enter the email of your service account".cyan)
352
+ UI.message("\t\t 4. Enter the service account email address".cyan)
353
353
  UI.message("\t\t 5. Set the role to 'Storage Admin'".cyan)
354
354
  UI.message("\t\t 6. Click 'Save'".cyan)
355
355
  UI.message("")
@@ -0,0 +1,162 @@
1
+ require 'fastlane_core/command_executor'
2
+ require 'fastlane_core/configuration/configuration'
3
+ require 'fastlane/helper/s3_client_helper'
4
+
5
+ require_relative '../options'
6
+ require_relative '../module'
7
+ require_relative '../spaceship_ensure'
8
+ require_relative './interface'
9
+
10
+ module Match
11
+ module Storage
12
+ # Store the code signing identities on AWS S3
13
+ class S3Storage < Interface
14
+ attr_reader :s3_bucket
15
+ attr_reader :s3_region
16
+ attr_reader :s3_client
17
+ attr_reader :readonly
18
+ attr_reader :username
19
+ attr_reader :team_id
20
+ attr_reader :team_name
21
+
22
+ def self.configure(params)
23
+ s3_region = params[:s3_region]
24
+ s3_access_key = params[:s3_access_key]
25
+ s3_secret_access_key = params[:s3_secret_access_key]
26
+ s3_bucket = params[:s3_bucket]
27
+
28
+ if params[:git_url].to_s.length > 0
29
+ UI.important("Looks like you still define a `git_url` somewhere, even though")
30
+ UI.important("you use S3 Storage. You can remove the `git_url`")
31
+ UI.important("from your Matchfile and Fastfile")
32
+ UI.message("The above is just a warning, fastlane will continue as usual now...")
33
+ end
34
+
35
+ return self.new(
36
+ s3_region: s3_region,
37
+ s3_access_key: s3_access_key,
38
+ s3_secret_access_key: s3_secret_access_key,
39
+ s3_bucket: s3_bucket,
40
+ readonly: params[:readonly],
41
+ username: params[:username],
42
+ team_id: params[:team_id],
43
+ team_name: params[:team_name]
44
+ )
45
+ end
46
+
47
+ def initialize(s3_region: nil,
48
+ s3_access_key: nil,
49
+ s3_secret_access_key: nil,
50
+ s3_bucket: nil,
51
+ readonly: nil,
52
+ username: nil,
53
+ team_id: nil,
54
+ team_name: nil)
55
+ @s3_bucket = s3_bucket
56
+ @s3_region = s3_region
57
+ @s3_client = Fastlane::Helper::S3ClientHelper.new(access_key: s3_access_key, secret_access_key: s3_secret_access_key, region: s3_region)
58
+ @readonly = readonly
59
+ @username = username
60
+ @team_id = team_id
61
+ @team_name = team_name
62
+ end
63
+
64
+ # To make debugging easier, we have a custom exception here
65
+ def prefixed_working_directory
66
+ # We fall back to "*", which means certificates and profiles
67
+ # from all teams that use this bucket would be installed. This is not ideal, but
68
+ # unless the user provides a `team_id`, we can't know which one to use
69
+ # This only happens if `readonly` is activated, and no `team_id` was provided
70
+ @_folder_prefix ||= currently_used_team_id
71
+ if @_folder_prefix.nil?
72
+ # We use a `@_folder_prefix` variable, to keep state between multiple calls of this
73
+ # method, as the value won't change. This way the warning is only printed once
74
+ UI.important("Looks like you run `match` in `readonly` mode, and didn't provide a `team_id`. This will still work, however it is recommended to provide a `team_id` in your Appfile or Matchfile")
75
+ @_folder_prefix = "*"
76
+ end
77
+ return File.join(working_directory, @_folder_prefix)
78
+ end
79
+
80
+ # Call this method for the initial clone/download of the
81
+ # user's certificates & profiles
82
+ # As part of this method, the `self.working_directory` attribute
83
+ # will be set
84
+ def download
85
+ # Check if we already have a functional working_directory
86
+ return if @working_directory && Dir.exist?(@working_directory)
87
+
88
+ # No existing working directory, creating a new one now
89
+ self.working_directory = Dir.mktmpdir
90
+
91
+ s3_client.find_bucket!(s3_bucket).objects.each do |object|
92
+ file_path = object.public_url.to_s.split("s3.amazonaws.com/").last
93
+ download_path = File.join(self.working_directory, file_path)
94
+
95
+ FileUtils.mkdir_p(File.expand_path("..", download_path))
96
+ UI.verbose("Downloading file from S3 '#{file_path}' on bucket #{self.s3_bucket}")
97
+
98
+ object.download_file(download_path)
99
+ end
100
+ UI.verbose("Successfully downloaded files from S3 to #{self.working_directory}")
101
+ end
102
+
103
+ # Returns a short string describing + identifing the current
104
+ # storage backend. This will be printed when nuking a storage
105
+ def human_readable_description
106
+ return "S3 Bucket [#{s3_bucket}] on region #{s3_region}"
107
+ end
108
+
109
+ def upload_files(files_to_upload: [], custom_message: nil)
110
+ # `files_to_upload` is an array of files that need to be uploaded to S3
111
+ # Those doesn't mean they're new, it might just be they're changed
112
+ # Either way, we'll upload them using the same technique
113
+
114
+ files_to_upload.each do |current_file|
115
+ # Go from
116
+ # "/var/folders/px/bz2kts9n69g8crgv4jpjh6b40000gn/T/d20181026-96528-1av4gge/profiles/development/Development_me.mobileprovision"
117
+ # to
118
+ # "profiles/development/Development_me.mobileprovision"
119
+ #
120
+
121
+ target_path = current_file.gsub(self.working_directory + "/", "")
122
+ UI.verbose("Uploading '#{target_path}' to S3 Storage...")
123
+
124
+ body = File.read(current_file)
125
+ acl = 'private'
126
+ s3_url = s3_client.upload_file(s3_bucket, target_path, body, acl)
127
+ UI.verbose("Uploaded '#{s3_url}' to S3 Storage.")
128
+ end
129
+ end
130
+
131
+ def delete_files(files_to_delete: [], custom_message: nil)
132
+ files_to_delete.each do |file_name|
133
+ s3_client.delete_file(s3_bucket, file_name)
134
+ end
135
+ end
136
+
137
+ def skip_docs
138
+ false
139
+ end
140
+
141
+ # Implement this for the `fastlane match init` command
142
+ # This method must return the content of the Matchfile
143
+ # that should be generated
144
+ def generate_matchfile_content(template: nil)
145
+ return "s3_bucket(\"#{self.s3_bucket}\")"
146
+ end
147
+
148
+ private
149
+
150
+ def currently_used_team_id
151
+ if self.readonly
152
+ # In readonly mode, we still want to see if the user provided a team_id
153
+ # see `prefixed_working_directory` comments for more details
154
+ return self.team_id
155
+ else
156
+ spaceship = SpaceshipEnsure.new(self.username, self.team_id, self.team_name)
157
+ return spaceship.team_id
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
@@ -39,17 +39,25 @@ module Pilot
39
39
 
40
40
  UI.success("Successfully uploaded the new binary to App Store Connect")
41
41
 
42
+ # We will fully skip waiting for build processing *only* if no changelog is supplied
43
+ # Otherwise we may partially wait until the build appears so the changelog can be set, and then bail.
44
+ return_when_build_appears = false
42
45
  if config[:skip_waiting_for_build_processing]
43
- UI.important("Skip waiting for build processing")
44
- UI.important("This means that no changelog will be set and no build will be distributed to testers")
45
- return
46
+ if config[:changelog].nil?
47
+ UI.important("`skip_waiting_for_build_processing` used and no `changelog` supplied - skipping waiting for build processing")
48
+ return
49
+ else
50
+ return_when_build_appears = true
51
+ end
46
52
  end
47
53
 
48
54
  # Calling login again here is needed if login was not called during 'start'
49
55
  login unless should_login_in_start
50
56
 
51
57
  UI.message("If you want to skip waiting for the processing to be finished, use the `skip_waiting_for_build_processing` option")
52
- latest_build = wait_for_build_processing_to_be_complete
58
+ UI.message("Note that if `skip_waiting_for_build_processing` is used but a `changelog` is supplied, this process will wait for the build to appear on AppStoreConnect, update the changelog and then skip the remaining of the processing steps.")
59
+
60
+ latest_build = wait_for_build_processing_to_be_complete(return_when_build_appears)
53
61
  distribute(options, build: latest_build)
54
62
  end
55
63
 
@@ -80,11 +88,20 @@ module Pilot
80
88
  end
81
89
  end
82
90
 
83
- def wait_for_build_processing_to_be_complete
91
+ def wait_for_build_processing_to_be_complete(return_when_build_appears = false)
84
92
  platform = fetch_app_platform
85
93
  app_version = FastlaneCore::IpaFileAnalyser.fetch_app_version(config[:ipa])
86
94
  app_build = FastlaneCore::IpaFileAnalyser.fetch_app_build(config[:ipa])
87
- latest_build = FastlaneCore::BuildWatcher.wait_for_build_processing_to_be_complete(app_id: app.id, platform: platform, app_version: app_version, build_version: app_build, poll_interval: config[:wait_processing_interval], return_spaceship_testflight_build: false)
95
+
96
+ latest_build = FastlaneCore::BuildWatcher.wait_for_build_processing_to_be_complete(
97
+ app_id: app.id,
98
+ platform: platform,
99
+ app_version: app_version,
100
+ build_version: app_build,
101
+ poll_interval: config[:wait_processing_interval],
102
+ return_when_build_appears: return_when_build_appears,
103
+ return_spaceship_testflight_build: false
104
+ )
88
105
 
89
106
  unless latest_build.app_version == app_version && latest_build.version == app_build
90
107
  UI.important("Uploaded app #{app_version} - #{app_build}, but received build #{latest_build.app_version} - #{latest_build.version}.")
@@ -137,6 +154,14 @@ module Pilot
137
154
  UI.success("Deleted beta app review submission for previous build: #{waiting_for_review_build.app_version} - #{waiting_for_review_build.version}")
138
155
  end
139
156
  end
157
+
158
+ if !build.ready_for_internal_testing? && options[:skip_waiting_for_build_processing]
159
+ # Meta can be uploaded for a build still in processing
160
+ # Returning before distribute if skip_waiting_for_build_processing
161
+ # because can't distribute an app that is still processing
162
+ return
163
+ end
164
+
140
165
  distribute_build(build, options)
141
166
  type = options[:distribute_external] ? 'External' : 'Internal'
142
167
  UI.success("Successfully distributed build to #{type} testers 🚀")
@@ -220,12 +245,21 @@ module Pilot
220
245
  end
221
246
 
222
247
  def self.truncate_changelog(changelog)
223
- max_changelog_length = 4000
224
- if changelog && changelog.length > max_changelog_length
225
- original_length = changelog.length
226
- bottom_message = "..."
227
- changelog = "#{changelog[0...max_changelog_length - bottom_message.length]}#{bottom_message}"
228
- UI.important("Changelog has been truncated since it exceeds Apple's #{max_changelog_length} character limit. It currently contains #{original_length} characters.")
248
+ max_changelog_bytes = 4000
249
+ if changelog
250
+ changelog_bytes = changelog.unpack('C*').length
251
+ if changelog_bytes > max_changelog_bytes
252
+ UI.important("Changelog will be truncated since it exceeds Apple's #{max_changelog_bytes}-byte limit. It currently contains #{changelog_bytes} bytes.")
253
+ new_changelog = ''
254
+ new_changelog_bytes = 0
255
+ max_changelog_bytes -= 3 # Will append '...' later.
256
+ changelog.chars.each do |char|
257
+ new_changelog_bytes += char.unpack('C*').length
258
+ break if new_changelog_bytes >= max_changelog_bytes
259
+ new_changelog += char
260
+ end
261
+ changelog = new_changelog + '...'
262
+ end
229
263
  end
230
264
  changelog
231
265
  end
@@ -447,12 +481,18 @@ module Pilot
447
481
  end
448
482
 
449
483
  def update_build_beta_details(build, info)
450
- build_beta_detail = build.build_beta_detail
451
-
452
484
  attributes = {}
453
485
  attributes[:autoNotifyEnabled] = info[:auto_notify_enabled] if info.key?(:auto_notify_enabled)
486
+ build_beta_detail = build.build_beta_detail
454
487
 
455
- Spaceship::ConnectAPI.patch_build_beta_details(build_beta_details_id: build_beta_detail.id, attributes: attributes)
488
+ # https://github.com/fastlane/fastlane/pull/16006
489
+ if build_beta_detail
490
+ Spaceship::ConnectAPI.patch_build_beta_details(build_beta_details_id: build_beta_detail.id, attributes: attributes)
491
+ else
492
+ if attributes[:autoNotifyEnabled]
493
+ UI.important("Unable to auto notify testers as the build did not include beta detail information - this is likely a temporary issue on TestFlight.")
494
+ end
495
+ end
456
496
  end
457
497
  end
458
498
  # rubocop:enable Metrics/ClassLength
@@ -132,7 +132,9 @@ module Pilot
132
132
  FastlaneCore::ConfigItem.new(key: :skip_waiting_for_build_processing,
133
133
  short_option: "-z",
134
134
  env_name: "PILOT_SKIP_WAITING_FOR_BUILD_PROCESSING",
135
- description: "Don't wait for the build to process. If set to true, the changelog won't be set, `distribute_external` option won't work and no build will be distributed to testers. (You might want to use this option if you are using this action on CI and have to pay for 'minutes used' on your CI plan)",
135
+ description: "If set to true, the `distribute_external` option won't work and no build will be distributed to testers. " \
136
+ "(You might want to use this option if you are using this action on CI and have to pay for 'minutes used' on your CI plan). " \
137
+ "If set to `true` and a changelog is provided, it will partially wait for the build to appear on AppStore Connect so the changelog can be set, and skip the remaining processing steps",
136
138
  is_string: false,
137
139
  default_value: false),
138
140
  FastlaneCore::ConfigItem.new(key: :update_build_info_on_upload,
@@ -108,7 +108,7 @@ module Scan
108
108
  def self.detect_simulator(devices, requested_os_type, deployment_target_key, default_device_name, simulator_type_descriptor)
109
109
  require 'set'
110
110
 
111
- deployment_target_version = Scan.project.build_settings(key: deployment_target_key) || '0'
111
+ deployment_target_version = get_deployment_target_version(deployment_target_key)
112
112
 
113
113
  simulators = filter_simulators(
114
114
  FastlaneCore::DeviceManager.simulators(requested_os_type).tap do |array|
@@ -215,5 +215,10 @@ module Scan
215
215
  Scan.config[:destination] = min_xcode8? ? ["platform=macOS"] : ["platform=OS X"]
216
216
  end
217
217
  end
218
+
219
+ # get deployment target version
220
+ def self.get_deployment_target_version(deployment_target_key)
221
+ Scan.config[:deployment_target_version] || Scan.project.build_settings(key: deployment_target_key) || '0'
222
+ end
218
223
  end
219
224
  end
@@ -4,8 +4,13 @@ require_relative 'runner'
4
4
 
5
5
  module Scan
6
6
  class Manager
7
+ attr_accessor :plist_files_before
8
+
7
9
  def work(options)
8
- Scan.config = options
10
+ Scan.config = options # we set this here to auto-detect missing values, which we need later on
11
+ unless options[:derived_data_path].to_s.empty?
12
+ self.plist_files_before = test_summary_filenames(Scan.config[:derived_data_path])
13
+ end
9
14
 
10
15
  # Also print out the path to the used Xcode installation
11
16
  # We go 2 folders up, to not show "Contents/Developer/"
@@ -17,5 +22,17 @@ module Scan
17
22
 
18
23
  return Runner.new.run
19
24
  end
25
+
26
+ def test_summary_filenames(derived_data_path)
27
+ files = []
28
+
29
+ # Xcode < 10
30
+ files += Dir["#{derived_data_path}/**/Logs/Test/*TestSummaries.plist"]
31
+
32
+ # Xcode 10
33
+ files += Dir["#{derived_data_path}/**/Logs/Test/*.xcresult/TestSummaries.plist"]
34
+
35
+ return files
36
+ end
20
37
  end
21
38
  end
@@ -81,6 +81,11 @@ module Scan
81
81
  description: "Enabling this option will automatically erase the simulator before running the application",
82
82
  default_value: false,
83
83
  type: Boolean),
84
+ FastlaneCore::ConfigItem.new(key: :disable_slide_to_type,
85
+ env_name: 'SCAN_DISABLE_SLIDE_TO_TYPE',
86
+ description: "Enabling this option will disable the simulator from showing the 'Slide to type' prompt",
87
+ default_value: true,
88
+ type: Boolean),
84
89
  FastlaneCore::ConfigItem.new(key: :prelaunch_simulator,
85
90
  env_name: 'SCAN_PRELAUNCH_SIMULATOR',
86
91
  description: "Enabling this option will launch the first simulator prior to calling any xcodebuild command",
@@ -249,6 +254,11 @@ module Scan
249
254
  default_value: false),
250
255
 
251
256
  # concurrency
257
+ FastlaneCore::ConfigItem.new(key: :concurrent_workers,
258
+ type: Integer,
259
+ env_name: "SCAN_CONCURRENT_WORKERS",
260
+ description: "Specify the exact number of test runners that will be spawned during parallel testing. Equivalent to -parallel-testing-worker-count",
261
+ optional: true),
252
262
  FastlaneCore::ConfigItem.new(key: :max_concurrent_simulators,
253
263
  type: Integer,
254
264
  env_name: "SCAN_MAX_CONCURRENT_SIMULATORS",
@@ -311,6 +321,18 @@ module Scan
311
321
  UI.user_error!("File not found at path '#{File.expand_path(value)}'") unless File.exist?(value)
312
322
  end),
313
323
 
324
+ # build settings
325
+ FastlaneCore::ConfigItem.new(key: :app_name,
326
+ env_name: "SCAN_APP_NAME",
327
+ optional: true,
328
+ description: "App name to use in slack message and logfile name",
329
+ is_string: true),
330
+ FastlaneCore::ConfigItem.new(key: :deployment_target_version,
331
+ env_name: "SCAN_DEPLOYMENT_TARGET_VERSION",
332
+ optional: true,
333
+ description: "Target version of the app being build or tested. Used to filter out simulator version",
334
+ is_string: true),
335
+
314
336
  # slack
315
337
  FastlaneCore::ConfigItem.new(key: :slack_url,
316
338
  short_option: "-i",
@@ -381,7 +403,12 @@ module Scan
381
403
  description: "Allows for override of the default `xcodebuild` command",
382
404
  type: String,
383
405
  optional: true,
384
- default_value: "env NSUnbufferedIO=YES xcodebuild")
406
+ default_value: "env NSUnbufferedIO=YES xcodebuild"),
407
+ FastlaneCore::ConfigItem.new(key: :cloned_source_packages_path,
408
+ env_name: "SCAN_CLONED_SOURCE_PACKAGES_PATH",
409
+ description: "Sets a custom path for Swift Package Manager dependencies",
410
+ type: String,
411
+ optional: true)
385
412
 
386
413
  ]
387
414
  end
@@ -25,9 +25,17 @@ module Scan
25
25
  def test_app
26
26
  force_quit_simulator_processes if Scan.config[:force_quit_simulator]
27
27
 
28
- if Scan.config[:reset_simulator]
29
- Scan.devices.each do |device|
30
- FastlaneCore::Simulator.reset(udid: device.udid)
28
+ if Scan.devices
29
+ if Scan.config[:reset_simulator]
30
+ Scan.devices.each do |device|
31
+ FastlaneCore::Simulator.reset(udid: device.udid)
32
+ end
33
+ end
34
+
35
+ if Scan.config[:disable_slide_to_type]
36
+ Scan.devices.each do |device|
37
+ FastlaneCore::Simulator.disable_slide_to_type(udid: device.udid)
38
+ end
31
39
  end
32
40
  end
33
41