fastlane-plugin-firebase_management_api 1.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c456fd3fde81966d576ecc095789ac862c3859fe635a6a2a14880edbc4a6f06d
4
+ data.tar.gz: e4d4430728bda4d189d296e8165967874168c5d4a6b997051818f36f45351d34
5
+ SHA512:
6
+ metadata.gz: da9ff9e31d404bf836964599443e2468db203cbb5664e23661611dbb37f7f28a91862d8191e935a575c7b545620fa3ae89d6bc0c185882c5c6c4f793f6c7720e
7
+ data.tar.gz: bc13fc7004eea8fc53a36cb2c12b0a0ef180abcc81076f8a103ec21eb0791aba32383df9d054cccb2cc71dd191658b5d3ddf17fa1e8f0e715bf3fa8be3d1bc93
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Tomas Kohout <email@tomaskohout.cz>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # firebase_management `fastlane` Plugin
2
+
3
+ [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-firebase_management)
4
+
5
+ ## Getting Started
6
+
7
+ This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-firebase_management`, add it to your project by running:
8
+
9
+ ```bash
10
+ fastlane add_plugin firebase_management
11
+ ```
12
+
13
+ ## About firebase_management
14
+
15
+ An unofficial tool to access Firebase project settings. It allows you to create new apps and download config files (GoogleInfo.plist for ios and google-services.json for android).
16
+
17
+ Plugin uses new official [Firebase Management API](https://firebase.google.com/docs/projects/api/reference/rest/) introduced on Firebase Summit 10/2018. It's based on [tkohout/fastlane-firebase-plugin](https://github.com/tkohout/fastlane-firebase-plugin), which uses web scraping instead of official API to manage Firebase apps. The plan is that both plugins will live next to each other until official API will contain all desired features and tkohout's plugin won't be needed anymore.
18
+
19
+ New features like deleting apps or APNs keys/certificates management are promised by guys from Google/Firebase so stay tuned 🤙
20
+
21
+ **This very first version was developed using alpha version of the API in a very short time, so it may contain bugs or mistakes. Issues and PRs are very welcome! 🤗**
22
+
23
+ ### Actions
24
+
25
+ List all projects and apps
26
+
27
+ ```
28
+ firebase_management_list
29
+ ```
30
+
31
+ Add app to a project and download config file
32
+
33
+ ```
34
+ firebase_management_add_app
35
+ ```
36
+
37
+ Add sha to an android app and download config file
38
+
39
+ ```
40
+ firebase_management_upload_sha
41
+ ```
42
+
43
+ Download config file for a client
44
+
45
+ ```
46
+ firebase_management_download_config
47
+ ```
48
+
49
+ ### Authentication
50
+
51
+ ~~Plugin works only with service accounts.~~
52
+
53
+ #### User login
54
+
55
+ You can use your ordinary account in combination with client secret json file created in GCP console.
56
+
57
+ #### Service accounts
58
+
59
+ A service account is a special Google account that belongs to your application or a virtual machine, instead of to an individual end user. Read more [here](https://cloud.google.com/iam/docs/service-accounts).
60
+
61
+ All you need for the plugin to work is a json file with service account private key information. The easiest way to get it is...
62
+
63
+ Go to Firebase Console -> Your project -> Project settings -> Service accounts and tap on button `Generate new private key`. 🎉 That's the file you need!
64
+
65
+ ## Example
66
+
67
+ 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`.
68
+
69
+ ## Run tests for this plugin
70
+
71
+ To run both the tests, and code style validation, run
72
+
73
+ ```
74
+ rake
75
+ ```
76
+
77
+ To automatically fix many of the styling issues, use
78
+
79
+ ```
80
+ rubocop -a
81
+ ```
82
+
83
+ ## Issues and Feedback
84
+
85
+ For any other issues and feedback about this plugin, please submit it to this repository.
86
+
87
+ ## Troubleshooting
88
+
89
+ If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
90
+
91
+ ## Using _fastlane_ Plugins
92
+
93
+ For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/).
94
+
95
+ ## About _fastlane_
96
+
97
+ _fastlane_ is the easiest way to automate beta deployments and releases for your iOS and Android apps. To learn more, check out [fastlane.tools](https://fastlane.tools).
98
+
99
+ ## Warning
100
+
101
+ DISCLAIMER OF WARRANTIES AND LIMITATION OF LIABILITY.
102
+
103
+ UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
104
+
105
+ TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
106
+
107
+ THE DISCLAIMER OF WARRANTIES AND LIMITATION OF LIABILITY PROVIDED ABOVE SHALL BE INTERPRETED IN A MANNER THAT, TO THE EXTENT POSSIBLE, MOST CLOSELY APPROXIMATES AN ABSOLUTE DISCLAIMER AND WAIVER OF ALL LIABILITY.
@@ -0,0 +1,200 @@
1
+ module Fastlane
2
+ module Actions
3
+ class FirebaseManagementAddAppAction < Action
4
+
5
+ def self.run(params)
6
+ manager = FirebaseManagement::Manager.new
7
+
8
+ # login
9
+ api = nil
10
+ if params[:service_account_json_path] != nil then
11
+ api = manager.serviceAccountLogin(params[:service_account_json_path])
12
+ elsif params[:email] != nil && params[:client_secret_json_path] != nil then
13
+ api = manager.userLogin(params[:email], params[:client_secret_json_path])
14
+ else
15
+ UI.error "You must define service_account_json_path or email with client_secret_json_path."
16
+ return nil
17
+ end
18
+
19
+ # select project
20
+ project_id = params[:project_id] || manager.select_project(nil)["projectId"]
21
+
22
+ # select type
23
+ type = params[:type].to_sym
24
+
25
+ bundle_id = params[:bundle_id]
26
+
27
+ display_name = params[:display_name]
28
+
29
+ case type
30
+ when :ios
31
+ # download apps for project
32
+ apps = api.ios_app_list(project_id)
33
+
34
+ # search for newly created app
35
+ app = apps.detect {|app| app["bundleId"] == bundle_id }
36
+
37
+ UI.success "Start detect app "
38
+
39
+ if app != nil then
40
+ UI.success "You already have app with id: #{app["appId"]}"
41
+ else
42
+ UI.success "Start create new app "
43
+
44
+ # create new ios app on Firebase
45
+ api.add_ios_app(project_id, bundle_id, display_name)
46
+
47
+ # App creation is a long-running operation.
48
+ # Creation endpoint returns operation ID which should be used to check
49
+ # the result of the operation. This requires another Google API to be
50
+ # enabled and other stuff to do so just wait for 3 seconds here, fetch
51
+ # apps from Firebase and check whether the new app is there.
52
+ sleep 3
53
+
54
+ # download apps for project
55
+ apps = api.ios_app_list(project_id)
56
+
57
+ # search for newly created app
58
+ app = apps.detect {|app| app["bundleId"] == bundle_id }
59
+ # present result to user
60
+ if app != nil then
61
+ UI.success "New app with id: #{app["appId"]} successfully created"
62
+ else
63
+ UI.crash! "Unable to create new app"
64
+ end
65
+ end
66
+
67
+
68
+ when :android
69
+
70
+ # download apps for project
71
+ apps = api.android_app_list(project_id)
72
+
73
+ # search for newly created app
74
+ app = apps.detect {|app| app["packageName"] == bundle_id }
75
+
76
+ if app != nil then
77
+ UI.success "You already have app with id: #{app["appId"]}"
78
+ else
79
+
80
+ # create new android app on Firebase
81
+ api.add_android_app(project_id, bundle_id, display_name)
82
+
83
+ # see reason described above
84
+ sleep 3
85
+
86
+ # download apps for project
87
+ apps = api.android_app_list(project_id)
88
+
89
+ # search for newly created app
90
+ app = apps.detect {|app| app["packageName"] == bundle_id }
91
+
92
+ # present result to user
93
+ if app != nil then
94
+ UI.success "New app with id: #{app["appId"]} successfully created"
95
+ else
96
+ UI.crash! "Unable to create new app"
97
+ end
98
+ end
99
+
100
+ end
101
+
102
+ if params[:download_config] then
103
+ #Download config
104
+ Actions::FirebaseManagementDownloadConfigAction.run(
105
+ service_account_json_path: params[:service_account_json_path],
106
+ project_id: project_id,
107
+ app_id: app["appId"],
108
+ type: type,
109
+ output_path: params[:output_path]
110
+ )
111
+ end
112
+ end
113
+
114
+ def self.description
115
+ "Add new app to Firebase project"
116
+ end
117
+
118
+ def self.authors
119
+ ["Ackee, s.r.o."]
120
+ end
121
+
122
+ def self.return_value
123
+ # If your method provides a return value, you can describe here what it does
124
+ end
125
+
126
+ def self.details
127
+ # Optional:
128
+ "Firebase plugin helps you list your projects, create applications and download configuration files."
129
+ end
130
+
131
+ def self.available_options
132
+ [
133
+ FastlaneCore::ConfigItem.new(key: :email,
134
+ env_name: "FIREBASE_EMAIL",
135
+ description: "User's email to identify stored credentials",
136
+ optional: true),
137
+
138
+ FastlaneCore::ConfigItem.new(key: :client_secret_json_path,
139
+ env_name: "FIREBASE_CLIENT_SECRET_JSON_PATH",
140
+ description: "Path to client secret json file",
141
+ optional: true),
142
+
143
+ FastlaneCore::ConfigItem.new(key: :service_account_json_path,
144
+ env_name: "FIREBASE_SERVICE_ACCOUNT_JSON_PATH",
145
+ description: "Path to service account json key",
146
+ optional: true),
147
+
148
+ FastlaneCore::ConfigItem.new(key: :project_id,
149
+ env_name: "FIREBASE_PROJECT_ID",
150
+ description: "Project id",
151
+ optional: true),
152
+
153
+ FastlaneCore::ConfigItem.new(key: :download_config,
154
+ env_name: "FIREBASE_DOWNLOAD_CONFIG",
155
+ description: "Should download config for created client",
156
+ optional: false,
157
+ is_string: false,
158
+ default_value: false),
159
+
160
+ FastlaneCore::ConfigItem.new(key: :type,
161
+ env_name: "FIREBASE_TYPE",
162
+ description: "Type of client (ios, android)",
163
+ verify_block: proc do |value|
164
+ types = [:ios, :android]
165
+ UI.user_error!("Type must be in #{types}") unless types.include?(value.to_sym)
166
+ end
167
+ ),
168
+ FastlaneCore::ConfigItem.new(key: :bundle_id,
169
+ env_name: "FIREBASE_BUNDLE_ID",
170
+ description: "Bundle ID (package name)",
171
+ optional: false),
172
+
173
+ FastlaneCore::ConfigItem.new(key: :display_name,
174
+ env_name: "FIREBASE_DISPLAY_NAME",
175
+ description: "Display name",
176
+ optional: true),
177
+
178
+ FastlaneCore::ConfigItem.new(key: :output_path,
179
+ env_name: "FIREBASE_OUTPUT_PATH",
180
+ description: "Path for the downloaded config",
181
+ optional: false,
182
+ default_value: "./"),
183
+
184
+ FastlaneCore::ConfigItem.new(key: :output_name,
185
+ env_name: "FIREBASE_OUTPUT_NAME",
186
+ description: "Name of the downloaded file",
187
+ optional: true)
188
+ ]
189
+ end
190
+
191
+ def self.is_supported?(platform)
192
+ # Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
193
+ # See: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Platforms.md
194
+ #
195
+ # [:ios, :mac, :android].include?(platform)
196
+ true
197
+ end
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,128 @@
1
+ module Fastlane
2
+ module Actions
3
+ class FirebaseManagementUploadShaAction < Action
4
+
5
+ def self.run(params)
6
+ manager = FirebaseManagement::Manager.new
7
+
8
+ # login
9
+ api = nil
10
+ if params[:service_account_json_path] != nil then
11
+ api = manager.serviceAccountLogin(params[:service_account_json_path])
12
+ elsif params[:email] != nil && params[:client_secret_json_path] != nil then
13
+ api = manager.userLogin(params[:email], params[:client_secret_json_path])
14
+ else
15
+ UI.error "You must define service_account_json_path or email with client_secret_json_path."
16
+ return nil
17
+ end
18
+
19
+ # select project
20
+ project_id = params[:project_id] || manager.select_project(nil)["projectId"]
21
+
22
+ # select app
23
+ app_id = params[:app_id] || manager.select_app(project_id, nil, :android)["appId"]
24
+
25
+ # create new android app on Firebase
26
+ api.upload_sha(project_id, app_id, params[:sha_hash], params[:cert_type])
27
+
28
+ if params[:download_config] then
29
+ #Download config
30
+ Actions::FirebaseManagementDownloadConfigAction.run(
31
+ service_account_json_path: params[:service_account_json_path],
32
+ project_id: project_id,
33
+ app_id: app["appId"],
34
+ type: type,
35
+ output_path: params[:output_path]
36
+ )
37
+ end
38
+ end
39
+
40
+ def self.description
41
+ "Add sha to to Firebase android app"
42
+ end
43
+
44
+ def self.authors
45
+ ["NicoLourenco"]
46
+ end
47
+
48
+ def self.return_value
49
+ # If your method provides a return value, you can describe here what it does
50
+ end
51
+
52
+ def self.details
53
+ # Optional:
54
+ "Firebase plugin helps you list your projects, create applications and download configuration files."
55
+ end
56
+
57
+ def self.available_options
58
+ [
59
+ FastlaneCore::ConfigItem.new(key: :email,
60
+ env_name: "FIREBASE_EMAIL",
61
+ description: "User's email to identify stored credentials",
62
+ optional: true),
63
+
64
+ FastlaneCore::ConfigItem.new(key: :client_secret_json_path,
65
+ env_name: "FIREBASE_CLIENT_SECRET_JSON_PATH",
66
+ description: "Path to client secret json file",
67
+ optional: true),
68
+
69
+ FastlaneCore::ConfigItem.new(key: :service_account_json_path,
70
+ env_name: "FIREBASE_SERVICE_ACCOUNT_JSON_PATH",
71
+ description: "Path to service account json key",
72
+ optional: true),
73
+
74
+ FastlaneCore::ConfigItem.new(key: :project_id,
75
+ env_name: "FIREBASE_PROJECT_ID",
76
+ description: "Project id",
77
+ optional: true),
78
+
79
+ FastlaneCore::ConfigItem.new(key: :app_id,
80
+ env_name: "FIREBASE_APP_ID",
81
+ description: "Project app id",
82
+ optional: true),
83
+
84
+ FastlaneCore::ConfigItem.new(key: :sha_hash,
85
+ env_name: "FIREBASE_SHA_HASH",
86
+ description: "Sha hash",
87
+ optional: false),
88
+
89
+ FastlaneCore::ConfigItem.new(key: :download_config,
90
+ env_name: "FIREBASE_DOWNLOAD_CONFIG",
91
+ description: "Should download config for created client",
92
+ optional: false,
93
+ is_string: false,
94
+ default_value: false),
95
+
96
+ FastlaneCore::ConfigItem.new(key: :cert_type,
97
+ env_name: "FIREBASE_CERT_TYPE",
98
+ description: "Type of certificate (SHA_1, SHA_256)",
99
+ optional: false,
100
+ verify_block: proc do |value|
101
+ types = [:SHA_1, :SHA_256]
102
+ UI.user_error!("Type must be in #{types}") unless types.include?(value.to_sym)
103
+ end
104
+ ),
105
+
106
+ FastlaneCore::ConfigItem.new(key: :output_path,
107
+ env_name: "FIREBASE_OUTPUT_PATH",
108
+ description: "Path for the downloaded config",
109
+ optional: false,
110
+ default_value: "./"),
111
+
112
+ FastlaneCore::ConfigItem.new(key: :output_name,
113
+ env_name: "FIREBASE_OUTPUT_NAME",
114
+ description: "Name of the downloaded file",
115
+ optional: true)
116
+ ]
117
+ end
118
+
119
+ def self.is_supported?(platform)
120
+ # Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
121
+ # See: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Platforms.md
122
+ #
123
+ # [:ios, :mac, :android].include?(platform)
124
+ true
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,122 @@
1
+ module Fastlane
2
+ module Actions
3
+ class FirebaseManagementDownloadConfigAction < Action
4
+
5
+ def self.run(params)
6
+ manager = FirebaseManagement::Manager.new
7
+
8
+ # login
9
+ api = nil
10
+ if params[:service_account_json_path] != nil then
11
+ api = manager.serviceAccountLogin(params[:service_account_json_path])
12
+ elsif params[:email] != nil && params[:client_secret_json_path] != nil then
13
+ api = manager.userLogin(params[:email], params[:client_secret_json_path])
14
+ else
15
+ UI.error "You must define service_account_json_path or email with client_secret_json_path."
16
+ return nil
17
+ end
18
+
19
+ # select project
20
+ project_id = params[:project_id] || manager.select_project(nil)["projectId"]
21
+
22
+ # select type
23
+ type = params[:type].to_sym
24
+
25
+ # select app
26
+ app_id = params[:app_id] || manager.select_app(project_id, nil, type)["appId"]
27
+
28
+ # download
29
+ case type
30
+ when :ios
31
+ config = api.download_ios_config_file(project_id, app_id)
32
+ when :android
33
+ config = api.download_android_config_file(project_id, app_id)
34
+ end
35
+
36
+ path = File.join(params[:output_path], params[:output_name] || config["configFilename"])
37
+
38
+ decode_base64_content = Base64.decode64(config["configFileContents"])
39
+ File.open(path, "wb") do |f|
40
+ f.write(decode_base64_content)
41
+ end
42
+
43
+ UI.success "Successfuly saved config at #{path}"
44
+
45
+ return nil
46
+ end
47
+
48
+ def self.description
49
+ "Download configuration file for Firebase app"
50
+ end
51
+
52
+ def self.authors
53
+ ["Ackee, s.r.o."]
54
+ end
55
+
56
+ def self.return_value
57
+ # If your method provides a return value, you can describe here what it does
58
+ end
59
+
60
+ def self.details
61
+ # Optional:
62
+ "Firebase plugin helps you list your projects, create applications and download configuration files."
63
+ end
64
+
65
+ def self.available_options
66
+ [
67
+ FastlaneCore::ConfigItem.new(key: :email,
68
+ env_name: "FIREBASE_EMAIL",
69
+ description: "User's email to identify stored credentials",
70
+ optional: true),
71
+
72
+ FastlaneCore::ConfigItem.new(key: :client_secret_json_path,
73
+ env_name: "FIREBASE_CLIENT_SECRET_JSON_PATH",
74
+ description: "Path to client secret json file",
75
+ optional: true),
76
+
77
+ FastlaneCore::ConfigItem.new(key: :service_account_json_path,
78
+ env_name: "FIREBASE_SERVICE_ACCOUNT_JSON_PATH",
79
+ description: "Path to service account json key",
80
+ optional: true),
81
+
82
+ FastlaneCore::ConfigItem.new(key: :project_id,
83
+ env_name: "FIREBASE_PROJECT_ID",
84
+ description: "Project id",
85
+ optional: true),
86
+
87
+ FastlaneCore::ConfigItem.new(key: :app_id,
88
+ env_name: "FIREBASE_APP_ID",
89
+ description: "Project app id",
90
+ optional: true),
91
+
92
+ FastlaneCore::ConfigItem.new(key: :type,
93
+ env_name: "FIREBASE_TYPE",
94
+ description: "Type of client (ios, android)",
95
+ verify_block: proc do |value|
96
+ types = [:ios, :android]
97
+ UI.user_error!("Type must be in #{types}") unless types.include?(value.to_sym)
98
+ end
99
+ ),
100
+ FastlaneCore::ConfigItem.new(key: :output_path,
101
+ env_name: "FIREBASE_OUTPUT_PATH",
102
+ description: "Path for the downloaded config",
103
+ optional: false,
104
+ default_value: "./"),
105
+
106
+ FastlaneCore::ConfigItem.new(key: :output_name,
107
+ env_name: "FIREBASE_OUTPUT_NAME",
108
+ description: "Name of the downloaded file",
109
+ optional: true)
110
+ ]
111
+ end
112
+
113
+ def self.is_supported?(platform)
114
+ # Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
115
+ # See: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Platforms.md
116
+ #
117
+ # [:ios, :mac, :android].include?(platform)
118
+ true
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,92 @@
1
+ module Fastlane
2
+ module Actions
3
+ class FirebaseManagementListAction < Action
4
+
5
+ def self.run(params)
6
+ manager = FirebaseManagement::Manager.new
7
+
8
+ # login
9
+ api = nil
10
+ if params[:service_account_json_path] != nil then
11
+ api = manager.serviceAccountLogin(params[:service_account_json_path])
12
+ elsif params[:email] != nil && params[:client_secret_json_path] != nil then
13
+ api = manager.userLogin(params[:email], params[:client_secret_json_path])
14
+ else
15
+ UI.error "You must define service_account_json_path or email with client_secret_json_path."
16
+ return nil
17
+ end
18
+
19
+ # download list of projects
20
+ projects = api.project_list()
21
+
22
+ # create formatted output
23
+ projects.each_with_index { |p, i|
24
+ UI.message "#{i+1}. #{p["displayName"]} (#{p["projectId"]})"
25
+
26
+ ios_apps = api.ios_app_list(p["projectId"])
27
+ if !ios_apps.empty? then
28
+ UI.message " iOS"
29
+ ios_apps.sort {|left, right| left["appId"] <=> right["appId"] }.each_with_index { |app, j|
30
+ UI.message " - #{app["displayName"] || app["bundleId"]} (#{app["appId"]})"
31
+ }
32
+ end
33
+
34
+ android_apps = api.android_app_list(p["projectId"])
35
+ if !android_apps.empty? then
36
+ UI.message " Android"
37
+ android_apps.sort {|left, right| left["appId"] <=> right["appId"] }.each_with_index { |app, j|
38
+ UI.message " - #{app["displayName"] || app["packageName"]} (#{app["appId"]})"
39
+ }
40
+ end
41
+ }
42
+
43
+ return nil
44
+ end
45
+
46
+ def self.description
47
+ "List all Firebase projects and their apps"
48
+ end
49
+
50
+ def self.authors
51
+ ["Ackee, s.r.o."]
52
+ end
53
+
54
+ def self.return_value
55
+ # If your method provides a return value, you can describe here what it does
56
+ end
57
+
58
+ def self.details
59
+ # Optional:
60
+ "Firebase plugin helps you list your projects, create applications and download configuration files."
61
+ end
62
+
63
+ def self.available_options
64
+ [
65
+ FastlaneCore::ConfigItem.new(key: :email,
66
+ env_name: "FIREBASE_EMAIL",
67
+ description: "User's email to identify stored credentials",
68
+ optional: true),
69
+
70
+ FastlaneCore::ConfigItem.new(key: :client_secret_json_path,
71
+ env_name: "FIREBASE_CLIENT_SECRET_JSON_PATH",
72
+ description: "Path to client secret json file",
73
+ optional: true),
74
+
75
+ FastlaneCore::ConfigItem.new(key: :service_account_json_path,
76
+ env_name: "FIREBASE_SERVICE_ACCOUNT_JSON_PATH",
77
+ description: "Path to service account json key",
78
+ optional: true
79
+ )
80
+ ]
81
+ end
82
+
83
+ def self.is_supported?(platform)
84
+ # Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
85
+ # See: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Platforms.md
86
+ #
87
+ # [:ios, :mac, :android].include?(platform)
88
+ true
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,16 @@
1
+ require 'fastlane_core/ui/ui'
2
+
3
+ module Fastlane
4
+ UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
5
+
6
+ module Helper
7
+ class FirebaseManagementHelper
8
+ # class methods that you define here become available in your action
9
+ # as `Helper::FirebaseManagementHelper.your_method`
10
+ #
11
+ def self.show_message
12
+ UI.message("Hello from the firebase_management plugin helper!")
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,147 @@
1
+ module Fastlane
2
+ module FirebaseManagement
3
+ class Api
4
+ class LoginError < StandardError
5
+ end
6
+
7
+ class BadRequestError < StandardError
8
+ attr_reader :code
9
+
10
+ def initialize(msg, code)
11
+ @code = code
12
+ super(msg)
13
+ end
14
+ end
15
+
16
+ require 'googleauth'
17
+ require 'httparty'
18
+
19
+ def initialize(access_token)
20
+ @base_url = "https://firebase.googleapis.com"
21
+ @authorization_headers = {
22
+ 'Authorization' => 'Bearer ' + access_token
23
+ }
24
+ end
25
+
26
+ def request_json(path, method = :get, parameters = Hash.new, headers = Hash.new)
27
+ begin
28
+ if method == :get then
29
+ response = HTTParty.get("#{@base_url}/#{path}", headers: headers.merge(@authorization_headers), format: :plain)
30
+ elsif method == :post then
31
+ headers['Content-Type'] = 'application/json'
32
+ response = HTTParty.post("#{@base_url}/#{path}", headers: headers.merge(@authorization_headers), body: parameters.to_json, format: :plain)
33
+ end
34
+
35
+ case response.code
36
+ when 400...600
37
+ UI.crash! response
38
+ else
39
+ JSON.parse(response)
40
+ end
41
+
42
+ rescue HTTParty::Error => e
43
+ UI.crash! e.response.body
44
+ rescue StandardError => e
45
+ UI.crash! e
46
+ end
47
+ end
48
+
49
+ def project_list
50
+ UI.verbose "Retrieving project list"
51
+ json = request_json("v1beta1/projects")
52
+ projects = json["results"] || []
53
+ UI.verbose "Found #{projects.count} projects"
54
+ projects
55
+ end
56
+
57
+ def ios_app_list(project_id, params = nil)
58
+ UI.verbose "Retrieving app list for project #{project_id}"
59
+
60
+ apps = []
61
+ pageToken = nil
62
+ loop do
63
+ url = "v1beta1/projects/#{project_id}/iosApps" + (pageToken ? "?pageToken=#{pageToken}" : "")
64
+ json = request_json(url)
65
+ apps.concat(json["apps"] || [])
66
+ pageToken = json["nextPageToken"]
67
+ break if !pageToken
68
+ end
69
+ UI.verbose "Found #{apps.count} apps"
70
+ apps
71
+ end
72
+
73
+ def android_app_list(project_id)
74
+ UI.verbose "Retrieving app list for project #{project_id}"
75
+ apps = []
76
+ pageToken = nil
77
+ loop do
78
+ url = "v1beta1/projects/#{project_id}/androidApps" + (pageToken ? "?pageToken=#{pageToken}" : "")
79
+ json = request_json(url)
80
+ apps.concat(json["apps"] || [])
81
+ pageToken = json["nextPageToken"]
82
+ break if !pageToken
83
+ end
84
+ UI.verbose "Found #{apps.count} apps"
85
+ apps
86
+ end
87
+
88
+ def add_ios_app(project_id, bundle_id, app_name)
89
+ parameters = {
90
+ "bundleId" => bundle_id,
91
+ "displayName" => app_name || ""
92
+ }
93
+
94
+ request_json("v1beta1/projects/#{project_id}/iosApps", :post, parameters)
95
+ end
96
+
97
+ def add_android_app(project_id, package_name, app_name)
98
+ parameters = {
99
+ "packageName" => package_name,
100
+ "displayName" => app_name || ""
101
+ }
102
+
103
+ request_json("v1beta1/projects/#{project_id}/androidApps", :post, parameters)
104
+ end
105
+
106
+ def upload_sha(project_id, app_id, sha_hash, cert_type)
107
+ UI.verbose "Uploading sha"
108
+ parameters = {
109
+ "shaHash" => sha_hash,
110
+ "certType" => cert_type,
111
+ }
112
+
113
+ json = request_json("v1beta1/projects/#{project_id}/androidApps/#{app_id}/sha", :post, parameters)
114
+ UI.verbose "Successfuly uploaded sha"
115
+ json
116
+ end
117
+
118
+ def upload_certificate(project_number, client_id, type, certificate_value, certificate_password)
119
+
120
+ prefix = type == :development ? "debug" : "prod"
121
+
122
+ parameters = {
123
+ "#{prefix}ApnsCertificate" => {
124
+ "certificateValue" => certificate_value,
125
+ "apnsPassword" => certificate_password
126
+ }
127
+ }
128
+
129
+ json = request_json("v1/projects/#{project_number}/clients/#{client_id}:setApnsCertificate", :post, parameters)
130
+ end
131
+
132
+ def download_ios_config_file(project_id, app_id)
133
+ UI.verbose "Downloading config file"
134
+ json = request_json("v1beta1/projects/#{project_id}/iosApps/#{app_id}/config")
135
+ UI.verbose "Successfuly downloaded #{json["configFilename"]}"
136
+ json
137
+ end
138
+
139
+ def download_android_config_file(project_id, app_id)
140
+ UI.verbose "Downloading config file"
141
+ json = request_json("v1beta1/projects/#{project_id}/androidApps/#{app_id}/config")
142
+ UI.verbose "Successfuly downloaded #{json["configFilename"]}"
143
+ json
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,41 @@
1
+ require 'commander'
2
+ require 'fastlane/version'
3
+
4
+
5
+ module FirebaseManagement
6
+ class CommandsGenerator
7
+ include Commander::Methods
8
+
9
+ def self.start
10
+ self.new.run
11
+ end
12
+
13
+ def run
14
+ program :name, 'firebase'
15
+ program :version, Fastlane::VERSION
16
+ program :description, 'CLI for \'PEM\' - Automatically generate and renew your push notification profiles'
17
+ program :help, 'Author', 'Felix Krause <pem@krausefx.com>'
18
+ program :help, 'Website', 'https://fastlane.tools'
19
+ program :help, 'GitHub', 'https://github.com/fastlane/PEM'
20
+ program :help_formatter, :compact
21
+
22
+ global_option('--verbose') { FastlaneCore::Globals.verbose = true }
23
+
24
+ command :list do |c|
25
+ c.syntax = 'fastlane firebase list'
26
+ c.description = 'Lists all projects in your firebase'
27
+
28
+ FastlaneCore::CommanderGenerator.new.generate(Firebase::Options.available_options, command: c)
29
+
30
+ c.action do |args, options|
31
+ Firebase.config = FastlaneCore::Configuration.create(Firebase::Options.available_options, options.__hash__)
32
+ #Firebase::Manager.start
33
+ end
34
+ end
35
+
36
+ default_command :list
37
+
38
+ run!
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,99 @@
1
+ module Fastlane
2
+ module FirebaseManagement
3
+ class Manager
4
+
5
+ require 'googleauth'
6
+ require 'googleauth/stores/file_token_store'
7
+
8
+ def userLogin(email, client_secrets_path)
9
+
10
+ system 'mkdir -p ~/.google'
11
+
12
+ oob_uri = "urn:ietf:wg:oauth:2.0:oob"
13
+
14
+ scopes = [
15
+ 'https://www.googleapis.com/auth/firebase',
16
+ 'https://www.googleapis.com/auth/cloud-platform'
17
+ ]
18
+ client_id = Google::Auth::ClientId.from_file(client_secrets_path)
19
+ token_store = Google::Auth::Stores::FileTokenStore.new(:file => File.expand_path("~/.google/tokens.yaml"))
20
+ authorizer = Google::Auth::UserAuthorizer.new(client_id, scopes, token_store)
21
+
22
+ credentials = authorizer.get_credentials(email)
23
+ if credentials.nil?
24
+ url = authorizer.get_authorization_url(base_url: oob_uri)
25
+ UI.message "Open #{url} in your browser and enter the resulting code."
26
+
27
+ code = Fastlane::Actions::PromptAction.run(text: "Code: ")
28
+
29
+ credentials = authorizer.get_and_store_credentials_from_code(user_id: email, code: code, base_url: oob_uri)
30
+ end
31
+
32
+ token = credentials.fetch_access_token!["access_token"]
33
+ @api = FirebaseManagement::Api.new(token)
34
+ @api
35
+ end
36
+
37
+ def serviceAccountLogin(jsonPath)
38
+ scope = 'https://www.googleapis.com/auth/firebase https://www.googleapis.com/auth/cloud-platform'
39
+
40
+ authorizer = Google::Auth::ServiceAccountCredentials.make_creds(
41
+ json_key_io: File.open(jsonPath),
42
+ scope: scope
43
+ )
44
+
45
+ token = authorizer.fetch_access_token!["access_token"]
46
+ @api = FirebaseManagement::Api.new(token)
47
+ @api
48
+ end
49
+
50
+ def select_project(project_id)
51
+
52
+ projects = @api.project_list()
53
+
54
+ if projects.count == 0 then
55
+ UI.user_error! "No projects exist under the account"
56
+ return
57
+ end
58
+
59
+ if project = projects.select {|p| p["projectId"] == project_id }.first then
60
+ project
61
+ else
62
+ options = projects.map { |p| "#{p["displayName"]} (#{p["projectId"]})" }
63
+ index = select_index("Select project:", options)
64
+ projects[index]
65
+ end
66
+ end
67
+
68
+ def select_app(project_id, app_id, type)
69
+
70
+ case type
71
+ when :ios
72
+ apps = @api.ios_app_list(project_id)
73
+ when :android
74
+ apps = @api.android_app_list(project_id)
75
+ end
76
+
77
+ if apps.empty? then
78
+ UI.user_error! "Project has no #{type} apps"
79
+ return
80
+ end
81
+
82
+ apps = apps.sort {|left, right| left["appId"] <=> right["appId"] }
83
+
84
+ if app = apps.select {|a| a["appId"] == app_id }.first then
85
+ app
86
+ else
87
+ options = apps.map { |a| "#{a["displayName"] || a["bundleId"] || a["packageName"]} (#{a["appId"]})" }
88
+ index = select_index("Select app:", options)
89
+ apps[index]
90
+ end
91
+ end
92
+
93
+ def select_index(text, options)
94
+ selected = UI.select(text, options)
95
+ return options.index(selected)
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,16 @@
1
+ require 'fastlane_core'
2
+ require 'credentials_manager'
3
+
4
+ module FirebaseManagement
5
+ class Options
6
+ def self.available_options
7
+ [
8
+ FastlaneCore::ConfigItem.new(
9
+ key: :username,
10
+ env_name: "FIREBASE_USERNAME",
11
+ description: "Username for the google account"
12
+ )
13
+ ]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ module Fastlane
2
+ module FirebaseManagement
3
+ VERSION = "1.1.1"
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ require 'fastlane/plugin/firebase_management_api/version'
2
+
3
+ module Fastlane
4
+ module FirebaseManagement
5
+ # Return all .rb files inside the "actions" and "helper" directory
6
+ def self.all_classes
7
+ Dir[File.expand_path('**/{actions,helper,lib}/*.rb', File.dirname(__FILE__))]
8
+ end
9
+ end
10
+ end
11
+
12
+ # By default we want to import all available actions and helpers
13
+ # A plugin can contain any number of actions and plugins
14
+ Fastlane::FirebaseManagement.all_classes.each do |current|
15
+ require current
16
+ end
metadata ADDED
@@ -0,0 +1,209 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fastlane-plugin-firebase_management_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Abdelrahman Eldesoky
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-01-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pry
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec_junit_formatter
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: 0.49.1
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '='
95
+ - !ruby/object:Gem::Version
96
+ version: 0.49.1
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-require_tools
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: fastlane
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: 2.108.0
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: 2.108.0
139
+ - !ruby/object:Gem::Dependency
140
+ name: googleauth
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: httparty
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ description:
168
+ email: abdelrhman.m.eldesoky@gmail.com
169
+ executables: []
170
+ extensions: []
171
+ extra_rdoc_files: []
172
+ files:
173
+ - LICENSE
174
+ - README.md
175
+ - lib/fastlane/plugin/firebase_management_api.rb
176
+ - lib/fastlane/plugin/firebase_management_api/actions/firebase_add_app_action.rb
177
+ - lib/fastlane/plugin/firebase_management_api/actions/firebase_add_app_sha_action.rb
178
+ - lib/fastlane/plugin/firebase_management_api/actions/firebase_download_config_action.rb
179
+ - lib/fastlane/plugin/firebase_management_api/actions/firebase_list_action.rb
180
+ - lib/fastlane/plugin/firebase_management_api/helper/firebase_management_helper.rb
181
+ - lib/fastlane/plugin/firebase_management_api/lib/api.rb
182
+ - lib/fastlane/plugin/firebase_management_api/lib/commands_generator.rb
183
+ - lib/fastlane/plugin/firebase_management_api/lib/manager.rb
184
+ - lib/fastlane/plugin/firebase_management_api/lib/options.rb
185
+ - lib/fastlane/plugin/firebase_management_api/version.rb
186
+ homepage: https://github.com/morecreative-dev/fastlane-plugin-firebase_management_api
187
+ licenses:
188
+ - MIT
189
+ metadata: {}
190
+ post_install_message:
191
+ rdoc_options: []
192
+ require_paths:
193
+ - lib
194
+ required_ruby_version: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - ">="
197
+ - !ruby/object:Gem::Version
198
+ version: '0'
199
+ required_rubygems_version: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
204
+ requirements: []
205
+ rubygems_version: 3.0.3.1
206
+ signing_key:
207
+ specification_version: 4
208
+ summary: Unofficial tool to access Firebase project settings
209
+ test_files: []