Class: Fastlane::Client::FirebaseAppDistributionApiClient
- Inherits:
-
Object
- Object
- Fastlane::Client::FirebaseAppDistributionApiClient
- Includes:
- Helper::FirebaseAppDistributionHelper
- Defined in:
- lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb
Constant Summary collapse
- BASE_URL =
"https://firebaseappdistribution.googleapis.com"
- TOKEN_CREDENTIAL_URI =
"https://oauth2.googleapis.com/token"
- MAX_POLLING_RETRIES =
60
- POLLING_INTERVAL_SECONDS =
5
- AUTHORIZATION =
"Authorization"
- CONTENT_TYPE =
"Content-Type"
- APPLICATION_JSON =
"application/json"
- APPLICATION_OCTET_STREAM =
"application/octet-stream"
- CLIENT_VERSION =
"X-Client-Version"
Instance Method Summary collapse
-
#add_testers(project_number, emails) ⇒ Object
Create testers.
-
#distribute(release_name, emails, group_aliases) ⇒ Object
Enables tester access to the specified app release.
-
#get_aab_info(app_name) ⇒ Object
Get AAB info (Android apps only).
-
#get_udids(app_id) ⇒ Object
Get tester UDIDs.
-
#get_upload_status(operation_name) ⇒ Object
Fetches the status of an uploaded binary.
-
#initialize(auth_token, debug = false) ⇒ FirebaseAppDistributionApiClient
constructor
A new instance of FirebaseAppDistributionApiClient.
-
#list_releases(app_name, page_size = 100, page_token = nil) ⇒ Object
List releases.
-
#remove_testers(project_number, emails) ⇒ Object
Delete testers.
-
#update_release_notes(release_name, release_notes) ⇒ Object
Update release notes for the specified app release.
-
#upload(app_name, binary_path, platform, timeout) ⇒ Object
Uploads the binary file if it has not already been uploaded Takes at least POLLING_INTERVAL_SECONDS between polling get_upload_status.
-
#upload_binary(app_name, binary_path, platform, timeout) ⇒ Object
Uploads the app binary to the Firebase API.
Methods included from Helper::FirebaseAppDistributionHelper
#app_name_from_app_id, #binary_type_from_path, #blank?, #get_ios_app_id_from_archive_plist, #get_value_from_value_or_file, #parse_plist, #present?, #string_to_array
Constructor Details
#initialize(auth_token, debug = false) ⇒ FirebaseAppDistributionApiClient
Returns a new instance of FirebaseAppDistributionApiClient.
23 24 25 26 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 23 def initialize(auth_token, debug = false) @auth_token = auth_token @debug = debug end |
Instance Method Details
#add_testers(project_number, emails) ⇒ Object
Create testers
args
project_number - Firebase project number
emails - An array of emails to be created as testers. A maximum of
1000 testers can be created at a time.
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 219 def add_testers(project_number, emails) payload = { emails: emails } connection.post(add_testers_url(project_number), payload.to_json) do |request| request.headers[AUTHORIZATION] = "Bearer " + @auth_token request.headers[CONTENT_TYPE] = APPLICATION_JSON request.headers[CLIENT_VERSION] = client_version_header_value end rescue Faraday::BadRequestError UI.user_error!(ErrorMessage::INVALID_EMAIL_ADDRESS) rescue Faraday::ResourceNotFound UI.user_error!(ErrorMessage::INVALID_PROJECT) rescue Faraday::ClientError => e if e.response[:status] == 429 UI.user_error!(ErrorMessage::TESTER_LIMIT_VIOLATION) else raise e end end |
#distribute(release_name, emails, group_aliases) ⇒ Object
Enables tester access to the specified app release. Skips this step if no testers are passed in (emails and group_aliases are nil/empty).
args
release_name - App release resource name, returned by upload_status endpoint
emails - String array of app testers' email addresses
group_aliases - String array of Firebase tester group aliases
Throws a user_error if emails or group_aliases are invalid
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 37 def distribute(release_name, emails, group_aliases) if (emails.nil? || emails.empty?) && (group_aliases.nil? || group_aliases.empty?) UI.success("✅ No testers passed in. Skipping this step.") return end payload = { testerEmails: emails, groupAliases: group_aliases } begin connection.post(distribute_url(release_name), payload.to_json) do |request| request.headers[AUTHORIZATION] = "Bearer " + @auth_token request.headers[CONTENT_TYPE] = APPLICATION_JSON request.headers[CLIENT_VERSION] = client_version_header_value end rescue Faraday::ClientError UI.user_error!("#{ErrorMessage::INVALID_TESTERS} \nEmails: #{emails} \nGroup Aliases: #{group_aliases}") end UI.success("✅ Added testers/groups.") end |
#get_aab_info(app_name) ⇒ Object
Get AAB info (Android apps only)
args
app_name - Firebase App resource name
Throws a user_error if the app hasn’t been onboarded to App Distribution
93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 93 def get_aab_info(app_name) begin response = connection.get(aab_info_url(app_name)) do |request| request.headers[AUTHORIZATION] = "Bearer " + @auth_token request.headers[CLIENT_VERSION] = client_version_header_value end rescue Faraday::ResourceNotFound UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{app_name}") end AabInfo.new(response.body) end |
#get_udids(app_id) ⇒ Object
Get tester UDIDs
args
app_name - Firebase App resource name
Returns a list of hashes containing tester device info
200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 200 def get_udids(app_id) begin response = connection.get(get_udids_url(app_id)) do |request| request.headers[AUTHORIZATION] = "Bearer " + @auth_token request.headers[CLIENT_VERSION] = client_version_header_value end rescue Faraday::ResourceNotFound UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{app_id}") end response.body[:testerUdids] || [] end |
#get_upload_status(operation_name) ⇒ Object
Fetches the status of an uploaded binary
args
operation_name - Upload operation name (with binary hash)
Returns the ‘done` status, as well as a release, error, or nil
186 187 188 189 190 191 192 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 186 def get_upload_status(operation_name) response = connection.get(upload_status_url(operation_name)) do |request| request.headers[AUTHORIZATION] = "Bearer " + @auth_token request.headers[CLIENT_VERSION] = client_version_header_value end UploadStatusResponse.new(response.body) end |
#list_releases(app_name, page_size = 100, page_token = nil) ⇒ Object
List releases
args
app_name - Firebase App resource name
page_size - The number of releases to return in the page
page_token - A page token, received from a previous call
Returns the response body. Throws a user_error if the app hasn’t been onboarded to App Distribution.
266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 266 def list_releases(app_name, page_size = 100, page_token = nil) begin response = connection.get(list_releases_url(app_name), { pageSize: page_size.to_s, pageToken: page_token }) do |request| request.headers[AUTHORIZATION] = "Bearer " + @auth_token request.headers[CLIENT_VERSION] = client_version_header_value end rescue Faraday::ResourceNotFound UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{app_name}") end return response.body end |
#remove_testers(project_number, emails) ⇒ Object
Delete testers
args
project_number - Firebase project number
emails - An array of emails to be deleted as testers. A maximum of
1000 testers can be deleted at a time.
Returns the number of testers that were deleted
246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 246 def remove_testers(project_number, emails) payload = { emails: emails } response = connection.post(remove_testers_url(project_number), payload.to_json) do |request| request.headers[AUTHORIZATION] = "Bearer " + @auth_token request.headers[CONTENT_TYPE] = APPLICATION_JSON request.headers[CLIENT_VERSION] = client_version_header_value end response.body[:emails] ? response.body[:emails].count : 0 rescue Faraday::ResourceNotFound UI.user_error!(ErrorMessage::INVALID_PROJECT) end |
#update_release_notes(release_name, release_notes) ⇒ Object
Update release notes for the specified app release. Skips this step if no notes are passed in (release_notes is nil/empty).
args
release_name - App release resource name, returned by upload_status endpoint
release_notes - String of notes for this release
Throws a user_error if the release_notes are invalid
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 63 def update_release_notes(release_name, release_notes) if release_notes.nil? || release_notes.empty? UI.success("✅ No release notes passed in. Skipping this step.") return end begin payload = { name: release_name, releaseNotes: { text: release_notes } } connection.patch(update_release_notes_url(release_name), payload.to_json) do |request| request.headers[AUTHORIZATION] = "Bearer " + @auth_token request.headers[CONTENT_TYPE] = APPLICATION_JSON request.headers[CLIENT_VERSION] = client_version_header_value end rescue Faraday::ClientError => e error = ErrorResponse.new(e.response) UI.user_error!("#{ErrorMessage::INVALID_RELEASE_NOTES}: #{error.}") end UI.success("✅ Posted release notes.") end |
#upload(app_name, binary_path, platform, timeout) ⇒ Object
Uploads the binary file if it has not already been uploaded Takes at least POLLING_INTERVAL_SECONDS between polling get_upload_status
args
app_name - Firebase App resource name
binary_path - Absolute path to your app's aab/apk/ipa file
timeout - The amount of seconds before the upload will timeout, if not completed
Returns the release_name of the uploaded release.
Crashes if the number of polling retries exceeds MAX_POLLING_RETRIES or if the binary cannot be uploaded.
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 143 def upload(app_name, binary_path, platform, timeout) binary_type = binary_type_from_path(binary_path) UI.("⌛ Uploading the #{binary_type}.") operation_name = upload_binary(app_name, binary_path, platform, timeout) upload_status_response = get_upload_status(operation_name) MAX_POLLING_RETRIES.times do if upload_status_response.success? if upload_status_response.release_updated? UI.success("✅ Uploaded #{binary_type} successfully; updated provisioning profile of existing release #{upload_status_response.release_version}.") break elsif upload_status_response.release_unmodified? UI.success("✅ The same #{binary_type} was found in release #{upload_status_response.release_version} with no changes, skipping.") break else UI.success("✅ Uploaded #{binary_type} successfully and created release #{upload_status_response.release_version}.") end break elsif upload_status_response.in_progress? sleep(POLLING_INTERVAL_SECONDS) upload_status_response = get_upload_status(operation_name) else if !upload_status_response..nil? UI.user_error!("#{ErrorMessage.upload_binary_error(binary_type)}: #{upload_status_response.}") else UI.user_error!(ErrorMessage.upload_binary_error(binary_type)) end end end unless upload_status_response.success? UI.crash!("It took longer than expected to process your #{binary_type}, please try again.") end upload_status_response end |
#upload_binary(app_name, binary_path, platform, timeout) ⇒ Object
Uploads the app binary to the Firebase API
args
app_name - Firebase App resource name
binary_path - Absolute path to your app's aab/apk/ipa file
platform - 'android' or 'ios'
timeout - The amount of seconds before the upload will timeout, if not completed
Throws a user_error if the binary file does not exist
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 115 def upload_binary(app_name, binary_path, platform, timeout) response = connection.post(binary_upload_url(app_name), read_binary(binary_path)) do |request| request..timeout = timeout # seconds request.headers[AUTHORIZATION] = "Bearer " + @auth_token request.headers[CONTENT_TYPE] = APPLICATION_OCTET_STREAM request.headers[CLIENT_VERSION] = client_version_header_value request.headers["X-Goog-Upload-File-Name"] = File.basename(binary_path) request.headers["X-Goog-Upload-Protocol"] = "raw" end response.body[:name] || '' rescue Errno::ENOENT # Raised when binary_path file does not exist binary_type = binary_type_from_path(binary_path) UI.user_error!("#{ErrorMessage.binary_not_found(binary_type)}: #{binary_path}") end |