fastlane-plugin-firebase_app_distribution 0.2.9 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_action.rb +32 -27
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_add_testers_action.rb +90 -0
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_remove_testers_action.rb +88 -0
- data/lib/fastlane/plugin/firebase_app_distribution/client/aab_info.rb +42 -0
- data/lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb +146 -80
- data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_auth_client.rb +19 -10
- data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_error_message.rb +3 -3
- data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_helper.rb +9 -0
- data/lib/fastlane/plugin/firebase_app_distribution/helper/upload_status_response.rb +43 -15
- data/lib/fastlane/plugin/firebase_app_distribution/version.rb +1 -1
- metadata +5 -4
- data/lib/fastlane/plugin/firebase_app_distribution/client/aab_certificate.rb +0 -23
- data/lib/fastlane/plugin/firebase_app_distribution/client/app.rb +0 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cf7cfe204f09a005063f099ef379887cda33351ed6f1dfd1bb84773b1c989a4f
|
4
|
+
data.tar.gz: 3fc3e7c82e6506a670ab6b137ab8a4a55d968ba5f89ff0f20bcb0448ca0d2f76
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c25cb0b20720cd286c3665d8496b7c66e90121f34c2802fa7e63e52835a54aff81cc7fe2c91313af45a9e69ded27560b495917da498d0ea13a34712ae323dbbf
|
7
|
+
data.tar.gz: 1b45cb5e6657fac457d9bf34bbe4e5a624a8f912b193eaf58138d964cdb3d793aac0bf5036cd56dd997dee1b25e57ab2d30602a122e2c9f24d7171c8f7b25ccc
|
data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_action.rb
CHANGED
@@ -19,6 +19,7 @@ module Fastlane
|
|
19
19
|
params.values # to validate all inputs before looking for the ipa/apk/aab
|
20
20
|
|
21
21
|
app_id = app_id_from_params(params)
|
22
|
+
app_name = app_name_from_app_id(app_id)
|
22
23
|
platform = lane_platform || platform_from_app_id(app_id)
|
23
24
|
|
24
25
|
binary_path = get_binary_path(platform, params)
|
@@ -26,35 +27,39 @@ module Fastlane
|
|
26
27
|
UI.user_error!("Couldn't find binary at path #{binary_path}") unless File.exist?(binary_path)
|
27
28
|
binary_type = binary_type_from_path(binary_path)
|
28
29
|
|
29
|
-
auth_token = fetch_auth_token(
|
30
|
+
auth_token = fetch_auth_token(
|
31
|
+
params[:service_credentials_file], params[:firebase_cli_token], params[:debug]
|
32
|
+
)
|
30
33
|
fad_api_client = Client::FirebaseAppDistributionApiClient.new(auth_token, params[:debug])
|
31
34
|
|
32
|
-
# If binary is an AAB get
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
# If binary is an AAB, get the AAB info for this app, which includes the integration state and certificate data
|
36
|
+
if binary_type == :AAB
|
37
|
+
aab_info = fad_api_client.get_aab_info(app_name)
|
38
|
+
validate_aab_setup!(aab_info)
|
39
|
+
end
|
40
|
+
|
41
|
+
release_name = fad_api_client.upload(app_name, binary_path, platform.to_s)
|
37
42
|
|
38
|
-
if binary_type == :AAB &&
|
39
|
-
|
40
|
-
|
43
|
+
if binary_type == :AAB && aab_info && !aab_info.certs_provided?
|
44
|
+
updated_aab_info = fad_api_client.get_aab_info(app_name)
|
45
|
+
if updated_aab_info.certs_provided?
|
41
46
|
UI.message("After you upload an AAB for the first time, App Distribution " \
|
42
47
|
"generates a new test certificate. All AAB uploads are re-signed with this test " \
|
43
48
|
"certificate. Use the certificate fingerprints below to register your app " \
|
44
49
|
"signing key with API providers, such as Google Sign-In and Google Maps.\n" \
|
45
|
-
"MD-1 certificate fingerprint: #{
|
46
|
-
"SHA-1 certificate fingerprint: #{
|
47
|
-
"SHA-256 certificate fingerprint: #{
|
50
|
+
"MD-1 certificate fingerprint: #{updated_aab_info.md5_certificate_hash}\n" \
|
51
|
+
"SHA-1 certificate fingerprint: #{updated_aab_info.sha1_certificate_hash}\n" \
|
52
|
+
"SHA-256 certificate fingerprint: #{updated_aab_info.sha256_certificate_hash}")
|
48
53
|
end
|
49
54
|
end
|
50
55
|
|
51
|
-
fad_api_client.
|
56
|
+
fad_api_client.update_release_notes(release_name, release_notes(params))
|
52
57
|
|
53
58
|
testers = get_value_from_value_or_file(params[:testers], params[:testers_file])
|
54
59
|
groups = get_value_from_value_or_file(params[:groups], params[:groups_file])
|
55
60
|
emails = string_to_array(testers)
|
56
|
-
|
57
|
-
fad_api_client.
|
61
|
+
group_aliases = string_to_array(groups)
|
62
|
+
fad_api_client.distribute(release_name, emails, group_aliases)
|
58
63
|
UI.success("🎉 App Distribution upload finished successfully.")
|
59
64
|
end
|
60
65
|
|
@@ -84,6 +89,10 @@ module Fastlane
|
|
84
89
|
app_id
|
85
90
|
end
|
86
91
|
|
92
|
+
def self.app_name_from_app_id(app_id)
|
93
|
+
"projects/#{app_id.split(':')[1]}/apps/#{app_id}"
|
94
|
+
end
|
95
|
+
|
87
96
|
def self.xcode_archive_path
|
88
97
|
# prevents issues on cross-platform build environments where an XCode build happens within
|
89
98
|
# the same lane
|
@@ -126,23 +135,19 @@ module Fastlane
|
|
126
135
|
end
|
127
136
|
end
|
128
137
|
|
129
|
-
def self.
|
130
|
-
if
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
if binary_type == :AAB && app.aab_state != App::AabState::ACTIVE && app.aab_state != App::AabState::UNAVAILABLE
|
135
|
-
case app.aab_state
|
136
|
-
when App::AabState::PLAY_ACCOUNT_NOT_LINKED
|
138
|
+
def self.validate_aab_setup!(aab_info)
|
139
|
+
if aab_info && aab_info.integration_state != AabInfo::AabState::INTEGRATED && aab_info.integration_state != AabInfo::AabState::UNAVAILABLE
|
140
|
+
case aab_info.integration_state
|
141
|
+
when AabInfo::AabState::PLAY_ACCOUNT_NOT_LINKED
|
137
142
|
UI.user_error!(ErrorMessage::PLAY_ACCOUNT_NOT_LINKED)
|
138
|
-
when
|
143
|
+
when AabInfo::AabState::APP_NOT_PUBLISHED
|
139
144
|
UI.user_error!(ErrorMessage::APP_NOT_PUBLISHED)
|
140
|
-
when
|
145
|
+
when AabInfo::AabState::NO_APP_WITH_GIVEN_BUNDLE_ID_IN_PLAY_ACCOUNT
|
141
146
|
UI.user_error!(ErrorMessage::NO_APP_WITH_GIVEN_BUNDLE_ID_IN_PLAY_ACCOUNT)
|
142
|
-
when
|
147
|
+
when AabInfo::AabState::PLAY_IAS_TERMS_NOT_ACCEPTED
|
143
148
|
UI.user_error!(ErrorMessage::PLAY_IAS_TERMS_NOT_ACCEPTED)
|
144
149
|
else
|
145
|
-
UI.user_error!(ErrorMessage.aab_upload_error(
|
150
|
+
UI.user_error!(ErrorMessage.aab_upload_error(aab_info.integration_state))
|
146
151
|
end
|
147
152
|
end
|
148
153
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require 'fastlane_core/ui/ui'
|
3
|
+
|
4
|
+
require_relative '../helper/firebase_app_distribution_helper'
|
5
|
+
require_relative '../helper/firebase_app_distribution_auth_client'
|
6
|
+
|
7
|
+
module Fastlane
|
8
|
+
module Actions
|
9
|
+
class FirebaseAppDistributionAddTestersAction < Action
|
10
|
+
extend Auth::FirebaseAppDistributionAuthClient
|
11
|
+
extend Helper::FirebaseAppDistributionHelper
|
12
|
+
|
13
|
+
def self.run(params)
|
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])
|
16
|
+
|
17
|
+
if blank?(params[:emails]) && blank?(params[:file])
|
18
|
+
UI.user_error!("Must specify `emails` or `file`.")
|
19
|
+
end
|
20
|
+
|
21
|
+
emails = string_to_array(get_value_from_value_or_file(params[:emails], params[:file]))
|
22
|
+
|
23
|
+
UI.user_error!("Must pass at least one email") if blank?(emails)
|
24
|
+
|
25
|
+
if emails.count > 1000
|
26
|
+
UI.user_error!("A maximum of 1000 testers can be added at a time.")
|
27
|
+
end
|
28
|
+
|
29
|
+
UI.message("⏳ Adding #{emails.count} testers to project #{params[:project_number]}...")
|
30
|
+
|
31
|
+
fad_api_client.add_testers(params[:project_number], emails)
|
32
|
+
|
33
|
+
# The add_testers response lists all the testers from the request
|
34
|
+
# regardless of whether or not they were created or if they already
|
35
|
+
# exists so can't get an accurate count of the number of newly created testers
|
36
|
+
UI.success("✅ Tester(s) successfully added.")
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.description
|
40
|
+
"Create testers in bulk from a comma-separated list or a file"
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.authors
|
44
|
+
["Tunde Agboola"]
|
45
|
+
end
|
46
|
+
|
47
|
+
# supports markdown.
|
48
|
+
def self.details
|
49
|
+
"Create testers in bulk from a comma-separated list or a file"
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.available_options
|
53
|
+
[
|
54
|
+
FastlaneCore::ConfigItem.new(key: :project_number,
|
55
|
+
env_name: "FIREBASEAPPDISTRO_PROJECT_NUMBER",
|
56
|
+
description: "Your Firebase project number. You can find the project number in the Firebase console, on the General Settings page",
|
57
|
+
type: Integer,
|
58
|
+
optional: false),
|
59
|
+
FastlaneCore::ConfigItem.new(key: :emails,
|
60
|
+
env_name: "FIREBASEAPPDISTRO_ADD_TESTERS_EMAILS",
|
61
|
+
description: "Comma separated list of tester emails to be created. A maximum of 1000 testers can be created at a time",
|
62
|
+
optional: true,
|
63
|
+
type: String),
|
64
|
+
FastlaneCore::ConfigItem.new(key: :file,
|
65
|
+
env_name: "FIREBASEAPPDISTRO_ADD_TESTERS_FILE",
|
66
|
+
description: "Path to a file containing a comma separated list of tester emails to be created. A maximum of 1000 testers can be deleted at a time",
|
67
|
+
optional: true,
|
68
|
+
type: String),
|
69
|
+
FastlaneCore::ConfigItem.new(key: :service_credentials_file,
|
70
|
+
description: "Path to Google service credentials file",
|
71
|
+
optional: true,
|
72
|
+
type: String),
|
73
|
+
FastlaneCore::ConfigItem.new(key: :firebase_cli_token,
|
74
|
+
description: "Auth token for firebase cli",
|
75
|
+
optional: true,
|
76
|
+
type: String),
|
77
|
+
FastlaneCore::ConfigItem.new(key: :debug,
|
78
|
+
description: "Print verbose debug output",
|
79
|
+
optional: true,
|
80
|
+
default_value: false,
|
81
|
+
is_string: false)
|
82
|
+
]
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.is_supported?(platform)
|
86
|
+
true
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require 'fastlane_core/ui/ui'
|
3
|
+
|
4
|
+
require_relative '../helper/firebase_app_distribution_helper'
|
5
|
+
require_relative '../helper/firebase_app_distribution_auth_client'
|
6
|
+
|
7
|
+
module Fastlane
|
8
|
+
module Actions
|
9
|
+
class FirebaseAppDistributionRemoveTestersAction < Action
|
10
|
+
extend Auth::FirebaseAppDistributionAuthClient
|
11
|
+
extend Helper::FirebaseAppDistributionHelper
|
12
|
+
|
13
|
+
def self.run(params)
|
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])
|
16
|
+
|
17
|
+
if blank?(params[:emails]) && blank?(params[:file])
|
18
|
+
UI.user_error!("Must specify `emails` or `file`.")
|
19
|
+
end
|
20
|
+
|
21
|
+
emails = string_to_array(get_value_from_value_or_file(params[:emails], params[:file]))
|
22
|
+
|
23
|
+
UI.user_error!("Must pass at least one email") if blank?(emails)
|
24
|
+
|
25
|
+
if emails.count > 1000
|
26
|
+
UI.user_error!("A maximum of 1000 testers can be removed at a time.")
|
27
|
+
end
|
28
|
+
|
29
|
+
UI.message("⏳ Removing #{emails.count} testers from project #{params[:project_number]}...")
|
30
|
+
|
31
|
+
count = fad_api_client.remove_testers(params[:project_number], emails)
|
32
|
+
|
33
|
+
UI.success("✅ #{count} tester(s) removed successfully.")
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.description
|
37
|
+
"Delete testers in bulk from a comma-separated list or a file"
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.authors
|
41
|
+
["Tunde Agboola"]
|
42
|
+
end
|
43
|
+
|
44
|
+
# supports markdown.
|
45
|
+
def self.details
|
46
|
+
"Delete testers in bulk from a comma-separated list or a file"
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.available_options
|
50
|
+
[
|
51
|
+
FastlaneCore::ConfigItem.new(key: :project_number,
|
52
|
+
env_name: "FIREBASEAPPDISTRO_PROJECT_NUMBER",
|
53
|
+
description: "Your Firebase project number. You can find the project number in the Firebase console, on the General Settings page",
|
54
|
+
type: Integer,
|
55
|
+
optional: false),
|
56
|
+
FastlaneCore::ConfigItem.new(key: :emails,
|
57
|
+
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
|
+
optional: true,
|
60
|
+
type: String),
|
61
|
+
FastlaneCore::ConfigItem.new(key: :file,
|
62
|
+
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
|
+
optional: true,
|
65
|
+
type: String),
|
66
|
+
FastlaneCore::ConfigItem.new(key: :service_credentials_file,
|
67
|
+
description: "Path to Google service credentials file",
|
68
|
+
optional: true,
|
69
|
+
type: String),
|
70
|
+
FastlaneCore::ConfigItem.new(key: :firebase_cli_token,
|
71
|
+
description: "Auth token for firebase cli",
|
72
|
+
optional: true,
|
73
|
+
type: String),
|
74
|
+
FastlaneCore::ConfigItem.new(key: :debug,
|
75
|
+
description: "Print verbose debug output",
|
76
|
+
optional: true,
|
77
|
+
default_value: false,
|
78
|
+
is_string: false)
|
79
|
+
|
80
|
+
]
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.is_supported?(platform)
|
84
|
+
true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class AabInfo
|
2
|
+
# AAB states
|
3
|
+
class AabState
|
4
|
+
UNSPECIFIED = 'AAB_STATE_UNSPECIFIED'
|
5
|
+
PLAY_ACCOUNT_NOT_LINKED = 'PLAY_ACCOUNT_NOT_LINKED'
|
6
|
+
NO_APP_WITH_GIVEN_BUNDLE_ID_IN_PLAY_ACCOUNT = 'NO_APP_WITH_GIVEN_BUNDLE_ID_IN_PLAY_ACCOUNT'
|
7
|
+
APP_NOT_PUBLISHED = 'APP_NOT_PUBLISHED'
|
8
|
+
PLAY_IAS_TERMS_NOT_ACCEPTED = 'PLAY_IAS_TERMS_NOT_ACCEPTED'
|
9
|
+
INTEGRATED = 'INTEGRATED'
|
10
|
+
UNAVAILABLE = 'AAB_STATE_UNAVAILABLE'
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(response)
|
14
|
+
@response = response || {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def integration_state
|
18
|
+
@response[:integrationState]
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_certificate
|
22
|
+
@response[:testCertificate] || {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def md5_certificate_hash
|
26
|
+
test_certificate[:hashMd5]
|
27
|
+
end
|
28
|
+
|
29
|
+
def sha1_certificate_hash
|
30
|
+
test_certificate[:hashSha1]
|
31
|
+
end
|
32
|
+
|
33
|
+
def sha256_certificate_hash
|
34
|
+
test_certificate[:hashSha256]
|
35
|
+
end
|
36
|
+
|
37
|
+
def certs_provided?
|
38
|
+
(!md5_certificate_hash.nil? && !md5_certificate_hash.empty?) &&
|
39
|
+
(!sha1_certificate_hash.nil? && !sha1_certificate_hash.empty?) &&
|
40
|
+
(!sha256_certificate_hash.nil? && !sha256_certificate_hash.empty?)
|
41
|
+
end
|
42
|
+
end
|
data/lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'fastlane_core/ui/ui'
|
2
2
|
require_relative '../actions/firebase_app_distribution_login'
|
3
3
|
require_relative '../client/error_response'
|
4
|
-
require_relative '../client/
|
4
|
+
require_relative '../client/aab_info'
|
5
5
|
require_relative '../helper/firebase_app_distribution_helper'
|
6
6
|
|
7
7
|
module Fastlane
|
@@ -12,12 +12,13 @@ module Fastlane
|
|
12
12
|
BASE_URL = "https://firebaseappdistribution.googleapis.com"
|
13
13
|
TOKEN_CREDENTIAL_URI = "https://oauth2.googleapis.com/token"
|
14
14
|
MAX_POLLING_RETRIES = 60
|
15
|
-
POLLING_INTERVAL_SECONDS =
|
15
|
+
POLLING_INTERVAL_SECONDS = 5
|
16
16
|
|
17
17
|
AUTHORIZATION = "Authorization"
|
18
18
|
CONTENT_TYPE = "Content-Type"
|
19
19
|
APPLICATION_JSON = "application/json"
|
20
20
|
APPLICATION_OCTET_STREAM = "application/octet-stream"
|
21
|
+
CLIENT_VERSION = "X-Client-Version"
|
21
22
|
|
22
23
|
def initialize(auth_token, debug = false)
|
23
24
|
@auth_token = auth_token
|
@@ -25,49 +26,52 @@ module Fastlane
|
|
25
26
|
end
|
26
27
|
|
27
28
|
# Enables tester access to the specified app release. Skips this
|
28
|
-
# step if no testers are passed in (emails and
|
29
|
+
# step if no testers are passed in (emails and group_aliases are nil/empty).
|
29
30
|
#
|
30
31
|
# args
|
31
|
-
#
|
32
|
-
# release_id - App release ID, returned by upload_status endpoint
|
32
|
+
# release_name - App release resource name, returned by upload_status endpoint
|
33
33
|
# emails - String array of app testers' email addresses
|
34
|
-
#
|
34
|
+
# group_aliases - String array of Firebase tester group aliases
|
35
35
|
#
|
36
|
-
# Throws a user_error if emails or
|
37
|
-
def
|
38
|
-
if (emails.nil? || emails.empty?) && (
|
36
|
+
# Throws a user_error if emails or group_aliases are invalid
|
37
|
+
def distribute(release_name, emails, group_aliases)
|
38
|
+
if (emails.nil? || emails.empty?) && (group_aliases.nil? || group_aliases.empty?)
|
39
39
|
UI.success("✅ No testers passed in. Skipping this step.")
|
40
40
|
return
|
41
41
|
end
|
42
|
-
payload = {
|
42
|
+
payload = { testerEmails: emails, groupAliases: group_aliases }
|
43
43
|
begin
|
44
|
-
connection.post(
|
44
|
+
connection.post(distribute_url(release_name), payload.to_json) do |request|
|
45
45
|
request.headers[AUTHORIZATION] = "Bearer " + @auth_token
|
46
46
|
request.headers[CONTENT_TYPE] = APPLICATION_JSON
|
47
47
|
end
|
48
48
|
rescue Faraday::ClientError
|
49
|
-
UI.user_error!("#{ErrorMessage::INVALID_TESTERS} \nEmails: #{emails} \nGroups: #{
|
49
|
+
UI.user_error!("#{ErrorMessage::INVALID_TESTERS} \nEmails: #{emails} \nGroups: #{group_aliases}")
|
50
50
|
end
|
51
51
|
UI.success("✅ Added testers/groups.")
|
52
52
|
end
|
53
53
|
|
54
|
-
#
|
54
|
+
# Update release notes for the specified app release. Skips this
|
55
55
|
# step if no notes are passed in (release_notes is nil/empty).
|
56
56
|
#
|
57
57
|
# args
|
58
|
-
#
|
59
|
-
# release_id - App release ID, returned by upload_status endpoint
|
58
|
+
# release_name - App release resource name, returned by upload_status endpoint
|
60
59
|
# release_notes - String of notes for this release
|
61
60
|
#
|
62
61
|
# Throws a user_error if the release_notes are invalid
|
63
|
-
def
|
64
|
-
payload = { releaseNotes: { releaseNotes: release_notes } }
|
62
|
+
def update_release_notes(release_name, release_notes)
|
65
63
|
if release_notes.nil? || release_notes.empty?
|
66
64
|
UI.success("✅ No release notes passed in. Skipping this step.")
|
67
65
|
return
|
68
66
|
end
|
69
67
|
begin
|
70
|
-
|
68
|
+
payload = {
|
69
|
+
name: release_name,
|
70
|
+
releaseNotes: {
|
71
|
+
text: release_notes
|
72
|
+
}
|
73
|
+
}
|
74
|
+
connection.patch(update_release_notes_url(release_name), payload.to_json) do |request|
|
71
75
|
request.headers[AUTHORIZATION] = "Bearer " + @auth_token
|
72
76
|
request.headers[CONTENT_TYPE] = APPLICATION_JSON
|
73
77
|
end
|
@@ -78,42 +82,42 @@ module Fastlane
|
|
78
82
|
UI.success("✅ Posted release notes.")
|
79
83
|
end
|
80
84
|
|
81
|
-
# Get
|
85
|
+
# Get AAB info (Android apps only)
|
82
86
|
#
|
83
87
|
# args
|
84
|
-
#
|
88
|
+
# app_name - Firebase App resource name
|
85
89
|
#
|
86
90
|
# Throws a user_error if the app hasn't been onboarded to App Distribution
|
87
|
-
def
|
91
|
+
def get_aab_info(app_name)
|
88
92
|
begin
|
89
|
-
response = connection.get(
|
93
|
+
response = connection.get(aab_info_url(app_name)) do |request|
|
90
94
|
request.headers[AUTHORIZATION] = "Bearer " + @auth_token
|
91
95
|
end
|
92
96
|
rescue Faraday::ResourceNotFound
|
93
|
-
UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{
|
97
|
+
UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{app_name}")
|
94
98
|
end
|
95
99
|
|
96
|
-
|
100
|
+
AabInfo.new(response.body)
|
97
101
|
end
|
98
102
|
|
99
103
|
# Uploads the app binary to the Firebase API
|
100
104
|
#
|
101
105
|
# args
|
102
|
-
#
|
106
|
+
# app_name - Firebase App resource name
|
103
107
|
# binary_path - Absolute path to your app's aab/apk/ipa file
|
104
108
|
# platform - 'android' or 'ios'
|
105
109
|
#
|
106
110
|
# Throws a user_error if the binary file does not exist
|
107
|
-
def upload_binary(
|
108
|
-
connection.post(binary_upload_url(
|
111
|
+
def upload_binary(app_name, binary_path, platform)
|
112
|
+
response = connection.post(binary_upload_url(app_name), read_binary(binary_path)) do |request|
|
109
113
|
request.headers[AUTHORIZATION] = "Bearer " + @auth_token
|
110
114
|
request.headers[CONTENT_TYPE] = APPLICATION_OCTET_STREAM
|
111
|
-
request.headers[
|
112
|
-
request.headers["X-
|
113
|
-
request.headers["X-
|
114
|
-
request.headers["X-GOOG-UPLOAD-FILE-NAME"] = File.basename(binary_path)
|
115
|
-
request.headers["X-GOOG-UPLOAD-PROTOCOL"] = "raw"
|
115
|
+
request.headers[CLIENT_VERSION] = client_version_header_value
|
116
|
+
request.headers["X-Goog-Upload-File-Name"] = File.basename(binary_path)
|
117
|
+
request.headers["X-Goog-Upload-Protocol"] = "raw"
|
116
118
|
end
|
119
|
+
|
120
|
+
response.body[:name] || ''
|
117
121
|
rescue Errno::ENOENT # Raised when binary_path file does not exist
|
118
122
|
binary_type = binary_type_from_path(binary_path)
|
119
123
|
UI.user_error!("#{ErrorMessage.binary_not_found(binary_type)}: #{binary_path}")
|
@@ -123,66 +127,67 @@ module Fastlane
|
|
123
127
|
# Takes at least POLLING_INTERVAL_SECONDS between polling get_upload_status
|
124
128
|
#
|
125
129
|
# args
|
126
|
-
#
|
127
|
-
# app_id - Firebase app ID
|
130
|
+
# app_name - Firebase App resource name
|
128
131
|
# binary_path - Absolute path to your app's aab/apk/ipa file
|
129
132
|
#
|
130
|
-
# Returns the
|
133
|
+
# Returns the release_name of the uploaded release.
|
131
134
|
#
|
132
135
|
# Crashes if the number of polling retries exceeds MAX_POLLING_RETRIES or if the binary cannot
|
133
136
|
# be uploaded.
|
134
|
-
def upload(
|
137
|
+
def upload(app_name, binary_path, platform)
|
135
138
|
binary_type = binary_type_from_path(binary_path)
|
136
139
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
if upload_status_response.success? || upload_status_response.already_uploaded?
|
149
|
-
UI.success("✅ Uploaded the #{binary_type}.")
|
140
|
+
UI.message("⌛ Uploading the #{binary_type}.")
|
141
|
+
operation_name = upload_binary(app_name, binary_path, platform)
|
142
|
+
|
143
|
+
upload_status_response = get_upload_status(operation_name)
|
144
|
+
MAX_POLLING_RETRIES.times do
|
145
|
+
if upload_status_response.success?
|
146
|
+
if upload_status_response.release_updated?
|
147
|
+
UI.success("✅ Uploaded #{binary_type} successfully; updated provisioning profile of existing release #{upload_status_response.release_version}.")
|
148
|
+
break
|
149
|
+
elsif upload_status_response.release_unmodified?
|
150
|
+
UI.success("✅ The same #{binary_type} was found in release #{upload_status_response.release_version} with no changes, skipping.")
|
150
151
|
break
|
151
|
-
elsif upload_status_response.in_progress?
|
152
|
-
sleep(POLLING_INTERVAL_SECONDS)
|
153
152
|
else
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
153
|
+
UI.success("✅ Uploaded #{binary_type} successfully and created release #{upload_status_response.release_version}.")
|
154
|
+
end
|
155
|
+
break
|
156
|
+
elsif upload_status_response.in_progress?
|
157
|
+
sleep(POLLING_INTERVAL_SECONDS)
|
158
|
+
upload_status_response = get_upload_status(operation_name)
|
159
|
+
else
|
160
|
+
if !upload_status_response.error_message.nil?
|
161
|
+
UI.user_error!("#{ErrorMessage.upload_binary_error(binary_type)}: #{upload_status_response.error_message}")
|
162
|
+
else
|
163
|
+
UI.user_error!(ErrorMessage.upload_binary_error(binary_type))
|
159
164
|
end
|
160
|
-
end
|
161
|
-
unless upload_status_response.success?
|
162
|
-
UI.crash!("It took longer than expected to process your #{binary_type}, please try again.")
|
163
165
|
end
|
164
166
|
end
|
165
|
-
upload_status_response.
|
167
|
+
unless upload_status_response.success?
|
168
|
+
UI.crash!("It took longer than expected to process your #{binary_type}, please try again.")
|
169
|
+
end
|
170
|
+
|
171
|
+
upload_status_response.release_name
|
166
172
|
end
|
167
173
|
|
168
174
|
# Fetches the status of an uploaded binary
|
169
175
|
#
|
170
176
|
# args
|
171
|
-
#
|
172
|
-
# upload_token - URL encoded upload token
|
177
|
+
# operation_name - Upload operation name (with binary hash)
|
173
178
|
#
|
174
|
-
# Returns the
|
175
|
-
def get_upload_status(
|
176
|
-
response = connection.get(upload_status_url(
|
179
|
+
# Returns the `done` status, as well as a release, error, or nil
|
180
|
+
def get_upload_status(operation_name)
|
181
|
+
response = connection.get(upload_status_url(operation_name)) do |request|
|
177
182
|
request.headers[AUTHORIZATION] = "Bearer " + @auth_token
|
178
183
|
end
|
179
|
-
|
184
|
+
UploadStatusResponse.new(response.body)
|
180
185
|
end
|
181
186
|
|
182
187
|
# Get tester UDIDs
|
183
188
|
#
|
184
189
|
# args
|
185
|
-
#
|
190
|
+
# app_name - Firebase App resource name
|
186
191
|
#
|
187
192
|
# Returns a list of hashes containing tester device info
|
188
193
|
def get_udids(app_id)
|
@@ -196,35 +201,96 @@ module Fastlane
|
|
196
201
|
response.body[:testerUdids] || []
|
197
202
|
end
|
198
203
|
|
204
|
+
# Create testers
|
205
|
+
#
|
206
|
+
# args
|
207
|
+
# project_number - Firebase project number
|
208
|
+
# emails - An array of emails to be created as testers. A maximum of
|
209
|
+
# 1000 testers can be created at a time.
|
210
|
+
#
|
211
|
+
def add_testers(project_number, emails)
|
212
|
+
payload = { emails: emails }
|
213
|
+
connection.post(add_testers_url(project_number), payload.to_json) do |request|
|
214
|
+
request.headers[AUTHORIZATION] = "Bearer " + @auth_token
|
215
|
+
request.headers[CONTENT_TYPE] = APPLICATION_JSON
|
216
|
+
request.headers[CLIENT_VERSION] = client_version_header_value
|
217
|
+
end
|
218
|
+
rescue Faraday::BadRequestError
|
219
|
+
UI.user_error!(ErrorMessage::INVALID_EMAIL_ADDRESS)
|
220
|
+
rescue Faraday::ResourceNotFound
|
221
|
+
UI.user_error!(ErrorMessage::INVALID_PROJECT)
|
222
|
+
rescue Faraday::ClientError => e
|
223
|
+
if e.response_status == 429
|
224
|
+
UI.user_error!(ErrorMessage::TESTER_LIMIT_VIOLATION)
|
225
|
+
else
|
226
|
+
raise e
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# Delete testers
|
231
|
+
#
|
232
|
+
# args
|
233
|
+
# project_number - Firebase project number
|
234
|
+
# emails - An array of emails to be deleted as testers. A maximum of
|
235
|
+
# 1000 testers can be deleted at a time.
|
236
|
+
#
|
237
|
+
# Returns the number of testers that were deleted
|
238
|
+
def remove_testers(project_number, emails)
|
239
|
+
payload = { emails: emails }
|
240
|
+
response = connection.post(remove_testers_url(project_number), payload.to_json) do |request|
|
241
|
+
request.headers[AUTHORIZATION] = "Bearer " + @auth_token
|
242
|
+
request.headers[CONTENT_TYPE] = APPLICATION_JSON
|
243
|
+
request.headers[CLIENT_VERSION] = client_version_header_value
|
244
|
+
end
|
245
|
+
response.body[:emails] ? response.body[:emails].count : 0
|
246
|
+
rescue Faraday::ResourceNotFound
|
247
|
+
UI.user_error!(ErrorMessage::INVALID_PROJECT)
|
248
|
+
end
|
249
|
+
|
199
250
|
private
|
200
251
|
|
201
|
-
def
|
252
|
+
def client_version_header_value
|
253
|
+
"fastlane/#{Fastlane::FirebaseAppDistribution::VERSION}"
|
254
|
+
end
|
255
|
+
|
256
|
+
def v1alpha_apps_url(app_id)
|
202
257
|
"/v1alpha/apps/#{app_id}"
|
203
258
|
end
|
204
259
|
|
205
|
-
def
|
206
|
-
"
|
260
|
+
def v1_apps_url(app_name)
|
261
|
+
"/v1/#{app_name}"
|
262
|
+
end
|
263
|
+
|
264
|
+
def aab_info_url(app_name)
|
265
|
+
"#{v1_apps_url(app_name)}/aabInfo"
|
207
266
|
end
|
208
267
|
|
209
|
-
def
|
210
|
-
"
|
268
|
+
def update_release_notes_url(release_name)
|
269
|
+
"/v1/#{release_name}?updateMask=release_notes.text"
|
211
270
|
end
|
212
271
|
|
213
|
-
def
|
214
|
-
"/
|
272
|
+
def distribute_url(release_name)
|
273
|
+
"/v1/#{release_name}:distribute"
|
215
274
|
end
|
216
275
|
|
217
|
-
def
|
218
|
-
"#{v1_apps_url(
|
276
|
+
def binary_upload_url(app_name)
|
277
|
+
"/upload#{v1_apps_url(app_name)}/releases:upload"
|
278
|
+
end
|
279
|
+
|
280
|
+
def upload_status_url(operation_name)
|
281
|
+
"/v1/#{operation_name}"
|
219
282
|
end
|
220
283
|
|
221
284
|
def get_udids_url(app_id)
|
222
|
-
"#{
|
285
|
+
"#{v1alpha_apps_url(app_id)}/testers:getTesterUdids"
|
286
|
+
end
|
287
|
+
|
288
|
+
def add_testers_url(project_number)
|
289
|
+
"/v1/projects/#{project_number}/testers:batchAdd"
|
223
290
|
end
|
224
291
|
|
225
|
-
def
|
226
|
-
|
227
|
-
CGI.escape("projects/#{project_number}/apps/#{app_id}/releases/-/binaries/#{binary_hash}")
|
292
|
+
def remove_testers_url(project_number)
|
293
|
+
"/v1/projects/#{project_number}/testers:batchRemove"
|
228
294
|
end
|
229
295
|
|
230
296
|
def connection
|
data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_auth_client.rb
CHANGED
@@ -13,28 +13,29 @@ module Fastlane
|
|
13
13
|
# google_service_path - Absolute path to the Google service account file
|
14
14
|
# firebase_cli_token - Firebase CLI refresh token from login action or
|
15
15
|
# CI environment
|
16
|
+
# debug - Whether to enable debug-level logging
|
16
17
|
#
|
17
18
|
# env variables
|
18
19
|
# GOOGLE_APPLICATION_CREDENTIALS - see google_service_path
|
19
20
|
# FIREBASE_TOKEN - see firebase_cli_token
|
20
21
|
#
|
21
22
|
# Crashes if given invalid or missing credentials
|
22
|
-
def fetch_auth_token(google_service_path, firebase_cli_token)
|
23
|
+
def fetch_auth_token(google_service_path, firebase_cli_token, debug = false)
|
23
24
|
if !google_service_path.nil? && !google_service_path.empty?
|
24
25
|
UI.message("Authenticating with --service_credentials_file path parameter: #{google_service_path}")
|
25
|
-
token = service_account(google_service_path)
|
26
|
+
token = service_account(google_service_path, debug)
|
26
27
|
elsif !firebase_cli_token.nil? && !firebase_cli_token.empty?
|
27
28
|
UI.message("Authenticating with --firebase_cli_token parameter")
|
28
|
-
token = firebase_token(firebase_cli_token)
|
29
|
+
token = firebase_token(firebase_cli_token, debug)
|
29
30
|
elsif !ENV["FIREBASE_TOKEN"].nil? && !ENV["FIREBASE_TOKEN"].empty?
|
30
31
|
UI.message("Authenticating with FIREBASE_TOKEN environment variable")
|
31
|
-
token = firebase_token(ENV["FIREBASE_TOKEN"])
|
32
|
+
token = firebase_token(ENV["FIREBASE_TOKEN"], debug)
|
32
33
|
elsif !ENV["GOOGLE_APPLICATION_CREDENTIALS"].nil? && !ENV["GOOGLE_APPLICATION_CREDENTIALS"].empty?
|
33
34
|
UI.message("Authenticating with GOOGLE_APPLICATION_CREDENTIALS environment variable: #{ENV['GOOGLE_APPLICATION_CREDENTIALS']}")
|
34
|
-
token = service_account(ENV["GOOGLE_APPLICATION_CREDENTIALS"])
|
35
|
+
token = service_account(ENV["GOOGLE_APPLICATION_CREDENTIALS"], debug)
|
35
36
|
elsif (refresh_token = refresh_token_from_firebase_tools)
|
36
37
|
UI.message("No authentication method specified. Using cached Firebase CLI credentials.")
|
37
|
-
token = firebase_token(refresh_token)
|
38
|
+
token = firebase_token(refresh_token, debug)
|
38
39
|
else
|
39
40
|
UI.user_error!(ErrorMessage::MISSING_CREDENTIALS)
|
40
41
|
end
|
@@ -62,7 +63,7 @@ module Fastlane
|
|
62
63
|
end
|
63
64
|
end
|
64
65
|
|
65
|
-
def firebase_token(refresh_token)
|
66
|
+
def firebase_token(refresh_token, debug)
|
66
67
|
client = Signet::OAuth2::Client.new(
|
67
68
|
token_credential_uri: TOKEN_CREDENTIAL_URI,
|
68
69
|
client_id: Fastlane::Actions::FirebaseAppDistributionLoginAction::CLIENT_ID,
|
@@ -71,11 +72,12 @@ module Fastlane
|
|
71
72
|
)
|
72
73
|
client.fetch_access_token!
|
73
74
|
client.access_token
|
74
|
-
rescue Signet::AuthorizationError
|
75
|
+
rescue Signet::AuthorizationError => error
|
76
|
+
log_authorization_error_details(error) if debug
|
75
77
|
UI.user_error!(ErrorMessage::REFRESH_TOKEN_ERROR)
|
76
78
|
end
|
77
79
|
|
78
|
-
def service_account(google_service_path)
|
80
|
+
def service_account(google_service_path, debug)
|
79
81
|
service_account_credentials = Google::Auth::ServiceAccountCredentials.make_creds(
|
80
82
|
json_key_io: File.open(google_service_path),
|
81
83
|
scope: Fastlane::Actions::FirebaseAppDistributionLoginAction::SCOPE
|
@@ -83,9 +85,16 @@ module Fastlane
|
|
83
85
|
service_account_credentials.fetch_access_token!["access_token"]
|
84
86
|
rescue Errno::ENOENT
|
85
87
|
UI.user_error!("#{ErrorMessage::SERVICE_CREDENTIALS_NOT_FOUND}: #{google_service_path}")
|
86
|
-
rescue Signet::AuthorizationError
|
88
|
+
rescue Signet::AuthorizationError => error
|
89
|
+
log_authorization_error_details(error) if debug
|
87
90
|
UI.user_error!("#{ErrorMessage::SERVICE_CREDENTIALS_ERROR}: #{google_service_path}")
|
88
91
|
end
|
92
|
+
|
93
|
+
def log_authorization_error_details(error)
|
94
|
+
UI.error("Error fetching access token:")
|
95
|
+
UI.error(error.message)
|
96
|
+
UI.error("Response status: #{error.response.status}")
|
97
|
+
end
|
89
98
|
end
|
90
99
|
end
|
91
100
|
end
|
data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_error_message.rb
CHANGED
@@ -7,19 +7,19 @@ module ErrorMessage
|
|
7
7
|
UPLOAD_TESTERS_ERROR = "App Distribution halted because it had a problem adding testers/groups"
|
8
8
|
GET_RELEASE_TIMEOUT = "App Distribution failed to fetch release information"
|
9
9
|
REFRESH_TOKEN_ERROR = "App Distribution could not generate credentials from the refresh token specified."
|
10
|
-
GET_APP_ERROR = "App Distribution failed to fetch app information"
|
11
10
|
APP_NOT_ONBOARDED_ERROR = "App Distribution not onboarded"
|
12
|
-
GET_APP_NO_CONTACT_EMAIL_ERROR = "App Distribution could not find a contact email associated with this app. Contact Email"
|
13
11
|
INVALID_APP_ID = "App Distribution could not find your app. Make sure to onboard your app by pressing the \"Get started\" button on the App Distribution page in the Firebase console: https://console.firebase.google.com/project/_/appdistribution. App ID"
|
12
|
+
INVALID_PROJECT = "App Distribution could not find your Firebase project. Make sure to onboard an app in your project by pressing the \"Get started\" button on the App Distribution page in the Firebase console: https://console.firebase.google.com/project/_/appdistribution."
|
14
13
|
INVALID_PATH = "Could not read content from"
|
15
14
|
INVALID_TESTERS = "Could not enable access for testers. Check that the groups exist and the tester emails are formatted correctly"
|
16
|
-
INVALID_RELEASE_ID = "App distribution failed to fetch release with id"
|
17
15
|
INVALID_RELEASE_NOTES = "Failed to add release notes"
|
18
16
|
SERVICE_CREDENTIALS_ERROR = "App Distribution could not generate credentials from the service credentials file specified. Service Account Path"
|
19
17
|
PLAY_ACCOUNT_NOT_LINKED = "This project is not linked to a Google Play account."
|
20
18
|
APP_NOT_PUBLISHED = "This app is not published in the Google Play console."
|
21
19
|
NO_APP_WITH_GIVEN_BUNDLE_ID_IN_PLAY_ACCOUNT = "App with matching package name does not exist in Google Play."
|
22
20
|
PLAY_IAS_TERMS_NOT_ACCEPTED = "You must accept the Play Internal App Sharing (IAS) terms to upload AABs."
|
21
|
+
INVALID_EMAIL_ADDRESS = "You passed an invalid email address."
|
22
|
+
TESTER_LIMIT_VIOLATION = "Creating testers would exceed tester limit"
|
23
23
|
|
24
24
|
def self.aab_upload_error(aab_state)
|
25
25
|
"Failed to process the AAB: #{aab_state}"
|
data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_helper.rb
CHANGED
@@ -44,6 +44,15 @@ module Fastlane
|
|
44
44
|
UI.shell_error!("can't extract GOOGLE_APP_ID") if identifier.empty?
|
45
45
|
return identifier
|
46
46
|
end
|
47
|
+
|
48
|
+
def blank?(value)
|
49
|
+
# Taken from https://apidock.com/rails/Object/blank%3F
|
50
|
+
value.respond_to?(:empty?) ? value.empty? : !value
|
51
|
+
end
|
52
|
+
|
53
|
+
def present?(value)
|
54
|
+
!blank?(value)
|
55
|
+
end
|
47
56
|
end
|
48
57
|
end
|
49
58
|
end
|
@@ -3,35 +3,63 @@ class UploadStatusResponse
|
|
3
3
|
@response_json_hash = response_json_hash
|
4
4
|
end
|
5
5
|
|
6
|
+
def done
|
7
|
+
!!@response_json_hash[:done]
|
8
|
+
end
|
9
|
+
|
10
|
+
def response
|
11
|
+
@response_json_hash[:response]
|
12
|
+
end
|
13
|
+
|
14
|
+
def release
|
15
|
+
response ? response[:release] : nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def release_name
|
19
|
+
release ? release[:name] : nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def release_version
|
23
|
+
if release
|
24
|
+
if release[:displayVersion] && release[:buildVersion]
|
25
|
+
"#{release[:displayVersion]} (#{release[:buildVersion]})"
|
26
|
+
elsif release[:displayVersion]
|
27
|
+
release[:displayVersion]
|
28
|
+
else
|
29
|
+
release[:buildVersion]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
6
34
|
def status
|
7
|
-
|
35
|
+
response ? response[:result] : nil
|
8
36
|
end
|
9
37
|
|
10
|
-
def
|
11
|
-
|
38
|
+
def error
|
39
|
+
@response_json_hash[:error]
|
12
40
|
end
|
13
41
|
|
14
|
-
def
|
15
|
-
|
42
|
+
def error_message
|
43
|
+
error ? error[:message] : nil
|
16
44
|
end
|
17
45
|
|
18
|
-
def
|
19
|
-
|
46
|
+
def success?
|
47
|
+
done && !!release
|
20
48
|
end
|
21
49
|
|
22
|
-
def
|
23
|
-
|
50
|
+
def in_progress?
|
51
|
+
!done
|
24
52
|
end
|
25
53
|
|
26
|
-
def
|
27
|
-
|
54
|
+
def error?
|
55
|
+
done && message
|
28
56
|
end
|
29
57
|
|
30
|
-
def
|
31
|
-
|
58
|
+
def release_updated?
|
59
|
+
done && status == 'RELEASE_UPDATED'
|
32
60
|
end
|
33
61
|
|
34
|
-
def
|
35
|
-
|
62
|
+
def release_unmodified?
|
63
|
+
done && status == 'RELEASE_UNMODIFIED'
|
36
64
|
end
|
37
65
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane-plugin-firebase_app_distribution
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefan Natchev
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2021-
|
13
|
+
date: 2021-08-27 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: pry
|
@@ -151,10 +151,11 @@ files:
|
|
151
151
|
- README.md
|
152
152
|
- lib/fastlane/plugin/firebase_app_distribution.rb
|
153
153
|
- lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_action.rb
|
154
|
+
- lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_add_testers_action.rb
|
154
155
|
- lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_get_udids.rb
|
155
156
|
- lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_login.rb
|
156
|
-
- lib/fastlane/plugin/firebase_app_distribution/
|
157
|
-
- lib/fastlane/plugin/firebase_app_distribution/client/
|
157
|
+
- lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_remove_testers_action.rb
|
158
|
+
- lib/fastlane/plugin/firebase_app_distribution/client/aab_info.rb
|
158
159
|
- lib/fastlane/plugin/firebase_app_distribution/client/error_response.rb
|
159
160
|
- lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb
|
160
161
|
- lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_auth_client.rb
|
@@ -1,23 +0,0 @@
|
|
1
|
-
class AabCertificate
|
2
|
-
def initialize(response)
|
3
|
-
@response = response || {}
|
4
|
-
end
|
5
|
-
|
6
|
-
def md5_certificate_hash
|
7
|
-
@response[:certificateHashMd5]
|
8
|
-
end
|
9
|
-
|
10
|
-
def sha1_certificate_hash
|
11
|
-
@response[:certificateHashSha1]
|
12
|
-
end
|
13
|
-
|
14
|
-
def sha256_certificate_hash
|
15
|
-
@response[:certificateHashSha256]
|
16
|
-
end
|
17
|
-
|
18
|
-
def empty?
|
19
|
-
(md5_certificate_hash.nil? || md5_certificate_hash.empty?) &&
|
20
|
-
(sha1_certificate_hash.nil? || sha1_certificate_hash.empty?) &&
|
21
|
-
(sha256_certificate_hash.nil? || sha256_certificate_hash.empty?)
|
22
|
-
end
|
23
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
require_relative 'aab_certificate'
|
2
|
-
|
3
|
-
class App
|
4
|
-
# AAB states
|
5
|
-
class AabState
|
6
|
-
UNSPECIFIED = "AAB_STATE_UNSPECIFIED"
|
7
|
-
PLAY_ACCOUNT_NOT_LINKED = "PLAY_ACCOUNT_NOT_LINKED"
|
8
|
-
NO_APP_WITH_GIVEN_BUNDLE_ID_IN_PLAY_ACCOUNT = "NO_APP_WITH_GIVEN_BUNDLE_ID_IN_PLAY_ACCOUNT"
|
9
|
-
APP_NOT_PUBLISHED = "APP_NOT_PUBLISHED"
|
10
|
-
PLAY_IAS_TERMS_NOT_ACCEPTED = "PLAY_IAS_TERMS_NOT_ACCEPTED"
|
11
|
-
ACTIVE = "ACTIVE"
|
12
|
-
UNAVAILABLE = "AAB_STATE_UNAVAILABLE"
|
13
|
-
end
|
14
|
-
|
15
|
-
attr_reader :aab_certificate
|
16
|
-
|
17
|
-
def initialize(response)
|
18
|
-
@response = response
|
19
|
-
@aab_certificate = AabCertificate.new(response[:aabCertificate])
|
20
|
-
end
|
21
|
-
|
22
|
-
def app_id
|
23
|
-
@response[:appId]
|
24
|
-
end
|
25
|
-
|
26
|
-
def project_number
|
27
|
-
@response[:projectNumber]
|
28
|
-
end
|
29
|
-
|
30
|
-
def contact_email
|
31
|
-
@response[:contactEmail]
|
32
|
-
end
|
33
|
-
|
34
|
-
def aab_state
|
35
|
-
@response[:aabState]
|
36
|
-
end
|
37
|
-
end
|