fastlane 2.135.2 → 2.140.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +64 -64
  3. data/deliver/lib/deliver/submit_for_review.rb +7 -1
  4. data/fastlane/lib/fastlane/action.rb +2 -2
  5. data/fastlane/lib/fastlane/actions/.hockey.rb.swp +0 -0
  6. data/fastlane/lib/fastlane/actions/.slack.rb.swp +0 -0
  7. data/fastlane/lib/fastlane/actions/.update_project_provisioning.rb.swp +0 -0
  8. data/fastlane/lib/fastlane/actions/app_store_build_number.rb +1 -1
  9. data/fastlane/lib/fastlane/actions/create_pull_request.rb +42 -2
  10. data/fastlane/lib/fastlane/actions/docs/capture_android_screenshots.md +38 -4
  11. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +19 -0
  12. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +10 -0
  13. data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +4 -2
  14. data/fastlane/lib/fastlane/actions/ensure_bundle_exec.rb +3 -3
  15. data/fastlane/lib/fastlane/actions/get_version_number.rb +7 -2
  16. data/fastlane/lib/fastlane/actions/gradle.rb +54 -3
  17. data/fastlane/lib/fastlane/actions/increment_version_number.rb +6 -3
  18. data/fastlane/lib/fastlane/actions/last_git_tag.rb +14 -5
  19. data/fastlane/lib/fastlane/actions/latest_testflight_build_number.rb +2 -2
  20. data/fastlane/lib/fastlane/actions/register_devices.rb +5 -1
  21. data/fastlane/lib/fastlane/actions/ruby_version.rb +1 -1
  22. data/fastlane/lib/fastlane/actions/run_tests.rb +5 -22
  23. data/fastlane/lib/fastlane/actions/setup_ci.rb +14 -8
  24. data/fastlane/lib/fastlane/actions/testfairy.rb +8 -1
  25. data/fastlane/lib/fastlane/actions/upload_to_play_store_internal_app_sharing.rb +78 -0
  26. data/fastlane/lib/fastlane/actions/verify_build.rb +1 -1
  27. data/fastlane/lib/fastlane/actions/xcode_select.rb +6 -1
  28. data/fastlane/lib/fastlane/cli_tools_distributor.rb +2 -2
  29. data/fastlane/lib/fastlane/commands_generator.rb +1 -1
  30. data/fastlane/lib/fastlane/helper/adb_helper.rb +13 -4
  31. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +1 -0
  32. data/fastlane/lib/fastlane/runner.rb +23 -18
  33. data/fastlane/lib/fastlane/swift_fastlane_function.rb +9 -0
  34. data/fastlane/lib/fastlane/version.rb +1 -1
  35. data/fastlane/swift/Deliverfile.swift +1 -1
  36. data/fastlane/swift/Fastlane.swift +130 -28
  37. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.xcworkspace/xcuserdata/josh.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  38. data/fastlane/swift/Gymfile.swift +1 -1
  39. data/fastlane/swift/Matchfile.swift +1 -1
  40. data/fastlane/swift/MatchfileProtocol.swift +6 -2
  41. data/fastlane/swift/Precheckfile.swift +1 -1
  42. data/fastlane/swift/Scanfile.swift +1 -1
  43. data/fastlane/swift/ScanfileProtocol.swift +13 -1
  44. data/fastlane/swift/Screengrabfile.swift +1 -1
  45. data/fastlane/swift/ScreengrabfileProtocol.swift +14 -2
  46. data/fastlane/swift/Snapshotfile.swift +1 -1
  47. data/fastlane_core/lib/fastlane_core/.build_watcher.rb.swp +0 -0
  48. data/fastlane_core/lib/fastlane_core/build_watcher.rb +6 -2
  49. data/fastlane_core/lib/fastlane_core/device_manager.rb +20 -0
  50. data/fastlane_core/lib/fastlane_core/helper.rb +7 -1
  51. data/frameit/lib/frameit/editor.rb +3 -0
  52. data/gym/lib/gym/generators/build_command_generator.rb +1 -0
  53. data/gym/lib/gym/runner.rb +38 -19
  54. data/match/lib/match/options.rb +8 -0
  55. data/match/lib/match/runner.rb +1 -0
  56. data/match/lib/match/storage/git_storage.rb +7 -2
  57. data/pilot/lib/pilot/.manager.rb.swp +0 -0
  58. data/pilot/lib/pilot/build_manager.rb +46 -12
  59. data/pilot/lib/pilot/options.rb +3 -1
  60. data/scan/lib/scan/detect_values.rb +6 -1
  61. data/scan/lib/scan/manager.rb +18 -1
  62. data/scan/lib/scan/options.rb +17 -0
  63. data/scan/lib/scan/runner.rb +6 -0
  64. data/scan/lib/scan/slack_poster.rb +1 -1
  65. data/scan/lib/scan/test_command_generator.rb +1 -1
  66. data/screengrab/lib/screengrab/module.rb +2 -0
  67. data/screengrab/lib/screengrab/options.rb +24 -11
  68. data/screengrab/lib/screengrab/runner.rb +79 -42
  69. data/spaceship/lib/spaceship/client.rb +9 -4
  70. data/spaceship/lib/spaceship/connect_api.rb +2 -0
  71. data/spaceship/lib/spaceship/connect_api/.DS_Store +0 -0
  72. data/spaceship/lib/spaceship/connect_api/models/app.rb +11 -0
  73. data/spaceship/lib/spaceship/connect_api/models/beta_feedback.rb +71 -0
  74. data/spaceship/lib/spaceship/connect_api/models/beta_screenshot.rb +18 -0
  75. data/spaceship/lib/spaceship/connect_api/models/build.rb +5 -0
  76. data/spaceship/lib/spaceship/connect_api/models/build_beta_detail.rb +5 -0
  77. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +9 -0
  78. data/spaceship/lib/spaceship/portal/.certificate.rb.swp +0 -0
  79. data/spaceship/lib/spaceship/tunes/iap.rb +11 -11
  80. data/spaceship/lib/spaceship/tunes/iap_detail.rb +7 -3
  81. data/spaceship/lib/spaceship/tunes/iap_families.rb +12 -1
  82. data/spaceship/lib/spaceship/tunes/iap_family_details.rb +26 -17
  83. data/spaceship/lib/spaceship/tunes/tunes_client.rb +4 -7
  84. data/supply/lib/supply/client.rb +27 -0
  85. data/supply/lib/supply/options.rb +8 -2
  86. data/supply/lib/supply/uploader.rb +82 -33
  87. metadata +49 -26
  88. data/supply/lib/supply/.options.rb.swp +0 -0
  89. data/supply/lib/supply/.uploader.rb.swp +0 -0
@@ -18,4 +18,4 @@ class Gymfile: GymfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.135.2
21
+ // Generated with fastlane 2.140.0
@@ -18,4 +18,4 @@ class Matchfile: MatchfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.135.2
21
+ // Generated with fastlane 2.140.0
@@ -48,6 +48,9 @@ protocol MatchfileProtocol: class {
48
48
  /// Use a basic authorization header to access the git repo (e.g.: access via HTTPS, GitHub Actions, etc), usually a string in Base64
49
49
  var gitBasicAuthorization: String? { get }
50
50
 
51
+ /// Use a bearer authorization header to access the git repo (e.g.: access to an Azure Devops repository), usually a string in Base64
52
+ var gitBearerAuthorization: String? { get }
53
+
51
54
  /// Name of the Google Cloud Storage bucket to use
52
55
  var googleCloudBucketName: String? { get }
53
56
 
@@ -91,7 +94,7 @@ protocol MatchfileProtocol: class {
91
94
  extension MatchfileProtocol {
92
95
  var type: String { return "development" }
93
96
  var readonly: Bool { return false }
94
- var generateAppleCerts: Bool { return false }
97
+ var generateAppleCerts: Bool { return true }
95
98
  var skipProvisioningProfiles: Bool { return false }
96
99
  var appIdentifier: [String] { return [] }
97
100
  var username: String { return "" }
@@ -105,6 +108,7 @@ extension MatchfileProtocol {
105
108
  var shallowClone: Bool { return false }
106
109
  var cloneBranchDirectly: Bool { return false }
107
110
  var gitBasicAuthorization: String? { return nil }
111
+ var gitBearerAuthorization: String? { return nil }
108
112
  var googleCloudBucketName: String? { return nil }
109
113
  var googleCloudKeysFile: String? { return nil }
110
114
  var googleCloudProjectId: String? { return nil }
@@ -122,4 +126,4 @@ extension MatchfileProtocol {
122
126
 
123
127
  // Please don't remove the lines below
124
128
  // They are used to detect outdated files
125
- // FastlaneRunnerAPIVersion [0.9.10]
129
+ // FastlaneRunnerAPIVersion [0.9.12]
@@ -18,4 +18,4 @@ class Precheckfile: PrecheckfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.135.2
21
+ // Generated with fastlane 2.140.0
@@ -18,4 +18,4 @@ class Scanfile: ScanfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.135.2
21
+ // Generated with fastlane 2.140.0
@@ -24,6 +24,9 @@ protocol ScanfileProtocol: class {
24
24
  /// Enabling this option will automatically erase the simulator before running the application
25
25
  var resetSimulator: Bool { get }
26
26
 
27
+ /// Enabling this option will disable the simulator from showing the 'Slide to type' prompt
28
+ var disableSlideToType: Bool { get }
29
+
27
30
  /// Enabling this option will launch the first simulator prior to calling any xcodebuild command
28
31
  var prelaunchSimulator: Bool? { get }
29
32
 
@@ -126,6 +129,12 @@ protocol ScanfileProtocol: class {
126
129
  /// Use an extra XCCONFIG file to build your app
127
130
  var xcconfig: String? { get }
128
131
 
132
+ /// App name to use in slack message and logfile name
133
+ var appName: String? { get }
134
+
135
+ /// Target version of the app being build or tested. Used to filter out simulator version
136
+ var deploymentTargetVersion: String? { get }
137
+
129
138
  /// Create an Incoming WebHook for your Slack group to post results there
130
139
  var slackUrl: String? { get }
131
140
 
@@ -172,6 +181,7 @@ extension ScanfileProtocol {
172
181
  var skipDetectDevices: Bool { return false }
173
182
  var forceQuitSimulator: Bool { return false }
174
183
  var resetSimulator: Bool { return false }
184
+ var disableSlideToType: Bool { return true }
175
185
  var prelaunchSimulator: Bool? { return nil }
176
186
  var reinstallApp: Bool { return false }
177
187
  var appIdentifier: String? { return nil }
@@ -206,6 +216,8 @@ extension ScanfileProtocol {
206
216
  var configuration: String? { return nil }
207
217
  var xcargs: String? { return nil }
208
218
  var xcconfig: String? { return nil }
219
+ var appName: String? { return nil }
220
+ var deploymentTargetVersion: String? { return nil }
209
221
  var slackUrl: String? { return nil }
210
222
  var slackChannel: String? { return nil }
211
223
  var slackMessage: String? { return nil }
@@ -222,4 +234,4 @@ extension ScanfileProtocol {
222
234
 
223
235
  // Please don't remove the lines below
224
236
  // They are used to detect outdated files
225
- // FastlaneRunnerAPIVersion [0.9.22]
237
+ // FastlaneRunnerAPIVersion [0.9.24]
@@ -18,4 +18,4 @@ class Screengrabfile: ScreengrabfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.135.2
21
+ // Generated with fastlane 2.140.0
@@ -39,6 +39,9 @@ protocol ScreengrabfileProtocol: class {
39
39
  /// Return the device to this locale after running tests
40
40
  var endingLocale: String { get }
41
41
 
42
+ /// Restarts the adb daemon using `adb root` to allow access to screenshots directories on device. Use if getting 'Permission denied' errors
43
+ var useAdbRoot: Bool { get }
44
+
42
45
  /// The path to the APK for the app under test
43
46
  var appApkPath: String? { get }
44
47
 
@@ -56,6 +59,12 @@ protocol ScreengrabfileProtocol: class {
56
59
 
57
60
  /// Enabling this option will automatically uninstall the application before running it
58
61
  var reinstallApp: Bool { get }
62
+
63
+ /// Add timestamp suffix to screenshot filename
64
+ var useTimestampSuffix: Bool { get }
65
+
66
+ /// Configure the host used by adb to connect, allows running on remote devices farm
67
+ var adbHost: String? { get }
59
68
  }
60
69
 
61
70
  extension ScreengrabfileProtocol {
@@ -70,16 +79,19 @@ extension ScreengrabfileProtocol {
70
79
  var useTestsInPackages: [String]? { return nil }
71
80
  var useTestsInClasses: [String]? { return nil }
72
81
  var launchArguments: [String]? { return nil }
73
- var testInstrumentationRunner: String { return "android.support.test.runner.AndroidJUnitRunner" }
82
+ var testInstrumentationRunner: String { return "androidx.test.runner.AndroidJUnitRunner" }
74
83
  var endingLocale: String { return "en-US" }
84
+ var useAdbRoot: Bool { return false }
75
85
  var appApkPath: String? { return nil }
76
86
  var testsApkPath: String? { return nil }
77
87
  var specificDevice: String? { return nil }
78
88
  var deviceType: String { return "phone" }
79
89
  var exitOnTestFailure: Bool { return true }
80
90
  var reinstallApp: Bool { return false }
91
+ var useTimestampSuffix: Bool { return true }
92
+ var adbHost: String? { return nil }
81
93
  }
82
94
 
83
95
  // Please don't remove the lines below
84
96
  // They are used to detect outdated files
85
- // FastlaneRunnerAPIVersion [0.9.11]
97
+ // FastlaneRunnerAPIVersion [0.9.13]
@@ -18,4 +18,4 @@ class Snapshotfile: SnapshotfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.135.2
21
+ // Generated with fastlane 2.140.0
@@ -6,7 +6,7 @@ module FastlaneCore
6
6
  class BuildWatcher
7
7
  class << self
8
8
  # @return The build we waited for. This method will always return a build
9
- def wait_for_build_processing_to_be_complete(app_id: nil, platform: nil, train_version: nil, app_version: nil, build_version: nil, poll_interval: 10, strict_build_watch: false, return_spaceship_testflight_build: true)
9
+ def wait_for_build_processing_to_be_complete(app_id: nil, platform: nil, train_version: nil, app_version: nil, build_version: nil, poll_interval: 10, strict_build_watch: false, return_when_build_appears: false, return_spaceship_testflight_build: true)
10
10
  # Warn about train_version being removed in the future
11
11
  if train_version
12
12
  UI.deprecated(":train_version is no longer a used argument on FastlaneCore::BuildWatcher. Please use :app_version instead.")
@@ -32,7 +32,11 @@ module FastlaneCore
32
32
 
33
33
  report_status(build: matched_build)
34
34
 
35
- if matched_build && matched_build.processed?
35
+ # Processing of builds by AppStoreConnect can be a very time consuming task and will
36
+ # block the worker running this task until it is completed. In some cases,
37
+ # having a build resource appear in AppStoreConnect (matched_build) may be enough (i.e. setting a changelog)
38
+ # so here we may choose to skip the full processing of the build if return_when_build_appears is true
39
+ if matched_build && (return_when_build_appears || matched_build.processed?)
36
40
  if return_spaceship_testflight_build
37
41
  return matched_build.to_testflight_build
38
42
  else
@@ -212,6 +212,19 @@ module FastlaneCore
212
212
  `xcrun simctl delete #{self.udid}`
213
213
  return
214
214
  end
215
+
216
+ def disable_slide_to_type
217
+ return unless is_simulator
218
+ return unless os_type == "iOS"
219
+ return unless Gem::Version.new(os_version) >= Gem::Version.new('13.0')
220
+ UI.message("Disabling 'Slide to Type' #{self}")
221
+
222
+ plist_buddy = '/usr/libexec/PlistBuddy'
223
+ plist_buddy_cmd = "-c \"Add :KeyboardContinuousPathEnabled bool false\""
224
+ plist_path = File.expand_path("~/Library/Developer/CoreSimulator/Devices/#{self.udid}/data/Library/Preferences/com.apple.keyboard.ContinuousPath.plist")
225
+
226
+ Helper.backticks("#{plist_buddy} #{plist_buddy_cmd} #{plist_path}")
227
+ end
215
228
  end
216
229
  end
217
230
 
@@ -248,6 +261,13 @@ module FastlaneCore
248
261
  all.select { |device| device.os_version == os_version }.each(&:delete)
249
262
  end
250
263
 
264
+ # Disable 'Slide to Type' by UDID or name and OS version
265
+ # Latter is useful when combined with -destination option of xcodebuild
266
+ def disable_slide_to_type(udid: nil, name: nil, os_version: nil)
267
+ match = all.detect { |device| device.udid == udid || device.name == name && device.os_version == os_version }
268
+ match.disable_slide_to_type if match
269
+ end
270
+
251
271
  def clear_cache
252
272
  @devices = nil
253
273
  end
@@ -71,13 +71,19 @@ module FastlaneCore
71
71
 
72
72
  # @return [boolean] true if building in a known CI environment
73
73
  def self.ci?
74
+ return true if self.is_circle_ci?
75
+
74
76
  # Check for Jenkins, Travis CI, ... environment variables
75
- ['JENKINS_HOME', 'JENKINS_URL', 'TRAVIS', 'CIRCLECI', 'CI', 'APPCENTER_BUILD_ID', 'TEAMCITY_VERSION', 'GO_PIPELINE_NAME', 'bamboo_buildKey', 'GITLAB_CI', 'XCS', 'TF_BUILD', 'GITHUB_ACTION', 'GITHUB_ACTIONS'].each do |current|
77
+ ['JENKINS_HOME', 'JENKINS_URL', 'TRAVIS', 'CI', 'APPCENTER_BUILD_ID', 'TEAMCITY_VERSION', 'GO_PIPELINE_NAME', 'bamboo_buildKey', 'GITLAB_CI', 'XCS', 'TF_BUILD', 'GITHUB_ACTION', 'GITHUB_ACTIONS', 'BITRISE_IO'].each do |current|
76
78
  return true if ENV.key?(current)
77
79
  end
78
80
  return false
79
81
  end
80
82
 
83
+ def self.is_circle_ci?
84
+ return ENV.key?('CIRCLECI')
85
+ end
86
+
81
87
  def self.operating_system
82
88
  return "macOS" if RUBY_PLATFORM.downcase.include?("darwin")
83
89
  return "Windows" if RUBY_PLATFORM.downcase.include?("mswin")
@@ -262,6 +262,9 @@ module Frameit
262
262
  left_space = (background.width / 2.0 - image.width / 2.0).round
263
263
 
264
264
  @image = background.composite(image, "png") do |c|
265
+ colorspace = image.data["colorspace"]
266
+ c.colorspace(colorspace) if colorspace
267
+
265
268
  c.compose("Over")
266
269
  c.geometry("+#{left_space}+#{device_top(background)}")
267
270
  end
@@ -51,6 +51,7 @@ module Gym
51
51
 
52
52
  buildactions = []
53
53
  buildactions << :clean if config[:clean]
54
+ buildactions << :build if config[:skip_archive]
54
55
  buildactions << :archive unless config[:skip_archive]
55
56
 
56
57
  buildactions
@@ -18,6 +18,9 @@ module Gym
18
18
  build_app
19
19
  end
20
20
  verify_archive unless Gym.config[:skip_archive]
21
+
22
+ return nil if Gym.config[:skip_archive]
23
+
21
24
  FileUtils.mkdir_p(File.expand_path(Gym.config[:output_directory]))
22
25
 
23
26
  if Gym.project.ios? || Gym.project.tvos?
@@ -97,9 +100,11 @@ module Gym
97
100
  ErrorHandler.handle_build_error(output)
98
101
  end)
99
102
 
100
- mark_archive_as_built_by_gym(BuildCommandGenerator.archive_path)
101
- UI.success("Successfully stored the archive. You can find it in the Xcode Organizer.") unless Gym.config[:archive_path].nil?
102
- UI.verbose("Stored the archive in: " + BuildCommandGenerator.archive_path)
103
+ unless Gym.config[:skip_archive]
104
+ mark_archive_as_built_by_gym(BuildCommandGenerator.archive_path)
105
+ UI.success("Successfully stored the archive. You can find it in the Xcode Organizer.") unless Gym.config[:archive_path].nil?
106
+ UI.verbose("Stored the archive in: " + BuildCommandGenerator.archive_path)
107
+ end
103
108
 
104
109
  post_build_app
105
110
  end
@@ -155,31 +160,45 @@ module Gym
155
160
  dwarfdump_command << "dwarfdump"
156
161
  dwarfdump_command << "--uuid #{dsym.shellescape}"
157
162
 
163
+ # Extract uuids
158
164
  dwarfdump_result = Helper.backticks(dwarfdump_command.join(" "), print: false)
159
165
  architecture_infos = dwarfdump_result.split("\n")
160
- architecture_uuids = architecture_infos.map do |info|
161
- info_array = info.split(" ")
166
+ architecture_infos.each do |info|
167
+ info_array = info.split(" ", 4)
162
168
  uuid = info_array[1]
169
+ dwarf_file_path = info_array[3]
163
170
 
164
171
  if uuid.nil? || !uuid.match(uuid_regex)
165
- nil
166
- else
167
- uuid
172
+ next
168
173
  end
169
- end
170
-
171
- architecture_uuids = architecture_uuids.reject(&:nil?)
172
174
 
173
- symbol_map_paths = architecture_uuids.map do |uuid|
174
- "#{bcsymbolmaps_directory.shellescape}/#{uuid}.bcsymbolmap"
175
- end
176
-
177
- symbol_map_paths << bcsymbolmaps_directory.shellescape if symbol_map_paths.empty?
178
-
179
- symbol_map_paths.each do |path|
175
+ # Find bcsymbolmap file to be used:
176
+ # - if a <uuid>.plist file exists, we will extract uuid of bcsymbolmap and use it
177
+ # - if a <uuid>.bcsymbolmap file exists, we will use it
178
+ # - otherwise let dsymutil figure it out
179
+ symbol_map_path = nil
180
+ split_dwarf_file_path = File.split(dwarf_file_path)
181
+ dsym_plist_file_path = File.join(split_dwarf_file_path[0], "..", "#{uuid}.plist")
182
+ if File.exist?(dsym_plist_file_path)
183
+ dsym_plist = Plist.parse_xml(dsym_plist_file_path)
184
+ original_uuid = dsym_plist['DBGOriginalUUID']
185
+ possible_symbol_map_path = "#{bcsymbolmaps_directory}/#{original_uuid}.bcsymbolmap"
186
+ if File.exist?(possible_symbol_map_path)
187
+ symbol_map_path = possible_symbol_map_path.shellescape
188
+ end
189
+ end
190
+ if symbol_map_path.nil?
191
+ possible_symbol_map_path = File.join(bcsymbolmaps_directory, "#{uuid}.bcsymbolmap")
192
+ if File.exist?(possible_symbol_map_path)
193
+ symbol_map_path = possible_symbol_map_path.shellescape
194
+ end
195
+ end
196
+ if symbol_map_path.nil?
197
+ symbol_map_path = bcsymbolmaps_directory.shellescape
198
+ end
180
199
  command = []
181
200
  command << "dsymutil"
182
- command << "--symbol-map #{path}"
201
+ command << "--symbol-map #{symbol_map_path}"
183
202
  command << dsym.shellescape
184
203
  Helper.backticks(command.join(" "), print: !Gym.config[:silent])
185
204
  end
@@ -125,6 +125,14 @@ module Match
125
125
  env_name: "MATCH_GIT_BASIC_AUTHORIZATION",
126
126
  sensitive: true,
127
127
  description: "Use a basic authorization header to access the git repo (e.g.: access via HTTPS, GitHub Actions, etc), usually a string in Base64",
128
+ conflicting_options: [:git_bearer_authorization],
129
+ optional: true,
130
+ default_value: nil),
131
+ FastlaneCore::ConfigItem.new(key: :git_bearer_authorization,
132
+ env_name: "MATCH_GIT_BEARER_AUTHORIZATION",
133
+ sensitive: true,
134
+ description: "Use a bearer authorization header to access the git repo (e.g.: access to an Azure Devops repository), usually a string in Base64",
135
+ conflicting_options: [:git_basic_authorization],
128
136
  optional: true,
129
137
  default_value: nil),
130
138
 
@@ -38,6 +38,7 @@ module Match
38
38
  git_user_email: params[:git_user_email],
39
39
  clone_branch_directly: params[:clone_branch_directly],
40
40
  git_basic_authorization: params[:git_basic_authorization],
41
+ git_bearer_authorization: params[:git_bearer_authorization],
41
42
  type: params[:type].to_s,
42
43
  generate_apple_certs: params[:generate_apple_certs],
43
44
  platform: params[:platform].to_s,
@@ -18,6 +18,7 @@ module Match
18
18
  attr_accessor :type
19
19
  attr_accessor :platform
20
20
  attr_accessor :git_basic_authorization
21
+ attr_accessor :git_bearer_authorization
21
22
 
22
23
  def self.configure(params)
23
24
  return self.new(
@@ -30,7 +31,8 @@ module Match
30
31
  git_full_name: params[:git_full_name],
31
32
  git_user_email: params[:git_user_email],
32
33
  clone_branch_directly: params[:clone_branch_directly],
33
- git_basic_authorization: params[:git_basic_authorization]
34
+ git_basic_authorization: params[:git_basic_authorization],
35
+ git_bearer_authorization: params[:git_bearer_authorization]
34
36
  )
35
37
  end
36
38
 
@@ -43,7 +45,8 @@ module Match
43
45
  git_full_name: nil,
44
46
  git_user_email: nil,
45
47
  clone_branch_directly: false,
46
- git_basic_authorization: nil)
48
+ git_basic_authorization: nil,
49
+ git_bearer_authorization: nil)
47
50
  self.git_url = git_url
48
51
  self.shallow_clone = shallow_clone
49
52
  self.skip_docs = skip_docs
@@ -52,6 +55,7 @@ module Match
52
55
  self.git_user_email = git_user_email
53
56
  self.clone_branch_directly = clone_branch_directly
54
57
  self.git_basic_authorization = git_basic_authorization
58
+ self.git_bearer_authorization = git_bearer_authorization
55
59
 
56
60
  self.type = type if type
57
61
  self.platform = platform if platform
@@ -70,6 +74,7 @@ module Match
70
74
 
71
75
  command = "git clone #{self.git_url.shellescape} #{self.working_directory.shellescape}"
72
76
  command << " -c http.extraheader='AUTHORIZATION: basic #{self.git_basic_authorization}'" unless self.git_basic_authorization.nil?
77
+ command << " -c http.extraheader='AUTHORIZATION: bearer #{self.git_bearer_authorization}'" unless self.git_bearer_authorization.nil?
73
78
 
74
79
  if self.shallow_clone
75
80
  command << " --depth 1 --no-single-branch"
@@ -39,17 +39,25 @@ module Pilot
39
39
 
40
40
  UI.success("Successfully uploaded the new binary to App Store Connect")
41
41
 
42
+ # We will fully skip waiting for build processing *only* if no changelog is supplied
43
+ # Otherwise we may partially wait until the build appears so the changelog can be set, and then bail.
44
+ return_when_build_appears = false
42
45
  if config[:skip_waiting_for_build_processing]
43
- UI.important("Skip waiting for build processing")
44
- UI.important("This means that no changelog will be set and no build will be distributed to testers")
45
- return
46
+ if config[:changelog].nil?
47
+ UI.important("`skip_waiting_for_build_processing` used and no `changelog` supplied - skipping waiting for build processing")
48
+ return
49
+ else
50
+ return_when_build_appears = true
51
+ end
46
52
  end
47
53
 
48
54
  # Calling login again here is needed if login was not called during 'start'
49
55
  login unless should_login_in_start
50
56
 
51
57
  UI.message("If you want to skip waiting for the processing to be finished, use the `skip_waiting_for_build_processing` option")
52
- latest_build = wait_for_build_processing_to_be_complete
58
+ UI.message("Note that if `skip_waiting_for_build_processing` is used but a `changelog` is supplied, this process will wait for the build to appear on AppStoreConnect, update the changelog and then skip the remaining of the processing steps.")
59
+
60
+ latest_build = wait_for_build_processing_to_be_complete(return_when_build_appears)
53
61
  distribute(options, build: latest_build)
54
62
  end
55
63
 
@@ -80,11 +88,20 @@ module Pilot
80
88
  end
81
89
  end
82
90
 
83
- def wait_for_build_processing_to_be_complete
91
+ def wait_for_build_processing_to_be_complete(return_when_build_appears = false)
84
92
  platform = fetch_app_platform
85
93
  app_version = FastlaneCore::IpaFileAnalyser.fetch_app_version(config[:ipa])
86
94
  app_build = FastlaneCore::IpaFileAnalyser.fetch_app_build(config[:ipa])
87
- latest_build = FastlaneCore::BuildWatcher.wait_for_build_processing_to_be_complete(app_id: app.id, platform: platform, app_version: app_version, build_version: app_build, poll_interval: config[:wait_processing_interval], return_spaceship_testflight_build: false)
95
+
96
+ latest_build = FastlaneCore::BuildWatcher.wait_for_build_processing_to_be_complete(
97
+ app_id: app.id,
98
+ platform: platform,
99
+ app_version: app_version,
100
+ build_version: app_build,
101
+ poll_interval: config[:wait_processing_interval],
102
+ return_when_build_appears: return_when_build_appears,
103
+ return_spaceship_testflight_build: false
104
+ )
88
105
 
89
106
  unless latest_build.app_version == app_version && latest_build.version == app_build
90
107
  UI.important("Uploaded app #{app_version} - #{app_build}, but received build #{latest_build.app_version} - #{latest_build.version}.")
@@ -137,6 +154,14 @@ module Pilot
137
154
  UI.success("Deleted beta app review submission for previous build: #{waiting_for_review_build.app_version} - #{waiting_for_review_build.version}")
138
155
  end
139
156
  end
157
+
158
+ if !build.ready_for_internal_testing? && options[:skip_waiting_for_build_processing]
159
+ # Meta can be uploaded for a build still in processing
160
+ # Returning before distribute if skip_waiting_for_build_processing
161
+ # because can't distribute an app that is still processing
162
+ return
163
+ end
164
+
140
165
  distribute_build(build, options)
141
166
  type = options[:distribute_external] ? 'External' : 'Internal'
142
167
  UI.success("Successfully distributed build to #{type} testers 🚀")
@@ -220,12 +245,21 @@ module Pilot
220
245
  end
221
246
 
222
247
  def self.truncate_changelog(changelog)
223
- max_changelog_length = 4000
224
- if changelog && changelog.length > max_changelog_length
225
- original_length = changelog.length
226
- bottom_message = "..."
227
- changelog = "#{changelog[0...max_changelog_length - bottom_message.length]}#{bottom_message}"
228
- UI.important("Changelog has been truncated since it exceeds Apple's #{max_changelog_length} character limit. It currently contains #{original_length} characters.")
248
+ max_changelog_bytes = 4000
249
+ if changelog
250
+ changelog_bytes = changelog.unpack('C*').length
251
+ if changelog_bytes > max_changelog_bytes
252
+ UI.important("Changelog will be truncated since it exceeds Apple's #{max_changelog_bytes}-byte limit. It currently contains #{changelog_bytes} bytes.")
253
+ new_changelog = ''
254
+ new_changelog_bytes = 0
255
+ max_changelog_bytes -= 3 # Will append '...' later.
256
+ changelog.chars.each do |char|
257
+ new_changelog_bytes += char.unpack('C*').length
258
+ break if new_changelog_bytes >= max_changelog_bytes
259
+ new_changelog += char
260
+ end
261
+ changelog = new_changelog + '...'
262
+ end
229
263
  end
230
264
  changelog
231
265
  end