fastlane 2.240.1 → 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 (161) 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/deliver/lib/deliver/app_screenshot.rb +0 -4
  6. data/deliver/lib/deliver/commands_generator.rb +1 -1
  7. data/deliver/lib/deliver/download_screenshots.rb +8 -1
  8. data/deliver/lib/deliver/sync_screenshots.rb +27 -28
  9. data/deliver/lib/deliver/upload_app_clip_default_experience_header_images.rb +3 -3
  10. data/deliver/lib/deliver/upload_metadata.rb +12 -16
  11. data/deliver/lib/deliver/upload_screenshots.rb +12 -14
  12. data/docs/README.md +25 -0
  13. data/fastlane/lib/assets/TeamTable.md.erb +28 -0
  14. data/fastlane/lib/fastlane/actions/appaloosa.rb +2 -1
  15. data/fastlane/lib/fastlane/actions/appium.rb +1 -1
  16. data/fastlane/lib/fastlane/actions/apteligent.rb +8 -1
  17. data/fastlane/lib/fastlane/actions/build_and_upload_to_appetize.rb +1 -1
  18. data/fastlane/lib/fastlane/actions/clean_build_artifacts.rb +3 -0
  19. data/fastlane/lib/fastlane/actions/danger.rb +5 -5
  20. data/fastlane/lib/fastlane/actions/docs/build_app.md +1 -2
  21. data/fastlane/lib/fastlane/actions/docs/create_app_online.md +1 -2
  22. data/fastlane/lib/fastlane/actions/docs/get_certificates.md +0 -2
  23. data/fastlane/lib/fastlane/actions/docs/get_push_certificate.md +1 -3
  24. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +13 -3
  25. data/fastlane/lib/fastlane/actions/ensure_no_debug_code.rb +2 -2
  26. data/fastlane/lib/fastlane/actions/get_managed_play_store_publishing_rights.rb +1 -0
  27. data/fastlane/lib/fastlane/actions/github_api.rb +1 -2
  28. data/fastlane/lib/fastlane/actions/hg_commit_version_bump.rb +1 -1
  29. data/fastlane/lib/fastlane/actions/increment_build_number.rb +1 -1
  30. data/fastlane/lib/fastlane/actions/increment_version_number.rb +1 -1
  31. data/fastlane/lib/fastlane/actions/install_xcode_plugin.rb +16 -6
  32. data/fastlane/lib/fastlane/actions/lcov.rb +9 -2
  33. data/fastlane/lib/fastlane/actions/nexus_upload.rb +16 -4
  34. data/fastlane/lib/fastlane/actions/notification.rb +3 -2
  35. data/fastlane/lib/fastlane/actions/oclint.rb +8 -8
  36. data/fastlane/lib/fastlane/actions/push_to_git_remote.rb +9 -4
  37. data/fastlane/lib/fastlane/actions/register_device.rb +1 -1
  38. data/fastlane/lib/fastlane/actions/say.rb +2 -4
  39. data/fastlane/lib/fastlane/actions/set_pod_key.rb +3 -3
  40. data/fastlane/lib/fastlane/actions/sonar.rb +16 -16
  41. data/fastlane/lib/fastlane/actions/sourcedocs.rb +8 -8
  42. data/fastlane/lib/fastlane/actions/splunkmint.rb +8 -1
  43. data/fastlane/lib/fastlane/actions/update_project_provisioning.rb +1 -1
  44. data/fastlane/lib/fastlane/actions/upload_to_app_store.rb +5 -2
  45. data/fastlane/lib/fastlane/actions/upload_to_testflight.rb +5 -2
  46. data/fastlane/lib/fastlane/actions/verify_build.rb +1 -4
  47. data/fastlane/lib/fastlane/actions/verify_pod_keys.rb +3 -1
  48. data/fastlane/lib/fastlane/actions/xcode_server_get_assets.rb +20 -19
  49. data/fastlane/lib/fastlane/actions/xcodebuild.rb +5 -6
  50. data/fastlane/lib/fastlane/actions/zip.rb +2 -1
  51. data/fastlane/lib/fastlane/auto_complete.rb +1 -1
  52. data/fastlane/lib/fastlane/cli_tools_distributor.rb +14 -0
  53. data/fastlane/lib/fastlane/documentation/markdown_docs_generator.rb +23 -0
  54. data/fastlane/lib/fastlane/environment_printer.rb +12 -25
  55. data/fastlane/lib/fastlane/fast_file.rb +2 -1
  56. data/fastlane/lib/fastlane/fastlane_require.rb +5 -1
  57. data/fastlane/lib/fastlane/helper/sh_helper.rb +16 -6
  58. data/fastlane/lib/fastlane/new_action.rb +1 -1
  59. data/fastlane/lib/fastlane/plugins/plugin_fetcher.rb +1 -1
  60. data/fastlane/lib/fastlane/plugins/plugin_info_collector.rb +1 -1
  61. data/fastlane/lib/fastlane/plugins/plugin_manager.rb +36 -4
  62. data/fastlane/lib/fastlane/plugins/template/%gem_name%.gemspec.erb +1 -1
  63. data/fastlane/lib/fastlane/plugins/template/.github/workflows/test.yml +1 -1
  64. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +3 -7
  65. data/fastlane/lib/fastlane/swift_lane_manager.rb +22 -4
  66. data/fastlane/lib/fastlane/version.rb +3 -2
  67. data/fastlane/swift/Deliverfile.swift +1 -1
  68. data/fastlane/swift/DeliverfileProtocol.swift +1 -1
  69. data/fastlane/swift/Fastlane.swift +55 -9
  70. data/fastlane/swift/Gymfile.swift +1 -1
  71. data/fastlane/swift/GymfileProtocol.swift +1 -1
  72. data/fastlane/swift/MainProcess.swift +190 -20
  73. data/fastlane/swift/Matchfile.swift +1 -1
  74. data/fastlane/swift/MatchfileProtocol.swift +10 -3
  75. data/fastlane/swift/Precheckfile.swift +1 -1
  76. data/fastlane/swift/PrecheckfileProtocol.swift +1 -1
  77. data/fastlane/swift/Scanfile.swift +1 -1
  78. data/fastlane/swift/ScanfileProtocol.swift +8 -1
  79. data/fastlane/swift/Screengrabfile.swift +1 -1
  80. data/fastlane/swift/ScreengrabfileProtocol.swift +1 -1
  81. data/fastlane/swift/Snapshotfile.swift +1 -1
  82. data/fastlane/swift/SnapshotfileProtocol.swift +1 -1
  83. data/fastlane/swift/formatting/Rakefile +1 -0
  84. data/fastlane/swift/main.swift +4 -1
  85. data/fastlane_core/README.md +1 -1
  86. data/fastlane_core/lib/fastlane_core/analytics/analytics_event_builder.rb +1 -17
  87. data/fastlane_core/lib/fastlane_core/configuration/configuration.rb +11 -8
  88. data/fastlane_core/lib/fastlane_core/device_manager.rb +2 -2
  89. data/fastlane_core/lib/fastlane_core/helper.rb +34 -5
  90. data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +0 -14
  91. data/fastlane_core/lib/fastlane_core/keychain_importer.rb +24 -27
  92. data/fastlane_core/lib/fastlane_core/languages.rb +0 -1
  93. data/fastlane_core/lib/fastlane_core/print_table.rb +5 -2
  94. data/fastlane_core/lib/fastlane_core/provisioning_profile.rb +10 -19
  95. data/fastlane_core/lib/fastlane_core/secrets.rb +77 -0
  96. data/fastlane_core/lib/fastlane_core/ui/fastlane_runner.rb +3 -3
  97. data/fastlane_core/lib/fastlane_core/ui/github_issue_inspector_reporter.rb +1 -1
  98. data/fastlane_core/lib/fastlane_core/ui/implementations/shell.rb +2 -1
  99. data/fastlane_core/lib/fastlane_core.rb +1 -0
  100. data/frameit/lib/frameit/device.rb +1 -1
  101. data/frameit/lib/frameit/frame_downloader.rb +2 -0
  102. data/frameit/lib/frameit/runner.rb +3 -2
  103. data/frameit/lib/frameit/screenshot.rb +0 -1
  104. data/gym/lib/gym/generators/build_command_generator.rb +4 -4
  105. data/gym/lib/gym/generators/package_command_generator_xcode7.rb +3 -3
  106. data/gym/lib/gym/runner.rb +1 -1
  107. data/internal/README.md +1 -1
  108. data/match/lib/match/generator.rb +1 -0
  109. data/match/lib/match/options.rb +13 -5
  110. data/match/lib/match/storage/git_storage.rb +43 -7
  111. data/match/lib/match/storage/gitlab/secure_file.rb +2 -1
  112. data/pem/lib/pem/module.rb +0 -4
  113. data/precheck/lib/precheck/rule_processor.rb +1 -0
  114. data/produce/lib/produce/developer_center.rb +49 -2
  115. data/produce/lib/produce/itunes_connect.rb +1 -1
  116. data/produce/lib/produce/module.rb +21 -0
  117. data/produce/lib/produce/options.rb +17 -0
  118. data/produce/lib/produce/service.rb +3 -5
  119. data/produce/lib/produce.rb +0 -1
  120. data/scan/lib/scan/options.rb +7 -0
  121. data/scan/lib/scan/runner.rb +1 -1
  122. data/scan/lib/scan/test_command_generator.rb +12 -9
  123. data/scan/lib/scan/test_result_parser.rb +1 -0
  124. data/scan/lib/scan/xcpretty_reporter_options_generator.rb +2 -2
  125. data/screengrab/lib/screengrab/page.html.erb +12 -7
  126. data/screengrab/lib/screengrab/reports_generator.rb +1 -1
  127. data/sigh/lib/assets/resign.sh +17 -0
  128. data/sigh/lib/sigh/local_manage.rb +1 -1
  129. data/sigh/lib/sigh/options.rb +5 -0
  130. data/sigh/lib/sigh/resign.rb +3 -3
  131. data/sigh/lib/sigh/runner.rb +6 -1
  132. data/snapshot/lib/snapshot/page.html.erb +17 -12
  133. data/snapshot/lib/snapshot/reports_generator.rb +1 -1
  134. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +1 -1
  135. data/snapshot/lib/snapshot.rb +0 -2
  136. data/spaceship/README.md +2 -3
  137. data/spaceship/lib/spaceship/base.rb +3 -1
  138. data/spaceship/lib/spaceship/client.rb +65 -47
  139. data/spaceship/lib/spaceship/connect_api/models/bundle_id.rb +13 -2
  140. data/spaceship/lib/spaceship/connect_api/models/bundle_id_capability.rb +6 -0
  141. data/spaceship/lib/spaceship/connect_api/models/profile.rb +7 -5
  142. data/spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb +25 -0
  143. data/spaceship/lib/spaceship/du/upload_file.rb +1 -1
  144. data/spaceship/lib/spaceship/errors.rb +7 -1
  145. data/spaceship/lib/spaceship/globals.rb +2 -2
  146. data/spaceship/lib/spaceship/portal/merchant.rb +127 -2
  147. data/spaceship/lib/spaceship/portal/portal_client.rb +58 -0
  148. data/spaceship/lib/spaceship/portal/ui/select_team.rb +0 -2
  149. data/spaceship/lib/spaceship/portal/website_push.rb +8 -2
  150. data/spaceship/lib/spaceship/test_flight/client.rb +0 -22
  151. data/spaceship/lib/spaceship/test_flight.rb +0 -1
  152. data/spaceship/lib/spaceship/two_step_or_factor_client.rb +11 -0
  153. data/supply/lib/supply/options.rb +1 -0
  154. data/supply/lib/supply.rb +0 -1
  155. metadata +54 -36
  156. data/produce/lib/produce/available_default_languages.rb +0 -62
  157. data/snapshot/lib/snapshot/screenshot_flatten.rb +0 -20
  158. data/snapshot/lib/snapshot/screenshot_rotate.rb +0 -36
  159. data/spaceship/lib/spaceship/test_flight/app_test_info.rb +0 -40
  160. data/supply/lib/supply/apk_listing.rb +0 -14
  161. /data/fastlane/lib/assets/{custom_action_template.rb → custom_action_template.rb.template} +0 -0
@@ -3068,6 +3068,8 @@ public func chatwork(apiToken: String,
3068
3068
 
3069
3069
  This action deletes the files that get created in your repo as a result of running the _gym_ and _sigh_ commands. It doesn't delete the `fastlane/report.xml` though, this is probably more suited for the .gitignore.
3070
3070
 
3071
+ From _cert_ it only deletes the `.cer` file. The private key (`<certificate id>.p12`, despite its name an unencrypted PEM key) and the `.certSigningRequest` that _cert_ writes to its `output_path` when it creates a certificate are kept: _cert_ uses that `.p12` to install the certificate on a machine that doesn't have it, and on systems other than macOS it is the only copy of the key. Keep them out of version control.
3072
+
3071
3073
  Useful if you quickly want to send out a test build by dropping down to the command line and typing something like `fastlane beta`, without leaving your repo in a messy state afterwards.
3072
3074
  */
3073
3075
  public func cleanBuildArtifacts(excludePattern: OptionalConfigValue<String?> = .fastlaneDefault(nil)) {
@@ -3435,6 +3437,8 @@ public func createAppOnManagedPlayStore(jsonKey: OptionalConfigValue<String?> =
3435
3437
 
3436
3438
  - parameters:
3437
3439
  - username: Your Apple ID Username
3440
+ - apiKeyPath: Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)
3441
+ - apiKey: Your App Store Connect API Key information (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-hash-option)
3438
3442
  - appIdentifier: App Identifier (Bundle ID, e.g. com.krausefx.app)
3439
3443
  - bundleIdentifierSuffix: App Identifier Suffix (Ignored if App Identifier does not end with .*)
3440
3444
  - appName: App Name
@@ -3459,6 +3463,8 @@ public func createAppOnManagedPlayStore(jsonKey: OptionalConfigValue<String?> =
3459
3463
  For more information about _produce_, visit its documentation page: [https://docs.fastlane.tools/actions/produce/](https://docs.fastlane.tools/actions/produce/).
3460
3464
  */
3461
3465
  public func createAppOnline(username: String,
3466
+ apiKeyPath: OptionalConfigValue<String?> = .fastlaneDefault(nil),
3467
+ apiKey: OptionalConfigValue<[String: Any]?> = .fastlaneDefault(nil),
3462
3468
  appIdentifier: String,
3463
3469
  bundleIdentifierSuffix: OptionalConfigValue<String?> = .fastlaneDefault(nil),
3464
3470
  appName: String,
@@ -3479,6 +3485,8 @@ public func createAppOnline(username: String,
3479
3485
  itcTeamName: OptionalConfigValue<String?> = .fastlaneDefault(nil))
3480
3486
  {
3481
3487
  let usernameArg = RubyCommand.Argument(name: "username", value: username, type: nil)
3488
+ let apiKeyPathArg = apiKeyPath.asRubyArgument(name: "api_key_path", type: nil)
3489
+ let apiKeyArg = apiKey.asRubyArgument(name: "api_key", type: nil)
3482
3490
  let appIdentifierArg = RubyCommand.Argument(name: "app_identifier", value: appIdentifier, type: nil)
3483
3491
  let bundleIdentifierSuffixArg = bundleIdentifierSuffix.asRubyArgument(name: "bundle_identifier_suffix", type: nil)
3484
3492
  let appNameArg = RubyCommand.Argument(name: "app_name", value: appName, type: nil)
@@ -3498,6 +3506,8 @@ public func createAppOnline(username: String,
3498
3506
  let itcTeamIdArg = RubyCommand.Argument(name: "itc_team_id", value: itcTeamId, type: nil)
3499
3507
  let itcTeamNameArg = itcTeamName.asRubyArgument(name: "itc_team_name", type: nil)
3500
3508
  let array: [RubyCommand.Argument?] = [usernameArg,
3509
+ apiKeyPathArg,
3510
+ apiKeyArg,
3501
3511
  appIdentifierArg,
3502
3512
  bundleIdentifierSuffixArg,
3503
3513
  appNameArg,
@@ -5214,6 +5224,7 @@ public func getManagedPlayStorePublishingRights(jsonKey: OptionalConfigValue<Str
5214
5224
  - force: Renew provisioning profiles regardless of its state - to automatically add all devices for ad hoc profiles
5215
5225
  - includeMacInProfiles: Include Apple Silicon Mac devices in provisioning profiles for iOS/iPadOS apps
5216
5226
  - appIdentifier: The bundle identifier of your app
5227
+ - offlineProfile: Enable profile with 'Offline Support' (7 day validity). Requires Apple ID login, not supported with App Store Connect API key authentication
5217
5228
  - apiKeyPath: Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)
5218
5229
  - apiKey: Your App Store Connect API Key information (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-hash-option)
5219
5230
  - username: Your Apple ID Username
@@ -5248,6 +5259,7 @@ public func getManagedPlayStorePublishingRights(jsonKey: OptionalConfigValue<Str
5248
5259
  force: OptionalConfigValue<Bool> = .fastlaneDefault(false),
5249
5260
  includeMacInProfiles: OptionalConfigValue<Bool> = .fastlaneDefault(false),
5250
5261
  appIdentifier: String,
5262
+ offlineProfile: OptionalConfigValue<Bool> = .fastlaneDefault(false),
5251
5263
  apiKeyPath: OptionalConfigValue<String?> = .fastlaneDefault(nil),
5252
5264
  apiKey: OptionalConfigValue<[String: Any]?> = .fastlaneDefault(nil),
5253
5265
  username: OptionalConfigValue<String?> = .fastlaneDefault(nil),
@@ -5278,6 +5290,7 @@ public func getManagedPlayStorePublishingRights(jsonKey: OptionalConfigValue<Str
5278
5290
  let forceArg = force.asRubyArgument(name: "force", type: nil)
5279
5291
  let includeMacInProfilesArg = includeMacInProfiles.asRubyArgument(name: "include_mac_in_profiles", type: nil)
5280
5292
  let appIdentifierArg = RubyCommand.Argument(name: "app_identifier", value: appIdentifier, type: nil)
5293
+ let offlineProfileArg = offlineProfile.asRubyArgument(name: "offline_profile", type: nil)
5281
5294
  let apiKeyPathArg = apiKeyPath.asRubyArgument(name: "api_key_path", type: nil)
5282
5295
  let apiKeyArg = apiKey.asRubyArgument(name: "api_key", type: nil)
5283
5296
  let usernameArg = username.asRubyArgument(name: "username", type: nil)
@@ -5307,6 +5320,7 @@ public func getManagedPlayStorePublishingRights(jsonKey: OptionalConfigValue<Str
5307
5320
  forceArg,
5308
5321
  includeMacInProfilesArg,
5309
5322
  appIdentifierArg,
5323
+ offlineProfileArg,
5310
5324
  apiKeyPathArg,
5311
5325
  apiKeyArg,
5312
5326
  usernameArg,
@@ -6923,8 +6937,8 @@ public func makeChangelogFromJenkins(fallbackChangelog: String = "",
6923
6937
  - gitUserEmail: git user email to commit
6924
6938
  - shallowClone: Make a shallow clone of the repository (truncate the history to 1 revision)
6925
6939
  - cloneBranchDirectly: Clone just the branch specified, instead of the whole repo. This requires that the branch already exists. Otherwise the command will fail
6926
- - gitBasicAuthorization: Use a basic authorization header to access the git repo (e.g.: access via HTTPS, GitHub Actions, etc), usually a string in Base64
6927
- - gitBearerAuthorization: Use a bearer authorization header to access the git repo (e.g.: access to an Azure DevOps repository), usually a string in Base64
6940
+ - gitBasicAuthorization: Use a basic authorization header to access the git repo (e.g.: access via HTTPS, GitHub Actions, etc), usually a string in Base64. Needs git 2.31 or later
6941
+ - gitBearerAuthorization: Use a bearer authorization header to access the git repo (e.g.: access to an Azure DevOps repository), usually a string in Base64. Needs git 2.31 or later
6928
6942
  - gitPrivateKey: Use a private key to access the git repo (e.g.: access to GitHub repository via Deploy keys), usually a id_rsa named file or the contents hereof
6929
6943
  - googleCloudBucketName: Name of the Google Cloud Storage bucket to use
6930
6944
  - googleCloudKeysFile: Path to the gc_keys.json file
@@ -6962,6 +6976,7 @@ public func makeChangelogFromJenkins(fallbackChangelog: String = "",
6962
6976
  - outputPath: Path in which to export certificates, key and profile
6963
6977
  - skipSetPartitionList: Skips setting the partition list (which can sometimes take a long time). Setting the partition list is usually needed to prevent Xcode from prompting to allow a cert to be used for signing
6964
6978
  - forceLegacyEncryption: Force encryption to use legacy cbc algorithm for backwards compatibility with older match versions
6979
+ - offlineProfile: Enable profile with 'Offline Support' (7 day validity). Requires Apple ID login, not supported with App Store Connect API key authentication
6965
6980
  - verbose: Print out extra information and all commands
6966
6981
 
6967
6982
  More information: https://docs.fastlane.tools/actions/match/
@@ -7023,6 +7038,7 @@ public func match(type: String = matchfile.type,
7023
7038
  outputPath: OptionalConfigValue<String?> = .fastlaneDefault(matchfile.outputPath),
7024
7039
  skipSetPartitionList: OptionalConfigValue<Bool> = .fastlaneDefault(matchfile.skipSetPartitionList),
7025
7040
  forceLegacyEncryption: OptionalConfigValue<Bool> = .fastlaneDefault(matchfile.forceLegacyEncryption),
7041
+ offlineProfile: OptionalConfigValue<Bool> = .fastlaneDefault(matchfile.offlineProfile),
7026
7042
  verbose: OptionalConfigValue<Bool> = .fastlaneDefault(matchfile.verbose))
7027
7043
  {
7028
7044
  let typeArg = RubyCommand.Argument(name: "type", value: type, type: nil)
@@ -7082,6 +7098,7 @@ public func match(type: String = matchfile.type,
7082
7098
  let outputPathArg = outputPath.asRubyArgument(name: "output_path", type: nil)
7083
7099
  let skipSetPartitionListArg = skipSetPartitionList.asRubyArgument(name: "skip_set_partition_list", type: nil)
7084
7100
  let forceLegacyEncryptionArg = forceLegacyEncryption.asRubyArgument(name: "force_legacy_encryption", type: nil)
7101
+ let offlineProfileArg = offlineProfile.asRubyArgument(name: "offline_profile", type: nil)
7085
7102
  let verboseArg = verbose.asRubyArgument(name: "verbose", type: nil)
7086
7103
  let array: [RubyCommand.Argument?] = [typeArg,
7087
7104
  additionalCertTypesArg,
@@ -7140,6 +7157,7 @@ public func match(type: String = matchfile.type,
7140
7157
  outputPathArg,
7141
7158
  skipSetPartitionListArg,
7142
7159
  forceLegacyEncryptionArg,
7160
+ offlineProfileArg,
7143
7161
  verboseArg]
7144
7162
  let args: [RubyCommand.Argument] = array
7145
7163
  .filter { $0?.value != nil }
@@ -7170,8 +7188,8 @@ public func match(type: String = matchfile.type,
7170
7188
  - gitUserEmail: git user email to commit
7171
7189
  - shallowClone: Make a shallow clone of the repository (truncate the history to 1 revision)
7172
7190
  - cloneBranchDirectly: Clone just the branch specified, instead of the whole repo. This requires that the branch already exists. Otherwise the command will fail
7173
- - gitBasicAuthorization: Use a basic authorization header to access the git repo (e.g.: access via HTTPS, GitHub Actions, etc), usually a string in Base64
7174
- - gitBearerAuthorization: Use a bearer authorization header to access the git repo (e.g.: access to an Azure DevOps repository), usually a string in Base64
7191
+ - gitBasicAuthorization: Use a basic authorization header to access the git repo (e.g.: access via HTTPS, GitHub Actions, etc), usually a string in Base64. Needs git 2.31 or later
7192
+ - gitBearerAuthorization: Use a bearer authorization header to access the git repo (e.g.: access to an Azure DevOps repository), usually a string in Base64. Needs git 2.31 or later
7175
7193
  - gitPrivateKey: Use a private key to access the git repo (e.g.: access to GitHub repository via Deploy keys), usually a id_rsa named file or the contents hereof
7176
7194
  - googleCloudBucketName: Name of the Google Cloud Storage bucket to use
7177
7195
  - googleCloudKeysFile: Path to the gc_keys.json file
@@ -7209,6 +7227,7 @@ public func match(type: String = matchfile.type,
7209
7227
  - outputPath: Path in which to export certificates, key and profile
7210
7228
  - skipSetPartitionList: Skips setting the partition list (which can sometimes take a long time). Setting the partition list is usually needed to prevent Xcode from prompting to allow a cert to be used for signing
7211
7229
  - forceLegacyEncryption: Force encryption to use legacy cbc algorithm for backwards compatibility with older match versions
7230
+ - offlineProfile: Enable profile with 'Offline Support' (7 day validity). Requires Apple ID login, not supported with App Store Connect API key authentication
7212
7231
  - verbose: Print out extra information and all commands
7213
7232
 
7214
7233
  Use the match_nuke action to revoke your certificates and provisioning profiles.
@@ -7274,6 +7293,7 @@ public func matchNuke(type: String = "development",
7274
7293
  outputPath: OptionalConfigValue<String?> = .fastlaneDefault(nil),
7275
7294
  skipSetPartitionList: OptionalConfigValue<Bool> = .fastlaneDefault(false),
7276
7295
  forceLegacyEncryption: OptionalConfigValue<Bool> = .fastlaneDefault(false),
7296
+ offlineProfile: OptionalConfigValue<Bool> = .fastlaneDefault(false),
7277
7297
  verbose: OptionalConfigValue<Bool> = .fastlaneDefault(false))
7278
7298
  {
7279
7299
  let typeArg = RubyCommand.Argument(name: "type", value: type, type: nil)
@@ -7333,6 +7353,7 @@ public func matchNuke(type: String = "development",
7333
7353
  let outputPathArg = outputPath.asRubyArgument(name: "output_path", type: nil)
7334
7354
  let skipSetPartitionListArg = skipSetPartitionList.asRubyArgument(name: "skip_set_partition_list", type: nil)
7335
7355
  let forceLegacyEncryptionArg = forceLegacyEncryption.asRubyArgument(name: "force_legacy_encryption", type: nil)
7356
+ let offlineProfileArg = offlineProfile.asRubyArgument(name: "offline_profile", type: nil)
7336
7357
  let verboseArg = verbose.asRubyArgument(name: "verbose", type: nil)
7337
7358
  let array: [RubyCommand.Argument?] = [typeArg,
7338
7359
  additionalCertTypesArg,
@@ -7391,6 +7412,7 @@ public func matchNuke(type: String = "development",
7391
7412
  outputPathArg,
7392
7413
  skipSetPartitionListArg,
7393
7414
  forceLegacyEncryptionArg,
7415
+ offlineProfileArg,
7394
7416
  verboseArg]
7395
7417
  let args: [RubyCommand.Argument] = array
7396
7418
  .filter { $0?.value != nil }
@@ -7581,8 +7603,8 @@ public func notarize(package: String,
7581
7603
  - message: The message to display in the notification
7582
7604
  - sound: The name of a sound to play when the notification appears (names are listed in Sound Preferences)
7583
7605
  - activate: Bundle identifier of application to be opened when the notification is clicked
7584
- - appIcon: The URL of an image to display instead of the application icon (Mavericks+ only)
7585
- - contentImage: The URL of an image to display attached to the notification (Mavericks+ only)
7606
+ - appIcon: **DEPRECATED!** The URL of an image to display instead of the application icon
7607
+ - contentImage: The local path of an image to display attached to the notification (Mavericks+)
7586
7608
  - open: URL of the resource to be opened when the notification is clicked
7587
7609
  - execute: Shell command to run when the notification is clicked
7588
7610
  */
@@ -8415,6 +8437,8 @@ public func println(message: OptionalConfigValue<String?> = .fastlaneDefault(nil
8415
8437
 
8416
8438
  - parameters:
8417
8439
  - username: Your Apple ID Username
8440
+ - apiKeyPath: Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)
8441
+ - apiKey: Your App Store Connect API Key information (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-hash-option)
8418
8442
  - appIdentifier: App Identifier (Bundle ID, e.g. com.krausefx.app)
8419
8443
  - bundleIdentifierSuffix: App Identifier Suffix (Ignored if App Identifier does not end with .*)
8420
8444
  - appName: App Name
@@ -8439,6 +8463,8 @@ public func println(message: OptionalConfigValue<String?> = .fastlaneDefault(nil
8439
8463
  For more information about _produce_, visit its documentation page: [https://docs.fastlane.tools/actions/produce/](https://docs.fastlane.tools/actions/produce/).
8440
8464
  */
8441
8465
  public func produce(username: String,
8466
+ apiKeyPath: OptionalConfigValue<String?> = .fastlaneDefault(nil),
8467
+ apiKey: OptionalConfigValue<[String: Any]?> = .fastlaneDefault(nil),
8442
8468
  appIdentifier: String,
8443
8469
  bundleIdentifierSuffix: OptionalConfigValue<String?> = .fastlaneDefault(nil),
8444
8470
  appName: String,
@@ -8459,6 +8485,8 @@ public func produce(username: String,
8459
8485
  itcTeamName: OptionalConfigValue<String?> = .fastlaneDefault(nil))
8460
8486
  {
8461
8487
  let usernameArg = RubyCommand.Argument(name: "username", value: username, type: nil)
8488
+ let apiKeyPathArg = apiKeyPath.asRubyArgument(name: "api_key_path", type: nil)
8489
+ let apiKeyArg = apiKey.asRubyArgument(name: "api_key", type: nil)
8462
8490
  let appIdentifierArg = RubyCommand.Argument(name: "app_identifier", value: appIdentifier, type: nil)
8463
8491
  let bundleIdentifierSuffixArg = bundleIdentifierSuffix.asRubyArgument(name: "bundle_identifier_suffix", type: nil)
8464
8492
  let appNameArg = RubyCommand.Argument(name: "app_name", value: appName, type: nil)
@@ -8478,6 +8506,8 @@ public func produce(username: String,
8478
8506
  let itcTeamIdArg = RubyCommand.Argument(name: "itc_team_id", value: itcTeamId, type: nil)
8479
8507
  let itcTeamNameArg = itcTeamName.asRubyArgument(name: "itc_team_name", type: nil)
8480
8508
  let array: [RubyCommand.Argument?] = [usernameArg,
8509
+ apiKeyPathArg,
8510
+ apiKeyArg,
8481
8511
  appIdentifierArg,
8482
8512
  bundleIdentifierSuffixArg,
8483
8513
  appNameArg,
@@ -9002,6 +9032,7 @@ public func rubyVersion() {
9002
9032
  - codeCoverage: Should code coverage be generated? (Xcode 7 and up)
9003
9033
  - addressSanitizer: Should the address sanitizer be turned on?
9004
9034
  - threadSanitizer: Should the thread sanitizer be turned on?
9035
+ - collectTestDiagnostics: Whether verbose and long-running diagnostics (like sysdiagnoses or log archives) are collected when testing. Valid values are: on-failure or never. If not specified, the value in the test plan is used. Equivalent to -collect-test-diagnostics (Xcode 14 and up)
9005
9036
  - openReport: Should the HTML report be opened when tests are completed?
9006
9037
  - outputDirectory: The directory in which all reports will be stored
9007
9038
  - outputStyle: Define how the output should look like. Valid values are: standard, basic, rspec, or raw (disables xcpretty during xcodebuild)
@@ -9090,6 +9121,7 @@ public func rubyVersion() {
9090
9121
  codeCoverage: OptionalConfigValue<Bool?> = .fastlaneDefault(nil),
9091
9122
  addressSanitizer: OptionalConfigValue<Bool?> = .fastlaneDefault(nil),
9092
9123
  threadSanitizer: OptionalConfigValue<Bool?> = .fastlaneDefault(nil),
9124
+ collectTestDiagnostics: OptionalConfigValue<String?> = .fastlaneDefault(nil),
9093
9125
  openReport: OptionalConfigValue<Bool> = .fastlaneDefault(false),
9094
9126
  outputDirectory: String = "./test_output",
9095
9127
  outputStyle: OptionalConfigValue<String?> = .fastlaneDefault(nil),
@@ -9174,6 +9206,7 @@ public func rubyVersion() {
9174
9206
  let codeCoverageArg = codeCoverage.asRubyArgument(name: "code_coverage", type: nil)
9175
9207
  let addressSanitizerArg = addressSanitizer.asRubyArgument(name: "address_sanitizer", type: nil)
9176
9208
  let threadSanitizerArg = threadSanitizer.asRubyArgument(name: "thread_sanitizer", type: nil)
9209
+ let collectTestDiagnosticsArg = collectTestDiagnostics.asRubyArgument(name: "collect_test_diagnostics", type: nil)
9177
9210
  let openReportArg = openReport.asRubyArgument(name: "open_report", type: nil)
9178
9211
  let outputDirectoryArg = RubyCommand.Argument(name: "output_directory", value: outputDirectory, type: nil)
9179
9212
  let outputStyleArg = outputStyle.asRubyArgument(name: "output_style", type: nil)
@@ -9257,6 +9290,7 @@ public func rubyVersion() {
9257
9290
  codeCoverageArg,
9258
9291
  addressSanitizerArg,
9259
9292
  threadSanitizerArg,
9293
+ collectTestDiagnosticsArg,
9260
9294
  openReportArg,
9261
9295
  outputDirectoryArg,
9262
9296
  outputStyleArg,
@@ -9453,6 +9487,7 @@ public func say(text: [String],
9453
9487
  - codeCoverage: Should code coverage be generated? (Xcode 7 and up)
9454
9488
  - addressSanitizer: Should the address sanitizer be turned on?
9455
9489
  - threadSanitizer: Should the thread sanitizer be turned on?
9490
+ - collectTestDiagnostics: Whether verbose and long-running diagnostics (like sysdiagnoses or log archives) are collected when testing. Valid values are: on-failure or never. If not specified, the value in the test plan is used. Equivalent to -collect-test-diagnostics (Xcode 14 and up)
9456
9491
  - openReport: Should the HTML report be opened when tests are completed?
9457
9492
  - outputDirectory: The directory in which all reports will be stored
9458
9493
  - outputStyle: Define how the output should look like. Valid values are: standard, basic, rspec, or raw (disables xcpretty during xcodebuild)
@@ -9541,6 +9576,7 @@ public func say(text: [String],
9541
9576
  codeCoverage: OptionalConfigValue<Bool?> = .fastlaneDefault(scanfile.codeCoverage),
9542
9577
  addressSanitizer: OptionalConfigValue<Bool?> = .fastlaneDefault(scanfile.addressSanitizer),
9543
9578
  threadSanitizer: OptionalConfigValue<Bool?> = .fastlaneDefault(scanfile.threadSanitizer),
9579
+ collectTestDiagnostics: OptionalConfigValue<String?> = .fastlaneDefault(scanfile.collectTestDiagnostics),
9544
9580
  openReport: OptionalConfigValue<Bool> = .fastlaneDefault(scanfile.openReport),
9545
9581
  outputDirectory: String = scanfile.outputDirectory,
9546
9582
  outputStyle: OptionalConfigValue<String?> = .fastlaneDefault(scanfile.outputStyle),
@@ -9625,6 +9661,7 @@ public func say(text: [String],
9625
9661
  let codeCoverageArg = codeCoverage.asRubyArgument(name: "code_coverage", type: nil)
9626
9662
  let addressSanitizerArg = addressSanitizer.asRubyArgument(name: "address_sanitizer", type: nil)
9627
9663
  let threadSanitizerArg = threadSanitizer.asRubyArgument(name: "thread_sanitizer", type: nil)
9664
+ let collectTestDiagnosticsArg = collectTestDiagnostics.asRubyArgument(name: "collect_test_diagnostics", type: nil)
9628
9665
  let openReportArg = openReport.asRubyArgument(name: "open_report", type: nil)
9629
9666
  let outputDirectoryArg = RubyCommand.Argument(name: "output_directory", value: outputDirectory, type: nil)
9630
9667
  let outputStyleArg = outputStyle.asRubyArgument(name: "output_style", type: nil)
@@ -9708,6 +9745,7 @@ public func say(text: [String],
9708
9745
  codeCoverageArg,
9709
9746
  addressSanitizerArg,
9710
9747
  threadSanitizerArg,
9748
+ collectTestDiagnosticsArg,
9711
9749
  openReportArg,
9712
9750
  outputDirectoryArg,
9713
9751
  outputStyleArg,
@@ -10311,6 +10349,7 @@ public func setupTravis(force: OptionalConfigValue<Bool> = .fastlaneDefault(fals
10311
10349
  - force: Renew provisioning profiles regardless of its state - to automatically add all devices for ad hoc profiles
10312
10350
  - includeMacInProfiles: Include Apple Silicon Mac devices in provisioning profiles for iOS/iPadOS apps
10313
10351
  - appIdentifier: The bundle identifier of your app
10352
+ - offlineProfile: Enable profile with 'Offline Support' (7 day validity). Requires Apple ID login, not supported with App Store Connect API key authentication
10314
10353
  - apiKeyPath: Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)
10315
10354
  - apiKey: Your App Store Connect API Key information (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-hash-option)
10316
10355
  - username: Your Apple ID Username
@@ -10345,6 +10384,7 @@ public func setupTravis(force: OptionalConfigValue<Bool> = .fastlaneDefault(fals
10345
10384
  force: OptionalConfigValue<Bool> = .fastlaneDefault(false),
10346
10385
  includeMacInProfiles: OptionalConfigValue<Bool> = .fastlaneDefault(false),
10347
10386
  appIdentifier: String,
10387
+ offlineProfile: OptionalConfigValue<Bool> = .fastlaneDefault(false),
10348
10388
  apiKeyPath: OptionalConfigValue<String?> = .fastlaneDefault(nil),
10349
10389
  apiKey: OptionalConfigValue<[String: Any]?> = .fastlaneDefault(nil),
10350
10390
  username: OptionalConfigValue<String?> = .fastlaneDefault(nil),
@@ -10375,6 +10415,7 @@ public func setupTravis(force: OptionalConfigValue<Bool> = .fastlaneDefault(fals
10375
10415
  let forceArg = force.asRubyArgument(name: "force", type: nil)
10376
10416
  let includeMacInProfilesArg = includeMacInProfiles.asRubyArgument(name: "include_mac_in_profiles", type: nil)
10377
10417
  let appIdentifierArg = RubyCommand.Argument(name: "app_identifier", value: appIdentifier, type: nil)
10418
+ let offlineProfileArg = offlineProfile.asRubyArgument(name: "offline_profile", type: nil)
10378
10419
  let apiKeyPathArg = apiKeyPath.asRubyArgument(name: "api_key_path", type: nil)
10379
10420
  let apiKeyArg = apiKey.asRubyArgument(name: "api_key", type: nil)
10380
10421
  let usernameArg = username.asRubyArgument(name: "username", type: nil)
@@ -10404,6 +10445,7 @@ public func setupTravis(force: OptionalConfigValue<Bool> = .fastlaneDefault(fals
10404
10445
  forceArg,
10405
10446
  includeMacInProfilesArg,
10406
10447
  appIdentifierArg,
10448
+ offlineProfileArg,
10407
10449
  apiKeyPathArg,
10408
10450
  apiKeyArg,
10409
10451
  usernameArg,
@@ -11536,8 +11578,8 @@ public func swiftlint(mode: String = "lint",
11536
11578
  - gitUserEmail: git user email to commit
11537
11579
  - shallowClone: Make a shallow clone of the repository (truncate the history to 1 revision)
11538
11580
  - cloneBranchDirectly: Clone just the branch specified, instead of the whole repo. This requires that the branch already exists. Otherwise the command will fail
11539
- - gitBasicAuthorization: Use a basic authorization header to access the git repo (e.g.: access via HTTPS, GitHub Actions, etc), usually a string in Base64
11540
- - gitBearerAuthorization: Use a bearer authorization header to access the git repo (e.g.: access to an Azure DevOps repository), usually a string in Base64
11581
+ - gitBasicAuthorization: Use a basic authorization header to access the git repo (e.g.: access via HTTPS, GitHub Actions, etc), usually a string in Base64. Needs git 2.31 or later
11582
+ - gitBearerAuthorization: Use a bearer authorization header to access the git repo (e.g.: access to an Azure DevOps repository), usually a string in Base64. Needs git 2.31 or later
11541
11583
  - gitPrivateKey: Use a private key to access the git repo (e.g.: access to GitHub repository via Deploy keys), usually a id_rsa named file or the contents hereof
11542
11584
  - googleCloudBucketName: Name of the Google Cloud Storage bucket to use
11543
11585
  - googleCloudKeysFile: Path to the gc_keys.json file
@@ -11575,6 +11617,7 @@ public func swiftlint(mode: String = "lint",
11575
11617
  - outputPath: Path in which to export certificates, key and profile
11576
11618
  - skipSetPartitionList: Skips setting the partition list (which can sometimes take a long time). Setting the partition list is usually needed to prevent Xcode from prompting to allow a cert to be used for signing
11577
11619
  - forceLegacyEncryption: Force encryption to use legacy cbc algorithm for backwards compatibility with older match versions
11620
+ - offlineProfile: Enable profile with 'Offline Support' (7 day validity). Requires Apple ID login, not supported with App Store Connect API key authentication
11578
11621
  - verbose: Print out extra information and all commands
11579
11622
 
11580
11623
  More information: https://docs.fastlane.tools/actions/match/
@@ -11636,6 +11679,7 @@ public func syncCodeSigning(type: String = "development",
11636
11679
  outputPath: OptionalConfigValue<String?> = .fastlaneDefault(nil),
11637
11680
  skipSetPartitionList: OptionalConfigValue<Bool> = .fastlaneDefault(false),
11638
11681
  forceLegacyEncryption: OptionalConfigValue<Bool> = .fastlaneDefault(false),
11682
+ offlineProfile: OptionalConfigValue<Bool> = .fastlaneDefault(false),
11639
11683
  verbose: OptionalConfigValue<Bool> = .fastlaneDefault(false))
11640
11684
  {
11641
11685
  let typeArg = RubyCommand.Argument(name: "type", value: type, type: nil)
@@ -11695,6 +11739,7 @@ public func syncCodeSigning(type: String = "development",
11695
11739
  let outputPathArg = outputPath.asRubyArgument(name: "output_path", type: nil)
11696
11740
  let skipSetPartitionListArg = skipSetPartitionList.asRubyArgument(name: "skip_set_partition_list", type: nil)
11697
11741
  let forceLegacyEncryptionArg = forceLegacyEncryption.asRubyArgument(name: "force_legacy_encryption", type: nil)
11742
+ let offlineProfileArg = offlineProfile.asRubyArgument(name: "offline_profile", type: nil)
11698
11743
  let verboseArg = verbose.asRubyArgument(name: "verbose", type: nil)
11699
11744
  let array: [RubyCommand.Argument?] = [typeArg,
11700
11745
  additionalCertTypesArg,
@@ -11753,6 +11798,7 @@ public func syncCodeSigning(type: String = "development",
11753
11798
  outputPathArg,
11754
11799
  skipSetPartitionListArg,
11755
11800
  forceLegacyEncryptionArg,
11801
+ offlineProfileArg,
11756
11802
  verboseArg]
11757
11803
  let args: [RubyCommand.Argument] = array
11758
11804
  .filter { $0?.value != nil }
@@ -14215,4 +14261,4 @@ public let snapshotfile: Snapshotfile = .init()
14215
14261
 
14216
14262
  // Please don't remove the lines below
14217
14263
  // They are used to detect outdated files
14218
- // FastlaneRunnerAPIVersion [0.9.208]
14264
+ // FastlaneRunnerAPIVersion [0.9.209]
@@ -17,4 +17,4 @@ public class Gymfile: GymfileProtocol {
17
17
  // during the `init` process, and you won't see this message
18
18
  }
19
19
 
20
- // Generated with fastlane 2.240.1
20
+ // Generated with fastlane 2.241.0
@@ -399,4 +399,4 @@ public extension GymfileProtocol {
399
399
 
400
400
  // Please don't remove the lines below
401
401
  // They are used to detect outdated files
402
- // FastlaneRunnerAPIVersion [0.9.158]
402
+ // FastlaneRunnerAPIVersion [0.9.159]
@@ -9,9 +9,6 @@
9
9
  //
10
10
 
11
11
  import Foundation
12
- #if canImport(SwiftShell)
13
- import SwiftShell
14
- #endif
15
12
 
16
13
  let argumentProcessor = ArgumentProcessor(args: CommandLine.arguments)
17
14
  let timeout = argumentProcessor.commandTimeout
@@ -20,9 +17,7 @@ class MainProcess {
20
17
  var doneRunningLane = false
21
18
  var thread: Thread!
22
19
  #if SWIFT_PACKAGE
23
- var lastPrintDate = Date.distantFuture
24
- var timeBetweenPrints = Int.min
25
- var rubySocketCommand: AsyncCommand!
20
+ var rubySocketCommand: Process!
26
21
  #endif
27
22
 
28
23
  @objc func connectToFastlaneAndRunLane(_ fastfile: LaneFile?) {
@@ -44,24 +39,199 @@ class MainProcess {
44
39
  #endif
45
40
  thread.name = "worker thread"
46
41
  #if SWIFT_PACKAGE
47
- let PATH = run("/bin/bash", "-c", "-l", "eval $(/usr/libexec/path_helper -s) ; echo $PATH").stdout
48
- main.env["PATH"] = PATH
49
- let path = main.run(bash: "which fastlane").stdout
50
- let pids = main.run("lsof", "-t", "-i", ":\(argumentProcessor.port)").stdout.split(separator: "\n")
51
- pids.forEach { main.run("kill", "-9", $0) }
52
- rubySocketCommand = main.runAsync(path, "socket_server", "-c", argumentProcessor.commandTimeout, "-p", argumentProcessor.port)
53
- lastPrintDate = Date()
54
- rubySocketCommand.stderror.onStringOutput { print($0) }
55
- rubySocketCommand.stdout.onStringOutput { stdout in
56
- print(stdout)
57
- self.timeBetweenPrints = Int(self.lastPrintDate.timeIntervalSinceNow)
58
- }
42
+ killExistingSocketServerProcesses(port: argumentProcessor.port)
43
+ abortIfPortIsInUse(argumentProcessor.port)
44
+
45
+ rubySocketCommand = Process()
46
+ rubySocketCommand.launchPath = "/usr/bin/env"
47
+ rubySocketCommand.arguments = fastlaneLaunchArguments() + ["socket_server", "-c", String(timeout), "-p", String(argumentProcessor.port)]
48
+ rubySocketCommand.launch()
59
49
 
60
- // swiftformat:disable:next redundantSelf
61
- _ = Runner.waitWithPolling(self.timeBetweenPrints, toEventually: { $0 > 5 }, timeout: 10)
50
+ waitUntilSocketServerIsListening(port: argumentProcessor.port, serverProcess: rubySocketCommand)
62
51
  thread.start()
63
52
  #endif
64
53
  }
54
+
55
+ #if SWIFT_PACKAGE
56
+ /// Resolves how to invoke fastlane, replacing the previous login-shell
57
+ /// `eval $(path_helper)` + `which fastlane` lookup that broke under
58
+ /// rbenv / bundler / system-ruby mixes (#29238). First match wins:
59
+ /// 1. FASTLANE_SPM_BIN environment variable (explicit override)
60
+ /// 2. bundler binstub bin/fastlane next to the Gemfile
61
+ /// 3. Gemfile (BUNDLE_GEMFILE, or found from the working directory up, as Bundler does) -> bundle exec fastlane
62
+ /// 4. fastlane on PATH
63
+ func fastlaneLaunchArguments() -> [String] {
64
+ if let bin = ProcessInfo.processInfo.environment["FASTLANE_SPM_BIN"],
65
+ !bin.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
66
+ {
67
+ // The shell splits the value, so quoted paths with spaces work; our arguments
68
+ // pass through "$@" untouched, and exec keeps the launched process ID.
69
+ return ["/bin/sh", "-c", "exec \(bin) \"$@\"", "sh"]
70
+ }
71
+ guard let bundleRoot = bundleRootDirectory() else {
72
+ return ["fastlane"]
73
+ }
74
+ let binstub = bundleRoot + "/bin/fastlane"
75
+ if FileManager.default.isExecutableFile(atPath: binstub) {
76
+ return [binstub]
77
+ }
78
+ return ["bundle", "exec", "fastlane"]
79
+ }
80
+
81
+ /// The directory of the Gemfile Bundler would use: BUNDLE_GEMFILE, else the
82
+ /// nearest Gemfile or gems.rb from the working directory up.
83
+ func bundleRootDirectory() -> String? {
84
+ let workingDirectory = FileManager.default.currentDirectoryPath
85
+ if let gemfile = ProcessInfo.processInfo.environment["BUNDLE_GEMFILE"], !gemfile.isEmpty {
86
+ let path = gemfile.hasPrefix("/") ? gemfile : workingDirectory + "/" + gemfile
87
+ return (path as NSString).deletingLastPathComponent
88
+ }
89
+ var directory = workingDirectory
90
+ while true {
91
+ for name in ["Gemfile", "gems.rb"] where FileManager.default.fileExists(atPath: directory + "/" + name) {
92
+ return directory
93
+ }
94
+ let parent = (directory as NSString).deletingLastPathComponent
95
+ if parent == directory || parent.isEmpty {
96
+ return nil
97
+ }
98
+ directory = parent
99
+ }
100
+ }
101
+
102
+ /// The ruby socket server performs a single `accept` (see
103
+ /// fastlane/server/socket_server.rb), so probing readiness with a TCP
104
+ /// connection would consume that accept and shut the server down.
105
+ /// Poll the LISTEN state read-only via lsof instead of the previous
106
+ /// "stdout quiet for 5 seconds" heuristic.
107
+ private func waitUntilSocketServerIsListening(port: UInt32, serverProcess: Process) {
108
+ let deadline = Date(timeIntervalSinceNow: 30)
109
+ while Date() < deadline {
110
+ if !serverProcess.isRunning {
111
+ log(message: "fastlane socket_server exited with status \(serverProcess.terminationStatus) before listening. Check that the resolved fastlane installation works (e.g. `bundle exec fastlane --version`).")
112
+ exit(1)
113
+ }
114
+ if isPortListening(port, by: serverProcess.processIdentifier) {
115
+ return
116
+ }
117
+ Thread.sleep(forTimeInterval: 0.2)
118
+ }
119
+ // Don't leak the socket server: it's still running (just not
120
+ // listening yet) on this timeout path, so terminate it before exit.
121
+ terminate(serverProcess: serverProcess)
122
+ log(message: "fastlane socket_server did not start listening on port \(port) within 30 seconds")
123
+ exit(1)
124
+ }
125
+
126
+ /// Terminate the socket server, escalating SIGTERM to SIGKILL if it
127
+ /// doesn't exit promptly, so the timeout path never leaves an orphan.
128
+ private func terminate(serverProcess: Process) {
129
+ serverProcess.terminate()
130
+ let killDeadline = Date(timeIntervalSinceNow: 2)
131
+ while serverProcess.isRunning, Date() < killDeadline {
132
+ Thread.sleep(forTimeInterval: 0.1)
133
+ }
134
+ if serverProcess.isRunning {
135
+ _ = outputOfProcess(arguments: ["/bin/kill", "-9", String(serverProcess.processIdentifier)])
136
+ serverProcess.waitUntilExit()
137
+ }
138
+ }
139
+
140
+ /// Clears a stale socket server left by a previously crashed run on this
141
+ /// port. Scoped to LISTENing ruby processes (`-sTCP:LISTEN -a -c ruby`)
142
+ /// so it never kills an unrelated service or a connected client that
143
+ /// happens to share the port.
144
+ private func killExistingSocketServerProcesses(port: UInt32) {
145
+ let pids = outputOfProcess(arguments: [lsofPath, "-t", "-nP", "-iTCP:\(port)", "-sTCP:LISTEN", "-a", "-c", "ruby"])
146
+ .split(separator: "\n")
147
+ pids.forEach { _ = outputOfProcess(arguments: ["/bin/kill", "-9", String($0)]) }
148
+ }
149
+
150
+ /// socket_server listens on whichever of 127.0.0.1 and ::1 is free, while the runner connects to `localhost`,
151
+ /// so a process holding the port on either address would receive the runner's commands.
152
+ private func abortIfPortIsInUse(_ port: UInt32) {
153
+ guard isAddressInUse(family: AF_INET, port: port) || isAddressInUse(family: AF_INET6, port: port) else {
154
+ return
155
+ }
156
+ // lsof only lists this user's processes unless run as root
157
+ let holders = outputOfProcess(arguments: [lsofPath, "-nP", "-iTCP:\(port)", "-sTCP:LISTEN"])
158
+ let holder = holders.isEmpty ? " by a process of another user" : ":\n\(holders)"
159
+ log(message: "Port \(port) is already in use on localhost\(holder)\nStop it, or choose another port for the runner with `swiftServerPort`.")
160
+ exit(1)
161
+ }
162
+
163
+ /// Binding fails with EADDRINUSE when another socket listens on that address and port, whoever owns it.
164
+ func isAddressInUse(family: Int32, port: UInt32) -> Bool {
165
+ let socketDescriptor = socket(family, SOCK_STREAM, 0)
166
+ guard socketDescriptor >= 0 else {
167
+ return false
168
+ }
169
+ defer { close(socketDescriptor) }
170
+ // Ignore connections left in TIME_WAIT by an earlier run, as the Ruby server does
171
+ var reuse: Int32 = 1
172
+ setsockopt(socketDescriptor, SOL_SOCKET, SO_REUSEADDR, &reuse, socklen_t(MemoryLayout<Int32>.size))
173
+
174
+ let result: Int32
175
+ if family == AF_INET {
176
+ var address = sockaddr_in()
177
+ address.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
178
+ address.sin_family = sa_family_t(AF_INET)
179
+ address.sin_port = in_port_t(UInt16(port).bigEndian)
180
+ address.sin_addr.s_addr = inet_addr("127.0.0.1")
181
+ result = withUnsafePointer(to: &address) {
182
+ $0.withMemoryRebound(to: sockaddr.self, capacity: 1) { bind(socketDescriptor, $0, socklen_t(MemoryLayout<sockaddr_in>.size)) }
183
+ }
184
+ } else {
185
+ var address = sockaddr_in6()
186
+ address.sin6_len = UInt8(MemoryLayout<sockaddr_in6>.size)
187
+ address.sin6_family = sa_family_t(AF_INET6)
188
+ address.sin6_port = in_port_t(UInt16(port).bigEndian)
189
+ address.sin6_addr = in6addr_loopback
190
+ result = withUnsafePointer(to: &address) {
191
+ $0.withMemoryRebound(to: sockaddr.self, capacity: 1) { bind(socketDescriptor, $0, socklen_t(MemoryLayout<sockaddr_in6>.size)) }
192
+ }
193
+ }
194
+ return result != 0 && errno == EADDRINUSE
195
+ }
196
+
197
+ /// Only the process we launched counts: another process listening on the port is not our server
198
+ private func isPortListening(_ port: UInt32, by processIdentifier: Int32) -> Bool {
199
+ let result = runProcess(arguments: [lsofPath, "-t", "-nP", "-iTCP:\(port)", "-sTCP:LISTEN"])
200
+ // `env` exits 127 when lsof can't be found. Without this guard the
201
+ // probe would silently return false on every poll, then kill the
202
+ // freshly launched server after the 30s timeout with a misleading
203
+ // "did not start listening" message. Fail fast with the real cause.
204
+ if result.status == 127 {
205
+ log(message: "Could not run lsof (\(lsofPath)) to check socket server readiness. lsof ships at /usr/sbin/lsof on macOS; ensure it is installed and reachable.")
206
+ exit(1)
207
+ }
208
+ return result.output.split(separator: "\n").contains { $0 == Substring(String(processIdentifier)) }
209
+ }
210
+
211
+ /// Prefer the absolute macOS path so port checks don't depend on PATH;
212
+ /// fall back to a PATH lookup if lsof lives somewhere non-standard.
213
+ private var lsofPath: String {
214
+ let standardPath = "/usr/sbin/lsof"
215
+ return FileManager.default.isExecutableFile(atPath: standardPath) ? standardPath : "lsof"
216
+ }
217
+
218
+ private func outputOfProcess(arguments: [String]) -> String {
219
+ return runProcess(arguments: arguments).output
220
+ }
221
+
222
+ private func runProcess(arguments: [String]) -> (output: String, status: Int32) {
223
+ let process = Process()
224
+ let pipe = Pipe()
225
+ process.launchPath = "/usr/bin/env"
226
+ process.arguments = arguments
227
+ process.standardOutput = pipe
228
+ process.standardError = FileHandle.nullDevice
229
+ process.launch()
230
+ process.waitUntilExit()
231
+ let data = pipe.fileHandleForReading.readDataToEndOfFile()
232
+ return (String(data: data, encoding: .utf8) ?? "", process.terminationStatus)
233
+ }
234
+ #endif
65
235
  }
66
236
 
67
237
  public class Main {
@@ -17,4 +17,4 @@ public class Matchfile: MatchfileProtocol {
17
17
  // during the `init` process, and you won't see this message
18
18
  }
19
19
 
20
- // Generated with fastlane 2.240.1
20
+ // Generated with fastlane 2.241.0