-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFastfile
More file actions
359 lines (314 loc) · 10.4 KB
/
Copy pathFastfile
File metadata and controls
359 lines (314 loc) · 10.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
# https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
# https://docs.fastlane.tools/plugins/available-plugins
#
# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane
default_platform(:ios)
platform :ios do
#
# CD Lanes
#
desc "Push a new beta build to TestFlight"
lane :publish_app do |options|
# setup release notes
release_notes = options[:release_notes]
contact_email = options[:contact_email]
contact_first_name = options[:contact_first_name]
contact_last_name = options[:contact_last_name]
contact_phone = options[:contact_phone]
demo_account_name = options[:demo_account_name]
demo_account_password = options[:demo_account_password]
# push to testflight
upload_to_testflight(
api_key_path: "./api_key.json",
beta_app_review_info: {
contact_email: contact_email,
contact_first_name: contact_first_name,
contact_last_name: contact_last_name,
contact_phone: contact_phone,
demo_account_name: demo_account_name,
demo_account_password: demo_account_password,
},
changelog: release_notes
)
end
desc "Push a build to TestFlight"
lane :publish_ipa do |options|
# setup release notes
ipa_path = options[:ipa_path]
api_key_path = options[:api_key_path]
release_notes = options[:release_notes]
contact_email = options[:contact_email]
contact_first_name = options[:contact_first_name]
contact_last_name = options[:contact_last_name]
contact_phone = options[:contact_phone]
demo_account_name = options[:demo_account_name]
demo_account_password = options[:demo_account_password]
# push to testflight
upload_to_testflight(
ipa: ipa_path,
api_key_path: api_key_path,
beta_app_review_info: {
contact_email: contact_email,
contact_first_name: contact_first_name,
contact_last_name: contact_last_name,
contact_phone: contact_phone,
demo_account_name: demo_account_name,
demo_account_password: demo_account_password,
},
changelog: release_notes
)
end
desc "Build App for TestFlight - Project"
lane :build_release_project do |options|
# Load inputs
project = options[:project]
scheme = options[:scheme]
keychain_password = options[:keychain_password]
keychain_path = options[:keychain_path]
app_id = options[:app_id]
provisioning_profile = options[:provisioning_profile]
# Unlock keychain
unlock_keychain(
path: keychain_path,
password: keychain_password
)
# Build app with provisioning profile mapping
build_app(
project: project,
scheme: scheme,
export_method: "app-store",
export_options: {
provisioningProfiles: {
app_id => provisioning_profile
}
}
)
end
desc "Build App for TestFlight - Workspace"
lane :build_release_workspace do |options|
# Load inputs
workspace = options[:workspace] # Optional
scheme = options[:scheme]
keychain_password = options[:keychain_password]
keychain_path = options[:keychain_path]
app_id = options[:app_id]
provisioning_profile = options[:provisioning_profile]
# Unlock keychain
unlock_keychain(
path: keychain_path,
password: keychain_password
)
# Build app with provisioning profile mapping
build_app(
workspace: workspace,
scheme: scheme,
export_method: "app-store",
export_options: {
provisioningProfiles: {
app_id => provisioning_profile
}
}
)
end
lane :build_release_workspace_multiple_targets do |options|
# Load inputs
workspace = options[:workspace]
scheme = options[:scheme]
keychain_password = options[:keychain_password]
keychain_path = options[:keychain_path]
app_id = options[:app_id]
provisioning_profile = options[:provisioning_profile]
extension_app_id = options[:extension_app_id]
extension_provisioning_profile = options[:extension_provisioning_profile]
# Unlock keychain
unlock_keychain(
path: keychain_path,
password: keychain_password
)
# Build app with provisioning profile mapping
build_app(
workspace: workspace,
scheme: scheme,
export_method: "app-store",
skip_profile_detection: true,
export_options: {
provisioningProfiles: {
app_id => provisioning_profile,
extension_app_id => extension_provisioning_profile
}
}
)
end
lane :build_release_multiple_targets do |options|
# Load inputs
scheme = options[:scheme]
keychain_password = options[:keychain_password]
keychain_path = options[:keychain_path]
app_id = options[:app_id]
provisioning_profile = options[:provisioning_profile]
extension_app_id = options[:extension_app_id]
extension_provisioning_profile = options[:extension_provisioning_profile]
# Unlock keychain
unlock_keychain(
path: keychain_path,
password: keychain_password
)
# Build app with provisioning profile mapping
build_app(
scheme: scheme,
export_method: "app-store",
export_options: {
provisioningProfiles: {
app_id => provisioning_profile,
extension_app_id => extension_provisioning_profile
}
}
)
end
desc "Loads provisioning profile"
lane :prepare_signing do |options|
# load keychain pwd
git_url = options[:git_url]
app_id = options[:app_id]
# match requires EnvVar MATCH_PASSWORD
match(app_identifier: [app_id], git_url: git_url)
end
desc "Loads provisioning profiles using PAT"
lane :prepare_signing_pat do |options|
# load keychain pwd
git_url = options[:git_url]
app_id = options[:app_id]
git_basic_authorization = options[:git_basic_authorization]
# match requires EnvVar MATCH_PASSWORD
match(app_identifier: [app_id], git_url: git_url, git_basic_authorization: git_basic_authorization)
end
desc "Sets the build_number to certain value"
lane :set_build_number do |options|
build_number = options[:build_number]
project = options[:project]
#set build number
increment_build_number(xcodeproj: project, build_number: build_number)
end
desc "Sets the API KEY for Appstore Connect"
lane :set_api_key do |options|
api_key_value = options[:api_key_value]
api_key_path = "./api_key.json"
# Write the ENV variable content to the file
File.open(api_key_path, "w") do |file|
file.write(api_key_value)
end
end
#
# CI Lanes
#
desc "Run Tests"
lane :test_app do |options|
workspace = options[:workspace]
project = options[:project]
scheme = options[:scheme]
testplan = options[:testplan]
# run tests
run_tests(
workspace: workspace,
project: project,
scheme: scheme,
testplan: testplan,
clean: true,
code_coverage: true,
configuration: "Debug"
)
end
desc "Run swiftlint"
lane :code_quality do
swiftlint(
mode: :lint,
ignore_exit_status: false,
quiet: true,
strict: false
)
end
desc "Run sonar"
lane :run_sonar do |options|
# load variables
project_key = options[:project_key]
sonar_token = options[:sonar_token]
sonar_url = options[:sonar_url]
# run sonar
sonar(
project_key: project_key,
sonar_token: sonar_token,
sonar_url: sonar_url
)
end
desc "Generate codecoverage"
lane :code_coverage do |options|
project = options[:project]
scheme = options[:scheme]
coverage = options[:coverage]
# run coverage report
xcov(
project: project,
scheme: scheme,
output_directory: "./Reports/Coverage",
json_report: true,
minimum_coverage_percentage: coverage
)
end
desc "Resign an existing IPA with a new profile and version"
lane :resign_ipa do |options|
ipa_path = options[:ipa_path]
profile_path = options[:profile_path]
signing_identity = options[:signing_identity]
new_version = options[:new_version]
UI.user_error!("ipa_path is required") unless ipa_path
UI.user_error!("profile_path is required") unless profile_path
UI.user_error!("signing_identity is required") unless signing_identity
UI.user_error!("new_version is required") unless new_version
UI.user_error!("ipa_path does not exist: #{ipa_path}") unless File.exist?(ipa_path)
UI.user_error!("profile_path does not exist: #{profile_path}") unless File.exist?(profile_path)
UI.message("Resigning IPA: #{ipa_path}")
UI.message("Using provisioning profile: #{profile_path}")
UI.message("Signing identity: #{signing_identity}")
UI.message("New version: #{new_version}")
# Ensure the signing identity exists before attempting to resign
verify_signing_identity(signing_identity: signing_identity)
resign(
ipa: ipa_path,
signing_identity: signing_identity,
provisioning_profile: profile_path,
version: new_version
)
UI.success("✅ Successfully resigned IPA at: #{ipa_path}")
end
desc "List available code signing identities in the keychain"
lane :list_signing_identities do
UI.message("Listing available code signing identities (Keychain):")
output = sh("security find-identity -v -p codesigning || true")
if output.to_s.strip.empty?
UI.important("No code signing identities found. Make sure your certificates are installed in the login keychain.")
else
UI.message(output)
end
end
desc "Verify that a given signing identity exists"
lane :verify_signing_identity do |options|
identity = options[:signing_identity]
UI.user_error!("signing_identity is required") unless identity
output = sh("security find-identity -v -p codesigning || true")
lines = output.to_s.split("\n")
found = lines.any? { |l| l.include?(identity) }
unless found
UI.user_error!("Signing identity not found: #{identity}\nRun 'fastlane ios list_signing_identities' to see available identities.")
end
UI.success("✅ Found signing identity: #{identity}")
end
end