fastlane-plugin-firebase_app_distribution 0.2.0.pre.1 → 0.2.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 +5 -5
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_action.rb +23 -36
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_login.rb +6 -6
- data/lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb +78 -30
- data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_auth_client.rb +61 -18
- data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_error_message.rb +21 -8
- data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_helper.rb +5 -0
- data/lib/fastlane/plugin/firebase_app_distribution/helper/upload_status_response.rb +13 -1
- data/lib/fastlane/plugin/firebase_app_distribution/version.rb +1 -1
- metadata +9 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5069b6e632432b25f206acbd47973be4326f582b8e555c7783c26638a6da9c21
|
4
|
+
data.tar.gz: a8f5e1ff46a220466eaa79e2e1072532b8715c79297462ac064e41da330e4c6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 93749ffc7b47c65964da87b9db79925d71f1a0fc81bc0f33bd8710c8af34b934d19c7aad04f1e79bed2f90000190485ed07b86b1fb623cccbd1a81839d0ccdff
|
7
|
+
data.tar.gz: ebba43e6bc7de7d8742bab36a7a8139b176f1cbfdf2130bdddd2131e114448077f51b3458c308ede0a828335a58ad21cdcfa7fc9a5ca1955f479919868236505
|
data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_action.rb
CHANGED
@@ -13,7 +13,6 @@ require_relative '../helper/firebase_app_distribution_auth_client'
|
|
13
13
|
module Fastlane
|
14
14
|
module Actions
|
15
15
|
class FirebaseAppDistributionAction < Action
|
16
|
-
DEFAULT_FIREBASE_CLI_PATH = `which firebase`
|
17
16
|
FIREBASECMD_ACTION = "appdistribution:distribute".freeze
|
18
17
|
|
19
18
|
extend Auth::FirebaseAppDistributionAuthClient
|
@@ -21,10 +20,10 @@ module Fastlane
|
|
21
20
|
|
22
21
|
def self.run(params)
|
23
22
|
params.values # to validate all inputs before looking for the ipa/apk
|
24
|
-
auth_token = fetch_auth_token(params[:service_credentials_file])
|
25
|
-
fad_api_client = Client::FirebaseAppDistributionApiClient.new(auth_token)
|
26
|
-
platform = Actions.lane_context[Actions::SharedValues::PLATFORM_NAME]
|
23
|
+
auth_token = fetch_auth_token(params[:service_credentials_file], params[:firebase_cli_token])
|
27
24
|
binary_path = params[:ipa_path] || params[:apk_path]
|
25
|
+
platform = lane_platform || platform_from_path(binary_path)
|
26
|
+
fad_api_client = Client::FirebaseAppDistributionApiClient.new(auth_token, platform)
|
28
27
|
|
29
28
|
if params[:app] # Set app_id if it is specified as a parameter
|
30
29
|
app_id = params[:app]
|
@@ -38,7 +37,7 @@ module Fastlane
|
|
38
37
|
if app_id.nil?
|
39
38
|
UI.crash!(ErrorMessage::MISSING_APP_ID)
|
40
39
|
end
|
41
|
-
release_id = fad_api_client.upload(app_id, binary_path)
|
40
|
+
release_id = fad_api_client.upload(app_id, binary_path, platform.to_s)
|
42
41
|
if release_id.nil?
|
43
42
|
return
|
44
43
|
end
|
@@ -51,7 +50,7 @@ module Fastlane
|
|
51
50
|
emails = string_to_array(testers)
|
52
51
|
group_ids = string_to_array(groups)
|
53
52
|
fad_api_client.enable_access(app_id, release_id, emails, group_ids)
|
54
|
-
UI.success("App Distribution upload finished successfully")
|
53
|
+
UI.success("🎉 App Distribution upload finished successfully.")
|
55
54
|
end
|
56
55
|
|
57
56
|
def self.description
|
@@ -67,14 +66,26 @@ module Fastlane
|
|
67
66
|
"Release your beta builds with Firebase App Distribution"
|
68
67
|
end
|
69
68
|
|
70
|
-
def self.
|
71
|
-
|
69
|
+
def self.lane_platform
|
70
|
+
Actions.lane_context[Actions::SharedValues::PLATFORM_NAME]
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.platform_from_path(binary_path)
|
74
|
+
return nil unless binary_path
|
75
|
+
case binary_path.split('.').last
|
76
|
+
when 'ipa'
|
77
|
+
:ios
|
78
|
+
when 'apk'
|
79
|
+
:android
|
80
|
+
end
|
81
|
+
end
|
72
82
|
|
73
|
-
|
83
|
+
def self.available_options
|
84
|
+
if lane_platform == :ios || lane_platform.nil?
|
74
85
|
ipa_path_default = Dir["*.ipa"].sort_by { |x| File.mtime(x) }.last
|
75
86
|
end
|
76
87
|
|
77
|
-
if
|
88
|
+
if lane_platform == :android
|
78
89
|
apk_path_default = Dir["*.apk"].last || Dir[File.join("app", "build", "outputs", "apk", "app-release.apk")].last
|
79
90
|
end
|
80
91
|
|
@@ -105,22 +116,10 @@ module Fastlane
|
|
105
116
|
optional: true,
|
106
117
|
type: String),
|
107
118
|
FastlaneCore::ConfigItem.new(key: :firebase_cli_path,
|
119
|
+
deprecated: "This plugin no longer uses the Firebase CLI",
|
108
120
|
env_name: "FIREBASEAPPDISTRO_FIREBASE_CLI_PATH",
|
109
121
|
description: "The absolute path of the firebase cli command",
|
110
|
-
|
111
|
-
default_value_dynamic: true,
|
112
|
-
optional: false,
|
113
|
-
type: String,
|
114
|
-
verify_block: proc do |value|
|
115
|
-
value.chomp!
|
116
|
-
if value.to_s == "" || !File.exist?(value)
|
117
|
-
UI.user_error!("firebase_cli_path: missing path to firebase cli tool. Please install firebase in $PATH or specify path")
|
118
|
-
end
|
119
|
-
|
120
|
-
unless is_firebasecmd_supported?(value)
|
121
|
-
UI.user_error!("firebase_cli_path: `#{value}` does not support the `#{FIREBASECMD_ACTION}` command. Please download (https://appdistro.page.link/firebase-cli-download) or specify the path to the correct version of firebse")
|
122
|
-
end
|
123
|
-
end),
|
122
|
+
type: String),
|
124
123
|
FastlaneCore::ConfigItem.new(key: :groups,
|
125
124
|
env_name: "FIREBASEAPPDISTRO_GROUPS",
|
126
125
|
description: "The groups used for distribution, separated by commas",
|
@@ -187,18 +186,6 @@ module Fastlane
|
|
187
186
|
CODE
|
188
187
|
]
|
189
188
|
end
|
190
|
-
|
191
|
-
## TODO: figure out if we can surpress color output.
|
192
|
-
def self.is_firebasecmd_supported?(cmd)
|
193
|
-
outerr, status = Open3.capture2e(cmd, "--non-interactive", FIREBASECMD_ACTION, "--help")
|
194
|
-
return false unless status.success?
|
195
|
-
|
196
|
-
if outerr =~ /is not a Firebase command/
|
197
|
-
return false
|
198
|
-
end
|
199
|
-
|
200
|
-
true
|
201
|
-
end
|
202
189
|
end
|
203
190
|
end
|
204
191
|
end
|
data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_login.rb
CHANGED
@@ -16,20 +16,20 @@ module Fastlane
|
|
16
16
|
authorizer = Google::Auth::UserAuthorizer.new(client_id, SCOPE, nil)
|
17
17
|
url = authorizer.get_authorization_url(base_url: OOB_URI)
|
18
18
|
|
19
|
-
UI.message("
|
19
|
+
UI.message("Open the following address in your browser and sign in with your Google account:")
|
20
20
|
UI.message(url)
|
21
21
|
UI.message("")
|
22
22
|
code = UI.input("Enter the resulting code here: ")
|
23
23
|
credentials = authorizer.get_credentials_from_code(code: code, base_url: OOB_URI)
|
24
|
-
|
25
|
-
UI.message("Refresh Token: #{credentials.refresh_token}")
|
26
24
|
UI.message("")
|
27
|
-
|
25
|
+
|
26
|
+
UI.success("Set the refresh token as the FIREBASE_TOKEN environment variable")
|
27
|
+
UI.success("Refresh Token: #{credentials.refresh_token}")
|
28
28
|
rescue Signet::AuthorizationError
|
29
|
-
UI.error("The code you entered
|
29
|
+
UI.error("The code you entered is invalid. Copy and paste the code and try again.")
|
30
30
|
rescue => error
|
31
31
|
UI.error(error.to_s)
|
32
|
-
UI.crash!("An error has occured please login again.")
|
32
|
+
UI.crash!("An error has occured, please login again.")
|
33
33
|
end
|
34
34
|
|
35
35
|
#####################################################
|
data/lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb
CHANGED
@@ -9,8 +9,16 @@ module Fastlane
|
|
9
9
|
MAX_POLLING_RETRIES = 60
|
10
10
|
POLLING_INTERVAL_SECONDS = 2
|
11
11
|
|
12
|
-
def initialize(auth_token)
|
12
|
+
def initialize(auth_token, platform)
|
13
13
|
@auth_token = auth_token
|
14
|
+
|
15
|
+
if platform.nil?
|
16
|
+
@binary_type = "IPA/APK"
|
17
|
+
elsif platform == :ios
|
18
|
+
@binary_type = "IPA"
|
19
|
+
else
|
20
|
+
@binary_type = "APK"
|
21
|
+
end
|
14
22
|
end
|
15
23
|
|
16
24
|
# Enables tester access to the specified app release. Skips this
|
@@ -25,7 +33,7 @@ module Fastlane
|
|
25
33
|
# Throws a user_error if app_id, emails, or group_ids are invalid
|
26
34
|
def enable_access(app_id, release_id, emails, group_ids)
|
27
35
|
if (emails.nil? || emails.empty?) && (group_ids.nil? || group_ids.empty?)
|
28
|
-
UI.
|
36
|
+
UI.success("✅ No testers passed in. Skipping this step.")
|
29
37
|
return
|
30
38
|
end
|
31
39
|
payload = { emails: emails, groupIds: group_ids }
|
@@ -38,6 +46,7 @@ module Fastlane
|
|
38
46
|
rescue Faraday::ClientError
|
39
47
|
UI.user_error!("#{ErrorMessage::INVALID_TESTERS} \nEmails: #{emails} \nGroups: #{group_ids}")
|
40
48
|
end
|
49
|
+
UI.success("✅ Added testers/groups.")
|
41
50
|
end
|
42
51
|
|
43
52
|
# Posts notes for the specified app release. Skips this
|
@@ -52,7 +61,7 @@ module Fastlane
|
|
52
61
|
def post_notes(app_id, release_id, release_notes)
|
53
62
|
payload = { releaseNotes: { releaseNotes: release_notes } }
|
54
63
|
if release_notes.nil? || release_notes.empty?
|
55
|
-
UI.
|
64
|
+
UI.success("✅ No release notes passed in. Skipping this step.")
|
56
65
|
return
|
57
66
|
end
|
58
67
|
begin
|
@@ -64,38 +73,57 @@ module Fastlane
|
|
64
73
|
# rescue Faraday::ClientError
|
65
74
|
# UI.user_error!("#{ErrorMessage::INVALID_RELEASE_ID}: #{release_id}")
|
66
75
|
end
|
67
|
-
UI.success("
|
76
|
+
UI.success("✅ Posted release notes.")
|
68
77
|
end
|
69
78
|
|
79
|
+
# Returns the url encoded upload token used for get_upload_status calls:
|
80
|
+
# projects/<project-number>/apps/<app-id>/releases/-/binaries/<binary-hash>
|
81
|
+
#
|
82
|
+
# args
|
83
|
+
# app_id - Firebase App ID
|
84
|
+
# binary_path - Absolute path to your app's apk/ipa file
|
85
|
+
#
|
86
|
+
# Throws a user_error if an invalid app id is passed in, the binary file does
|
87
|
+
# not exist, or invalid auth credentials are used (e.g. wrong project permissions)
|
70
88
|
def get_upload_token(app_id, binary_path)
|
71
|
-
|
72
|
-
|
73
|
-
rescue Errno::ENOENT
|
74
|
-
UI.crash!("#{ErrorMessage::APK_NOT_FOUND}: #{binary_path}")
|
89
|
+
if binary_path.nil? || !File.exist?(binary_path)
|
90
|
+
UI.crash!("#{ErrorMessage.binary_not_found(@binary_type)}: #{binary_path}")
|
75
91
|
end
|
92
|
+
binary_hash = Digest::SHA256.hexdigest(read_binary(binary_path))
|
76
93
|
|
77
94
|
begin
|
78
95
|
response = connection.get(v1_apps_url(app_id)) do |request|
|
79
96
|
request.headers["Authorization"] = "Bearer " + @auth_token
|
80
97
|
end
|
81
98
|
rescue Faraday::ResourceNotFound
|
82
|
-
UI.
|
99
|
+
UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{app_id}")
|
83
100
|
end
|
84
101
|
contact_email = response.body[:contactEmail]
|
85
102
|
if contact_email.nil? || contact_email.strip.empty?
|
86
|
-
UI.
|
103
|
+
UI.user_error!(ErrorMessage::GET_APP_NO_CONTACT_EMAIL_ERROR)
|
87
104
|
end
|
88
105
|
return upload_token_format(response.body[:appId], response.body[:projectNumber], binary_hash)
|
89
106
|
end
|
90
107
|
|
91
|
-
|
92
|
-
|
108
|
+
# Uploads the app binary to the Firebase API
|
109
|
+
#
|
110
|
+
# args
|
111
|
+
# app_id - Firebase App ID
|
112
|
+
# binary_path - Absolute path to your app's apk/ipa file
|
113
|
+
# platform - 'android' or 'ios'
|
114
|
+
#
|
115
|
+
# Throws a user_error if an invalid app id is passed in, or if the binary file does not exist
|
116
|
+
def upload_binary(app_id, binary_path, platform)
|
117
|
+
connection.post(binary_upload_url(app_id), read_binary(binary_path)) do |request|
|
93
118
|
request.headers["Authorization"] = "Bearer " + @auth_token
|
119
|
+
request.headers["X-APP-DISTRO-API-CLIENT-ID"] = "fastlane"
|
120
|
+
request.headers["X-APP-DISTRO-API-CLIENT-TYPE"] = platform
|
121
|
+
request.headers["X-APP-DISTRO-API-CLIENT-VERSION"] = Fastlane::FirebaseAppDistribution::VERSION
|
94
122
|
end
|
95
123
|
rescue Faraday::ResourceNotFound
|
96
|
-
UI.
|
97
|
-
rescue Errno::ENOENT
|
98
|
-
UI.
|
124
|
+
UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{app_id}")
|
125
|
+
rescue Errno::ENOENT # Raised when binary_path file does not exist
|
126
|
+
UI.user_error!("#{ErrorMessage.binary_not_found(@binary_type)}: #{binary_path}")
|
99
127
|
end
|
100
128
|
|
101
129
|
# Uploads the binary file if it has not already been uploaded
|
@@ -107,42 +135,57 @@ module Fastlane
|
|
107
135
|
#
|
108
136
|
# Returns the release_id on a successful release, otherwise returns nil.
|
109
137
|
#
|
110
|
-
# Throws
|
111
|
-
|
138
|
+
# Throws a UI error if the number of polling retries exceeds MAX_POLLING_RETRIES
|
139
|
+
# Crashes if not able to upload the binary
|
140
|
+
def upload(app_id, binary_path, platform)
|
112
141
|
upload_token = get_upload_token(app_id, binary_path)
|
113
142
|
upload_status_response = get_upload_status(app_id, upload_token)
|
114
|
-
if upload_status_response.success?
|
115
|
-
UI.success("This
|
143
|
+
if upload_status_response.success? || upload_status_response.already_uploaded?
|
144
|
+
UI.success("✅ This #{@binary_type} has been uploaded before. Skipping upload step.")
|
116
145
|
else
|
117
|
-
|
146
|
+
unless upload_status_response.in_progress?
|
147
|
+
UI.message("⌛ Uploading the #{@binary_type}.")
|
148
|
+
upload_binary(app_id, binary_path, platform)
|
149
|
+
end
|
118
150
|
MAX_POLLING_RETRIES.times do
|
119
|
-
|
120
|
-
|
151
|
+
upload_status_response = get_upload_status(app_id, upload_token)
|
152
|
+
if upload_status_response.success? || upload_status_response.already_uploaded?
|
153
|
+
UI.success("✅ Uploaded the #{@binary_type}.")
|
121
154
|
break
|
122
155
|
elsif upload_status_response.in_progress?
|
123
156
|
sleep(POLLING_INTERVAL_SECONDS)
|
124
157
|
else
|
125
|
-
|
126
|
-
|
158
|
+
if !upload_status_response.message.nil?
|
159
|
+
UI.user_error!("#{ErrorMessage.upload_binary_error(@binary_type)}: #{upload_status_response.message}")
|
160
|
+
else
|
161
|
+
UI.user_error!(ErrorMessage.upload_binary_error(@binary_type))
|
162
|
+
end
|
127
163
|
end
|
128
|
-
upload_status_response = get_upload_status(app_id, upload_token)
|
129
164
|
end
|
130
165
|
unless upload_status_response.success?
|
131
|
-
UI.error("It took longer than expected to process your
|
166
|
+
UI.error("It took longer than expected to process your #{@binary_type}, please try again.")
|
132
167
|
return nil
|
133
168
|
end
|
134
169
|
end
|
135
170
|
upload_status_response.release_id
|
136
171
|
end
|
137
172
|
|
138
|
-
#
|
139
|
-
|
173
|
+
# Fetches the status of an uploaded binary
|
174
|
+
#
|
175
|
+
# args
|
176
|
+
# app_id - Firebase App ID
|
177
|
+
# upload_token - URL encoded upload token
|
178
|
+
#
|
179
|
+
# Returns the release ID on a successful release, otherwise returns nil.
|
180
|
+
#
|
181
|
+
# Throws a user_error if an invalid app_id is passed in
|
182
|
+
def get_upload_status(app_id, upload_token)
|
140
183
|
begin
|
141
|
-
response = connection.get(upload_status_url(app_id,
|
184
|
+
response = connection.get(upload_status_url(app_id, upload_token)) do |request|
|
142
185
|
request.headers["Authorization"] = "Bearer " + @auth_token
|
143
186
|
end
|
144
187
|
rescue Faraday::ResourceNotFound
|
145
|
-
UI.
|
188
|
+
UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{app_id}")
|
146
189
|
end
|
147
190
|
return UploadStatusResponse.new(response.body)
|
148
191
|
end
|
@@ -180,6 +223,11 @@ module Fastlane
|
|
180
223
|
conn.adapter(Faraday.default_adapter)
|
181
224
|
end
|
182
225
|
end
|
226
|
+
|
227
|
+
def read_binary(path)
|
228
|
+
# File must be read in binary mode to work on Windows
|
229
|
+
File.open(path, 'rb').read
|
230
|
+
end
|
183
231
|
end
|
184
232
|
end
|
185
233
|
end
|
data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_auth_client.rb
CHANGED
@@ -5,33 +5,74 @@ module Fastlane
|
|
5
5
|
module FirebaseAppDistributionAuthClient
|
6
6
|
TOKEN_CREDENTIAL_URI = "https://oauth2.googleapis.com/token"
|
7
7
|
|
8
|
-
|
8
|
+
# Returns the auth token for any of the auth methods (Firebase CLI token,
|
9
|
+
# Google service account, firebase-tools). To ensure that a specific
|
10
|
+
# auth method is used, unset all other auth variables/parameters to nil/empty
|
11
|
+
#
|
12
|
+
# args
|
13
|
+
# google_service_path - Absolute path to the Google service account file
|
14
|
+
# firebase_cli_token - Firebase CLI refresh token from login action or
|
15
|
+
# CI environment
|
16
|
+
#
|
17
|
+
# env variables
|
18
|
+
# GOOGLE_APPLICATION_CREDENTIALS - see google_service_path
|
19
|
+
# FIREBASE_TOKEN - see firebase_cli_token
|
20
|
+
#
|
21
|
+
# Crashes if given invalid or missing credentials
|
22
|
+
def fetch_auth_token(google_service_path, firebase_cli_token)
|
9
23
|
if !google_service_path.nil? && !google_service_path.empty?
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
24
|
+
UI.message("Authenticating with --service_credentials_file path parameter: #{google_service_path}")
|
25
|
+
token = service_account(google_service_path)
|
26
|
+
elsif !firebase_cli_token.nil? && !firebase_cli_token.empty?
|
27
|
+
UI.message("Authenticating with --firebase_cli_token parameter")
|
28
|
+
token = firebase_token(firebase_cli_token)
|
29
|
+
elsif !ENV["FIREBASE_TOKEN"].nil? && !ENV["FIREBASE_TOKEN"].empty?
|
30
|
+
UI.message("Authenticating with FIREBASE_TOKEN environment variable")
|
31
|
+
token = firebase_token(ENV["FIREBASE_TOKEN"])
|
32
|
+
elsif !ENV["GOOGLE_APPLICATION_CREDENTIALS"].nil? && !ENV["GOOGLE_APPLICATION_CREDENTIALS"].empty?
|
33
|
+
UI.message("Authenticating with GOOGLE_APPLICATION_CREDENTIALS environment variable: #{ENV['GOOGLE_APPLICATION_CREDENTIALS']}")
|
34
|
+
token = service_account(ENV["GOOGLE_APPLICATION_CREDENTIALS"])
|
35
|
+
elsif (refresh_token = refresh_token_from_firebase_tools)
|
36
|
+
UI.message("No authentication method specified. Using cached Firebase CLI credentials.")
|
37
|
+
token = firebase_token(refresh_token)
|
15
38
|
else
|
16
|
-
UI.
|
39
|
+
UI.user_error!(ErrorMessage::MISSING_CREDENTIALS)
|
17
40
|
end
|
41
|
+
UI.success("🔐 Authenticated successfully.")
|
42
|
+
token
|
18
43
|
end
|
19
44
|
|
20
45
|
private
|
21
46
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
47
|
+
def refresh_token_from_firebase_tools
|
48
|
+
if ENV["XDG_CONFIG_HOME"].nil? || ENV["XDG_CONFIG_HOME"].empty?
|
49
|
+
config_path = File.expand_path(".config/configstore/firebase-tools.json", "~")
|
50
|
+
else
|
51
|
+
config_path = File.expand_path("configstore/firebase-tools.json", ENV["XDG_CONFIG_HOME"])
|
52
|
+
end
|
53
|
+
|
54
|
+
if File.exist?(config_path)
|
55
|
+
begin
|
56
|
+
refresh_token = JSON.parse(File.read(config_path))['tokens']['refresh_token']
|
57
|
+
refresh_token unless refresh_token.nil? || refresh_token.empty?
|
58
|
+
# TODO: Catch parser errors, improve error handling here
|
59
|
+
# Returns nil when there is an empty "tokens" field in the firebase-tools json
|
60
|
+
rescue NoMethodError
|
61
|
+
end
|
32
62
|
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def firebase_token(refresh_token)
|
66
|
+
client = Signet::OAuth2::Client.new(
|
67
|
+
token_credential_uri: TOKEN_CREDENTIAL_URI,
|
68
|
+
client_id: Fastlane::Actions::FirebaseAppDistributionLoginAction::CLIENT_ID,
|
69
|
+
client_secret: Fastlane::Actions::FirebaseAppDistributionLoginAction::CLIENT_SECRET,
|
70
|
+
refresh_token: refresh_token
|
71
|
+
)
|
33
72
|
client.fetch_access_token!
|
34
73
|
client.access_token
|
74
|
+
rescue Signet::AuthorizationError
|
75
|
+
UI.user_error!(ErrorMessage::REFRESH_TOKEN_ERROR)
|
35
76
|
end
|
36
77
|
|
37
78
|
def service_account(google_service_path)
|
@@ -41,7 +82,9 @@ module Fastlane
|
|
41
82
|
)
|
42
83
|
service_account_credentials.fetch_access_token!["access_token"]
|
43
84
|
rescue Errno::ENOENT
|
44
|
-
UI.
|
85
|
+
UI.user_error!("#{ErrorMessage::SERVICE_CREDENTIALS_NOT_FOUND}: #{google_service_path}")
|
86
|
+
rescue Signet::AuthorizationError
|
87
|
+
UI.user_error!("#{ErrorMessage::SERVICE_CREDENTIALS_ERROR}: #{google_service_path}")
|
45
88
|
end
|
46
89
|
end
|
47
90
|
end
|
data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_error_message.rb
CHANGED
@@ -1,21 +1,34 @@
|
|
1
1
|
module ErrorMessage
|
2
|
-
MISSING_CREDENTIALS = "Missing credentials.
|
3
|
-
|
4
|
-
MISSING_APP_ID = "Missing app id. Please check that it was passed in and try again"
|
2
|
+
MISSING_CREDENTIALS = "Missing authentication credentials. Check that your Firebase refresh token is set or that your service account file path is correct and try again."
|
3
|
+
MISSING_APP_ID = "Missing app id. Please check that the app parameter is set and try again"
|
5
4
|
SERVICE_CREDENTIALS_NOT_FOUND = "Service credentials file does not exist. Please check the service credentials path and try again"
|
6
5
|
PARSE_SERVICE_CREDENTIALS_ERROR = "Failed to extract service account information from the service credentials file"
|
7
|
-
PARSE_APK_METADATA_ERROR = "Failed to extract APK/IPA metadata from the APK/IPA path"
|
8
6
|
UPLOAD_RELEASE_NOTES_ERROR = "App Distribution halted because it had a problem uploading release notes"
|
9
7
|
UPLOAD_TESTERS_ERROR = "App Distribution halted because it had a problem adding testers/groups"
|
10
|
-
UPLOAD_APK_ERROR = "App Distribution halted because it had a problem uploading the APK/IPA"
|
11
|
-
APK_PROCESSING_ERROR = "App Distribution failed to process the APK/IPA"
|
12
8
|
GET_RELEASE_TIMEOUT = "App Distribution failed to fetch release information"
|
13
|
-
REFRESH_TOKEN_ERROR = "
|
9
|
+
REFRESH_TOKEN_ERROR = "App Distribution could not generate credentials from the refresh token specified."
|
14
10
|
GET_APP_ERROR = "App Distribution failed to fetch app information"
|
15
11
|
APP_NOT_ONBOARDED_ERROR = "App Distribution not onboarded"
|
16
12
|
GET_APP_NO_CONTACT_EMAIL_ERROR = "App Distribution could not find a contact email associated with this app. Contact Email"
|
17
13
|
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"
|
18
14
|
INVALID_PATH = "Could not read content from"
|
19
|
-
INVALID_TESTERS = "Could not enable access for testers.
|
15
|
+
INVALID_TESTERS = "Could not enable access for testers. Check that the groups exist and the tester emails are formatted correctly"
|
20
16
|
INVALID_RELEASE_ID = "App distribution failed to fetch release with id"
|
17
|
+
SERVICE_CREDENTIALS_ERROR = "App Distribution could not generate credentials from the service credentials file specified. Service Account Path"
|
18
|
+
|
19
|
+
def self.binary_not_found(binary_type)
|
20
|
+
"Could not find the #{binary_type}. Make sure you set the #{binary_type} path parameter to point to your #{binary_type}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.parse_binary_metadata_error(binary_type)
|
24
|
+
"Failed to extract #{binary_type} metadata from the #{binary_type} path"
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.upload_binary_error(binary_type)
|
28
|
+
"App Distribution halted because it had a problem uploading the #{binary_type}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.binary_processing_error(binary_type)
|
32
|
+
"App Distribution failed to process the #{binary_type}"
|
33
|
+
end
|
21
34
|
end
|
data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_helper.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'fastlane_core/ui/ui'
|
2
|
+
require 'cfpropertylist'
|
2
3
|
module Fastlane
|
3
4
|
UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
|
4
5
|
module Helper
|
@@ -23,6 +24,10 @@ module Fastlane
|
|
23
24
|
return string_array
|
24
25
|
end
|
25
26
|
|
27
|
+
def parse_plist(path)
|
28
|
+
CFPropertyList.native_types(CFPropertyList::List.new(file: path).value)
|
29
|
+
end
|
30
|
+
|
26
31
|
def get_ios_app_id_from_archive(path)
|
27
32
|
app_path = parse_plist("#{path}/Info.plist")["ApplicationProperties"]["ApplicationPath"]
|
28
33
|
UI.shell_error!("can't extract application path from Info.plist at #{path}") if app_path.empty?
|
@@ -12,7 +12,15 @@ class UploadStatusResponse
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def in_progress?
|
15
|
-
status ==
|
15
|
+
status == 'IN_PROGRESS'
|
16
|
+
end
|
17
|
+
|
18
|
+
def error?
|
19
|
+
status == 'ERROR'
|
20
|
+
end
|
21
|
+
|
22
|
+
def already_uploaded?
|
23
|
+
status == 'ALREADY_UPLOADED'
|
16
24
|
end
|
17
25
|
|
18
26
|
def release_hash
|
@@ -22,4 +30,8 @@ class UploadStatusResponse
|
|
22
30
|
def release_id
|
23
31
|
release_hash ? release_hash[:id] : nil
|
24
32
|
end
|
33
|
+
|
34
|
+
def message
|
35
|
+
@response_json_hash[:message]
|
36
|
+
end
|
25
37
|
end
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane-plugin-firebase_app_distribution
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefan Natchev
|
8
8
|
- Manny Jimenez
|
9
9
|
- Alonso Salas Infante
|
10
|
-
autorequire:
|
10
|
+
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2020-
|
13
|
+
date: 2020-09-16 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: pry
|
@@ -138,7 +138,7 @@ dependencies:
|
|
138
138
|
- - ">="
|
139
139
|
- !ruby/object:Gem::Version
|
140
140
|
version: 2.127.1
|
141
|
-
description:
|
141
|
+
description:
|
142
142
|
email:
|
143
143
|
- snatchev@google.com
|
144
144
|
- mannyjimenez@google.com
|
@@ -162,7 +162,7 @@ homepage: https://github.com/fastlane/fastlane-plugin-firebase_app_distribution
|
|
162
162
|
licenses:
|
163
163
|
- MIT
|
164
164
|
metadata: {}
|
165
|
-
post_install_message:
|
165
|
+
post_install_message:
|
166
166
|
rdoc_options: []
|
167
167
|
require_paths:
|
168
168
|
- lib
|
@@ -173,13 +173,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
173
173
|
version: '0'
|
174
174
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
175
175
|
requirements:
|
176
|
-
- - "
|
176
|
+
- - ">="
|
177
177
|
- !ruby/object:Gem::Version
|
178
|
-
version:
|
178
|
+
version: '0'
|
179
179
|
requirements: []
|
180
|
-
|
181
|
-
|
182
|
-
signing_key:
|
180
|
+
rubygems_version: 3.1.2
|
181
|
+
signing_key:
|
183
182
|
specification_version: 4
|
184
183
|
summary: Release your beta builds to Firebase App Distribution. https://firebase.google.com/docs/app-distribution
|
185
184
|
test_files: []
|