fastlane 2.196.0 → 2.212.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (211) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +88 -81
  4. data/cert/lib/cert/runner.rb +19 -8
  5. data/deliver/lib/assets/ScreenshotsHelp +29 -6
  6. data/deliver/lib/deliver/app_screenshot.rb +30 -4
  7. data/deliver/lib/deliver/app_screenshot_iterator.rb +1 -1
  8. data/deliver/lib/deliver/options.rb +6 -2
  9. data/deliver/lib/deliver/runner.rb +88 -24
  10. data/deliver/lib/deliver/submit_for_review.rb +25 -3
  11. data/deliver/lib/deliver/upload_price_tier.rb +3 -1
  12. data/deliver/lib/deliver/upload_screenshots.rb +2 -2
  13. data/fastlane/lib/assets/AppfileTemplate +1 -1
  14. data/fastlane/lib/assets/AppfileTemplate.swift +1 -1
  15. data/fastlane/lib/fastlane/actions/badge.rb +1 -1
  16. data/fastlane/lib/fastlane/actions/changelog_from_git_commits.rb +1 -1
  17. data/fastlane/lib/fastlane/actions/danger.rb +14 -0
  18. data/fastlane/lib/fastlane/actions/docs/build_app.md +5 -5
  19. data/fastlane/lib/fastlane/actions/docs/capture_android_screenshots.md +19 -2
  20. data/fastlane/lib/fastlane/actions/docs/frame_screenshots.md +1 -1
  21. data/fastlane/lib/fastlane/actions/docs/run_tests.md +1 -1
  22. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +1 -1
  23. data/fastlane/lib/fastlane/actions/download_dsyms.rb +62 -46
  24. data/fastlane/lib/fastlane/actions/ensure_git_status_clean.rb +15 -4
  25. data/fastlane/lib/fastlane/actions/ensure_xcode_version.rb +1 -1
  26. data/fastlane/lib/fastlane/actions/get_push_certificate.rb +1 -1
  27. data/fastlane/lib/fastlane/actions/get_version_number.rb +8 -3
  28. data/fastlane/lib/fastlane/actions/git_commit.rb +4 -6
  29. data/fastlane/lib/fastlane/actions/import_certificate.rb +1 -1
  30. data/fastlane/lib/fastlane/actions/notarize.rb +29 -11
  31. data/fastlane/lib/fastlane/actions/pod_lib_lint.rb +1 -1
  32. data/fastlane/lib/fastlane/actions/pod_push.rb +19 -1
  33. data/fastlane/lib/fastlane/actions/read_podspec.rb +1 -1
  34. data/fastlane/lib/fastlane/actions/run_tests.rb +19 -9
  35. data/fastlane/lib/fastlane/actions/set_github_release.rb +11 -5
  36. data/fastlane/lib/fastlane/actions/setup_ci.rb +13 -4
  37. data/fastlane/lib/fastlane/actions/trainer.rb +49 -0
  38. data/fastlane/lib/fastlane/actions/update_code_signing_settings.rb +31 -4
  39. data/fastlane/lib/fastlane/actions/update_info_plist.rb +1 -1
  40. data/fastlane/lib/fastlane/actions/update_project_provisioning.rb +10 -1
  41. data/fastlane/lib/fastlane/actions/upload_symbols_to_sentry.rb +1 -1
  42. data/fastlane/lib/fastlane/actions/verify_build.rb +1 -1
  43. data/fastlane/lib/fastlane/actions/xcode_install.rb +5 -1
  44. data/fastlane/lib/fastlane/actions/xcode_select.rb +1 -1
  45. data/fastlane/lib/fastlane/actions/xcodebuild.rb +8 -2
  46. data/fastlane/lib/fastlane/actions/xcodes.rb +152 -0
  47. data/fastlane/lib/fastlane/actions/xcov.rb +5 -0
  48. data/fastlane/lib/fastlane/actions/xcversion.rb +17 -7
  49. data/fastlane/lib/fastlane/cli_tools_distributor.rb +5 -0
  50. data/fastlane/lib/fastlane/commands_generator.rb +2 -1
  51. data/fastlane/lib/fastlane/documentation/docs_generator.rb +17 -12
  52. data/fastlane/lib/fastlane/fast_file.rb +18 -5
  53. data/fastlane/lib/fastlane/features.rb +3 -0
  54. data/fastlane/lib/fastlane/helper/xcodebuild_formatter_helper.rb +9 -0
  55. data/fastlane/lib/fastlane/helper/xcodes_helper.rb +28 -0
  56. data/fastlane/lib/fastlane/helper/xcversion_helper.rb +0 -9
  57. data/fastlane/lib/fastlane/lane_manager.rb +1 -1
  58. data/fastlane/lib/fastlane/plugins/template/%gem_name%.gemspec.erb +1 -1
  59. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +5 -1
  60. data/fastlane/lib/fastlane/setup/setup_ios.rb +1 -1
  61. data/fastlane/lib/fastlane/swift_fastlane_api_generator.rb +1 -1
  62. data/fastlane/lib/fastlane/swift_lane_manager.rb +11 -3
  63. data/fastlane/lib/fastlane/swift_runner_upgrader.rb +54 -1
  64. data/fastlane/lib/fastlane/tools.rb +18 -1
  65. data/fastlane/lib/fastlane/version.rb +1 -1
  66. data/fastlane/swift/Actions.swift +1 -1
  67. data/fastlane/swift/Appfile.swift +2 -2
  68. data/fastlane/swift/ArgumentProcessor.swift +1 -1
  69. data/fastlane/swift/Atomic.swift +150 -0
  70. data/fastlane/swift/ControlCommand.swift +1 -1
  71. data/fastlane/swift/Deliverfile.swift +2 -2
  72. data/fastlane/swift/DeliverfileProtocol.swift +8 -4
  73. data/fastlane/swift/Fastlane.swift +570 -239
  74. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.pbxproj +30 -20
  75. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/xcshareddata/xcschemes/FastlaneRunner.xcscheme +1 -1
  76. data/fastlane/swift/Gymfile.swift +2 -2
  77. data/fastlane/swift/GymfileProtocol.swift +20 -8
  78. data/fastlane/swift/LaneFileProtocol.swift +2 -2
  79. data/fastlane/swift/MainProcess.swift +3 -3
  80. data/fastlane/swift/Matchfile.swift +2 -2
  81. data/fastlane/swift/MatchfileProtocol.swift +21 -5
  82. data/fastlane/swift/OptionalConfigValue.swift +1 -1
  83. data/fastlane/swift/Plugins.swift +1 -1
  84. data/fastlane/swift/Precheckfile.swift +2 -2
  85. data/fastlane/swift/PrecheckfileProtocol.swift +3 -3
  86. data/fastlane/swift/RubyCommand.swift +1 -1
  87. data/fastlane/swift/RubyCommandable.swift +1 -1
  88. data/fastlane/swift/Runner.swift +13 -9
  89. data/fastlane/swift/RunnerArgument.swift +1 -1
  90. data/fastlane/swift/Scanfile.swift +2 -2
  91. data/fastlane/swift/ScanfileProtocol.swift +31 -11
  92. data/fastlane/swift/Screengrabfile.swift +2 -2
  93. data/fastlane/swift/ScreengrabfileProtocol.swift +3 -3
  94. data/fastlane/swift/Snapshotfile.swift +2 -2
  95. data/fastlane/swift/SnapshotfileProtocol.swift +12 -8
  96. data/fastlane/swift/SocketClient.swift +9 -5
  97. data/fastlane/swift/SocketClientDelegateProtocol.swift +2 -2
  98. data/fastlane/swift/SocketResponse.swift +1 -1
  99. data/fastlane/swift/formatting/Brewfile.lock.json +46 -23
  100. data/fastlane/swift/main.swift +1 -1
  101. data/fastlane/swift/upgrade_manifest.json +1 -1
  102. data/fastlane_core/README.md +1 -0
  103. data/fastlane_core/lib/fastlane_core/cert_checker.rb +79 -17
  104. data/fastlane_core/lib/fastlane_core/device_manager.rb +5 -1
  105. data/fastlane_core/lib/fastlane_core/ipa_file_analyser.rb +10 -5
  106. data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +409 -26
  107. data/fastlane_core/lib/fastlane_core/keychain_importer.rb +1 -0
  108. data/fastlane_core/lib/fastlane_core/project.rb +19 -2
  109. data/fastlane_core/lib/fastlane_core/ui/fastlane_runner.rb +7 -0
  110. data/fastlane_core/lib/fastlane_core/ui/implementations/shell.rb +4 -2
  111. data/frameit/lib/frameit/device.rb +1 -1
  112. data/frameit/lib/frameit/device_types.rb +9 -0
  113. data/frameit/lib/frameit/editor.rb +16 -18
  114. data/frameit/lib/frameit/frame_downloader.rb +1 -1
  115. data/frameit/lib/frameit/trim_box.rb +6 -0
  116. data/gym/lib/gym/generators/build_command_generator.rb +70 -23
  117. data/gym/lib/gym/options.rb +30 -5
  118. data/match/lib/match/change_password.rb +2 -0
  119. data/match/lib/match/commands_generator.rb +2 -1
  120. data/match/lib/match/encryption/openssl.rb +1 -1
  121. data/match/lib/match/encryption.rb +3 -0
  122. data/match/lib/match/generator.rb +1 -0
  123. data/match/lib/match/importer.rb +10 -1
  124. data/match/lib/match/migrate.rb +4 -3
  125. data/match/lib/match/module.rb +54 -2
  126. data/match/lib/match/nuke.rb +114 -47
  127. data/match/lib/match/options.rb +22 -1
  128. data/match/lib/match/runner.rb +25 -6
  129. data/match/lib/match/setup.rb +1 -1
  130. data/match/lib/match/spaceship_ensure.rb +5 -2
  131. data/match/lib/match/storage/gitlab/client.rb +102 -0
  132. data/match/lib/match/storage/gitlab/secure_file.rb +65 -0
  133. data/match/lib/match/storage/gitlab_secure_files.rb +182 -0
  134. data/match/lib/match/storage/google_cloud_storage.rb +7 -6
  135. data/match/lib/match/storage/s3_storage.rb +3 -3
  136. data/match/lib/match/storage.rb +4 -0
  137. data/match/lib/match/table_printer.rb +2 -1
  138. data/match/lib/match/utils.rb +15 -2
  139. data/pem/lib/pem/manager.rb +30 -7
  140. data/pem/lib/pem/options.rb +9 -0
  141. data/pilot/lib/pilot/build_manager.rb +34 -14
  142. data/pilot/lib/pilot/options.rb +6 -1
  143. data/scan/lib/scan/detect_values.rb +6 -0
  144. data/scan/lib/scan/error_handler.rb +9 -0
  145. data/scan/lib/scan/options.rb +49 -9
  146. data/scan/lib/scan/runner.rb +171 -25
  147. data/scan/lib/scan/test_command_generator.rb +65 -5
  148. data/sigh/lib/sigh/download_all.rb +14 -2
  149. data/sigh/lib/sigh/module.rb +3 -1
  150. data/sigh/lib/sigh/options.rb +5 -0
  151. data/sigh/lib/sigh/runner.rb +12 -2
  152. data/snapshot/lib/assets/SnapshotHelper.swift +3 -3
  153. data/snapshot/lib/snapshot/latest_os_version.rb +2 -5
  154. data/snapshot/lib/snapshot/options.rb +24 -8
  155. data/snapshot/lib/snapshot/reports_generator.rb +1 -0
  156. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +10 -3
  157. data/snapshot/lib/snapshot/test_command_generator.rb +37 -2
  158. data/spaceship/lib/spaceship/client.rb +71 -40
  159. data/spaceship/lib/spaceship/commands_generator.rb +1 -1
  160. data/spaceship/lib/spaceship/connect_api/api_client.rb +10 -5
  161. data/spaceship/lib/spaceship/connect_api/models/actor.rb +26 -0
  162. data/spaceship/lib/spaceship/connect_api/models/app.rb +52 -6
  163. data/spaceship/lib/spaceship/connect_api/models/app_info.rb +1 -0
  164. data/spaceship/lib/spaceship/connect_api/models/app_info_localization.rb +5 -0
  165. data/spaceship/lib/spaceship/connect_api/models/app_screenshot_set.rb +7 -0
  166. data/spaceship/lib/spaceship/connect_api/models/app_store_version.rb +1 -1
  167. data/spaceship/lib/spaceship/connect_api/models/app_store_version_localization.rb +27 -10
  168. data/spaceship/lib/spaceship/connect_api/models/build.rb +4 -2
  169. data/spaceship/lib/spaceship/connect_api/models/build_bundle.rb +68 -0
  170. data/spaceship/lib/spaceship/connect_api/models/build_bundle_file_sizes.rb +34 -0
  171. data/spaceship/lib/spaceship/connect_api/models/build_delivery.rb +2 -1
  172. data/spaceship/lib/spaceship/connect_api/models/certificate.rb +4 -0
  173. data/spaceship/lib/spaceship/connect_api/models/device.rb +47 -4
  174. data/spaceship/lib/spaceship/connect_api/models/profile.rb +4 -0
  175. data/spaceship/lib/spaceship/connect_api/models/resolution_center_message.rb +29 -0
  176. data/spaceship/lib/spaceship/connect_api/models/resolution_center_thread.rb +67 -0
  177. data/spaceship/lib/spaceship/connect_api/models/review_rejection.rb +19 -0
  178. data/spaceship/lib/spaceship/connect_api/models/review_submission.rb +86 -0
  179. data/spaceship/lib/spaceship/connect_api/models/review_submission_item.rb +40 -0
  180. data/spaceship/lib/spaceship/connect_api/models/user.rb +5 -0
  181. data/spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb +19 -0
  182. data/spaceship/lib/spaceship/connect_api/response.rb +23 -6
  183. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +33 -2
  184. data/spaceship/lib/spaceship/connect_api/token.rb +5 -2
  185. data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +124 -8
  186. data/spaceship/lib/spaceship/connect_api.rb +9 -0
  187. data/spaceship/lib/spaceship/errors.rb +34 -0
  188. data/spaceship/lib/spaceship/globals.rb +9 -0
  189. data/spaceship/lib/spaceship/hashcash.rb +52 -0
  190. data/spaceship/lib/spaceship/portal/certificate.rb +4 -3
  191. data/spaceship/lib/spaceship/spaceauth_runner.rb +1 -1
  192. data/spaceship/lib/spaceship/tunes/app_ratings.rb +6 -6
  193. data/spaceship/lib/spaceship/tunes/iap_families.rb +1 -1
  194. data/spaceship/lib/spaceship/tunes/tunes.rb +0 -1
  195. data/spaceship/lib/spaceship/tunes/tunes_client.rb +79 -21
  196. data/spaceship/lib/spaceship/two_step_or_factor_client.rb +11 -3
  197. data/spaceship/lib/spaceship.rb +1 -0
  198. data/supply/lib/supply/client.rb +2 -7
  199. data/supply/lib/supply/options.rb +8 -0
  200. data/supply/lib/supply/uploader.rb +6 -2
  201. data/trainer/lib/assets/junit.xml.erb +28 -0
  202. data/trainer/lib/trainer/commands_generator.rb +51 -0
  203. data/trainer/lib/trainer/junit_generator.rb +31 -0
  204. data/trainer/lib/trainer/module.rb +10 -0
  205. data/trainer/lib/trainer/options.rb +66 -0
  206. data/trainer/lib/trainer/test_parser.rb +398 -0
  207. data/trainer/lib/trainer/xcresult.rb +403 -0
  208. data/trainer/lib/trainer.rb +7 -0
  209. metadata +49 -24
  210. data/spaceship/lib/spaceship/connect_api/testflight/.testflight.rb.swp +0 -0
  211. data/spaceship/lib/spaceship/tunes/user_detail.rb +0 -15
@@ -12,11 +12,18 @@ module Fastlane
12
12
  require 'net/http'
13
13
  require 'date'
14
14
 
15
- # Team selection passed though FASTLANE_ITC_TEAM_ID and FASTLANE_ITC_TEAM_NAME environment variables
16
- # Prompts select team if multiple teams and none specified
17
- UI.message("Login to App Store Connect (#{params[:username]})")
18
- Spaceship::ConnectAPI.login(params[:username], use_portal: false, use_tunes: true)
19
- UI.message("Login successful")
15
+ if (api_token = Spaceship::ConnectAPI::Token.from(hash: params[:api_key], filepath: params[:api_key_path]))
16
+ UI.message("Creating authorization token for App Store Connect API")
17
+ Spaceship::ConnectAPI.token = api_token
18
+ elsif !Spaceship::ConnectAPI.token.nil?
19
+ UI.message("Using existing authorization token for App Store Connect API")
20
+ else
21
+ # Team selection passed though FASTLANE_ITC_TEAM_ID and FASTLANE_ITC_TEAM_NAME environment variables
22
+ # Prompts select team if multiple teams and none specified
23
+ UI.message("Login to App Store Connect (#{params[:username]})")
24
+ Spaceship::ConnectAPI.login(params[:username], use_portal: false, use_tunes: true)
25
+ UI.message("Login successful")
26
+ end
20
27
 
21
28
  # Get App
22
29
  app = Spaceship::ConnectAPI::App.find(params[:app_identifier])
@@ -68,10 +75,11 @@ module Fastlane
68
75
 
69
76
  filter = { app: app.id }
70
77
  filter["preReleaseVersion.platform"] = platform
71
- build_resps = Spaceship::ConnectAPI.get_builds(filter: filter, sort: "-uploadedDate", includes: "preReleaseVersion").all_pages
72
- builds = build_resps.flat_map(&:to_models)
78
+ filter["preReleaseVersion.version"] = version if version
79
+ filter["version"] = build_number if build_number
80
+ build_resp = Spaceship::ConnectAPI.get_builds(filter: filter, sort: "-uploadedDate", includes: "preReleaseVersion,buildBundles")
73
81
 
74
- builds.each do |build|
82
+ build_resp.all_pages_each do |build|
75
83
  asc_app_version = build.app_version
76
84
  asc_build_number = build.version
77
85
  uploaded_date = DateTime.parse(build.uploaded_date)
@@ -93,7 +101,7 @@ module Fastlane
93
101
 
94
102
  if after_uploaded_date && after_uploaded_date >= uploaded_date
95
103
  UI.verbose("Upload date #{after_uploaded_date} not reached: #{uploaded_date}")
96
- next
104
+ break
97
105
  end
98
106
 
99
107
  message = []
@@ -107,46 +115,37 @@ module Fastlane
107
115
  end
108
116
 
109
117
  UI.verbose("Build_version: #{asc_build_number} matches #{build_number}, grabbing dsym_url") if build_number
110
- get_details_and_download_dsym(app: app, train: asc_app_version, build_number: asc_build_number, uploaded_date: uploaded_date, platform: itc_platform, wait_for_dsym_processing: wait_for_dsym_processing, wait_timeout: wait_timeout, output_directory: output_directory)
118
+ download_dsym(build: build, app: app, wait_for_dsym_processing: wait_for_dsym_processing, wait_timeout: wait_timeout, output_directory: output_directory)
111
119
  end
112
120
  end
113
121
 
114
- def self.get_details_and_download_dsym(app: nil, train: nil, build_number: nil, uploaded_date: nil, platform: nil, wait_for_dsym_processing: nil, wait_timeout: nil, output_directory: nil)
122
+ def self.download_dsym(build: nil, app: nil, wait_for_dsym_processing: nil, wait_timeout: nil, output_directory: nil)
115
123
  start = Time.now
116
- download_url = nil
124
+ dsym_urls = []
117
125
 
118
126
  loop do
119
- begin
120
- resp = Spaceship::Tunes.client.build_details(app_id: app.id, train: train, build_number: build_number, platform: platform)
121
-
122
- resp['apple_id'] = app.id
123
- build_details = Spaceship::Tunes::BuildDetails.factory(resp)
124
-
125
- download_url = build_details.dsym_url
126
- UI.verbose("dsym_url: #{download_url}")
127
- rescue Spaceship::TunesClient::ITunesConnectError => ex
128
- UI.error("Error accessing dSYM file for build\n\n#{build}\n\nException: #{ex}")
129
- end
130
-
131
- unless download_url
132
- if !wait_for_dsym_processing || (Time.now - start) > wait_timeout
133
- # In some cases, AppStoreConnect does not process the dSYMs, thus no error should be thrown.
134
- UI.message("Could not find any dSYM for #{build_number} (#{train})")
135
- else
136
- UI.message("Waiting for dSYM file to appear...")
137
- sleep(30)
138
- next
139
- end
127
+ build_bundles = build.build_bundles.select { |b| b.includes_symbols == true }
128
+ dsym_urls = build_bundles.map(&:dsym_url).compact
129
+
130
+ break if build_bundles.count == dsym_urls.count
131
+
132
+ if !wait_for_dsym_processing || (Time.now - start) > wait_timeout
133
+ # In some cases, AppStoreConnect does not process the dSYMs, thus no error should be thrown.
134
+ UI.message("Could not find any dSYM for #{build.version} (#{build.app_version})")
135
+ break
136
+ else
137
+ UI.message("Waiting for dSYM file to appear...")
138
+ sleep(30) unless FastlaneCore::Helper.is_test?
139
+ build = Spaceship::ConnectAPI::Build.get(build_id: build.id)
140
140
  end
141
-
142
- break
143
141
  end
144
142
 
145
- if download_url
146
- self.download(download_url, app.bundle_id, train, build_number, uploaded_date, output_directory)
147
- return if build_number
143
+ if dsym_urls.count == 0
144
+ UI.message("No dSYM URL for #{build.version} (#{build.app_version})")
148
145
  else
149
- UI.message("No dSYM URL for #{build_number} (#{train})")
146
+ dsym_urls.each do |url|
147
+ self.download(url, build, app, output_directory)
148
+ end
150
149
  end
151
150
  end
152
151
  # rubocop:enable Metrics/PerceivedComplexity
@@ -154,7 +153,7 @@ module Fastlane
154
153
  def self.get_latest_build!(app_id: nil, platform: nil)
155
154
  filter = { app: app_id }
156
155
  filter["preReleaseVersion.platform"] = platform
157
- latest_build = Spaceship::ConnectAPI.get_builds(filter: filter, sort: "-uploadedDate", includes: "preReleaseVersion").first
156
+ latest_build = Spaceship::ConnectAPI.get_builds(filter: filter, sort: "-uploadedDate", includes: "preReleaseVersion,buildBundles").first
158
157
 
159
158
  if latest_build.nil?
160
159
  UI.user_error!("Could not find any build for platform #{platform}") if platform
@@ -164,18 +163,18 @@ module Fastlane
164
163
  return latest_build
165
164
  end
166
165
 
167
- def self.download(download_url, bundle_id, train_number, build_version, uploaded_date, output_directory)
166
+ def self.download(download_url, build, app, output_directory)
168
167
  result = self.download_file(download_url)
169
- path = write_dsym(result, bundle_id, train_number, build_version, output_directory)
170
- UI.success("🔑 Successfully downloaded dSYM file for #{train_number} - #{build_version} to '#{path}'")
168
+ path = write_dsym(result, app.bundle_id, build.app_version, build.version, output_directory)
169
+ UI.success("🔑 Successfully downloaded dSYM file for #{build.app_version} - #{build.version} to '#{path}'")
171
170
 
172
171
  Actions.lane_context[SharedValues::DSYM_PATHS] ||= []
173
172
  Actions.lane_context[SharedValues::DSYM_PATHS] << File.expand_path(path)
174
173
 
175
- unless uploaded_date.nil?
176
- Actions.lane_context[SharedValues::DSYM_LATEST_UPLOADED_DATE] ||= uploaded_date
174
+ unless build.uploaded_date.nil?
175
+ Actions.lane_context[SharedValues::DSYM_LATEST_UPLOADED_DATE] ||= build.uploaded_date
177
176
  current_latest = Actions.lane_context[SharedValues::DSYM_LATEST_UPLOADED_DATE]
178
- Actions.lane_context[SharedValues::DSYM_LATEST_UPLOADED_DATE] = [current_latest, uploaded_date].max
177
+ Actions.lane_context[SharedValues::DSYM_LATEST_UPLOADED_DATE] = [current_latest, build.uploaded_date].max
179
178
  UI.verbose("Most recent build uploaded_date #{Actions.lane_context[SharedValues::DSYM_LATEST_UPLOADED_DATE]}")
180
179
  end
181
180
  end
@@ -234,6 +233,23 @@ module Fastlane
234
233
  user ||= CredentialsManager::AppfileConfig.try_fetch_value(:apple_id)
235
234
 
236
235
  [
236
+ FastlaneCore::ConfigItem.new(key: :api_key_path,
237
+ env_names: ["DOWNLOAD_DSYMS_API_KEY_PATH", "APP_STORE_CONNECT_API_KEY_PATH"],
238
+ description: "Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)",
239
+ optional: true,
240
+ conflicting_options: [:api_key],
241
+ verify_block: proc do |value|
242
+ UI.user_error!("Couldn't find API key JSON file at path '#{value}'") unless File.exist?(value)
243
+ end),
244
+ FastlaneCore::ConfigItem.new(key: :api_key,
245
+ env_names: ["DOWNLOAD_DSYMS_API_KEY", "APP_STORE_CONNECT_API_KEY"],
246
+ description: "Your App Store Connect API Key information (https://docs.fastlane.tools/app-store-connect-api/#use-return-value-and-pass-in-as-an-option)",
247
+ type: Hash,
248
+ default_value: Fastlane::Actions.lane_context[Fastlane::Actions::SharedValues::APP_STORE_CONNECT_API_KEY],
249
+ default_value_dynamic: true,
250
+ optional: true,
251
+ sensitive: true,
252
+ conflicting_options: [:api_key_path]),
237
253
  FastlaneCore::ConfigItem.new(key: :username,
238
254
  short_option: "-u",
239
255
  env_name: "DOWNLOAD_DSYMS_USERNAME",
@@ -8,8 +8,9 @@ module Fastlane
8
8
  class EnsureGitStatusCleanAction < Action
9
9
  def self.run(params)
10
10
  if params[:ignored]
11
- ignored_file = params[:ignored]
12
- repo_status = Actions.sh("git status --porcelain --ignored #{ignored_file}")
11
+ ignored_mode = params[:ignored]
12
+ ignored_mode = 'no' if ignored_mode == 'none'
13
+ repo_status = Actions.sh("git status --porcelain --ignored='#{ignored_mode}'")
13
14
  else
14
15
  repo_status = Actions.sh("git status --porcelain")
15
16
  end
@@ -74,8 +75,18 @@ module Fastlane
74
75
  type: Boolean),
75
76
  FastlaneCore::ConfigItem.new(key: :ignored,
76
77
  env_name: "FL_ENSURE_GIT_STATUS_CLEAN_IGNORED_FILE",
77
- description: "The flag whether to ignore file the git status if the repo is dirty",
78
- optional: true)
78
+ description: [
79
+ "The handling mode of the ignored files. The available options are: `'traditional'`, `'none'` (default) and `'matching'`.",
80
+ "Specifying `'none'` to this parameter is the same as not specifying the parameter at all, which means that no ignored file will be used to check if the repo is dirty or not.",
81
+ "Specifying `'traditional'` or `'matching'` causes some ignored files to be used to check if the repo is dirty or not (more info in the official docs: https://git-scm.com/docs/git-status#Documentation/git-status.txt---ignoredltmodegt)"
82
+ ].join(" "),
83
+ optional: true,
84
+ verify_block: proc do |value|
85
+ mode = value.to_s
86
+ modes = %w(traditional none matching)
87
+
88
+ UI.user_error!("Unsupported mode, must be: #{modes}") unless modes.include?(mode)
89
+ end)
79
90
  ]
80
91
  end
81
92
 
@@ -75,7 +75,7 @@ module Fastlane
75
75
  [
76
76
  "If building your app requires a specific version of Xcode, you can invoke this command before using gym.",
77
77
  "For example, to ensure that a beta version of Xcode is not accidentally selected to build, which would make uploading to TestFlight fail.",
78
- "You can either manually provide a specific version using `version: ` or you make use of the `.xcode-version` file.",
78
+ "You can either manually provide a specific version using `version:` or you make use of the `.xcode-version` file.",
79
79
  "Using the `strict` parameter, you can either verify the full set of version numbers strictly (i.e. `11.3.1`) or only a subset of them (i.e. `11.3` or `11`)."
80
80
  ].join("\n")
81
81
  end
@@ -60,7 +60,7 @@ module Fastlane
60
60
  end
61
61
 
62
62
  def self.is_supported?(platform)
63
- platform == :ios
63
+ [:ios, :mac].include?(platform)
64
64
  end
65
65
 
66
66
  def self.example_code
@@ -109,8 +109,10 @@ module Fastlane
109
109
  options = plist_files.keys
110
110
  selected = UI.select("What build configuration would you like to use?", options)
111
111
  plist_file = plist_files[selected]
112
- else
112
+ elsif plist_files_count > 0
113
113
  plist_file = plist_files.values.first
114
+ else
115
+ return nil
114
116
  end
115
117
 
116
118
  # $(SRCROOT) is the path of where the XcodeProject is
@@ -131,9 +133,12 @@ module Fastlane
131
133
  end
132
134
 
133
135
  def self.get_version_number_from_plist!(plist_file)
136
+ return '$(MARKETING_VERSION)' if plist_file.nil?
137
+
134
138
  plist = Xcodeproj::Plist.read_from_path(plist_file)
135
139
  UI.user_error!("Unable to read plist: #{plist_file}") unless plist
136
140
 
141
+ return '${MARKETING_VERSION}' if plist["CFBundleShortVersionString"].nil?
137
142
  plist["CFBundleShortVersionString"]
138
143
  end
139
144
 
@@ -146,14 +151,14 @@ module Fastlane
146
151
  end
147
152
 
148
153
  def self.details
149
- "This action will return the current version number set on your project."
154
+ "This action will return the current version number set on your project. It first looks in the plist and then for '$(MARKETING_VERSION)' in the build settings."
150
155
  end
151
156
 
152
157
  def self.available_options
153
158
  [
154
159
  FastlaneCore::ConfigItem.new(key: :xcodeproj,
155
160
  env_name: "FL_VERSION_NUMBER_PROJECT",
156
- description: "Path to the Xcode project to read version number from, or its containing directory, optional. If ommitted, or if a directory is passed instead, it will use the first Xcode project found within the given directory, or the project root directory if none is passed",
161
+ description: "Path to the Xcode project to read version number from, or its containing directory, optional. If omitted, or if a directory is passed instead, it will use the first Xcode project found within the given directory, or the project root directory if none is passed",
157
162
  optional: true,
158
163
  verify_block: proc do |value|
159
164
  UI.user_error!("Please pass the path to the project or its containing directory, not the workspace path") if value.end_with?(".xcworkspace")
@@ -2,22 +2,20 @@ module Fastlane
2
2
  module Actions
3
3
  class GitCommitAction < Action
4
4
  def self.run(params)
5
- paths = params[:path].map(&:shellescape).join(' ')
6
-
7
- skip_git_hooks = params[:skip_git_hooks] ? '--no-verify' : ''
5
+ paths = params[:path]
6
+ skip_git_hooks = params[:skip_git_hooks] ? ['--no-verify'] : []
8
7
 
9
8
  if params[:allow_nothing_to_commit]
10
9
  # Here we check if the path passed in parameter contains any modification
11
10
  # and we skip the `git commit` command if there is none.
12
11
  # That means you can have other files modified that are not in the path parameter
13
12
  # and still make use of allow_nothing_to_commit.
14
- repo_clean = Actions.sh("git status #{paths} --porcelain").empty?
13
+ repo_clean = Actions.sh('git', 'status', *paths, '--porcelain').empty?
15
14
  UI.success("Nothing to commit, working tree clean ✅.") if repo_clean
16
15
  return if repo_clean
17
16
  end
18
17
 
19
- command = "git commit -m #{params[:message].shellescape} #{paths} #{skip_git_hooks}".strip
20
- result = Actions.sh(command)
18
+ result = Actions.sh('git', 'commit', '-m', params[:message], *paths, *skip_git_hooks)
21
19
  UI.success("Successfully committed \"#{params[:path]}\" 💾.")
22
20
  return result
23
21
  end
@@ -58,7 +58,7 @@ module Fastlane
58
58
 
59
59
  def self.example_code
60
60
  [
61
- 'import_certificate(certificate_path: "certs/AppleWWDRCA.cer")',
61
+ 'import_certificate(certificate_path: "certs/AppleWWDRCA6.cer")',
62
62
  'import_certificate(
63
63
  certificate_path: "certs/dist.p12",
64
64
  certificate_password: ENV["CERTIFICATE_PASSWORD"] || "default"
@@ -5,6 +5,7 @@ module Fastlane
5
5
  def self.run(params)
6
6
  package_path = params[:package]
7
7
  bundle_id = params[:bundle_id]
8
+ skip_stapling = params[:skip_stapling]
8
9
  try_early_stapling = params[:try_early_stapling]
9
10
  print_log = params[:print_log]
10
11
  verbose = params[:verbose]
@@ -38,13 +39,13 @@ module Fastlane
38
39
  UI.user_error!('Could not read bundle identifier, provide as a parameter') unless bundle_id
39
40
 
40
41
  if use_notarytool
41
- notarytool(params, package_path, bundle_id, try_early_stapling, print_log, verbose, api_key, compressed_package_path)
42
+ notarytool(params, package_path, bundle_id, skip_stapling, print_log, verbose, api_key, compressed_package_path)
42
43
  else
43
- altool(params, package_path, bundle_id, try_early_stapling, print_log, verbose, api_key, compressed_package_path)
44
+ altool(params, package_path, bundle_id, try_early_stapling, skip_stapling, print_log, verbose, api_key, compressed_package_path)
44
45
  end
45
46
  end
46
47
 
47
- def self.notarytool(params, package_path, bundle_id, try_early_stapling, print_log, verbose, api_key, compressed_package_path)
48
+ def self.notarytool(params, package_path, bundle_id, skip_stapling, print_log, verbose, api_key, compressed_package_path)
48
49
  temp_file = nil
49
50
 
50
51
  # Create authorization part of command with either API Key or Apple ID
@@ -89,10 +90,15 @@ module Fastlane
89
90
  submission_id = notarization_info["id"]
90
91
  UI.success("Successfully uploaded package to notarization service with request identifier #{submission_id}")
91
92
 
92
- UI.message('Stapling package')
93
- self.staple(package_path, verbose)
93
+ if skip_stapling
94
+ UI.success("Successfully notarized artifact")
95
+ else
96
+ UI.message('Stapling package')
94
97
 
95
- UI.success("Successfully notarized and stapled package")
98
+ self.staple(package_path, verbose)
99
+
100
+ UI.success("Successfully notarized and stapled package")
101
+ end
96
102
  when 'Invalid'
97
103
  UI.user_error!("Could not notarize package with message '#{notarization_info['statusSummary']}'")
98
104
  else
@@ -102,7 +108,7 @@ module Fastlane
102
108
  temp_file.delete if temp_file
103
109
  end
104
110
 
105
- def self.altool(params, package_path, bundle_id, try_early_stapling, print_log, verbose, api_key, compressed_package_path)
111
+ def self.altool(params, package_path, bundle_id, try_early_stapling, skip_stapling, print_log, verbose, api_key, compressed_package_path)
106
112
  UI.message('Uploading package to notarization service, might take a while')
107
113
 
108
114
  notarization_upload_command = "xcrun altool --notarize-app -t osx -f \"#{compressed_package_path || package_path}\" --primary-bundle-id #{bundle_id} --output-format xml"
@@ -133,7 +139,7 @@ module Fastlane
133
139
  while notarization_info.empty? || (notarization_info['Status'] == 'in progress')
134
140
  if notarization_info.empty?
135
141
  UI.message('Waiting to query request status')
136
- elsif try_early_stapling
142
+ elsif try_early_stapling && !skip_stapling
137
143
  UI.message('Request in progress, trying early staple')
138
144
 
139
145
  begin
@@ -182,11 +188,15 @@ module Fastlane
182
188
 
183
189
  case notarization_info['Status']
184
190
  when 'success'
185
- UI.message('Stapling package')
191
+ if skip_stapling
192
+ UI.success("Successfully notarized artifact#{log_suffix}")
193
+ else
194
+ UI.message('Stapling package')
186
195
 
187
- self.staple(package_path, verbose)
196
+ self.staple(package_path, verbose)
188
197
 
189
- UI.success("Successfully notarized and stapled package#{log_suffix}")
198
+ UI.success("Successfully notarized and stapled package#{log_suffix}")
199
+ end
190
200
  when 'invalid'
191
201
  UI.user_error!("Could not notarize package with message '#{notarization_info['Status Message']}'#{log_suffix}")
192
202
  else
@@ -262,6 +272,14 @@ module Fastlane
262
272
  env_name: 'FL_NOTARIZE_TRY_EARLY_STAPLING',
263
273
  description: 'Whether to try early stapling while the notarization request is in progress',
264
274
  optional: true,
275
+ conflicting_options: [:skip_stapling],
276
+ default_value: false,
277
+ type: Boolean),
278
+ FastlaneCore::ConfigItem.new(key: :skip_stapling,
279
+ env_name: 'FL_NOTARIZE_SKIP_STAPLING',
280
+ description: 'Do not staple the notarization ticket to the artifact; useful for single file executables and ZIP archives',
281
+ optional: true,
282
+ conflicting_options: [:try_early_stapling],
265
283
  default_value: false,
266
284
  type: Boolean),
267
285
  FastlaneCore::ConfigItem.new(key: :bundle_id,
@@ -29,7 +29,7 @@ module Fastlane
29
29
  command << "--analyze" if params[:analyze]
30
30
 
31
31
  result = Actions.sh(command.join(' '))
32
- UI.success("Pod lib lint Successfully ⬆️ ")
32
+ UI.success("Pod lib lint successful ⬆️ ")
33
33
  return result
34
34
  end
35
35
 
@@ -59,6 +59,14 @@ module Fastlane
59
59
  command << "--synchronous"
60
60
  end
61
61
 
62
+ if params[:no_overwrite]
63
+ command << "--no-overwrite"
64
+ end
65
+
66
+ if params[:local_only]
67
+ command << "--local-only"
68
+ end
69
+
62
70
  result = Actions.sh(command.join(' '))
63
71
  UI.success("Successfully pushed Podspec ⬆️ ")
64
72
  return result
@@ -143,7 +151,17 @@ module Fastlane
143
151
  description: "If validation depends on other recently pushed pods, synchronize",
144
152
  optional: true,
145
153
  type: Boolean,
146
- env_name: "FL_POD_PUSH_SYNCHRONOUS")
154
+ env_name: "FL_POD_PUSH_SYNCHRONOUS"),
155
+ FastlaneCore::ConfigItem.new(key: :no_overwrite,
156
+ description: "Disallow pushing that would overwrite an existing spec",
157
+ optional: true,
158
+ type: Boolean,
159
+ env_name: "FL_POD_PUSH_NO_OVERWRITE"),
160
+ FastlaneCore::ConfigItem.new(key: :local_only,
161
+ description: "Does not perform the step of pushing REPO to its remote",
162
+ optional: true,
163
+ type: Boolean,
164
+ env_name: "FL_POD_PUSH_LOCAL_ONLY")
147
165
  ]
148
166
  end
149
167
 
@@ -79,7 +79,7 @@ module Fastlane
79
79
  end
80
80
 
81
81
  def self.return_type
82
- :hash_of_strings
82
+ :hash
83
83
  end
84
84
 
85
85
  def self.category
@@ -4,6 +4,7 @@ module Fastlane
4
4
  SCAN_DERIVED_DATA_PATH = :SCAN_DERIVED_DATA_PATH
5
5
  SCAN_GENERATED_PLIST_FILE = :SCAN_GENERATED_PLIST_FILE
6
6
  SCAN_GENERATED_PLIST_FILES = :SCAN_GENERATED_PLIST_FILES
7
+ SCAN_GENERATED_XCRESULT_PATH = :SCAN_GENERATED_XCRESULT_PATH
7
8
  SCAN_ZIP_BUILD_PRODUCTS_PATH = :SCAN_ZIP_BUILD_PRODUCTS_PATH
8
9
  end
9
10
 
@@ -13,12 +14,12 @@ module Fastlane
13
14
  manager = Scan::Manager.new
14
15
 
15
16
  begin
16
- manager.work(values)
17
+ results = manager.work(values)
17
18
 
18
19
  zip_build_products_path = Scan.cache[:zip_build_products_path]
19
20
  Actions.lane_context[SharedValues::SCAN_ZIP_BUILD_PRODUCTS_PATH] = zip_build_products_path if zip_build_products_path
20
21
 
21
- return true
22
+ return results
22
23
  rescue FastlaneCore::Interface::FastlaneBuildFailure => ex
23
24
  # Specifically catching FastlaneBuildFailure to prevent build/compile errors from being
24
25
  # silenced when :fail_build is set to false
@@ -29,6 +30,12 @@ module Fastlane
29
30
  raise ex
30
31
  end
31
32
  ensure
33
+ if Scan.cache && (result_bundle_path = Scan.cache[:result_bundle_path])
34
+ Actions.lane_context[SharedValues::SCAN_GENERATED_XCRESULT_PATH] = File.absolute_path(result_bundle_path)
35
+ else
36
+ Actions.lane_context[SharedValues::SCAN_GENERATED_XCRESULT_PATH] = nil
37
+ end
38
+
32
39
  unless values[:derived_data_path].to_s.empty?
33
40
  plist_files_before = manager.plist_files_before || []
34
41
 
@@ -49,6 +56,14 @@ module Fastlane
49
56
  "More information: https://docs.fastlane.tools/actions/scan/"
50
57
  end
51
58
 
59
+ def self.return_value
60
+ 'Outputs hash of results with the following keys: :number_of_tests, :number_of_failures, :number_of_retries, :number_of_tests_excluding_retries, :number_of_failures_excluding_retries'
61
+ end
62
+
63
+ def self.return_type
64
+ :hash
65
+ end
66
+
52
67
  def self.author
53
68
  "KrauseFx"
54
69
  end
@@ -56,13 +71,7 @@ module Fastlane
56
71
  def self.available_options
57
72
  require 'scan'
58
73
 
59
- FastlaneCore::CommanderGenerator.new.generate(Scan::Options.available_options) + [
60
- FastlaneCore::ConfigItem.new(key: :fail_build,
61
- env_name: "SCAN_FAIL_BUILD",
62
- description: "Should this step stop the build if the tests fail? Set this to false if you're using trainer",
63
- type: Boolean,
64
- default_value: true)
65
- ]
74
+ FastlaneCore::CommanderGenerator.new.generate(Scan::Options.available_options)
66
75
  end
67
76
 
68
77
  def self.output
@@ -70,6 +79,7 @@ module Fastlane
70
79
  ['SCAN_DERIVED_DATA_PATH', 'The path to the derived data'],
71
80
  ['SCAN_GENERATED_PLIST_FILE', 'The generated plist file'],
72
81
  ['SCAN_GENERATED_PLIST_FILES', 'The generated plist files'],
82
+ ['SCAN_GENERATED_XCRESULT_PATH', 'The path to the generated .xcresult'],
73
83
  ['SCAN_ZIP_BUILD_PRODUCTS_PATH', 'The path to the zipped build products']
74
84
  ]
75
85
  end
@@ -19,11 +19,12 @@ module Fastlane
19
19
 
20
20
  payload = {
21
21
  'tag_name' => params[:tag_name],
22
- 'name' => params[:name],
23
- 'body' => params[:description],
24
22
  'draft' => !!params[:is_draft],
25
- 'prerelease' => !!params[:is_prerelease]
23
+ 'prerelease' => !!params[:is_prerelease],
24
+ 'generate_release_notes' => !!params[:is_generate_release_notes]
26
25
  }
26
+ payload['name'] = params[:name] if params[:name]
27
+ payload['body'] = params[:description] if params[:description]
27
28
  payload['target_commitish'] = params[:commitish] if params[:commitish]
28
29
 
29
30
  GithubApiAction.run(
@@ -48,8 +49,7 @@ module Fastlane
48
49
  UI.user_error!("You are not authorized to access #{repo_name}, please make sure you provided a valid API token (GITHUB_API_TOKEN)")
49
50
  end,
50
51
  '*' => proc do |result|
51
- UI.error("GitHub responded with #{result[:status]}:#{result[:body]}")
52
- return nil
52
+ UI.user_error!("GitHub responded with #{result[:status]}:#{result[:body]}")
53
53
  end
54
54
  }
55
55
  ) do |result|
@@ -221,6 +221,12 @@ module Fastlane
221
221
  optional: true,
222
222
  default_value: false,
223
223
  type: Boolean),
224
+ FastlaneCore::ConfigItem.new(key: :is_generate_release_notes,
225
+ env_name: "FL_SET_GITHUB_RELEASE_IS_GENERATE_RELEASE_NOTES",
226
+ description: "Whether the name and body of this release should be generated automatically",
227
+ optional: true,
228
+ default_value: false,
229
+ type: Boolean),
224
230
  FastlaneCore::ConfigItem.new(key: :upload_assets,
225
231
  env_name: "FL_SET_GITHUB_RELEASE_UPLOAD_ASSETS",
226
232
  description: "Path to assets to be uploaded with the release",
@@ -12,7 +12,7 @@ module Fastlane
12
12
  setup_output_paths
13
13
  end
14
14
 
15
- setup_keychain
15
+ setup_keychain(params)
16
16
  end
17
17
 
18
18
  def self.should_run?(params)
@@ -23,7 +23,7 @@ module Fastlane
23
23
  params[:provider] || (Helper.is_circle_ci? ? 'circleci' : nil)
24
24
  end
25
25
 
26
- def self.setup_keychain
26
+ def self.setup_keychain(params)
27
27
  unless Helper.mac?
28
28
  UI.message("Skipping Keychain setup on non-macOS CI Agent")
29
29
  return
@@ -43,7 +43,7 @@ module Fastlane
43
43
  name: keychain_name,
44
44
  default_keychain: true,
45
45
  unlock: true,
46
- timeout: 3600,
46
+ timeout: params[:timeout],
47
47
  lock_when_sleeps: true,
48
48
  password: "",
49
49
  add_to_search_list: true
@@ -103,7 +103,12 @@ module Fastlane
103
103
  # Validate both 'travis' and 'circleci' for backwards compatibility, even
104
104
  # though only the latter receives special treatment by this action
105
105
  UI.user_error!("A given CI provider '#{value}' is not supported. Available CI providers: 'travis', 'circleci'") unless ["travis", "circleci"].include?(value)
106
- end)
106
+ end),
107
+ FastlaneCore::ConfigItem.new(key: :timeout,
108
+ env_name: "FL_SETUP_CI_TIMEOUT",
109
+ description: "Set a custom timeout in seconds for keychain. Set `0` if you want to specify 'no time-out'",
110
+ type: Integer,
111
+ default_value: 3600)
107
112
  ]
108
113
  end
109
114
 
@@ -119,6 +124,10 @@ module Fastlane
119
124
  [
120
125
  'setup_ci(
121
126
  provider: "circleci"
127
+ )',
128
+ 'setup_ci(
129
+ provider: "circleci",
130
+ timeout: 0
122
131
  )'
123
132
  ]
124
133
  end