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

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 3316c560bc4c691d569deea229397668e8e3a00ca4201d332602acd112379639
4
- data.tar.gz: 6fe95425b0f4a85d3492ec51ae8353979f3534b635655ee55349f12191c721ae
2
+ SHA1:
3
+ metadata.gz: ab7379d2d8feb6112f778c3b4a64e2f2181a099a
4
+ data.tar.gz: bdb617b84fb387a5486faee45d23be3043a9d9af
5
5
  SHA512:
6
- metadata.gz: fc0f5ac7cd9081eb02e539cb6bc2f2116dcc51e04ac8b5685ca611469fd76f37470d35c4c5085bf267fa7d296a76d95ddbdc5714ab8fe2388cf249d51101740d
7
- data.tar.gz: 5e8cc15580a5f98491f1d9318728600c751a807a8f5108df4844fe6f371e2725b5dcffb38af560b58de202dc20bb3ba3d77ec2155d065c4452f0b287f15728ec
6
+ metadata.gz: 69f808e806793eb81839ac45241445c8764884f35c92c25066c86121c5ecb7ebf981371ed347fceadbfb0161df03ac6613fbd3f2aebe42a935783ca55d239df5
7
+ data.tar.gz: 83c298cdfd08b945957f10f9194142423418b89ee5dc17a2718b1506013e79fbba2f94ad11e1b7c0b92a874c3e69731eba327e66f393bb61b99fae0bf423d5b5
data/README.md CHANGED
@@ -1,26 +1,15 @@
1
- # firebase_app_distribution plugin
2
1
 
3
- [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-firebase_app_distribution)
4
-
5
- ## Getting Started
6
2
 
7
- This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-firebase_app_distribution`, add it to your project by running:
8
-
9
- ```bash
10
- fastlane add_plugin firebase_app_distribution
11
- ```
3
+ # ![Firebase App Distribution](fad-icon.png) Firebase App Distribution
12
4
 
13
- ## About firebase_app_distribution
14
-
15
- Release your beta builds to Firebase App Distro
16
-
17
- **Note to author:** Add a more detailed description about this plugin here. If your plugin contains multiple actions, make sure to mention them here.
5
+ [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-firebase_app_distribution)
18
6
 
19
- ## Example
7
+ Firebase App Distribution makes distributing your apps to trusted testers painless. By getting your apps onto testers' devices quickly, you can get feedback early and often. To learn more about Firebase App Distribution, go [here](https://firebase.google.com/docs/app-distribution).
20
8
 
21
- Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plugin. Try it by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane test`.
22
9
 
23
- **Note to author:** Please set up a sample project to make it easy for users to explore what your plugin does. Provide everything that is necessary to try out the plugin in this project (including a sample Xcode/Android project if necessary)
10
+ ## Getting Started
11
+ - [iOS](https://firebase.google.com/docs/app-distribution/ios/distribute-fastlane)
12
+ - [Android](https://firebase.google.com/docs/app-distribution/android/distribute-fastlane)
24
13
 
25
14
  ## Run tests for this plugin
26
15
 
@@ -1,58 +1,70 @@
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?
9
13
  module Fastlane
10
14
  module Actions
11
15
  class FirebaseAppDistributionAction < Action
12
-
13
- DEFAULT_FIREBASE_CLI_PATH = %x(which firebase).chomp
16
+ DEFAULT_FIREBASE_CLI_PATH = `which firebase`
14
17
  FIREBASECMD_ACTION = "appdistribution:distribute".freeze
15
-
18
+
19
+ extend Auth::FirebaseAppDistributionAuthClient
16
20
  extend Helper::FirebaseAppDistributionHelper
17
21
 
18
22
  def self.run(params)
19
23
  params.values # to validate all inputs before looking for the ipa/apk
20
-
21
- release_file = params[:release_notes_file]
22
- if params[:release_notes].to_s != ""
23
- release_file = file_for_contents(:release_notes, from: params)
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
24
36
  end
25
37
 
26
- groups_file = file_for_contents(:groups, from: params)
27
- testers_file = file_for_contents(:testers, from: params)
28
-
29
- cmd = [params[:firebase_cli_path], FIREBASECMD_ACTION]
30
- cmd << Shellwords.escape(params[:ipa_path] || params[:apk_path])
31
- cmd << "--app #{params[:app]}"
32
- cmd << "--groups-file #{groups_file}" if groups_file
33
- cmd << "--testers-file #{testers_file}" if testers_file
34
- cmd << "--release-notes-file #{release_file}" if release_file
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
35
45
 
36
- result = Actions.sh_control_output(
37
- cmd.join(" "),
38
- print_command: false,
39
- print_command_output: true
40
- )
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)
41
48
 
42
- cleanup_tempfiles
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")
43
55
  end
44
56
 
45
57
  def self.description
46
- "Release your beta builds to Firebase App Distro"
58
+ "Release your beta builds with Firebase App Distribution"
47
59
  end
48
60
 
49
61
  def self.authors
50
- ["Stefan Natchev"]
62
+ ["Stefan Natchev", "Manny Jimenez Github: mannyjimenez0810, Alonso Salas Infante Github: alonsosalasinfante"]
51
63
  end
52
64
 
53
65
  # supports markdown.
54
66
  def self.details
55
- "Release your beta builds to Firebase App Distro"
67
+ "Release your beta builds with Firebase App Distribution"
56
68
  end
57
69
 
58
70
  def self.available_options
@@ -90,7 +102,7 @@ module Fastlane
90
102
  FastlaneCore::ConfigItem.new(key: :app,
91
103
  env_name: "FIREBASEAPPDISTRO_APP",
92
104
  description: "Your app's Firebase App ID. You can find the App ID in the Firebase console, on the General Settings page",
93
- optional: false,
105
+ optional: true,
94
106
  type: String),
95
107
  FastlaneCore::ConfigItem.new(key: :firebase_cli_path,
96
108
  env_name: "FIREBASEAPPDISTRO_FIREBASE_CLI_PATH",
@@ -100,12 +112,13 @@ module Fastlane
100
112
  optional: false,
101
113
  type: String,
102
114
  verify_block: proc do |value|
115
+ value.chomp!
103
116
  if value.to_s == "" || !File.exist?(value)
104
117
  UI.user_error!("firebase_cli_path: missing path to firebase cli tool. Please install firebase in $PATH or specify path")
105
118
  end
106
119
 
107
120
  unless is_firebasecmd_supported?(value)
108
- 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")
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")
109
122
  end
110
123
  end),
111
124
  FastlaneCore::ConfigItem.new(key: :groups,
@@ -140,6 +153,19 @@ module Fastlane
140
153
  description: "Release notes file for this build",
141
154
  optional: true,
142
155
  type: String),
156
+ FastlaneCore::ConfigItem.new(key: :firebase_cli_token,
157
+ description: "Auth token for firebase cli",
158
+ optional: true,
159
+ type: String),
160
+ FastlaneCore::ConfigItem.new(key: :debug,
161
+ description: "Print verbose debug output",
162
+ optional: true,
163
+ default_value: 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)
143
169
  ]
144
170
  end
145
171
 
@@ -162,8 +188,6 @@ module Fastlane
162
188
  ]
163
189
  end
164
190
 
165
- private
166
-
167
191
  ## TODO: figure out if we can surpress color output.
168
192
  def self.is_firebasecmd_supported?(cmd)
169
193
  outerr, status = Open3.capture2e(cmd, "--non-interactive", FIREBASECMD_ACTION, "--help")
@@ -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
@@ -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
@@ -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
@@ -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
@@ -1,39 +1,35 @@
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
- ##
9
- # always return a file for a given content
10
- # TODO: explain this more.
11
- def file_for_contents(parameter_name, from: nil, contents: nil)
12
- if parameter_name.to_s.end_with?("_file")
13
- return parameter_name
14
- end
15
-
16
- if @tempfiles == nil
17
- @tempfiles = []
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
18
13
  end
19
-
20
- contents ||= from[parameter_name]
21
- return nil if contents.nil?
22
-
23
- file = Tempfile.new(parameter_name.to_s)
24
- file.write(contents)
25
- file.close
26
- @tempfiles << file
27
-
28
- file.path
14
+ value
29
15
  end
30
16
 
31
- def cleanup_tempfiles
32
- @tempfiles.each do |f|
33
- f.unlink
34
- end
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
35
24
  end
36
25
 
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
32
+ end
37
33
  end
38
34
  end
39
35
  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
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module FirebaseAppDistribution
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0.pre.1"
4
4
  end
5
5
  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.0
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: 2019-08-27 00:00:00.000000000 Z
13
+ date: 2020-07-28 00:00:00.000000000 Z
12
14
  dependencies:
13
15
  - !ruby/object:Gem::Dependency
14
16
  name: pry
@@ -137,7 +139,10 @@ dependencies:
137
139
  - !ruby/object:Gem::Version
138
140
  version: 2.127.1
139
141
  description:
140
- email: snatchev@google.com
142
+ email:
143
+ - snatchev@google.com
144
+ - mannyjimenez@google.com
145
+ - alonsosi@google.com
141
146
  executables: []
142
147
  extensions: []
143
148
  extra_rdoc_files: []
@@ -146,9 +151,14 @@ files:
146
151
  - README.md
147
152
  - lib/fastlane/plugin/firebase_app_distribution.rb
148
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
149
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
150
160
  - lib/fastlane/plugin/firebase_app_distribution/version.rb
151
- homepage:
161
+ homepage: https://github.com/fastlane/fastlane-plugin-firebase_app_distribution
152
162
  licenses:
153
163
  - MIT
154
164
  metadata: {}
@@ -163,12 +173,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
163
173
  version: '0'
164
174
  required_rubygems_version: !ruby/object:Gem::Requirement
165
175
  requirements:
166
- - - ">="
176
+ - - ">"
167
177
  - !ruby/object:Gem::Version
168
- version: '0'
178
+ version: 1.3.1
169
179
  requirements: []
170
- rubygems_version: 3.0.1
180
+ rubyforge_project:
181
+ rubygems_version: 2.2.5
171
182
  signing_key:
172
183
  specification_version: 4
173
- summary: Release your beta builds to Firebase App Distro
184
+ summary: Release your beta builds to Firebase App Distribution. https://firebase.google.com/docs/app-distribution
174
185
  test_files: []