fastlane-plugin-firebase_app_distribution 0.4.2 → 0.6.0

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
2
  SHA256:
3
- metadata.gz: 0c1ecfa3d259597531bf5d000974d70de8f91aaf2e530f4b277f9382627bb27c
4
- data.tar.gz: 64de62eea1701401a75adee5b412970e6bc3abb14964ad9f4fc7a57ce74d03e6
3
+ metadata.gz: c8c5fed8eb93d2d6c62dee224fb08c366646a91b0ddd38d74689e5c34b0f355b
4
+ data.tar.gz: 03ee7ef5569e510ae63370cd860ec6f118f6ce5d8771c2f961d9194609232709
5
5
  SHA512:
6
- metadata.gz: 01423717bdd9b128f047b81c3e91072067441aeb0378b27e45b72af59f4387bb37d40144f2d082f1608bcf59f709bae0feefa9fcdba490873e679fff9898dca2
7
- data.tar.gz: 02d60865da2daee4b649bcebe14c35f64eaba2c8fd09f4ebd21d3099632779492d81eeac454697052db836ba63425f68ef7a1a59656d6f915b14a36a57cc2096
6
+ metadata.gz: e0b67fbe3ac855aec3dd70be48726d44bcae8eb021a70984ff5274431b0e093c6849ad9ddf64f6186698ffa5701950acc53c602cb48583d520738a1bfa75f6b5
7
+ data.tar.gz: ec59af9949e4d9086004c63561b2e74a3bf09b9a270b02a12e62d66a322198124c8019724ae7cd33f2f5097615dd9c068f416e3efa5bc48fe4b77e11133b6946
@@ -11,6 +11,10 @@ require_relative '../helper/firebase_app_distribution_auth_client'
11
11
  ## How should we document the usage of release notes?
12
12
  module Fastlane
13
13
  module Actions
14
+ module SharedValues
15
+ FIREBASE_APP_DISTRO_RELEASE ||= :FIREBASE_APP_DISTRO_RELEASE
16
+ end
17
+
14
18
  class FirebaseAppDistributionAction < Action
15
19
  extend Auth::FirebaseAppDistributionAuthClient
16
20
  extend Helper::FirebaseAppDistributionHelper
@@ -48,6 +52,7 @@ module Fastlane
48
52
 
49
53
  upload_status_response = fad_api_client.upload(app_name, binary_path, platform.to_s, upload_timeout)
50
54
  release_name = upload_status_response.release_name
55
+ release = upload_status_response.release
51
56
 
52
57
  if binary_type == :AAB && aab_info && !aab_info.certs_provided?
53
58
  updated_aab_info = fad_api_client.get_aab_info(app_name)
@@ -62,14 +67,19 @@ module Fastlane
62
67
  end
63
68
  end
64
69
 
65
- fad_api_client.update_release_notes(release_name, release_notes(params))
70
+ release_notes = release_notes(params)
71
+ if release_notes.nil? || release_notes.empty?
72
+ UI.message("⏩ No release notes passed in. Skipping this step.")
73
+ else
74
+ release = fad_api_client.update_release_notes(release_name, release_notes)
75
+ end
66
76
 
67
77
  testers = get_value_from_value_or_file(params[:testers], params[:testers_file])
68
78
  groups = get_value_from_value_or_file(params[:groups], params[:groups_file])
69
79
  emails = string_to_array(testers)
70
80
  group_aliases = string_to_array(groups)
71
81
  fad_api_client.distribute(release_name, emails, group_aliases)
72
- UI.success("🎉 App Distribution upload finished successfully.")
82
+ UI.success("🎉 App Distribution upload finished successfully. Setting Actions.lane_context[SharedValues::FIREBASE_APP_DISTRO_RELEASE] to the uploaded release.")
73
83
 
74
84
  if upload_status_response.firebase_console_uri
75
85
  UI.message("🔗 View this release in the Firebase console: #{upload_status_response.firebase_console_uri}")
@@ -82,6 +92,9 @@ module Fastlane
82
92
  if upload_status_response.binary_download_uri
83
93
  UI.message("🔗 Download the release binary (link expires in 1 hour): #{upload_status_response.binary_download_uri}")
84
94
  end
95
+
96
+ Actions.lane_context[SharedValues::FIREBASE_APP_DISTRO_RELEASE] = release
97
+ release
85
98
  end
86
99
 
87
100
  def self.description
@@ -256,7 +269,7 @@ module Fastlane
256
269
  optional: true,
257
270
  type: String),
258
271
  FastlaneCore::ConfigItem.new(key: :firebase_cli_token,
259
- description: "Auth token generated using 'fastlane run firebase_app_distribution_login', or the Firebase CLI's login:ci command",
272
+ description: "Auth token generated using the Firebase CLI's login:ci command",
260
273
  optional: true,
261
274
  type: String),
262
275
  FastlaneCore::ConfigItem.new(key: :debug,
@@ -294,6 +307,12 @@ module Fastlane
294
307
  CODE
295
308
  ]
296
309
  end
310
+
311
+ def self.output
312
+ [
313
+ ['FIREBASE_APP_DISTRO_RELEASE', 'A hash representing the uploaded release created in Firebase App Distribution']
314
+ ]
315
+ end
297
316
  end
298
317
  end
299
318
  end
@@ -30,6 +30,11 @@ module Fastlane
30
30
 
31
31
  fad_api_client.add_testers(params[:project_number], emails)
32
32
 
33
+ unless blank?(params[:group_alias])
34
+ UI.message("⏳ Adding testers to group #{params[:group_alias]}...")
35
+ fad_api_client.add_testers_to_group(params[:project_number], params[:group_alias], emails)
36
+ end
37
+
33
38
  # The add_testers response lists all the testers from the request
34
39
  # regardless of whether or not they were created or if they already
35
40
  # exists so can't get an accurate count of the number of newly created testers
@@ -66,12 +71,17 @@ module Fastlane
66
71
  description: "Path to a file containing a comma separated list of tester emails to be created. A maximum of 1000 testers can be deleted at a time",
67
72
  optional: true,
68
73
  type: String),
74
+ FastlaneCore::ConfigItem.new(key: :group_alias,
75
+ env_name: "FIREBASEAPPDISTRO_ADD_TESTERS_GROUP_ALIAS",
76
+ description: "Alias of the group to add the specified testers to. The group must already exist. If not specified, testers will not be added to a group",
77
+ optional: true,
78
+ type: String),
69
79
  FastlaneCore::ConfigItem.new(key: :service_credentials_file,
70
80
  description: "Path to Google service credentials file",
71
81
  optional: true,
72
82
  type: String),
73
83
  FastlaneCore::ConfigItem.new(key: :firebase_cli_token,
74
- description: "Auth token generated using 'fastlane run firebase_app_distribution_login', or the Firebase CLI's login:ci command",
84
+ description: "Auth token generated using the Firebase CLI's login:ci command",
75
85
  optional: true,
76
86
  type: String),
77
87
  FastlaneCore::ConfigItem.new(key: :debug,
@@ -0,0 +1,87 @@
1
+ require 'fastlane/action'
2
+ require 'fastlane_core/ui/ui'
3
+
4
+ require_relative '../helper/firebase_app_distribution_helper'
5
+ require_relative '../helper/firebase_app_distribution_auth_client'
6
+
7
+ module Fastlane
8
+ module Actions
9
+ class FirebaseAppDistributionCreateGroupAction < Action
10
+ extend Auth::FirebaseAppDistributionAuthClient
11
+ extend Helper::FirebaseAppDistributionHelper
12
+
13
+ def self.run(params)
14
+ auth_token = fetch_auth_token(params[:service_credentials_file], params[:firebase_cli_token])
15
+ fad_api_client = Client::FirebaseAppDistributionApiClient.new(auth_token, params[:debug])
16
+
17
+ if blank?(params[:alias])
18
+ UI.user_error!("Must specify `alias`.")
19
+ end
20
+
21
+ if blank?(params[:display_name])
22
+ UI.user_error!("Must specify `display_name`.")
23
+ end
24
+
25
+ project_number = params[:project_number]
26
+ group_alias = params[:alias]
27
+ display_name = params[:display_name]
28
+
29
+ UI.message("⏳ Creating tester group '#{group_alias} (#{display_name})' in project #{project_number}...")
30
+
31
+ fad_api_client.create_group(project_number, group_alias, display_name)
32
+
33
+ UI.success("✅ Group created successfully.")
34
+ end
35
+
36
+ def self.description
37
+ "Create a tester group"
38
+ end
39
+
40
+ def self.authors
41
+ ["Garry Jeromson"]
42
+ end
43
+
44
+ # supports markdown.
45
+ def self.details
46
+ "Create a tester group"
47
+ end
48
+
49
+ def self.available_options
50
+ [
51
+ FastlaneCore::ConfigItem.new(key: :project_number,
52
+ env_name: "FIREBASEAPPDISTRO_PROJECT_NUMBER",
53
+ description: "Your Firebase project number. You can find the project number in the Firebase console, on the General Settings page",
54
+ type: Integer,
55
+ optional: false),
56
+ FastlaneCore::ConfigItem.new(key: :alias,
57
+ env_name: "FIREBASEAPPDISTRO_CREATE_GROUP_ALIAS",
58
+ description: "Alias of the group to be created",
59
+ optional: false,
60
+ type: String),
61
+ FastlaneCore::ConfigItem.new(key: :display_name,
62
+ env_name: "FIREBASEAPPDISTRO_CREATE_GROUP_DISPLAY_NAME",
63
+ description: "Display name for the group to be created",
64
+ optional: false,
65
+ type: String),
66
+ FastlaneCore::ConfigItem.new(key: :service_credentials_file,
67
+ description: "Path to Google service credentials file",
68
+ optional: true,
69
+ type: String),
70
+ FastlaneCore::ConfigItem.new(key: :firebase_cli_token,
71
+ description: "Auth token generated using the Firebase CLI's login:ci command",
72
+ optional: true,
73
+ type: String),
74
+ FastlaneCore::ConfigItem.new(key: :debug,
75
+ description: "Print verbose debug output",
76
+ optional: true,
77
+ default_value: false,
78
+ is_string: false)
79
+ ]
80
+ end
81
+
82
+ def self.is_supported?(platform)
83
+ true
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,77 @@
1
+ require 'fastlane/action'
2
+ require 'fastlane_core/ui/ui'
3
+
4
+ require_relative '../helper/firebase_app_distribution_helper'
5
+ require_relative '../helper/firebase_app_distribution_auth_client'
6
+
7
+ module Fastlane
8
+ module Actions
9
+ class FirebaseAppDistributionDeleteGroupAction < Action
10
+ extend Auth::FirebaseAppDistributionAuthClient
11
+ extend Helper::FirebaseAppDistributionHelper
12
+
13
+ def self.run(params)
14
+ auth_token = fetch_auth_token(params[:service_credentials_file], params[:firebase_cli_token])
15
+ fad_api_client = Client::FirebaseAppDistributionApiClient.new(auth_token, params[:debug])
16
+
17
+ if blank?(params[:alias])
18
+ UI.user_error!("Must specify `alias`.")
19
+ end
20
+
21
+ project_number = params[:project_number]
22
+ group_alias = params[:alias]
23
+
24
+ UI.message("⏳ Deleting tester group '#{group_alias}' in project #{project_number}...")
25
+
26
+ fad_api_client.delete_group(project_number, group_alias)
27
+
28
+ UI.success("✅ Group deleted successfully.")
29
+ end
30
+
31
+ def self.description
32
+ "Delete a tester group"
33
+ end
34
+
35
+ def self.authors
36
+ ["Garry Jeromson"]
37
+ end
38
+
39
+ # supports markdown.
40
+ def self.details
41
+ "Delete a tester group"
42
+ end
43
+
44
+ def self.available_options
45
+ [
46
+ FastlaneCore::ConfigItem.new(key: :project_number,
47
+ env_name: "FIREBASEAPPDISTRO_PROJECT_NUMBER",
48
+ description: "Your Firebase project number. You can find the project number in the Firebase console, on the General Settings page",
49
+ type: Integer,
50
+ optional: false),
51
+ FastlaneCore::ConfigItem.new(key: :alias,
52
+ env_name: "FIREBASEAPPDISTRO_DELETE_GROUP_ALIAS",
53
+ description: "Alias of the group to be deleted",
54
+ optional: false,
55
+ type: String),
56
+ FastlaneCore::ConfigItem.new(key: :service_credentials_file,
57
+ description: "Path to Google service credentials file",
58
+ optional: true,
59
+ type: String),
60
+ FastlaneCore::ConfigItem.new(key: :firebase_cli_token,
61
+ description: "Auth token generated using the Firebase CLI's login:ci command",
62
+ optional: true,
63
+ type: String),
64
+ FastlaneCore::ConfigItem.new(key: :debug,
65
+ description: "Print verbose debug output",
66
+ optional: true,
67
+ default_value: false,
68
+ is_string: false)
69
+ ]
70
+ end
71
+
72
+ def self.is_supported?(platform)
73
+ true
74
+ end
75
+ end
76
+ end
77
+ end
@@ -5,6 +5,9 @@ require_relative '../helper/firebase_app_distribution_helper'
5
5
 
6
6
  module Fastlane
7
7
  module Actions
8
+ module SharedValues
9
+ FIREBASE_APP_DISTRO_LATEST_RELEASE ||= :FIREBASE_APP_DISTRO_LATEST_RELEASE
10
+ end
8
11
  class FirebaseAppDistributionGetLatestReleaseAction < Action
9
12
  extend Auth::FirebaseAppDistributionAuthClient
10
13
  extend Helper::FirebaseAppDistributionHelper
@@ -18,12 +21,12 @@ module Fastlane
18
21
  releases = fad_api_client.list_releases(app_name_from_app_id(params[:app]), 1)[:releases] || []
19
22
  if releases.empty?
20
23
  latest_release = nil
21
- UI.important("No releases for app #{params[:app]} found in App Distribution. Returning nil and setting Actions.lane_context[:FIREBASE_APP_DISTRO_LATEST_RELEASE].")
24
+ UI.important("No releases for app #{params[:app]} found in App Distribution. Returning nil and setting Actions.lane_context[SharedValues::FIREBASE_APP_DISTRO_LATEST_RELEASE].")
22
25
  else
23
26
  latest_release = releases[0]
24
- UI.success("✅ Latest release fetched successfully. Returning release and setting Actions.lane_context[:FIREBASE_APP_DISTRO_LATEST_RELEASE].")
27
+ UI.success("✅ Latest release fetched successfully. Returning release and setting Actions.lane_context[SharedValues::FIREBASE_APP_DISTRO_LATEST_RELEASE].")
25
28
  end
26
- Actions.lane_context[:FIREBASE_APP_DISTRO_LATEST_RELEASE] = latest_release
29
+ Actions.lane_context[SharedValues::FIREBASE_APP_DISTRO_LATEST_RELEASE] = latest_release
27
30
  return latest_release
28
31
  end
29
32
 
@@ -49,7 +52,7 @@ module Fastlane
49
52
  optional: false,
50
53
  type: String),
51
54
  FastlaneCore::ConfigItem.new(key: :firebase_cli_token,
52
- description: "Auth token generated using 'fastlane run firebase_app_distribution_login', or the Firebase CLI's login:ci command",
55
+ description: "Auth token generated using Firebase CLI's login:ci command",
53
56
  optional: true,
54
57
  type: String),
55
58
  FastlaneCore::ConfigItem.new(key: :service_credentials_file,
@@ -63,7 +63,7 @@ module Fastlane
63
63
  optional: false,
64
64
  type: String),
65
65
  FastlaneCore::ConfigItem.new(key: :firebase_cli_token,
66
- description: "Auth token generated using 'fastlane run firebase_app_distribution_login', or the Firebase CLI's login:ci command",
66
+ description: "Auth token generated using the Firebase CLI's login:ci command",
67
67
  optional: true,
68
68
  type: String),
69
69
  FastlaneCore::ConfigItem.new(key: :service_credentials_file,
@@ -68,7 +68,7 @@ module Fastlane
68
68
  optional: true,
69
69
  type: String),
70
70
  FastlaneCore::ConfigItem.new(key: :firebase_cli_token,
71
- description: "Auth token generated using 'fastlane run firebase_app_distribution_login', or the Firebase CLI's login:ci command",
71
+ description: "Auth token generated using the Firebase CLI's login:ci command",
72
72
  optional: true,
73
73
  type: String),
74
74
  FastlaneCore::ConfigItem.new(key: :debug,
@@ -1,5 +1,4 @@
1
1
  require 'fastlane_core/ui/ui'
2
- require_relative '../actions/firebase_app_distribution_login'
3
2
  require_relative '../client/error_response'
4
3
  require_relative '../client/aab_info'
5
4
  require_relative '../helper/firebase_app_distribution_helper'
@@ -59,29 +58,26 @@ module Fastlane
59
58
  # release_name - App release resource name, returned by upload_status endpoint
60
59
  # release_notes - String of notes for this release
61
60
  #
61
+ # Returns a hash of the release
62
+ #
62
63
  # Throws a user_error if the release_notes are invalid
63
64
  def update_release_notes(release_name, release_notes)
64
- if release_notes.nil? || release_notes.empty?
65
- UI.success("✅ No release notes passed in. Skipping this step.")
66
- return
67
- end
68
- begin
69
- payload = {
70
- name: release_name,
71
- releaseNotes: {
72
- text: release_notes
73
- }
65
+ payload = {
66
+ name: release_name,
67
+ releaseNotes: {
68
+ text: release_notes
74
69
  }
75
- connection.patch(update_release_notes_url(release_name), payload.to_json) do |request|
76
- request.headers[AUTHORIZATION] = "Bearer " + @auth_token
77
- request.headers[CONTENT_TYPE] = APPLICATION_JSON
78
- request.headers[CLIENT_VERSION] = client_version_header_value
79
- end
80
- rescue Faraday::ClientError => e
81
- error = ErrorResponse.new(e.response)
82
- UI.user_error!("#{ErrorMessage::INVALID_RELEASE_NOTES}: #{error.message}")
70
+ }
71
+ response = connection.patch(update_release_notes_url(release_name), payload.to_json) do |request|
72
+ request.headers[AUTHORIZATION] = "Bearer " + @auth_token
73
+ request.headers[CONTENT_TYPE] = APPLICATION_JSON
74
+ request.headers[CLIENT_VERSION] = client_version_header_value
83
75
  end
84
76
  UI.success("✅ Posted release notes.")
77
+ response.body
78
+ rescue Faraday::ClientError => e
79
+ error = ErrorResponse.new(e.response)
80
+ UI.user_error!("#{ErrorMessage::INVALID_RELEASE_NOTES}: #{error.message}")
85
81
  end
86
82
 
87
83
  # Get AAB info (Android apps only)
@@ -136,7 +132,7 @@ module Fastlane
136
132
  # binary_path - Absolute path to your app's aab/apk/ipa file
137
133
  # timeout - The amount of seconds before the upload will timeout, if not completed
138
134
  #
139
- # Returns the release_name of the uploaded release.
135
+ # Returns a `UploadStatusResponse` with the upload is complete.
140
136
  #
141
137
  # Crashes if the number of polling retries exceeds MAX_POLLING_RETRIES or if the binary cannot
142
138
  # be uploaded.
@@ -255,6 +251,102 @@ module Fastlane
255
251
  UI.user_error!(ErrorMessage::INVALID_PROJECT)
256
252
  end
257
253
 
254
+ # Create tester group
255
+ #
256
+ # args
257
+ # project_number - Firebase project number
258
+ # group_alias - Alias of the tester group
259
+ # display_name - Display name of the tester group
260
+ #
261
+ def create_group(project_number, group_alias, display_name)
262
+ payload = { name: "projects/#{project_number}/groups/#{group_alias}",
263
+ displayName: display_name }
264
+ response = connection.post(add_tester_group_url(project_number), payload.to_json) do |request|
265
+ request.params["groupId"] = group_alias
266
+ request.headers[AUTHORIZATION] = "Bearer " + @auth_token
267
+ request.headers[CONTENT_TYPE] = APPLICATION_JSON
268
+ request.headers[CLIENT_VERSION] = client_version_header_value
269
+ end
270
+ response.body
271
+ rescue Faraday::BadRequestError
272
+ UI.user_error!(ErrorMessage::INVALID_TESTER_GROUP_NAME)
273
+ rescue Faraday::ResourceNotFound
274
+ UI.user_error!(ErrorMessage::INVALID_PROJECT)
275
+ rescue Faraday::ConflictError
276
+ UI.important("Tester group #{group_alias} already exists.")
277
+ return {
278
+ name: "projects/#{project_number}/groups/#{group_alias}"
279
+ }
280
+ rescue Faraday::ClientError => e
281
+ raise e
282
+ end
283
+
284
+ # Add testers to group
285
+ #
286
+ # args
287
+ # project_number - Firebase project number
288
+ # group_alias - Alias of the tester group
289
+ # emails - An array of emails to be added to the group.
290
+ # A maximum of 1000 testers can be added at a time, if creating missing testers is enabled.
291
+ # create_missing_testers - If true, missing testers will be created and added to the group.
292
+ #
293
+ def add_testers_to_group(project_number, group_alias, emails, create_missing_testers = false)
294
+ payload = { emails: emails,
295
+ createMissingTesters: create_missing_testers }
296
+ response = connection.post(add_testers_to_group_url(project_number, group_alias), payload.to_json) do |request|
297
+ request.headers[AUTHORIZATION] = "Bearer " + @auth_token
298
+ request.headers[CONTENT_TYPE] = APPLICATION_JSON
299
+ request.headers[CLIENT_VERSION] = client_version_header_value
300
+ end
301
+ response.body
302
+ rescue Faraday::BadRequestError
303
+ UI.user_error!(ErrorMessage::INVALID_EMAIL_ADDRESS)
304
+ rescue Faraday::ResourceNotFound
305
+ UI.user_error!(ErrorMessage::INVALID_TESTER_GROUP)
306
+ rescue Faraday::ClientError => e
307
+ raise e
308
+ end
309
+
310
+ # Remove testers from group
311
+ #
312
+ # args
313
+ # project_number - Firebase project number
314
+ # group_alias - Alias of the tester group
315
+ # emails - An array of emails to be removed from the group.
316
+ #
317
+ def remove_testers_from_group(project_number, group_alias, emails)
318
+ payload = { emails: emails }
319
+ response = connection.post(remove_testers_from_group_url(project_number, group_alias), payload.to_json) do |request|
320
+ request.headers[AUTHORIZATION] = "Bearer " + @auth_token
321
+ request.headers[CONTENT_TYPE] = APPLICATION_JSON
322
+ request.headers[CLIENT_VERSION] = client_version_header_value
323
+ end
324
+ response.body
325
+ rescue Faraday::BadRequestError
326
+ UI.user_error!(ErrorMessage::INVALID_EMAIL_ADDRESS)
327
+ rescue Faraday::ResourceNotFound
328
+ UI.user_error!(ErrorMessage::INVALID_TESTER_GROUP)
329
+ rescue Faraday::ClientError => e
330
+ raise e
331
+ end
332
+
333
+ # Delete tester group
334
+ #
335
+ # args
336
+ # project_number - Firebase project number
337
+ # group_alias - Alias of the tester group
338
+ #
339
+ def delete_group(project_number, group_alias)
340
+ response = connection.delete(delete_tester_group_url(project_number, group_alias)) do |request|
341
+ request.headers[AUTHORIZATION] = "Bearer " + @auth_token
342
+ request.headers[CONTENT_TYPE] = APPLICATION_JSON
343
+ request.headers[CLIENT_VERSION] = client_version_header_value
344
+ end
345
+ response.body
346
+ rescue Faraday::ResourceNotFound
347
+ UI.user_error!(ErrorMessage::INVALID_TESTER_GROUP)
348
+ end
349
+
258
350
  # List releases
259
351
  #
260
352
  # args
@@ -273,7 +365,7 @@ module Fastlane
273
365
  UI.user_error!("#{ErrorMessage::INVALID_APP_ID}: #{app_name}")
274
366
  end
275
367
 
276
- return response.body
368
+ response.body
277
369
  end
278
370
 
279
371
  private
@@ -326,6 +418,22 @@ module Fastlane
326
418
  "/v1/projects/#{project_number}/testers:batchRemove"
327
419
  end
328
420
 
421
+ def add_tester_group_url(project_number)
422
+ "/v1/projects/#{project_number}/groups"
423
+ end
424
+
425
+ def delete_tester_group_url(project_number, group_alias)
426
+ "/v1/projects/#{project_number}/groups/#{group_alias}"
427
+ end
428
+
429
+ def add_testers_to_group_url(project_number, group_alias)
430
+ "/v1/projects/#{project_number}/groups/#{group_alias}:batchJoin"
431
+ end
432
+
433
+ def remove_testers_from_group_url(project_number, group_alias)
434
+ "/v1/projects/#{project_number}/groups/#{group_alias}:batchLeave"
435
+ end
436
+
329
437
  def connection
330
438
  @connection ||= Faraday.new(url: BASE_URL) do |conn|
331
439
  conn.response(:json, parser_options: { symbolize_names: true })
@@ -6,6 +6,12 @@ module Fastlane
6
6
  TOKEN_CREDENTIAL_URI = "https://oauth2.googleapis.com/token"
7
7
  REDACTION_EXPOSED_LENGTH = 5
8
8
  REDACTION_CHARACTER = "X"
9
+ SCOPE = "https://www.googleapis.com/auth/cloud-platform"
10
+
11
+ # In this type of application, the client secret is not treated as a secret.
12
+ # See: https://developers.google.com/identity/protocols/OAuth2InstalledApp
13
+ CLIENT_ID = "563584335869-fgrhgmd47bqnekij5i8b5pr03ho849e6.apps.googleusercontent.com"
14
+ CLIENT_SECRET = "j9iVZfS8kkCEFUPaAeJV0sAi"
9
15
 
10
16
  # Returns the auth token for any of the auth methods (Firebase CLI token,
11
17
  # Google service account, firebase-tools). To ensure that a specific
@@ -13,8 +19,7 @@ module Fastlane
13
19
  #
14
20
  # args
15
21
  # google_service_path - Absolute path to the Google service account file
16
- # firebase_cli_token - Firebase CLI refresh token from login action or
17
- # CI environment
22
+ # firebase_cli_token - Refresh token
18
23
  # debug - Whether to enable debug-level logging
19
24
  #
20
25
  # env variables
@@ -74,8 +79,8 @@ module Fastlane
74
79
  def firebase_token(refresh_token, debug)
75
80
  client = Signet::OAuth2::Client.new(
76
81
  token_credential_uri: TOKEN_CREDENTIAL_URI,
77
- client_id: Fastlane::Actions::FirebaseAppDistributionLoginAction::CLIENT_ID,
78
- client_secret: Fastlane::Actions::FirebaseAppDistributionLoginAction::CLIENT_SECRET,
82
+ client_id: CLIENT_ID,
83
+ client_secret: CLIENT_SECRET,
79
84
  refresh_token: refresh_token
80
85
  )
81
86
  client.fetch_access_token!
@@ -94,7 +99,7 @@ module Fastlane
94
99
  def service_account(google_service_path, debug)
95
100
  service_account_credentials = Google::Auth::ServiceAccountCredentials.make_creds(
96
101
  json_key_io: File.open(google_service_path),
97
- scope: Fastlane::Actions::FirebaseAppDistributionLoginAction::SCOPE
102
+ scope: SCOPE
98
103
  )
99
104
  service_account_credentials.fetch_access_token!["access_token"]
100
105
  rescue Errno::ENOENT
@@ -13,6 +13,8 @@ module ErrorMessage
13
13
  INVALID_PROJECT = "App Distribution could not find your Firebase project. Make sure to onboard an app in your project by pressing the \"Get started\" button on the App Distribution page in the Firebase console: https://console.firebase.google.com/project/_/appdistribution."
14
14
  INVALID_PATH = "Could not read content from"
15
15
  INVALID_TESTERS = "Could not enable access for testers. Check that the tester emails are formatted correctly, the groups exist and you are using group aliases (not group names) for specifying groups."
16
+ INVALID_TESTER_GROUP = "App Distribution could not find your tester group. Make sure that it exists before trying to add testers, and that the group alias is specified correctly."
17
+ INVALID_TESTER_GROUP_NAME = "The tester group name should be 4-63 characters, and valid characters are /[a-z][0-9]-/."
16
18
  INVALID_RELEASE_NOTES = "Failed to add release notes"
17
19
  SERVICE_CREDENTIALS_ERROR = "App Distribution could not generate credentials from the service credentials file specified"
18
20
  PLAY_ACCOUNT_NOT_LINKED = "This project is not linked to a Google Play account."
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module FirebaseAppDistribution
3
- VERSION = "0.4.2"
3
+ VERSION = "0.6.0"
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.4.2
4
+ version: 0.6.0
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: 2023-01-24 00:00:00.000000000 Z
13
+ date: 2023-06-05 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
@@ -153,9 +153,10 @@ files:
153
153
  - lib/fastlane/plugin/firebase_app_distribution.rb
154
154
  - lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_action.rb
155
155
  - lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_add_testers_action.rb
156
+ - lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_create_group_action.rb
157
+ - lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_delete_group_action.rb
156
158
  - lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_get_latest_release.rb
157
159
  - lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_get_udids.rb
158
- - lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_login.rb
159
160
  - lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_remove_testers_action.rb
160
161
  - lib/fastlane/plugin/firebase_app_distribution/client/aab_info.rb
161
162
  - lib/fastlane/plugin/firebase_app_distribution/client/error_response.rb
@@ -169,7 +170,7 @@ homepage: https://github.com/fastlane/fastlane-plugin-firebase_app_distribution
169
170
  licenses:
170
171
  - MIT
171
172
  metadata: {}
172
- post_install_message:
173
+ post_install_message:
173
174
  rdoc_options: []
174
175
  require_paths:
175
176
  - lib
@@ -184,8 +185,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
184
185
  - !ruby/object:Gem::Version
185
186
  version: '0'
186
187
  requirements: []
187
- rubygems_version: 3.1.6
188
- signing_key:
188
+ rubygems_version: 3.4.10
189
+ signing_key:
189
190
  specification_version: 4
190
191
  summary: Release your beta builds to Firebase App Distribution. https://firebase.google.com/docs/app-distribution
191
192
  test_files: []
@@ -1,121 +0,0 @@
1
- require 'googleauth'
2
- require "fileutils"
3
-
4
- module Fastlane
5
- module Actions
6
- class FirebaseAppDistributionLoginAction < Action
7
- SCOPE = "https://www.googleapis.com/auth/cloud-platform"
8
-
9
- # In this type of application, the client secret is not treated as a secret.
10
- # See: https://developers.google.com/identity/protocols/OAuth2InstalledApp
11
- CLIENT_ID = "563584335869-fgrhgmd47bqnekij5i8b5pr03ho849e6.apps.googleusercontent.com"
12
- CLIENT_SECRET = "j9iVZfS8kkCEFUPaAeJV0sAi"
13
-
14
- def self.run(params)
15
- callback_uri = "http://localhost:#{params[:port]}"
16
- client_id = Google::Auth::ClientId.new(CLIENT_ID, CLIENT_SECRET)
17
- authorizer = Google::Auth::UserAuthorizer.new(client_id, SCOPE, nil, callback_uri)
18
-
19
- # Create an anti-forgery state token as described here:
20
- # https://developers.google.com/identity/protocols/OpenIDConnect#createxsrftoken
21
- state = SecureRandom.hex(16)
22
- url = authorizer.get_authorization_url(state: state)
23
-
24
- UI.message("Open the following address in your browser and sign in with your Google account:")
25
- UI.message(url)
26
-
27
- response_params = get_authorization_code(params[:port])
28
-
29
- # Confirm that the state in the response matches the state token used to
30
- # generate the authorization URL.
31
- unless state == response_params['state'][0]
32
- UI.crash!('An error has occurred. The state parameter in the authorization response does not match the expected state, which could mean that a malicious attacker is trying to make a login request.')
33
- end
34
-
35
- user_credentials = authorizer.get_credentials_from_code(
36
- code: response_params['code'][0]
37
- )
38
- UI.success("Set the refresh token as the FIREBASE_TOKEN environment variable")
39
- UI.success("Refresh Token: #{user_credentials.refresh_token}")
40
- rescue => error
41
- UI.error(error.to_s)
42
- UI.crash!("An error has occurred, please login again.")
43
- end
44
-
45
- def self.get_authorization_code(port)
46
- begin
47
- server = TCPServer.open(port)
48
- rescue Errno::EADDRINUSE => error
49
- UI.error(error.to_s)
50
- UI.crash!("Port #{port} is in use. Please specify a different one using the port parameter.")
51
- end
52
- client = server.accept
53
- callback_request = client.readline
54
- # Use a regular expression to extract the request line from the first line of
55
- # the callback request, e.g.:
56
- # GET /?code=AUTH_CODE&state=XYZ&scope=... HTTP/1.1
57
- matcher = /GET +([^ ]+)/.match(callback_request)
58
- response_params = CGI.parse(URI.parse(matcher[1]).query) unless matcher.nil?
59
-
60
- client.puts("HTTP/1.1 200 OK")
61
- client.puts("Content-Type: text/html")
62
- client.puts("")
63
- client.puts("<b>")
64
- if response_params['code'].nil?
65
- client.puts("Failed to retrieve authorization code.")
66
- else
67
- client.puts("Authorization code was successfully retrieved.")
68
- end
69
- client.puts("</b>")
70
- client.puts("<p>Please check the console output.</p>")
71
- client.close
72
-
73
- return response_params
74
- end
75
-
76
- #####################################################
77
- # @!group Documentation
78
- #####################################################
79
-
80
- def self.description
81
- "Authenticate with Firebase App Distribution using a Google account."
82
- end
83
-
84
- def self.details
85
- "Log in to Firebase App Distribution using a Google account to generate an authentication "\
86
- "token. This token is stored within an environment variable and used to authenticate with your Firebase project. "\
87
- "See https://firebase.google.com/docs/app-distribution/ios/distribute-fastlane for more information."
88
- end
89
-
90
- def self.authors
91
- ["Manny Jimenez Github: mannyjimenez0810, Alonso Salas Infante Github: alonsosalasinfante"]
92
- end
93
-
94
- def self.is_supported?(platform)
95
- [:ios, :android].include?(platform)
96
- end
97
-
98
- def self.available_options
99
- [
100
- FastlaneCore::ConfigItem.new(key: :port,
101
- env_name: "FIREBASEAPPDISTRO_LOGIN_PORT",
102
- description: "Port for the local web server which receives the response from Google's authorization server",
103
- default_value: "8081",
104
- optional: true,
105
- type: String)
106
-
107
- ]
108
- end
109
-
110
- def self.category
111
- :deprecated
112
- end
113
-
114
- def self.deprecated_notes
115
- "The firebase_app_distribution_login task is deprecated and will be removed in Q1 2023. See "\
116
- "https://firebase.google.com/docs/app-distribution/android/distribute-gradle#authenticate "\
117
- "for more information on alternative ways to authenticate."
118
- end
119
- end
120
- end
121
- end