fastlane-plugin-firebase_app_distribution 0.2.0.pre.1 → 0.2.1

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