fastlane-plugin-firebase_app_distribution 0.6.0 → 0.7.0.pre.1
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.
- checksums.yaml +4 -4
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_action.rb +150 -40
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_add_testers_action.rb +52 -9
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_create_group_action.rb +25 -4
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_delete_group_action.rb +11 -3
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_get_latest_release.rb +39 -6
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_get_udids.rb +2 -2
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_remove_testers_action.rb +57 -9
- data/lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb +1 -396
- data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_auth_client.rb +24 -19
- data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_error_message.rb +2 -3
- data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_helper.rb +31 -2
- data/lib/fastlane/plugin/firebase_app_distribution/version.rb +1 -1
- metadata +32 -7
- data/lib/fastlane/plugin/firebase_app_distribution/client/aab_info.rb +0 -42
- data/lib/fastlane/plugin/firebase_app_distribution/client/error_response.rb +0 -16
- data/lib/fastlane/plugin/firebase_app_distribution/helper/upload_status_response.rb +0 -77
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0de4fec6f4206e3577c8e2d6e247d64336020336f0db820c732b7b08a3473848
|
4
|
+
data.tar.gz: dd9d4f3bb86846b3115c3311dbc413e837134cd8d0fecc1ba845328b0fa62420
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb67a198cbf50af6cf4eec6cae102b99ae2e3c64752a726e33812bbb761b6da0372bae5f3e905413f5a949a72896a9901ba3d0429c92a77d0dbdf1a849628d52
|
7
|
+
data.tar.gz: b2e7b60eb0e5831a3de41340c22f452577fa675cce46c9dd40eeabcc0ba5a5614f915202cedcab362783b3d71ed153e672b350813beb953d8f53c22103f71e82
|
data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_action.rb
CHANGED
@@ -2,10 +2,8 @@ require 'fastlane/action'
|
|
2
2
|
require 'open3'
|
3
3
|
require 'shellwords'
|
4
4
|
require 'googleauth'
|
5
|
-
require_relative '../helper/upload_status_response'
|
6
5
|
require_relative '../helper/firebase_app_distribution_helper'
|
7
6
|
require_relative '../helper/firebase_app_distribution_error_message'
|
8
|
-
require_relative '../client/firebase_app_distribution_api_client'
|
9
7
|
require_relative '../helper/firebase_app_distribution_auth_client'
|
10
8
|
|
11
9
|
## How should we document the usage of release notes?
|
@@ -15,19 +13,18 @@ module Fastlane
|
|
15
13
|
FIREBASE_APP_DISTRO_RELEASE ||= :FIREBASE_APP_DISTRO_RELEASE
|
16
14
|
end
|
17
15
|
|
16
|
+
# rubocop:disable Metrics/ClassLength
|
18
17
|
class FirebaseAppDistributionAction < Action
|
19
18
|
extend Auth::FirebaseAppDistributionAuthClient
|
20
19
|
extend Helper::FirebaseAppDistributionHelper
|
21
20
|
|
22
21
|
DEFAULT_UPLOAD_TIMEOUT_SECONDS = 300
|
22
|
+
MAX_POLLING_RETRIES = 60
|
23
|
+
POLLING_INTERVAL_SECONDS = 5
|
23
24
|
|
24
25
|
def self.run(params)
|
25
26
|
params.values # to validate all inputs before looking for the ipa/apk/aab
|
26
27
|
|
27
|
-
if params[:debug]
|
28
|
-
UI.important("Warning: Debug logging enabled. Output may include sensitive information.")
|
29
|
-
end
|
30
|
-
|
31
28
|
app_id = app_id_from_params(params)
|
32
29
|
app_name = app_name_from_app_id(app_id)
|
33
30
|
platform = lane_platform || platform_from_app_id(app_id)
|
@@ -37,33 +34,31 @@ module Fastlane
|
|
37
34
|
UI.user_error!("Couldn't find binary at path #{binary_path}") unless File.exist?(binary_path)
|
38
35
|
binary_type = binary_type_from_path(binary_path)
|
39
36
|
|
40
|
-
|
41
|
-
params[:service_credentials_file], params[:firebase_cli_token], params[:debug]
|
42
|
-
)
|
43
|
-
fad_api_client = Client::FirebaseAppDistributionApiClient.new(auth_token, params[:debug])
|
37
|
+
client = init_client(params[:service_credentials_file], params[:firebase_cli_token], params[:debug])
|
44
38
|
|
45
39
|
# If binary is an AAB, get the AAB info for this app, which includes the integration state and certificate data
|
46
40
|
if binary_type == :AAB
|
47
|
-
aab_info =
|
41
|
+
aab_info = get_aab_info(client, app_name)
|
48
42
|
validate_aab_setup!(aab_info)
|
49
43
|
end
|
50
44
|
|
51
|
-
|
45
|
+
binary_type = binary_type_from_path(binary_path)
|
46
|
+
UI.message("⌛ Uploading the #{binary_type}.")
|
52
47
|
|
53
|
-
|
54
|
-
|
55
|
-
release =
|
48
|
+
timeout = get_upload_timeout(params)
|
49
|
+
operation = upload_binary(app_name, binary_path, client, timeout)
|
50
|
+
release = poll_upload_release_operation(client, operation, binary_type)
|
56
51
|
|
57
|
-
if binary_type == :AAB && aab_info && !aab_info.
|
58
|
-
updated_aab_info =
|
59
|
-
if updated_aab_info.
|
52
|
+
if binary_type == :AAB && aab_info && !aab_certs_included?(aab_info.test_certificate)
|
53
|
+
updated_aab_info = get_aab_info(client, app_name)
|
54
|
+
if aab_certs_included?(updated_aab_info.test_certificate)
|
60
55
|
UI.message("After you upload an AAB for the first time, App Distribution " \
|
61
56
|
"generates a new test certificate. All AAB uploads are re-signed with this test " \
|
62
57
|
"certificate. Use the certificate fingerprints below to register your app " \
|
63
58
|
"signing key with API providers, such as Google Sign-In and Google Maps.\n" \
|
64
|
-
"MD-1 certificate fingerprint: #{updated_aab_info.
|
65
|
-
"SHA-1 certificate fingerprint: #{updated_aab_info.
|
66
|
-
"SHA-256 certificate fingerprint: #{updated_aab_info.
|
59
|
+
"MD-1 certificate fingerprint: #{updated_aab_info.test_certificate.hash_md5}\n" \
|
60
|
+
"SHA-1 certificate fingerprint: #{updated_aab_info.test_certificate.hash_sha1}\n" \
|
61
|
+
"SHA-256 certificate fingerprint: #{updated_aab_info.test_certificate.hash_sha256}")
|
67
62
|
end
|
68
63
|
end
|
69
64
|
|
@@ -71,30 +66,35 @@ module Fastlane
|
|
71
66
|
if release_notes.nil? || release_notes.empty?
|
72
67
|
UI.message("⏩ No release notes passed in. Skipping this step.")
|
73
68
|
else
|
74
|
-
release =
|
69
|
+
release.release_notes = Google::Apis::FirebaseappdistributionV1::GoogleFirebaseAppdistroV1ReleaseNotes.new(
|
70
|
+
text: release_notes
|
71
|
+
)
|
72
|
+
release = update_release(client, release)
|
75
73
|
end
|
76
74
|
|
77
75
|
testers = get_value_from_value_or_file(params[:testers], params[:testers_file])
|
78
76
|
groups = get_value_from_value_or_file(params[:groups], params[:groups_file])
|
79
77
|
emails = string_to_array(testers)
|
80
78
|
group_aliases = string_to_array(groups)
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
79
|
+
if present?(emails) || present?(group_aliases)
|
80
|
+
request = Google::Apis::FirebaseappdistributionV1::GoogleFirebaseAppdistroV1DistributeReleaseRequest.new(
|
81
|
+
tester_emails: emails,
|
82
|
+
group_aliases: group_aliases
|
83
|
+
)
|
84
|
+
distribute_release(client, release, request)
|
85
|
+
else
|
86
|
+
UI.message("⏩ No testers or groups passed in. Skipping this step.")
|
86
87
|
end
|
87
88
|
|
88
|
-
|
89
|
-
UI.message("🔗 Share this release with testers who have access: #{upload_status_response.testing_uri}")
|
90
|
-
end
|
89
|
+
UI.success("🎉 App Distribution upload finished successfully. Setting Actions.lane_context[SharedValues::FIREBASE_APP_DISTRO_RELEASE] to the uploaded release.")
|
91
90
|
|
92
|
-
if
|
93
|
-
|
94
|
-
|
91
|
+
UI.message("🔗 View this release in the Firebase console: #{release.firebase_console_uri}") if release.firebase_console_uri
|
92
|
+
UI.message("🔗 Share this release with testers who have access: #{release.testing_uri}") if release.testing_uri
|
93
|
+
UI.message("🔗 Download the release binary (link expires in 1 hour): #{release.binary_download_uri}") if release.binary_download_uri
|
95
94
|
|
96
|
-
|
97
|
-
|
95
|
+
release_hash = deep_symbolize_keys(JSON.parse(release.to_json))
|
96
|
+
Actions.lane_context[SharedValues::FIREBASE_APP_DISTRO_RELEASE] = release_hash
|
97
|
+
release_hash
|
98
98
|
end
|
99
99
|
|
100
100
|
def self.description
|
@@ -174,15 +174,15 @@ module Fastlane
|
|
174
174
|
end
|
175
175
|
|
176
176
|
def self.validate_aab_setup!(aab_info)
|
177
|
-
if aab_info && aab_info.integration_state !=
|
177
|
+
if aab_info && aab_info.integration_state != 'INTEGRATED' && aab_info.integration_state != 'AAB_STATE_UNAVAILABLE'
|
178
178
|
case aab_info.integration_state
|
179
|
-
when
|
179
|
+
when 'PLAY_ACCOUNT_NOT_LINKED'
|
180
180
|
UI.user_error!(ErrorMessage::PLAY_ACCOUNT_NOT_LINKED)
|
181
|
-
when
|
181
|
+
when 'APP_NOT_PUBLISHED'
|
182
182
|
UI.user_error!(ErrorMessage::APP_NOT_PUBLISHED)
|
183
|
-
when
|
183
|
+
when 'NO_APP_WITH_GIVEN_BUNDLE_ID_IN_PLAY_ACCOUNT'
|
184
184
|
UI.user_error!(ErrorMessage::NO_APP_WITH_GIVEN_BUNDLE_ID_IN_PLAY_ACCOUNT)
|
185
|
-
when
|
185
|
+
when 'PLAY_IAS_TERMS_NOT_ACCEPTED'
|
186
186
|
UI.user_error!(ErrorMessage::PLAY_IAS_TERMS_NOT_ACCEPTED)
|
187
187
|
else
|
188
188
|
UI.user_error!(ErrorMessage.aab_upload_error(aab_info.integration_state))
|
@@ -190,12 +190,121 @@ module Fastlane
|
|
190
190
|
end
|
191
191
|
end
|
192
192
|
|
193
|
+
def self.aab_certs_included?(test_certificate)
|
194
|
+
present?(test_certificate.hash_md5) && present?(test_certificate.hash_sha1) &&
|
195
|
+
present?(test_certificate.hash_sha256)
|
196
|
+
end
|
197
|
+
|
198
|
+
def self.aab_info_name(app_name)
|
199
|
+
"#{app_name}/aabInfo"
|
200
|
+
end
|
201
|
+
|
193
202
|
def self.release_notes(params)
|
194
203
|
release_notes_param =
|
195
204
|
get_value_from_value_or_file(params[:release_notes], params[:release_notes_file])
|
196
205
|
release_notes_param || Actions.lane_context[SharedValues::FL_CHANGELOG]
|
197
206
|
end
|
198
207
|
|
208
|
+
def self.poll_upload_release_operation(client, operation, binary_type)
|
209
|
+
operation = client.get_project_app_release_operation(operation.name)
|
210
|
+
MAX_POLLING_RETRIES.times do
|
211
|
+
if operation.done && operation.response && operation.response['release']
|
212
|
+
release = extract_release(operation)
|
213
|
+
result = operation.response['result']
|
214
|
+
if result == 'RELEASE_UPDATED'
|
215
|
+
UI.success("✅ Uploaded #{binary_type} successfully; updated provisioning profile of existing release #{release_version(release)}.")
|
216
|
+
break
|
217
|
+
elsif result == 'RELEASE_UNMODIFIED'
|
218
|
+
UI.success("✅ The same #{binary_type} was found in release #{release_version(release)} with no changes, skipping.")
|
219
|
+
break
|
220
|
+
else
|
221
|
+
UI.success("✅ Uploaded #{binary_type} successfully and created release #{release_version(release)}.")
|
222
|
+
end
|
223
|
+
break
|
224
|
+
elsif !operation.done
|
225
|
+
sleep(POLLING_INTERVAL_SECONDS)
|
226
|
+
operation = client.get_project_app_release_operation(operation.name)
|
227
|
+
else
|
228
|
+
if operation.error && operation.error.message
|
229
|
+
UI.user_error!("#{ErrorMessage.upload_binary_error(binary_type)}: #{operation.error.message}")
|
230
|
+
else
|
231
|
+
UI.user_error!(ErrorMessage.upload_binary_error(binary_type))
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
extract_release(operation)
|
236
|
+
end
|
237
|
+
|
238
|
+
def self.upload_binary(app_name, binary_path, client, timeout)
|
239
|
+
options = Google::Apis::RequestOptions.new
|
240
|
+
options.max_elapsed_time = timeout
|
241
|
+
options.header = {
|
242
|
+
'Content-Type' => 'application/octet-stream',
|
243
|
+
'X-Goog-Upload-File-Name' => File.basename(binary_path),
|
244
|
+
'X-Goog-Upload-Protocol' => 'raw'
|
245
|
+
}
|
246
|
+
# For some reason calling the client.upload_medium returns nil when
|
247
|
+
# it should return a long running operation object, so we make a
|
248
|
+
# standard http call instead and convert it to a long running object
|
249
|
+
# https://github.com/googleapis/google-api-ruby-client/blob/main/generated/google-apis-firebaseappdistribution_v1/lib/google/apis/firebaseappdistribution_v1/service.rb#L79
|
250
|
+
# TODO(kbolay) Prefer client.upload_medium
|
251
|
+
response = client.http(
|
252
|
+
:post,
|
253
|
+
"https://firebaseappdistribution.googleapis.com/upload/v1/#{app_name}/releases:upload",
|
254
|
+
body: File.open(binary_path, 'rb').read,
|
255
|
+
options: options
|
256
|
+
)
|
257
|
+
|
258
|
+
Google::Apis::FirebaseappdistributionV1::GoogleLongrunningOperation.from_json(response)
|
259
|
+
end
|
260
|
+
|
261
|
+
def self.extract_release(operation)
|
262
|
+
Google::Apis::FirebaseappdistributionV1::GoogleFirebaseAppdistroV1Release.from_json(operation.response['release'].to_json)
|
263
|
+
end
|
264
|
+
|
265
|
+
def self.release_version(release)
|
266
|
+
if release.display_version && release.build_version
|
267
|
+
"#{release.display_version} (#{release.build_version})"
|
268
|
+
elsif release.display_version
|
269
|
+
release.display_version
|
270
|
+
else
|
271
|
+
release.build_version
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def self.get_aab_info(client, app_name)
|
276
|
+
client.get_project_app_aab_info(aab_info_name(app_name))
|
277
|
+
rescue Google::Apis::Error => err
|
278
|
+
case err.status_code.to_i
|
279
|
+
when 404
|
280
|
+
UI.user_error!(ErrorMessage::INVALID_APP_ID)
|
281
|
+
else
|
282
|
+
UI.crash!(err)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def self.update_release(client, release)
|
287
|
+
client.patch_project_app_release(release.name, release)
|
288
|
+
rescue Google::Apis::Error => err
|
289
|
+
case err.status_code.to_i
|
290
|
+
when 400
|
291
|
+
UI.user_error!("#{ErrorMessage::INVALID_RELEASE_NOTES}: #{err.body}")
|
292
|
+
else
|
293
|
+
UI.crash!(err)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def self.distribute_release(client, release, request)
|
298
|
+
client.distribute_project_app_release(release.name, request)
|
299
|
+
rescue Google::Apis::Error => err
|
300
|
+
case err.status_code.to_i
|
301
|
+
when 400
|
302
|
+
UI.user_error!("#{ErrorMessage::INVALID_TESTERS}\nEmails: #{request.tester_emails} \nGroup Aliases: #{request.group_aliases}")
|
303
|
+
else
|
304
|
+
UI.crash!(err)
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
199
308
|
def self.available_options
|
200
309
|
[
|
201
310
|
# iOS Specific
|
@@ -314,5 +423,6 @@ module Fastlane
|
|
314
423
|
]
|
315
424
|
end
|
316
425
|
end
|
426
|
+
# rubocop:enable Metrics/ClassLength
|
317
427
|
end
|
318
428
|
end
|
@@ -11,14 +11,15 @@ module Fastlane
|
|
11
11
|
extend Helper::FirebaseAppDistributionHelper
|
12
12
|
|
13
13
|
def self.run(params)
|
14
|
-
|
15
|
-
fad_api_client = Client::FirebaseAppDistributionApiClient.new(auth_token, params[:debug])
|
14
|
+
client = init_client(params[:service_credentials_file], params[:firebase_cli_token], params[:debug])
|
16
15
|
|
17
16
|
if blank?(params[:emails]) && blank?(params[:file])
|
18
17
|
UI.user_error!("Must specify `emails` or `file`.")
|
19
18
|
end
|
20
19
|
|
21
20
|
emails = string_to_array(get_value_from_value_or_file(params[:emails], params[:file]))
|
21
|
+
project_number = params[:project_number]
|
22
|
+
group_alias = params[:group_alias]
|
22
23
|
|
23
24
|
UI.user_error!("Must pass at least one email") if blank?(emails)
|
24
25
|
|
@@ -26,13 +27,10 @@ module Fastlane
|
|
26
27
|
UI.user_error!("A maximum of 1000 testers can be added at a time.")
|
27
28
|
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
unless blank?(params[:group_alias])
|
34
|
-
UI.message("⏳ Adding testers to group #{params[:group_alias]}...")
|
35
|
-
fad_api_client.add_testers_to_group(params[:project_number], params[:group_alias], emails)
|
30
|
+
if present?(group_alias)
|
31
|
+
add_testers_to_group(client, project_number, emails, group_alias)
|
32
|
+
else
|
33
|
+
add_testers_to_project(client, emails, project_number)
|
36
34
|
end
|
37
35
|
|
38
36
|
# The add_testers response lists all the testers from the request
|
@@ -95,6 +93,51 @@ module Fastlane
|
|
95
93
|
def self.is_supported?(platform)
|
96
94
|
true
|
97
95
|
end
|
96
|
+
|
97
|
+
def self.add_testers_to_project(client, emails, project_number)
|
98
|
+
UI.message("⏳ Adding #{emails.count} testers to project #{project_number}...")
|
99
|
+
request = Google::Apis::FirebaseappdistributionV1::GoogleFirebaseAppdistroV1BatchAddTestersRequest.new(
|
100
|
+
emails: emails
|
101
|
+
)
|
102
|
+
|
103
|
+
begin
|
104
|
+
client.batch_project_tester_add(project_name(project_number), request)
|
105
|
+
rescue Google::Apis::Error => err
|
106
|
+
case err.status_code.to_i
|
107
|
+
when 400
|
108
|
+
UI.user_error!(ErrorMessage::INVALID_EMAIL_ADDRESS)
|
109
|
+
when 404
|
110
|
+
UI.user_error!(ErrorMessage::INVALID_PROJECT)
|
111
|
+
when 429
|
112
|
+
UI.user_error!(ErrorMessage::TESTER_LIMIT_VIOLATION)
|
113
|
+
else
|
114
|
+
UI.crash!(err)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.add_testers_to_group(client, project_number, emails, group_alias)
|
120
|
+
UI.message("⏳ Adding testers to group #{group_alias}...")
|
121
|
+
request = Google::Apis::FirebaseappdistributionV1::GoogleFirebaseAppdistroV1BatchJoinGroupRequest.new(
|
122
|
+
emails: emails,
|
123
|
+
create_missing_testers: true
|
124
|
+
)
|
125
|
+
|
126
|
+
begin
|
127
|
+
client.batch_project_group_join(group_name(project_number, group_alias), request)
|
128
|
+
rescue Google::Apis::Error => err
|
129
|
+
case err.status_code.to_i
|
130
|
+
when 400
|
131
|
+
UI.user_error!(ErrorMessage::INVALID_EMAIL_ADDRESS)
|
132
|
+
when 404
|
133
|
+
UI.user_error!(ErrorMessage::INVALID_TESTER_GROUP)
|
134
|
+
when 429
|
135
|
+
UI.user_error!(ErrorMessage::TESTER_LIMIT_VIOLATION)
|
136
|
+
else
|
137
|
+
UI.crash!(err)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
98
141
|
end
|
99
142
|
end
|
100
143
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'fastlane/action'
|
2
2
|
require 'fastlane_core/ui/ui'
|
3
|
+
require 'google/apis/firebaseappdistribution_v1'
|
3
4
|
|
4
5
|
require_relative '../helper/firebase_app_distribution_helper'
|
5
6
|
require_relative '../helper/firebase_app_distribution_auth_client'
|
@@ -10,10 +11,9 @@ module Fastlane
|
|
10
11
|
extend Auth::FirebaseAppDistributionAuthClient
|
11
12
|
extend Helper::FirebaseAppDistributionHelper
|
12
13
|
|
13
|
-
|
14
|
-
auth_token = fetch_auth_token(params[:service_credentials_file], params[:firebase_cli_token])
|
15
|
-
fad_api_client = Client::FirebaseAppDistributionApiClient.new(auth_token, params[:debug])
|
14
|
+
FirebaseAppDistributionV1 = Google::Apis::FirebaseappdistributionV1
|
16
15
|
|
16
|
+
def self.run(params)
|
17
17
|
if blank?(params[:alias])
|
18
18
|
UI.user_error!("Must specify `alias`.")
|
19
19
|
end
|
@@ -22,13 +22,34 @@ module Fastlane
|
|
22
22
|
UI.user_error!("Must specify `display_name`.")
|
23
23
|
end
|
24
24
|
|
25
|
+
client = init_client(params[:service_credentials_file], params[:firebase_cli_token], params[:debug])
|
26
|
+
|
25
27
|
project_number = params[:project_number]
|
26
28
|
group_alias = params[:alias]
|
27
29
|
display_name = params[:display_name]
|
28
30
|
|
29
31
|
UI.message("⏳ Creating tester group '#{group_alias} (#{display_name})' in project #{project_number}...")
|
30
32
|
|
31
|
-
|
33
|
+
parent = project_name(project_number)
|
34
|
+
group = FirebaseAppDistributionV1::GoogleFirebaseAppdistroV1Group.new(
|
35
|
+
name: group_name(project_number, group_alias),
|
36
|
+
display_name: display_name
|
37
|
+
)
|
38
|
+
|
39
|
+
begin
|
40
|
+
client.create_project_group(parent, group, group_id: group_alias)
|
41
|
+
rescue Google::Apis::Error => err
|
42
|
+
case err.status_code.to_i
|
43
|
+
when 400
|
44
|
+
UI.user_error!(ErrorMessage::INVALID_TESTER_GROUP_NAME)
|
45
|
+
when 404
|
46
|
+
UI.user_error!(ErrorMessage::INVALID_PROJECT)
|
47
|
+
when 409
|
48
|
+
UI.important("Tester group #{group_alias} already exists.")
|
49
|
+
else
|
50
|
+
UI.crash!(err)
|
51
|
+
end
|
52
|
+
end
|
32
53
|
|
33
54
|
UI.success("✅ Group created successfully.")
|
34
55
|
end
|
@@ -11,8 +11,7 @@ module Fastlane
|
|
11
11
|
extend Helper::FirebaseAppDistributionHelper
|
12
12
|
|
13
13
|
def self.run(params)
|
14
|
-
|
15
|
-
fad_api_client = Client::FirebaseAppDistributionApiClient.new(auth_token, params[:debug])
|
14
|
+
client = init_client(params[:service_credentials_file], params[:firebase_cli_token], params[:debug])
|
16
15
|
|
17
16
|
if blank?(params[:alias])
|
18
17
|
UI.user_error!("Must specify `alias`.")
|
@@ -23,7 +22,16 @@ module Fastlane
|
|
23
22
|
|
24
23
|
UI.message("⏳ Deleting tester group '#{group_alias}' in project #{project_number}...")
|
25
24
|
|
26
|
-
|
25
|
+
begin
|
26
|
+
client.delete_project_group(group_name(project_number, group_alias))
|
27
|
+
rescue Google::Apis::Error => err
|
28
|
+
case err.status_code.to_i
|
29
|
+
when 404
|
30
|
+
UI.user_error!(ErrorMessage::INVALID_TESTER_GROUP)
|
31
|
+
else
|
32
|
+
UI.crash!(err)
|
33
|
+
end
|
34
|
+
end
|
27
35
|
|
28
36
|
UI.success("✅ Group deleted successfully.")
|
29
37
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'fastlane/action'
|
2
|
-
|
2
|
+
require 'google/apis/firebaseappdistribution_v1'
|
3
3
|
require_relative '../helper/firebase_app_distribution_auth_client'
|
4
4
|
require_relative '../helper/firebase_app_distribution_helper'
|
5
5
|
|
@@ -13,23 +13,53 @@ module Fastlane
|
|
13
13
|
extend Helper::FirebaseAppDistributionHelper
|
14
14
|
|
15
15
|
def self.run(params)
|
16
|
-
|
17
|
-
fad_api_client = Client::FirebaseAppDistributionApiClient.new(auth_token, params[:debug])
|
16
|
+
client = init_client(params[:service_credentials_file], params[:firebase_cli_token], params[:debug])
|
18
17
|
|
19
18
|
UI.message("⏳ Fetching latest release for app #{params[:app]}...")
|
20
19
|
|
21
|
-
|
22
|
-
|
20
|
+
parent = app_name_from_app_id(params[:app])
|
21
|
+
|
22
|
+
begin
|
23
|
+
releases = client.list_project_app_releases(parent, page_size: 1).releases
|
24
|
+
rescue Google::Apis::Error => err
|
25
|
+
if err.status_code.to_i == 404
|
26
|
+
UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{params[:app]}")
|
27
|
+
else
|
28
|
+
UI.crash!(err)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
if releases.nil? || releases.empty?
|
23
33
|
latest_release = nil
|
24
34
|
UI.important("No releases for app #{params[:app]} found in App Distribution. Returning nil and setting Actions.lane_context[SharedValues::FIREBASE_APP_DISTRO_LATEST_RELEASE].")
|
25
35
|
else
|
26
|
-
latest_release = releases[0]
|
36
|
+
# latest_release = append_json_style_fields(response.releases[0].to_h)
|
37
|
+
latest_release = map_release_hash(releases[0])
|
27
38
|
UI.success("✅ Latest release fetched successfully. Returning release and setting Actions.lane_context[SharedValues::FIREBASE_APP_DISTRO_LATEST_RELEASE].")
|
28
39
|
end
|
29
40
|
Actions.lane_context[SharedValues::FIREBASE_APP_DISTRO_LATEST_RELEASE] = latest_release
|
30
41
|
return latest_release
|
31
42
|
end
|
32
43
|
|
44
|
+
def self.map_release_hash(release)
|
45
|
+
{
|
46
|
+
name: release.name,
|
47
|
+
releaseNotes: map_release_notes_hash(release.release_notes),
|
48
|
+
displayVersion: release.display_version,
|
49
|
+
buildVersion: release.build_version,
|
50
|
+
binaryDownloadUri: release.binary_download_uri,
|
51
|
+
firebaseConsoleUri: release.firebase_console_uri,
|
52
|
+
testingUri: release.testing_uri,
|
53
|
+
createTime: release.create_time
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.map_release_notes_hash(release_notes)
|
58
|
+
return nil if release_notes.nil?
|
59
|
+
|
60
|
+
{ text: release_notes.text }
|
61
|
+
end
|
62
|
+
|
33
63
|
#####################################################
|
34
64
|
# @!group Documentation
|
35
65
|
#####################################################
|
@@ -106,6 +136,9 @@ module Fastlane
|
|
106
136
|
},
|
107
137
|
displayVersion: "1.2.3",
|
108
138
|
buildVersion: "10",
|
139
|
+
binaryDownloadUri: "<URI>",
|
140
|
+
firebaseConsoleUri: "<URI>",
|
141
|
+
testingUri: "<URI>",
|
109
142
|
createTime: "2021-10-06T15:01:23Z"
|
110
143
|
}
|
111
144
|
end
|
data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_get_udids.rb
CHANGED
@@ -14,8 +14,8 @@ module Fastlane
|
|
14
14
|
extend Helper::FirebaseAppDistributionHelper
|
15
15
|
|
16
16
|
def self.run(params)
|
17
|
-
|
18
|
-
fad_api_client = Client::FirebaseAppDistributionApiClient.new(
|
17
|
+
client = init_client(params[:service_credentials_file], params[:firebase_cli_token], params[:debug])
|
18
|
+
fad_api_client = Client::FirebaseAppDistributionApiClient.new(client.authorization.access_token, params[:debug])
|
19
19
|
|
20
20
|
app_id = params[:app]
|
21
21
|
udids = fad_api_client.get_udids(app_id)
|
@@ -11,14 +11,15 @@ module Fastlane
|
|
11
11
|
extend Helper::FirebaseAppDistributionHelper
|
12
12
|
|
13
13
|
def self.run(params)
|
14
|
-
|
15
|
-
fad_api_client = Client::FirebaseAppDistributionApiClient.new(auth_token, params[:debug])
|
14
|
+
client = init_client(params[:service_credentials_file], params[:firebase_cli_token], params[:debug])
|
16
15
|
|
17
16
|
if blank?(params[:emails]) && blank?(params[:file])
|
18
17
|
UI.user_error!("Must specify `emails` or `file`.")
|
19
18
|
end
|
20
19
|
|
21
20
|
emails = string_to_array(get_value_from_value_or_file(params[:emails], params[:file]))
|
21
|
+
project_number = params[:project_number]
|
22
|
+
group_alias = params[:group_alias]
|
22
23
|
|
23
24
|
UI.user_error!("Must pass at least one email") if blank?(emails)
|
24
25
|
|
@@ -26,11 +27,11 @@ module Fastlane
|
|
26
27
|
UI.user_error!("A maximum of 1000 testers can be removed at a time.")
|
27
28
|
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
if present?(group_alias)
|
31
|
+
remove_testers_from_group(client, project_number, group_alias, emails)
|
32
|
+
else
|
33
|
+
remove_testers_from_project(client, project_number, emails)
|
34
|
+
end
|
34
35
|
end
|
35
36
|
|
36
37
|
def self.description
|
@@ -55,14 +56,19 @@ module Fastlane
|
|
55
56
|
optional: false),
|
56
57
|
FastlaneCore::ConfigItem.new(key: :emails,
|
57
58
|
env_name: "FIREBASEAPPDISTRO_REMOVE_TESTERS_EMAILS",
|
58
|
-
description: "Comma separated list of tester emails to be deleted. A maximum of 1000 testers can be deleted at a time",
|
59
|
+
description: "Comma separated list of tester emails to be deleted (or removed from a group if a group alias is specified). A maximum of 1000 testers can be deleted/removed at a time",
|
59
60
|
optional: true,
|
60
61
|
type: String),
|
61
62
|
FastlaneCore::ConfigItem.new(key: :file,
|
62
63
|
env_name: "FIREBASEAPPDISTRO_REMOVE_TESTERS_FILE",
|
63
|
-
description: "Path to a file containing a comma separated list of tester emails to be deleted. A maximum of 1000 testers can be deleted at a time",
|
64
|
+
description: "Path to a file containing a comma separated list of tester emails to be deleted (or removed from a group if a group alias is specified). A maximum of 1000 testers can be deleted/removed at a time",
|
64
65
|
optional: true,
|
65
66
|
type: String),
|
67
|
+
FastlaneCore::ConfigItem.new(key: :group_alias,
|
68
|
+
env_name: "FIREBASEAPPDISTRO_REMOVE_TESTERS_GROUP_ALIAS",
|
69
|
+
description: "Alias of the group to remove the specified testers from. Testers will not be deleted from the project",
|
70
|
+
optional: true,
|
71
|
+
type: String),
|
66
72
|
FastlaneCore::ConfigItem.new(key: :service_credentials_file,
|
67
73
|
description: "Path to Google service credentials file",
|
68
74
|
optional: true,
|
@@ -83,6 +89,48 @@ module Fastlane
|
|
83
89
|
def self.is_supported?(platform)
|
84
90
|
true
|
85
91
|
end
|
92
|
+
|
93
|
+
def self.remove_testers_from_project(client, project_number, emails)
|
94
|
+
UI.message("⏳ Removing #{emails.count} testers from project #{project_number}...")
|
95
|
+
request = Google::Apis::FirebaseappdistributionV1::GoogleFirebaseAppdistroV1BatchRemoveTestersRequest.new(
|
96
|
+
emails: emails
|
97
|
+
)
|
98
|
+
|
99
|
+
begin
|
100
|
+
response = client.batch_project_tester_remove(project_name(project_number), request)
|
101
|
+
rescue Google::Apis::Error => err
|
102
|
+
case err.status_code.to_i
|
103
|
+
when 404
|
104
|
+
UI.user_error!(ErrorMessage::INVALID_PROJECT)
|
105
|
+
else
|
106
|
+
UI.crash!(err)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
UI.success("✅ #{response.emails.count} tester(s) removed successfully.")
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.remove_testers_from_group(client, project_number, group_alias, emails)
|
114
|
+
UI.message("⏳ Removing #{emails.count} testers from group #group_alias}...")
|
115
|
+
request = Google::Apis::FirebaseappdistributionV1::GoogleFirebaseAppdistroV1BatchLeaveGroupRequest.new(
|
116
|
+
emails: emails
|
117
|
+
)
|
118
|
+
|
119
|
+
begin
|
120
|
+
client.batch_project_group_leave(group_name(project_number, group_alias), request)
|
121
|
+
rescue Google::Apis::Error => err
|
122
|
+
case err.status_code.to_i
|
123
|
+
when 400
|
124
|
+
UI.user_error!(ErrorMessage::INVALID_EMAIL_ADDRESS)
|
125
|
+
when 404
|
126
|
+
UI.user_error!(ErrorMessage::INVALID_TESTER_GROUP)
|
127
|
+
else
|
128
|
+
UI.crash!(err)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
UI.success("✅ Tester(s) removed successfully.")
|
133
|
+
end
|
86
134
|
end
|
87
135
|
end
|
88
136
|
end
|