fastlane 2.139.0 → 2.144.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +85 -72
  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 +28 -2
  7. data/deliver/lib/deliver/runner.rb +13 -2
  8. data/fastlane/lib/fastlane/action.rb +1 -1
  9. data/fastlane/lib/fastlane/actions/.hockey.rb.swp +0 -0
  10. data/fastlane/lib/fastlane/actions/.slack.rb.swp +0 -0
  11. data/fastlane/lib/fastlane/actions/.update_project_provisioning.rb.swp +0 -0
  12. data/fastlane/lib/fastlane/actions/README.md +2 -0
  13. data/fastlane/lib/fastlane/actions/app_store_build_number.rb +13 -5
  14. data/fastlane/lib/fastlane/actions/automatic_code_signing.rb +7 -1
  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/clean_build_artifacts.rb +3 -0
  19. data/fastlane/lib/fastlane/actions/cocoapods.rb +2 -2
  20. data/fastlane/lib/fastlane/actions/crashlytics.rb +14 -2
  21. data/fastlane/lib/fastlane/actions/create_pull_request.rb +29 -0
  22. data/fastlane/lib/fastlane/actions/docs/{build_ios_app.md → build_app.md} +1 -1
  23. data/fastlane/lib/fastlane/actions/docs/frame_screenshots.md +22 -6
  24. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +22 -6
  25. data/fastlane/lib/fastlane/actions/ensure_git_branch.rb +1 -1
  26. data/fastlane/lib/fastlane/actions/ensure_xcode_version.rb +35 -7
  27. data/fastlane/lib/fastlane/actions/frame_screenshots.rb +2 -1
  28. data/fastlane/lib/fastlane/actions/get_github_release.rb +3 -0
  29. data/fastlane/lib/fastlane/actions/gradle.rb +43 -2
  30. data/fastlane/lib/fastlane/actions/gym.rb +3 -7
  31. data/fastlane/lib/fastlane/actions/import_from_git.rb +4 -0
  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/pod_lib_lint.rb +7 -1
  35. data/fastlane/lib/fastlane/actions/run_tests.rb +5 -22
  36. data/fastlane/lib/fastlane/actions/s3.rb +5 -291
  37. data/fastlane/lib/fastlane/actions/set_github_release.rb +1 -1
  38. data/fastlane/lib/fastlane/actions/spm.rb +8 -0
  39. data/fastlane/lib/fastlane/actions/swiftlint.rb +45 -9
  40. data/fastlane/lib/fastlane/actions/update_code_signing_settings.rb +190 -0
  41. data/fastlane/lib/fastlane/actions/update_plist.rb +37 -2
  42. data/fastlane/lib/fastlane/actions/upload_symbols_to_crashlytics.rb +13 -3
  43. data/fastlane/lib/fastlane/actions/upload_to_app_store.rb +1 -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 +422 -45
  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/cert_checker.rb +28 -0
  68. data/fastlane_core/lib/fastlane_core/device_manager.rb +1 -1
  69. data/fastlane_core/lib/fastlane_core/ipa_file_analyser.rb +1 -0
  70. data/fastlane_core/lib/fastlane_core/keychain_importer.rb +2 -0
  71. data/fastlane_core/lib/fastlane_core/project.rb +27 -0
  72. data/fastlane_core/lib/fastlane_core/provisioning_profile.rb +15 -2
  73. data/frameit/lib/frameit/commands_generator.rb +25 -0
  74. data/frameit/lib/frameit/config_parser.rb +31 -9
  75. data/frameit/lib/frameit/device.rb +90 -0
  76. data/frameit/lib/frameit/device_types.rb +121 -5
  77. data/frameit/lib/frameit/editor.rb +28 -40
  78. data/frameit/lib/frameit/offsets.rb +8 -1
  79. data/frameit/lib/frameit/options.rb +81 -54
  80. data/frameit/lib/frameit/runner.rb +17 -7
  81. data/frameit/lib/frameit/screenshot.rb +35 -47
  82. data/frameit/lib/frameit/template_finder.rb +15 -12
  83. data/gym/lib/gym/code_signing_mapping.rb +32 -3
  84. data/gym/lib/gym/detect_values.rb +34 -2
  85. data/gym/lib/gym/generators/package_command_generator.rb +8 -0
  86. data/gym/lib/gym/generators/package_command_generator_xcode7.rb +52 -17
  87. data/gym/lib/gym/module.rb +8 -0
  88. data/gym/lib/gym/options.rb +25 -1
  89. data/gym/lib/gym/runner.rb +70 -21
  90. data/match/lib/match/change_password.rb +1 -1
  91. data/match/lib/match/encryption.rb +4 -0
  92. data/match/lib/match/encryption/openssl.rb +1 -1
  93. data/match/lib/match/generator.rb +17 -3
  94. data/match/lib/match/importer.rb +35 -20
  95. data/match/lib/match/module.rb +5 -2
  96. data/match/lib/match/nuke.rb +59 -17
  97. data/match/lib/match/options.rb +38 -15
  98. data/match/lib/match/runner.rb +24 -8
  99. data/match/lib/match/setup.rb +1 -1
  100. data/match/lib/match/spaceship_ensure.rb +19 -9
  101. data/match/lib/match/storage.rb +4 -0
  102. data/match/lib/match/storage/git_storage.rb +5 -2
  103. data/match/lib/match/storage/google_cloud_storage.rb +2 -2
  104. data/match/lib/match/storage/s3_storage.rb +162 -0
  105. data/pilot/lib/pilot/.manager.rb.swp +0 -0
  106. data/pilot/lib/pilot/build_manager.rb +24 -9
  107. data/scan/lib/scan/detect_values.rb +6 -1
  108. data/scan/lib/scan/manager.rb +18 -1
  109. data/scan/lib/scan/options.rb +28 -1
  110. data/scan/lib/scan/runner.rb +9 -7
  111. data/scan/lib/scan/slack_poster.rb +1 -1
  112. data/scan/lib/scan/test_command_generator.rb +12 -5
  113. data/screengrab/lib/screengrab/runner.rb +31 -18
  114. data/sigh/lib/sigh/.runner.rb.swp +0 -0
  115. data/snapshot/lib/snapshot/fixes/simulator_shared_pasteboard.rb +16 -0
  116. data/snapshot/lib/snapshot/options.rb +12 -1
  117. data/snapshot/lib/snapshot/simulator_launchers/launcher_configuration.rb +2 -0
  118. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +13 -0
  119. data/spaceship/lib/spaceship/connect_api/.DS_Store +0 -0
  120. data/spaceship/lib/spaceship/connect_api/models/.bundle_id.rb.swp +0 -0
  121. data/{gym/lib/gym/.runner.rb.swp → spaceship/lib/spaceship/connect_api/models/.bundle_id_capability.rb.swp} +0 -0
  122. data/spaceship/lib/spaceship/connect_api/models/app.rb +11 -0
  123. data/spaceship/lib/spaceship/connect_api/models/beta_feedback.rb +4 -0
  124. data/spaceship/lib/spaceship/connect_api/models/build.rb +1 -2
  125. data/spaceship/lib/spaceship/connect_api/models/certificate.rb +2 -0
  126. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +29 -0
  127. data/spaceship/lib/spaceship/portal/app.rb +11 -2
  128. data/spaceship/lib/spaceship/tunes/app_version.rb +6 -1
  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 +1 -1
  136. metadata +63 -18
@@ -34,7 +34,7 @@ module Match
34
34
  end
35
35
 
36
36
  def storage_options
37
- return ["git", "google_cloud"]
37
+ return ["git", "google_cloud", "s3"]
38
38
  end
39
39
  end
40
40
  end
@@ -28,8 +28,8 @@ module Match
28
28
  return Spaceship.client.team_id
29
29
  end
30
30
 
31
- def bundle_identifier_exists(username: nil, app_identifier: nil)
32
- found = Spaceship.app.find(app_identifier)
31
+ def bundle_identifier_exists(username: nil, app_identifier: nil, platform: nil)
32
+ found = Spaceship.app.find(app_identifier, mac: platform == "macos")
33
33
  return if found
34
34
 
35
35
  require 'sigh/runner'
@@ -45,24 +45,34 @@ module Match
45
45
  UI.user_error!("Couldn't find bundle identifier '#{app_identifier}' for the user '#{username}'")
46
46
  end
47
47
 
48
- def certificate_exists(username: nil, certificate_id: nil)
49
- found = Spaceship.certificate.all.find do |cert|
50
- cert.id == certificate_id
48
+ def certificates_exists(username: nil, certificate_ids: [], platform: nil)
49
+ Spaceship.certificate.all(mac: platform == "macos").each do |cert|
50
+ certificate_ids.delete(cert.id)
51
51
  end
52
- return if found
52
+ return if certificate_ids.empty?
53
53
 
54
- UI.error("Certificate '#{certificate_id}' (stored in your storage) is not available on the Developer Portal")
54
+ certificate_ids.each do |certificate_id|
55
+ UI.error("Certificate '#{certificate_id}' (stored in your storage) is not available on the Developer Portal")
56
+ end
55
57
  UI.error("for the user #{username}")
56
58
  UI.error("Make sure to use the same user and team every time you run 'match' for this")
57
59
  UI.error("Git repository. This might be caused by revoking the certificate on the Dev Portal")
58
60
  UI.user_error!("To reset the certificates of your Apple account, you can use the `fastlane match nuke` feature, more information on https://docs.fastlane.tools/actions/match/")
59
61
  end
60
62
 
61
- def profile_exists(username: nil, uuid: nil)
62
- found = Spaceship.provisioning_profile.all.find do |profile|
63
+ def profile_exists(username: nil, uuid: nil, platform: nil)
64
+ is_mac = platform == "macos"
65
+ found = Spaceship.provisioning_profile.all(mac: is_mac).find do |profile|
63
66
  profile.uuid == uuid
64
67
  end
65
68
 
69
+ # Look for iOS after looking for macOS (needed for Catalyst apps)
70
+ if !found && is_mac
71
+ found = Spaceship.provisioning_profile.all(mac: false).find do |profile|
72
+ profile.uuid == uuid
73
+ end
74
+ end
75
+
66
76
  unless found
67
77
  UI.error("Provisioning profile '#{uuid}' is not available on the Developer Portal for the user #{username}, fixing this now for you 🔨")
68
78
  return false
@@ -1,6 +1,7 @@
1
1
  require_relative 'storage/interface'
2
2
  require_relative 'storage/git_storage'
3
3
  require_relative 'storage/google_cloud_storage'
4
+ require_relative 'storage/s3_storage'
4
5
 
5
6
  module Match
6
7
  module Storage
@@ -12,6 +13,9 @@ module Match
12
13
  },
13
14
  "google_cloud" => lambda { |params|
14
15
  return Storage::GoogleCloudStorage.configure(params)
16
+ },
17
+ "s3" => lambda { |params|
18
+ return Storage::S3Storage.configure(params)
15
19
  }
16
20
  }
17
21
  end
@@ -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
@@ -245,12 +245,21 @@ module Pilot
245
245
  end
246
246
 
247
247
  def self.truncate_changelog(changelog)
248
- max_changelog_length = 4000
249
- if changelog && changelog.length > max_changelog_length
250
- original_length = changelog.length
251
- bottom_message = "..."
252
- changelog = "#{changelog[0...max_changelog_length - bottom_message.length]}#{bottom_message}"
253
- 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
254
263
  end
255
264
  changelog
256
265
  end
@@ -472,12 +481,18 @@ module Pilot
472
481
  end
473
482
 
474
483
  def update_build_beta_details(build, info)
475
- build_beta_detail = build.build_beta_detail
476
-
477
484
  attributes = {}
478
485
  attributes[:autoNotifyEnabled] = info[:auto_notify_enabled] if info.key?(:auto_notify_enabled)
486
+ build_beta_detail = build.build_beta_detail
479
487
 
480
- 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
481
496
  end
482
497
  end
483
498
  # rubocop:enable Metrics/ClassLength
@@ -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
@@ -124,6 +124,11 @@ module Scan
124
124
  end),
125
125
 
126
126
  # other test options
127
+ FastlaneCore::ConfigItem.new(key: :testplan,
128
+ env_name: "SCAN_TESTPLAN",
129
+ description: "The testplan associated with the scheme that should be used for testing",
130
+ is_string: true,
131
+ optional: true),
127
132
  FastlaneCore::ConfigItem.new(key: :xctestrun,
128
133
  short_option: "-X",
129
134
  env_name: "SCAN_XCTESTRUN",
@@ -254,6 +259,11 @@ module Scan
254
259
  default_value: false),
255
260
 
256
261
  # concurrency
262
+ FastlaneCore::ConfigItem.new(key: :concurrent_workers,
263
+ type: Integer,
264
+ env_name: "SCAN_CONCURRENT_WORKERS",
265
+ description: "Specify the exact number of test runners that will be spawned during parallel testing. Equivalent to -parallel-testing-worker-count",
266
+ optional: true),
257
267
  FastlaneCore::ConfigItem.new(key: :max_concurrent_simulators,
258
268
  type: Integer,
259
269
  env_name: "SCAN_MAX_CONCURRENT_SIMULATORS",
@@ -316,6 +326,18 @@ module Scan
316
326
  UI.user_error!("File not found at path '#{File.expand_path(value)}'") unless File.exist?(value)
317
327
  end),
318
328
 
329
+ # build settings
330
+ FastlaneCore::ConfigItem.new(key: :app_name,
331
+ env_name: "SCAN_APP_NAME",
332
+ optional: true,
333
+ description: "App name to use in slack message and logfile name",
334
+ is_string: true),
335
+ FastlaneCore::ConfigItem.new(key: :deployment_target_version,
336
+ env_name: "SCAN_DEPLOYMENT_TARGET_VERSION",
337
+ optional: true,
338
+ description: "Target version of the app being build or tested. Used to filter out simulator version",
339
+ is_string: true),
340
+
319
341
  # slack
320
342
  FastlaneCore::ConfigItem.new(key: :slack_url,
321
343
  short_option: "-i",
@@ -386,7 +408,12 @@ module Scan
386
408
  description: "Allows for override of the default `xcodebuild` command",
387
409
  type: String,
388
410
  optional: true,
389
- default_value: "env NSUnbufferedIO=YES xcodebuild")
411
+ default_value: "env NSUnbufferedIO=YES xcodebuild"),
412
+ FastlaneCore::ConfigItem.new(key: :cloned_source_packages_path,
413
+ env_name: "SCAN_CLONED_SOURCE_PACKAGES_PATH",
414
+ description: "Sets a custom path for Swift Package Manager dependencies",
415
+ type: String,
416
+ optional: true)
390
417
 
391
418
  ]
392
419
  end
@@ -25,15 +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
31
33
  end
32
- end
33
34
 
34
- if Scan.config[:disable_slide_to_type]
35
- Scan.devices.each do |device|
36
- FastlaneCore::Simulator.disable_slide_to_type(udid: device.udid)
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
37
39
  end
38
40
  end
39
41