fastlane 2.143.0 → 2.147.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +82 -82
  3. data/credentials_manager/lib/credentials_manager/appfile_config.rb +4 -0
  4. data/deliver/lib/deliver/app_screenshot.rb +1 -0
  5. data/deliver/lib/deliver/options.rb +30 -1
  6. data/deliver/lib/deliver/setup.rb +4 -4
  7. data/fastlane/lib/assets/custom_action_template.rb +6 -6
  8. data/fastlane/lib/fastlane/actions/automatic_code_signing.rb +7 -1
  9. data/fastlane/lib/fastlane/actions/clean_build_artifacts.rb +3 -0
  10. data/fastlane/lib/fastlane/actions/cocoapods.rb +1 -1
  11. data/fastlane/lib/fastlane/actions/crashlytics.rb +14 -2
  12. data/fastlane/lib/fastlane/actions/create_pull_request.rb +7 -1
  13. data/fastlane/lib/fastlane/actions/docs/capture_ios_screenshots.md +13 -5
  14. data/fastlane/lib/fastlane/actions/docs/frame_screenshots.md +1 -1
  15. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +3 -3
  16. data/fastlane/lib/fastlane/actions/get_version_number.rb +1 -1
  17. data/fastlane/lib/fastlane/actions/git_branch.rb +1 -1
  18. data/fastlane/lib/fastlane/actions/pod_lib_lint.rb +7 -1
  19. data/fastlane/lib/fastlane/actions/set_pod_key.rb +3 -3
  20. data/fastlane/lib/fastlane/actions/setup_ci.rb +1 -1
  21. data/fastlane/lib/fastlane/actions/setup_jenkins.rb +11 -2
  22. data/fastlane/lib/fastlane/actions/slather.rb +1 -1
  23. data/fastlane/lib/fastlane/actions/swiftlint.rb +28 -7
  24. data/fastlane/lib/fastlane/actions/testfairy.rb +18 -3
  25. data/fastlane/lib/fastlane/actions/update_code_signing_settings.rb +203 -0
  26. data/fastlane/lib/fastlane/actions/upload_symbols_to_crashlytics.rb +1 -1
  27. data/fastlane/lib/fastlane/actions/verify_build.rb +1 -1
  28. data/fastlane/lib/fastlane/actions/verify_xcode.rb +7 -0
  29. data/fastlane/lib/fastlane/commands_generator.rb +4 -1
  30. data/fastlane/lib/fastlane/helper/lane_helper.rb +13 -0
  31. data/fastlane/lib/fastlane/helper/s3_client_helper.rb +14 -9
  32. data/fastlane/lib/fastlane/version.rb +1 -1
  33. data/fastlane/swift/Deliverfile.swift +1 -1
  34. data/fastlane/swift/Fastlane.swift +138 -23
  35. data/fastlane/swift/Gymfile.swift +1 -1
  36. data/fastlane/swift/Matchfile.swift +1 -1
  37. data/fastlane/swift/MatchfileProtocol.swift +6 -2
  38. data/fastlane/swift/Precheckfile.swift +1 -1
  39. data/fastlane/swift/Scanfile.swift +1 -1
  40. data/fastlane/swift/ScanfileProtocol.swift +10 -2
  41. data/fastlane/swift/Screengrabfile.swift +1 -1
  42. data/fastlane/swift/Snapshotfile.swift +1 -1
  43. data/fastlane/swift/SnapshotfileProtocol.swift +9 -1
  44. data/fastlane_core/lib/fastlane_core/configuration/config_item.rb +9 -0
  45. data/fastlane_core/lib/fastlane_core/device_manager.rb +3 -3
  46. data/fastlane_core/lib/fastlane_core/helper.rb +17 -0
  47. data/fastlane_core/lib/fastlane_core/keychain_importer.rb +46 -2
  48. data/fastlane_core/lib/fastlane_core/provisioning_profile.rb +15 -2
  49. data/frameit/lib/frameit/device_types.rb +10 -0
  50. data/frameit/lib/frameit/editor.rb +1 -1
  51. data/frameit/lib/frameit/options.rb +5 -2
  52. data/frameit/lib/frameit/runner.rb +5 -0
  53. data/frameit/lib/frameit/screenshot.rb +5 -0
  54. data/gym/lib/gym/generators/package_command_generator.rb +4 -0
  55. data/gym/lib/gym/generators/package_command_generator_xcode7.rb +5 -0
  56. data/gym/lib/gym/runner.rb +14 -0
  57. data/match/lib/match/change_password.rb +1 -18
  58. data/match/lib/match/encryption/openssl.rb +1 -1
  59. data/match/lib/match/generator.rb +5 -1
  60. data/match/lib/match/importer.rb +35 -18
  61. data/match/lib/match/options.rb +6 -1
  62. data/match/lib/match/storage/s3_storage.rb +10 -5
  63. data/match/lib/match/utils.rb +1 -1
  64. data/pilot/lib/pilot/build_manager.rb +15 -4
  65. data/pilot/lib/pilot/options.rb +8 -0
  66. data/produce/lib/produce/developer_center.rb +11 -2
  67. data/produce/lib/produce/itunes_connect.rb +11 -3
  68. data/produce/lib/produce/options.rb +12 -0
  69. data/scan/lib/scan/options.rb +11 -1
  70. data/scan/lib/scan/runner.rb +2 -0
  71. data/scan/lib/scan/test_command_generator.rb +4 -1
  72. data/screengrab/lib/screengrab/runner.rb +1 -1
  73. data/snapshot/lib/assets/SnapfileTemplate +3 -0
  74. data/snapshot/lib/snapshot/options.rb +10 -0
  75. data/snapshot/lib/snapshot/reports_generator.rb +4 -0
  76. data/snapshot/lib/snapshot/simulator_launchers/launcher_configuration.rb +2 -0
  77. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher.rb +4 -0
  78. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +21 -0
  79. data/snapshot/lib/snapshot/test_command_generator_base.rb +3 -0
  80. data/spaceship/lib/spaceship/base.rb +1 -1
  81. data/spaceship/lib/spaceship/connect_api/model.rb +6 -0
  82. data/spaceship/lib/spaceship/connect_api/models/app.rb +11 -0
  83. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +23 -0
  84. data/spaceship/lib/spaceship/portal/app_service.rb +2 -2
  85. data/spaceship/lib/spaceship/portal/portal_client.rb +13 -0
  86. data/spaceship/lib/spaceship/tunes/app_version.rb +6 -1
  87. data/spaceship/lib/spaceship/tunes/application.rb +2 -1
  88. data/spaceship/lib/spaceship/tunes/iap.rb +15 -0
  89. data/spaceship/lib/spaceship/tunes/tunes_client.rb +16 -2
  90. data/spaceship/lib/spaceship/two_step_or_factor_client.rb +52 -16
  91. data/supply/lib/supply/.client.rb.swp +0 -0
  92. data/supply/lib/supply/client.rb +4 -4
  93. data/supply/lib/supply/setup.rb +5 -3
  94. metadata +40 -32
  95. data/fastlane/lib/fastlane/actions/.hockey.rb.swp +0 -0
  96. data/fastlane/lib/fastlane/actions/.slack.rb.swp +0 -0
  97. data/fastlane/lib/fastlane/actions/.update_project_provisioning.rb.swp +0 -0
  98. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.xcworkspace/xcuserdata/josh.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  99. data/pilot/lib/pilot/.manager.rb.swp +0 -0
  100. data/spaceship/lib/spaceship/connect_api/.DS_Store +0 -0
  101. data/spaceship/lib/spaceship/portal/.certificate.rb.swp +0 -0
@@ -136,6 +136,11 @@ module Gym
136
136
  Gym.cache[:apps_path] ||= File.join(temporary_output_path, "Apps")
137
137
  end
138
138
 
139
+ # The path to the Apps folder
140
+ def asset_packs_path
141
+ Gym.cache[:asset_packs_path] ||= File.join(temporary_output_path, "OnDemandResources")
142
+ end
143
+
139
144
  private
140
145
 
141
146
  def normalize_export_options(hash)
@@ -39,6 +39,7 @@ module Gym
39
39
  move_app_thinning
40
40
  move_app_thinning_size_report
41
41
  move_apps_folder
42
+ move_asset_packs
42
43
  elsif is_mac
43
44
  path = File.expand_path(Gym.config[:output_directory])
44
45
  compress_and_move_dsym
@@ -325,6 +326,19 @@ module Gym
325
326
  end
326
327
  end
327
328
 
329
+ # Move Asset Packs folder to the output directory
330
+ # @return (String) The path to the resulting Asset Packs (aka OnDemandResources) folder
331
+ def move_asset_packs
332
+ if Dir.exist?(PackageCommandGenerator.asset_packs_path)
333
+ FileUtils.mv(PackageCommandGenerator.asset_packs_path, File.expand_path(Gym.config[:output_directory]), force: true)
334
+ asset_packs_path = File.join(File.expand_path(Gym.config[:output_directory]), File.basename(PackageCommandGenerator.asset_packs_path))
335
+
336
+ UI.success("Successfully exported Asset Pack folder:")
337
+ UI.message(asset_packs_path)
338
+ asset_packs_path
339
+ end
340
+ end
341
+
328
342
  def find_archive_path
329
343
  Dir.glob(File.join(BuildCommandGenerator.build_path, "*.ipa")).last
330
344
  end
@@ -16,7 +16,7 @@ module Match
16
16
 
17
17
  ensure_ui_interactive
18
18
 
19
- to = ChangePassword.ask_password(message: "New passphrase for Git Repo: ", confirm: true)
19
+ to = FastlaneCore::Helper.ask_password(message: "New passphrase for Git Repo: ", confirm: true)
20
20
 
21
21
  # Choose the right storage and encryption implementations
22
22
  storage = Storage.for_mode(params[:storage_mode], {
@@ -44,23 +44,6 @@ module Match
44
44
  storage.save_changes!(files_to_commit: files_to_commit, custom_message: message)
45
45
  end
46
46
 
47
- # This method is called from both here, and from `openssl.rb`
48
- def self.ask_password(message: "Passphrase for Match storage: ", confirm: nil)
49
- ensure_ui_interactive
50
- loop do
51
- password = UI.password(message)
52
- if confirm
53
- password2 = UI.password("Type passphrase again: ")
54
- if password == password2
55
- return password
56
- end
57
- else
58
- return password
59
- end
60
- UI.error("Passphrases differ. Try again")
61
- end
62
- end
63
-
64
47
  def self.ensure_ui_interactive
65
48
  raise "This code should only run in interactive mode" unless UI.interactive?
66
49
  end
@@ -99,7 +99,7 @@ module Match
99
99
  UI.important("Enter the passphrase that should be used to encrypt/decrypt your certificates")
100
100
  UI.important("This passphrase is specific per repository and will be stored in your local keychain")
101
101
  UI.important("Make sure to remember the password, as you'll need it when you run match on a different machine")
102
- password = ChangePassword.ask_password(confirm: true)
102
+ password = FastlaneCore::Helper.ask_password(message: "Passphrase for Match storage: ", confirm: true)
103
103
  store_password(password)
104
104
  end
105
105
  end
@@ -60,7 +60,11 @@ module Match
60
60
  names << params[:platform]
61
61
  end
62
62
 
63
- profile_name = names.join(" ")
63
+ if params[:profile_name].to_s.empty?
64
+ profile_name = names.join(" ")
65
+ else
66
+ profile_name = params[:profile_name]
67
+ end
64
68
 
65
69
  values = {
66
70
  app_identifier: app_identifier,
@@ -2,23 +2,16 @@ require_relative 'spaceship_ensure'
2
2
  require_relative 'encryption'
3
3
  require_relative 'storage'
4
4
  require_relative 'module'
5
+ require 'fastlane_core/provisioning_profile'
5
6
  require 'fileutils'
6
7
 
7
8
  module Match
8
9
  class Importer
9
- def import_cert(params, cert_path: nil, p12_path: nil)
10
- # Get and verify cert and p12 path
11
- cert_path ||= UI.input("Certificate (.cer) path:")
12
- p12_path ||= UI.input("Private key (.p12) path:")
13
-
14
- cert_path = File.absolute_path(cert_path)
15
- p12_path = File.absolute_path(p12_path)
16
-
17
- UI.user_error!("Certificate does not exist at path: #{cert_path}") unless File.exist?(cert_path)
18
- UI.user_error!("Private key does not exist at path: #{p12_path}") unless File.exist?(p12_path)
19
-
20
- # Base64 encode contents to find match from API to find a cert ID
21
- cert_contents_base_64 = Base64.strict_encode64(File.open(cert_path).read)
10
+ def import_cert(params, cert_path: nil, p12_path: nil, profile_path: nil)
11
+ # Get and verify cert, p12 and profiles path
12
+ cert_path = ensure_valid_file_path(cert_path, "Certificate", ".cer")
13
+ p12_path = ensure_valid_file_path(p12_path, "Private key", ".p12")
14
+ profile_path = ensure_valid_file_path(profile_path, "Provisioning profile", ".mobileprovision or .provisionprofile", optional: true)
22
15
 
23
16
  # Storage
24
17
  storage = Storage.for_mode(params[:storage_mode], {
@@ -57,17 +50,22 @@ module Match
57
50
  certificate_type = Spaceship::ConnectAPI::Certificate::CertificateType::IOS_DEVELOPMENT + "," + Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPMENT
58
51
  when :distribution, :enterprise
59
52
  certificate_type = Spaceship::ConnectAPI::Certificate::CertificateType::IOS_DISTRIBUTION + "," + Spaceship::ConnectAPI::Certificate::CertificateType::DISTRIBUTION
53
+ when :developer_id_application
54
+ certificate_type = Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPER_ID_APPLICATION
60
55
  else
61
56
  UI.user_error!("Cert type '#{cert_type}' is not supported")
62
57
  end
63
58
 
64
- output_dir = File.join(storage.prefixed_working_directory, "certs", cert_type.to_s)
59
+ output_dir_certs = File.join(storage.prefixed_working_directory, "certs", cert_type.to_s)
60
+ output_dir_profiles = File.join(storage.prefixed_working_directory, "profiles", cert_type.to_s)
65
61
 
66
62
  # Need to get the cert id by comparing base64 encoded cert content with certificate content from the API responses
67
63
  Spaceship::Portal.login(params[:username])
68
64
  Spaceship::Portal.select_team(team_id: params[:team_id], team_name: params[:team_name])
69
65
  certs = Spaceship::ConnectAPI::Certificate.all(filter: { certificateType: certificate_type })
70
66
 
67
+ # Base64 encode contents to find match from API to find a cert ID
68
+ cert_contents_base_64 = Base64.strict_encode64(File.binread(cert_path))
71
69
  matching_cert = certs.find do |cert|
72
70
  cert.certificate_content == cert_contents_base_64
73
71
  end
@@ -75,18 +73,37 @@ module Match
75
73
  UI.user_error!("This certificate cannot be imported - the certificate contents did not match with any available on the Developer Portal") if matching_cert.nil?
76
74
 
77
75
  # Make dir if doesn't exist
78
- FileUtils.mkdir_p(output_dir)
79
- dest_cert_path = File.join(output_dir, "#{matching_cert.id}.cer")
80
- dest_p12_path = File.join(output_dir, "#{matching_cert.id}.p12")
76
+ FileUtils.mkdir_p(output_dir_certs)
77
+ dest_cert_path = File.join(output_dir_certs, "#{matching_cert.id}.cer")
78
+ dest_p12_path = File.join(output_dir_certs, "#{matching_cert.id}.p12")
79
+
80
+ files_to_commit = [dest_cert_path, dest_p12_path]
81
81
 
82
82
  # Copy files
83
83
  IO.copy_stream(cert_path, dest_cert_path)
84
84
  IO.copy_stream(p12_path, dest_p12_path)
85
- files_to_commit = [dest_cert_path, dest_p12_path]
85
+ unless profile_path.nil?
86
+ FileUtils.mkdir_p(output_dir_profiles)
87
+ bundle_id = FastlaneCore::ProvisioningProfile.bundle_id(profile_path)
88
+ profile_extension = FastlaneCore::ProvisioningProfile.profile_extension(profile_path)
89
+ dest_profile_path = File.join(output_dir_profiles, "#{cert_type.to_s.capitalize}_#{bundle_id}#{profile_extension}")
90
+ files_to_commit.push(dest_profile_path)
91
+ IO.copy_stream(profile_path, dest_profile_path)
92
+ end
86
93
 
87
94
  # Encrypt and commit
88
95
  encryption.encrypt_files if encryption
89
96
  storage.save_changes!(files_to_commit: files_to_commit)
90
97
  end
98
+
99
+ def ensure_valid_file_path(file_path, file_description, file_extension, optional: false)
100
+ optional_file_message = optional ? " or leave empty to skip this file" : ""
101
+ file_path ||= UI.input("#{file_description} (#{file_extension}) path#{optional_file_message}:")
102
+
103
+ file_path = File.absolute_path(file_path) unless file_path == ""
104
+ file_path = File.exist?(file_path) ? file_path : nil
105
+ UI.user_error!("#{file_description} does not exist at path: #{file_path}") unless !file_path.nil? || optional
106
+ file_path
107
+ end
91
108
  end
92
109
  end
@@ -170,7 +170,7 @@ module Match
170
170
  optional: true),
171
171
  FastlaneCore::ConfigItem.new(key: :s3_secret_access_key,
172
172
  env_name: "MATCH_S3_SECRET_ACCESS_KEY",
173
- description: "S3 secret secret access key",
173
+ description: "S3 secret access key",
174
174
  optional: true),
175
175
  FastlaneCore::ConfigItem.new(key: :s3_bucket,
176
176
  env_name: "MATCH_S3_BUCKET",
@@ -226,6 +226,11 @@ module Match
226
226
  description: "The name of provisioning profile template. If the developer account has provisioning profile templates (aka: custom entitlements), the template name can be found by inspecting the Entitlements drop-down while creating/editing a provisioning profile (e.g. \"Apple Pay Pass Suppression Development\")",
227
227
  optional: true,
228
228
  default_value: nil),
229
+ FastlaneCore::ConfigItem.new(key: :profile_name,
230
+ env_name: "MATCH_PROVISIONING_PROFILE_NAME",
231
+ description: "A custom name for the provisioning profile. This will replace the default provisioning profile name if specified",
232
+ optional: true,
233
+ default_value: nil),
229
234
  FastlaneCore::ConfigItem.new(key: :output_path,
230
235
  env_name: "MATCH_OUTPUT_PATH",
231
236
  description: "Path in which to export certificates, key and profile",
@@ -89,7 +89,7 @@ module Match
89
89
  self.working_directory = Dir.mktmpdir
90
90
 
91
91
  s3_client.find_bucket!(s3_bucket).objects.each do |object|
92
- file_path = object.public_url.to_s.split("s3.amazonaws.com/").last
92
+ file_path = object.key # :team_id/path/to/file
93
93
  download_path = File.join(self.working_directory, file_path)
94
94
 
95
95
  FileUtils.mkdir_p(File.expand_path("..", download_path))
@@ -111,17 +111,17 @@ module Match
111
111
  # Those doesn't mean they're new, it might just be they're changed
112
112
  # Either way, we'll upload them using the same technique
113
113
 
114
- files_to_upload.each do |current_file|
114
+ files_to_upload.each do |file_name|
115
115
  # Go from
116
116
  # "/var/folders/px/bz2kts9n69g8crgv4jpjh6b40000gn/T/d20181026-96528-1av4gge/profiles/development/Development_me.mobileprovision"
117
117
  # to
118
118
  # "profiles/development/Development_me.mobileprovision"
119
119
  #
120
120
 
121
- target_path = current_file.gsub(self.working_directory + "/", "")
121
+ target_path = sanitize_file_name(file_name)
122
122
  UI.verbose("Uploading '#{target_path}' to S3 Storage...")
123
123
 
124
- body = File.read(current_file)
124
+ body = File.read(file_name)
125
125
  acl = 'private'
126
126
  s3_url = s3_client.upload_file(s3_bucket, target_path, body, acl)
127
127
  UI.verbose("Uploaded '#{s3_url}' to S3 Storage.")
@@ -130,7 +130,8 @@ module Match
130
130
 
131
131
  def delete_files(files_to_delete: [], custom_message: nil)
132
132
  files_to_delete.each do |file_name|
133
- s3_client.delete_file(s3_bucket, file_name)
133
+ target_path = sanitize_file_name(file_name)
134
+ s3_client.delete_file(s3_bucket, target_path)
134
135
  end
135
136
  end
136
137
 
@@ -147,6 +148,10 @@ module Match
147
148
 
148
149
  private
149
150
 
151
+ def sanitize_file_name(file_name)
152
+ file_name.gsub(self.working_directory + "/", "")
153
+ end
154
+
150
155
  def currently_used_team_id
151
156
  if self.readonly
152
157
  # In readonly mode, we still want to see if the user provided a team_id
@@ -4,7 +4,7 @@ require_relative 'module'
4
4
 
5
5
  module Match
6
6
  class Utils
7
- def self.import(item_path, keychain, password: "")
7
+ def self.import(item_path, keychain, password: nil)
8
8
  keychain_path = FastlaneCore::Helper.keychain_path(keychain)
9
9
  FastlaneCore::KeychainImporter.import_file(item_path, keychain_path, keychain_password: password, output: FastlaneCore::Globals.verbose?)
10
10
  end
@@ -118,9 +118,17 @@ module Pilot
118
118
 
119
119
  # Get latest uploaded build if no build specified
120
120
  if build.nil?
121
- UI.important("No build specified - fetching latest build")
121
+ app_version = config[:app_version]
122
+ build_number = config[:build_number]
123
+ if build_number.nil?
124
+ if app_version.nil?
125
+ UI.important("No build specified - fetching latest build")
126
+ else
127
+ UI.important("No build specified - fetching latest build for version #{app_version}")
128
+ end
129
+ end
122
130
  platform = Spaceship::ConnectAPI::Platform.map(fetch_app_platform)
123
- build ||= Spaceship::ConnectAPI::Build.all(app_id: app.id, sort: "-uploadedDate", platform: platform, limit: 1).first
131
+ build ||= Spaceship::ConnectAPI::Build.all(app_id: app.id, version: app_version, build_number: build_number, sort: "-uploadedDate", platform: platform, limit: 1).first
124
132
  end
125
133
 
126
134
  # Verify the build has all the includes that we need
@@ -207,8 +215,11 @@ module Pilot
207
215
  end
208
216
 
209
217
  def update_beta_app_meta(options, build)
210
- # Setting account required wth AppStore Connect API
211
- update_review_detail(build, { demo_account_required: options[:demo_account_required] })
218
+ # If demo_account_required is a parameter, it should added into beta_app_review_info
219
+ unless options[:demo_account_required].nil?
220
+ options[:beta_app_review_info] = {} if options[:beta_app_review_info].nil?
221
+ options[:beta_app_review_info][:demo_account_required] = options[:demo_account_required]
222
+ end
212
223
 
213
224
  if should_update_beta_app_review_info(options)
214
225
  update_review_detail(build, options[:beta_app_review_info])
@@ -162,6 +162,14 @@ module Pilot
162
162
  env_name: "PILOT_NOTIFY_EXTERNAL_TESTERS",
163
163
  description: "Should notify external testers?",
164
164
  default_value: true),
165
+ FastlaneCore::ConfigItem.new(key: :app_version,
166
+ env_name: "PILOT_APP_VERSION",
167
+ description: "The version number of the application build to distribute. If the version number is not specified, then the most recent build uploaded to TestFlight will be distributed. If specified, the most recent build for the version number will be distributed",
168
+ optional: true),
169
+ FastlaneCore::ConfigItem.new(key: :build_number,
170
+ env_name: "PILOT_BUILD_NUMBER",
171
+ description: "The build number of the application build to distribute. If the build number is not specified, the most recent build is distributed",
172
+ optional: true),
165
173
 
166
174
  # testers
167
175
  FastlaneCore::ConfigItem.new(key: :first_name,
@@ -59,7 +59,7 @@ module Produce
59
59
  app = Spaceship.app.create!(bundle_id: app_identifier,
60
60
  name: app_name,
61
61
  enable_services: enable_services,
62
- mac: Produce.config[:platform] == "osx")
62
+ mac: platform == "osx")
63
63
 
64
64
  if app.name != Produce.config[:app_name]
65
65
  UI.important("Your app name includes non-ASCII characters, which are not supported by the Apple Developer Portal.")
@@ -122,8 +122,17 @@ module Produce
122
122
 
123
123
  private
124
124
 
125
+ def platform
126
+ # This was added to support creation of multiple platforms
127
+ # Produce::ItunesConnect can take an array of platforms to create for App Store Connect
128
+ # but the Developer Center is now platform agnostic so we choose any platform here
129
+ #
130
+ # Platform won't be needed at all in the future when this is change over to use Spaceship::ConnectAPI
131
+ (Produce.config[:platforms] || []).first || Produce.config[:platform]
132
+ end
133
+
125
134
  def app_exists?
126
- Spaceship.app.find(app_identifier, mac: Produce.config[:platform] == "osx") != nil
135
+ Spaceship.app.find(app_identifier, mac: platform == "osx") != nil
127
136
  end
128
137
 
129
138
  def login
@@ -23,6 +23,8 @@ module Produce
23
23
  else
24
24
  UI.success("Creating new app '#{Produce.config[:app_name]}' on App Store Connect")
25
25
 
26
+ platforms = Produce.config[:platforms] || [Produce.config[:platform]]
27
+
26
28
  Produce.config[:bundle_identifier_suffix] = '' unless wildcard_bundle?
27
29
  generated_app = Spaceship::Tunes::Application.create!(name: Produce.config[:app_name],
28
30
  primary_language: language,
@@ -30,7 +32,7 @@ module Produce
30
32
  bundle_id: app_identifier,
31
33
  bundle_id_suffix: Produce.config[:bundle_identifier_suffix],
32
34
  company_name: Produce.config[:company_name],
33
- platform: Produce.config[:platform],
35
+ platforms: platforms,
34
36
  itunes_connect_users: Produce.config[:itc_users])
35
37
 
36
38
  UI.crash!("Something went wrong when creating the new app on iTC") if generated_app["adamId"].to_s.empty?
@@ -51,16 +53,22 @@ module Produce
51
53
  UI.crash!("Something went wrong when creating the new app - it's not listed in the App's list") unless application
52
54
 
53
55
  UI.message("Ensuring version number")
54
- application.ensure_version!(Produce.config[:app_version], platform: Produce.config[:platform]) if Produce.config[:app_version]
56
+ platforms.each do |platform|
57
+ application.ensure_version!(Produce.config[:app_version], platform: platform) if Produce.config[:app_version]
58
+ end
55
59
 
56
60
  UI.success("Successfully created new app '#{Produce.config[:app_name]}' on App Store Connect with ID #{application.apple_id}")
57
61
  end
58
62
 
59
- return Spaceship::Tunes::Application.find(@full_bundle_identifier, mac: Produce.config[:platform] == "osx").apple_id
63
+ return Spaceship::Tunes::Application.find(@full_bundle_identifier, mac: platform == "osx").apple_id
60
64
  end
61
65
 
62
66
  private
63
67
 
68
+ def platform
69
+ (Produce.config[:platforms] || []).first || Produce.config[:platform]
70
+ end
71
+
64
72
  def fetch_application
65
73
  Spaceship::Tunes::Application.find(@full_bundle_identifier)
66
74
  end
@@ -50,11 +50,23 @@ module Produce
50
50
  short_option: "-j",
51
51
  env_name: "PRODUCE_PLATFORM",
52
52
  description: "The platform to use (optional)",
53
+ conflicting_options: [:platforms],
53
54
  optional: true,
54
55
  default_value: "ios",
55
56
  verify_block: proc do |value|
56
57
  UI.user_error!("The platform can only be ios or osx") unless %('ios', 'osx').include?(value)
57
58
  end),
59
+ FastlaneCore::ConfigItem.new(key: :platforms,
60
+ short_option: "-J",
61
+ env_name: "PRODUCE_PLATFORMS",
62
+ description: "The platforms to use (optional)",
63
+ conflicting_options: [:platform],
64
+ optional: true,
65
+ type: Array,
66
+ verify_block: proc do |values|
67
+ types = %w(ios osx)
68
+ UI.user_error!("The platform can only be #{types}") unless (values - types).empty?
69
+ end),
58
70
  FastlaneCore::ConfigItem.new(key: :language,
59
71
  short_option: "-m",
60
72
  env_name: "PRODUCE_LANGUAGE",
@@ -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",
@@ -175,6 +180,11 @@ module Scan
175
180
  description: "Should the HTML report be opened when tests are completed?",
176
181
  is_string: false,
177
182
  default_value: false),
183
+ FastlaneCore::ConfigItem.new(key: :disable_xcpretty,
184
+ env_name: "SCAN_DISABLE_XCPRETTY",
185
+ description: "Disable xcpretty formatting of build, similar to `output_style='raw'` but this will also skip the test results table",
186
+ type: Boolean,
187
+ optional: true),
178
188
  FastlaneCore::ConfigItem.new(key: :output_directory,
179
189
  short_option: "-o",
180
190
  env_name: "SCAN_OUTPUT_DIRECTORY",
@@ -186,7 +196,7 @@ module Scan
186
196
  FastlaneCore::ConfigItem.new(key: :output_style,
187
197
  short_option: "-b",
188
198
  env_name: "SCAN_OUTPUT_STYLE",
189
- description: "Define how the output should look like. Valid values are: standard, basic, rspec, or raw (disables xcpretty)",
199
+ description: "Define how the output should look like. Valid values are: standard, basic, rspec, or raw (disables xcpretty during xcodebuild)",
190
200
  optional: true,
191
201
  verify_block: proc do |value|
192
202
  UI.user_error!("Invalid output_style #{value}") unless ['standard', 'basic', 'rspec', 'raw'].include?(value)