-
Notifications
You must be signed in to change notification settings - Fork 208
Expand file tree
/
Copy pathFastfile
More file actions
339 lines (299 loc) · 13.1 KB
/
Fastfile
File metadata and controls
339 lines (299 loc) · 13.1 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
# 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
require 'yaml'
require 'os'
require 'fileutils'
files_with_version_number = {
'./.version' => ['{x}'],
'./pubspec.yaml' => ['version: {x}'],
'./ios/purchases_flutter.podspec' => ['s.version = \'{x}\''],
'./macos/purchases_flutter.podspec' => ['s.version = \'{x}\''],
'./ios/purchases_flutter/Sources/purchases_flutter/PurchasesFlutterPlugin.m' => ['return @"{x}"'],
'./android/build.gradle' => ['version \'{x}\''],
'./android/src/main/java/com/revenuecat/purchases_flutter/PurchasesFlutterPlugin.java' => ['PLUGIN_VERSION = "{x}"'],
'./purchases_ui_flutter/pubspec.yaml' => ['version: {x}', 'purchases_flutter: ^{x}'],
'./purchases_ui_flutter/ios/purchases_ui_flutter.podspec' => ['s.version = \'{x}\''],
'./purchases_ui_flutter/macos/purchases_ui_flutter.podspec' => ['s.version = \'{x}\''],
'./purchases_ui_flutter/android/build.gradle' => ['version \'{x}\''],
'./lib/web/purchases_flutter_web.dart' => ['_pluginVersion = \'{x}\''],
}
repo_name = 'purchases-flutter'
changelog_latest_path = './CHANGELOG-LATEST.md'
changelog_path = './CHANGELOG.md'
versions_path = './VERSIONS.md'
before_all do
setup_circle_ci
update_fastlane
end
desc "Bump version, edit changelog, and create pull request"
lane :bump do |options|
phc_version = get_phc_version
bump_version_update_changelog_create_pr(
current_version: current_version_number,
changelog_latest_path: changelog_latest_path,
changelog_path: changelog_path,
files_to_update: files_with_version_number,
files_to_update_without_prerelease_modifiers: {},
repo_name: repo_name,
github_rate_limit: options[:github_rate_limit],
editor: options[:editor],
next_version: options[:next_version],
automatic_release: options[:automatic_release],
hybrid_common_version: phc_version,
versions_file_path: versions_path,
is_prerelease: options[:is_prerelease],
include_purchases_js: true
)
update_hybrids_versions_file(
versions_file_path: versions_path,
new_sdk_version: current_version_number,
hybrid_common_version: phc_version,
include_purchases_js: true
)
commit_current_changes(commit_message: 'Update VERSIONS.md')
push_to_git_remote(set_upstream: true)
end
desc "Automatically bumps version, edit changelog, and create pull request"
lane :automatic_bump do |options|
next_version, type_of_bump = determine_next_version_using_labels(
repo_name: repo_name,
github_rate_limit: options[:github_rate_limit]
)
options[:next_version] = next_version
options[:automatic_release] = true
if type_of_bump == :skip
UI.message('Skipping automatic bump since the next version doesn\'t include public facing changes')
next
end
if type_of_bump == :major
UI.message('Skipping automatic bump since the next version is a major release')
next
end
bump(options)
end
desc "Create release"
lane :release do |options|
# Remove purchases_ui_flutter so it's not included in the release of the main SDK
# Can't use .pubignore because it causes files to not be found when trying to
# deploy purchases_ui_flutter
sh('rm', '-rf', 'purchases_ui_flutter')
Dir.chdir('..') do
sh('flutter', 'pub', 'publish', '--dry-run')
end
setup_credentials_file
Dir.chdir('..') do
sh('flutter', 'pub', 'publish', '--force')
end
end
desc "Create purchases_ui_flutter release"
lane :release_purchases_ui_flutter do |options|
Dir.chdir('../purchases_ui_flutter') do
sh('flutter', 'pub', 'publish', '--dry-run')
end
setup_credentials_file
Dir.chdir('../purchases_ui_flutter') do
sh('flutter', 'pub', 'publish', '--force')
end
end
desc "Make github release with current version number"
lane :github_release_current_version do |options|
github_release(version: current_version_number)
end
desc "Make github release"
lane :github_release do |options|
create_github_release(
version: options[:version],
repo_name: repo_name,
github_api_token: ENV["GITHUB_TOKEN"],
changelog_latest_path: changelog_latest_path,
upload_assets: []
)
end
desc "Builds and analyzes the api_tester project to make sure APIs are expected"
lane :run_api_tests do |options|
check_api_tester_imports_up_to_date
build_api_tester_apk
analyze_api_tester
end
desc "Tag current branch with current version number"
lane :tag_current_branch do |options|
version_number = current_version_number
check_no_git_tag_exists(version_number)
add_git_tag(tag: version_number)
push_git_tags(tag: version_number)
end
desc "Update hybrid common pod and gradle"
lane :update_hybrid_common do |options|
if options[:dry_run]
dry_run = true
end
if options[:version]
new_version_number = options[:version]
else
UI.user_error!("Missing `version` argument")
end
current_phc_version = get_phc_version
UI.message("ℹ️ Current Purchases Hybrid Common version: #{current_phc_version}")
UI.message("ℹ️ Setting Purchases Hybrid Common version: #{new_version_number}")
files_to_update = {
'ios/purchases_flutter.podspec' => ['s.dependency \'PurchasesHybridCommon\', \'{x}\''],
'macos/purchases_flutter.podspec' => ['s.dependency \'PurchasesHybridCommon\', \'{x}\''],
'ios/purchases_flutter/Package.swift' => ['.package(url: "https://github.com/RevenueCat/purchases-hybrid-common.git", exact: "{x}")'],
'macos/purchases_flutter/Package.swift' => ['.package(url: "https://github.com/RevenueCat/purchases-hybrid-common.git", exact: "{x}")'],
'android/build.gradle' => ['ext.common_version = \'{x}\''],
'purchases_ui_flutter/ios/purchases_ui_flutter.podspec' => [
's.dependency \'PurchasesHybridCommon\', \'{x}\'',
's.dependency \'PurchasesHybridCommonUI\', \'{x}\''
],
'purchases_ui_flutter/macos/purchases_ui_flutter.podspec' => [
's.dependency \'PurchasesHybridCommon\', \'{x}\'',
's.dependency \'PurchasesHybridCommonUI\', \'{x}\''
],
'purchases_ui_flutter/ios/purchases_ui_flutter/Package.swift' => ['.package(url: "https://github.com/RevenueCat/purchases-hybrid-common.git", exact: "{x}")'],
'purchases_ui_flutter/macos/purchases_ui_flutter/Package.swift' => ['.package(url: "https://github.com/RevenueCat/purchases-hybrid-common.git", exact: "{x}")'],
'purchases_ui_flutter/android/build.gradle' => ['ext.common_version = \'{x}\''],
'lib/web/purchases_flutter_web.dart' => ['_purchasesHybridMappingsVersion = \'{x}\''],
}
if dry_run
UI.message('ℹ️ Nothing more to do, dry_run: true')
next
end
bump_phc_version(
repo_name: 'purchases-flutter',
files_to_update: files_to_update,
current_version: current_phc_version,
next_version: new_version_number,
open_pr: options[:open_pr] || false,
automatic_release: options[:automatic_release] || false,
enable_auto_merge: options[:automatic_release] || false
)
end
desc "Run maestro E2E tests on iOS"
lane :run_maestro_e2e_tests_ios do
UI.user_error!("RC_E2E_TEST_API_KEY_PRODUCTION_TEST_STORE is not set") if ENV["RC_E2E_TEST_API_KEY_PRODUCTION_TEST_STORE"].to_s.empty?
Dir.chdir("../e2e-tests/MaestroTestApp") do
sh("sed -i '' 's/MAESTRO_TESTS_REVENUECAT_API_KEY/'\"$RC_E2E_TEST_API_KEY_PRODUCTION_TEST_STORE\"'/g' lib/main.dart")
sh("grep -q MAESTRO_TESTS_REVENUECAT_API_KEY lib/main.dart && echo 'ERROR: API key placeholder was not replaced' && exit 1 || true")
sh("flutter pub get")
sh("flutter build ios --debug --simulator")
sh("xcrun simctl install booted build/ios/iphonesimulator/Runner.app")
end
run_maestro_e2e_tests(flow_dir: "../e2e-tests/maestro/", output_dir: "test_output")
end
desc "Build maestro E2E test app for Android"
lane :build_maestro_app_android do
UI.user_error!("RC_E2E_TEST_API_KEY_PRODUCTION_TEST_STORE is not set") if ENV["RC_E2E_TEST_API_KEY_PRODUCTION_TEST_STORE"].to_s.empty?
Dir.chdir("../e2e-tests/MaestroTestApp") do
sh("sed -i 's/MAESTRO_TESTS_REVENUECAT_API_KEY/'\"$RC_E2E_TEST_API_KEY_PRODUCTION_TEST_STORE\"'/g' lib/main.dart")
sh("grep -q MAESTRO_TESTS_REVENUECAT_API_KEY lib/main.dart && echo 'ERROR: API key placeholder was not replaced' && exit 1 || true")
sh("flutter pub get")
sh("flutter build apk --debug")
end
end
desc "Run maestro E2E tests on Android (emulator must be running)"
lane :run_maestro_e2e_tests_android do
sh("adb install ../e2e-tests/MaestroTestApp/build/app/outputs/flutter-apk/app-debug.apk")
run_maestro_e2e_tests(flow_dir: "../e2e-tests/maestro/", output_dir: "test_output")
end
desc "Trigger bump"
lane :trigger_bump do
trigger_action_in_circle_ci(action: 'bump', repo_name: repo_name)
end
###############################################################################
# Helper functions 🤜🤛 #
###############################################################################
def get_root_folder
return File.expand_path('../../', __FILE__)
end
def setup_credentials_file
access_token = ENV['FLUTTER_PUB_ACCESS_TOKEN'] || UI.user_error!('Need to set FLUTTER_PUB_ACCESS_TOKEN to publish package.')
refresh_token = ENV['FLUTTER_PUB_REFRESH_TOKEN'] || UI.user_error!('Need to set FLUTTER_PUB_REFRESH_TOKEN to publish package.')
id_token = ENV['FLUTTER_PUB_ID_TOKEN'] || UI.user_error!('Need to set FLUTTER_PUB_ID_TOKEN to publish package.')
expiration = ENV['FLUTTER_PUB_EXPIRATION_TIMESTAMP'] || UI.user_error!('Need to set FLUTTER_PUB_EXPIRATION_TIMESTAMP to publish package.')
token_endpoint = 'https://accounts.google.com/o/oauth2/token'
scopes = ['openid', 'https://www.googleapis.com/auth/userinfo.email']
credentials_hash = {
"accessToken": access_token,
"refreshToken": refresh_token,
"idToken": id_token,
"tokenEndpoint": token_endpoint,
"scopes": scopes,
"expiration": expiration.to_i
}
home_folder = ENV['HOME']
output_relative_path = OS.mac? ? "Library/Application\ Support/dart/pub-credentials.json" : ".config/dart/pub-credentials.json"
output_path = File.join(home_folder, output_relative_path)
if File.exist?(output_path)
UI.message('Credentials file already exists. Skipping setup')
return
end
UI.message('Creating credentials file')
output_directory = File.dirname(output_path)
FileUtils.mkpath(output_directory)
File.write(output_path, credentials_hash.to_json)
end
def current_version_number
File.read("../.version").strip
end
def check_api_tester_imports_up_to_date
api_test_files = Dir
.glob("../api_tester/lib/api_tests/**/*.dart")
.reject { |file_path| File.directory?(file_path) }
import_file_lines = File.readlines("../api_tester/lib/api_tests_import.dart")
api_test_files.each do |file_path|
file_name = File.basename(file_path)
unless import_file_lines.any? { |line| line.include?(file_name) }
UI.user_error!("api_tester api_tests_import.dart is not up-to-date. Missing #{file_name}")
end
end
end
def build_api_tester_apk
Dir.chdir("../api_tester") do
sh("flutter", "build", "apk", "--debug")
end
end
def analyze_api_tester
Dir.chdir("../api_tester") do
sh("flutter", "analyze")
end
end
def get_phc_version
android_build_gradle_path = '../android/build.gradle'
android_build_gradle_contents = File.read(android_build_gradle_path)
android_phc_version = android_build_gradle_contents.match("ext.common_version = '(.*)'").captures[0]
UI.user_error!("Android PHC version not found.") if android_phc_version.nil?
android_ui_build_gradle_path = '../purchases_ui_flutter/android/build.gradle'
android_ui_build_gradle_contents = File.read(android_ui_build_gradle_path)
android_phc_ui_version = android_ui_build_gradle_contents.match("ext.common_version = '(.*)'").captures[0]
UI.user_error!("Android PHC UI version not found.") if android_phc_ui_version.nil?
ios_podspec_path = '../ios/purchases_flutter.podspec'
ios_podspec_contents = File.read(ios_podspec_path)
ios_phc_version = ios_podspec_contents.match("s.dependency 'PurchasesHybridCommon', '(.*)'").captures[0]
UI.user_error!("iOS PHC version not found.") if ios_phc_version.nil?
ios_ui_podspec_path = '../purchases_ui_flutter/ios/purchases_ui_flutter.podspec'
ios_ui_podspec_contents = File.read(ios_ui_podspec_path)
ios_phc_ui_version = ios_ui_podspec_contents.match("s.dependency 'PurchasesHybridCommonUI', '(.*)'").captures[0]
UI.user_error!("iOS PHC UI version not found.") if ios_phc_ui_version.nil?
versions_match =
android_phc_version == ios_phc_version &&
android_phc_version == android_phc_ui_version &&
ios_phc_version == ios_phc_ui_version
UI.user_error!("Android and iOS PHC (UI) versions don't match. Please make sure they match.") unless versions_match
ios_phc_version
end
def check_no_git_tag_exists(version_number)
if git_tag_exists(tag: version_number, remote: true, remote_name: 'origin')
raise "git tag with version #{version_number} already exists!"
end
end