fastlane 2.240.0 → 2.241.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +57 -177
  3. data/bin/fastlane +4 -2
  4. data/credentials_manager/README.md +1 -1
  5. data/credentials_manager/lib/credentials_manager/account_manager.rb +6 -2
  6. data/deliver/lib/deliver/app_screenshot.rb +0 -4
  7. data/deliver/lib/deliver/commands_generator.rb +1 -1
  8. data/deliver/lib/deliver/detect_values.rb +3 -1
  9. data/deliver/lib/deliver/download_screenshots.rb +8 -1
  10. data/deliver/lib/deliver/sync_screenshots.rb +27 -28
  11. data/deliver/lib/deliver/upload_app_clip_default_experience_header_images.rb +3 -3
  12. data/deliver/lib/deliver/upload_metadata.rb +12 -16
  13. data/deliver/lib/deliver/upload_screenshots.rb +12 -14
  14. data/docs/README.md +25 -0
  15. data/fastlane/lib/assets/TeamTable.md.erb +28 -0
  16. data/fastlane/lib/fastlane/actions/appaloosa.rb +2 -1
  17. data/fastlane/lib/fastlane/actions/appium.rb +1 -1
  18. data/fastlane/lib/fastlane/actions/apteligent.rb +8 -1
  19. data/fastlane/lib/fastlane/actions/build_and_upload_to_appetize.rb +1 -1
  20. data/fastlane/lib/fastlane/actions/clean_build_artifacts.rb +3 -0
  21. data/fastlane/lib/fastlane/actions/danger.rb +5 -5
  22. data/fastlane/lib/fastlane/actions/docs/build_app.md +1 -2
  23. data/fastlane/lib/fastlane/actions/docs/create_app_online.md +1 -2
  24. data/fastlane/lib/fastlane/actions/docs/get_certificates.md +0 -2
  25. data/fastlane/lib/fastlane/actions/docs/get_push_certificate.md +1 -3
  26. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +13 -3
  27. data/fastlane/lib/fastlane/actions/ensure_no_debug_code.rb +2 -2
  28. data/fastlane/lib/fastlane/actions/get_managed_play_store_publishing_rights.rb +1 -0
  29. data/fastlane/lib/fastlane/actions/github_api.rb +1 -2
  30. data/fastlane/lib/fastlane/actions/hg_commit_version_bump.rb +1 -1
  31. data/fastlane/lib/fastlane/actions/increment_build_number.rb +1 -1
  32. data/fastlane/lib/fastlane/actions/increment_version_number.rb +1 -1
  33. data/fastlane/lib/fastlane/actions/install_xcode_plugin.rb +16 -6
  34. data/fastlane/lib/fastlane/actions/lcov.rb +9 -2
  35. data/fastlane/lib/fastlane/actions/nexus_upload.rb +16 -4
  36. data/fastlane/lib/fastlane/actions/notification.rb +3 -2
  37. data/fastlane/lib/fastlane/actions/oclint.rb +8 -8
  38. data/fastlane/lib/fastlane/actions/push_to_git_remote.rb +9 -4
  39. data/fastlane/lib/fastlane/actions/register_device.rb +1 -1
  40. data/fastlane/lib/fastlane/actions/say.rb +2 -4
  41. data/fastlane/lib/fastlane/actions/set_pod_key.rb +3 -3
  42. data/fastlane/lib/fastlane/actions/sonar.rb +16 -16
  43. data/fastlane/lib/fastlane/actions/sourcedocs.rb +8 -8
  44. data/fastlane/lib/fastlane/actions/splunkmint.rb +8 -1
  45. data/fastlane/lib/fastlane/actions/update_project_provisioning.rb +1 -1
  46. data/fastlane/lib/fastlane/actions/upload_to_app_store.rb +5 -2
  47. data/fastlane/lib/fastlane/actions/upload_to_testflight.rb +5 -2
  48. data/fastlane/lib/fastlane/actions/verify_build.rb +1 -4
  49. data/fastlane/lib/fastlane/actions/verify_pod_keys.rb +3 -1
  50. data/fastlane/lib/fastlane/actions/xcode_server_get_assets.rb +20 -19
  51. data/fastlane/lib/fastlane/actions/xcodebuild.rb +5 -6
  52. data/fastlane/lib/fastlane/actions/zip.rb +2 -1
  53. data/fastlane/lib/fastlane/auto_complete.rb +1 -1
  54. data/fastlane/lib/fastlane/cli_tools_distributor.rb +14 -0
  55. data/fastlane/lib/fastlane/documentation/markdown_docs_generator.rb +23 -0
  56. data/fastlane/lib/fastlane/environment_printer.rb +12 -25
  57. data/fastlane/lib/fastlane/fast_file.rb +2 -1
  58. data/fastlane/lib/fastlane/fastlane_require.rb +5 -1
  59. data/fastlane/lib/fastlane/helper/sh_helper.rb +16 -6
  60. data/fastlane/lib/fastlane/new_action.rb +1 -1
  61. data/fastlane/lib/fastlane/plugins/plugin_fetcher.rb +1 -1
  62. data/fastlane/lib/fastlane/plugins/plugin_info_collector.rb +1 -1
  63. data/fastlane/lib/fastlane/plugins/plugin_manager.rb +36 -4
  64. data/fastlane/lib/fastlane/plugins/template/%gem_name%.gemspec.erb +1 -1
  65. data/fastlane/lib/fastlane/plugins/template/.github/workflows/test.yml +1 -1
  66. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +3 -7
  67. data/fastlane/lib/fastlane/swift_lane_manager.rb +22 -4
  68. data/fastlane/lib/fastlane/version.rb +3 -2
  69. data/fastlane/swift/Deliverfile.swift +1 -1
  70. data/fastlane/swift/DeliverfileProtocol.swift +1 -1
  71. data/fastlane/swift/Fastlane.swift +55 -9
  72. data/fastlane/swift/Gymfile.swift +1 -1
  73. data/fastlane/swift/GymfileProtocol.swift +1 -1
  74. data/fastlane/swift/MainProcess.swift +190 -20
  75. data/fastlane/swift/Matchfile.swift +1 -1
  76. data/fastlane/swift/MatchfileProtocol.swift +10 -3
  77. data/fastlane/swift/Precheckfile.swift +1 -1
  78. data/fastlane/swift/PrecheckfileProtocol.swift +1 -1
  79. data/fastlane/swift/Scanfile.swift +1 -1
  80. data/fastlane/swift/ScanfileProtocol.swift +8 -1
  81. data/fastlane/swift/Screengrabfile.swift +1 -1
  82. data/fastlane/swift/ScreengrabfileProtocol.swift +1 -1
  83. data/fastlane/swift/Snapshotfile.swift +1 -1
  84. data/fastlane/swift/SnapshotfileProtocol.swift +1 -1
  85. data/fastlane/swift/formatting/Rakefile +1 -0
  86. data/fastlane/swift/main.swift +4 -1
  87. data/fastlane_core/README.md +1 -1
  88. data/fastlane_core/lib/fastlane_core/analytics/analytics_event_builder.rb +1 -17
  89. data/fastlane_core/lib/fastlane_core/configuration/configuration.rb +23 -8
  90. data/fastlane_core/lib/fastlane_core/device_manager.rb +2 -2
  91. data/fastlane_core/lib/fastlane_core/helper.rb +34 -5
  92. data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +0 -14
  93. data/fastlane_core/lib/fastlane_core/keychain_importer.rb +31 -28
  94. data/fastlane_core/lib/fastlane_core/languages.rb +0 -1
  95. data/fastlane_core/lib/fastlane_core/print_table.rb +5 -2
  96. data/fastlane_core/lib/fastlane_core/provisioning_profile.rb +10 -19
  97. data/fastlane_core/lib/fastlane_core/secrets.rb +77 -0
  98. data/fastlane_core/lib/fastlane_core/ui/fastlane_runner.rb +3 -3
  99. data/fastlane_core/lib/fastlane_core/ui/github_issue_inspector_reporter.rb +1 -1
  100. data/fastlane_core/lib/fastlane_core/ui/implementations/shell.rb +2 -1
  101. data/fastlane_core/lib/fastlane_core.rb +1 -0
  102. data/frameit/lib/frameit/device.rb +1 -1
  103. data/frameit/lib/frameit/frame_downloader.rb +2 -0
  104. data/frameit/lib/frameit/runner.rb +3 -2
  105. data/frameit/lib/frameit/screenshot.rb +0 -1
  106. data/gym/lib/gym/generators/build_command_generator.rb +4 -4
  107. data/gym/lib/gym/generators/package_command_generator_xcode7.rb +3 -3
  108. data/gym/lib/gym/runner.rb +1 -1
  109. data/internal/README.md +1 -1
  110. data/match/lib/match/encryption/openssl.rb +6 -2
  111. data/match/lib/match/generator.rb +1 -0
  112. data/match/lib/match/options.rb +13 -5
  113. data/match/lib/match/runner.rb +30 -3
  114. data/match/lib/match/storage/git_storage.rb +43 -7
  115. data/match/lib/match/storage/gitlab/secure_file.rb +2 -1
  116. data/match/lib/match/storage/interface.rb +8 -5
  117. data/pem/lib/pem/module.rb +0 -4
  118. data/precheck/lib/precheck/rule_processor.rb +1 -0
  119. data/produce/lib/produce/developer_center.rb +49 -2
  120. data/produce/lib/produce/itunes_connect.rb +1 -1
  121. data/produce/lib/produce/module.rb +21 -0
  122. data/produce/lib/produce/options.rb +17 -0
  123. data/produce/lib/produce/service.rb +3 -5
  124. data/produce/lib/produce.rb +0 -1
  125. data/scan/lib/scan/options.rb +7 -0
  126. data/scan/lib/scan/runner.rb +1 -1
  127. data/scan/lib/scan/test_command_generator.rb +12 -9
  128. data/scan/lib/scan/test_result_parser.rb +1 -0
  129. data/scan/lib/scan/xcpretty_reporter_options_generator.rb +2 -2
  130. data/screengrab/lib/screengrab/page.html.erb +12 -7
  131. data/screengrab/lib/screengrab/reports_generator.rb +1 -1
  132. data/sigh/lib/assets/resign.sh +17 -0
  133. data/sigh/lib/sigh/local_manage.rb +1 -1
  134. data/sigh/lib/sigh/options.rb +5 -0
  135. data/sigh/lib/sigh/resign.rb +3 -3
  136. data/sigh/lib/sigh/runner.rb +6 -1
  137. data/snapshot/lib/snapshot/page.html.erb +17 -12
  138. data/snapshot/lib/snapshot/reports_generator.rb +1 -1
  139. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +1 -1
  140. data/snapshot/lib/snapshot.rb +0 -2
  141. data/spaceship/README.md +2 -3
  142. data/spaceship/lib/spaceship/base.rb +3 -1
  143. data/spaceship/lib/spaceship/client.rb +65 -47
  144. data/spaceship/lib/spaceship/connect_api/models/bundle_id.rb +13 -2
  145. data/spaceship/lib/spaceship/connect_api/models/bundle_id_capability.rb +6 -0
  146. data/spaceship/lib/spaceship/connect_api/models/profile.rb +7 -5
  147. data/spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb +25 -0
  148. data/spaceship/lib/spaceship/du/upload_file.rb +1 -1
  149. data/spaceship/lib/spaceship/errors.rb +7 -1
  150. data/spaceship/lib/spaceship/globals.rb +2 -2
  151. data/spaceship/lib/spaceship/portal/merchant.rb +127 -2
  152. data/spaceship/lib/spaceship/portal/portal_client.rb +58 -0
  153. data/spaceship/lib/spaceship/portal/ui/select_team.rb +0 -2
  154. data/spaceship/lib/spaceship/portal/website_push.rb +8 -2
  155. data/spaceship/lib/spaceship/test_flight/client.rb +0 -22
  156. data/spaceship/lib/spaceship/test_flight.rb +0 -1
  157. data/spaceship/lib/spaceship/two_step_or_factor_client.rb +11 -0
  158. data/supply/lib/supply/options.rb +1 -0
  159. data/supply/lib/supply.rb +0 -1
  160. metadata +75 -43
  161. data/produce/lib/produce/available_default_languages.rb +0 -62
  162. data/snapshot/lib/snapshot/screenshot_flatten.rb +0 -20
  163. data/snapshot/lib/snapshot/screenshot_rotate.rb +0 -36
  164. data/spaceship/lib/spaceship/test_flight/app_test_info.rb +0 -40
  165. data/supply/lib/supply/apk_listing.rb +0 -14
  166. /data/fastlane/lib/assets/{custom_action_template.rb → custom_action_template.rb.template} +0 -0
@@ -25,7 +25,7 @@ module Fastlane
25
25
  UI.message("Downloading root certificate from (#{ROOT_CERTIFICATE_URL}) to path '#{params[:certificate]}'")
26
26
  require 'open-uri'
27
27
  File.open(params[:certificate], "w:ASCII-8BIT") do |file|
28
- file.write(URI.open(ROOT_CERTIFICATE_URL, "rb").read)
28
+ file.write(URI.parse(ROOT_CERTIFICATE_URL).open("rb").read)
29
29
  end
30
30
  end
31
31
 
@@ -10,8 +10,11 @@ module Fastlane
10
10
  begin
11
11
  config.load_configuration_file("Deliverfile")
12
12
  config[:screenshots_path] ||= Actions.lane_context[SharedValues::SNAPSHOT_SCREENSHOTS_PATH] if Actions.lane_context[SharedValues::SNAPSHOT_SCREENSHOTS_PATH]
13
- config[:ipa] ||= Actions.lane_context[SharedValues::IPA_OUTPUT_PATH] if Actions.lane_context[SharedValues::IPA_OUTPUT_PATH]
14
- config[:pkg] ||= Actions.lane_context[SharedValues::PKG_OUTPUT_PATH] if Actions.lane_context[SharedValues::PKG_OUTPUT_PATH]
13
+ # The build from gym wins over the newest *.ipa/*.pkg in the current directory, the options' default
14
+ unless config.specified?(:ipa) || config.specified?(:pkg)
15
+ config[:ipa] = Actions.lane_context[SharedValues::IPA_OUTPUT_PATH] if Actions.lane_context[SharedValues::IPA_OUTPUT_PATH]
16
+ config[:pkg] = Actions.lane_context[SharedValues::PKG_OUTPUT_PATH] if Actions.lane_context[SharedValues::PKG_OUTPUT_PATH]
17
+ end
15
18
 
16
19
  # Only set :api_key from SharedValues if :api_key_path isn't set (conflicting options)
17
20
  unless config[:api_key_path]
@@ -11,9 +11,12 @@ module Fastlane
11
11
  values[:changelog] ||= changelog if changelog
12
12
 
13
13
  unless distribute_only
14
- values[:ipa] ||= Actions.lane_context[SharedValues::IPA_OUTPUT_PATH]
14
+ # The build from gym wins over the newest *.ipa/*.pkg in the current directory, the options' default
15
+ unless values.specified?(:ipa) || values.specified?(:pkg)
16
+ values[:ipa] = Actions.lane_context[SharedValues::IPA_OUTPUT_PATH] if Actions.lane_context[SharedValues::IPA_OUTPUT_PATH]
17
+ values[:pkg] = Actions.lane_context[SharedValues::PKG_OUTPUT_PATH] if Actions.lane_context[SharedValues::PKG_OUTPUT_PATH]
18
+ end
15
19
  values[:ipa] = File.expand_path(values[:ipa]) if values[:ipa]
16
- values[:pkg] ||= Actions.lane_context[SharedValues::PKG_OUTPUT_PATH]
17
20
  values[:pkg] = File.expand_path(values[:pkg]) if values[:pkg]
18
21
  end
19
22
 
@@ -69,10 +69,7 @@ module Fastlane
69
69
  provision_profile_path = "#{app_path}/embedded.mobileprovision"
70
70
  UI.user_error!("Unable to find embedded profile in #{provision_profile_path}") unless File.exist?(provision_profile_path)
71
71
 
72
- profile = `cat #{provision_profile_path.shellescape} | security cms -D`
73
- UI.user_error!("Unable to extract profile") unless $? == 0
74
-
75
- plist = Plist.parse_xml(profile)
72
+ plist = FastlaneCore::ProvisioningProfile.parse(provision_profile_path)
76
73
 
77
74
  values['app_name'] = plist['AppIDName']
78
75
  values['provisioning_uuid'] = plist['UUID']
@@ -29,7 +29,9 @@ module Fastlane
29
29
  end
30
30
 
31
31
  def self.value(key, target)
32
- value = `pod keys get #{key} #{target}`
32
+ command = ["pod", "keys", "get", key]
33
+ command << target unless target.to_s.empty?
34
+ value = `#{command.shelljoin}`
33
35
  value.split("]").last.strip
34
36
  end
35
37
 
@@ -20,12 +20,8 @@ module Fastlane
20
20
  password = params[:password]
21
21
  trust_self_signed_certs = params[:trust_self_signed_certs]
22
22
 
23
- # setup (not)trusting self signed certificates.
24
23
  # it's normal to have a self signed certificate on your Xcode Server
25
- Excon.defaults[:ssl_verify_peer] = !trust_self_signed_certs # for self-signed certificates
26
-
27
- # create Xcode Server config
28
- xcs = XcodeServer.new(host, username, password)
24
+ xcs = XcodeServer.new(host, username, password, ssl_verify_peer: !trust_self_signed_certs)
29
25
  bots = xcs.fetch_all_bots
30
26
 
31
27
  UI.important("Fetched #{bots.count} Bots from Xcode Server at #{host}.")
@@ -106,10 +102,11 @@ module Fastlane
106
102
  end
107
103
 
108
104
  class XcodeServer
109
- def initialize(host, username, password)
105
+ def initialize(host, username, password, ssl_verify_peer: true)
110
106
  @host = host.start_with?('https://') ? host : "https://#{host}"
111
107
  @username = username
112
108
  @password = password
109
+ @ssl_verify_peer = ssl_verify_peer
113
110
  end
114
111
 
115
112
  def fetch_all_bots
@@ -129,18 +126,18 @@ module Fastlane
129
126
  # create a temp folder and a file, stream the download into it
130
127
  Dir.mktmpdir do |dir|
131
128
  temp_file = File.join(dir, "tmp_download.#{rand(1_000_000)}")
132
- f = open(temp_file, 'w')
133
- streamer = lambda do |chunk, remaining_bytes, total_bytes|
134
- if remaining_bytes && total_bytes
135
- UI.important("Downloading: #{100 - (100 * remaining_bytes.to_f / total_bytes.to_f).to_i}%")
136
- else
137
- UI.error(chunk.to_s)
129
+ response = File.open(temp_file, 'w') do |f|
130
+ streamer = lambda do |chunk, remaining_bytes, total_bytes|
131
+ if remaining_bytes && total_bytes
132
+ UI.important("Downloading: #{100 - (100 * remaining_bytes.to_f / total_bytes.to_f).to_i}%")
133
+ else
134
+ UI.error(chunk.to_s)
135
+ end
136
+ f.write(chunk)
138
137
  end
139
- f.write(chunk)
140
- end
141
138
 
142
- response = self.get_endpoint("/integrations/#{integration_id}/assets", streamer)
143
- f.close
139
+ self.get_endpoint("/integrations/#{integration_id}/assets", streamer)
140
+ end
144
141
 
145
142
  UI.user_error!("Integration doesn't have any assets (it probably never ran).") if response.status == 500
146
143
  UI.user_error!("Failed to fetch Assets zip for Integration #{integration_id} from Xcode Server at #{@host}, response: #{response.status}: #{response.body}") if response.status != 200
@@ -199,9 +196,9 @@ module Fastlane
199
196
  headers = self.headers || {}
200
197
 
201
198
  if response_block
202
- response = Excon.get(url, response_block: response_block, headers: headers)
199
+ response = Excon.get(url, response_block: response_block, headers: headers, ssl_verify_peer: @ssl_verify_peer)
203
200
  else
204
- response = Excon.get(url, headers: headers)
201
+ response = Excon.get(url, headers: headers, ssl_verify_peer: @ssl_verify_peer)
205
202
  end
206
203
 
207
204
  return response
@@ -305,7 +302,11 @@ module Fastlane
305
302
  end
306
303
 
307
304
  def self.category
308
- :testing
305
+ :deprecated
306
+ end
307
+
308
+ def self.deprecated_notes
309
+ "Xcode Server is no longer supported since Xcode 14 ([Xcode 14 Release Notes](https://developer.apple.com/documentation/xcode-release-notes/xcode-14-release-notes))."
309
310
  end
310
311
  end
311
312
  end
@@ -260,7 +260,7 @@ module Fastlane
260
260
  xcpretty_command = "#{xcpretty_command} --utf" if xcpretty_utf
261
261
  end
262
262
 
263
- pipe_command = "| tee '#{buildlog_path}/xcodebuild.log' #{xcpretty_command}"
263
+ pipe_command = "| tee #{File.join(buildlog_path, 'xcodebuild.log').shellescape} #{xcpretty_command}"
264
264
 
265
265
  FileUtils.mkdir_p buildlog_path
266
266
  UI.message("For a more detailed xcodebuild log open #{buildlog_path}/xcodebuild.log")
@@ -293,7 +293,7 @@ module Fastlane
293
293
 
294
294
  # If raw_buildlog and some reports had to be created, create xcpretty reports from the build log
295
295
  if raw_buildlog && xcpretty_args.include?('--report')
296
- output_result = Actions.sh "set -o pipefail && cat '#{buildlog_path}/xcodebuild.log' | xcpretty #{xcpretty_args} > /dev/null"
296
+ output_result = Actions.sh "set -o pipefail && cat #{File.join(buildlog_path, 'xcodebuild.log').shellescape} | xcpretty #{xcpretty_args} > /dev/null"
297
297
  end
298
298
 
299
299
  output_result
@@ -349,11 +349,10 @@ module Fastlane
349
349
  end.compact
350
350
  end
351
351
 
352
- # Cleans values for build settings
353
- # Only escaping `$(inherit)` types of values since "sh"
354
- # interprets these as sub-commands instead of passing value into xcodebuild
352
+ # Escapes what sh interprets inside double quotes, so the value reaches xcodebuild unchanged.
353
+ # xcodebuild expands $(VAR), ${VAR} and $VAR itself, from build settings and the environment.
355
354
  def self.clean_build_setting_value(value)
356
- value.to_s.gsub('$(', '\\$(')
355
+ value.to_s.gsub(/[\\"$`]/) { |char| "\\#{char}" }
357
356
  end
358
357
 
359
358
  def self.detect_workspace
@@ -103,7 +103,8 @@ module Fastlane
103
103
  FastlaneCore::ConfigItem.new(key: :password,
104
104
  env_name: "FL_ZIP_PASSWORD",
105
105
  description: "Encrypt the contents of the zip archive using a password",
106
- optional: true),
106
+ optional: true,
107
+ sensitive: true),
107
108
  FastlaneCore::ConfigItem.new(key: :symlinks,
108
109
  env_name: "FL_ZIP_SYMLINKS",
109
110
  description: "Store symbolic links as such in the zip archive",
@@ -45,7 +45,7 @@ module Fastlane
45
45
  custom_commands = options.custom.to_s.split(',')
46
46
 
47
47
  Fastlane::SHELLS.each do |shell_name|
48
- open("#{fastlane_conf_dir}/completions/completion.#{shell_name}", 'a') do |file|
48
+ File.open("#{fastlane_conf_dir}/completions/completion.#{shell_name}", 'a') do |file|
49
49
  default_line_prefix = Helper.bundler? ? "bundle exec " : ""
50
50
 
51
51
  file.puts(self.get_auto_complete_line(shell_name, "#{default_line_prefix}fastlane"))
@@ -53,6 +53,7 @@ module Fastlane
53
53
  # We want to avoid printing output other than the version number if we are running `fastlane -v`
54
54
  unless running_version_command? || running_init_command?
55
55
  print_bundle_exec_warning(is_slow: (Time.now - before_import_time > 3))
56
+ print_running_version
56
57
  end
57
58
 
58
59
  # Try to check UTF-8 with `locale`, fallback to environment variables
@@ -179,6 +180,19 @@ module Fastlane
179
180
  }[tool_name] || tool_name
180
181
  end
181
182
 
183
+ # Which fastlane a log comes from: `fastlane env`, run later by hand, can describe another install. See #29938.
184
+ def print_running_version
185
+ source = FastlaneCore::Helper.install_method
186
+ if ARGV.include?("--verbose")
187
+ require "fastlane/environment_printer"
188
+ location = FastlaneCore::Helper.bundler? ? ENV["BUNDLE_GEMFILE"] : $PROGRAM_NAME
189
+ # Dir.home rather than ENV['HOME'], which does not match the paths Ruby gives on Windows
190
+ source += ": #{EnvironmentPrinter.anonymized_path(location.to_s, Dir.home)}"
191
+ end
192
+
193
+ UI.message("fastlane #{Fastlane::VERSION} (Ruby #{RUBY_VERSION}, #{source})")
194
+ end
195
+
182
196
  def print_bundle_exec_warning(is_slow: false)
183
197
  return if FastlaneCore::Helper.bundler? # user is already using bundler
184
198
  return if FastlaneCore::Env.truthy?('SKIP_SLOW_FASTLANE_WARNING') # user disabled the warnings
@@ -193,9 +193,32 @@ module Fastlane
193
193
  FileUtils.cp(current_asset_path, File.join(docs_dir, "img", "actions", File.basename(current_asset_path)))
194
194
  end
195
195
 
196
+ # Generate the team table (docs/generated/team-table.md) from team.json
197
+ generate_team_table(docs_dir)
198
+
196
199
  UI.success("Generated new docs on path #{target_path}")
197
200
  end
198
201
 
202
+ def generate_team_table(docs_dir)
203
+ team_json_path = File.expand_path(File.join(Fastlane::ROOT, "..", "internal", "team.json"))
204
+ unless File.exist?(team_json_path)
205
+ UI.message("Skipping team table generation, could not find #{team_json_path}")
206
+ return
207
+ end
208
+
209
+ File.write(File.join(docs_dir, "generated", "team-table.md"), self.class.render_team(team_json_path))
210
+ end
211
+
212
+ # Also used by the `generate_team_table` rake task, so it must not depend on fastlane being loaded
213
+ def self.render_team(team_json_path)
214
+ require 'erb'
215
+ require 'json'
216
+
217
+ team, alumni = JSON.parse(File.read(team_json_path)).to_a.shuffle.partition { |_, user| !user['alumni'] }
218
+ template = File.expand_path("../../assets/TeamTable.md.erb", __dir__)
219
+ ERB.new(File.read(template), trim_mode: '-').result(binding)
220
+ end
221
+
199
222
  private
200
223
 
201
224
  def readable_category_name(category_symbol)
@@ -252,34 +252,21 @@ module Fastlane
252
252
  def self.print_fastlane_files
253
253
  env_output = "### fastlane files:\n\n"
254
254
 
255
- fastlane_path = FastlaneCore::FastlaneFolder.fastfile_path
256
-
257
- if fastlane_path && File.exist?(fastlane_path)
258
- env_output << "<details>"
259
- env_output << "<summary>`#{fastlane_path}`</summary>\n"
255
+ {
256
+ "Fastfile" => FastlaneCore::FastlaneFolder.fastfile_path,
257
+ "Appfile" => CredentialsManager::AppfileConfig.default_path
258
+ }.each do |name, path|
259
+ if path && File.exist?(path)
260
+ env_output << "**#{name}** found at `#{path}`\n"
261
+ else
262
+ env_output << "**No #{name} found**\n"
263
+ end
260
264
  env_output << "\n"
261
- env_output << "```ruby\n"
262
- env_output << File.read(fastlane_path, encoding: "utf-8")
263
- env_output << "\n```\n"
264
- env_output << "</details>"
265
- else
266
- env_output << "**No Fastfile found**\n"
267
265
  end
268
- env_output << "\n\n"
269
266
 
270
- appfile_path = CredentialsManager::AppfileConfig.default_path
271
- if appfile_path && File.exist?(appfile_path)
272
- env_output << "<details>"
273
- env_output << "<summary>`#{appfile_path}`</summary>\n"
274
- env_output << "\n"
275
- env_output << "```ruby\n"
276
- env_output << File.read(appfile_path, encoding: "utf-8")
277
- env_output << "\n```\n"
278
- env_output << "</details>"
279
- else
280
- env_output << "**No Appfile found**\n"
281
- end
282
- env_output << "\n\n"
267
+ env_output << "The contents of these files are not included, as they may contain secrets. "
268
+ env_output << "If they are relevant to your issue, please add the parts that are, with any sensitive values removed.\n"
269
+ env_output << "\n"
283
270
  env_output
284
271
  end
285
272
 
@@ -314,6 +314,7 @@ module Fastlane
314
314
  # it would defeat the caching's purpose.
315
315
  command += ['--depth', '1'] unless is_eligible_for_caching
316
316
  command += ['--branch', branch] unless branch == 'HEAD'
317
+ FastlaneCore::Secrets.register(git_extra_headers, name: :git_extra_headers)
317
318
  git_extra_headers.each do |header|
318
319
  command += ['--config', "http.extraHeader=#{header}"]
319
320
  end
@@ -329,7 +330,7 @@ module Fastlane
329
330
  # Update the repo and try again before failing
330
331
  UI.message("Updating git repo...")
331
332
  Helper.with_env_values('GIT_TERMINAL_PROMPT' => '0') do
332
- Actions.sh("cd #{clone_folder.shellescape} && git checkout #{branch} && git reset --hard && git pull --all")
333
+ Actions.sh("cd #{clone_folder.shellescape} && git checkout #{branch.shellescape} && git reset --hard && git pull --all")
333
334
  end
334
335
 
335
336
  checkout_param = find_tag(folder: clone_folder, version: version, remote: false)
@@ -27,7 +27,11 @@ module Fastlane
27
27
  UI.important("Installing Ruby gem '#{gem_name}'...")
28
28
 
29
29
  spec_name = self.find_gem_name(gem_name)
30
- UI.important("Found gem \"#{spec_name}\" instead of the required name \"#{gem_name}\"") if spec_name != gem_name
30
+ if spec_name != gem_name
31
+ message = "Could not find gem '#{gem_name}' on RubyGems"
32
+ message += ". Did you mean '#{spec_name}'? Fix the name in your Fastfile" if spec_name
33
+ UI.user_error!(message)
34
+ end
31
35
 
32
36
  return if Helper.test?
33
37
 
@@ -8,12 +8,13 @@ module Fastlane
8
8
  # When running this in tests, it will return the actual command instead of executing it
9
9
  # @param log [Boolean] should fastlane print out the executed command
10
10
  # @param error_callback [Block] a callback invoked with the command output if there is a non-zero exit status
11
- def self.sh(*command, log: true, error_callback: nil, &b)
12
- sh_control_output(*command, print_command: log, print_command_output: log, error_callback: error_callback, &b)
11
+ # @param stdin [String] data written to the command's standard input, which is then closed; it is never printed
12
+ def self.sh(*command, log: true, error_callback: nil, stdin: nil, &b)
13
+ sh_control_output(*command, print_command: log, print_command_output: log, error_callback: error_callback, stdin: stdin, &b)
13
14
  end
14
15
 
15
- def self.sh_no_action(*command, log: true, error_callback: nil, &b)
16
- sh_control_output(*command, print_command: log, print_command_output: log, error_callback: error_callback, &b)
16
+ def self.sh_no_action(*command, log: true, error_callback: nil, stdin: nil, &b)
17
+ sh_control_output(*command, print_command: log, print_command_output: log, error_callback: error_callback, stdin: stdin, &b)
17
18
  end
18
19
 
19
20
  # @param command The command to be executed (variadic)
@@ -25,7 +26,7 @@ module Fastlane
25
26
  # @yieldparam [String] result The complete output to stdout and stderr of the completed command
26
27
  # @yieldparam [String] cmd A shell command equivalent to the arguments passed
27
28
  # rubocop: disable Metrics/PerceivedComplexity
28
- def self.sh_control_output(*command, print_command: true, print_command_output: true, error_callback: nil)
29
+ def self.sh_control_output(*command, print_command: true, print_command_output: true, error_callback: nil, stdin: nil)
29
30
  print_command = print_command_output = true if $troubleshoot
30
31
  # Set the encoding first, the user might have set it wrong
31
32
  previous_encoding = [Encoding.default_external, Encoding.default_internal]
@@ -52,7 +53,15 @@ module Fastlane
52
53
  # sh "ls", "-la", "/Applications/Xcode 7.3.1.app"
53
54
  # sh({ "FOO" => "Hello" }, "echo $FOO")
54
55
  sanitized_output = false
55
- Open3.popen2e(*command) do |stdin, io, thread|
56
+ Open3.popen2e(*command) do |command_stdin, io, thread|
57
+ # From a thread, so a command that writes a lot before reading its input cannot block on a full pipe
58
+ writer = stdin && Thread.new do
59
+ command_stdin.write(stdin)
60
+ rescue Errno::EPIPE
61
+ # The command exited without reading all of it; its exit status says what happened
62
+ ensure
63
+ command_stdin.close
64
+ end
56
65
  io.sync = true
57
66
  io.each do |line|
58
67
  if print_command_output
@@ -64,6 +73,7 @@ module Fastlane
64
73
  result << line
65
74
  end
66
75
  exit_status = thread.value
76
+ writer&.join
67
77
  end
68
78
 
69
79
  UI.important("Command output wasn't valid UTF-8 and was sanitized. Please report the issue.") if sanitized_output
@@ -18,7 +18,7 @@ module Fastlane
18
18
  end
19
19
 
20
20
  def self.generate_action(name)
21
- template = File.read("#{Fastlane::ROOT}/lib/assets/custom_action_template.rb")
21
+ template = File.read("#{Fastlane::ROOT}/lib/assets/custom_action_template.rb.template")
22
22
  template.gsub!('[[NAME]]', name)
23
23
  template.gsub!('[[NAME_UP]]', name.upcase)
24
24
  template.gsub!('[[NAME_CLASS]]', name.fastlane_class + 'Action')
@@ -14,7 +14,7 @@ module Fastlane
14
14
  loop do
15
15
  url = "https://rubygems.org/api/v1/search.json?query=#{PluginManager.plugin_prefix}&page=#{page}"
16
16
  FastlaneCore::UI.verbose("RubyGems API Request: #{url}")
17
- results = JSON.parse(URI.open(url).read)
17
+ results = JSON.parse(URI.parse(url).open.read)
18
18
  break if results.count == 0
19
19
 
20
20
  plugins += results.collect do |current|
@@ -68,7 +68,7 @@ module Fastlane
68
68
  require 'json'
69
69
  require 'open-uri'
70
70
  url = "https://rubygems.org/api/v1/gems/#{name}.json"
71
- response = JSON.parse(URI.open(url).read)
71
+ response = JSON.parse(URI.parse(url).open.read)
72
72
  return !!response['version']
73
73
  rescue
74
74
  false
@@ -66,6 +66,15 @@ module Fastlane
66
66
  end
67
67
  end
68
68
 
69
+ # Returns the fastlane plugins the given gem depends on, directly or through other gems
70
+ def plugins_required_by(gem_name)
71
+ rubygem = Bundler.rubygems.find_name(gem_name).first
72
+ return [] unless rubygem
73
+ collect_bundler_runtime_dependencies([], rubygem).map(&:name).keep_if do |current|
74
+ current.start_with?(self.class.plugin_prefix)
75
+ end
76
+ end
77
+
69
78
  # Check if a plugin is added as dependency to either the
70
79
  # Gemfile or the Pluginfile
71
80
  def plugin_is_added_as_dependency?(plugin_name)
@@ -159,7 +168,7 @@ module Fastlane
159
168
  require 'open-uri'
160
169
  url = "https://rubygems.org/api/v1/gems/#{gem_name}.json"
161
170
  begin
162
- JSON.parse(URI.open(url).read)
171
+ JSON.parse(URI.parse(url).open.read)
163
172
  rescue
164
173
  nil
165
174
  end
@@ -278,11 +287,12 @@ module Fastlane
278
287
  # fastlane-plugin-[plugin_name]
279
288
  # This will make sure to load the action
280
289
  # and all its helpers
281
- def load_plugins(print_table: true)
290
+ # @param plugins [Array] the plugins to load, the available plugins by default
291
+ def load_plugins(print_table: true, plugins: nil)
282
292
  UI.verbose("Checking if there are any plugins that should be loaded...")
283
293
 
284
294
  loaded_plugins = false
285
- available_plugins.each do |gem_name|
295
+ (plugins || available_plugins).each do |gem_name|
286
296
  UI.verbose("Loading '#{gem_name}' plugin")
287
297
  begin
288
298
  # BEFORE requiring the gem, we get a list of loaded actions
@@ -306,7 +316,7 @@ module Fastlane
306
316
  end
307
317
  end
308
318
 
309
- if !loaded_plugins && self.pluginfile_content.to_s.include?(PluginManager.plugin_prefix)
319
+ if plugins.nil? && !loaded_plugins && self.pluginfile_content.to_s.include?(PluginManager.plugin_prefix)
310
320
  UI.error("It seems like you wanted to load some plugins, however they couldn't be loaded")
311
321
  UI.error("Please follow the troubleshooting guide: #{TROUBLESHOOTING_URL}")
312
322
  end
@@ -317,6 +327,12 @@ module Fastlane
317
327
  print_plugin_information(self.plugin_references) unless skip_print_plugin_info
318
328
  end
319
329
 
330
+ # Loads the plugins the given gem depends on that are not loaded yet
331
+ def load_plugins_required_by(gem_name, print_table: true)
332
+ plugins = plugins_required_by(gem_name) - self.plugin_references.keys
333
+ load_plugins(print_table: print_table, plugins: plugins) unless plugins.empty?
334
+ end
335
+
320
336
  # Prints a table all the plugins that were loaded
321
337
  def print_plugin_information(references)
322
338
  no_action_found = false
@@ -395,5 +411,21 @@ module Fastlane
395
411
  actions: references
396
412
  }
397
413
  end
414
+
415
+ private
416
+
417
+ # recursively collect runtime dependencies
418
+ def collect_bundler_runtime_dependencies(collection, source)
419
+ # Compare by name: one gem can be required with different version constraints
420
+ known = collection.map(&:name)
421
+ runtime_deps = source.dependencies.select { |d| d.type == :runtime && !known.include?(d.name) }.uniq(&:name)
422
+ collection.concat(runtime_deps)
423
+ runtime_deps.each do |d|
424
+ collect_bundler_runtime_dependencies(collection, d.to_spec)
425
+ rescue Gem::MissingSpecError
426
+ # ignoring unresolvable dependencies
427
+ end
428
+ collection
429
+ end
398
430
  end
399
431
  end
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
15
15
  spec.files = Dir["lib/**/*"] + %w(README.md LICENSE)
16
16
  spec.require_paths = ['lib']
17
17
  spec.metadata['rubygems_mfa_required'] = 'true'
18
- spec.required_ruby_version = '>= 3.1'
18
+ spec.required_ruby_version = '>= <%= Fastlane::MINIMUM_RUBY %>'
19
19
 
20
20
  # Don't add a dependency to fastlane or fastlane_re
21
21
  # since this would cause a circular dependency
@@ -8,7 +8,7 @@ jobs:
8
8
  runs-on: ubuntu-latest
9
9
  strategy:
10
10
  matrix:
11
- ruby-version: ['3.0', '3.1', '3.2', '3.3', '3.4']
11
+ ruby-version: ['3.2', '3.3', '3.4']
12
12
  steps:
13
13
  - uses: actions/checkout@v6
14
14
 
@@ -1,9 +1,9 @@
1
1
  ---
2
+ plugins:
3
+ - rubocop-performance
2
4
  require:
3
5
  - rubocop/require_tools
4
- - rubocop-performance
5
6
  AllCops:
6
- TargetRubyVersion: 3.1
7
7
  SuggestExtensions: false
8
8
  NewCops: enable
9
9
  Include:
@@ -13,11 +13,9 @@ AllCops:
13
13
  - "*/lib/assets/*Template"
14
14
  - "*/lib/assets/*TemplateAndroid"
15
15
  Exclude:
16
- - "**/lib/assets/custom_action_template.rb"
17
16
  - "./vendor/**/*"
18
17
  - "**/lib/assets/DefaultFastfileTemplate"
19
18
  - "**/lib/assets/MatchfileTemplate"
20
- - "**/spec/fixtures/broken_files/broken_file.rb"
21
19
  - "**/*.provisionprofile"
22
20
  Lint/ErbNewArguments:
23
21
  Enabled: false
@@ -140,7 +138,7 @@ Lint/UnusedMethodArgument:
140
138
  Lint/ParenthesesAsGroupedExpression:
141
139
  Exclude:
142
140
  - "**/spec/**/*"
143
- Naming/PredicateName:
141
+ Naming/PredicatePrefix:
144
142
  Enabled: false
145
143
  Style/PerlBackrefs:
146
144
  Enabled: false
@@ -149,8 +147,6 @@ Layout/SpaceAroundOperators:
149
147
  - "**/spec/actions_specs/xcodebuild_spec.rb"
150
148
  Naming/FileName:
151
149
  Exclude:
152
- - "**/Dangerfile"
153
- - "**/Brewfile"
154
150
  - "**/Gemfile"
155
151
  - "**/Podfile"
156
152
  - "**/Rakefile"
@@ -3,6 +3,10 @@ require_relative 'swift_runner_upgrader.rb'
3
3
 
4
4
  module Fastlane
5
5
  class SwiftLaneManager < LaneManagerBase
6
+ # The runner protocol version this fastlane ships, see main.swift
7
+ RUNNER_PROTOCOL_VERSION = 1
8
+ RUNNER_PROTOCOL_VERSION_REGEX = /FastlaneRunnerProtocolVersion \[(\d+)\]/
9
+
6
10
  # @param lane_name The name of the lane to execute
7
11
  # @param parameters [Hash] The parameters passed from the command line to the lane
8
12
  def self.cruise_lane(lane, parameters = nil, disable_runner_upgrades: false, swift_server_port: nil)
@@ -26,6 +30,7 @@ module Fastlane
26
30
  end
27
31
 
28
32
  self.ensure_runner_built!
33
+ self.warn_if_runner_outdated
29
34
  swift_server_port ||= 2000
30
35
  socket_thread = self.start_socket_thread(port: swift_server_port)
31
36
  sleep(0.250) while socket_thread[:ready].nil?
@@ -229,6 +234,17 @@ module Fastlane
229
234
  end
230
235
  end
231
236
 
237
+ # The protocol version compiled into the built runner, 0 for runners from before it had one
238
+ def self.runner_protocol_version
239
+ File.binread(FastlaneCore::FastlaneFolder.swift_runner_path)[RUNNER_PROTOCOL_VERSION_REGEX, 1].to_i
240
+ end
241
+
242
+ def self.warn_if_runner_outdated
243
+ return if runner_protocol_version >= RUNNER_PROTOCOL_VERSION
244
+
245
+ UI.important("Your FastlaneRunner is outdated for this version of fastlane. Run a lane outside CI, without `disable_runner_upgrades`, to update it, then commit the changes.")
246
+ end
247
+
232
248
  def self.ensure_runner_built!
233
249
  UI.verbose("Checking for new user-provided tool configuration files")
234
250
  # if self.link_user_configs_to_project returns true, that means we need to rebuild the runner
@@ -236,11 +252,13 @@ module Fastlane
236
252
 
237
253
  if FastlaneCore::FastlaneFolder.swift_runner_built?
238
254
  runner_last_modified_age = File.mtime(FastlaneCore::FastlaneFolder.swift_runner_path).to_i
239
- fastfile_last_modified_age = File.mtime(FastlaneCore::FastlaneFolder.fastfile_path).to_i
255
+ # The Fastfile, and the runner's own files, which an upgrade or a pull can change without touching the Fastfile
256
+ sources = [FastlaneCore::FastlaneFolder.fastfile_path] + Dir[File.join(FastlaneCore::FastlaneFolder.swift_folder_path, '**', '*.swift')]
257
+ changed = sources.find { |source| File.mtime(source).to_i > runner_last_modified_age }
240
258
 
241
- if runner_last_modified_age < fastfile_last_modified_age
242
- # It's older than the Fastfile, so build it again
243
- UI.verbose("Found changes to user's Fastfile.swift, setting re-build runner flag")
259
+ if changed
260
+ # It's older than one of its sources, so build it again
261
+ UI.verbose("Found changes to #{changed}, setting re-build runner flag")
244
262
  runner_needs_building = true
245
263
  end
246
264
  else
@@ -1,8 +1,9 @@
1
1
  module Fastlane
2
- VERSION = '2.240.0'.freeze
2
+ VERSION = '2.241.0'.freeze
3
3
  SUMMARY = "The easiest way to build and release mobile apps.".freeze
4
4
  DESCRIPTION = "The easiest way to automate beta deployments and releases for your iOS and Android apps".freeze
5
5
  MINIMUM_XCODE_RELEASE = "7.0".freeze
6
- RUBOCOP_REQUIREMENT = '1.50.2'.freeze
6
+ RUBOCOP_REQUIREMENT = '1.91.0'.freeze
7
+ MINIMUM_RUBY = '3.2.0'.freeze
7
8
  SUGGESTED_MINIMUM_RUBY = '3.3.0'.freeze
8
9
  end
@@ -17,4 +17,4 @@ public class Deliverfile: DeliverfileProtocol {
17
17
  // during the `init` process, and you won't see this message
18
18
  }
19
19
 
20
- // Generated with fastlane 2.240.0
20
+ // Generated with fastlane 2.241.0