fastlane 2.214.0 → 2.217.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +98 -98
  3. data/deliver/lib/deliver/app_screenshot.rb +20 -10
  4. data/deliver/lib/deliver/runner.rb +2 -1
  5. data/deliver/lib/deliver/submit_for_review.rb +13 -0
  6. data/deliver/lib/deliver/upload_metadata.rb +58 -13
  7. data/fastlane/lib/fastlane/actions/docs/build_app.md +2 -2
  8. data/fastlane/lib/fastlane/actions/docs/capture_android_screenshots.md +8 -8
  9. data/fastlane/lib/fastlane/actions/docs/check_app_store_metadata.md +3 -3
  10. data/fastlane/lib/fastlane/actions/docs/get_push_certificate.md +2 -2
  11. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +1 -1
  12. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +1 -1
  13. data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +6 -2
  14. data/fastlane/lib/fastlane/actions/docs/upload_to_testflight.md +1 -1
  15. data/fastlane/lib/fastlane/actions/download_universal_apk_from_google_play.rb +1 -1
  16. data/fastlane/lib/fastlane/actions/ensure_xcode_version.rb +4 -0
  17. data/fastlane/lib/fastlane/actions/git_branch.rb +1 -1
  18. data/fastlane/lib/fastlane/actions/install_on_device.rb +1 -1
  19. data/fastlane/lib/fastlane/actions/nexus_upload.rb +1 -0
  20. data/fastlane/lib/fastlane/actions/notarize.rb +17 -2
  21. data/fastlane/lib/fastlane/actions/slather.rb +17 -4
  22. data/fastlane/lib/fastlane/helper/git_helper.rb +3 -0
  23. data/fastlane/lib/fastlane/helper/xcodes_helper.rb +0 -3
  24. data/fastlane/lib/fastlane/lane.rb +9 -1
  25. data/fastlane/lib/fastlane/new_action.rb +1 -1
  26. data/fastlane/lib/fastlane/plugins/plugin_info_collector.rb +3 -3
  27. data/fastlane/lib/fastlane/plugins/template/%gem_name%.gemspec.erb +1 -2
  28. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +5 -1
  29. data/fastlane/lib/fastlane/plugins/template/lib/fastlane/plugin/%plugin_name%/helper/%plugin_name%_helper.rb.erb +1 -1
  30. data/fastlane/lib/fastlane/runner.rb +1 -1
  31. data/fastlane/lib/fastlane/version.rb +2 -2
  32. data/fastlane/swift/Deliverfile.swift +1 -1
  33. data/fastlane/swift/DeliverfileProtocol.swift +1 -1
  34. data/fastlane/swift/Fastlane.swift +67 -7
  35. data/fastlane/swift/Gymfile.swift +1 -1
  36. data/fastlane/swift/GymfileProtocol.swift +1 -1
  37. data/fastlane/swift/Matchfile.swift +1 -1
  38. data/fastlane/swift/MatchfileProtocol.swift +17 -1
  39. data/fastlane/swift/Precheckfile.swift +1 -1
  40. data/fastlane/swift/PrecheckfileProtocol.swift +1 -1
  41. data/fastlane/swift/Scanfile.swift +1 -1
  42. data/fastlane/swift/ScanfileProtocol.swift +1 -1
  43. data/fastlane/swift/Screengrabfile.swift +1 -1
  44. data/fastlane/swift/ScreengrabfileProtocol.swift +1 -1
  45. data/fastlane/swift/Snapshotfile.swift +1 -1
  46. data/fastlane/swift/SnapshotfileProtocol.swift +1 -1
  47. data/fastlane/swift/formatting/Brewfile.lock.json +22 -22
  48. data/fastlane_core/lib/fastlane_core/cert_checker.rb +2 -2
  49. data/fastlane_core/lib/fastlane_core/project.rb +4 -0
  50. data/fastlane_core/lib/fastlane_core/queue_worker.rb +1 -1
  51. data/frameit/lib/frameit/device_types.rb +1 -1
  52. data/gym/lib/gym/module.rb +13 -2
  53. data/gym/lib/gym/options.rb +1 -1
  54. data/match/lib/match/change_password.rb +3 -9
  55. data/match/lib/match/commands_generator.rb +3 -6
  56. data/match/lib/match/encryption.rb +1 -1
  57. data/match/lib/match/importer.rb +3 -31
  58. data/match/lib/match/migrate.rb +6 -2
  59. data/match/lib/match/nuke.rb +3 -25
  60. data/match/lib/match/options.rb +20 -0
  61. data/match/lib/match/runner.rb +16 -37
  62. data/match/lib/match/setup.rb +1 -1
  63. data/match/lib/match/storage/git_storage.rb +9 -1
  64. data/match/lib/match/storage/s3_storage.rb +6 -0
  65. data/match/lib/match/storage.rb +56 -5
  66. data/precheck/lib/precheck/rules/unreachable_urls_rule.rb +1 -1
  67. data/snapshot/lib/assets/SnapshotHelper.swift +13 -9
  68. data/snapshot/lib/snapshot/reports_generator.rb +48 -7
  69. data/spaceship/lib/spaceship/connect_api/api_client.rb +21 -2
  70. data/spaceship/lib/spaceship/connect_api/models/app.rb +3 -2
  71. data/spaceship/lib/spaceship/connect_api/models/app_info.rb +15 -9
  72. data/spaceship/lib/spaceship/connect_api/models/app_screenshot_set.rb +7 -0
  73. data/spaceship/lib/spaceship/connect_api/models/app_store_version.rb +1 -0
  74. data/spaceship/lib/spaceship/connect_api/models/beta_group.rb +3 -1
  75. data/spaceship/lib/spaceship/connect_api/models/bundle_id.rb +4 -4
  76. data/spaceship/lib/spaceship/connect_api/models/certificate.rb +2 -2
  77. data/spaceship/lib/spaceship/connect_api/models/device.rb +2 -2
  78. data/spaceship/lib/spaceship/connect_api/models/profile.rb +3 -2
  79. data/spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb +14 -8
  80. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +8 -2
  81. data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +0 -3
  82. data/supply/lib/supply/client.rb +47 -21
  83. data/supply/lib/supply/image_listing.rb +15 -0
  84. data/supply/lib/supply/options.rb +5 -0
  85. data/supply/lib/supply/setup.rb +1 -1
  86. data/supply/lib/supply/uploader.rb +60 -18
  87. data/supply/lib/supply.rb +1 -0
  88. data/trainer/lib/trainer/xcresult.rb +1 -1
  89. metadata +282 -273
@@ -6,7 +6,7 @@ module FastlaneCore
6
6
  # Use this when you have all the items that you'll process in advance.
7
7
  # Simply enqueue them to this and call `QueueWorker#start`.
8
8
  class QueueWorker
9
- NUMBER_OF_THREADS = FastlaneCore::Helper.test? ? 1 : [(ENV["DELIVER_NUMBER_OF_THREADS"] || ENV.fetch("FL_NUMBER_OF_THREADS", 10)).to_i, 10].min
9
+ NUMBER_OF_THREADS = FastlaneCore::Helper.test? ? 1 : [ENV["DELIVER_NUMBER_OF_THREADS"], ENV["FL_NUMBER_OF_THREADS"], 10].map(&:to_i).find(&:positive?).clamp(1, ENV.fetch("FL_MAX_NUMBER_OF_THREADS", 10).to_i)
10
10
 
11
11
  # @param concurrency (Numeric) - A number of threads to be created
12
12
  # @param block (Proc) - A task you want to execute with enqueued items
@@ -120,7 +120,7 @@ module Frameit
120
120
  IPHONE_8_PLUS ||= Frameit::Device.new("iphone-8-plus", "Apple iPhone 8 Plus", 6, [[1242, 2208], [2208, 1242]], 401, Color::SPACE_GRAY)
121
121
  IPHONE_X ||= Frameit::Device.new("iphone-X", "Apple iPhone X", 7, [[1125, 2436], [2436, 1125]], 458, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_58, :use_legacy_iphonex)
122
122
  IPHONE_XS ||= Frameit::Device.new("iphone-XS", "Apple iPhone XS", 8, [[1125, 2436], [2436, 1125]], 458, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_58, :use_legacy_iphonexs)
123
- IPHONE_XR ||= Frameit::Device.new("iphone-XR", "Apple iPhone XR", 8, [[828, 1792], [1792, 828]], 326, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_61, :use_legacy_iphonexr)
123
+ IPHONE_XR ||= Frameit::Device.new("iphone-XR", "Apple iPhone XR", 8, [[828, 1792], [1792, 828]], 326, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_65, :use_legacy_iphonexsmax)
124
124
  IPHONE_XS_MAX ||= Frameit::Device.new("iphone-XS-Max", "Apple iPhone XS Max", 8, [[1242, 2688], [2688, 1242]], 458, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_65, :use_legacy_iphonexsmax)
125
125
  IPHONE_11 ||= Frameit::Device.new("iphone-11", "Apple iPhone 11", 9, [[828, 1792], [1792, 828]], 326, Color::BLACK, Platform::IOS)
126
126
  IPHONE_11_PRO ||= Frameit::Device.new("iphone-11-pro", "Apple iPhone 11 Pro", 9, [[1125, 2436], [2436, 1125]], 458, Color::SPACE_GRAY, Platform::IOS)
@@ -27,8 +27,8 @@ module Gym
27
27
 
28
28
  def building_for_ios?
29
29
  if Gym.project.mac?
30
- # Can be building for iOS if mac project and catalyst
31
- return building_mac_catalyst_for_ios?
30
+ # Can be building for iOS if mac project and catalyst or multiplatform and set to iOS
31
+ return building_mac_catalyst_for_ios? || building_multiplatform_for_ios?
32
32
  else
33
33
  # Can be iOS project and build for mac if catalyst
34
34
  return false if building_mac_catalyst_for_mac?
@@ -43,6 +43,9 @@ module Gym
43
43
  # Can be a mac project and not build mac if catalyst
44
44
  return building_mac_catalyst_for_mac?
45
45
  else
46
+ # Can be mac project but multiplatform and building for iOS
47
+ return false if building_multiplatform_for_ios?
48
+
46
49
  return Gym.project.mac?
47
50
  end
48
51
  end
@@ -55,6 +58,14 @@ module Gym
55
58
  Gym.project.supports_mac_catalyst? && Gym.config[:catalyst_platform] == "macos"
56
59
  end
57
60
 
61
+ def building_multiplatform_for_ios?
62
+ Gym.project.multiplatform? && Gym.project.ios? && (Gym.config[:sdk] == "iphoneos" || Gym.config[:sdk] == "iphonesimulator")
63
+ end
64
+
65
+ def building_multiplatform_for_mac?
66
+ Gym.project.multiplatform? && Gym.project.mac? && Gym.config[:sdk] == "macosx"
67
+ end
68
+
58
69
  def export_destination_upload?
59
70
  config_path = Gym.cache[:config_path]
60
71
  return false if config_path.nil?
@@ -152,7 +152,7 @@ module Gym
152
152
  optional: true,
153
153
  verify_block: proc do |value|
154
154
  av = %w(ios macos)
155
- UI.user_error!("Unsupported export_method '#{value}', must be: #{av}") unless av.include?(value)
155
+ UI.user_error!("Unsupported catalyst_platform '#{value}', must be: #{av}") unless av.include?(value)
156
156
  end),
157
157
  FastlaneCore::ConfigItem.new(key: :installer_cert_name,
158
158
  env_name: "GYM_INSTALLER_CERT_NAME",
@@ -19,19 +19,13 @@ module Match
19
19
  new_password = FastlaneCore::Helper.ask_password(message: "New passphrase for Git Repo: ", confirm: true)
20
20
 
21
21
  # Choose the right storage and encryption implementations
22
- storage = Storage.for_mode(params[:storage_mode], {
23
- git_url: params[:git_url],
24
- shallow_clone: params[:shallow_clone],
25
- skip_docs: params[:skip_docs],
26
- git_branch: params[:git_branch],
27
- git_full_name: params[:git_full_name],
28
- git_user_email: params[:git_user_email],
29
- clone_branch_directly: params[:clone_branch_directly]
30
- })
22
+ storage = Storage.from_params(params)
31
23
  storage.download
32
24
 
33
25
  encryption = Encryption.for_storage_mode(params[:storage_mode], {
34
26
  git_url: params[:git_url],
27
+ s3_bucket: params[:s3_bucket],
28
+ s3_skip_encryption: params[:s3_skip_encryption],
35
29
  working_directory: storage.working_directory
36
30
  })
37
31
  encryption.decrypt_files
@@ -118,16 +118,13 @@ module Match
118
118
  params = FastlaneCore::Configuration.create(Match::Options.available_options, options.__hash__)
119
119
  params.load_configuration_file("Matchfile")
120
120
 
121
- storage = Storage.for_mode(params[:storage_mode], {
122
- git_url: params[:git_url],
123
- shallow_clone: params[:shallow_clone],
124
- git_branch: params[:git_branch],
125
- clone_branch_directly: params[:clone_branch_directly]
126
- })
121
+ storage = Storage.from_params(params)
127
122
  storage.download
128
123
 
129
124
  encryption = Encryption.for_storage_mode(params[:storage_mode], {
130
125
  git_url: params[:git_url],
126
+ s3_bucket: params[:s3_bucket],
127
+ s3_skip_encryption: params[:s3_skip_encryption],
131
128
  working_directory: storage.working_directory
132
129
  })
133
130
  encryption.decrypt_files if encryption
@@ -17,7 +17,7 @@ module Match
17
17
  },
18
18
  "s3" => lambda { |params|
19
19
  params[:keychain_name] = params[:s3_bucket]
20
- return Encryption::OpenSSL.configure(params)
20
+ return params[:s3_skip_encryption] ? nil : Encryption::OpenSSL.configure(params)
21
21
  },
22
22
  "gitlab_secure_files" => lambda { |params|
23
23
  return nil
@@ -15,42 +15,14 @@ module Match
15
15
  profile_path = ensure_valid_file_path(profile_path, "Provisioning profile", ".mobileprovision or .provisionprofile", optional: true)
16
16
 
17
17
  # Storage
18
- storage = Storage.for_mode(params[:storage_mode], {
19
- git_url: params[:git_url],
20
- shallow_clone: params[:shallow_clone],
21
- skip_docs: params[:skip_docs],
22
- git_branch: params[:git_branch],
23
- git_full_name: params[:git_full_name],
24
- git_user_email: params[:git_user_email],
25
- git_private_key: params[:git_private_key],
26
- git_basic_authorization: params[:git_basic_authorization],
27
- git_bearer_authorization: params[:git_bearer_authorization],
28
- clone_branch_directly: params[:clone_branch_directly],
29
- type: params[:type].to_s,
30
- platform: params[:platform].to_s,
31
- google_cloud_bucket_name: params[:google_cloud_bucket_name].to_s,
32
- google_cloud_keys_file: params[:google_cloud_keys_file].to_s,
33
- google_cloud_project_id: params[:google_cloud_project_id].to_s,
34
- skip_google_cloud_account_confirmation: params[:skip_google_cloud_account_confirmation],
35
- s3_bucket: params[:s3_bucket],
36
- s3_region: params[:s3_region],
37
- s3_access_key: params[:s3_access_key],
38
- s3_secret_access_key: params[:s3_secret_access_key],
39
- s3_object_prefix: params[:s3_object_prefix],
40
- gitlab_project: params[:gitlab_project],
41
- gitlab_host: params[:gitlab_host],
42
- readonly: params[:readonly],
43
- username: params[:username],
44
- team_id: params[:team_id],
45
- team_name: params[:team_name],
46
- api_key_path: params[:api_key_path],
47
- api_key: params[:api_key]
48
- })
18
+ storage = Storage.from_params(params)
49
19
  storage.download
50
20
 
51
21
  # Encryption
52
22
  encryption = Encryption.for_storage_mode(params[:storage_mode], {
53
23
  git_url: params[:git_url],
24
+ s3_bucket: params[:s3_bucket],
25
+ s3_skip_encryption: params[:s3_skip_encryption],
54
26
  working_directory: storage.working_directory
55
27
  })
56
28
  encryption.decrypt_files if encryption
@@ -13,13 +13,15 @@ module Match
13
13
 
14
14
  # We init the Google storage client before the git client
15
15
  # to ask for all the missing inputs *before* cloning the git repo
16
- google_cloud_storage = Storage.for_mode("google_cloud", {
16
+ google_cloud_storage = Storage.from_params({
17
+ storage_mode: "google_cloud",
17
18
  google_cloud_bucket_name: params[:google_cloud_bucket_name],
18
19
  google_cloud_keys_file: params[:google_cloud_keys_file],
19
20
  google_cloud_project_id: params[:google_cloud_project_id]
20
21
  })
21
22
 
22
- git_storage = Storage.for_mode("git", {
23
+ git_storage = Storage.from_params({
24
+ storage_mode: "git",
23
25
  git_url: params[:git_url],
24
26
  shallow_clone: params[:shallow_clone],
25
27
  git_branch: params[:git_branch],
@@ -29,6 +31,8 @@ module Match
29
31
 
30
32
  encryption = Encryption.for_storage_mode(params[:storage_mode], {
31
33
  git_url: params[:git_url],
34
+ s3_bucket: params[:s3_bucket],
35
+ s3_skip_encryption: params[:s3_skip_encryption],
32
36
  working_directory: git_storage.working_directory
33
37
  })
34
38
  encryption.decrypt_files if encryption
@@ -34,36 +34,14 @@ module Match
34
34
 
35
35
  spaceship_login
36
36
 
37
- self.storage = Storage.for_mode(params[:storage_mode], {
38
- git_url: params[:git_url],
39
- shallow_clone: params[:shallow_clone],
40
- skip_docs: params[:skip_docs],
41
- git_branch: params[:git_branch],
42
- git_full_name: params[:git_full_name],
43
- git_user_email: params[:git_user_email],
44
-
45
- git_private_key: params[:git_private_key],
46
- git_basic_authorization: params[:git_basic_authorization],
47
- git_bearer_authorization: params[:git_bearer_authorization],
48
-
49
- clone_branch_directly: params[:clone_branch_directly],
50
- google_cloud_bucket_name: params[:google_cloud_bucket_name].to_s,
51
- google_cloud_keys_file: params[:google_cloud_keys_file].to_s,
52
- google_cloud_project_id: params[:google_cloud_project_id].to_s,
53
- s3_region: params[:s3_region].to_s,
54
- s3_access_key: params[:s3_access_key].to_s,
55
- s3_secret_access_key: params[:s3_secret_access_key].to_s,
56
- s3_bucket: params[:s3_bucket].to_s,
57
- s3_object_prefix: params[:s3_object_prefix].to_s,
58
- gitlab_project: params[:gitlab_project],
59
- gitlab_host: params[:gitlab_host],
60
- team_id: params[:team_id] || Spaceship::ConnectAPI.client.portal_team_id
61
- })
37
+ self.storage = Storage.from_params(params)
62
38
  self.storage.download
63
39
 
64
40
  # After the download was complete
65
41
  self.encryption = Encryption.for_storage_mode(params[:storage_mode], {
66
42
  git_url: params[:git_url],
43
+ s3_bucket: params[:s3_bucket],
44
+ s3_skip_encryption: params[:s3_skip_encryption],
67
45
  working_directory: storage.working_directory
68
46
  })
69
47
  self.encryption.decrypt_files if self.encryption
@@ -4,6 +4,7 @@ require 'credentials_manager/appfile_config'
4
4
  require_relative 'module'
5
5
 
6
6
  module Match
7
+ # rubocop:disable Metrics/ClassLength
7
8
  class Options
8
9
  # This is match specific, as users can append storage specific options
9
10
  def self.append_option(option)
@@ -222,6 +223,11 @@ module Match
222
223
  env_name: "MATCH_S3_OBJECT_PREFIX",
223
224
  description: "Prefix to be used on all objects uploaded to S3",
224
225
  optional: true),
226
+ FastlaneCore::ConfigItem.new(key: :s3_skip_encryption,
227
+ env_name: "MATCH_S3_SKIP_ENCRYPTION",
228
+ description: "Skip encryption of all objects uploaded to S3. WARNING: only enable this on S3 buckets with sufficiently restricted permissions and server-side encryption enabled. See https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingEncryption.html",
229
+ type: Boolean,
230
+ default_value: false),
225
231
 
226
232
  # Storage: GitLab Secure Files
227
233
  FastlaneCore::ConfigItem.new(key: :gitlab_project,
@@ -233,6 +239,14 @@ module Match
233
239
  default_value: 'https://gitlab.com',
234
240
  description: "GitLab Host (i.e. 'https://gitlab.com')",
235
241
  optional: true),
242
+ FastlaneCore::ConfigItem.new(key: :job_token,
243
+ env_name: "CI_JOB_TOKEN",
244
+ description: "GitLab CI_JOB_TOKEN",
245
+ optional: true),
246
+ FastlaneCore::ConfigItem.new(key: :private_token,
247
+ env_name: "PRIVATE_TOKEN",
248
+ description: "GitLab Access Token",
249
+ optional: true),
236
250
 
237
251
  # Keychain
238
252
  FastlaneCore::ConfigItem.new(key: :keychain_name,
@@ -268,6 +282,11 @@ module Match
268
282
  description: "Include all matching certificates in the provisioning profile. Works only for the 'development' provisioning profile type",
269
283
  type: Boolean,
270
284
  default_value: false),
285
+ FastlaneCore::ConfigItem.new(key: :certificate_id,
286
+ env_name: "MATCH_CERTIFICATE_ID",
287
+ description: "Select certificate by id. Useful if multiple certificates are stored in one place",
288
+ type: String,
289
+ optional: true),
271
290
  FastlaneCore::ConfigItem.new(key: :force_for_new_certificates,
272
291
  env_name: "MATCH_FORCE_FOR_NEW_CERTIFICATES",
273
292
  description: "Renew the provisioning profiles if the certificate count on the developer portal has changed. Works only for the 'development' provisioning profile type. Requires 'include_all_certificates' option to be 'true'",
@@ -349,4 +368,5 @@ module Match
349
368
  ]
350
369
  end
351
370
  end
371
+ # rubocop:enable Metrics/ClassLength
352
372
  end
@@ -31,43 +31,16 @@ module Match
31
31
  update_optional_values_depending_on_storage_type(params)
32
32
 
33
33
  # Choose the right storage and encryption implementations
34
- self.storage = Storage.for_mode(params[:storage_mode], {
35
- git_url: params[:git_url],
36
- shallow_clone: params[:shallow_clone],
37
- skip_docs: params[:skip_docs],
38
- git_branch: params[:git_branch],
39
- git_full_name: params[:git_full_name],
40
- git_user_email: params[:git_user_email],
41
- clone_branch_directly: params[:clone_branch_directly],
42
- git_basic_authorization: params[:git_basic_authorization],
43
- git_bearer_authorization: params[:git_bearer_authorization],
44
- git_private_key: params[:git_private_key],
45
- type: params[:type].to_s,
46
- generate_apple_certs: params[:generate_apple_certs],
47
- platform: params[:platform].to_s,
48
- google_cloud_bucket_name: params[:google_cloud_bucket_name].to_s,
49
- google_cloud_keys_file: params[:google_cloud_keys_file].to_s,
50
- google_cloud_project_id: params[:google_cloud_project_id].to_s,
51
- skip_google_cloud_account_confirmation: params[:skip_google_cloud_account_confirmation],
52
- s3_region: params[:s3_region],
53
- s3_access_key: params[:s3_access_key],
54
- s3_secret_access_key: params[:s3_secret_access_key],
55
- s3_bucket: params[:s3_bucket],
56
- s3_object_prefix: params[:s3_object_prefix],
57
- gitlab_project: params[:gitlab_project],
58
- gitlab_host: params[:gitlab_host],
59
- readonly: params[:readonly],
60
- username: params[:readonly] ? nil : params[:username], # only pass username if not readonly
61
- team_id: params[:team_id],
62
- team_name: params[:team_name],
63
- api_key_path: params[:api_key_path],
64
- api_key: params[:api_key]
65
- })
34
+ storage_params = params
35
+ storage_params[:username] = params[:readonly] ? nil : params[:username] # only pass username if not readonly
36
+ self.storage = Storage.from_params(storage_params)
66
37
  storage.download
67
38
 
68
39
  # Init the encryption only after the `storage.download` was called to have the right working directory
69
40
  encryption = Encryption.for_storage_mode(params[:storage_mode], {
70
41
  git_url: params[:git_url],
42
+ s3_bucket: params[:s3_bucket],
43
+ s3_skip_encryption: params[:s3_skip_encryption],
71
44
  working_directory: storage.working_directory
72
45
  })
73
46
  encryption.decrypt_files if encryption
@@ -175,7 +148,7 @@ module Match
175
148
  self.files_to_commit << cert_path
176
149
  self.files_to_commit << private_key_path
177
150
  else
178
- cert_path = certs.last
151
+ cert_path = select_cert_or_key(paths: certs)
179
152
 
180
153
  # Check validity of certificate
181
154
  if Utils.is_cert_valid?(cert_path)
@@ -199,7 +172,7 @@ module Match
199
172
  # Import the private key
200
173
  # there seems to be no good way to check if it's already installed - so just install it
201
174
  # Key will only be added to the partition list if it isn't already installed
202
- Utils.import(keys.last, params[:keychain_name], password: params[:keychain_password])
175
+ Utils.import(select_cert_or_key(paths: keys), params[:keychain_name], password: params[:keychain_password])
203
176
  end
204
177
  else
205
178
  UI.message("Skipping installation of certificate as it would not work on this operating system.")
@@ -207,7 +180,7 @@ module Match
207
180
 
208
181
  if params[:output_path]
209
182
  FileUtils.cp(cert_path, params[:output_path])
210
- FileUtils.cp(keys.last, params[:output_path])
183
+ FileUtils.cp(select_cert_or_key(paths: keys), params[:output_path])
211
184
  end
212
185
 
213
186
  # Get and print info of certificate
@@ -218,6 +191,12 @@ module Match
218
191
  return File.basename(cert_path).gsub(".cer", "") # Certificate ID
219
192
  end
220
193
 
194
+ # @return [String] Path to certificate or P12 key
195
+ def select_cert_or_key(paths:)
196
+ cert_id_path = ENV['MATCH_CERTIFICATE_ID'] ? paths.find { |path| path.include?(ENV['MATCH_CERTIFICATE_ID']) } : nil
197
+ cert_id_path || paths.last
198
+ end
199
+
221
200
  # rubocop:disable Metrics/PerceivedComplexity
222
201
  # @return [String] The UUID of the provisioning profile so we can verify it with the Apple Developer Portal
223
202
  def fetch_provisioning_profile(params: nil, certificate_id: nil, app_identifier: nil, working_directory: nil)
@@ -358,7 +337,7 @@ module Match
358
337
  portal_profile = all_profiles.detect { |i| i.uuid == uuid }
359
338
 
360
339
  if portal_profile
361
- profile_device_count = portal_profile.fetch_all_devices.count
340
+ profile_device_count = portal_profile.devices.count
362
341
 
363
342
  device_classes =
364
343
  case platform
@@ -439,7 +418,7 @@ module Match
439
418
  # * For portal certificates, we filter out the expired one but includes a new certificate;
440
419
  # * Profile still contains an expired certificate and is valid.
441
420
  # Thus, we need to check the validity of profile certificates too.
442
- profile_certs_count = portal_profile.fetch_all_certificates.select(&:valid?).count
421
+ profile_certs_count = portal_profile.certificates.select(&:valid?).count
443
422
 
444
423
  certificate_types =
445
424
  case platform
@@ -15,7 +15,7 @@ module Match
15
15
  self.storage_options
16
16
  )
17
17
 
18
- storage = Storage.for_mode(storage_mode, {})
18
+ storage = Storage.from_params({ storage_mode: storage_mode })
19
19
 
20
20
  specific_content = storage.generate_matchfile_content
21
21
  UI.crash!("Looks like `generate_matchfile_content` was `nil` for `#{storage_mode}`") if specific_content.nil?
@@ -59,12 +59,20 @@ module Match
59
59
  self.clone_branch_directly = clone_branch_directly
60
60
  self.git_basic_authorization = git_basic_authorization
61
61
  self.git_bearer_authorization = git_bearer_authorization
62
- self.git_private_key = git_private_key
62
+ self.git_private_key = convert_private_key_path_to_absolute(git_private_key)
63
63
 
64
64
  self.type = type if type
65
65
  self.platform = platform if platform
66
66
  end
67
67
 
68
+ def convert_private_key_path_to_absolute(git_private_key)
69
+ if !git_private_key.nil? && File.file?(File.expand_path(git_private_key))
70
+ File.expand_path(git_private_key).shellescape.to_s
71
+ else
72
+ git_private_key
73
+ end
74
+ end
75
+
68
76
  def prefixed_working_directory
69
77
  return working_directory
70
78
  end
@@ -102,6 +102,12 @@ module Match
102
102
  self.working_directory = Dir.mktmpdir
103
103
 
104
104
  s3_client.find_bucket!(s3_bucket).objects(prefix: s3_object_prefix).each do |object|
105
+
106
+ # Prevent download if the file path is a directory.
107
+ # We need to check if string ends with "/" instead of using `File.directory?` because
108
+ # the string represent a remote location, not a local file in disk.
109
+ next if object.key.end_with?("/")
110
+
105
111
  file_path = strip_s3_object_prefix(object.key) # :s3_object_prefix:team_id/path/to/file
106
112
 
107
113
  # strip s3_prefix from file_path
@@ -10,16 +10,66 @@ module Match
10
10
  def backends
11
11
  @backends ||= {
12
12
  "git" => lambda { |params|
13
- return Storage::GitStorage.configure(params)
13
+ return Storage::GitStorage.configure({
14
+ type: params[:type],
15
+ platform: params[:platform],
16
+ git_url: params[:git_url],
17
+ shallow_clone: params[:shallow_clone],
18
+ skip_docs: params[:skip_docs],
19
+ git_branch: params[:git_branch],
20
+ git_full_name: params[:git_full_name],
21
+ git_user_email: params[:git_user_email],
22
+ clone_branch_directly: params[:clone_branch_directly],
23
+ git_basic_authorization: params[:git_basic_authorization],
24
+ git_bearer_authorization: params[:git_bearer_authorization],
25
+ git_private_key: params[:git_private_key]
26
+ })
14
27
  },
15
28
  "google_cloud" => lambda { |params|
16
- return Storage::GoogleCloudStorage.configure(params)
29
+ return Storage::GoogleCloudStorage.configure({
30
+ type: params[:type],
31
+ platform: params[:platform],
32
+ google_cloud_bucket_name: params[:google_cloud_bucket_name],
33
+ google_cloud_keys_file: params[:google_cloud_keys_file],
34
+ google_cloud_project_id: params[:google_cloud_project_id],
35
+ readonly: params[:readonly],
36
+ username: params[:username],
37
+ team_id: params[:team_id],
38
+ team_name: params[:team_name],
39
+ api_key_path: params[:api_key_path],
40
+ api_key: params[:api_key],
41
+ skip_google_cloud_account_confirmation: params[:skip_google_cloud_account_confirmation]
42
+ })
17
43
  },
18
44
  "s3" => lambda { |params|
19
- return Storage::S3Storage.configure(params)
45
+ return Storage::S3Storage.configure({
46
+ s3_region: params[:s3_region],
47
+ s3_access_key: params[:s3_access_key],
48
+ s3_secret_access_key: params[:s3_secret_access_key],
49
+ s3_bucket: params[:s3_bucket],
50
+ s3_object_prefix: params[:s3_object_prefix],
51
+ readonly: params[:readonly],
52
+ username: params[:username],
53
+ team_id: params[:team_id],
54
+ team_name: params[:team_name],
55
+ api_key_path: params[:api_key_path],
56
+ api_key: params[:api_key]
57
+ })
20
58
  },
21
59
  "gitlab_secure_files" => lambda { |params|
22
- return Storage::GitLabSecureFiles.configure(params)
60
+ return Storage::GitLabSecureFiles.configure({
61
+ gitlab_host: params[:gitlab_host],
62
+ gitlab_project: params[:gitlab_project],
63
+ git_url: params[:git_url], # enables warning about unnecessary git_url
64
+ job_token: params[:job_token],
65
+ private_token: params[:private_token],
66
+ readonly: params[:readonly],
67
+ username: params[:username],
68
+ team_id: params[:team_id],
69
+ team_name: params[:team_name],
70
+ api_key_path: params[:api_key_path],
71
+ api_key: params[:api_key]
72
+ })
23
73
  }
24
74
  }
25
75
  end
@@ -39,7 +89,8 @@ module Match
39
89
  end
40
90
  end
41
91
 
42
- def for_mode(storage_mode, params)
92
+ def from_params(params)
93
+ storage_mode = params[:storage_mode]
43
94
  configurator = backends[storage_mode.to_s]
44
95
  return configurator.call(params) if configurator
45
96
 
@@ -33,7 +33,7 @@ module Precheck
33
33
  connection.use(FaradayMiddleware::FollowRedirects)
34
34
  connection.adapter(:net_http)
35
35
  end
36
- return RuleReturn.new(validation_state: Precheck::VALIDATION_STATES[:failed], failure_data: url) unless request.head.status == 200
36
+ return RuleReturn.new(validation_state: Precheck::VALIDATION_STATES[:failed], failure_data: "HTTP #{request.head.status}: #{url}") unless request.head.status == 200
37
37
  rescue StandardError => e
38
38
  UI.verbose("URL #{url} not reachable 😵: #{e.message}")
39
39
  # I can only return :fail here, but I also want to return #{url}
@@ -15,13 +15,12 @@
15
15
  import Foundation
16
16
  import XCTest
17
17
 
18
- var deviceLanguage = ""
19
- var locale = ""
20
-
18
+ @MainActor
21
19
  func setupSnapshot(_ app: XCUIApplication, waitForAnimations: Bool = true) {
22
20
  Snapshot.setupSnapshot(app, waitForAnimations: waitForAnimations)
23
21
  }
24
22
 
23
+ @MainActor
25
24
  func snapshot(_ name: String, waitForLoadingIndicator: Bool) {
26
25
  if waitForLoadingIndicator {
27
26
  Snapshot.snapshot(name)
@@ -33,6 +32,7 @@ func snapshot(_ name: String, waitForLoadingIndicator: Bool) {
33
32
  /// - Parameters:
34
33
  /// - name: The name of the snapshot
35
34
  /// - timeout: Amount of seconds to wait until the network loading indicator disappears. Pass `0` if you don't want to wait.
35
+ @MainActor
36
36
  func snapshot(_ name: String, timeWaitingForIdle timeout: TimeInterval = 20) {
37
37
  Snapshot.snapshot(name, timeWaitingForIdle: timeout)
38
38
  }
@@ -52,6 +52,7 @@ enum SnapshotError: Error, CustomDebugStringConvertible {
52
52
  }
53
53
 
54
54
  @objcMembers
55
+ @MainActor
55
56
  open class Snapshot: NSObject {
56
57
  static var app: XCUIApplication?
57
58
  static var waitForAnimations = true
@@ -59,6 +60,8 @@ open class Snapshot: NSObject {
59
60
  static var screenshotsDirectory: URL? {
60
61
  return cacheDirectory?.appendingPathComponent("screenshots", isDirectory: true)
61
62
  }
63
+ static var deviceLanguage = ""
64
+ static var currentLocale = ""
62
65
 
63
66
  open class func setupSnapshot(_ app: XCUIApplication, waitForAnimations: Bool = true) {
64
67
 
@@ -103,17 +106,17 @@ open class Snapshot: NSObject {
103
106
 
104
107
  do {
105
108
  let trimCharacterSet = CharacterSet.whitespacesAndNewlines
106
- locale = try String(contentsOf: path, encoding: .utf8).trimmingCharacters(in: trimCharacterSet)
109
+ currentLocale = try String(contentsOf: path, encoding: .utf8).trimmingCharacters(in: trimCharacterSet)
107
110
  } catch {
108
111
  NSLog("Couldn't detect/set locale...")
109
112
  }
110
113
 
111
- if locale.isEmpty && !deviceLanguage.isEmpty {
112
- locale = Locale(identifier: deviceLanguage).identifier
114
+ if currentLocale.isEmpty && !deviceLanguage.isEmpty {
115
+ currentLocale = Locale(identifier: deviceLanguage).identifier
113
116
  }
114
117
 
115
- if !locale.isEmpty {
116
- app.launchArguments += ["-AppleLocale", "\"\(locale)\""]
118
+ if !currentLocale.isEmpty {
119
+ app.launchArguments += ["-AppleLocale", "\"\(currentLocale)\""]
117
120
  }
118
121
  }
119
122
 
@@ -281,6 +284,7 @@ private extension XCUIElementQuery {
281
284
  return self.containing(isNetworkLoadingIndicator)
282
285
  }
283
286
 
287
+ @MainActor
284
288
  var deviceStatusBars: XCUIElementQuery {
285
289
  guard let app = Snapshot.app else {
286
290
  fatalError("XCUIApplication is not set. Please call setupSnapshot(app) before snapshot().")
@@ -306,4 +310,4 @@ private extension CGFloat {
306
310
 
307
311
  // Please don't remove the lines below
308
312
  // They are used to detect outdated configuration files
309
- // SnapshotHelperVersion [1.29]
313
+ // SnapshotHelperVersion [1.30]