fastlane 2.136.0 → 2.141.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +85 -72
  3. data/cert/lib/cert/options.rb +12 -5
  4. data/cert/lib/cert/runner.rb +13 -0
  5. data/deliver/lib/deliver/options.rb +2 -2
  6. data/deliver/lib/deliver/runner.rb +13 -2
  7. data/deliver/lib/deliver/submit_for_review.rb +7 -1
  8. data/fastlane/lib/fastlane/action.rb +2 -2
  9. data/fastlane/lib/fastlane/actions/app_store_build_number.rb +1 -1
  10. data/fastlane/lib/fastlane/actions/build_app.rb +157 -6
  11. data/fastlane/lib/fastlane/actions/build_ios_app.rb +28 -132
  12. data/fastlane/lib/fastlane/actions/build_mac_app.rb +46 -0
  13. data/fastlane/lib/fastlane/actions/create_pull_request.rb +71 -2
  14. data/fastlane/lib/fastlane/actions/docs/{build_ios_app.md → build_app.md} +1 -1
  15. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +19 -0
  16. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +10 -0
  17. data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +4 -2
  18. data/fastlane/lib/fastlane/actions/ensure_bundle_exec.rb +3 -3
  19. data/fastlane/lib/fastlane/actions/get_version_number.rb +7 -2
  20. data/fastlane/lib/fastlane/actions/gradle.rb +54 -3
  21. data/fastlane/lib/fastlane/actions/gym.rb +3 -7
  22. data/fastlane/lib/fastlane/actions/import_from_git.rb +4 -0
  23. data/fastlane/lib/fastlane/actions/increment_version_number.rb +6 -3
  24. data/fastlane/lib/fastlane/actions/last_git_tag.rb +14 -5
  25. data/fastlane/lib/fastlane/actions/latest_testflight_build_number.rb +2 -2
  26. data/fastlane/lib/fastlane/actions/register_devices.rb +5 -1
  27. data/fastlane/lib/fastlane/actions/ruby_version.rb +1 -1
  28. data/fastlane/lib/fastlane/actions/run_tests.rb +5 -22
  29. data/fastlane/lib/fastlane/actions/set_github_release.rb +1 -1
  30. data/fastlane/lib/fastlane/actions/setup_ci.rb +14 -8
  31. data/fastlane/lib/fastlane/actions/testfairy.rb +8 -1
  32. data/fastlane/lib/fastlane/actions/update_plist.rb +37 -2
  33. data/fastlane/lib/fastlane/actions/upload_to_app_store.rb +1 -0
  34. data/fastlane/lib/fastlane/actions/upload_to_play_store_internal_app_sharing.rb +78 -0
  35. data/fastlane/lib/fastlane/actions/verify_build.rb +1 -1
  36. data/fastlane/lib/fastlane/actions/xcode_select.rb +6 -1
  37. data/fastlane/lib/fastlane/cli_tools_distributor.rb +2 -2
  38. data/fastlane/lib/fastlane/commands_generator.rb +1 -1
  39. data/fastlane/lib/fastlane/fast_file.rb +13 -3
  40. data/fastlane/lib/fastlane/helper/adb_helper.rb +13 -4
  41. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +2 -0
  42. data/fastlane/lib/fastlane/runner.rb +23 -18
  43. data/fastlane/lib/fastlane/version.rb +1 -1
  44. data/fastlane/swift/Deliverfile.swift +1 -1
  45. data/fastlane/swift/DeliverfileProtocol.swift +3 -3
  46. data/fastlane/swift/Fastlane.swift +342 -66
  47. data/fastlane/swift/Gymfile.swift +1 -1
  48. data/fastlane/swift/GymfileProtocol.swift +17 -1
  49. data/fastlane/swift/Matchfile.swift +1 -1
  50. data/fastlane/swift/MatchfileProtocol.swift +12 -4
  51. data/fastlane/swift/Precheckfile.swift +1 -1
  52. data/fastlane/swift/Scanfile.swift +1 -1
  53. data/fastlane/swift/ScanfileProtocol.swift +17 -1
  54. data/fastlane/swift/Screengrabfile.swift +1 -1
  55. data/fastlane/swift/ScreengrabfileProtocol.swift +1 -9
  56. data/fastlane/swift/Snapshotfile.swift +1 -1
  57. data/fastlane/swift/SnapshotfileProtocol.swift +9 -1
  58. data/fastlane_core/lib/fastlane_core/build_watcher.rb +6 -2
  59. data/fastlane_core/lib/fastlane_core/cert_checker.rb +28 -0
  60. data/fastlane_core/lib/fastlane_core/device_manager.rb +20 -0
  61. data/fastlane_core/lib/fastlane_core/helper.rb +7 -1
  62. data/fastlane_core/lib/fastlane_core/project.rb +23 -0
  63. data/frameit/lib/frameit/editor.rb +3 -0
  64. data/gym/lib/gym/code_signing_mapping.rb +32 -3
  65. data/gym/lib/gym/detect_values.rb +34 -2
  66. data/gym/lib/gym/generators/build_command_generator.rb +1 -0
  67. data/gym/lib/gym/generators/package_command_generator.rb +4 -0
  68. data/gym/lib/gym/generators/package_command_generator_xcode7.rb +47 -17
  69. data/gym/lib/gym/module.rb +8 -0
  70. data/gym/lib/gym/options.rb +25 -1
  71. data/gym/lib/gym/runner.rb +63 -23
  72. data/match/lib/match/encryption/openssl.rb +1 -1
  73. data/match/lib/match/generator.rb +17 -3
  74. data/match/lib/match/module.rb +4 -1
  75. data/match/lib/match/nuke.rb +54 -16
  76. data/match/lib/match/options.rb +28 -15
  77. data/match/lib/match/runner.rb +21 -8
  78. data/match/lib/match/spaceship_ensure.rb +19 -9
  79. data/match/lib/match/storage/git_storage.rb +11 -3
  80. data/pilot/lib/pilot/build_manager.rb +46 -12
  81. data/pilot/lib/pilot/options.rb +3 -1
  82. data/scan/lib/scan/detect_values.rb +6 -1
  83. data/scan/lib/scan/manager.rb +18 -1
  84. data/scan/lib/scan/options.rb +23 -1
  85. data/scan/lib/scan/runner.rb +6 -0
  86. data/scan/lib/scan/slack_poster.rb +1 -1
  87. data/scan/lib/scan/test_command_generator.rb +1 -1
  88. data/screengrab/lib/screengrab/options.rb +1 -10
  89. data/screengrab/lib/screengrab/runner.rb +16 -19
  90. data/snapshot/lib/snapshot/options.rb +12 -1
  91. data/snapshot/lib/snapshot/simulator_launchers/launcher_configuration.rb +2 -0
  92. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +11 -0
  93. data/spaceship/lib/spaceship/client.rb +9 -4
  94. data/spaceship/lib/spaceship/connect_api.rb +2 -0
  95. data/spaceship/lib/spaceship/connect_api/models/app.rb +11 -0
  96. data/spaceship/lib/spaceship/connect_api/models/beta_feedback.rb +75 -0
  97. data/spaceship/lib/spaceship/connect_api/models/beta_screenshot.rb +18 -0
  98. data/spaceship/lib/spaceship/connect_api/models/build.rb +5 -0
  99. data/spaceship/lib/spaceship/connect_api/models/build_beta_detail.rb +5 -0
  100. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +15 -0
  101. data/spaceship/lib/spaceship/portal/app.rb +11 -2
  102. data/spaceship/lib/spaceship/tunes/iap.rb +11 -11
  103. data/spaceship/lib/spaceship/tunes/iap_detail.rb +7 -3
  104. data/spaceship/lib/spaceship/tunes/iap_families.rb +12 -1
  105. data/spaceship/lib/spaceship/tunes/iap_family_details.rb +26 -17
  106. data/spaceship/lib/spaceship/tunes/iap_status.rb +5 -1
  107. data/spaceship/lib/spaceship/tunes/tunes_client.rb +4 -7
  108. data/supply/lib/supply/client.rb +27 -0
  109. data/supply/lib/supply/options.rb +8 -2
  110. data/supply/lib/supply/uploader.rb +55 -26
  111. metadata +44 -25
  112. data/supply/lib/supply/.uploader.rb.swp +0 -0
@@ -9,7 +9,7 @@ module Match
9
9
  DESCRIPTION = "Easily sync your certificates and profiles across your team"
10
10
 
11
11
  def self.environments
12
- return %w(appstore adhoc development enterprise)
12
+ return %w(appstore adhoc development enterprise developer_id)
13
13
  end
14
14
 
15
15
  def self.storage_modes
@@ -21,6 +21,9 @@ module Match
21
21
  end
22
22
 
23
23
  def self.cert_type_sym(type)
24
+ return :mac_installer_distribution if type == "mac_installer_distribution"
25
+ return :developer_id_installer if type == "developer_id_installer"
26
+ return :developer_id_application if type == "developer_id"
24
27
  return :enterprise if type == "enterprise"
25
28
  return :development if type == "development"
26
29
  return :distribution if ["adhoc", "appstore", "distribution"].include?(type)
@@ -93,10 +93,11 @@ module Match
93
93
  def prepare_list
94
94
  UI.message("Fetching certificates and profiles...")
95
95
  cert_type = Match.cert_type_sym(type)
96
+ cert_types = [cert_type]
96
97
 
97
98
  prov_types = []
98
99
  prov_types = [:development] if cert_type == :development
99
- prov_types = [:appstore, :adhoc] if cert_type == :distribution
100
+ prov_types = [:appstore, :adhoc, :developer_id] if cert_type == :distribution
100
101
  prov_types = [:enterprise] if cert_type == :enterprise
101
102
 
102
103
  Spaceship.login(params[:username])
@@ -112,17 +113,39 @@ module Match
112
113
  UI.user_error!("Enterprise account nuke cancelled") unless UI.confirm("Do you really want to nuke your Enterprise account?")
113
114
  end
114
115
 
115
- self.certs = certificate_type(cert_type).flat_map(&:all)
116
+ # Get all iOS and macOS profile
116
117
  self.profiles = []
117
118
  prov_types.each do |prov_type|
118
- self.profiles += profile_type(prov_type).all
119
+ self.profiles += profile_type(prov_type).all(mac: false)
120
+ self.profiles += profile_type(prov_type).all(mac: true)
119
121
  end
120
122
 
121
- certs = Dir[File.join(self.storage.working_directory, "**", cert_type.to_s, "*.cer")]
122
- keys = Dir[File.join(self.storage.working_directory, "**", cert_type.to_s, "*.p12")]
123
+ # Gets the main and additional cert types
124
+ cert_types += (params[:additional_cert_types] || []).map do |ct|
125
+ Match.cert_type_sym(ct)
126
+ end
127
+
128
+ # Gets all the certs form the cert types
129
+ self.certs = []
130
+ self.certs += cert_types.map do |ct|
131
+ certificate_type(ct).flat_map do |cert|
132
+ cert.all(mac: false) + cert.all(mac: true)
133
+ end
134
+ end.flatten
135
+
136
+ # Finds all the .cer and .p12 files in the file storage
137
+ certs = []
138
+ keys = []
139
+ cert_types.each do |ct|
140
+ certs += Dir[File.join(self.storage.working_directory, "**", ct.to_s, "*.cer")]
141
+ keys += Dir[File.join(self.storage.working_directory, "**", ct.to_s, "*.p12")]
142
+ end
143
+
144
+ # Finds all the iOS and macOS profofiles in the file storage
123
145
  profiles = []
124
146
  prov_types.each do |prov_type|
125
147
  profiles += Dir[File.join(self.storage.working_directory, "**", prov_type.to_s, "*.mobileprovision")]
148
+ profiles += Dir[File.join(self.storage.working_directory, "**", prov_type.to_s, "*.provisionprofile")]
126
149
  end
127
150
 
128
151
  self.files = certs + keys + profiles
@@ -240,21 +263,36 @@ module Match
240
263
 
241
264
  # The kind of certificate we're interested in
242
265
  def certificate_type(type)
243
- {
244
- distribution: [Spaceship.certificate.production, Spaceship.certificate.apple_distribution],
245
- development: [Spaceship.certificate.development, Spaceship.certificate.apple_development],
246
- enterprise: [Spaceship.certificate.in_house]
247
- }[type] ||= raise "Unknown type '#{type}'"
266
+ case type.to_sym
267
+ when :mac_installer_distribution
268
+ return [Spaceship.certificate.mac_installer_distribution]
269
+ when :distribution
270
+ return [Spaceship.certificate.production, Spaceship.certificate.apple_distribution]
271
+ when :development
272
+ return [Spaceship.certificate.development, Spaceship.certificate.apple_development]
273
+ when :enterprise
274
+ return [Spaceship.certificate.in_house]
275
+ else
276
+ raise "Unknown type '#{type}'"
277
+ end
248
278
  end
249
279
 
250
280
  # The kind of provisioning profile we're interested in
251
281
  def profile_type(prov_type)
252
- {
253
- appstore: Spaceship.provisioning_profile.app_store,
254
- development: Spaceship.provisioning_profile.development,
255
- enterprise: Spaceship.provisioning_profile.in_house,
256
- adhoc: Spaceship.provisioning_profile.ad_hoc
257
- }[prov_type] ||= raise "Unknown provisioning type '#{prov_type}'"
282
+ case prov_type.to_sym
283
+ when :appstore
284
+ return Spaceship.provisioning_profile.app_store
285
+ when :development
286
+ return Spaceship.provisioning_profile.development
287
+ when :enterprise
288
+ return Spaceship.provisioning_profile.in_house
289
+ when :adhoc
290
+ return Spaceship.provisioning_profile.ad_hoc
291
+ when :developer_id
292
+ return Spaceship.provisioning_profile.direct
293
+ else
294
+ raise "Unknown provisioning type '#{prov_type}'"
295
+ end
258
296
  end
259
297
  end
260
298
  end
@@ -19,7 +19,6 @@ module Match
19
19
  FastlaneCore::ConfigItem.new(key: :type,
20
20
  env_name: "MATCH_TYPE",
21
21
  description: "Define the profile type, can be #{Match.environments.join(', ')}",
22
- is_string: true,
23
22
  short_option: "-y",
24
23
  default_value: 'development',
25
24
  verify_block: proc do |value|
@@ -27,10 +26,19 @@ module Match
27
26
  UI.user_error!("Unsupported environment #{value}, must be in #{Match.environments.join(', ')}")
28
27
  end
29
28
  end),
29
+ FastlaneCore::ConfigItem.new(key: :additional_cert_types,
30
+ env_name: "MATCH_ADDITIONAL_CERT_TYPES",
31
+ description: "Create additional cert types needed for macOS installers (valid values: mac_installer_distribution, developer_id_installer)",
32
+ optional: true,
33
+ type: Array,
34
+ verify_block: proc do |values|
35
+ types = %w(mac_installer_distribution developer_id_installer)
36
+ UI.user_error!("Unsupported types, must be: #{types}") unless (values - types).empty?
37
+ end),
30
38
  FastlaneCore::ConfigItem.new(key: :readonly,
31
39
  env_name: "MATCH_READONLY",
32
40
  description: "Only fetch existing certificates and profiles, don't generate new ones",
33
- is_string: false,
41
+ type: Boolean,
34
42
  default_value: false),
35
43
  FastlaneCore::ConfigItem.new(key: :generate_apple_certs,
36
44
  env_name: "MATCH_GENERATE_APPLE_CERTS",
@@ -41,7 +49,7 @@ module Match
41
49
  FastlaneCore::ConfigItem.new(key: :skip_provisioning_profiles,
42
50
  env_name: "MATCH_SKIP_PROVISIONING_PROFILES",
43
51
  description: "Skip syncing provisioning profiles",
44
- is_string: false,
52
+ type: Boolean,
45
53
  default_value: false),
46
54
 
47
55
  # app
@@ -49,7 +57,6 @@ module Match
49
57
  short_option: "-a",
50
58
  env_name: "MATCH_APP_IDENTIFIER",
51
59
  description: "The bundle identifier(s) of your app (comma-separated)",
52
- is_string: false,
53
60
  type: Array, # we actually allow String and Array here
54
61
  skip_type_validation: true,
55
62
  code_gen_sensitive: true,
@@ -82,7 +89,6 @@ module Match
82
89
  FastlaneCore::ConfigItem.new(key: :storage_mode,
83
90
  env_name: "MATCH_STORAGE_MODE",
84
91
  description: "Define where you want to store your certificates",
85
- is_string: true,
86
92
  short_option: "-q",
87
93
  default_value: 'git',
88
94
  verify_block: proc do |value|
@@ -114,17 +120,25 @@ module Match
114
120
  FastlaneCore::ConfigItem.new(key: :shallow_clone,
115
121
  env_name: "MATCH_SHALLOW_CLONE",
116
122
  description: "Make a shallow clone of the repository (truncate the history to 1 revision)",
117
- is_string: false,
123
+ type: Boolean,
118
124
  default_value: false),
119
125
  FastlaneCore::ConfigItem.new(key: :clone_branch_directly,
120
126
  env_name: "MATCH_CLONE_BRANCH_DIRECTLY",
121
127
  description: "Clone just the branch specified, instead of the whole repo. This requires that the branch already exists. Otherwise the command will fail",
122
- is_string: false,
128
+ type: Boolean,
123
129
  default_value: false),
124
130
  FastlaneCore::ConfigItem.new(key: :git_basic_authorization,
125
131
  env_name: "MATCH_GIT_BASIC_AUTHORIZATION",
126
132
  sensitive: true,
127
133
  description: "Use a basic authorization header to access the git repo (e.g.: access via HTTPS, GitHub Actions, etc), usually a string in Base64",
134
+ conflicting_options: [:git_bearer_authorization],
135
+ optional: true,
136
+ default_value: nil),
137
+ FastlaneCore::ConfigItem.new(key: :git_bearer_authorization,
138
+ env_name: "MATCH_GIT_BEARER_AUTHORIZATION",
139
+ sensitive: true,
140
+ description: "Use a bearer authorization header to access the git repo (e.g.: access to an Azure Devops repository), usually a string in Base64",
141
+ conflicting_options: [:git_basic_authorization],
128
142
  optional: true,
129
143
  default_value: nil),
130
144
 
@@ -162,32 +176,31 @@ module Match
162
176
  FastlaneCore::ConfigItem.new(key: :force,
163
177
  env_name: "MATCH_FORCE",
164
178
  description: "Renew the provisioning profiles every time you run match",
165
- is_string: false,
179
+ type: Boolean,
166
180
  default_value: false),
167
181
  FastlaneCore::ConfigItem.new(key: :force_for_new_devices,
168
182
  env_name: "MATCH_FORCE_FOR_NEW_DEVICES",
169
183
  description: "Renew the provisioning profiles if the device count on the developer portal has changed. Ignored for profile type 'appstore'",
170
- is_string: false,
184
+ type: Boolean,
171
185
  default_value: false),
172
186
  FastlaneCore::ConfigItem.new(key: :skip_confirmation,
173
187
  env_name: "MATCH_SKIP_CONFIRMATION",
174
188
  description: "Disables confirmation prompts during nuke, answering them with yes",
175
- is_string: false,
189
+ type: Boolean,
176
190
  default_value: false),
177
191
  FastlaneCore::ConfigItem.new(key: :skip_docs,
178
192
  env_name: "MATCH_SKIP_DOCS",
179
193
  description: "Skip generation of a README.md for the created git repository",
180
- is_string: false,
194
+ type: Boolean,
181
195
  default_value: false),
182
196
  FastlaneCore::ConfigItem.new(key: :platform,
183
197
  short_option: '-o',
184
198
  env_name: "MATCH_PLATFORM",
185
- description: "Set the provisioning profile's platform to work with (i.e. ios, tvos)",
186
- is_string: false,
199
+ description: "Set the provisioning profile's platform to work with (i.e. ios, tvos, macos)",
187
200
  default_value: "ios",
188
201
  verify_block: proc do |value|
189
202
  value = value.to_s
190
- pt = %w(tvos ios)
203
+ pt = %w(tvos ios macos)
191
204
  UI.user_error!("Unsupported platform, must be: #{pt}") unless pt.include?(value)
192
205
  end),
193
206
  FastlaneCore::ConfigItem.new(key: :template_name,
@@ -204,7 +217,7 @@ module Match
204
217
  FastlaneCore::ConfigItem.new(key: :verbose,
205
218
  env_name: "MATCH_VERBOSE",
206
219
  description: "Print out extra information and all commands",
207
- is_string: false,
220
+ type: Boolean,
208
221
  default_value: false,
209
222
  verify_block: proc do |value|
210
223
  FastlaneCore::Globals.verbose = true if value
@@ -18,6 +18,7 @@ module Match
18
18
 
19
19
  attr_accessor :storage
20
20
 
21
+ # rubocop:disable Metrics/PerceivedComplexity
21
22
  def run(params)
22
23
  self.files_to_commit = []
23
24
 
@@ -38,6 +39,7 @@ module Match
38
39
  git_user_email: params[:git_user_email],
39
40
  clone_branch_directly: params[:clone_branch_directly],
40
41
  git_basic_authorization: params[:git_basic_authorization],
42
+ git_bearer_authorization: params[:git_bearer_authorization],
41
43
  type: params[:type].to_s,
42
44
  generate_apple_certs: params[:generate_apple_certs],
43
45
  platform: params[:platform].to_s,
@@ -78,13 +80,21 @@ module Match
78
80
  # Verify the App ID (as we don't want 'match' to fail at a later point)
79
81
  if spaceship
80
82
  app_identifiers.each do |app_identifier|
81
- spaceship.bundle_identifier_exists(username: params[:username], app_identifier: app_identifier)
83
+ spaceship.bundle_identifier_exists(username: params[:username], app_identifier: app_identifier, platform: params[:platform])
82
84
  end
83
85
  end
84
86
 
85
87
  # Certificate
86
88
  cert_id = fetch_certificate(params: params, working_directory: storage.working_directory)
87
- spaceship.certificate_exists(username: params[:username], certificate_id: cert_id) if spaceship
89
+
90
+ # Mac Installer Distribution Certificate
91
+ additional_cert_types = params[:additional_cert_types] || []
92
+ cert_ids = additional_cert_types.map do |additional_cert_type|
93
+ fetch_certificate(params: params, working_directory: storage.working_directory, specific_cert_type: additional_cert_type)
94
+ end
95
+
96
+ cert_ids << cert_id
97
+ spaceship.certificates_exists(username: params[:username], certificate_ids: cert_ids, platform: params[:platform]) if spaceship
88
98
 
89
99
  # Provisioning Profiles
90
100
  unless params[:skip_provisioning_profiles]
@@ -118,6 +128,7 @@ module Match
118
128
  ensure
119
129
  storage.clear_changes if storage
120
130
  end
131
+ # rubocop:enable Metrics/PerceivedComplexity
121
132
 
122
133
  # Used when creating a new certificate or profile
123
134
  def prefixed_working_directory
@@ -132,8 +143,8 @@ module Match
132
143
  end
133
144
  end
134
145
 
135
- def fetch_certificate(params: nil, working_directory: nil)
136
- cert_type = Match.cert_type_sym(params[:type])
146
+ def fetch_certificate(params: nil, working_directory: nil, specific_cert_type: nil)
147
+ cert_type = Match.cert_type_sym(specific_cert_type || params[:type])
137
148
 
138
149
  certs = Dir[File.join(prefixed_working_directory, "certs", cert_type.to_s, "*.cer")]
139
150
  keys = Dir[File.join(prefixed_working_directory, "certs", cert_type.to_s, "*.p12")]
@@ -141,7 +152,7 @@ module Match
141
152
  if certs.count == 0 || keys.count == 0
142
153
  UI.important("Couldn't find a valid code signing identity for #{cert_type}... creating one for you now")
143
154
  UI.crash!("No code signing identity found and can not create a new one because you enabled `readonly`") if params[:readonly]
144
- cert_path = Generator.generate_certificate(params, cert_type, prefixed_working_directory)
155
+ cert_path = Generator.generate_certificate(params, cert_type, prefixed_working_directory, specific_cert_type: specific_cert_type)
145
156
  private_key_path = cert_path.gsub(".cer", ".p12")
146
157
 
147
158
  self.files_to_commit << cert_path
@@ -195,13 +206,15 @@ module Match
195
206
  prov_type = Match.profile_type_sym(params[:type])
196
207
 
197
208
  names = [Match::Generator.profile_type_name(prov_type), app_identifier]
198
- if params[:platform].to_s != :ios.to_s
209
+ if params[:platform].to_s == :tvos.to_s
199
210
  names.push(params[:platform])
200
211
  end
201
212
 
202
213
  profile_name = names.join("_").gsub("*", '\*') # this is important, as it shouldn't be a wildcard
203
214
  base_dir = File.join(prefixed_working_directory, "profiles", prov_type.to_s)
204
- profiles = Dir[File.join(base_dir, "#{profile_name}.mobileprovision")]
215
+
216
+ extension = params[:platform].to_s == :macos.to_s ? ".provisionprofile" : ".mobileprovision"
217
+ profiles = Dir[File.join(base_dir, "#{profile_name}#{extension}")]
205
218
  if Helper.mac?
206
219
  keychain_path = FastlaneCore::Helper.keychain_path(params[:keychain_name]) unless params[:keychain_name].nil?
207
220
  end
@@ -253,7 +266,7 @@ module Match
253
266
  FileUtils.cp(profile, params[:output_path])
254
267
  end
255
268
 
256
- if spaceship && !spaceship.profile_exists(username: params[:username], uuid: uuid)
269
+ if spaceship && !spaceship.profile_exists(username: params[:username], uuid: uuid, platform: params[:platform])
257
270
  # This profile is invalid, let's remove the local file and generate a new one
258
271
  File.delete(profile)
259
272
  # This method will be called again, no need to modify `files_to_commit`
@@ -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
@@ -18,6 +18,7 @@ module Match
18
18
  attr_accessor :type
19
19
  attr_accessor :platform
20
20
  attr_accessor :git_basic_authorization
21
+ attr_accessor :git_bearer_authorization
21
22
 
22
23
  def self.configure(params)
23
24
  return self.new(
@@ -30,7 +31,8 @@ module Match
30
31
  git_full_name: params[:git_full_name],
31
32
  git_user_email: params[:git_user_email],
32
33
  clone_branch_directly: params[:clone_branch_directly],
33
- git_basic_authorization: params[:git_basic_authorization]
34
+ git_basic_authorization: params[:git_basic_authorization],
35
+ git_bearer_authorization: params[:git_bearer_authorization]
34
36
  )
35
37
  end
36
38
 
@@ -43,7 +45,8 @@ module Match
43
45
  git_full_name: nil,
44
46
  git_user_email: nil,
45
47
  clone_branch_directly: false,
46
- git_basic_authorization: nil)
48
+ git_basic_authorization: nil,
49
+ git_bearer_authorization: nil)
47
50
  self.git_url = git_url
48
51
  self.shallow_clone = shallow_clone
49
52
  self.skip_docs = skip_docs
@@ -52,6 +55,7 @@ module Match
52
55
  self.git_user_email = git_user_email
53
56
  self.clone_branch_directly = clone_branch_directly
54
57
  self.git_basic_authorization = git_basic_authorization
58
+ self.git_bearer_authorization = git_bearer_authorization
55
59
 
56
60
  self.type = type if type
57
61
  self.platform = platform if platform
@@ -69,7 +73,11 @@ module Match
69
73
  self.working_directory = Dir.mktmpdir
70
74
 
71
75
  command = "git clone #{self.git_url.shellescape} #{self.working_directory.shellescape}"
72
- command << " -c http.extraheader='AUTHORIZATION: basic #{self.git_basic_authorization}'" unless self.git_basic_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?
73
81
 
74
82
  if self.shallow_clone
75
83
  command << " --depth 1 --no-single-branch"
@@ -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