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.
-
#add_testers_to_group(project_number, group_alias, emails, create_missing_testers = false) ⇒ Object
Add testers to group.
-
#create_group(project_number, group_alias, display_name) ⇒ Object
Create tester group.
-
#delete_group(project_number, group_alias) ⇒ Object
Delete tester group.
-
#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.
-
#remove_testers_from_group(project_number, group_alias, emails) ⇒ Object
Remove testers from group.
-
#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.
22 23 24 25 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 22 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.
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 215 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 |
#add_testers_to_group(project_number, group_alias, emails, create_missing_testers = false) ⇒ Object
Add testers to group
args
project_number - Firebase project number
group_alias - Alias of the tester group
emails - An array of emails to be added to the group.
A maximum of 1000 testers can be added at a time, if creating missing testers is enabled.
create_missing_testers - If true, missing testers will be created and added to the group.
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 293 def add_testers_to_group(project_number, group_alias, emails, create_missing_testers = false) payload = { emails: emails, createMissingTesters: create_missing_testers } response = connection.post(add_testers_to_group_url(project_number, group_alias), 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 rescue Faraday::BadRequestError UI.user_error!(ErrorMessage::INVALID_EMAIL_ADDRESS) rescue Faraday::ResourceNotFound UI.user_error!(ErrorMessage::INVALID_TESTER_GROUP) rescue Faraday::ClientError => e raise e end |
#create_group(project_number, group_alias, display_name) ⇒ Object
Create tester group
args
project_number - Firebase project number
group_alias - Alias of the tester group
display_name - Display name of the tester group
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 261 def create_group(project_number, group_alias, display_name) payload = { name: "projects/#{project_number}/groups/#{group_alias}", displayName: display_name } response = connection.post(add_tester_group_url(project_number), payload.to_json) do |request| request.params["groupId"] = group_alias request.headers[AUTHORIZATION] = "Bearer " + @auth_token request.headers[CONTENT_TYPE] = APPLICATION_JSON request.headers[CLIENT_VERSION] = client_version_header_value end response.body rescue Faraday::BadRequestError UI.user_error!(ErrorMessage::INVALID_TESTER_GROUP_NAME) rescue Faraday::ResourceNotFound UI.user_error!(ErrorMessage::INVALID_PROJECT) rescue Faraday::ConflictError UI.important("Tester group #{group_alias} already exists.") return { name: "projects/#{project_number}/groups/#{group_alias}" } rescue Faraday::ClientError => e raise e end |
#delete_group(project_number, group_alias) ⇒ Object
Delete tester group
args
project_number - Firebase project number
group_alias - Alias of the tester group
339 340 341 342 343 344 345 346 347 348 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 339 def delete_group(project_number, group_alias) response = connection.delete(delete_tester_group_url(project_number, group_alias)) 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 rescue Faraday::ResourceNotFound UI.user_error!(ErrorMessage::INVALID_TESTER_GROUP) 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
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 36 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
89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 89 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
196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 196 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
182 183 184 185 186 187 188 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 182 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.
358 359 360 361 362 363 364 365 366 367 368 369 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 358 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 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
242 243 244 245 246 247 248 249 250 251 252 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 242 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 |
#remove_testers_from_group(project_number, group_alias, emails) ⇒ Object
Remove testers from group
args
project_number - Firebase project number
group_alias - Alias of the tester group
emails - An array of emails to be removed from the group.
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 317 def remove_testers_from_group(project_number, group_alias, emails) payload = { emails: emails } response = connection.post(remove_testers_from_group_url(project_number, group_alias), 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 rescue Faraday::BadRequestError UI.user_error!(ErrorMessage::INVALID_EMAIL_ADDRESS) rescue Faraday::ResourceNotFound UI.user_error!(ErrorMessage::INVALID_TESTER_GROUP) rescue Faraday::ClientError => e raise e 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
Returns a hash of the release
Throws a user_error if the release_notes are invalid
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 64 def update_release_notes(release_name, release_notes) payload = { name: release_name, releaseNotes: { text: release_notes } } response = 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 UI.success("✅ Posted release notes.") response.body rescue Faraday::ClientError => e error = ErrorResponse.new(e.response) UI.user_error!("#{ErrorMessage::INVALID_RELEASE_NOTES}: #{error.}") 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 a ‘UploadStatusResponse` with the upload is complete.
Crashes if the number of polling retries exceeds MAX_POLLING_RETRIES or if the binary cannot be uploaded.
139 140 141 142 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 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 139 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
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb', line 111 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 |