fastlane 2.237.0 → 2.239.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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +107 -100
  3. data/bin/fastlane +2 -2
  4. data/deliver/lib/deliver/html_generator.rb +1 -1
  5. data/deliver/lib/deliver/options.rb +9 -1
  6. data/deliver/lib/deliver/upload_metadata.rb +22 -0
  7. data/deliver/lib/deliver/upload_screenshots.rb +12 -4
  8. data/fastlane/lib/fastlane/actions/changelog_from_git_commits.rb +7 -2
  9. data/fastlane/lib/fastlane/actions/deploygate.rb +3 -2
  10. data/fastlane/lib/fastlane/actions/docs/get_push_certificate.md +6 -0
  11. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +4 -2
  12. data/fastlane/lib/fastlane/actions/hockey.rb +3 -2
  13. data/fastlane/lib/fastlane/actions/installr.rb +3 -2
  14. data/fastlane/lib/fastlane/actions/mailgun.rb +1 -0
  15. data/fastlane/lib/fastlane/actions/notarize.rb +3 -18
  16. data/fastlane/lib/fastlane/actions/register_devices.rb +21 -5
  17. data/fastlane/lib/fastlane/actions/setup_ci.rb +7 -2
  18. data/fastlane/lib/fastlane/actions/spm.rb +6 -0
  19. data/fastlane/lib/fastlane/actions/testfairy.rb +5 -3
  20. data/fastlane/lib/fastlane/actions/tryouts.rb +3 -2
  21. data/fastlane/lib/fastlane/actions/update_project_team.rb +17 -9
  22. data/fastlane/lib/fastlane/actions/upload_symbols_to_crashlytics.rb +33 -7
  23. data/fastlane/lib/fastlane/helper/git_helper.rb +4 -2
  24. data/fastlane/lib/fastlane/helper/sh_helper.rb +9 -1
  25. data/fastlane/lib/fastlane/plugins/template/%gem_name%.gemspec.erb +1 -1
  26. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +5 -1
  27. data/fastlane/lib/fastlane/version.rb +1 -1
  28. data/fastlane/swift/Deliverfile.swift +1 -1
  29. data/fastlane/swift/DeliverfileProtocol.swift +9 -2
  30. data/fastlane/swift/Fastlane.swift +66 -20
  31. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.pbxproj +1 -1
  32. data/fastlane/swift/Gymfile.swift +1 -1
  33. data/fastlane/swift/GymfileProtocol.swift +1 -1
  34. data/fastlane/swift/Matchfile.swift +1 -1
  35. data/fastlane/swift/MatchfileProtocol.swift +1 -1
  36. data/fastlane/swift/Precheckfile.swift +1 -1
  37. data/fastlane/swift/PrecheckfileProtocol.swift +1 -1
  38. data/fastlane/swift/Scanfile.swift +1 -1
  39. data/fastlane/swift/ScanfileProtocol.swift +1 -1
  40. data/fastlane/swift/Screengrabfile.swift +1 -1
  41. data/fastlane/swift/ScreengrabfileProtocol.swift +1 -1
  42. data/fastlane/swift/Snapshotfile.swift +1 -1
  43. data/fastlane/swift/SnapshotfileProtocol.swift +1 -1
  44. data/fastlane_core/lib/fastlane_core/analytics/analytics_event_builder.rb +31 -5
  45. data/fastlane_core/lib/fastlane_core/analytics/analytics_ingester_client.rb +24 -12
  46. data/fastlane_core/lib/fastlane_core/analytics/analytics_session.rb +22 -12
  47. data/fastlane_core/lib/fastlane_core/cert_checker.rb +22 -9
  48. data/fastlane_core/lib/fastlane_core/helper.rb +4 -3
  49. data/fastlane_core/lib/fastlane_core/ipa_upload_package_builder.rb +6 -2
  50. data/fastlane_core/lib/fastlane_core/pkg_upload_package_builder.rb +1 -1
  51. data/fastlane_core/lib/fastlane_core/print_table.rb +0 -16
  52. data/fastlane_core/lib/fastlane_core/queue_worker.rb +10 -1
  53. data/fastlane_core/lib/fastlane_core/video_utils.rb +4 -2
  54. data/gym/lib/gym/module.rb +20 -2
  55. data/match/lib/match/nuke.rb +2 -2
  56. data/match/lib/match/storage/git_storage.rb +1 -4
  57. data/match/lib/match/storage/google_cloud_storage.rb +6 -1
  58. data/pem/lib/pem/manager.rb +5 -1
  59. data/pem/lib/pem/options.rb +6 -0
  60. data/pilot/lib/pilot/build_manager.rb +34 -2
  61. data/pilot/lib/pilot/options.rb +10 -2
  62. data/pilot/lib/pilot/tester_manager.rb +2 -2
  63. data/precheck/lib/precheck/rules/copyright_date_rule.rb +1 -1
  64. data/precheck/lib/precheck/rules/unreachable_urls_rule.rb +2 -2
  65. data/sigh/lib/assets/resign.sh +21 -9
  66. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +4 -1
  67. data/spaceship/lib/spaceship/client.rb +0 -1
  68. data/spaceship/lib/spaceship/connect_api/file_uploader.rb +1 -1
  69. data/spaceship/lib/spaceship/connect_api/models/age_rating_declaration.rb +6 -0
  70. data/spaceship/lib/spaceship/connect_api/models/app_store_version.rb +16 -0
  71. data/spaceship/lib/spaceship/connect_api/models/beta_group.rb +5 -0
  72. data/spaceship/lib/spaceship/connect_api/models/routing_app_coverage.rb +75 -0
  73. data/spaceship/lib/spaceship/connect_api/token.rb +6 -1
  74. data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +45 -0
  75. data/spaceship/lib/spaceship/connect_api.rb +1 -0
  76. data/spaceship/lib/spaceship/helper/plist_middleware.rb +37 -8
  77. data/supply/lib/supply/client.rb +6 -0
  78. data/supply/lib/supply/reader.rb +15 -0
  79. metadata +79 -53
@@ -17,4 +17,4 @@ public class Snapshotfile: SnapshotfileProtocol {
17
17
  // during the `init` process, and you won't see this message
18
18
  }
19
19
 
20
- // Generated with fastlane 2.237.0
20
+ // Generated with fastlane 2.239.0
@@ -378,4 +378,4 @@ public extension SnapshotfileProtocol {
378
378
 
379
379
  // Please don't remove the lines below
380
380
  // They are used to detect outdated files
381
- // FastlaneRunnerAPIVersion [0.9.143]
381
+ // FastlaneRunnerAPIVersion [0.9.145]
@@ -1,23 +1,49 @@
1
+ require_relative '../helper'
2
+
1
3
  module FastlaneCore
2
4
  class AnalyticsEventBuilder
3
5
  attr_accessor :action_name
4
6
 
5
7
  # fastlane_client_language valid options are :ruby or :swift
6
- def initialize(p_hash: nil, session_id: nil, action_name: nil, fastlane_client_language: :ruby)
8
+ def initialize(p_hash: nil, session_id: nil, action_name: nil, fastlane_client_language: :ruby, build_tool_version: nil)
7
9
  @p_hash = p_hash
8
10
  @session_id = session_id
9
11
  @action_name = action_name
10
12
  @fastlane_client_language = fastlane_client_language
13
+ @build_tool_version = build_tool_version
11
14
  end
12
15
 
13
16
  def new_event(action_stage)
14
17
  {
15
18
  client_id: @p_hash,
16
- category: "fastlane Client Language - #{@fastlane_client_language}",
17
- action: action_stage,
18
- label: action_name,
19
- value: nil
19
+ session_id: @session_id,
20
+ name: action_stage,
21
+ params: {
22
+ fastlane_client_language: @fastlane_client_language,
23
+ fastlane_version: Fastlane::VERSION,
24
+ install_method: install_method,
25
+ ruby_version: RUBY_VERSION,
26
+ operating_system: Helper.operating_system,
27
+ build_tool_version: @build_tool_version,
28
+ ci: Helper.ci?.to_s
29
+ }.reject { |_, value| value.nil? }
20
30
  }
21
31
  end
32
+
33
+ private
34
+
35
+ def install_method
36
+ if Helper.bundler?
37
+ 'bundler'
38
+ elsif Helper.contained_fastlane?
39
+ 'standalone'
40
+ elsif Helper.homebrew?
41
+ 'homebrew'
42
+ elsif Helper.mac_app?
43
+ 'mac_app'
44
+ else
45
+ 'gem'
46
+ end
47
+ end
22
48
  end
23
49
  end
@@ -34,21 +34,33 @@ module FastlaneCore
34
34
 
35
35
  def post_request(event)
36
36
  connection = Faraday.new(GA_URL) do |conn|
37
- conn.request(:url_encoded)
37
+ # This request runs while fastlane is shutting down,
38
+ # so keep the timeouts short to not delay the user
39
+ conn.options.open_timeout = 5
40
+ conn.options.timeout = 5
38
41
  conn.adapter(Faraday.default_adapter)
39
42
  end
40
43
  connection.headers[:user_agent] = 'fastlane/' + Fastlane::VERSION
41
- connection.post("/collect", {
42
- v: "1", # API Version
43
- tid: @ga_tracking, # Tracking ID / Property ID
44
- cid: event[:client_id], # Client ID
45
- t: "event", # Event hit type
46
- ec: event[:category], # Event category
47
- ea: event[:action], # Event action
48
- el: event[:label] || "na", # Event label
49
- ev: event[:value] || "0", # Event value
50
- aip: "1" # IP anonymization
51
- })
44
+
45
+ # GA4 protocol, event parameters are sent as `ep.<name>` query parameters
46
+ params = {
47
+ v: "2", # Protocol version (GA4)
48
+ tid: @ga_tracking, # GA4 measurement ID
49
+ cid: event[:client_id], # Client ID
50
+ sid: event[:session_id], # Session ID
51
+ _ss: "1", # Session start
52
+ seg: "1", # Session engaged
53
+ # Engagement time in ms, required for events to count towards active users
54
+ _et: (event[:engagement_time_msec] || 100).to_s,
55
+ en: event[:name].to_s # Event name
56
+ }
57
+ (event[:params] || {}).each do |key, value|
58
+ params["ep.#{key}"] = value.to_s
59
+ end
60
+
61
+ connection.post("/g/collect") do |request|
62
+ request.params = params
63
+ end
52
64
  end
53
65
  end
54
66
  end
@@ -4,18 +4,20 @@ require_relative 'analytics_event_builder'
4
4
 
5
5
  module FastlaneCore
6
6
  class AnalyticsSession
7
- GA_TRACKING = "UA-121171860-1"
7
+ GA_TRACKING = "G-94HQ3VVP0X"
8
8
 
9
9
  private_constant :GA_TRACKING
10
10
  attr_accessor :session_id
11
11
  attr_accessor :client
12
12
 
13
13
  def initialize(analytics_ingester_client: AnalyticsIngesterClient.new(GA_TRACKING))
14
- require 'securerandom'
15
- @session_id = SecureRandom.uuid
14
+ # GA4 requires a numeric session ID for events to be attributed to a session
15
+ @session_id = Time.now.to_i.to_s
16
+ @session_start_time = Time.now
16
17
  @client = analytics_ingester_client
17
18
  @threads = []
18
- @launch_event_sent = false
19
+ @launch_event = nil
20
+ @launch_event_captured = false
19
21
  end
20
22
 
21
23
  def action_launched(launch_context: nil)
@@ -23,23 +25,22 @@ module FastlaneCore
23
25
  show_message
24
26
  end
25
27
 
26
- if @launch_event_sent || launch_context.p_hash.nil?
28
+ if @launch_event_captured || launch_context.p_hash.nil?
27
29
  return
28
30
  end
29
31
 
30
- @launch_event_sent = true
32
+ @launch_event_captured = true
31
33
  builder = AnalyticsEventBuilder.new(
32
34
  p_hash: launch_context.p_hash,
33
35
  session_id: session_id,
34
36
  action_name: nil,
35
- fastlane_client_language: launch_context.fastlane_client_language
37
+ fastlane_client_language: launch_context.fastlane_client_language,
38
+ build_tool_version: launch_context.build_tool_version
36
39
  )
37
40
 
38
- launch_event = builder.new_event(:launch)
39
- post_thread = client.post_event(launch_event)
40
- unless post_thread.nil?
41
- @threads << post_thread
42
- end
41
+ # The event is not posted until finalize_session, so that the
42
+ # run duration can be reported as GA4 engagement time
43
+ @launch_event = builder.new_event(:launch)
43
44
  end
44
45
 
45
46
  def action_completed(completion_context: nil)
@@ -64,6 +65,15 @@ module FastlaneCore
64
65
  end
65
66
 
66
67
  def finalize_session
68
+ unless @launch_event.nil?
69
+ @launch_event[:engagement_time_msec] = ((Time.now - @session_start_time) * 1000).round
70
+ post_thread = client.post_event(@launch_event)
71
+ unless post_thread.nil?
72
+ @threads << post_thread
73
+ end
74
+ @launch_event = nil
75
+ end
76
+
67
77
  @threads.map(&:join)
68
78
  end
69
79
  end
@@ -43,6 +43,15 @@ WWDRCA_CERTIFICATES = [
43
43
  }
44
44
  ]
45
45
 
46
+ # Common names of the certificates in `WWDRCA_CERTIFICATES`. The WWDR
47
+ # certificates (G2-G6) and the Developer ID certificates (DEV-ID-G1,
48
+ # DEV-ID-G2) use different common names, so each of them has to be queried
49
+ # separately when looking up the installed certificates
50
+ WWDRCA_CERTIFICATE_NAMES = [
51
+ 'Apple Worldwide Developer Relations',
52
+ 'Developer ID Certification Authority'
53
+ ]
54
+
46
55
  module FastlaneCore
47
56
  # This class checks if a specific certificate is installed on the current mac
48
57
  class CertChecker
@@ -123,18 +132,21 @@ module FastlaneCore
123
132
  end
124
133
 
125
134
  def self.installed_wwdr_certificates(keychain: nil)
126
- certificate_name = "Apple Worldwide Developer Relations"
127
135
  keychain ||= wwdr_keychain # backwards compatibility
128
136
 
129
- # Find all installed WWDRCA certificates
137
+ # Find all installed WWDRCA certificates. A single `security
138
+ # find-certificate` call can only match one common name, so query the
139
+ # keychain once per common name used by the certificates
130
140
  installed_certs = []
131
- Helper.backticks("security find-certificate -a -c '#{certificate_name}' -p #{keychain.shellescape}", print: false)
132
- .lines
133
- .each do |line|
134
- if line.start_with?('-----BEGIN CERTIFICATE-----')
135
- installed_certs << line
136
- else
137
- installed_certs.last << line
141
+ WWDRCA_CERTIFICATE_NAMES.each do |certificate_name|
142
+ Helper.backticks("security find-certificate -a -c '#{certificate_name}' -p #{keychain.shellescape}", print: false)
143
+ .lines
144
+ .each do |line|
145
+ if line.start_with?('-----BEGIN CERTIFICATE-----')
146
+ installed_certs << line
147
+ else
148
+ installed_certs.last << line
149
+ end
138
150
  end
139
151
  end
140
152
 
@@ -145,6 +157,7 @@ module FastlaneCore
145
157
  WWDRCA_CERTIFICATES.find { |c| c[:sha256].casecmp?(sha256) }&.fetch(:alias)
146
158
  end
147
159
  .compact
160
+ .uniq
148
161
  end
149
162
 
150
163
  def self.install_missing_wwdr_certificates(in_keychain: nil)
@@ -91,9 +91,10 @@ module FastlaneCore
91
91
  end
92
92
 
93
93
  def self.operating_system
94
- return "macOS" if RUBY_PLATFORM.downcase.include?("darwin")
95
- return "Windows" if RUBY_PLATFORM.downcase.include?("mswin")
96
- return "Linux" if RUBY_PLATFORM.downcase.include?("linux")
94
+ return "macOS" if self.mac?
95
+ return "Windows" if self.windows?
96
+ return "Linux" if self.linux?
97
+ return "Java" if RUBY_PLATFORM =~ /java/
97
98
  return "Unknown"
98
99
  end
99
100
 
@@ -14,8 +14,12 @@ module FastlaneCore
14
14
 
15
15
  def generate(app_id: nil, ipa_path: nil, package_path: nil, platform: nil, app_identifier: nil, short_version: nil, bundle_version: nil)
16
16
  unless Helper.is_mac?
17
- # .itmsp packages are not supported for ipa uploads starting Transporter 4.1, for non-macOS
18
- self.package_path = package_path
17
+ # .itmsp packages are not supported for ipa uploads starting Transporter 4.1, for non-macOS.
18
+ # Use a unique subdirectory anyway: callers pass a shared parent (deliver passes "/tmp"),
19
+ # and ItunesTransporter#upload runs FileUtils.rm_rf on whatever this returns.
20
+ self.package_path = File.join(package_path, "#{app_id}-#{SecureRandom.uuid}")
21
+ FileUtils.mkdir_p(self.package_path)
22
+
19
23
  copy_ipa(ipa_path)
20
24
 
21
25
  # copy any AppStoreInfo.plist file that's next to the ipa file
@@ -22,7 +22,7 @@ module FastlaneCore
22
22
  apple_id: app_id,
23
23
  file_size: File.size(pkg_path),
24
24
  ipa_path: File.basename(pkg_path), # this is only the base name as the ipa is inside the package
25
- md5: Digest::MD5.hexdigest(File.read(pkg_path)),
25
+ md5: Digest::MD5.file(pkg_path).hexdigest,
26
26
  archive_type: 'product-archive',
27
27
  platform: platform
28
28
  }
@@ -1,22 +1,6 @@
1
1
  require_relative 'configuration/configuration'
2
2
  require_relative 'helper'
3
3
 
4
- # Monkey patch Terminal::Table until this is merged
5
- # https://github.com/tj/terminal-table/pull/131
6
- # solves https://github.com/fastlane/fastlane/issues/21852
7
- # loads Terminal::Table first to be able to monkey patch it.
8
- require 'terminal-table'
9
- module Terminal
10
- class Table
11
- class Cell
12
- def lines
13
- # @value.to_s.split(/\n/)
14
- @value.to_s.encode("utf-8", invalid: :replace).split(/\n/)
15
- end
16
- end
17
- end
18
- end
19
-
20
4
  module FastlaneCore
21
5
  class PrintTable
22
6
  class << self
@@ -33,17 +33,26 @@ module FastlaneCore
33
33
  @queue.close
34
34
 
35
35
  threads = []
36
+ results = Queue.new
36
37
  @concurrency.times do
37
38
  threads << Thread.new do
39
+ # Exceptions are re-joined (and raised) below, so this just causes duplicate raised exceptions
40
+ Thread.current.report_on_exception = false
41
+
38
42
  job = @queue.pop
39
43
  while job
40
- @block.call(job)
44
+ results << @block.call(job)
41
45
  job = @queue.pop
42
46
  end
43
47
  end
44
48
  end
45
49
 
46
50
  threads.each(&:join)
51
+
52
+ # Convert Queue to Array
53
+ real_results = []
54
+ real_results << results.pop until results.empty?
55
+ real_results
47
56
  end
48
57
  end
49
58
  end
@@ -60,7 +60,9 @@ module FastlaneCore
60
60
  nil
61
61
  end
62
62
 
63
- # Reads the moov box and returns [w, h] if found in any trak/tkhd, else nil.
63
+ # Reads the moov box and returns [w, h] from the first trak/tkhd with non-zero dimensions, else nil.
64
+ # Non-video tracks (e.g. audio) carry a legitimate tkhd width/height of 0x0,
65
+ # so zero-sized results are skipped to keep scanning for the video track.
64
66
  # Input: io (IO) positioned at moov contents; moov_end (Integer) absolute end offset.
65
67
  # Output: [width, height] or nil.
66
68
  def self.extract_resolution_from_moov(io, moov_end)
@@ -71,7 +73,7 @@ module FastlaneCore
71
73
  if atom_type == "trak"
72
74
  trak_end = io.pos + (atom_size - 8)
73
75
  resolution = extract_resolution_from_trak(io, trak_end)
74
- return resolution if resolution
76
+ return resolution if resolution && resolution[0] > 0 && resolution[1] > 0
75
77
  io.seek(trak_end, IO::SEEK_SET)
76
78
  else
77
79
  skip(io, atom_size - 8)
@@ -56,11 +56,29 @@ module Gym
56
56
  end
57
57
 
58
58
  def building_mac_catalyst_for_ios?
59
- Gym.project.supports_mac_catalyst? && Gym.config[:catalyst_platform] == "ios"
59
+ return false unless Gym.project.supports_mac_catalyst?
60
+
61
+ # If catalyst_platform is explicitly set, use it
62
+ if Gym.config[:catalyst_platform]
63
+ return Gym.config[:catalyst_platform] == "ios"
64
+ end
65
+
66
+ # If catalyst_platform is not set, use SDK to determine
67
+ # Mac Catalyst apps with iOS SDK build for iOS (IPA), not macOS
68
+ return Gym.config[:sdk] == "iphoneos" || Gym.config[:sdk] == "iphonesimulator"
60
69
  end
61
70
 
62
71
  def building_mac_catalyst_for_mac?
63
- Gym.project.supports_mac_catalyst? && Gym.config[:catalyst_platform] == "macos"
72
+ return false unless Gym.project.supports_mac_catalyst?
73
+
74
+ # If catalyst_platform is explicitly set, use it
75
+ if Gym.config[:catalyst_platform]
76
+ return Gym.config[:catalyst_platform] == "macos"
77
+ end
78
+
79
+ # If catalyst_platform is not set, use SDK to determine
80
+ # Mac Catalyst apps with SDK macosx build for Mac (PKG), otherwise for iOS (IPA)
81
+ return Gym.config[:sdk] == "macosx"
64
82
  end
65
83
 
66
84
  def building_multiplatform_for_ios?
@@ -341,9 +341,9 @@ module Match
341
341
  def filter_profiles_and_files_by_selected_certificates
342
342
  # Do profile selection logic
343
343
  cert_ids = self.certs.map { |cert| cert.id.to_s }
344
- self.profiles = self.profiles.reject do |profile|
344
+ self.profiles = self.profiles.select do |profile|
345
345
  profile_cert_ids = profile.certificates.map { |cert| cert.id.to_s }
346
- (cert_ids & profile_cert_ids).empty?
346
+ cert_ids.intersect?(profile_cert_ids)
347
347
  end
348
348
 
349
349
  profile_uuids = self.profiles.map do |profile|
@@ -117,13 +117,10 @@ module Match
117
117
  print_command: FastlaneCore::Globals.verbose?)
118
118
  end
119
119
  rescue
120
- UI.error("Error cloning certificates repo, please make sure you have read access to the repository you want to use")
121
120
  if self.branch && self.clone_branch_directly
122
121
  UI.error("You passed '#{self.branch}' as branch in combination with the `clone_branch_directly` flag. Please remove `clone_branch_directly` flag on the first run for _match_ to create the branch.")
123
122
  end
124
- UI.error("Run the following command manually to make sure you're properly authenticated:")
125
- UI.command(command)
126
- UI.user_error!("Error cloning certificates git repo, please make sure you have access to the repository - see instructions above")
123
+ UI.user_error!("Error cloning certificates repo, please make sure you have read access to the repository you want to use")
127
124
  end
128
125
 
129
126
  add_user_config(self.git_full_name, self.git_user_email)
@@ -82,7 +82,12 @@ module Match
82
82
  if self.google_cloud_keys_file.to_s.length > 0
83
83
  # Extract the Project ID from the `JSON` file
84
84
  # so the user doesn't have to provide it manually
85
- keys_file_content = JSON.parse(File.read(self.google_cloud_keys_file))
85
+ begin
86
+ keys_file_content = JSON.parse(File.read(self.google_cloud_keys_file))
87
+ rescue JSON::ParserError
88
+ # Don't dump secret into logs in case a secret (p8) is passed. See fastlane/fastlane#21017
89
+ UI.user_error!("Provided keys file on path #{File.expand_path(self.google_cloud_keys_file)} is not a valid JSON file")
90
+ end
86
91
  if google_cloud_project_id.to_s.length > 0 && google_cloud_project_id != keys_file_content["project_id"]
87
92
  UI.important("The google_cloud_keys_file's project ID ('#{keys_file_content['project_id']}') doesn't match the google_cloud_project_id ('#{google_cloud_project_id}'). This may be the wrong keys file.")
88
93
  end
@@ -20,7 +20,7 @@ module PEM
20
20
  remaining_days = (existing_certificate.expires - Time.now) / 60 / 60 / 24
21
21
 
22
22
  display_platform = ''
23
- unless PEM.config[:website_push]
23
+ unless PEM.config[:website_push] || PEM.config[:voip_push]
24
24
  display_platform = "#{PEM.config[:platform]} "
25
25
  end
26
26
 
@@ -94,6 +94,8 @@ module PEM
94
94
  def certificate
95
95
  if PEM.config[:website_push]
96
96
  Spaceship.certificate.website_push
97
+ elsif PEM.config[:voip_push]
98
+ Spaceship.certificate.voip_push
97
99
  else
98
100
  platform = PEM.config[:platform]
99
101
  UI.user_error!('platform parameter is unspecified.') unless platform
@@ -123,6 +125,8 @@ module PEM
123
125
  'development'
124
126
  elsif PEM.config[:website_push]
125
127
  'website'
128
+ elsif PEM.config[:voip_push]
129
+ 'voip'
126
130
  else
127
131
  'production'
128
132
  end
@@ -30,6 +30,12 @@ module PEM
30
30
  is_string: false,
31
31
  conflicting_options: [:development],
32
32
  default_value: false),
33
+ FastlaneCore::ConfigItem.new(key: :voip_push,
34
+ env_name: "PEM_VOIP_PUSH",
35
+ description: "Create a VoIP Services certificate",
36
+ is_string: false,
37
+ conflicting_options: [:development, :website_push],
38
+ default_value: false),
33
39
  FastlaneCore::ConfigItem.new(key: :generate_p12,
34
40
  env_name: "PEM_GENERATE_P12_FILE",
35
41
  description: "Generate a p12 file additionally to a PEM file",
@@ -172,7 +172,7 @@ module Pilot
172
172
  # Verify the build has all the includes that we need
173
173
  # and fetch a new build if not
174
174
  if build && (!build.app || !build.build_beta_detail || !build.pre_release_version)
175
- UI.important("Build did include information for app, build beta detail and pre release version")
175
+ UI.important("Build did not include information for app, build beta detail and pre release version")
176
176
  UI.important("Fetching a new build with all the information needed")
177
177
  build = Spaceship::ConnectAPI::Build.get(build_id: build.id)
178
178
  end
@@ -296,6 +296,9 @@ module Pilot
296
296
 
297
297
  # Handle beta app clip invocations
298
298
  update_app_clip_invocations(options: options, build: build)
299
+
300
+ # Handle routing app coverage file
301
+ update_routing_app_coverage(options)
299
302
  end
300
303
 
301
304
  def self.truncate_changelog(changelog)
@@ -459,7 +462,7 @@ module Pilot
459
462
  if options[:groups]
460
463
  app = uploaded_build.app
461
464
  beta_groups = app.get_beta_groups.select do |group|
462
- options[:groups].include?(group.name)
465
+ group.matches_identifiers?(options[:groups])
463
466
  end
464
467
 
465
468
  unless beta_groups.empty?
@@ -679,6 +682,35 @@ module Pilot
679
682
  end
680
683
  end
681
684
  end
685
+
686
+ def update_routing_app_coverage(options)
687
+ # Skip logic entirely if no coverage file passed. So status-quo stays the same.
688
+ return unless options[:routing_app_coverage_file]
689
+
690
+ # We can only attach a coverage file to build upload - so pick the most recent edit.
691
+ platform = Spaceship::ConnectAPI::Platform.map(fetch_app_platform)
692
+ version = app.get_edit_app_store_version(platform: platform)
693
+ unless version
694
+ UI.important("Skipping upload of routing app coverage file - could not find an editable app store version")
695
+ return
696
+ end
697
+
698
+ routing_app_coverage =
699
+ begin
700
+ version.fetch_routing_app_coverage
701
+ rescue => error
702
+ UI.important("Error fetching routing app coverage - #{error.message}")
703
+ nil
704
+ end
705
+
706
+ if routing_app_coverage
707
+ UI.message("Removing previous routing app coverage file from App Store Connect")
708
+ routing_app_coverage.delete!
709
+ end
710
+
711
+ UI.message("Uploading routing app coverage file to App Store Connect")
712
+ version.upload_routing_app_coverage(path: options[:routing_app_coverage_file])
713
+ end
682
714
  end
683
715
  # rubocop:enable Metrics/ClassLength
684
716
  end
@@ -201,6 +201,14 @@ module Pilot
201
201
  optional: true,
202
202
  type: Boolean,
203
203
  default_value: false),
204
+ FastlaneCore::ConfigItem.new(key: :routing_app_coverage_file,
205
+ env_name: "PILOT_ROUTING_APP_COVERAGE_FILE",
206
+ description: "Path to the routing app coverage file (`.geojson`) that is required for routing apps. It will be uploaded to the editable App Store version of the app",
207
+ optional: true,
208
+ verify_block: proc do |value|
209
+ UI.user_error!("Could not find routing app coverage file at path '#{File.expand_path(value)}'") unless File.exist?(value)
210
+ UI.user_error!("Routing app coverage file must be a .geojson file") unless File.extname(value).casecmp(".geojson").zero?
211
+ end),
204
212
 
205
213
  # distribution
206
214
  FastlaneCore::ConfigItem.new(key: :distribute_only,
@@ -267,7 +275,7 @@ module Pilot
267
275
  FastlaneCore::ConfigItem.new(key: :groups,
268
276
  short_option: "-g",
269
277
  env_name: "PILOT_GROUPS",
270
- description: "Associate tester to one group or more by group name / group id. E.g. `-g \"Team 1\",\"Team 2\"` This is required when `distribute_external` option is set to true or when we want to add a tester to one or more external testing groups ",
278
+ description: "Associate tester to one group or more by group name / group id. E.g. `-g \"Team 1\",\"a06cf5b5-95a9-4beb-88c6-f22bd6b3f7a2\"` This is required when `distribute_external` option is set to true or when we want to add a tester to one or more external testing groups ",
271
279
  optional: true,
272
280
  type: Array,
273
281
  verify_block: proc do |value|
@@ -312,7 +320,7 @@ module Pilot
312
320
  # rubocop:disable Layout/LineLength
313
321
  FastlaneCore::ConfigItem.new(key: :itc_provider,
314
322
  env_name: "PILOT_ITC_PROVIDER",
315
- description: "The provider short name to be used with the iTMSTransporter to identify your team. This value will override the automatically detected provider short name. To get provider short name run `pathToXcode.app/Contents/Applications/Application\\ Loader.app/Contents/itms/bin/iTMSTransporter -m provider -u 'USERNAME' -p 'PASSWORD' -account_type itunes_connect -v off`. The short names of providers should be listed in the second column",
323
+ description: "The provider short name to be used with the iTMSTransporter to identify your team. This value will override the automatically detected provider short name. To get provider short name run `xcrun iTMSTransporter -m provider -u 'USERNAME' -p 'PASSWORD' -account_type itunes_connect -v off`. The short names of providers should be listed in the second column",
316
324
  optional: true),
317
325
  FastlaneCore::ConfigItem.new(key: :provider_public_id,
318
326
  env_name: "PILOT_PROVIDER_PUBLIC_ID",
@@ -13,7 +13,7 @@ module Pilot
13
13
  UI.user_error!("You must provide 1 or more groups (with the `:groups` option)") unless groups_param
14
14
 
15
15
  app.get_beta_groups.select do |group|
16
- next unless groups_param.include?(group.name)
16
+ next unless group.matches_identifiers?(groups_param)
17
17
  user = {
18
18
  email: config[:email],
19
19
  firstName: config[:first_name],
@@ -54,7 +54,7 @@ module Pilot
54
54
  UI.success("Successfully removed tester #{tester.email} from app: #{app.name}")
55
55
  else
56
56
  groups = tester.beta_groups.select do |group|
57
- config[:groups].include?(group.name)
57
+ group.matches_identifiers?(config[:groups])
58
58
  end
59
59
  tester.delete_from_beta_groups(beta_groups: groups)
60
60
 
@@ -11,7 +11,7 @@ module Precheck
11
11
  end
12
12
 
13
13
  def self.friendly_name
14
- "Incorrect, or missing copyright date"
14
+ "No incorrect or missing copyright date"
15
15
  end
16
16
 
17
17
  def self.description
@@ -1,5 +1,5 @@
1
1
  require 'addressable'
2
- require 'faraday_middleware'
2
+ require 'faraday/follow_redirects'
3
3
 
4
4
  require_relative '../rule'
5
5
 
@@ -30,7 +30,7 @@ module Precheck
30
30
  uri = Addressable::URI.parse(url)
31
31
  uri.fragment = nil
32
32
  request = Faraday.new(uri.normalize.to_s) do |connection|
33
- connection.use(FaradayMiddleware::FollowRedirects)
33
+ connection.response(:follow_redirects)
34
34
  connection.adapter(:net_http)
35
35
  end
36
36
  return RuleReturn.new(validation_state: Precheck::VALIDATION_STATES[:failed], failure_data: "HTTP #{request.head.status}: #{url}") unless request.head.status == 200