fastlane-plugin-firebase_app_distribution 0.2.2.pre.2 → 0.2.6.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 +76 -28
- data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_login.rb +3 -0
- data/lib/fastlane/plugin/firebase_app_distribution/client/aab_certificate.rb +23 -0
- data/lib/fastlane/plugin/firebase_app_distribution/client/app.rb +37 -0
- data/lib/fastlane/plugin/firebase_app_distribution/client/error_response.rb +16 -0
- data/lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb +54 -62
- data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_error_message.rb +9 -0
- data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_helper.rb +9 -0
- data/lib/fastlane/plugin/firebase_app_distribution/version.rb +1 -1
- metadata +10 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d129a8d78fc5bca84c4e7484dbe02436ee9cd4ef9e9005bec4e1646401b9b143
|
4
|
+
data.tar.gz: 1677a9d201117796c171ed8a0a9472b69bc8b763bdd5492e3a3fd8f3dae19d84
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1c6e3502a696a1d759f838028812a526745e6d11fe678e26a829ead65fd8114b4244565695d338b1d60ef34cb1129b70948e87c8d297c72334abc46e9bbc20ec
|
7
|
+
data.tar.gz: 47504b8df8a313b588aea6c5fa8b7d8cebc5d7ea66117c0025b73f53e6f529bbc443e395c66baa357248c81b864ed81f5cfe46cd957c42c92d03e63e16cbc89a
|
data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_action.rb
CHANGED
@@ -13,26 +13,46 @@ require_relative '../helper/firebase_app_distribution_auth_client'
|
|
13
13
|
module Fastlane
|
14
14
|
module Actions
|
15
15
|
class FirebaseAppDistributionAction < Action
|
16
|
-
FIREBASECMD_ACTION = "appdistribution:distribute".freeze
|
17
|
-
|
18
16
|
extend Auth::FirebaseAppDistributionAuthClient
|
19
17
|
extend Helper::FirebaseAppDistributionHelper
|
20
18
|
|
21
19
|
def self.run(params)
|
22
|
-
params.values # to validate all inputs before looking for the ipa/apk
|
20
|
+
params.values # to validate all inputs before looking for the ipa/apk/aab
|
23
21
|
|
24
22
|
app_id = app_id_from_params(params)
|
25
23
|
platform = lane_platform || platform_from_app_id(app_id)
|
26
|
-
|
24
|
+
|
25
|
+
binary_path = get_binary_path(platform, params)
|
26
|
+
UI.user_error!("Couldn't find binary") if binary_path.nil?
|
27
|
+
UI.user_error!("Couldn't find binary at path #{binary_path}") unless File.exist?(binary_path)
|
28
|
+
binary_type = binary_type_from_path(binary_path)
|
27
29
|
|
28
30
|
auth_token = fetch_auth_token(params[:service_credentials_file], params[:firebase_cli_token])
|
29
|
-
fad_api_client = Client::FirebaseAppDistributionApiClient.new(auth_token,
|
31
|
+
fad_api_client = Client::FirebaseAppDistributionApiClient.new(auth_token, params[:debug])
|
30
32
|
|
31
|
-
|
33
|
+
# If binary is an AAB get FULL view of app which includes the aab_state
|
34
|
+
app_view = binary_type == :AAB ? 'FULL' : 'BASIC'
|
35
|
+
app = fad_api_client.get_app(app_id, app_view)
|
36
|
+
validate_app!(app, binary_type)
|
37
|
+
|
38
|
+
release_id = fad_api_client.upload(app.project_number, app_id, binary_path, platform.to_s)
|
32
39
|
if release_id.nil?
|
33
40
|
return
|
34
41
|
end
|
35
42
|
|
43
|
+
if binary_type == :AAB && app.aab_certificate.empty?
|
44
|
+
updated_app = fad_api_client.get_app(app_id)
|
45
|
+
unless updated_app.aab_certificate.empty?
|
46
|
+
UI.message("After you upload an AAB for the first time, App Distribution " \
|
47
|
+
"generates a new test certificate. All AAB uploads are re-signed with this test " \
|
48
|
+
"certificate. Use the certificate fingerprints below to register your app " \
|
49
|
+
"signing key with API providers, such as Google Sign-In and Google Maps.\n" \
|
50
|
+
"MD-1 certificate fingerprint: #{updated_app.aab_certificate.md5_certificate_hash}\n" \
|
51
|
+
"SHA-1 certificate fingerprint: #{updated_app.aab_certificate.sha1_certificate_hash}\n" \
|
52
|
+
"SHA-256 certificate fingerprint: #{updated_app.aab_certificate.sha256_certificate_hash}")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
36
56
|
release_notes = get_value_from_value_or_file(params[:release_notes], params[:release_notes_file])
|
37
57
|
fad_api_client.post_notes(app_id, release_id, release_notes)
|
38
58
|
|
@@ -90,52 +110,80 @@ module Fastlane
|
|
90
110
|
end
|
91
111
|
end
|
92
112
|
|
93
|
-
def self.
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
113
|
+
def self.get_binary_path(platform, params)
|
114
|
+
if platform == :ios
|
115
|
+
return params[:ipa_path] ||
|
116
|
+
Actions.lane_context[SharedValues::IPA_OUTPUT_PATH] ||
|
117
|
+
Dir["*.ipa"].sort_by { |x| File.mtime(x) }.last
|
118
|
+
end
|
119
|
+
|
120
|
+
if platform == :android
|
121
|
+
return params[:apk_path] || params[:android_artifact_path] if params[:apk_path] || params[:android_artifact_path]
|
122
|
+
|
123
|
+
if params[:android_artifact_type] == 'AAB'
|
124
|
+
return Actions.lane_context[SharedValues::GRADLE_AAB_OUTPUT_PATH] ||
|
125
|
+
Dir["*.aab"].last ||
|
126
|
+
Dir[File.join("app", "build", "outputs", "bundle", "release", "app-release.aab")].last
|
127
|
+
end
|
128
|
+
|
129
|
+
return Actions.lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH] ||
|
130
|
+
Dir["*.apk"].last ||
|
131
|
+
Dir[File.join("app", "build", "outputs", "apk", "release", "app-release.apk")].last
|
101
132
|
end
|
102
133
|
end
|
103
134
|
|
104
|
-
def self.
|
105
|
-
if
|
106
|
-
|
135
|
+
def self.validate_app!(app, binary_type)
|
136
|
+
if app.contact_email.nil? || app.contact_email.strip.empty?
|
137
|
+
UI.user_error!(ErrorMessage::GET_APP_NO_CONTACT_EMAIL_ERROR)
|
107
138
|
end
|
108
139
|
|
109
|
-
if
|
110
|
-
|
140
|
+
if binary_type == :AAB && app.aab_state != App::AabState::ACTIVE && app.aab_state != App::AabState::UNAVAILABLE
|
141
|
+
case app.aab_state
|
142
|
+
when App::AabState::PLAY_ACCOUNT_NOT_LINKED
|
143
|
+
UI.user_error!(ErrorMessage::PLAY_ACCOUNT_NOT_LINKED)
|
144
|
+
when App::AabState::APP_NOT_PUBLISHED
|
145
|
+
UI.user_error!(ErrorMessage::APP_NOT_PUBLISHED)
|
146
|
+
when App::AabState::NO_APP_WITH_GIVEN_BUNDLE_ID_IN_PLAY_ACCOUNT
|
147
|
+
UI.user_error!(ErrorMessage::NO_APP_WITH_GIVEN_BUNDLE_ID_IN_PLAY_ACCOUNT)
|
148
|
+
when App::AabState::PLAY_IAS_TERMS_NOT_ACCEPTED
|
149
|
+
UI.user_error!(ErrorMessage::PLAY_IAS_TERMS_NOT_ACCEPTED)
|
150
|
+
else
|
151
|
+
UI.user_error!(ErrorMessage.aab_upload_error(app.aab_state))
|
152
|
+
end
|
111
153
|
end
|
154
|
+
end
|
112
155
|
|
156
|
+
def self.available_options
|
113
157
|
[
|
114
158
|
# iOS Specific
|
115
159
|
FastlaneCore::ConfigItem.new(key: :ipa_path,
|
116
160
|
env_name: "FIREBASEAPPDISTRO_IPA_PATH",
|
117
161
|
description: "Path to your IPA file. Optional if you use the _gym_ or _xcodebuild_ action",
|
118
|
-
|
119
|
-
default_value_dynamic: true,
|
120
|
-
optional: true,
|
121
|
-
verify_block: proc do |value|
|
122
|
-
UI.user_error!("firebase_app_distribution: Couldn't find ipa file at path '#{value}'") unless File.exist?(value)
|
123
|
-
end),
|
162
|
+
optional: true),
|
124
163
|
FastlaneCore::ConfigItem.new(key: :googleservice_info_plist_path,
|
125
164
|
env_name: "GOOGLESERVICE_INFO_PLIST_PATH",
|
126
|
-
description: "Path to your GoogleService-Info.plist file, relative to the
|
165
|
+
description: "Path to your GoogleService-Info.plist file, relative to the archived product path",
|
127
166
|
default_value: "GoogleService-Info.plist",
|
128
167
|
optional: true,
|
129
168
|
type: String),
|
130
169
|
# Android Specific
|
131
170
|
FastlaneCore::ConfigItem.new(key: :apk_path,
|
132
171
|
env_name: "FIREBASEAPPDISTRO_APK_PATH",
|
172
|
+
deprecated: "The apk_path parameter is deprecated. Please use android_artifact_path instead",
|
133
173
|
description: "Path to your APK file",
|
134
|
-
|
174
|
+
optional: true),
|
175
|
+
FastlaneCore::ConfigItem.new(key: :android_artifact_path,
|
176
|
+
env_name: "FIREBASEAPPDISTRO_ANDROID_ARTIFACT_PATH",
|
177
|
+
description: "Path to your APK or AAB file",
|
178
|
+
optional: true),
|
179
|
+
FastlaneCore::ConfigItem.new(key: :android_artifact_type,
|
180
|
+
env_name: "FIREBASEAPPDISTRO_ANDROID_ARTIFACT_TYPE",
|
181
|
+
description: "Android artifact type. Set to 'APK' or 'AAB'. Defaults to 'APK' if not set",
|
182
|
+
default_value: "APK",
|
135
183
|
default_value_dynamic: true,
|
136
184
|
optional: true,
|
137
185
|
verify_block: proc do |value|
|
138
|
-
UI.user_error!("firebase_app_distribution:
|
186
|
+
UI.user_error!("firebase_app_distribution: '#{value}' is not a valid value for android_artifact_path. Should be 'APK' or 'AAB'") unless ['APK', 'AAB'].include?(value)
|
139
187
|
end),
|
140
188
|
FastlaneCore::ConfigItem.new(key: :app,
|
141
189
|
env_name: "FIREBASEAPPDISTRO_APP",
|
data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_login.rb
CHANGED
@@ -8,6 +8,9 @@ module Fastlane
|
|
8
8
|
class FirebaseAppDistributionLoginAction < Action
|
9
9
|
OOB_URI = "urn:ietf:wg:oauth:2.0:oob"
|
10
10
|
SCOPE = "https://www.googleapis.com/auth/cloud-platform"
|
11
|
+
|
12
|
+
# In this type of application, the client secret is not treated as a secret.
|
13
|
+
# See: https://developers.google.com/identity/protocols/OAuth2InstalledApp
|
11
14
|
CLIENT_ID = "563584335869-fgrhgmd47bqnekij5i8b5pr03ho849e6.apps.googleusercontent.com"
|
12
15
|
CLIENT_SECRET = "j9iVZfS8kkCEFUPaAeJV0sAi"
|
13
16
|
|
@@ -0,0 +1,23 @@
|
|
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
|
@@ -0,0 +1,37 @@
|
|
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
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Fastlane
|
2
|
+
module Client
|
3
|
+
class ErrorResponse
|
4
|
+
attr_accessor :code, :message, :status
|
5
|
+
|
6
|
+
def initialize(response)
|
7
|
+
unless response[:body].nil? || response[:body].empty?
|
8
|
+
response_body = JSON.parse(response[:body], symbolize_names: true)
|
9
|
+
@code = response_body[:error][:code]
|
10
|
+
@message = response_body[:error][:message]
|
11
|
+
@status = response_body[:error][:status]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb
CHANGED
@@ -1,24 +1,27 @@
|
|
1
1
|
require 'fastlane_core/ui/ui'
|
2
2
|
require_relative '../actions/firebase_app_distribution_login'
|
3
|
+
require_relative '../client/error_response'
|
4
|
+
require_relative '../client/app'
|
5
|
+
require_relative '../helper/firebase_app_distribution_helper'
|
3
6
|
|
4
7
|
module Fastlane
|
5
8
|
module Client
|
6
9
|
class FirebaseAppDistributionApiClient
|
10
|
+
include Helper::FirebaseAppDistributionHelper
|
11
|
+
|
7
12
|
BASE_URL = "https://firebaseappdistribution.googleapis.com"
|
8
13
|
TOKEN_CREDENTIAL_URI = "https://oauth2.googleapis.com/token"
|
9
14
|
MAX_POLLING_RETRIES = 60
|
10
15
|
POLLING_INTERVAL_SECONDS = 2
|
11
16
|
|
12
|
-
|
13
|
-
|
17
|
+
AUTHORIZATION = "Authorization"
|
18
|
+
CONTENT_TYPE = "Content-Type"
|
19
|
+
APPLICATION_JSON = "application/json"
|
20
|
+
APPLICATION_OCTET_STREAM = "application/octet-stream"
|
14
21
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
@binary_type = "IPA"
|
19
|
-
else
|
20
|
-
@binary_type = "APK"
|
21
|
-
end
|
22
|
+
def initialize(auth_token, debug = false)
|
23
|
+
@auth_token = auth_token
|
24
|
+
@debug = debug
|
22
25
|
end
|
23
26
|
|
24
27
|
# Enables tester access to the specified app release. Skips this
|
@@ -30,7 +33,7 @@ module Fastlane
|
|
30
33
|
# emails - String array of app testers' email addresses
|
31
34
|
# group_ids - String array of Firebase tester group IDs
|
32
35
|
#
|
33
|
-
# Throws a user_error if
|
36
|
+
# Throws a user_error if emails or group_ids are invalid
|
34
37
|
def enable_access(app_id, release_id, emails, group_ids)
|
35
38
|
if (emails.nil? || emails.empty?) && (group_ids.nil? || group_ids.empty?)
|
36
39
|
UI.success("✅ No testers passed in. Skipping this step.")
|
@@ -39,10 +42,9 @@ module Fastlane
|
|
39
42
|
payload = { emails: emails, groupIds: group_ids }
|
40
43
|
begin
|
41
44
|
connection.post(enable_access_url(app_id, release_id), payload.to_json) do |request|
|
42
|
-
request.headers[
|
45
|
+
request.headers[AUTHORIZATION] = "Bearer " + @auth_token
|
46
|
+
request.headers[CONTENT_TYPE] = APPLICATION_JSON
|
43
47
|
end
|
44
|
-
rescue Faraday::ResourceNotFound
|
45
|
-
UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{app_id}")
|
46
48
|
rescue Faraday::ClientError
|
47
49
|
UI.user_error!("#{ErrorMessage::INVALID_TESTERS} \nEmails: #{emails} \nGroups: #{group_ids}")
|
48
50
|
end
|
@@ -57,7 +59,7 @@ module Fastlane
|
|
57
59
|
# release_id - App release ID, returned by upload_status endpoint
|
58
60
|
# release_notes - String of notes for this release
|
59
61
|
#
|
60
|
-
# Throws a user_error if
|
62
|
+
# Throws a user_error if the release_notes are invalid
|
61
63
|
def post_notes(app_id, release_id, release_notes)
|
62
64
|
payload = { releaseNotes: { releaseNotes: release_notes } }
|
63
65
|
if release_notes.nil? || release_notes.empty?
|
@@ -66,104 +68,98 @@ module Fastlane
|
|
66
68
|
end
|
67
69
|
begin
|
68
70
|
connection.post(release_notes_create_url(app_id, release_id), payload.to_json) do |request|
|
69
|
-
request.headers[
|
71
|
+
request.headers[AUTHORIZATION] = "Bearer " + @auth_token
|
72
|
+
request.headers[CONTENT_TYPE] = APPLICATION_JSON
|
70
73
|
end
|
71
|
-
rescue Faraday::
|
72
|
-
|
73
|
-
#
|
74
|
-
# UI.user_error!("#{ErrorMessage::INVALID_RELEASE_ID}: #{release_id}")
|
74
|
+
rescue Faraday::ClientError => e
|
75
|
+
error = ErrorResponse.new(e.response)
|
76
|
+
UI.user_error!("#{ErrorMessage::INVALID_RELEASE_NOTES}: #{error.message}")
|
75
77
|
end
|
76
78
|
UI.success("✅ Posted release notes.")
|
77
79
|
end
|
78
80
|
|
79
|
-
#
|
80
|
-
# projects/<project-number>/apps/<app-id>/releases/-/binaries/<binary-hash>
|
81
|
+
# Get app
|
81
82
|
#
|
82
83
|
# args
|
83
84
|
# app_id - Firebase App ID
|
84
|
-
# binary_path - Absolute path to your app's apk/ipa file
|
85
85
|
#
|
86
|
-
# Throws a user_error if
|
87
|
-
|
88
|
-
def get_upload_token(app_id, binary_path)
|
89
|
-
if binary_path.nil? || !File.exist?(binary_path)
|
90
|
-
UI.crash!("#{ErrorMessage.binary_not_found(@binary_type)}: #{binary_path}")
|
91
|
-
end
|
92
|
-
binary_hash = Digest::SHA256.hexdigest(read_binary(binary_path))
|
93
|
-
|
86
|
+
# Throws a user_error if the app hasn't been onboarded to App Distribution
|
87
|
+
def get_app(app_id, app_view = 'BASIC')
|
94
88
|
begin
|
95
|
-
response = connection.get(v1_apps_url(app_id)) do |request|
|
96
|
-
request.headers[
|
89
|
+
response = connection.get("#{v1_apps_url(app_id)}?appView=#{app_view}") do |request|
|
90
|
+
request.headers[AUTHORIZATION] = "Bearer " + @auth_token
|
97
91
|
end
|
98
92
|
rescue Faraday::ResourceNotFound
|
99
93
|
UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{app_id}")
|
100
94
|
end
|
101
|
-
|
102
|
-
|
103
|
-
UI.user_error!(ErrorMessage::GET_APP_NO_CONTACT_EMAIL_ERROR)
|
104
|
-
end
|
105
|
-
return upload_token_format(response.body[:appId], response.body[:projectNumber], binary_hash)
|
95
|
+
|
96
|
+
App.new(response.body)
|
106
97
|
end
|
107
98
|
|
108
99
|
# Uploads the app binary to the Firebase API
|
109
100
|
#
|
110
101
|
# args
|
111
102
|
# app_id - Firebase App ID
|
112
|
-
# binary_path - Absolute path to your app's apk/ipa file
|
103
|
+
# binary_path - Absolute path to your app's aab/apk/ipa file
|
113
104
|
# platform - 'android' or 'ios'
|
114
105
|
#
|
115
|
-
# Throws a user_error if
|
106
|
+
# Throws a user_error if the binary file does not exist
|
116
107
|
def upload_binary(app_id, binary_path, platform)
|
117
108
|
connection.post(binary_upload_url(app_id), read_binary(binary_path)) do |request|
|
118
|
-
request.headers[
|
109
|
+
request.headers[AUTHORIZATION] = "Bearer " + @auth_token
|
110
|
+
request.headers[CONTENT_TYPE] = APPLICATION_OCTET_STREAM
|
119
111
|
request.headers["X-APP-DISTRO-API-CLIENT-ID"] = "fastlane"
|
120
112
|
request.headers["X-APP-DISTRO-API-CLIENT-TYPE"] = platform
|
121
113
|
request.headers["X-APP-DISTRO-API-CLIENT-VERSION"] = Fastlane::FirebaseAppDistribution::VERSION
|
114
|
+
request.headers["X-GOOG-UPLOAD-FILE-NAME"] = File.basename(binary_path)
|
115
|
+
request.headers["X-GOOG-UPLOAD-PROTOCOL"] = "raw"
|
122
116
|
end
|
123
|
-
rescue Faraday::ResourceNotFound
|
124
|
-
UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{app_id}")
|
125
117
|
rescue Errno::ENOENT # Raised when binary_path file does not exist
|
126
|
-
|
118
|
+
binary_type = binary_type_from_path(binary_path)
|
119
|
+
UI.user_error!("#{ErrorMessage.binary_not_found(binary_type)}: #{binary_path}")
|
127
120
|
end
|
128
121
|
|
129
122
|
# Uploads the binary file if it has not already been uploaded
|
130
123
|
# Takes at least POLLING_INTERVAL_SECONDS between polling get_upload_status
|
131
124
|
#
|
132
125
|
# args
|
133
|
-
#
|
134
|
-
#
|
126
|
+
# project_number - Firebase project number
|
127
|
+
# app_id - Firebase app ID
|
128
|
+
# binary_path - Absolute path to your app's aab/apk/ipa file
|
135
129
|
#
|
136
130
|
# Returns the release_id on a successful release, otherwise returns nil.
|
137
131
|
#
|
138
132
|
# Throws a UI error if the number of polling retries exceeds MAX_POLLING_RETRIES
|
139
133
|
# Crashes if not able to upload the binary
|
140
|
-
def upload(app_id, binary_path, platform)
|
141
|
-
|
134
|
+
def upload(project_number, app_id, binary_path, platform)
|
135
|
+
binary_type = binary_type_from_path(binary_path)
|
136
|
+
|
137
|
+
upload_token = get_upload_token(project_number, app_id, binary_path)
|
142
138
|
upload_status_response = get_upload_status(app_id, upload_token)
|
143
139
|
if upload_status_response.success? || upload_status_response.already_uploaded?
|
144
|
-
UI.success("✅ This #{
|
140
|
+
UI.success("✅ This #{binary_type} has been uploaded before. Skipping upload step.")
|
145
141
|
else
|
146
142
|
unless upload_status_response.in_progress?
|
147
|
-
UI.message("⌛ Uploading the #{
|
143
|
+
UI.message("⌛ Uploading the #{binary_type}.")
|
148
144
|
upload_binary(app_id, binary_path, platform)
|
149
145
|
end
|
150
146
|
MAX_POLLING_RETRIES.times do
|
151
147
|
upload_status_response = get_upload_status(app_id, upload_token)
|
152
148
|
if upload_status_response.success? || upload_status_response.already_uploaded?
|
153
|
-
UI.success("✅ Uploaded the #{
|
149
|
+
UI.success("✅ Uploaded the #{binary_type}.")
|
154
150
|
break
|
155
151
|
elsif upload_status_response.in_progress?
|
156
152
|
sleep(POLLING_INTERVAL_SECONDS)
|
157
153
|
else
|
158
154
|
if !upload_status_response.message.nil?
|
159
|
-
UI.user_error!("#{ErrorMessage.upload_binary_error(
|
155
|
+
UI.user_error!("#{ErrorMessage.upload_binary_error(binary_type)}: #{upload_status_response.message}")
|
160
156
|
else
|
161
|
-
UI.user_error!(ErrorMessage.upload_binary_error(
|
157
|
+
UI.user_error!(ErrorMessage.upload_binary_error(binary_type))
|
162
158
|
end
|
163
159
|
end
|
164
160
|
end
|
165
161
|
unless upload_status_response.success?
|
166
|
-
UI.error("It took longer than expected to process your #{
|
162
|
+
UI.error("It took longer than expected to process your #{binary_type}, please try again.")
|
167
163
|
return nil
|
168
164
|
end
|
169
165
|
end
|
@@ -177,15 +173,9 @@ module Fastlane
|
|
177
173
|
# upload_token - URL encoded upload token
|
178
174
|
#
|
179
175
|
# 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
176
|
def get_upload_status(app_id, upload_token)
|
183
|
-
|
184
|
-
|
185
|
-
request.headers["Authorization"] = "Bearer " + @auth_token
|
186
|
-
end
|
187
|
-
rescue Faraday::ResourceNotFound
|
188
|
-
UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{app_id}")
|
177
|
+
response = connection.get(upload_status_url(app_id, upload_token)) do |request|
|
178
|
+
request.headers[AUTHORIZATION] = "Bearer " + @auth_token
|
189
179
|
end
|
190
180
|
return UploadStatusResponse.new(response.body)
|
191
181
|
end
|
@@ -212,7 +202,8 @@ module Fastlane
|
|
212
202
|
"#{v1_apps_url(app_id)}/upload_status/#{app_token}"
|
213
203
|
end
|
214
204
|
|
215
|
-
def
|
205
|
+
def get_upload_token(project_number, app_id, binary_path)
|
206
|
+
binary_hash = Digest::SHA256.hexdigest(read_binary(binary_path))
|
216
207
|
CGI.escape("projects/#{project_number}/apps/#{app_id}/releases/-/binaries/#{binary_hash}")
|
217
208
|
end
|
218
209
|
|
@@ -220,6 +211,7 @@ module Fastlane
|
|
220
211
|
@connection ||= Faraday.new(url: BASE_URL) do |conn|
|
221
212
|
conn.response(:json, parser_options: { symbolize_names: true })
|
222
213
|
conn.response(:raise_error) # raise_error middleware will run before the json middleware
|
214
|
+
conn.response(:logger, nil, { headers: false, bodies: { response: true }, log_level: :debug }) if @debug
|
223
215
|
conn.adapter(Faraday.default_adapter)
|
224
216
|
end
|
225
217
|
end
|
data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_error_message.rb
CHANGED
@@ -14,7 +14,16 @@ module ErrorMessage
|
|
14
14
|
INVALID_PATH = "Could not read content from"
|
15
15
|
INVALID_TESTERS = "Could not enable access for testers. Check that the groups exist and the tester emails are formatted correctly"
|
16
16
|
INVALID_RELEASE_ID = "App distribution failed to fetch release with id"
|
17
|
+
INVALID_RELEASE_NOTES = "Failed to add release notes"
|
17
18
|
SERVICE_CREDENTIALS_ERROR = "App Distribution could not generate credentials from the service credentials file specified. Service Account Path"
|
19
|
+
PLAY_ACCOUNT_NOT_LINKED = "This project is not linked to a Google Play account."
|
20
|
+
APP_NOT_PUBLISHED = "This app is not published in the Google Play console."
|
21
|
+
NO_APP_WITH_GIVEN_BUNDLE_ID_IN_PLAY_ACCOUNT = "App with matching package name does not exist in Google Play."
|
22
|
+
PLAY_IAS_TERMS_NOT_ACCEPTED = "You must accept the Play Internal App Sharing (IAS) terms to upload AABs."
|
23
|
+
|
24
|
+
def self.aab_upload_error(aab_state)
|
25
|
+
"Failed to process the AAB: #{aab_state}"
|
26
|
+
end
|
18
27
|
|
19
28
|
def self.binary_not_found(binary_type)
|
20
29
|
"Could not find the #{binary_type}. Make sure you set the #{binary_type} path parameter to point to your #{binary_type}"
|
data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_helper.rb
CHANGED
@@ -4,6 +4,15 @@ module Fastlane
|
|
4
4
|
UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
|
5
5
|
module Helper
|
6
6
|
module FirebaseAppDistributionHelper
|
7
|
+
def binary_type_from_path(binary_path)
|
8
|
+
extension = File.extname(binary_path)
|
9
|
+
return :APK if extension == '.apk'
|
10
|
+
return :AAB if extension == '.aab'
|
11
|
+
return :IPA if extension == '.ipa'
|
12
|
+
|
13
|
+
UI.user_error!("Unsupported distribution file format, should be .ipa, .apk or .aab")
|
14
|
+
end
|
15
|
+
|
7
16
|
def get_value_from_value_or_file(value, path)
|
8
17
|
if (value.nil? || value.empty?) && !path.nil?
|
9
18
|
begin
|
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.6.pre.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:
|
13
|
+
date: 2021-03-08 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
|
@@ -152,6 +152,9 @@ files:
|
|
152
152
|
- lib/fastlane/plugin/firebase_app_distribution.rb
|
153
153
|
- lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_action.rb
|
154
154
|
- lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_login.rb
|
155
|
+
- lib/fastlane/plugin/firebase_app_distribution/client/aab_certificate.rb
|
156
|
+
- lib/fastlane/plugin/firebase_app_distribution/client/app.rb
|
157
|
+
- lib/fastlane/plugin/firebase_app_distribution/client/error_response.rb
|
155
158
|
- lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb
|
156
159
|
- lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_auth_client.rb
|
157
160
|
- lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_error_message.rb
|
@@ -162,7 +165,7 @@ homepage: https://github.com/fastlane/fastlane-plugin-firebase_app_distribution
|
|
162
165
|
licenses:
|
163
166
|
- MIT
|
164
167
|
metadata: {}
|
165
|
-
post_install_message:
|
168
|
+
post_install_message:
|
166
169
|
rdoc_options: []
|
167
170
|
require_paths:
|
168
171
|
- lib
|
@@ -177,8 +180,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
177
180
|
- !ruby/object:Gem::Version
|
178
181
|
version: 1.3.1
|
179
182
|
requirements: []
|
180
|
-
rubygems_version: 3.1.
|
181
|
-
signing_key:
|
183
|
+
rubygems_version: 3.1.4
|
184
|
+
signing_key:
|
182
185
|
specification_version: 4
|
183
186
|
summary: Release your beta builds to Firebase App Distribution. https://firebase.google.com/docs/app-distribution
|
184
187
|
test_files: []
|