fastlane-plugin-match_import 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,295 @@
1
+ require 'fastlane_core/print_table'
2
+ require 'spaceship'
3
+
4
+ module Fastlane
5
+ module MatchImport
6
+ class RunnerAPNS
7
+ attr_accessor :files_to_commit
8
+ attr_accessor :storage
9
+
10
+ def run(params)
11
+ self.files_to_commit = []
12
+
13
+ FastlaneCore::PrintTable.print_values(config: params,
14
+ hide_keys: [],
15
+ title: "Summary for match_import #{Fastlane::MatchImport::VERSION}")
16
+
17
+ MatchImport::Utils.update_optional_values_depending_on_storage_type(params)
18
+
19
+ # Verify correct type
20
+ cert_type = params[:type]
21
+
22
+ UI.user_error!("Cert type '#{cert_type}' is not supported. Use 'development' for development push or 'appstore', 'adhoc', 'enterprise' for production push") unless ['development', 'appstore', 'adhoc', 'enterprise'].include?(cert_type)
23
+
24
+ # Get and verify apns cert path
25
+ cert_path = MatchImport::Utils.ensure_valid_file_path(params[:cert_file_name], params[:source_path], "Certificate to import", one_file_only: true)
26
+ p12_path = MatchImport::Utils.ensure_valid_file_path(params[:p12_file_name], params[:source_path], "Private key to import", one_file_only: true)
27
+
28
+ # Check validity of certificate
29
+ if Utils.is_cert_valid?(cert_path)
30
+ UI.verbose("Your certificate '#{File.basename(cert_path)}' is valid")
31
+ else
32
+ UI.user_error!("Your certificate '#{File.basename(cert_path)}' is not valid, please check end date and renew it if necessary")
33
+ end
34
+
35
+ Spaceship::Portal.login(params[:username])
36
+ Spaceship::Portal.select_team(team_id: params[:team_id], team_name: params[:team_name])
37
+
38
+ certs = []
39
+ cert_type_s = ""
40
+ case cert_type
41
+ when "development"
42
+ cert_type_s = "development"
43
+ certs = Spaceship::Portal.certificate.development_push.all
44
+ when "appstore", "adhoc", "enterprise"
45
+ cert_type_s = "production"
46
+ certs = Spaceship::Portal.certificate.production_push.all
47
+ else
48
+ UI.user_error!("Cert type '#{cert_type}' is not supported")
49
+ end
50
+
51
+ # Base64 encode contents to find match from API to find a cert ID
52
+ cert_contents_base_64 = Base64.strict_encode64(File.binread(cert_path))
53
+ matching_cert = certs.find do |cert|
54
+ content_cert = Base64.strict_encode64(cert.download_raw)
55
+ is_same_cert = content_cert == cert_contents_base_64
56
+
57
+ cert_type = Spaceship::Portal::Certificate::CERTIFICATE_TYPE_IDS[cert.type_display_id].to_s.split("::")[-1]
58
+ if is_same_cert
59
+ UI.success("(Cert id: #{cert.id}, name: #{cert.name}, expires: #{cert.expires.strftime('%Y-%m-%d')}, type: #{cert_type}) - match") if FastlaneCore::Globals.verbose?
60
+ else
61
+ UI.verbose("(Cert id: #{cert.id}, name: #{cert.name}, expires: #{cert.expires.strftime('%Y-%m-%d')}, type: #{cert_type}) - don't match") if FastlaneCore::Globals.verbose?
62
+ end
63
+
64
+ is_same_cert
65
+ end
66
+
67
+ UI.user_error!("This certificate cannot be imported - the certificate contents did not match with any available on the Developer Portal") if matching_cert.nil?
68
+
69
+ # Choose the right storage and encryption implementations
70
+ storage = MatchImport::Utils.storage(params, false)
71
+
72
+ # Init the encryption only after the `storage.download` was called to have the right working directory
73
+ encryption = MatchImport::Utils.encryption(params, storage)
74
+
75
+ storage_workspace = storage.prefixed_working_directory
76
+
77
+ # Hack to avoid conflicts with "fastlane match" encryption.
78
+ # It uses pattern: [File.join(source_path, "**", "*.{cer,p12,mobileprovision,provisionprofile}")]
79
+ # To avoid conflicts we use three level deep folder.
80
+ output_dir = File.join(storage_workspace, "customImport/customImport/customImport", "apns")
81
+ output_dir = File.join(output_dir, cert_type_s)
82
+
83
+ # Make dir if doesn't exist
84
+ FileUtils.mkdir_p(output_dir)
85
+ # dest_path = File.join(output_dir, params[:file_name])
86
+ dest_path = output_dir
87
+
88
+ dest_cert_path = File.join(dest_path, "#{matching_cert.id}.cer")
89
+ dest_p12_path = File.join(dest_path, "#{matching_cert.id}.p12")
90
+
91
+ self.files_to_commit = [dest_cert_path, dest_p12_path]
92
+
93
+ # Copy file
94
+ IO.copy_stream(cert_path, dest_cert_path)
95
+ IO.copy_stream(p12_path, dest_p12_path)
96
+ UI.success("Finish copying '#{cert_path}' and '#{p12_path}'") if FastlaneCore::Globals.verbose?
97
+
98
+ encryption.encrypt_files if encryption
99
+ storage.save_changes!(files_to_commit: self.files_to_commit)
100
+ end
101
+
102
+ def run_export(params)
103
+ FastlaneCore::PrintTable.print_values(config: params,
104
+ hide_keys: [],
105
+ title: "Summary for match_import #{Fastlane::MatchImport::VERSION}")
106
+
107
+ MatchImport::Utils.update_optional_values_depending_on_storage_type(params)
108
+
109
+ # Verify correct type
110
+ cert_type = params[:type]
111
+
112
+ UI.user_error!("Cert type '#{cert_type}' is not supported. Use 'development' for development push or 'appstore', 'adhoc', 'enterprise' for production push") unless ['development', 'appstore', 'adhoc', 'enterprise'].include?(cert_type)
113
+
114
+ cert_type_s = ""
115
+ case cert_type
116
+ when "development"
117
+ cert_type_s = "development"
118
+ when "appstore", "adhoc", "enterprise"
119
+ cert_type_s = "production"
120
+ else
121
+ UI.user_error!("Cert type '#{cert_type}' is not supported")
122
+ end
123
+
124
+ # Choose the right storage and encryption implementations
125
+ storage = MatchImport::Utils.storage(params, true)
126
+
127
+ # Init the encryption only after the `storage.download` was called to have the right working directory
128
+ MatchImport::Utils.encryption(params, storage)
129
+
130
+ storage_workspace = storage.prefixed_working_directory
131
+
132
+ # Hack to avoid conflicts with "fastlane match" encryption.
133
+ # It uses pattern: [File.join(source_path, "**", "*.{cer,p12,mobileprovision,provisionprofile}")]
134
+ # To avoid conflicts we use three level deep folder.
135
+ source_path = File.join(storage_workspace, "customImport/customImport/customImport", "apns")
136
+ source_path = File.join(source_path, cert_type_s)
137
+
138
+ output_dir = params[:destination_path]
139
+
140
+ # Make dir if doesn't exist
141
+ FileUtils.mkdir_p(output_dir) if output_dir
142
+ # dest_path = File.join(output_dir, params[:file_name])
143
+ dest_path = output_dir
144
+
145
+ if Dir.exist?(source_path) && !Dir.empty?(source_path)
146
+ file_path = File.join(source_path, '*.cer')
147
+ Dir[file_path].each do |file|
148
+ p12_file = File.basename(file, ".cer") + ".p12"
149
+ p12_file = File.join(source_path, p12_file)
150
+
151
+ # Check validity of certificate
152
+ if Utils.is_cert_valid?(file)
153
+ UI.verbose("Your certificate '#{File.basename(file)}' is valid")
154
+ else
155
+ UI.user_error!("Your certificate '#{File.basename(file)}' is not valid, please check end date and renew it if necessary")
156
+ end
157
+
158
+ if Helper.mac?
159
+ UI.message("Installing certificate...")
160
+
161
+ # Only looking for cert in "custom" (non login.keychain) keychain
162
+ # Doing this for backwards compatibility
163
+ keychain_name = params[:keychain_name] == "login.keychain" ? nil : params[:keychain_name]
164
+
165
+ if FastlaneCore::CertChecker.installed?(file, in_keychain: keychain_name)
166
+ UI.verbose("Certificate '#{File.basename(cert_path)}' is already installed on this machine")
167
+ else
168
+ Utils.import(file, params[:keychain_name], password: params[:keychain_password])
169
+ end
170
+
171
+ # Import the private key
172
+ # there seems to be no good way to check if it's already installed - so just install it
173
+ # Key will only be added to the partition list if it isn't already installed
174
+ Utils.import(p12_file, params[:keychain_name], password: params[:keychain_password])
175
+ else
176
+ UI.message("Skipping installation of certificate as it would not work on this operating system.")
177
+ end
178
+
179
+ next unless dest_path
180
+
181
+ FileUtils.cp(file, dest_path)
182
+ UI.success("Finish copying '#{file}' to '#{dest_path}'") if FastlaneCore::Globals.verbose?
183
+
184
+ FileUtils.cp(p12_file, dest_path)
185
+ UI.success("Finish copying '#{p12_file}' to '#{dest_path}'") if FastlaneCore::Globals.verbose?
186
+ end
187
+ else
188
+ UI.important("#{source_path} is empty. Nothing to export")
189
+ end
190
+ end
191
+
192
+ def run_remove_invalid(params)
193
+ self.files_to_commit = []
194
+
195
+ FastlaneCore::PrintTable.print_values(config: params,
196
+ hide_keys: [],
197
+ title: "Summary for match_import #{Fastlane::MatchImport::VERSION}")
198
+
199
+ MatchImport::Utils.update_optional_values_depending_on_storage_type(params)
200
+
201
+ # Verify correct type
202
+ cert_type = params[:type]
203
+
204
+ UI.user_error!("Cert type '#{cert_type}' is not supported. Use 'development' for development push or 'appstore', 'adhoc', 'enterprise' for production push") unless ['development', 'appstore', 'adhoc', 'enterprise'].include?(cert_type)
205
+
206
+ Spaceship::Portal.login(params[:username])
207
+ Spaceship::Portal.select_team(team_id: params[:team_id], team_name: params[:team_name])
208
+
209
+ certs = []
210
+ cert_type_s = ""
211
+ case cert_type
212
+ when "development"
213
+ cert_type_s = "development"
214
+ certs = Spaceship::Portal.certificate.development_push.all
215
+ when "appstore", "adhoc", "enterprise"
216
+ cert_type_s = "production"
217
+ certs = Spaceship::Portal.certificate.production_push.all
218
+ else
219
+ UI.user_error!("Cert type '#{cert_type}' is not supported")
220
+ end
221
+
222
+ # Choose the right storage and encryption implementations
223
+ storage = MatchImport::Utils.storage(params, true)
224
+
225
+ # Init the encryption only after the `storage.download` was called to have the right working directory
226
+ MatchImport::Utils.encryption(params, storage)
227
+
228
+ storage_workspace = storage.prefixed_working_directory
229
+
230
+ # Hack to avoid conflicts with "fastlane match" encryption.
231
+ # It uses pattern: [File.join(source_path, "**", "*.{cer,p12,mobileprovision,provisionprofile}")]
232
+ # To avoid conflicts we use three level deep folder.
233
+ source_path = File.join(storage_workspace, "customImport/customImport/customImport", "apns")
234
+ source_path = File.join(source_path, cert_type_s)
235
+
236
+ if Dir.exist?(source_path) && !Dir.empty?(source_path)
237
+ file_path = File.join(source_path, '*.cer')
238
+ Dir[file_path].each do |file|
239
+ p12_file = File.basename(file, ".cer") + ".p12"
240
+ p12_file = File.join(source_path, p12_file)
241
+
242
+ # Check validity of certificate
243
+ is_valid = Utils.is_cert_valid?(file)
244
+ if is_valid
245
+ UI.verbose("Your certificate '#{File.basename(file)}' is not expired.")
246
+ else
247
+ UI.verbose("Your certificate '#{File.basename(file)}' is not valid, please check end date. Will remove it together with '#{File.basename(p12_file)}'")
248
+ files_to_commit << file
249
+ files_to_commit << p12_file
250
+ end
251
+
252
+ next unless is_valid
253
+
254
+ UI.verbose("Checking if '#{File.basename(file)}' is present on Developer Portal")
255
+
256
+ # Base64 encode contents to find match from API to find a cert ID
257
+ cert_contents_base_64 = Base64.strict_encode64(File.binread(file))
258
+ matching_cert = certs.find do |cert|
259
+ content_cert = Base64.strict_encode64(cert.download_raw)
260
+ is_same_cert = content_cert == cert_contents_base_64
261
+
262
+ cert_type = Spaceship::Portal::Certificate::CERTIFICATE_TYPE_IDS[cert.type_display_id].to_s.split("::")[-1]
263
+ if is_same_cert
264
+ UI.success("(Cert id: #{cert.id}, name: #{cert.name}, expires: #{cert.expires.strftime('%Y-%m-%d')}, type: #{cert_type}) - match") if FastlaneCore::Globals.verbose?
265
+ else
266
+ UI.verbose("(Cert id: #{cert.id}, name: #{cert.name}, expires: #{cert.expires.strftime('%Y-%m-%d')}, type: #{cert_type}) - don't match") if FastlaneCore::Globals.verbose?
267
+ end
268
+
269
+ is_same_cert
270
+ end
271
+
272
+ if matching_cert.nil?
273
+ UI.verbose("This certificate '#{File.basename(file)}' will be removed together with '#{File.basename(p12_file)}' - the certificate contents did not match with any available on the Developer Portal")
274
+ files_to_commit << file
275
+ files_to_commit << p12_file
276
+ else
277
+ UI.verbose("Your certificate '#{File.basename(file)}' is valid. Skip it")
278
+ end
279
+ end
280
+ else
281
+ UI.important("#{source_path} is empty. Nothing to check")
282
+ end
283
+
284
+ if self.files_to_commit.count > 0
285
+ self.files_to_commit.each do |file|
286
+ FileUtils.rm(file)
287
+ UI.success("Finish removing '#{file}'") if FastlaneCore::Globals.verbose?
288
+ end
289
+
290
+ storage.save_changes!(files_to_commit: self.files_to_commit)
291
+ end
292
+ end
293
+ end
294
+ end
295
+ end
@@ -0,0 +1,81 @@
1
+ require 'match'
2
+
3
+ module Fastlane
4
+ module MatchImport
5
+ class Utils
6
+ # Be smart about optional values here
7
+ # Depending on the storage mode, different values are required
8
+ def self.update_optional_values_depending_on_storage_type(params)
9
+ if params[:storage_mode] != "git"
10
+ params.option_for_key(:git_url).optional = true
11
+ end
12
+ end
13
+
14
+ def self.ensure_valid_file_path(file_path, source_path, file_description, one_file_only: false)
15
+ file_path = File.join(source_path, file_path) if source_path
16
+ file_path = File.absolute_path(file_path) unless file_path == ""
17
+ path_to_file = file_path
18
+ if one_file_only
19
+ file_path = File.exist?(file_path) ? file_path : nil
20
+ else
21
+ file_path = nil if Dir.glob(file_path).empty?
22
+ end
23
+
24
+ UI.user_error!("#{file_description} does not exist at path: #{path_to_file}") if file_path.nil?
25
+ file_path
26
+ end
27
+
28
+ def self.ensure_valid_one_level_path(destination_path)
29
+ destination_path_components = []
30
+ destination_path_components = destination_path.split("/") if destination_path
31
+ UI.user_error!("#{destination_path} should be one level dir(Correct encrypt/decript requires one level). It has more levels: #{destination_path_components}.") if destination_path_components.count > 1
32
+ destination_path
33
+ end
34
+
35
+ def self.storage(params, readonly)
36
+ storage = Match::Storage.for_mode(params[:storage_mode], {
37
+ git_url: params[:git_url],
38
+ shallow_clone: params[:shallow_clone],
39
+ skip_docs: params[:skip_docs],
40
+ git_branch: params[:git_branch],
41
+ git_full_name: params[:git_full_name],
42
+ git_user_email: params[:git_user_email],
43
+ clone_branch_directly: params[:clone_branch_directly],
44
+ type: params[:type].to_s,
45
+ platform: params[:platform].to_s,
46
+ google_cloud_bucket_name: params[:google_cloud_bucket_name].to_s,
47
+ google_cloud_keys_file: params[:google_cloud_keys_file].to_s,
48
+ google_cloud_project_id: params[:google_cloud_project_id].to_s,
49
+ readonly: readonly,
50
+ username: readonly ? nil : params[:username],
51
+ team_id: params[:team_id],
52
+ team_name: params[:team_name]
53
+ })
54
+ storage.download
55
+
56
+ storage
57
+ end
58
+
59
+ def self.encryption(params, storage)
60
+ encryption = Match::Encryption.for_storage_mode(params[:storage_mode], {
61
+ git_url: params[:git_url],
62
+ working_directory: storage.working_directory
63
+ })
64
+ encryption.decrypt_files if encryption
65
+
66
+ encryption
67
+ end
68
+
69
+ def self.import(item_path, keychain, password: "")
70
+ keychain_path = FastlaneCore::Helper.keychain_path(keychain)
71
+ FastlaneCore::KeychainImporter.import_file(item_path, keychain_path, keychain_password: password, output: FastlaneCore::Globals.verbose?)
72
+ end
73
+
74
+ def self.is_cert_valid?(cer_certificate_path)
75
+ cert = OpenSSL::X509::Certificate.new(File.binread(cer_certificate_path))
76
+ now = Time.now.utc
77
+ return (now <=> cert.not_after) == -1
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,6 @@
1
+ module Fastlane
2
+ module MatchImport
3
+ VERSION = "0.1.2"
4
+ DESCRIPTION = "match_import command import/export files to/from match encrypted repo. Also remove files is supported"
5
+ end
6
+ end
@@ -0,0 +1,26 @@
1
+ module Fastlane
2
+ module MatchImport
3
+ # Return all .rb files inside the "actions" and "helper" directory
4
+ def self.all_classes
5
+ Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
6
+ end
7
+ end
8
+ end
9
+
10
+ require 'fastlane/plugin/match_import/version'
11
+ require 'fastlane/plugin/match_import/options'
12
+ require 'fastlane/plugin/match_import/runner'
13
+ require 'fastlane/plugin/match_import/runner_apns'
14
+ require 'fastlane/plugin/match_import/utils'
15
+ require 'fastlane/plugin/match_import/custom_file_options'
16
+ require 'fastlane/plugin/match_import/apns_file_options'
17
+ require 'fastlane/plugin/match_import/apns_export_file_options'
18
+ require 'fastlane/plugin/match_import/apns_remove_invalid_file_options'
19
+ require 'fastlane/plugin/match_import/encryption/openssl'
20
+ require 'fastlane/plugin/match_import/commands_generator'
21
+
22
+ # By default we want to import all available actions and helpers
23
+ # A plugin can contain any number of actions and plugins
24
+ Fastlane::MatchImport.all_classes.each do |current|
25
+ require current
26
+ end
metadata ADDED
@@ -0,0 +1,189 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fastlane-plugin-match_import
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Serhii Batsevych
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-04-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pry
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec_junit_formatter
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: 0.49.1
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '='
95
+ - !ruby/object:Gem::Version
96
+ version: 0.49.1
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-require_tools
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: fastlane
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: 2.144.0
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: 2.144.0
139
+ description:
140
+ email: serbats@ukr.net
141
+ executables: []
142
+ extensions: []
143
+ extra_rdoc_files: []
144
+ files:
145
+ - LICENSE
146
+ - README.md
147
+ - lib/fastlane/plugin/match_import.rb
148
+ - lib/fastlane/plugin/match_import/actions/match_export_action.rb
149
+ - lib/fastlane/plugin/match_import/actions/match_export_apns_action.rb
150
+ - lib/fastlane/plugin/match_import/actions/match_import_action.rb
151
+ - lib/fastlane/plugin/match_import/actions/match_import_apns_action.rb
152
+ - lib/fastlane/plugin/match_import/actions/match_remove_action.rb
153
+ - lib/fastlane/plugin/match_import/actions/match_remove_invalid_apns_action.rb
154
+ - lib/fastlane/plugin/match_import/apns_export_file_options.rb
155
+ - lib/fastlane/plugin/match_import/apns_file_options.rb
156
+ - lib/fastlane/plugin/match_import/apns_remove_invalid_file_options.rb
157
+ - lib/fastlane/plugin/match_import/commands_generator.rb
158
+ - lib/fastlane/plugin/match_import/custom_file_options.rb
159
+ - lib/fastlane/plugin/match_import/encryption/openssl.rb
160
+ - lib/fastlane/plugin/match_import/helper/match_import_helper.rb
161
+ - lib/fastlane/plugin/match_import/options.rb
162
+ - lib/fastlane/plugin/match_import/runner.rb
163
+ - lib/fastlane/plugin/match_import/runner_apns.rb
164
+ - lib/fastlane/plugin/match_import/utils.rb
165
+ - lib/fastlane/plugin/match_import/version.rb
166
+ homepage: https://github.com/serbats/fastlane-plugin-match_import
167
+ licenses:
168
+ - MIT
169
+ metadata: {}
170
+ post_install_message:
171
+ rdoc_options: []
172
+ require_paths:
173
+ - lib
174
+ required_ruby_version: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ required_rubygems_version: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - ">="
182
+ - !ruby/object:Gem::Version
183
+ version: '0'
184
+ requirements: []
185
+ rubygems_version: 3.0.3
186
+ signing_key:
187
+ specification_version: 4
188
+ summary: Match repository custom import
189
+ test_files: []