fastlane-plugin-firebase_app_distribution 0.1.4 → 0.2.0.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 +5 -5
 - data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_action.rb +44 -22
 - data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_login.rb +58 -0
 - data/lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb +185 -0
 - data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_auth_client.rb +48 -0
 - data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_error_message.rb +21 -0
 - data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_helper.rb +21 -47
 - data/lib/fastlane/plugin/firebase_app_distribution/helper/upload_status_response.rb +25 -0
 - data/lib/fastlane/plugin/firebase_app_distribution/version.rb +1 -1
 - metadata +16 -6
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 2 
     | 
    
         
            +
            SHA1:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: ab7379d2d8feb6112f778c3b4a64e2f2181a099a
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: bdb617b84fb387a5486faee45d23be3043a9d9af
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 69f808e806793eb81839ac45241445c8764884f35c92c25066c86121c5ecb7ebf981371ed347fceadbfb0161df03ac6613fbd3f2aebe42a935783ca55d239df5
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 83c298cdfd08b945957f10f9194142423418b89ee5dc17a2718b1506013e79fbba2f94ad11e1b7c0b92a874c3e69731eba327e66f393bb61b99fae0bf423d5b5
         
     | 
    
        data/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_action.rb
    CHANGED
    
    | 
         @@ -1,8 +1,12 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'tempfile'
         
     | 
| 
       2 
1 
     | 
    
         
             
            require 'fastlane/action'
         
     | 
| 
       3 
2 
     | 
    
         
             
            require 'open3'
         
     | 
| 
       4 
3 
     | 
    
         
             
            require 'shellwords'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'googleauth'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require_relative '../helper/upload_status_response'
         
     | 
| 
       5 
6 
     | 
    
         
             
            require_relative '../helper/firebase_app_distribution_helper'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require_relative '../helper/firebase_app_distribution_error_message'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require_relative '../client/firebase_app_distribution_api_client'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require_relative '../helper/firebase_app_distribution_auth_client'
         
     | 
| 
       6 
10 
     | 
    
         | 
| 
       7 
11 
     | 
    
         
             
            ## TODO: should always use a file underneath? I think so.
         
     | 
| 
       8 
12 
     | 
    
         
             
            ## How should we document the usage of release notes?
         
     | 
| 
         @@ -12,28 +16,42 @@ module Fastlane 
     | 
|
| 
       12 
16 
     | 
    
         
             
                  DEFAULT_FIREBASE_CLI_PATH = `which firebase`
         
     | 
| 
       13 
17 
     | 
    
         
             
                  FIREBASECMD_ACTION = "appdistribution:distribute".freeze
         
     | 
| 
       14 
18 
     | 
    
         | 
| 
      
 19 
     | 
    
         
            +
                  extend Auth::FirebaseAppDistributionAuthClient
         
     | 
| 
       15 
20 
     | 
    
         
             
                  extend Helper::FirebaseAppDistributionHelper
         
     | 
| 
       16 
21 
     | 
    
         | 
| 
       17 
22 
     | 
    
         
             
                  def self.run(params)
         
     | 
| 
       18 
23 
     | 
    
         
             
                    params.values # to validate all inputs before looking for the ipa/apk
         
     | 
| 
       19 
     | 
    
         
            -
                     
     | 
| 
       20 
     | 
    
         
            -
                     
     | 
| 
       21 
     | 
    
         
            -
                     
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
                     
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                     
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
                       
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
                     
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
                     
     | 
| 
      
 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]
         
     | 
| 
      
 27 
     | 
    
         
            +
                    binary_path = params[:ipa_path] || params[:apk_path]
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    if params[:app] # Set app_id if it is specified as a parameter
         
     | 
| 
      
 30 
     | 
    
         
            +
                      app_id = params[:app]
         
     | 
| 
      
 31 
     | 
    
         
            +
                    elsif platform == :ios
         
     | 
| 
      
 32 
     | 
    
         
            +
                      archive_path = Actions.lane_context[SharedValues::XCODEBUILD_ARCHIVE]
         
     | 
| 
      
 33 
     | 
    
         
            +
                      if archive_path
         
     | 
| 
      
 34 
     | 
    
         
            +
                        app_id = get_ios_app_id_from_archive(archive_path)
         
     | 
| 
      
 35 
     | 
    
         
            +
                      end
         
     | 
| 
      
 36 
     | 
    
         
            +
                    end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                    if app_id.nil?
         
     | 
| 
      
 39 
     | 
    
         
            +
                      UI.crash!(ErrorMessage::MISSING_APP_ID)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
                    release_id = fad_api_client.upload(app_id, binary_path)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    if release_id.nil?
         
     | 
| 
      
 43 
     | 
    
         
            +
                      return
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    release_notes = get_value_from_value_or_file(params[:release_notes], params[:release_notes_file])
         
     | 
| 
      
 47 
     | 
    
         
            +
                    fad_api_client.post_notes(app_id, release_id, release_notes)
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                    testers = get_value_from_value_or_file(params[:testers], params[:testers_file])
         
     | 
| 
      
 50 
     | 
    
         
            +
                    groups = get_value_from_value_or_file(params[:groups], params[:groups_file])
         
     | 
| 
      
 51 
     | 
    
         
            +
                    emails = string_to_array(testers)
         
     | 
| 
      
 52 
     | 
    
         
            +
                    group_ids = string_to_array(groups)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    fad_api_client.enable_access(app_id, release_id, emails, group_ids)
         
     | 
| 
      
 54 
     | 
    
         
            +
                    UI.success("App Distribution upload finished successfully")
         
     | 
| 
       37 
55 
     | 
    
         
             
                  end
         
     | 
| 
       38 
56 
     | 
    
         | 
| 
       39 
57 
     | 
    
         
             
                  def self.description
         
     | 
| 
         @@ -41,7 +59,7 @@ module Fastlane 
     | 
|
| 
       41 
59 
     | 
    
         
             
                  end
         
     | 
| 
       42 
60 
     | 
    
         | 
| 
       43 
61 
     | 
    
         
             
                  def self.authors
         
     | 
| 
       44 
     | 
    
         
            -
                    ["Stefan Natchev"]
         
     | 
| 
      
 62 
     | 
    
         
            +
                    ["Stefan Natchev", "Manny Jimenez Github: mannyjimenez0810, Alonso Salas Infante Github: alonsosalasinfante"]
         
     | 
| 
       45 
63 
     | 
    
         
             
                  end
         
     | 
| 
       46 
64 
     | 
    
         | 
| 
       47 
65 
     | 
    
         
             
                  # supports markdown.
         
     | 
| 
         @@ -84,7 +102,7 @@ module Fastlane 
     | 
|
| 
       84 
102 
     | 
    
         
             
                      FastlaneCore::ConfigItem.new(key: :app,
         
     | 
| 
       85 
103 
     | 
    
         
             
                                                   env_name: "FIREBASEAPPDISTRO_APP",
         
     | 
| 
       86 
104 
     | 
    
         
             
                                                   description: "Your app's Firebase App ID. You can find the App ID in the Firebase console, on the General Settings page",
         
     | 
| 
       87 
     | 
    
         
            -
                                                   optional:  
     | 
| 
      
 105 
     | 
    
         
            +
                                                   optional: true,
         
     | 
| 
       88 
106 
     | 
    
         
             
                                                   type: String),
         
     | 
| 
       89 
107 
     | 
    
         
             
                      FastlaneCore::ConfigItem.new(key: :firebase_cli_path,
         
     | 
| 
       90 
108 
     | 
    
         
             
                                                   env_name: "FIREBASEAPPDISTRO_FIREBASE_CLI_PATH",
         
     | 
| 
         @@ -143,7 +161,11 @@ module Fastlane 
     | 
|
| 
       143 
161 
     | 
    
         
             
                                                   description: "Print verbose debug output",
         
     | 
| 
       144 
162 
     | 
    
         
             
                                                   optional: true,
         
     | 
| 
       145 
163 
     | 
    
         
             
                                                   default_value: false,
         
     | 
| 
       146 
     | 
    
         
            -
                                                   is_string: false)
         
     | 
| 
      
 164 
     | 
    
         
            +
                                                   is_string: false),
         
     | 
| 
      
 165 
     | 
    
         
            +
                      FastlaneCore::ConfigItem.new(key: :service_credentials_file,
         
     | 
| 
      
 166 
     | 
    
         
            +
                                                   description: "Path to Google service account json",
         
     | 
| 
      
 167 
     | 
    
         
            +
                                                   optional: true,
         
     | 
| 
      
 168 
     | 
    
         
            +
                                                   type: String)
         
     | 
| 
       147 
169 
     | 
    
         
             
                    ]
         
     | 
| 
       148 
170 
     | 
    
         
             
                  end
         
     | 
| 
       149 
171 
     | 
    
         | 
| 
         @@ -0,0 +1,58 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'googleauth'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'googleauth/stores/file_token_store'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require "google/apis/people_v1"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "fileutils"
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Fastlane
         
     | 
| 
      
 7 
     | 
    
         
            +
              module Actions
         
     | 
| 
      
 8 
     | 
    
         
            +
                class FirebaseAppDistributionLoginAction < Action
         
     | 
| 
      
 9 
     | 
    
         
            +
                  OOB_URI = "urn:ietf:wg:oauth:2.0:oob"
         
     | 
| 
      
 10 
     | 
    
         
            +
                  SCOPE = "https://www.googleapis.com/auth/cloud-platform"
         
     | 
| 
      
 11 
     | 
    
         
            +
                  CLIENT_ID = "563584335869-fgrhgmd47bqnekij5i8b5pr03ho849e6.apps.googleusercontent.com"
         
     | 
| 
      
 12 
     | 
    
         
            +
                  CLIENT_SECRET = "j9iVZfS8kkCEFUPaAeJV0sAi"
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def self.run(params)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    client_id = Google::Auth::ClientId.new(CLIENT_ID, CLIENT_SECRET)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    authorizer = Google::Auth::UserAuthorizer.new(client_id, SCOPE, nil)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    url = authorizer.get_authorization_url(base_url: OOB_URI)
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                    UI.message("Please open the following address in your browser:")
         
     | 
| 
      
 20 
     | 
    
         
            +
                    UI.message(url)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    UI.message("")
         
     | 
| 
      
 22 
     | 
    
         
            +
                    code = UI.input("Enter the resulting code here: ")
         
     | 
| 
      
 23 
     | 
    
         
            +
                    credentials = authorizer.get_credentials_from_code(code: code, base_url: OOB_URI)
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    UI.message("Refresh Token: #{credentials.refresh_token}")
         
     | 
| 
      
 26 
     | 
    
         
            +
                    UI.message("")
         
     | 
| 
      
 27 
     | 
    
         
            +
                    UI.message("Set the refresh token as a FIREBASE_TOKEN environment variable")
         
     | 
| 
      
 28 
     | 
    
         
            +
                  rescue Signet::AuthorizationError
         
     | 
| 
      
 29 
     | 
    
         
            +
                    UI.error("The code you entered was invalid. Ensure that you have copied the code correctly.")
         
     | 
| 
      
 30 
     | 
    
         
            +
                  rescue => error
         
     | 
| 
      
 31 
     | 
    
         
            +
                    UI.error(error.to_s)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    UI.crash!("An error has occured please login again.")
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  #####################################################
         
     | 
| 
      
 36 
     | 
    
         
            +
                  # @!group Documentation
         
     | 
| 
      
 37 
     | 
    
         
            +
                  #####################################################
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  def self.description
         
     | 
| 
      
 40 
     | 
    
         
            +
                    "Authenticate with Firebase App Distribution using a Google account."
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  def self.details
         
     | 
| 
      
 44 
     | 
    
         
            +
                    "Log in to Firebase App Distribution using a Google account to generate an authentication "\
         
     | 
| 
      
 45 
     | 
    
         
            +
                    "token. This token is stored within an environment variable and used to authenticate with your Firebase project. "\
         
     | 
| 
      
 46 
     | 
    
         
            +
                    "See https://firebase.google.com/docs/app-distribution/ios/distribute-fastlane for more information."
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  def self.authors
         
     | 
| 
      
 50 
     | 
    
         
            +
                    ["Manny Jimenez Github: mannyjimenez0810, Alonso Salas Infante Github: alonsosalasinfante"]
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                  def self.is_supported?(platform)
         
     | 
| 
      
 54 
     | 
    
         
            +
                    [:ios, :android].include?(platform)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb
    ADDED
    
    | 
         @@ -0,0 +1,185 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'fastlane_core/ui/ui'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require_relative '../actions/firebase_app_distribution_login'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Fastlane
         
     | 
| 
      
 5 
     | 
    
         
            +
              module Client
         
     | 
| 
      
 6 
     | 
    
         
            +
                class FirebaseAppDistributionApiClient
         
     | 
| 
      
 7 
     | 
    
         
            +
                  BASE_URL = "https://firebaseappdistribution.googleapis.com"
         
     | 
| 
      
 8 
     | 
    
         
            +
                  TOKEN_CREDENTIAL_URI = "https://oauth2.googleapis.com/token"
         
     | 
| 
      
 9 
     | 
    
         
            +
                  MAX_POLLING_RETRIES = 60
         
     | 
| 
      
 10 
     | 
    
         
            +
                  POLLING_INTERVAL_SECONDS = 2
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  def initialize(auth_token)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @auth_token = auth_token
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  # Enables tester access to the specified app release. Skips this
         
     | 
| 
      
 17 
     | 
    
         
            +
                  # step if no testers are passed in (emails and group_ids are nil/empty).
         
     | 
| 
      
 18 
     | 
    
         
            +
                  #
         
     | 
| 
      
 19 
     | 
    
         
            +
                  # args
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #   app_id - Firebase App ID
         
     | 
| 
      
 21 
     | 
    
         
            +
                  #   release_id - App release ID, returned by upload_status endpoint
         
     | 
| 
      
 22 
     | 
    
         
            +
                  #   emails - String array of app testers' email addresses
         
     | 
| 
      
 23 
     | 
    
         
            +
                  #   group_ids - String array of Firebase tester group IDs
         
     | 
| 
      
 24 
     | 
    
         
            +
                  #
         
     | 
| 
      
 25 
     | 
    
         
            +
                  # Throws a user_error if app_id, emails, or group_ids are invalid
         
     | 
| 
      
 26 
     | 
    
         
            +
                  def enable_access(app_id, release_id, emails, group_ids)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    if (emails.nil? || emails.empty?) && (group_ids.nil? || group_ids.empty?)
         
     | 
| 
      
 28 
     | 
    
         
            +
                      UI.message("No testers passed in. Skipping this step")
         
     | 
| 
      
 29 
     | 
    
         
            +
                      return
         
     | 
| 
      
 30 
     | 
    
         
            +
                    end
         
     | 
| 
      
 31 
     | 
    
         
            +
                    payload = { emails: emails, groupIds: group_ids }
         
     | 
| 
      
 32 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 33 
     | 
    
         
            +
                      connection.post(enable_access_url(app_id, release_id), payload.to_json) do |request|
         
     | 
| 
      
 34 
     | 
    
         
            +
                        request.headers["Authorization"] = "Bearer " + @auth_token
         
     | 
| 
      
 35 
     | 
    
         
            +
                      end
         
     | 
| 
      
 36 
     | 
    
         
            +
                    rescue Faraday::ResourceNotFound
         
     | 
| 
      
 37 
     | 
    
         
            +
                      UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{app_id}")
         
     | 
| 
      
 38 
     | 
    
         
            +
                    rescue Faraday::ClientError
         
     | 
| 
      
 39 
     | 
    
         
            +
                      UI.user_error!("#{ErrorMessage::INVALID_TESTERS} \nEmails: #{emails} \nGroups: #{group_ids}")
         
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  # Posts notes for the specified app release. Skips this
         
     | 
| 
      
 44 
     | 
    
         
            +
                  # step if no notes are passed in (release_notes is nil/empty).
         
     | 
| 
      
 45 
     | 
    
         
            +
                  #
         
     | 
| 
      
 46 
     | 
    
         
            +
                  # args
         
     | 
| 
      
 47 
     | 
    
         
            +
                  #   app_id - Firebase App ID
         
     | 
| 
      
 48 
     | 
    
         
            +
                  #   release_id - App release ID, returned by upload_status endpoint
         
     | 
| 
      
 49 
     | 
    
         
            +
                  #   release_notes - String of notes for this release
         
     | 
| 
      
 50 
     | 
    
         
            +
                  #
         
     | 
| 
      
 51 
     | 
    
         
            +
                  # Throws a user_error if app_id or release_id are invalid
         
     | 
| 
      
 52 
     | 
    
         
            +
                  def post_notes(app_id, release_id, release_notes)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    payload = { releaseNotes: { releaseNotes: release_notes } }
         
     | 
| 
      
 54 
     | 
    
         
            +
                    if release_notes.nil? || release_notes.empty?
         
     | 
| 
      
 55 
     | 
    
         
            +
                      UI.message("No release notes passed in. Skipping this step.")
         
     | 
| 
      
 56 
     | 
    
         
            +
                      return
         
     | 
| 
      
 57 
     | 
    
         
            +
                    end
         
     | 
| 
      
 58 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 59 
     | 
    
         
            +
                      connection.post(release_notes_create_url(app_id, release_id), payload.to_json) do |request|
         
     | 
| 
      
 60 
     | 
    
         
            +
                        request.headers["Authorization"] = "Bearer " + @auth_token
         
     | 
| 
      
 61 
     | 
    
         
            +
                      end
         
     | 
| 
      
 62 
     | 
    
         
            +
                    rescue Faraday::ResourceNotFound
         
     | 
| 
      
 63 
     | 
    
         
            +
                      UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{app_id}")
         
     | 
| 
      
 64 
     | 
    
         
            +
                      # rescue Faraday::ClientError
         
     | 
| 
      
 65 
     | 
    
         
            +
                      #   UI.user_error!("#{ErrorMessage::INVALID_RELEASE_ID}: #{release_id}")
         
     | 
| 
      
 66 
     | 
    
         
            +
                    end
         
     | 
| 
      
 67 
     | 
    
         
            +
                    UI.success("Release notes have been posted.")
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                  def get_upload_token(app_id, binary_path)
         
     | 
| 
      
 71 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 72 
     | 
    
         
            +
                      binary_hash = Digest::SHA256.hexdigest(File.open(binary_path).read)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    rescue Errno::ENOENT
         
     | 
| 
      
 74 
     | 
    
         
            +
                      UI.crash!("#{ErrorMessage::APK_NOT_FOUND}: #{binary_path}")
         
     | 
| 
      
 75 
     | 
    
         
            +
                    end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 78 
     | 
    
         
            +
                      response = connection.get(v1_apps_url(app_id)) do |request|
         
     | 
| 
      
 79 
     | 
    
         
            +
                        request.headers["Authorization"] = "Bearer " + @auth_token
         
     | 
| 
      
 80 
     | 
    
         
            +
                      end
         
     | 
| 
      
 81 
     | 
    
         
            +
                    rescue Faraday::ResourceNotFound
         
     | 
| 
      
 82 
     | 
    
         
            +
                      UI.crash!("#{ErrorMessage::INVALID_APP_ID}: #{app_id}")
         
     | 
| 
      
 83 
     | 
    
         
            +
                    end
         
     | 
| 
      
 84 
     | 
    
         
            +
                    contact_email = response.body[:contactEmail]
         
     | 
| 
      
 85 
     | 
    
         
            +
                    if contact_email.nil? || contact_email.strip.empty?
         
     | 
| 
      
 86 
     | 
    
         
            +
                      UI.crash!(ErrorMessage::GET_APP_NO_CONTACT_EMAIL_ERROR)
         
     | 
| 
      
 87 
     | 
    
         
            +
                    end
         
     | 
| 
      
 88 
     | 
    
         
            +
                    return upload_token_format(response.body[:appId], response.body[:projectNumber], binary_hash)
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                  def upload_binary(app_id, binary_path)
         
     | 
| 
      
 92 
     | 
    
         
            +
                    connection.post(binary_upload_url(app_id), File.open(binary_path).read) do |request|
         
     | 
| 
      
 93 
     | 
    
         
            +
                      request.headers["Authorization"] = "Bearer " + @auth_token
         
     | 
| 
      
 94 
     | 
    
         
            +
                    end
         
     | 
| 
      
 95 
     | 
    
         
            +
                  rescue Faraday::ResourceNotFound
         
     | 
| 
      
 96 
     | 
    
         
            +
                    UI.crash!("#{ErrorMessage::INVALID_APP_ID}: #{app_id}")
         
     | 
| 
      
 97 
     | 
    
         
            +
                  rescue Errno::ENOENT
         
     | 
| 
      
 98 
     | 
    
         
            +
                    UI.crash!("#{ErrorMessage::APK_NOT_FOUND}: #{binary_path}")
         
     | 
| 
      
 99 
     | 
    
         
            +
                  end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                  # Uploads the binary file if it has not already been uploaded
         
     | 
| 
      
 102 
     | 
    
         
            +
                  # Takes at least POLLING_INTERVAL_SECONDS between polling get_upload_status
         
     | 
| 
      
 103 
     | 
    
         
            +
                  #
         
     | 
| 
      
 104 
     | 
    
         
            +
                  # args
         
     | 
| 
      
 105 
     | 
    
         
            +
                  #   app_id - Firebase App ID
         
     | 
| 
      
 106 
     | 
    
         
            +
                  #   binary_path - Absolute path to your app's apk/ipa file
         
     | 
| 
      
 107 
     | 
    
         
            +
                  #
         
     | 
| 
      
 108 
     | 
    
         
            +
                  # Returns the release_id on a successful release, otherwise returns nil.
         
     | 
| 
      
 109 
     | 
    
         
            +
                  #
         
     | 
| 
      
 110 
     | 
    
         
            +
                  # Throws an error if the number of polling retries exceeds MAX_POLLING_RETRIES
         
     | 
| 
      
 111 
     | 
    
         
            +
                  def upload(app_id, binary_path)
         
     | 
| 
      
 112 
     | 
    
         
            +
                    upload_token = get_upload_token(app_id, binary_path)
         
     | 
| 
      
 113 
     | 
    
         
            +
                    upload_status_response = get_upload_status(app_id, upload_token)
         
     | 
| 
      
 114 
     | 
    
         
            +
                    if upload_status_response.success?
         
     | 
| 
      
 115 
     | 
    
         
            +
                      UI.success("This APK/IPA has been uploaded before. Skipping upload step.")
         
     | 
| 
      
 116 
     | 
    
         
            +
                    else
         
     | 
| 
      
 117 
     | 
    
         
            +
                      UI.message("This APK has not been uploaded before.")
         
     | 
| 
      
 118 
     | 
    
         
            +
                      MAX_POLLING_RETRIES.times do
         
     | 
| 
      
 119 
     | 
    
         
            +
                        if upload_status_response.success?
         
     | 
| 
      
 120 
     | 
    
         
            +
                          UI.success("Uploaded APK/IPA Successfully!")
         
     | 
| 
      
 121 
     | 
    
         
            +
                          break
         
     | 
| 
      
 122 
     | 
    
         
            +
                        elsif upload_status_response.in_progress?
         
     | 
| 
      
 123 
     | 
    
         
            +
                          sleep(POLLING_INTERVAL_SECONDS)
         
     | 
| 
      
 124 
     | 
    
         
            +
                        else
         
     | 
| 
      
 125 
     | 
    
         
            +
                          UI.message("Uploading the APK/IPA.")
         
     | 
| 
      
 126 
     | 
    
         
            +
                          upload_binary(app_id, binary_path)
         
     | 
| 
      
 127 
     | 
    
         
            +
                        end
         
     | 
| 
      
 128 
     | 
    
         
            +
                        upload_status_response = get_upload_status(app_id, upload_token)
         
     | 
| 
      
 129 
     | 
    
         
            +
                      end
         
     | 
| 
      
 130 
     | 
    
         
            +
                      unless upload_status_response.success?
         
     | 
| 
      
 131 
     | 
    
         
            +
                        UI.error("It took longer than expected to process your APK/IPA, please try again.")
         
     | 
| 
      
 132 
     | 
    
         
            +
                        return nil
         
     | 
| 
      
 133 
     | 
    
         
            +
                      end
         
     | 
| 
      
 134 
     | 
    
         
            +
                    end
         
     | 
| 
      
 135 
     | 
    
         
            +
                    upload_status_response.release_id
         
     | 
| 
      
 136 
     | 
    
         
            +
                  end
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                  # Gets the upload status for the app release.
         
     | 
| 
      
 139 
     | 
    
         
            +
                  def get_upload_status(app_id, app_token)
         
     | 
| 
      
 140 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 141 
     | 
    
         
            +
                      response = connection.get(upload_status_url(app_id, app_token)) do |request|
         
     | 
| 
      
 142 
     | 
    
         
            +
                        request.headers["Authorization"] = "Bearer " + @auth_token
         
     | 
| 
      
 143 
     | 
    
         
            +
                      end
         
     | 
| 
      
 144 
     | 
    
         
            +
                    rescue Faraday::ResourceNotFound
         
     | 
| 
      
 145 
     | 
    
         
            +
                      UI.crash!("#{ErrorMessage::INVALID_APP_ID}: #{app_id}")
         
     | 
| 
      
 146 
     | 
    
         
            +
                    end
         
     | 
| 
      
 147 
     | 
    
         
            +
                    return UploadStatusResponse.new(response.body)
         
     | 
| 
      
 148 
     | 
    
         
            +
                  end
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                  private
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                  def v1_apps_url(app_id)
         
     | 
| 
      
 153 
     | 
    
         
            +
                    "/v1alpha/apps/#{app_id}"
         
     | 
| 
      
 154 
     | 
    
         
            +
                  end
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
                  def release_notes_create_url(app_id, release_id)
         
     | 
| 
      
 157 
     | 
    
         
            +
                    "#{v1_apps_url(app_id)}/releases/#{release_id}/notes"
         
     | 
| 
      
 158 
     | 
    
         
            +
                  end
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
                  def enable_access_url(app_id, release_id)
         
     | 
| 
      
 161 
     | 
    
         
            +
                    "#{v1_apps_url(app_id)}/releases/#{release_id}/enable_access"
         
     | 
| 
      
 162 
     | 
    
         
            +
                  end
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                  def binary_upload_url(app_id)
         
     | 
| 
      
 165 
     | 
    
         
            +
                    "/app-binary-uploads?app_id=#{app_id}"
         
     | 
| 
      
 166 
     | 
    
         
            +
                  end
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
                  def upload_status_url(app_id, app_token)
         
     | 
| 
      
 169 
     | 
    
         
            +
                    "#{v1_apps_url(app_id)}/upload_status/#{app_token}"
         
     | 
| 
      
 170 
     | 
    
         
            +
                  end
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                  def upload_token_format(app_id, project_number, binary_hash)
         
     | 
| 
      
 173 
     | 
    
         
            +
                    CGI.escape("projects/#{project_number}/apps/#{app_id}/releases/-/binaries/#{binary_hash}")
         
     | 
| 
      
 174 
     | 
    
         
            +
                  end
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
                  def connection
         
     | 
| 
      
 177 
     | 
    
         
            +
                    @connection ||= Faraday.new(url: BASE_URL) do |conn|
         
     | 
| 
      
 178 
     | 
    
         
            +
                      conn.response(:json, parser_options: { symbolize_names: true })
         
     | 
| 
      
 179 
     | 
    
         
            +
                      conn.response(:raise_error) # raise_error middleware will run before the json middleware
         
     | 
| 
      
 180 
     | 
    
         
            +
                      conn.adapter(Faraday.default_adapter)
         
     | 
| 
      
 181 
     | 
    
         
            +
                    end
         
     | 
| 
      
 182 
     | 
    
         
            +
                  end
         
     | 
| 
      
 183 
     | 
    
         
            +
                end
         
     | 
| 
      
 184 
     | 
    
         
            +
              end
         
     | 
| 
      
 185 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_auth_client.rb
    ADDED
    
    | 
         @@ -0,0 +1,48 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'fastlane_core/ui/ui'
         
     | 
| 
      
 2 
     | 
    
         
            +
            module Fastlane
         
     | 
| 
      
 3 
     | 
    
         
            +
              UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Auth
         
     | 
| 
      
 5 
     | 
    
         
            +
                module FirebaseAppDistributionAuthClient
         
     | 
| 
      
 6 
     | 
    
         
            +
                  TOKEN_CREDENTIAL_URI = "https://oauth2.googleapis.com/token"
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def fetch_auth_token(google_service_path)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    if !google_service_path.nil? && !google_service_path.empty?
         
     | 
| 
      
 10 
     | 
    
         
            +
                      service_account(google_service_path)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    elsif ENV["FIREBASE_TOKEN"]
         
     | 
| 
      
 12 
     | 
    
         
            +
                      firebase_token
         
     | 
| 
      
 13 
     | 
    
         
            +
                    elsif ENV["GOOGLE_APPLICATION_CREDENTIALS"]
         
     | 
| 
      
 14 
     | 
    
         
            +
                      service_account(ENV["GOOGLE_APPLICATION_CREDENTIALS"])
         
     | 
| 
      
 15 
     | 
    
         
            +
                    else
         
     | 
| 
      
 16 
     | 
    
         
            +
                      UI.crash!(ErrorMessage::MISSING_CREDENTIALS)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  private
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  def firebase_token
         
     | 
| 
      
 23 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 24 
     | 
    
         
            +
                      client = Signet::OAuth2::Client.new(
         
     | 
| 
      
 25 
     | 
    
         
            +
                        token_credential_uri: TOKEN_CREDENTIAL_URI,
         
     | 
| 
      
 26 
     | 
    
         
            +
                        client_id: Fastlane::Actions::FirebaseAppDistributionLoginAction::CLIENT_ID,
         
     | 
| 
      
 27 
     | 
    
         
            +
                        client_secret: Fastlane::Actions::FirebaseAppDistributionLoginAction::CLIENT_SECRET,
         
     | 
| 
      
 28 
     | 
    
         
            +
                        refresh_token: ENV["FIREBASE_TOKEN"]
         
     | 
| 
      
 29 
     | 
    
         
            +
                      )
         
     | 
| 
      
 30 
     | 
    
         
            +
                    rescue Signet::AuthorizationError
         
     | 
| 
      
 31 
     | 
    
         
            +
                      UI.crash!(ErrorMessage::REFRESH_TOKEN_ERROR)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                    client.fetch_access_token!
         
     | 
| 
      
 34 
     | 
    
         
            +
                    client.access_token
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  def service_account(google_service_path)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    service_account_credentials = Google::Auth::ServiceAccountCredentials.make_creds(
         
     | 
| 
      
 39 
     | 
    
         
            +
                      json_key_io: File.open(google_service_path),
         
     | 
| 
      
 40 
     | 
    
         
            +
                      scope: Fastlane::Actions::FirebaseAppDistributionLoginAction::SCOPE
         
     | 
| 
      
 41 
     | 
    
         
            +
                    )
         
     | 
| 
      
 42 
     | 
    
         
            +
                    service_account_credentials.fetch_access_token!["access_token"]
         
     | 
| 
      
 43 
     | 
    
         
            +
                  rescue Errno::ENOENT
         
     | 
| 
      
 44 
     | 
    
         
            +
                    UI.crash!("#{ErrorMessage::SERVICE_CREDENTIALS_NOT_FOUND}: #{google_service_path}")
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_error_message.rb
    ADDED
    
    | 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ErrorMessage
         
     | 
| 
      
 2 
     | 
    
         
            +
              MISSING_CREDENTIALS = "Missing credentials. Please check that a refresh token was set or service credentials were passed in and try again"
         
     | 
| 
      
 3 
     | 
    
         
            +
              APK_NOT_FOUND = "Could not find the APK/IPA. Make sure you set the apk_path parameter to point to your APK/IPA"
         
     | 
| 
      
 4 
     | 
    
         
            +
              MISSING_APP_ID = "Missing app id. Please check that it was passed in and try again"
         
     | 
| 
      
 5 
     | 
    
         
            +
              SERVICE_CREDENTIALS_NOT_FOUND = "Service credentials file does not exist. Please check the service credentials path and try again"
         
     | 
| 
      
 6 
     | 
    
         
            +
              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 
     | 
    
         
            +
              UPLOAD_RELEASE_NOTES_ERROR = "App Distribution halted because it had a problem uploading release notes"
         
     | 
| 
      
 9 
     | 
    
         
            +
              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 
     | 
    
         
            +
              GET_RELEASE_TIMEOUT = "App Distribution failed to fetch release information"
         
     | 
| 
      
 13 
     | 
    
         
            +
              REFRESH_TOKEN_ERROR = "Could not generate credentials from the refresh token specified"
         
     | 
| 
      
 14 
     | 
    
         
            +
              GET_APP_ERROR = "App Distribution failed to fetch app information"
         
     | 
| 
      
 15 
     | 
    
         
            +
              APP_NOT_ONBOARDED_ERROR = "App Distribution not onboarded"
         
     | 
| 
      
 16 
     | 
    
         
            +
              GET_APP_NO_CONTACT_EMAIL_ERROR = "App Distribution could not find a contact email associated with this app. Contact Email"
         
     | 
| 
      
 17 
     | 
    
         
            +
              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 
     | 
    
         
            +
              INVALID_PATH = "Could not read content from"
         
     | 
| 
      
 19 
     | 
    
         
            +
              INVALID_TESTERS = "Could not enable access for testers. Ensure that the groups exist and the tester emails are formatted correctly"
         
     | 
| 
      
 20 
     | 
    
         
            +
              INVALID_RELEASE_ID = "App distribution failed to fetch release with id"
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_helper.rb
    CHANGED
    
    | 
         @@ -1,60 +1,34 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'fastlane_core/ui/ui'
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
2 
     | 
    
         
             
            module Fastlane
         
     | 
| 
       4 
3 
     | 
    
         
             
              UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
4 
     | 
    
         
             
              module Helper
         
     | 
| 
       7 
5 
     | 
    
         
             
                module FirebaseAppDistributionHelper
         
     | 
| 
       8 
     | 
    
         
            -
                  def  
     | 
| 
       9 
     | 
    
         
            -
                     
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
                  def release_notes_flag(params)
         
     | 
| 
       17 
     | 
    
         
            -
                    file_flag_if_supplied("--release-notes-file", "release_notes", params)
         
     | 
| 
       18 
     | 
    
         
            -
                  end
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
                  def file_flag_if_supplied(flag, param_name, params)
         
     | 
| 
       21 
     | 
    
         
            -
                    file = params["#{param_name}_file".to_sym]
         
     | 
| 
       22 
     | 
    
         
            -
                    file ||= file_for_contents(param_name.to_sym, params)
         
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
                    if file
         
     | 
| 
       25 
     | 
    
         
            -
                      return "#{flag} #{file}"
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def get_value_from_value_or_file(value, path)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    if (value.nil? || value.empty?) && !path.nil?
         
     | 
| 
      
 8 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 9 
     | 
    
         
            +
                        return File.open(path).read
         
     | 
| 
      
 10 
     | 
    
         
            +
                      rescue Errno::ENOENT
         
     | 
| 
      
 11 
     | 
    
         
            +
                        UI.crash!("#{ErrorMessage::INVALID_PATH}: #{path}")
         
     | 
| 
      
 12 
     | 
    
         
            +
                      end
         
     | 
| 
       26 
13 
     | 
    
         
             
                    end
         
     | 
| 
      
 14 
     | 
    
         
            +
                    value
         
     | 
| 
       27 
15 
     | 
    
         
             
                  end
         
     | 
| 
       28 
16 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
                   
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
                   
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
                     
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
                  ##
         
     | 
| 
       38 
     | 
    
         
            -
                  # always return a file for a given content
         
     | 
| 
       39 
     | 
    
         
            -
                  def file_for_contents(parameter_name, params)
         
     | 
| 
       40 
     | 
    
         
            -
                    if @tempfiles.nil?
         
     | 
| 
       41 
     | 
    
         
            -
                      @tempfiles = []
         
     | 
| 
       42 
     | 
    
         
            -
                    end
         
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
                    contents = params[parameter_name]
         
     | 
| 
       45 
     | 
    
         
            -
                    return nil if contents.nil?
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
                    file = Tempfile.new(parameter_name.to_s)
         
     | 
| 
       48 
     | 
    
         
            -
                    file.write(contents)
         
     | 
| 
       49 
     | 
    
         
            -
                    file.close
         
     | 
| 
       50 
     | 
    
         
            -
                    @tempfiles << file
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
                    file.path
         
     | 
| 
      
 17 
     | 
    
         
            +
                  # Returns the array representation of a string with comma seperated values.
         
     | 
| 
      
 18 
     | 
    
         
            +
                  #
         
     | 
| 
      
 19 
     | 
    
         
            +
                  # Does not work with strings whose individual values have spaces. EX "Hello World" the space will be removed to "HelloWorld"
         
     | 
| 
      
 20 
     | 
    
         
            +
                  def string_to_array(string)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    return nil if string.nil? || string.empty?
         
     | 
| 
      
 22 
     | 
    
         
            +
                    string_array = string.gsub(/\s+/, '').split(",")
         
     | 
| 
      
 23 
     | 
    
         
            +
                    return string_array
         
     | 
| 
       53 
24 
     | 
    
         
             
                  end
         
     | 
| 
       54 
25 
     | 
    
         | 
| 
       55 
     | 
    
         
            -
                  def  
     | 
| 
       56 
     | 
    
         
            -
                     
     | 
| 
       57 
     | 
    
         
            -
                     
     | 
| 
      
 26 
     | 
    
         
            +
                  def get_ios_app_id_from_archive(path)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    app_path = parse_plist("#{path}/Info.plist")["ApplicationProperties"]["ApplicationPath"]
         
     | 
| 
      
 28 
     | 
    
         
            +
                    UI.shell_error!("can't extract application path from Info.plist at #{path}") if app_path.empty?
         
     | 
| 
      
 29 
     | 
    
         
            +
                    identifier = parse_plist("#{path}/Products/#{app_path}/GoogleService-Info.plist")["GOOGLE_APP_ID"]
         
     | 
| 
      
 30 
     | 
    
         
            +
                    UI.shell_error!("can't extract GOOGLE_APP_ID") if identifier.empty?
         
     | 
| 
      
 31 
     | 
    
         
            +
                    return identifier
         
     | 
| 
       58 
32 
     | 
    
         
             
                  end
         
     | 
| 
       59 
33 
     | 
    
         
             
                end
         
     | 
| 
       60 
34 
     | 
    
         
             
              end
         
     | 
| 
         @@ -0,0 +1,25 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class UploadStatusResponse
         
     | 
| 
      
 2 
     | 
    
         
            +
              def initialize(response_json_hash)
         
     | 
| 
      
 3 
     | 
    
         
            +
                @response_json_hash = response_json_hash
         
     | 
| 
      
 4 
     | 
    
         
            +
              end
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              def status
         
     | 
| 
      
 7 
     | 
    
         
            +
                @response_json_hash[:status]
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              def success?
         
     | 
| 
      
 11 
     | 
    
         
            +
                status == 'SUCCESS'
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              def in_progress?
         
     | 
| 
      
 15 
     | 
    
         
            +
                status == "IN_PROGRESS"
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              def release_hash
         
     | 
| 
      
 19 
     | 
    
         
            +
                @response_json_hash[:release]
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              def release_id
         
     | 
| 
      
 23 
     | 
    
         
            +
                release_hash ? release_hash[:id] : nil
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +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.1 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.2.0.pre.1
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Stefan Natchev
         
     | 
| 
      
 8 
     | 
    
         
            +
            - Manny Jimenez
         
     | 
| 
      
 9 
     | 
    
         
            +
            - Alonso Salas Infante
         
     | 
| 
       8 
10 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
11 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
12 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date:  
     | 
| 
      
 13 
     | 
    
         
            +
            date: 2020-07-28 00:00:00.000000000 Z
         
     | 
| 
       12 
14 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
15 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
16 
     | 
    
         
             
              name: pry
         
     | 
| 
         @@ -139,6 +141,8 @@ dependencies: 
     | 
|
| 
       139 
141 
     | 
    
         
             
            description: 
         
     | 
| 
       140 
142 
     | 
    
         
             
            email:
         
     | 
| 
       141 
143 
     | 
    
         
             
            - snatchev@google.com
         
     | 
| 
      
 144 
     | 
    
         
            +
            - mannyjimenez@google.com
         
     | 
| 
      
 145 
     | 
    
         
            +
            - alonsosi@google.com
         
     | 
| 
       142 
146 
     | 
    
         
             
            executables: []
         
     | 
| 
       143 
147 
     | 
    
         
             
            extensions: []
         
     | 
| 
       144 
148 
     | 
    
         
             
            extra_rdoc_files: []
         
     | 
| 
         @@ -147,9 +151,14 @@ files: 
     | 
|
| 
       147 
151 
     | 
    
         
             
            - README.md
         
     | 
| 
       148 
152 
     | 
    
         
             
            - lib/fastlane/plugin/firebase_app_distribution.rb
         
     | 
| 
       149 
153 
     | 
    
         
             
            - lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_action.rb
         
     | 
| 
      
 154 
     | 
    
         
            +
            - lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_login.rb
         
     | 
| 
      
 155 
     | 
    
         
            +
            - lib/fastlane/plugin/firebase_app_distribution/client/firebase_app_distribution_api_client.rb
         
     | 
| 
      
 156 
     | 
    
         
            +
            - lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_auth_client.rb
         
     | 
| 
      
 157 
     | 
    
         
            +
            - lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_error_message.rb
         
     | 
| 
       150 
158 
     | 
    
         
             
            - lib/fastlane/plugin/firebase_app_distribution/helper/firebase_app_distribution_helper.rb
         
     | 
| 
      
 159 
     | 
    
         
            +
            - lib/fastlane/plugin/firebase_app_distribution/helper/upload_status_response.rb
         
     | 
| 
       151 
160 
     | 
    
         
             
            - lib/fastlane/plugin/firebase_app_distribution/version.rb
         
     | 
| 
       152 
     | 
    
         
            -
            homepage: https://github.com/fastlane 
     | 
| 
      
 161 
     | 
    
         
            +
            homepage: https://github.com/fastlane/fastlane-plugin-firebase_app_distribution
         
     | 
| 
       153 
162 
     | 
    
         
             
            licenses:
         
     | 
| 
       154 
163 
     | 
    
         
             
            - MIT
         
     | 
| 
       155 
164 
     | 
    
         
             
            metadata: {}
         
     | 
| 
         @@ -164,11 +173,12 @@ required_ruby_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       164 
173 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       165 
174 
     | 
    
         
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
       166 
175 
     | 
    
         
             
              requirements:
         
     | 
| 
       167 
     | 
    
         
            -
              - - " 
     | 
| 
      
 176 
     | 
    
         
            +
              - - ">"
         
     | 
| 
       168 
177 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       169 
     | 
    
         
            -
                  version:  
     | 
| 
      
 178 
     | 
    
         
            +
                  version: 1.3.1
         
     | 
| 
       170 
179 
     | 
    
         
             
            requirements: []
         
     | 
| 
       171 
     | 
    
         
            -
             
     | 
| 
      
 180 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 181 
     | 
    
         
            +
            rubygems_version: 2.2.5
         
     | 
| 
       172 
182 
     | 
    
         
             
            signing_key: 
         
     | 
| 
       173 
183 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       174 
184 
     | 
    
         
             
            summary: Release your beta builds to Firebase App Distribution. https://firebase.google.com/docs/app-distribution
         
     |