fastlane 2.217.0 → 2.218.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +96 -96
- data/deliver/lib/deliver/app_screenshot.rb +2 -2
- data/deliver/lib/deliver/app_screenshot_iterator.rb +2 -2
- data/deliver/lib/deliver/detect_values.rb +1 -1
- data/deliver/lib/deliver/languages.rb +1 -1
- data/deliver/lib/deliver/loader.rb +2 -2
- data/deliver/lib/deliver/options.rb +4 -4
- data/deliver/lib/deliver/runner.rb +1 -1
- data/deliver/lib/deliver/sync_screenshots.rb +2 -2
- data/deliver/lib/deliver/upload_metadata.rb +4 -4
- data/deliver/lib/deliver/upload_price_tier.rb +1 -1
- data/deliver/lib/deliver/upload_screenshots.rb +3 -3
- data/fastlane/lib/fastlane/action.rb +1 -1
- data/fastlane/lib/fastlane/actions/appledoc.rb +1 -1
- data/fastlane/lib/fastlane/actions/apteligent.rb +1 -1
- data/fastlane/lib/fastlane/actions/backup_xcarchive.rb +1 -1
- data/fastlane/lib/fastlane/actions/commit_github_file.rb +2 -2
- data/fastlane/lib/fastlane/actions/copy_artifacts.rb +1 -1
- data/fastlane/lib/fastlane/actions/create_app_online.rb +1 -1
- data/fastlane/lib/fastlane/actions/create_pull_request.rb +1 -1
- data/fastlane/lib/fastlane/actions/get_certificates.rb +1 -1
- data/fastlane/lib/fastlane/actions/get_github_release.rb +1 -1
- data/fastlane/lib/fastlane/actions/get_provisioning_profile.rb +1 -1
- data/fastlane/lib/fastlane/actions/github_api.rb +1 -1
- data/fastlane/lib/fastlane/actions/gradle.rb +1 -1
- data/fastlane/lib/fastlane/actions/install_on_device.rb +1 -1
- data/fastlane/lib/fastlane/actions/ipa.rb +1 -1
- data/fastlane/lib/fastlane/actions/jazzy.rb +1 -1
- data/fastlane/lib/fastlane/actions/oclint.rb +3 -3
- data/fastlane/lib/fastlane/actions/opt_out_crash_reporting.rb +2 -2
- data/fastlane/lib/fastlane/actions/restore_file.rb +1 -1
- data/fastlane/lib/fastlane/actions/set_github_release.rb +1 -1
- data/fastlane/lib/fastlane/actions/slather.rb +1 -1
- data/fastlane/lib/fastlane/actions/sonar.rb +12 -3
- data/fastlane/lib/fastlane/actions/splunkmint.rb +1 -1
- data/fastlane/lib/fastlane/actions/spm.rb +76 -2
- data/fastlane/lib/fastlane/actions/update_info_plist.rb +1 -1
- data/fastlane/lib/fastlane/actions/update_urban_airship_configuration.rb +1 -1
- data/fastlane/lib/fastlane/actions/upload_symbols_to_crashlytics.rb +1 -0
- data/fastlane/lib/fastlane/actions/upload_symbols_to_sentry.rb +1 -1
- data/fastlane/lib/fastlane/actions/upload_to_testflight.rb +2 -2
- data/fastlane/lib/fastlane/actions/verify_build.rb +7 -4
- data/fastlane/lib/fastlane/actions/xcov.rb +1 -1
- data/fastlane/lib/fastlane/cli_tools_distributor.rb +1 -1
- data/fastlane/lib/fastlane/command_line_handler.rb +2 -4
- data/fastlane/lib/fastlane/commands_generator.rb +2 -2
- data/fastlane/lib/fastlane/fast_file.rb +1 -1
- data/fastlane/lib/fastlane/helper/dotenv_helper.rb +1 -1
- data/fastlane/lib/fastlane/junit_generator.rb +1 -1
- data/fastlane/lib/fastlane/lane_manager.rb +1 -2
- data/fastlane/lib/fastlane/plugins/template/%gem_name%.gemspec.erb +0 -11
- data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +5 -1
- data/fastlane/lib/fastlane/plugins/template/Gemfile.erb +27 -0
- data/fastlane/lib/fastlane/runner.rb +1 -1
- data/fastlane/lib/fastlane/setup/setup.rb +1 -1
- data/fastlane/lib/fastlane/swift_lane_manager.rb +2 -5
- data/fastlane/lib/fastlane/swift_runner_upgrader.rb +7 -4
- data/fastlane/lib/fastlane/version.rb +1 -1
- data/fastlane/swift/Actions.swift +1 -1
- data/fastlane/swift/Appfile.swift +1 -1
- data/fastlane/swift/ArgumentProcessor.swift +1 -1
- data/fastlane/swift/Atomic.swift +1 -1
- data/fastlane/swift/ControlCommand.swift +1 -1
- data/fastlane/swift/Deliverfile.swift +2 -2
- data/fastlane/swift/DeliverfileProtocol.swift +4 -4
- data/fastlane/swift/Fastlane.swift +79 -27
- data/fastlane/swift/Gymfile.swift +2 -2
- data/fastlane/swift/GymfileProtocol.swift +2 -2
- data/fastlane/swift/LaneFileProtocol.swift +5 -5
- data/fastlane/swift/MainProcess.swift +1 -1
- data/fastlane/swift/Matchfile.swift +2 -2
- data/fastlane/swift/MatchfileProtocol.swift +2 -2
- data/fastlane/swift/OptionalConfigValue.swift +1 -1
- data/fastlane/swift/Plugins.swift +1 -1
- data/fastlane/swift/Precheckfile.swift +2 -2
- data/fastlane/swift/PrecheckfileProtocol.swift +2 -2
- data/fastlane/swift/RubyCommand.swift +1 -1
- data/fastlane/swift/RubyCommandable.swift +1 -1
- data/fastlane/swift/Runner.swift +1 -1
- data/fastlane/swift/RunnerArgument.swift +1 -1
- data/fastlane/swift/Scanfile.swift +2 -2
- data/fastlane/swift/ScanfileProtocol.swift +2 -2
- data/fastlane/swift/Screengrabfile.swift +2 -2
- data/fastlane/swift/ScreengrabfileProtocol.swift +2 -2
- data/fastlane/swift/Snapshotfile.swift +2 -2
- data/fastlane/swift/SnapshotfileProtocol.swift +2 -2
- data/fastlane/swift/SocketClient.swift +1 -1
- data/fastlane/swift/SocketClientDelegateProtocol.swift +1 -1
- data/fastlane/swift/SocketResponse.swift +1 -1
- data/fastlane/swift/formatting/Brewfile.lock.json +18 -18
- data/fastlane/swift/main.swift +1 -1
- data/fastlane_core/lib/fastlane_core/build_watcher.rb +1 -1
- data/fastlane_core/lib/fastlane_core/cert_checker.rb +2 -2
- data/fastlane_core/lib/fastlane_core/configuration/configuration_file.rb +1 -1
- data/fastlane_core/lib/fastlane_core/device_manager.rb +17 -15
- data/fastlane_core/lib/fastlane_core/fastlane_pty.rb +34 -12
- data/fastlane_core/lib/fastlane_core/helper.rb +1 -1
- data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +5 -2
- data/fastlane_core/lib/fastlane_core/project.rb +3 -2
- data/fastlane_core/lib/fastlane_core/queue_worker.rb +1 -1
- data/fastlane_core/lib/fastlane_core/string_filters.rb +6 -6
- data/fastlane_core/lib/fastlane_core/ui/fastlane_runner.rb +2 -2
- data/frameit/lib/frameit/editor.rb +4 -4
- data/frameit/lib/frameit/trim_box.rb +1 -1
- data/gym/lib/gym/error_handler.rb +1 -1
- data/gym/lib/gym/generators/package_command_generator_xcode7.rb +3 -3
- data/gym/lib/gym/runner.rb +1 -1
- data/gym/lib/gym/xcodebuild_fixes/README.md +1 -1
- data/match/lib/match/generator.rb +9 -1
- data/match/lib/match/module.rb +2 -1
- data/match/lib/match/portal_cache.rb +106 -0
- data/match/lib/match/portal_fetcher.rb +72 -0
- data/match/lib/match/profile_includes.rb +120 -0
- data/match/lib/match/runner.rb +70 -169
- data/match/lib/match/spaceship_ensure.rb +15 -11
- data/match/lib/match/storage/git_storage.rb +8 -3
- data/match/lib/match/storage/gitlab/client.rb +1 -1
- data/match/lib/match/storage/gitlab_secure_files.rb +1 -1
- data/match/lib/match/storage/interface.rb +1 -1
- data/match/lib/match/storage/s3_storage.rb +1 -1
- data/match/lib/match.rb +3 -0
- data/produce/lib/produce/itunes_connect.rb +1 -1
- data/scan/lib/scan/detect_values.rb +78 -20
- data/scan/lib/scan/options.rb +1 -1
- data/scan/lib/scan/runner.rb +1 -1
- data/screengrab/lib/screengrab/runner.rb +1 -1
- data/sigh/lib/assets/resign.sh +10 -10
- data/sigh/lib/sigh/commands_generator.rb +1 -1
- data/sigh/lib/sigh/module.rb +98 -0
- data/sigh/lib/sigh/options.rb +55 -1
- data/sigh/lib/sigh/resign.rb +1 -1
- data/sigh/lib/sigh/runner.rb +35 -111
- data/snapshot/lib/snapshot/setup.rb +2 -2
- data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher.rb +23 -22
- data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +2 -2
- data/spaceship/lib/spaceship/client.rb +1 -1
- data/spaceship/lib/spaceship/connect_api/api_client.rb +1 -1
- data/spaceship/lib/spaceship/connect_api/client.rb +4 -4
- data/spaceship/lib/spaceship/connect_api/models/app_preview_set.rb +2 -0
- data/spaceship/lib/spaceship/connect_api/models/app_screenshot.rb +2 -2
- data/spaceship/lib/spaceship/connect_api/models/bundle_id.rb +2 -2
- data/spaceship/lib/spaceship/connect_api/models/certificate.rb +2 -2
- data/spaceship/lib/spaceship/connect_api/models/device.rb +82 -3
- data/spaceship/lib/spaceship/connect_api/models/profile.rb +3 -2
- data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +3 -3
- data/spaceship/lib/spaceship/connect_api.rb +2 -0
- data/spaceship/lib/spaceship/portal/app.rb +1 -1
- data/spaceship/lib/spaceship/portal/app_group.rb +1 -1
- data/spaceship/lib/spaceship/test_flight/client.rb +1 -1
- data/spaceship/lib/spaceship/test_flight/tester.rb +1 -1
- data/spaceship/lib/spaceship/tunes/app_details.rb +2 -2
- data/spaceship/lib/spaceship/tunes/app_image.rb +1 -1
- data/spaceship/lib/spaceship/tunes/app_review_attachment.rb +1 -1
- data/spaceship/lib/spaceship/tunes/app_submission.rb +1 -1
- data/spaceship/lib/spaceship/tunes/app_version.rb +5 -5
- data/spaceship/lib/spaceship/tunes/build_details.rb +1 -1
- data/spaceship/lib/spaceship/tunes/iap.rb +3 -3
- data/spaceship/lib/spaceship/tunes/iap_detail.rb +2 -2
- data/spaceship/lib/spaceship/tunes/iap_families.rb +1 -1
- data/spaceship/lib/spaceship/tunes/iap_family_details.rb +2 -2
- data/spaceship/lib/spaceship/tunes/iap_family_list.rb +1 -1
- data/spaceship/lib/spaceship/tunes/tunes_client.rb +2 -2
- data/supply/lib/supply/client.rb +1 -1
- data/supply/lib/supply/setup.rb +1 -1
- data/trainer/lib/trainer/junit_generator.rb +1 -1
- data/trainer/lib/trainer/test_parser.rb +1 -1
- metadata +26 -289
- data/fastlane/lib/fastlane/plugins/template/Gemfile +0 -6
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'fastlane_core/provisioning_profile'
|
2
|
+
require 'spaceship/client'
|
3
|
+
require_relative 'portal_fetcher'
|
4
|
+
module Match
|
5
|
+
class Portal
|
6
|
+
class Cache
|
7
|
+
def self.build(params:, bundle_id_identifiers:)
|
8
|
+
require_relative 'profile_includes'
|
9
|
+
require 'sigh'
|
10
|
+
|
11
|
+
profile_type = Sigh.profile_type_for_distribution_type(
|
12
|
+
platform: params[:platform],
|
13
|
+
distribution_type: params[:type]
|
14
|
+
)
|
15
|
+
|
16
|
+
cache = Portal::Cache.new(
|
17
|
+
platform: params[:platform],
|
18
|
+
profile_type: profile_type,
|
19
|
+
additional_cert_types: params[:additional_cert_types],
|
20
|
+
bundle_id_identifiers: bundle_id_identifiers,
|
21
|
+
needs_profiles_devices: ProfileIncludes.can_force_include?(params: params, notify: true) && !params[:force] && !params[:readonly],
|
22
|
+
needs_profiles_certificate_content: !ProfileIncludes.can_force_include_all_certificates?(params: params),
|
23
|
+
include_mac_in_profiles: params[:include_mac_in_profiles]
|
24
|
+
)
|
25
|
+
|
26
|
+
return cache
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :platform, :profile_type, :bundle_id_identifiers, :additional_cert_types, :needs_profiles_devices, :needs_profiles_certificate_content, :include_mac_in_profiles
|
30
|
+
|
31
|
+
def initialize(platform:, profile_type:, additional_cert_types:, bundle_id_identifiers:, needs_profiles_devices:, needs_profiles_certificate_content:, include_mac_in_profiles:)
|
32
|
+
@platform = platform
|
33
|
+
@profile_type = profile_type
|
34
|
+
|
35
|
+
# Bundle Ids
|
36
|
+
@bundle_id_identifiers = bundle_id_identifiers
|
37
|
+
|
38
|
+
# Certs
|
39
|
+
@additional_cert_types = additional_cert_types
|
40
|
+
|
41
|
+
# Profiles
|
42
|
+
@needs_profiles_devices = needs_profiles_devices
|
43
|
+
@needs_profiles_certificate_content = needs_profiles_certificate_content
|
44
|
+
|
45
|
+
# Devices
|
46
|
+
@include_mac_in_profiles = include_mac_in_profiles
|
47
|
+
end
|
48
|
+
|
49
|
+
def portal_profile(stored_profile_path:, keychain_path:)
|
50
|
+
parsed = FastlaneCore::ProvisioningProfile.parse(stored_profile_path, keychain_path)
|
51
|
+
uuid = parsed["UUID"]
|
52
|
+
|
53
|
+
portal_profile = self.profiles.detect { |i| i.uuid == uuid }
|
54
|
+
|
55
|
+
portal_profile
|
56
|
+
end
|
57
|
+
|
58
|
+
def reset_certificates
|
59
|
+
@certificates = nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def forget_portal_profile(portal_profile)
|
63
|
+
return unless @profiles && portal_profile
|
64
|
+
|
65
|
+
@profiles -= [portal_profile]
|
66
|
+
end
|
67
|
+
|
68
|
+
def bundle_ids
|
69
|
+
@bundle_ids ||= Match::Portal::Fetcher.bundle_ids(
|
70
|
+
bundle_id_identifiers: @bundle_id_identifiers
|
71
|
+
)
|
72
|
+
|
73
|
+
return @bundle_ids.dup
|
74
|
+
end
|
75
|
+
|
76
|
+
def certificates
|
77
|
+
@certificates ||= Match::Portal::Fetcher.certificates(
|
78
|
+
platform: @platform,
|
79
|
+
profile_type: @profile_type,
|
80
|
+
additional_cert_types: @additional_cert_types
|
81
|
+
)
|
82
|
+
|
83
|
+
return @certificates.dup
|
84
|
+
end
|
85
|
+
|
86
|
+
def profiles
|
87
|
+
@profiles ||= Match::Portal::Fetcher.profiles(
|
88
|
+
profile_type: @profile_type,
|
89
|
+
needs_profiles_devices: @needs_profiles_devices,
|
90
|
+
needs_profiles_certificate_content: @needs_profiles_certificate_content
|
91
|
+
)
|
92
|
+
|
93
|
+
return @profiles.dup
|
94
|
+
end
|
95
|
+
|
96
|
+
def devices
|
97
|
+
@devices ||= Match::Portal::Fetcher.devices(
|
98
|
+
platform: @platform,
|
99
|
+
include_mac_in_profiles: @include_mac_in_profiles
|
100
|
+
)
|
101
|
+
|
102
|
+
return @devices.dup
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'fastlane_core/provisioning_profile'
|
2
|
+
require 'spaceship/client'
|
3
|
+
require 'spaceship/connect_api/models/profile'
|
4
|
+
|
5
|
+
module Match
|
6
|
+
class Portal
|
7
|
+
module Fetcher
|
8
|
+
def self.profiles(profile_type:, needs_profiles_devices: false, needs_profiles_certificate_content: false, name: nil)
|
9
|
+
includes = ['bundleId']
|
10
|
+
|
11
|
+
if needs_profiles_devices
|
12
|
+
includes += ['devices', 'certificates']
|
13
|
+
end
|
14
|
+
|
15
|
+
if needs_profiles_certificate_content
|
16
|
+
includes += ['certificates']
|
17
|
+
end
|
18
|
+
|
19
|
+
profiles = Spaceship::ConnectAPI::Profile.all(
|
20
|
+
filter: { profileType: profile_type, name: name }.compact,
|
21
|
+
includes: includes.uniq.join(',')
|
22
|
+
)
|
23
|
+
|
24
|
+
profiles
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.certificates(platform:, profile_type:, additional_cert_types:)
|
28
|
+
require 'sigh'
|
29
|
+
certificate_types = Sigh.certificate_types_for_profile_and_platform(platform: platform, profile_type: profile_type)
|
30
|
+
|
31
|
+
additional_cert_types ||= []
|
32
|
+
additional_cert_types.map! do |cert_type|
|
33
|
+
case Match.cert_type_sym(cert_type)
|
34
|
+
when :mac_installer_distribution
|
35
|
+
Spaceship::ConnectAPI::Certificate::CertificateType::MAC_INSTALLER_DISTRIBUTION
|
36
|
+
when :developer_id_installer
|
37
|
+
Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPER_ID_INSTALLER
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
certificate_types += additional_cert_types
|
42
|
+
|
43
|
+
filter = { certificateType: certificate_types.uniq.sort.join(',') } unless certificate_types.empty?
|
44
|
+
|
45
|
+
certificates = Spaceship::ConnectAPI::Certificate.all(
|
46
|
+
filter: filter
|
47
|
+
).select(&:valid?)
|
48
|
+
|
49
|
+
certificates
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.devices(platform: nil, include_mac_in_profiles: false)
|
53
|
+
devices = Spaceship::ConnectAPI::Device.devices_for_platform(
|
54
|
+
platform: platform,
|
55
|
+
include_mac_in_profiles: include_mac_in_profiles
|
56
|
+
)
|
57
|
+
|
58
|
+
devices
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.bundle_ids(bundle_id_identifiers: nil)
|
62
|
+
filter = { identifier: bundle_id_identifiers.join(',') } if bundle_id_identifiers
|
63
|
+
|
64
|
+
bundle_ids = Spaceship::ConnectAPI::BundleId.all(
|
65
|
+
filter: filter
|
66
|
+
)
|
67
|
+
|
68
|
+
bundle_ids
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require_relative 'portal_fetcher'
|
2
|
+
require_relative 'module'
|
3
|
+
|
4
|
+
module Match
|
5
|
+
class ProfileIncludes
|
6
|
+
PROV_TYPES_WITH_DEVICES = [:adhoc, :development]
|
7
|
+
PROV_TYPES_WITH_MULTIPLE_CERTIFICATES = [:development]
|
8
|
+
|
9
|
+
def self.can_force_include?(params:, notify:)
|
10
|
+
self.can_force_include_all_devices?(params: params, notify: notify) &&
|
11
|
+
self.can_force_include_all_certificates?(params: params, notify: notify)
|
12
|
+
end
|
13
|
+
|
14
|
+
###############
|
15
|
+
#
|
16
|
+
# DEVICES
|
17
|
+
#
|
18
|
+
###############
|
19
|
+
|
20
|
+
def self.should_force_include_all_devices?(params:, portal_profile:, cached_devices:)
|
21
|
+
return false unless self.can_force_include_all_devices?(params: params)
|
22
|
+
|
23
|
+
force = devices_differ?(portal_profile: portal_profile, platform: params[:platform], include_mac_in_profiles: params[:include_mac_in_profiles], cached_devices: cached_devices)
|
24
|
+
|
25
|
+
return force
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.can_force_include_all_devices?(params:, notify: false)
|
29
|
+
return false if params[:readonly] || params[:force]
|
30
|
+
return false unless params[:force_for_new_devices]
|
31
|
+
|
32
|
+
provisioning_type = params[:type].to_sym
|
33
|
+
|
34
|
+
can_force = PROV_TYPES_WITH_DEVICES.include?(provisioning_type)
|
35
|
+
|
36
|
+
if !can_force && notify
|
37
|
+
# App Store provisioning profiles don't contain device identifiers and
|
38
|
+
# thus shouldn't be renewed if the device count has changed.
|
39
|
+
UI.important("Warning: `force_for_new_devices` is set but is ignored for #{provisioning_type}.")
|
40
|
+
UI.important("You can safely stop specifying `force_for_new_devices` when running Match for type '#{provisioning_type}'.")
|
41
|
+
end
|
42
|
+
|
43
|
+
can_force
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.devices_differ?(portal_profile:, platform:, include_mac_in_profiles:, cached_devices:)
|
47
|
+
return false unless portal_profile
|
48
|
+
|
49
|
+
profile_devices = portal_profile.devices
|
50
|
+
|
51
|
+
portal_devices = cached_devices
|
52
|
+
portal_devices ||= Match::Portal::Fetcher.devices(platform: platform, include_mac_in_profiles: include_mac_in_profiles)
|
53
|
+
|
54
|
+
profile_device_ids = profile_devices.map(&:id).sort
|
55
|
+
portal_devices_ids = portal_devices.map(&:id).sort
|
56
|
+
|
57
|
+
devices_differs = profile_device_ids != portal_devices_ids
|
58
|
+
|
59
|
+
UI.important("Devices in the profile and available on the portal differ. Recreating a profile") if devices_differs
|
60
|
+
|
61
|
+
return devices_differs
|
62
|
+
end
|
63
|
+
|
64
|
+
###############
|
65
|
+
#
|
66
|
+
# CERTIFICATES
|
67
|
+
#
|
68
|
+
###############
|
69
|
+
|
70
|
+
def self.should_force_include_all_certificates?(params:, portal_profile:, cached_certificates:)
|
71
|
+
return false unless self.can_force_include_all_certificates?(params: params)
|
72
|
+
|
73
|
+
force = certificates_differ?(portal_profile: portal_profile, platform: params[:platform], cached_certificates: cached_certificates)
|
74
|
+
|
75
|
+
return force
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.can_force_include_all_certificates?(params:, notify: false)
|
79
|
+
return false if params[:readonly] || params[:force]
|
80
|
+
return false unless params[:force_for_new_certificates]
|
81
|
+
|
82
|
+
unless params[:include_all_certificates]
|
83
|
+
UI.important("You specified 'force_for_new_certificates: true', but new certificates will not be added, cause 'include_all_certificates' is 'false'") if notify
|
84
|
+
return false
|
85
|
+
end
|
86
|
+
|
87
|
+
provisioning_type = params[:type].to_sym
|
88
|
+
|
89
|
+
can_force = PROV_TYPES_WITH_MULTIPLE_CERTIFICATES.include?(provisioning_type)
|
90
|
+
|
91
|
+
if !can_force && notify
|
92
|
+
# All other (not development) provisioning profiles don't contain
|
93
|
+
# multiple certificates, thus shouldn't be renewed
|
94
|
+
# if the certificates count has changed.
|
95
|
+
UI.important("Warning: `force_for_new_certificates` is set but is ignored for non-'development' provisioning profiles.")
|
96
|
+
UI.important("You can safely stop specifying `force_for_new_certificates` when running Match for '#{provisioning_type}' provisioning profiles.")
|
97
|
+
end
|
98
|
+
|
99
|
+
can_force
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.certificates_differ?(portal_profile:, platform:, cached_certificates:)
|
103
|
+
return false unless portal_profile
|
104
|
+
|
105
|
+
profile_certs = portal_profile.certificates
|
106
|
+
|
107
|
+
portal_certs = cached_certificates
|
108
|
+
portal_certs ||= Match::Portal::Fetcher.certificates(platform: platform, profile_type: portal_profile.profile_type)
|
109
|
+
|
110
|
+
profile_certs_ids = profile_certs.map(&:id).sort
|
111
|
+
portal_certs_ids = portal_certs.map(&:id).sort
|
112
|
+
|
113
|
+
certificates_differ = profile_certs_ids != portal_certs_ids
|
114
|
+
|
115
|
+
UI.important("Certificates in the profile and available on the portal differ. Recreating a profile") if certificates_differ
|
116
|
+
|
117
|
+
return certificates_differ
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
data/match/lib/match/runner.rb
CHANGED
@@ -2,6 +2,8 @@ require 'fastlane_core/cert_checker'
|
|
2
2
|
require 'fastlane_core/provisioning_profile'
|
3
3
|
require 'fastlane_core/print_table'
|
4
4
|
require 'spaceship/client'
|
5
|
+
require 'sigh/module'
|
6
|
+
|
5
7
|
require_relative 'generator'
|
6
8
|
require_relative 'module'
|
7
9
|
require_relative 'table_printer'
|
@@ -10,6 +12,8 @@ require_relative 'utils'
|
|
10
12
|
|
11
13
|
require_relative 'storage'
|
12
14
|
require_relative 'encryption'
|
15
|
+
require_relative 'profile_includes'
|
16
|
+
require_relative 'portal_cache'
|
13
17
|
|
14
18
|
module Match
|
15
19
|
# rubocop:disable Metrics/ClassLength
|
@@ -19,6 +23,8 @@ module Match
|
|
19
23
|
|
20
24
|
attr_accessor :storage
|
21
25
|
|
26
|
+
attr_accessor :cache
|
27
|
+
|
22
28
|
# rubocop:disable Metrics/PerceivedComplexity
|
23
29
|
def run(params)
|
24
30
|
self.files_to_commit = []
|
@@ -60,12 +66,18 @@ module Match
|
|
60
66
|
|
61
67
|
# sometimes we get an array with arrays, this is a bug. To unblock people using match, I suggest we flatten
|
62
68
|
# then in the future address the root cause of https://github.com/fastlane/fastlane/issues/11324
|
63
|
-
app_identifiers = app_identifiers.flatten
|
69
|
+
app_identifiers = app_identifiers.flatten.uniq
|
70
|
+
|
71
|
+
# Cache bundle ids, certificates, profiles, and devices.
|
72
|
+
self.cache = Portal::Cache.build(
|
73
|
+
params: params,
|
74
|
+
bundle_id_identifiers: app_identifiers
|
75
|
+
)
|
64
76
|
|
65
77
|
# Verify the App ID (as we don't want 'match' to fail at a later point)
|
66
78
|
if spaceship
|
67
79
|
app_identifiers.each do |app_identifier|
|
68
|
-
spaceship.bundle_identifier_exists(username: params[:username], app_identifier: app_identifier,
|
80
|
+
spaceship.bundle_identifier_exists(username: params[:username], app_identifier: app_identifier, cached_bundle_ids: self.cache.bundle_ids)
|
69
81
|
end
|
70
82
|
end
|
71
83
|
|
@@ -78,17 +90,24 @@ module Match
|
|
78
90
|
fetch_certificate(params: params, working_directory: storage.working_directory, specific_cert_type: additional_cert_type)
|
79
91
|
end
|
80
92
|
|
93
|
+
profile_type = Sigh.profile_type_for_distribution_type(
|
94
|
+
platform: params[:platform],
|
95
|
+
distribution_type: params[:type]
|
96
|
+
)
|
97
|
+
|
81
98
|
cert_ids << cert_id
|
82
|
-
spaceship.certificates_exists(username: params[:username], certificate_ids: cert_ids) if spaceship
|
99
|
+
spaceship.certificates_exists(username: params[:username], certificate_ids: cert_ids, platform: params[:platform], profile_type: profile_type, cached_certificates: self.cache.certificates) if spaceship
|
83
100
|
|
84
101
|
# Provisioning Profiles
|
102
|
+
|
85
103
|
unless params[:skip_provisioning_profiles]
|
86
104
|
app_identifiers.each do |app_identifier|
|
87
105
|
loop do
|
88
106
|
break if fetch_provisioning_profile(params: params,
|
107
|
+
profile_type: profile_type,
|
89
108
|
certificate_id: cert_id,
|
90
109
|
app_identifier: app_identifier,
|
91
|
-
|
110
|
+
working_directory: storage.working_directory)
|
92
111
|
end
|
93
112
|
end
|
94
113
|
end
|
@@ -141,12 +160,15 @@ module Match
|
|
141
160
|
|
142
161
|
if certs.count == 0 || keys.count == 0
|
143
162
|
UI.important("Couldn't find a valid code signing identity for #{cert_type}... creating one for you now")
|
144
|
-
UI.crash!("No code signing identity found and
|
163
|
+
UI.crash!("No code signing identity found and cannot create a new one because you enabled `readonly`") if params[:readonly]
|
145
164
|
cert_path = Generator.generate_certificate(params, cert_type, prefixed_working_directory, specific_cert_type: specific_cert_type)
|
146
165
|
private_key_path = cert_path.gsub(".cer", ".p12")
|
147
166
|
|
148
167
|
self.files_to_commit << cert_path
|
149
168
|
self.files_to_commit << private_key_path
|
169
|
+
|
170
|
+
# Reset certificates cache since we have a new cert.
|
171
|
+
self.cache.reset_certificates
|
150
172
|
else
|
151
173
|
cert_path = select_cert_or_key(paths: certs)
|
152
174
|
|
@@ -199,7 +221,7 @@ module Match
|
|
199
221
|
|
200
222
|
# rubocop:disable Metrics/PerceivedComplexity
|
201
223
|
# @return [String] The UUID of the provisioning profile so we can verify it with the Apple Developer Portal
|
202
|
-
def fetch_provisioning_profile(params: nil, certificate_id: nil, app_identifier: nil, working_directory: nil)
|
224
|
+
def fetch_provisioning_profile(params: nil, profile_type:, certificate_id: nil, app_identifier: nil, working_directory: nil)
|
203
225
|
prov_type = Match.profile_type_sym(params[:type])
|
204
226
|
|
205
227
|
names = [Match::Generator.profile_type_name(prov_type), app_identifier]
|
@@ -222,20 +244,23 @@ module Match
|
|
222
244
|
end
|
223
245
|
|
224
246
|
# Install the provisioning profiles
|
225
|
-
|
247
|
+
stored_profile_path = profiles.last
|
226
248
|
force = params[:force]
|
227
249
|
|
250
|
+
portal_profile = self.cache.portal_profile(stored_profile_path: stored_profile_path, keychain_path: keychain_path) if stored_profile_path
|
251
|
+
|
228
252
|
if params[:force_for_new_devices]
|
229
|
-
force
|
253
|
+
force ||= ProfileIncludes.should_force_include_all_devices?(params: params, portal_profile: portal_profile, cached_devices: self.cache.devices)
|
230
254
|
end
|
231
255
|
|
232
256
|
if params[:include_all_certificates]
|
233
257
|
# Clearing specified certificate id which will prevent a profile being created with only one certificate
|
234
258
|
certificate_id = nil
|
235
|
-
force
|
259
|
+
force ||= ProfileIncludes.should_force_include_all_certificates?(params: params, portal_profile: portal_profile, cached_certificates: self.cache.certificates)
|
236
260
|
end
|
237
261
|
|
238
|
-
|
262
|
+
is_new_profile_created = false
|
263
|
+
if stored_profile_path.nil? || force
|
239
264
|
if params[:readonly]
|
240
265
|
UI.error("No matching provisioning profiles found for '#{profile_file}'")
|
241
266
|
UI.error("A new one cannot be created because you enabled `readonly`")
|
@@ -245,38 +270,53 @@ module Match
|
|
245
270
|
all_profiles.each { |p| UI.error("- '#{p}'") }
|
246
271
|
end
|
247
272
|
UI.error("If you are certain that a profile should exist, double-check the recent changes to your match repository")
|
248
|
-
UI.user_error!("No matching provisioning profiles found and
|
273
|
+
UI.user_error!("No matching provisioning profiles found and cannot create a new one because you enabled `readonly`. Check the output above for more information.")
|
249
274
|
end
|
250
275
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
276
|
+
stored_profile_path = Generator.generate_provisioning_profile(
|
277
|
+
params: params,
|
278
|
+
prov_type: prov_type,
|
279
|
+
certificate_id: certificate_id,
|
280
|
+
app_identifier: app_identifier,
|
281
|
+
force: force,
|
282
|
+
cache: self.cache,
|
283
|
+
working_directory: prefixed_working_directory
|
284
|
+
)
|
259
285
|
|
260
|
-
|
261
|
-
|
286
|
+
# Recreation of the profile means old profile is invalid.
|
287
|
+
# Removing it from cache. We don't need a new profile in cache.
|
288
|
+
self.cache.forget_portal_profile(portal_profile) if portal_profile
|
289
|
+
|
290
|
+
self.files_to_commit << stored_profile_path
|
291
|
+
|
292
|
+
is_new_profile_created = true
|
262
293
|
end
|
263
|
-
|
294
|
+
|
295
|
+
parsed = FastlaneCore::ProvisioningProfile.parse(stored_profile_path, keychain_path)
|
264
296
|
uuid = parsed["UUID"]
|
297
|
+
name = parsed["Name"]
|
265
298
|
|
266
|
-
|
267
|
-
|
268
|
-
|
299
|
+
check_profile_existence = !is_new_profile_created && spaceship
|
300
|
+
if check_profile_existence && !spaceship.profile_exists(profile_type: profile_type,
|
301
|
+
name: name,
|
302
|
+
username: params[:username],
|
303
|
+
uuid: uuid,
|
304
|
+
cached_profiles: self.cache.profiles)
|
269
305
|
|
270
|
-
if spaceship && !spaceship.profile_exists(type: prov_type,
|
271
|
-
username: params[:username],
|
272
|
-
uuid: uuid,
|
273
|
-
platform: params[:platform])
|
274
306
|
# This profile is invalid, let's remove the local file and generate a new one
|
275
|
-
File.delete(
|
307
|
+
File.delete(stored_profile_path)
|
276
308
|
# This method will be called again, no need to modify `files_to_commit`
|
277
309
|
return nil
|
278
310
|
end
|
279
311
|
|
312
|
+
if Helper.mac?
|
313
|
+
installed_profile = FastlaneCore::ProvisioningProfile.install(stored_profile_path, keychain_path)
|
314
|
+
end
|
315
|
+
|
316
|
+
if params[:output_path]
|
317
|
+
FileUtils.cp(stored_profile_path, params[:output_path])
|
318
|
+
end
|
319
|
+
|
280
320
|
Utils.fill_environment(Utils.environment_variable_name(app_identifier: app_identifier,
|
281
321
|
type: prov_type,
|
282
322
|
platform: params[:platform]),
|
@@ -308,145 +348,6 @@ module Match
|
|
308
348
|
return uuid
|
309
349
|
end
|
310
350
|
# rubocop:enable Metrics/PerceivedComplexity
|
311
|
-
|
312
|
-
def should_force_include_all_devices(params: nil, prov_type: nil, profile: nil, keychain_path: nil)
|
313
|
-
return false unless params[:force_for_new_devices] && !params[:readonly]
|
314
|
-
|
315
|
-
force = false
|
316
|
-
|
317
|
-
prov_types_without_devices = [:appstore, :developer_id]
|
318
|
-
if !prov_types_without_devices.include?(prov_type) && !params[:force]
|
319
|
-
force = device_count_different?(profile: profile, keychain_path: keychain_path, platform: params[:platform].to_sym, include_mac_in_profiles: params[:include_mac_in_profiles])
|
320
|
-
else
|
321
|
-
# App Store provisioning profiles don't contain device identifiers and
|
322
|
-
# thus shouldn't be renewed if the device count has changed.
|
323
|
-
UI.important("Warning: `force_for_new_devices` is set but is ignored for App Store & Developer ID provisioning profiles.")
|
324
|
-
UI.important("You can safely stop specifying `force_for_new_devices` when running Match for type 'appstore' or 'developer_id'.")
|
325
|
-
end
|
326
|
-
|
327
|
-
return force
|
328
|
-
end
|
329
|
-
|
330
|
-
def device_count_different?(profile: nil, keychain_path: nil, platform: nil, include_mac_in_profiles: false)
|
331
|
-
return false unless profile
|
332
|
-
|
333
|
-
parsed = FastlaneCore::ProvisioningProfile.parse(profile, keychain_path)
|
334
|
-
uuid = parsed["UUID"]
|
335
|
-
|
336
|
-
all_profiles = Spaceship::ConnectAPI::Profile.all(includes: "devices")
|
337
|
-
portal_profile = all_profiles.detect { |i| i.uuid == uuid }
|
338
|
-
|
339
|
-
if portal_profile
|
340
|
-
profile_device_count = portal_profile.devices.count
|
341
|
-
|
342
|
-
device_classes =
|
343
|
-
case platform
|
344
|
-
when :ios
|
345
|
-
[
|
346
|
-
Spaceship::ConnectAPI::Device::DeviceClass::IPAD,
|
347
|
-
Spaceship::ConnectAPI::Device::DeviceClass::IPHONE,
|
348
|
-
Spaceship::ConnectAPI::Device::DeviceClass::IPOD,
|
349
|
-
Spaceship::ConnectAPI::Device::DeviceClass::APPLE_WATCH
|
350
|
-
]
|
351
|
-
when :tvos
|
352
|
-
[
|
353
|
-
Spaceship::ConnectAPI::Device::DeviceClass::APPLE_TV
|
354
|
-
]
|
355
|
-
when :macos, :catalyst
|
356
|
-
[
|
357
|
-
Spaceship::ConnectAPI::Device::DeviceClass::MAC
|
358
|
-
]
|
359
|
-
else
|
360
|
-
[]
|
361
|
-
end
|
362
|
-
if platform == :ios && include_mac_in_profiles
|
363
|
-
device_classes += [Spaceship::ConnectAPI::Device::DeviceClass::APPLE_SILICON_MAC]
|
364
|
-
end
|
365
|
-
|
366
|
-
devices = Spaceship::ConnectAPI::Device.all
|
367
|
-
unless device_classes.empty?
|
368
|
-
devices = devices.select do |device|
|
369
|
-
device_classes.include?(device.device_class) && device.enabled?
|
370
|
-
end
|
371
|
-
end
|
372
|
-
|
373
|
-
portal_device_count = devices.size
|
374
|
-
|
375
|
-
return portal_device_count != profile_device_count
|
376
|
-
end
|
377
|
-
return false
|
378
|
-
end
|
379
|
-
|
380
|
-
def should_force_include_all_certificates(params: nil, prov_type: nil, profile: nil, keychain_path: nil)
|
381
|
-
unless params[:include_all_certificates]
|
382
|
-
if params[:force_for_new_certificates]
|
383
|
-
UI.important("You specified 'force_for_new_certificates: true', but new certificates will not be added, cause 'include_all_certificates' is 'false'")
|
384
|
-
end
|
385
|
-
return false
|
386
|
-
end
|
387
|
-
|
388
|
-
force = false
|
389
|
-
|
390
|
-
if params[:force_for_new_certificates] && !params[:readonly]
|
391
|
-
if prov_type == :development && !params[:force]
|
392
|
-
force = certificate_count_different?(profile: profile, keychain_path: keychain_path, platform: params[:platform].to_sym)
|
393
|
-
else
|
394
|
-
# All other (not development) provisioning profiles don't contain
|
395
|
-
# multiple certificates, thus shouldn't be renewed
|
396
|
-
# if the certificates count has changed.
|
397
|
-
UI.important("Warning: `force_for_new_certificates` is set but is ignored for non-'development' provisioning profiles.")
|
398
|
-
UI.important("You can safely stop specifying `force_for_new_certificates` when running Match for '#{prov_type}' provisioning profiles.")
|
399
|
-
end
|
400
|
-
end
|
401
|
-
|
402
|
-
return force
|
403
|
-
end
|
404
|
-
|
405
|
-
def certificate_count_different?(profile: nil, keychain_path: nil, platform: nil)
|
406
|
-
return false unless profile
|
407
|
-
|
408
|
-
parsed = FastlaneCore::ProvisioningProfile.parse(profile, keychain_path)
|
409
|
-
uuid = parsed["UUID"]
|
410
|
-
|
411
|
-
all_profiles = Spaceship::ConnectAPI::Profile.all(includes: "certificates")
|
412
|
-
portal_profile = all_profiles.detect { |i| i.uuid == uuid }
|
413
|
-
|
414
|
-
return false unless portal_profile
|
415
|
-
|
416
|
-
# When a certificate expires (not revoked) provisioning profile stays valid.
|
417
|
-
# And if we regenerate certificate count will not differ:
|
418
|
-
# * For portal certificates, we filter out the expired one but includes a new certificate;
|
419
|
-
# * Profile still contains an expired certificate and is valid.
|
420
|
-
# Thus, we need to check the validity of profile certificates too.
|
421
|
-
profile_certs_count = portal_profile.certificates.select(&:valid?).count
|
422
|
-
|
423
|
-
certificate_types =
|
424
|
-
case platform
|
425
|
-
when :ios, :tvos
|
426
|
-
[
|
427
|
-
Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPMENT,
|
428
|
-
Spaceship::ConnectAPI::Certificate::CertificateType::IOS_DEVELOPMENT
|
429
|
-
]
|
430
|
-
when :macos, :catalyst
|
431
|
-
[
|
432
|
-
Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPMENT,
|
433
|
-
Spaceship::ConnectAPI::Certificate::CertificateType::MAC_APP_DEVELOPMENT
|
434
|
-
]
|
435
|
-
else
|
436
|
-
[]
|
437
|
-
end
|
438
|
-
|
439
|
-
certificates = Spaceship::ConnectAPI::Certificate.all
|
440
|
-
unless certificate_types.empty?
|
441
|
-
certificates = certificates.select do |certificate|
|
442
|
-
certificate_types.include?(certificate.certificateType) && certificate.valid?
|
443
|
-
end
|
444
|
-
end
|
445
|
-
|
446
|
-
portal_certs_count = certificates.size
|
447
|
-
|
448
|
-
return portal_certs_count != profile_certs_count
|
449
|
-
end
|
450
351
|
end
|
451
352
|
# rubocop:enable Metrics/ClassLength
|
452
353
|
end
|