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
|