fastlane-plugin-fabric_beta_unregistered_devices 0.1.0

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: a84c77a5c421fb3b45ef76e57567f828ceff4a554a57550e40e7f53bcb5081b6
4
+ data.tar.gz: f7deebfbe974569251c2b6385ca96aa3fd2b48b27dc1e02e1dcf0d5ff08843f0
5
+ SHA512:
6
+ metadata.gz: 7a90370ba641e09ec7395b1f5fce6f72403b200c89074f414da4eaaead0f39bc5dc9ec94c573741e06ff08ac0f3176b2e670c62792ca3f060f63603a877dabcd
7
+ data.tar.gz: 9ad010db10158c0e22c84cd5223db28700eb64d336cb9e0ae2db07e5a4440e2fd4def8c2b3d52a6ef2bde68d62059a5953a712853e39ccbb2d6a097fc0dc59b4
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Starmel <slava.kornienko16@gmail.com>
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,62 @@
1
+ # fabric_beta_unregistered_devices plugin
2
+
3
+ [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-fabric_beta_unregistered_devices)
4
+
5
+ ## Getting Started
6
+
7
+ This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-fabric_beta_unregistered_devices`, add it to your project by running:
8
+
9
+ ```bash
10
+ fastlane add_plugin fabric_beta_unregistered_devices
11
+ ```
12
+
13
+ ## About fabric_beta_unregistered_devices
14
+
15
+ Get unregistered devices of your Fabric Beta project release.
16
+
17
+ Plugin is checking testers in your last app release and verify that all test device included in your Apple Developer Account.
18
+
19
+ Warning: This plugin is not automatically add devices to your profile, just checking included.
20
+
21
+ ## For setup required
22
+
23
+ * fabric_login - Fabric username or email
24
+ * fabric_password - Fabric password for authorization (Fabric do not provide CI keys, api keys used for uploading builds to Crashlytics are not allow to see organization Beta releases)
25
+ * fabric_organization_name - organization or profile name which own project
26
+ * bundle_identifier - App Bundle Id
27
+ * apple_username - username of Apple Developer Account
28
+ * team_id - if few team in one account. Optional.
29
+
30
+ Example how to use with automatic registration:
31
+ ```bash
32
+ devices_to_register = fabric_beta_unregistered_devices(
33
+ fabric_login: "login",
34
+ fabric_password: "password",
35
+ fabric_organization_name: "organization",
36
+ bundle_identifier: "identifier",
37
+ apple_username: "username",
38
+ team_id: "team"
39
+ )
40
+ register_devices(devices: devices_to_register, username: "username") if devices_to_register.size > 0
41
+ ```
42
+
43
+
44
+ ## Example
45
+
46
+ 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`.
47
+
48
+ ## Issues and Feedback
49
+
50
+ For any other issues and feedback about this plugin, please submit it to this repository.
51
+
52
+ ## Troubleshooting
53
+
54
+ If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
55
+
56
+ ## Using _fastlane_ Plugins
57
+
58
+ For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/).
59
+
60
+ ## About _fastlane_
61
+
62
+ _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).
@@ -0,0 +1,16 @@
1
+ require 'fastlane/plugin/fabric_beta_unregistered_devices/version'
2
+
3
+ module Fastlane
4
+ module FabricBetaUnregisteredDevices
5
+ # Return all .rb files inside the "actions" and "helper" directory
6
+ def self.all_classes
7
+ Dir[File.expand_path('**/{actions,helper}/*.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::FabricBetaUnregisteredDevices.all_classes.each do |current|
15
+ require current
16
+ end
@@ -0,0 +1,198 @@
1
+ require 'fastlane/action'
2
+ require_relative '../helper/fabric_api_helper'
3
+ require_relative '../helper/fabric_auth_helper'
4
+
5
+ module Fastlane
6
+ module Actions
7
+ class FabricBetaUnregisteredDevicesAction < Action
8
+
9
+ UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
10
+
11
+ def self.run(params)
12
+ require 'Spaceship'
13
+ require 'credentials_manager'
14
+
15
+ # Log in AppleId
16
+ credentials = CredentialsManager::AccountManager.new(user: params[:apple_username])
17
+ Spaceship.login(credentials.user, credentials.password)
18
+ Spaceship.select_team
19
+
20
+ # Log in Fabric
21
+ fabric_auth_helper = FabricAuthHelper.new
22
+ access_token = fabric_auth_helper.get_auth_token(params[:fabric_login], params[:fabric_password])
23
+
24
+ fabric_api_helper = FabricApiHelper.new access_token
25
+
26
+ # Get Fabric Organizations
27
+ profile_info_json = fabric_api_helper.get_profile_info_json
28
+
29
+ organizations = profile_info_json["organizations"]
30
+
31
+ # Select organization for choosing it api_key
32
+ selected_organization = organizations.find {|organization| organization["name"] == params[:fabric_organization_name]}
33
+ fabric_api_helper.organization_api_key = selected_organization["api_key"]
34
+
35
+ # Get all organization projects
36
+ organization_detail_info_json = fabric_api_helper.get_organization_info_json selected_organization["id"]
37
+ projects_json = organization_detail_info_json["apps"].select {|app| app["platform"] == "ios"}
38
+
39
+ if projects_json.size > 0
40
+ selected_project = projects_json.find {|project| project["bundle_identifier"] == params[:bundle_identifier]}
41
+
42
+ # Get last project release for getting testers from it
43
+ releases_json = fabric_api_helper.get_project_releases_json(selected_project["bundle_identifier"])
44
+ instances = releases_json["instances"]
45
+ if instances && instances.size > 0
46
+ last_release = instances.first
47
+
48
+ project_uid = selected_project["bundle_identifier"]
49
+ release_uid = last_release["instance_identifier"]
50
+ display_version = last_release["build_version"]["display_version"]
51
+ build_version = last_release["build_version"]["build_version"]
52
+
53
+ release_detail_json = fabric_api_helper.get_project_release_json(project_uid, release_uid, display_version, build_version)
54
+
55
+ # v Users in last release v
56
+ entries = release_detail_json["entries"]
57
+ self.puts_testers_info(entries)
58
+ devices = self.select_devices_for_registration(entries)
59
+ self.puts_devices_for_registration(devices)
60
+
61
+ devices.to_h {|item| [item[0], item[1]]}
62
+ else
63
+ UI.error "Not found releases in App: #{params[:bundle_identifier]}"
64
+ end
65
+ else
66
+ UI.error "Not found iOS apps in organization."
67
+ end
68
+ end
69
+
70
+ def self.select_devices_for_registration(entries)
71
+ registered_device_udids = Spaceship::Portal.device.all.map(&:udid)
72
+
73
+ devices_to_register = []
74
+
75
+ entries.each do |entry|
76
+ devices = entry["devices"]
77
+ devices.each do |device|
78
+ unless registered_device_udids.include? device["identifier"]
79
+ devices_to_register << ["#{entry["email"]} #{device["name"]}", device["identifier"]]
80
+ end
81
+ end
82
+ end
83
+
84
+ devices_to_register
85
+ end
86
+
87
+ def self.puts_devices_for_registration(devices)
88
+ require 'terminal-table'
89
+ if devices.size > 0
90
+ UI.success("Unregistered devices:")
91
+ puts Terminal::Table.new :rows => devices, :headings => ["Registration name", "Device uuid"]
92
+ else
93
+ UI.success("All devices is up-to-date!")
94
+ end
95
+ end
96
+
97
+ def self.puts_testers_info(entries)
98
+ require 'terminal-table'
99
+ rows = []
100
+ entries.each do |entry|
101
+ rows << [entry["name"], entry["email"], "", "", ""]
102
+
103
+ devices = entry["devices"]
104
+ if devices.size > 0
105
+ devices.each {|device| rows << ["", "", device["name"], device["identifier"], device["distribution_available"]]}
106
+ else
107
+ rows << ["", "", "no devices", "", ""]
108
+ end
109
+
110
+ end
111
+ puts Terminal::Table.new :rows => rows, :headings => ["Tester name", "Tester email", "Device name", "Device uuid", "Can distribute?"]
112
+ end
113
+
114
+ def self.description
115
+ "Get unregistered devices from Fabric Beta."
116
+ end
117
+
118
+ def self.authors
119
+ ["Slava Kornienko"]
120
+ end
121
+
122
+ def self.return_value
123
+ '{ "Registration name" => "DeviceUID", ... }'
124
+ end
125
+
126
+ def self.details
127
+ # Optional:
128
+ end
129
+
130
+ def self.available_options
131
+ user = CredentialsManager::AppfileConfig.try_fetch_value(:apple_dev_portal_id)
132
+ user ||= CredentialsManager::AppfileConfig.try_fetch_value(:apple_id)
133
+ [
134
+ # Fabric options
135
+ FastlaneCore::ConfigItem.new(key: :fabric_login,
136
+ env_name: "SYNC_DEVICES_FABRIC_LOGIN",
137
+ description: "Username/email for Fabric",
138
+ verify_block: proc do |value|
139
+ UI.user_error!("No login for Fabric") if value.to_s.length == 0
140
+ end),
141
+ FastlaneCore::ConfigItem.new(key: :fabric_password,
142
+ env_name: "SYNC_DEVICES_FABRIC_PASSWORD",
143
+ description: "Password for Fabric",
144
+ sensitive: true,
145
+ verify_block: proc do |value|
146
+ UI.user_error!("No password for Fabric") if value.to_s.length == 0
147
+ end),
148
+ FastlaneCore::ConfigItem.new(key: :fabric_organization_name,
149
+ env_name: "SYNC_DEVICES_FABRIC_ORGANIZATION",
150
+ description: "Fabric organization name",
151
+ sensitive: true,
152
+ verify_block: proc do |value|
153
+ UI.user_error!("No Fabric organization name") if value.to_s.length == 0
154
+ end),
155
+ FastlaneCore::ConfigItem.new(key: :bundle_identifier,
156
+ env_name: "SYNC_DEVICES_FABRIC_APP",
157
+ description: "Fabric Bundle Identifier (XCode App Bundle)",
158
+ sensitive: true,
159
+ verify_block: proc do |value|
160
+ UI.user_error!("No Fabric project uid") if value.to_s.length == 0
161
+ end),
162
+
163
+ # SpaceShip options
164
+ FastlaneCore::ConfigItem.new(key: :team_id,
165
+ env_name: "REGISTER_DEVICES_TEAM_ID",
166
+ code_gen_sensitive: true,
167
+ default_value: CredentialsManager::AppfileConfig.try_fetch_value(:team_id),
168
+ default_value_dynamic: true,
169
+ description: "The ID of your Developer Portal team if you're in multiple teams",
170
+ optional: true,
171
+ verify_block: proc do |value|
172
+ ENV["FASTLANE_TEAM_ID"] = value.to_s
173
+ end),
174
+ FastlaneCore::ConfigItem.new(key: :team_name,
175
+ env_name: "REGISTER_DEVICES_TEAM_NAME",
176
+ description: "The name of your Developer Portal team if you're in multiple teams",
177
+ optional: true,
178
+ code_gen_sensitive: true,
179
+ default_value: CredentialsManager::AppfileConfig.try_fetch_value(:team_name),
180
+ default_value_dynamic: true,
181
+ verify_block: proc do |value|
182
+ ENV["FASTLANE_TEAM_NAME"] = value.to_s
183
+ end),
184
+ FastlaneCore::ConfigItem.new(key: :apple_username,
185
+ env_name: "DELIVER_USER",
186
+ description: "Your Apple ID",
187
+ default_value: user,
188
+ default_value_dynamic: true)
189
+ ]
190
+ end
191
+
192
+ def self.is_supported?(platform)
193
+ platform == :ios
194
+ end
195
+
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,50 @@
1
+ class FabricApiHelper
2
+ attr_writer :organization_api_key
3
+ require 'httpclient'
4
+ require 'json'
5
+
6
+
7
+ def initialize(auth_token)
8
+ @organization_api_key = ""
9
+ @http_client = HTTPClient.new :base_url => "https://fabric.io", :default_header => {
10
+ :Authorization => "Bearer #{auth_token}"
11
+ }
12
+ end
13
+
14
+ def get_profile_info_json
15
+ res = @http_client.get "/api/v3/account"
16
+ parse_or_print_body(res)
17
+ end
18
+
19
+ def get_organization_info_json(organization_id)
20
+ res = @http_client.get "/api/v2/organizations/#{organization_id}", :header => {
21
+ :"X-CRASHLYTICS-API-KEY" => @organization_api_key
22
+ }
23
+ parse_or_print_body(res)
24
+ end
25
+
26
+ def get_project_releases_json(project_uid)
27
+ res = @http_client.get "http://api.crashlytics.com/spi/v1/platforms/ios/apps/#{project_uid}/releases?", :header => {
28
+ :"X-CRASHLYTICS-API-KEY" => @organization_api_key
29
+ }
30
+ parse_or_print_body(res)
31
+ end
32
+
33
+ def get_project_release_json(project_uid, release_uid, build_version, display_version)
34
+ res = @http_client.get "http://api.crashlytics.com/spi/v1/platforms/ios/apps/#{project_uid}/releases/#{release_uid}/access?app%5Bbuild_version%5D=#{build_version}&app%5Bdisplay_version%5D=#{display_version}", :header => {
35
+ :"X-CRASHLYTICS-API-KEY" => @organization_api_key
36
+ }
37
+ parse_or_print_body(res)
38
+ end
39
+
40
+ private
41
+
42
+ def parse_or_print_body(res)
43
+ begin
44
+ JSON.parse(res.body)
45
+ rescue
46
+ raise "\nResponse status: #{res.status}\nResponse body: '#{res.body}'"
47
+ end
48
+ end
49
+
50
+ end
@@ -0,0 +1,32 @@
1
+ class FabricAuthHelper
2
+ require 'httpclient'
3
+
4
+
5
+ def initialize
6
+ @http_client = HTTPClient.new :base_url => "https://api.crashlytics.com"
7
+ end
8
+
9
+ def get_auth_token(login, password)
10
+ require 'json'
11
+
12
+ query = {
13
+ :username => login,
14
+ :password => password,
15
+ :client_id => 'a8f97eb503023b933741db3ff2160fa33204014d162a96d17ca67996fad1414c', # Data from Fabric Mac App
16
+ :client_secret => '9386d1a4ed1c00913d1a2b43bba2961c66a499ce8f9aa67ba73dd232b1357d1a',
17
+ :grant_type => 'password',
18
+ :scope => "organizations apps account beta"
19
+ }
20
+
21
+ res = @http_client.post "/oauth/token", query
22
+ json_response = JSON.parse(res.body)
23
+ if res.status == 200
24
+ json_response["access_token"]
25
+ elsif json_response["error_description"]
26
+ raise "\nError from Fabric: #{json_response["error_description"]}"
27
+ else
28
+ raise "\nInvalid response: \nResponse status: #{res.status}\nResponse body: '#{res.body}'"
29
+ end
30
+ end
31
+
32
+ end
@@ -0,0 +1,5 @@
1
+ module Fastlane
2
+ module FabricBetaUnregisteredDevices
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,176 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fastlane-plugin-fabric_beta_unregistered_devices
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Slava Kornienko
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-02-10 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.115.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.115.0
139
+ description:
140
+ email: slava.kornienko16@gmail.com
141
+ executables: []
142
+ extensions: []
143
+ extra_rdoc_files: []
144
+ files:
145
+ - LICENSE
146
+ - README.md
147
+ - lib/fastlane/plugin/fabric_beta_unregistered_devices.rb
148
+ - lib/fastlane/plugin/fabric_beta_unregistered_devices/actions/fabric_beta_unregistered_devices_action.rb
149
+ - lib/fastlane/plugin/fabric_beta_unregistered_devices/helper/fabric_api_helper.rb
150
+ - lib/fastlane/plugin/fabric_beta_unregistered_devices/helper/fabric_auth_helper.rb
151
+ - lib/fastlane/plugin/fabric_beta_unregistered_devices/version.rb
152
+ homepage: https://github.com/Starmel/Fabric-Beta-unregistered-devices
153
+ licenses:
154
+ - MIT
155
+ metadata: {}
156
+ post_install_message:
157
+ rdoc_options: []
158
+ require_paths:
159
+ - lib
160
+ required_ruby_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ required_rubygems_version: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ requirements: []
171
+ rubyforge_project:
172
+ rubygems_version: 2.7.3
173
+ signing_key:
174
+ specification_version: 4
175
+ summary: SHORT
176
+ test_files: []