fastlane-plugin-saucelabs 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 630500a71605b851cfb589ac405a07224fa59f53c5662b06e99a8e9299636a51
4
+ data.tar.gz: 997c24e1a95370d16a4c92b1a54a39d670fdf0fe356d03181983942883525eec
5
+ SHA512:
6
+ metadata.gz: a5e52b334958665f2350cf226768dc07aa94b42c67a824162ae3e33844ecaa51c062c7890d2e7ebff186f8cc45cc4f5c52a7008b9471d6a8520ac1da698698af
7
+ data.tar.gz: 2587f5419680e6d76ae720dc5b9526ca91bad027720db59b1ff94de69d58895cd48a12b1fc6b83e8361aa2be2efd123478ad450eabbea3df6fc2e7032ee6d401
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 ivan kat <cloudkats@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,67 @@
1
+ # saucelabs plugin
2
+
3
+ [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-saucelabs)
4
+
5
+ ## Getting Started
6
+
7
+ This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-saucelabs`, add it to your project by running:
8
+
9
+ ```bash
10
+ fastlane add_plugin saucelabs
11
+ ```
12
+
13
+ ## About saucelabs
14
+
15
+ Sauce Labs android & ios configuraiton
16
+
17
+ **Note to author:** Add a more detailed description about this plugin here. If your plugin contains multiple actions, make sure to mention them here.
18
+
19
+ ## Example
20
+
21
+ Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plugin. Try it by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane test`.
22
+
23
+ **Note to author:** Please set up a sample project to make it easy for users to explore what your plugin does. Provide everything that is necessary to try out the plugin in this project (including a sample Xcode/Android project if necessary)
24
+
25
+ ## Run tests for this plugin
26
+
27
+ To run both the tests, and code style validation, run
28
+
29
+ ```
30
+ rake
31
+ ```
32
+
33
+ To automatically fix many of the styling issues, use
34
+ ```
35
+ rubocop -a
36
+ ```
37
+
38
+ ## Issues and Feedback
39
+
40
+ For any other issues and feedback about this plugin, please submit it to this repository.
41
+
42
+ ## Troubleshooting
43
+
44
+ If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
45
+
46
+ ## Using _fastlane_ Plugins
47
+
48
+ For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/).
49
+
50
+ ## About _fastlane_
51
+
52
+ _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).
53
+
54
+ ## Resources
55
+
56
+ - [SauceLabs Status page](https://status.saucelabs.com/)
57
+ - [SauceLabs API](https://docs.saucelabs.com/dev/api/index.html)
58
+
59
+ ## TODO
60
+
61
+ - [ ] Support folders
62
+ - [ ] Configure uploaded version
63
+ - [X] Support mulitple regions to upload
64
+ - [ ] Retry logic
65
+ - [ ] Timeout logic
66
+ - [X] Update description
67
+ - [ ] Test key functionality
@@ -0,0 +1,183 @@
1
+ require 'fastlane/action'
2
+ require_relative '../helper/saucelabs_helper'
3
+
4
+ module Fastlane
5
+ module Actions
6
+
7
+ module SharedValues
8
+ SAUCE_USERNAME = :SAUCE_USERNAME
9
+ SAUCE_ACCESS_KEY = :SAUCE_ACCESS_KEY
10
+ SAUCE_REGION = :SAUCE_REGION
11
+ SAUCE_ITEM_NAME = :SAUCE_ITEM_NAME
12
+ SAUCE_ITEM_KIND = :SAUCE_ITEM_KIND
13
+ SAUCE_ITEM_ID = :SAUCE_ITEM_ID
14
+ SAUCE_ITEM_SIZE = :SAUCE_ITEM_SIZE
15
+ SAUCE_ITEM_REGION = :SAUCE_ITEM_REGION
16
+ end
17
+
18
+ class SaucelabsUploadAction < Action
19
+ #noinspection RubyResolve
20
+ def self.run(params)
21
+ UI.message("The saucelabs plugin is working!")
22
+ file = params[:file]
23
+ region = params[:region]
24
+ username = params[:user_name]
25
+ apikey = params[:api_key]
26
+ app_name = params[:app_name]
27
+ app_description = params[:app_description]
28
+
29
+ if file.to_s.length == 0
30
+ UI.user_error!("Couldn't find build file at path #{file}` ❌")
31
+ end
32
+
33
+ upload(payload: file,
34
+ app_name: app_name,
35
+ app_description: app_description,
36
+ user_name: username,
37
+ api_key: apikey,
38
+ region: region)
39
+ end
40
+
41
+ def self.upload(payload:, app_name:, app_description:, user_name:, api_key:, region:)
42
+ UI.message("Starting \"#{app_name}\" upload to Sauce Labs...")
43
+
44
+ begin
45
+ result = Helper::SaucelabsHelper.upload(
46
+ payload: payload,
47
+ app_name: app_name,
48
+ app_description: app_description,
49
+ user_name: user_name,
50
+ api_key: api_key,
51
+ region: region)
52
+
53
+ if result and result.is_a?(Hash)
54
+ Actions.lane_context[SharedValues::SAUCE_ITEM_NAME] = result[:name] if result.has_key?(:name)
55
+ Actions.lane_context[SharedValues::SAUCE_ITEM_KIND] = result[:kind] if result.has_key?(:kind)
56
+ Actions.lane_context[SharedValues::SAUCE_ITEM_ID] = result[:id] if result.has_key?(:id)
57
+ Actions.lane_context[SharedValues::SAUCE_ITEM_SIZE] = result[:size] if result.has_key?(:size)
58
+ Actions.lane_context[SharedValues::SAUCE_ITEM_REGION] = result[:region] if result.has_key?(:region)
59
+ end
60
+ UI.message("Upload \"#{app_name}\" ✅")
61
+ rescue => exception
62
+ UI.user_error!("Failed to upload ❌. #{exception.to_s}")
63
+ end
64
+ end
65
+
66
+ def self.description
67
+ "Sauce labs android & ios Fastlane plugin"
68
+ end
69
+
70
+ def self.authors
71
+ ["@CloudKats https://github.com/cloudkats"]
72
+ end
73
+
74
+ def self.return_value
75
+ # If your method provides a return value, you can describe here what it does
76
+ end
77
+
78
+ def self.details
79
+ # Optional:
80
+ "Upload ios&android artifacts to Sauce Labs https://docs.saucelabs.com/"
81
+ end
82
+
83
+ def self.available_options
84
+ [
85
+ FastlaneCore::ConfigItem.new(key: :file,
86
+ env_name: "",
87
+ description: "zip file for the upload",
88
+ optional: false,
89
+ type: String,
90
+ verify_block: proc do |value|
91
+ if value
92
+ UI.user_error!("Could not find file to upload \"#{file}\" ") unless File.exist?(value) || Helper.test?
93
+ accepted_formats = %w(.api .ipa)
94
+ file_ext = Helper::SaucelabsHelper.file_extname(accepted_formats, value)
95
+ # UI.user_error!("Extension not supported for \"#{file}\" ") unless accepted_formats.include? file_ext
96
+ end
97
+ end),
98
+ FastlaneCore::ConfigItem.new(key: :app_name,
99
+ env_name: "SAUCE_APP_NAME",
100
+ description: "App name as found in the App's URL in Sauce Labs",
101
+ default_value: Actions.lane_context[SharedValues::SAUCE_ITEM_NAME],
102
+ optional: false,
103
+ type: String,
104
+ verify_block: proc do |value|
105
+ UI.user_error!("No App name given, pass using `app_name: 'app name'`") unless value && !value.empty?
106
+ end),
107
+ FastlaneCore::ConfigItem.new(key: :app_description,
108
+ description: "App description as it found in \"item.description\" Sauce Labs",
109
+ optional: true,
110
+ type: String),
111
+ FastlaneCore::ConfigItem.new(key: :user_name,
112
+ env_name: "SAUCE_USERNAME",
113
+ description: "The Sauce Labs API uses basic auth username to authenticate requests",
114
+ default_value: Actions.lane_context[SharedValues::SAUCE_USERNAME],
115
+ optional: false,
116
+ type: String,
117
+ verify_block: proc do |value|
118
+ UI.user_error!("No API username given, pass using `username: 'sauce user name'`") unless value && !value.empty?
119
+ end),
120
+ FastlaneCore::ConfigItem.new(key: :api_key,
121
+ env_name: "SAUCE_ACCESS_KEY",
122
+ description: "The Sauce Labs API uses API keys to authenticate requests",
123
+ default_value: Actions.lane_context[SharedValues::SAUCE_ACCESS_KEY],
124
+ optional: false,
125
+ type: String,
126
+ verify_block: proc do |value|
127
+ UI.user_error!("No API key given, pass using `apikey: 'sauce access key'`") unless value && !value.empty?
128
+ end),
129
+ FastlaneCore::ConfigItem.new(key: :region,
130
+ env_name: "SAUCE_REGION",
131
+ description: "Api endpoint region e.g. 'us', 'us-west-1', 'eu' or 'eu-central-1' ",
132
+ default_value: Actions.lane_context[SharedValues::SAUCE_REGION],
133
+ optional: false,
134
+ type: String,
135
+ verify_block: proc do |value|
136
+ accepted_formats = %w[us us-west-1 eu-central-1 eu]
137
+ UI.user_error!("Only \"us\", \"eu\", \"us-west-1\" and \"eu-central-1\", types are allowed, you provided \"#{value}\"") unless accepted_formats.include? value || Helper.test?
138
+ end)
139
+ ]
140
+ end
141
+
142
+ def self.output
143
+ [
144
+ ['SAUCE_USERNAME', 'Contains API user name'],
145
+ ['SAUCE_REGION', 'Contains API region'],
146
+ ['SAUCE_ITEM_NAME', 'Contains item name'],
147
+ ['SAUCE_ITEM_SIZE', 'Contains item size'],
148
+ ['SAUCE_ITEM_ID', 'Contains item id in uuid format'],
149
+ ['SAUCE_ITEM_KIND', 'Contains item kind e.g., android or ios'],
150
+ ['SAUCE_ITEM_REGION', 'Contains region where item is uploaded']
151
+ ]
152
+ end
153
+
154
+ def self.example_code
155
+ [
156
+ 'saucelabs_upload(
157
+ user_name: "user name",
158
+ api_key: "api key",
159
+ app_name: "Android.artifact.apk",
160
+ file: "app/build/outputs/apk/debug/app-debug.apk",
161
+ region: "eu"
162
+ )',
163
+ 'saucelabs_upload(
164
+ user_name: "user name",
165
+ api_key: "api key",
166
+ app_name: "iOS.artifact.ipa",
167
+ file: "app.ipa",
168
+ description
169
+ region: "us-west-1"
170
+ )'
171
+ ]
172
+ end
173
+
174
+ def self.is_supported?(platform)
175
+ # Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
176
+ # See: https://docs.fastlane.tools/advanced/#control-configuration-by-lane-and-by-platform
177
+ #
178
+ # [:ios, :mac, :android].include?(platform)
179
+ true
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,115 @@
1
+ require "uri"
2
+ require "net/http"
3
+ #TODO: test all the methods
4
+
5
+ class SauceHttp
6
+ def initialize(ui, username, apikey, region)
7
+ @UI = ui
8
+ encoded_auth = Base64::strict_encode64(username + ":" + apikey)
9
+ @basic_auth_key = "Basic #{encoded_auth}"
10
+ endpoints = {
11
+ 'us' => "https://api.us-west-1.saucelabs.com",
12
+ 'us-west-1' => "https://api.us-west-1.saucelabs.com",
13
+ 'eu' => "https://api.eu-central-1.saucelabs.com",
14
+ 'eu-central-1' => "https://api.eu-central-1.saucelabs.com"
15
+ }
16
+ @region = case region
17
+ when 'eu' then "eu-central-1"
18
+ when 'us' then "us-west-1"
19
+ else region
20
+ end
21
+ @endpoint = endpoints[region]
22
+ @UI.message("DEBUG: BASE URL #{@endpoint}") if ENV['DEBUG']
23
+ end
24
+
25
+ def is_access_authorized(resource_path = 'team-management/v1/teams/')
26
+ @UI.message("DEBUG: GET(authorization) #{@endpoint}/#{resource_path}") if ENV['DEBUG']
27
+ https, url = request_prepare(resource_path)
28
+ request = Net::HTTP::Get.new(url)
29
+ request["Authorization"] = @basic_auth_key
30
+ response = https.request(request)
31
+ response.kind_of?(Net::HTTPOK)
32
+ unless response.kind_of?(Net::HTTPOK)
33
+ raise "Auth Error, provided invalid username or token"
34
+ end
35
+ end
36
+
37
+ def is_available(resource_path = 'rest/v1/info/status')
38
+ @UI.message("DEBUG: GET(platform status) #{@endpoint}/#{resource_path}") if ENV['DEBUG']
39
+ https, url = request_prepare(resource_path)
40
+ request = Net::HTTP::Get.new(url)
41
+ response = https.request(request)
42
+ body = JSON.parse(response.body)
43
+ unless response.kind_of?(Net::HTTPOK) && body['service_operational']
44
+ raise "Service #{@endpoint}/#{resource_path} is not operational. #{body['status_message']}"
45
+ end
46
+ end
47
+
48
+ def upload(app_name, app_description, payload, size, resource_path = 'v1/storage/upload')
49
+ @UI.message("DEBUG: POST(artifact upload) #{@endpoint}/#{resource_path}") if ENV['DEBUG']
50
+
51
+ https, url = request_prepare(resource_path)
52
+ request = Net::HTTP::Post.new(url)
53
+ request["Authorization"] = @basic_auth_key
54
+ request['Content-Length'] = size
55
+ request['Accept'] = '*/*'
56
+ form_data = [['payload', payload], ['name', app_name]]
57
+ request.set_form form_data, "multipart/form-data"
58
+ response = https.request(request)
59
+ body = JSON.parse(response.body)
60
+
61
+ case response.code.to_i
62
+ when 406
63
+ raise "#{body['title']}. #{body['detail']}"
64
+ end
65
+
66
+ item = body['item']
67
+ if app_description and !app_description.to_s.strip.empty?
68
+ update_description(item['id'], app_description)
69
+ end
70
+
71
+ {
72
+ id: item['id'],
73
+ kind: item['kind'],
74
+ name: item['name'],
75
+ size: size,
76
+ region: @region
77
+ }
78
+ end
79
+
80
+ def update_description(id, app_description)
81
+ resource_path = "v1/storage/files/#{id}"
82
+ @UI.message("DEBUG: PUT(artifact update) #{@endpoint}/#{resource_path}/#{id}") if ENV['DEBUG']
83
+ @UI.message("DEBUG: PUT(artifact update) app description #{app_description}") if ENV['DEBUG']
84
+
85
+ https, url = request_prepare(resource_path)
86
+ request = Net::HTTP::Put.new(url)
87
+ request["Authorization"] = @basic_auth_key
88
+ request["Content-Type"] = "application/json"
89
+ request.body = JSON.dump({
90
+ "item": {
91
+ "description": app_description
92
+ }
93
+ })
94
+
95
+ response = https.request(request)
96
+
97
+ unless response.kind_of?(Net::HTTPOK)
98
+ body = JSON.parse(response.body)
99
+ case response.code.to_i
100
+ when 404
101
+ raise "#{body['title']}. #{body['detail']}"
102
+ end
103
+ raise "Unhandled exception. #{body}"
104
+ end
105
+ end
106
+
107
+ private
108
+
109
+ def request_prepare(resource_path)
110
+ url = URI("#{@endpoint}/#{resource_path}")
111
+ https = Net::HTTP.new(url.host, url.port)
112
+ https.use_ssl = true
113
+ [https, url]
114
+ end
115
+ end
@@ -0,0 +1,37 @@
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 SaucelabsHelper
8
+ # class methods that you define here become available in your action
9
+ # as `Helper::SaucelabsHelper.your_method`
10
+ #
11
+ def self.show_message
12
+ UI.message("Hello from the saucelabs plugin helper!")
13
+ end
14
+
15
+ # basic utility method to upload a file and set a description,
16
+ def self.upload(payload:, app_name:, app_description:, user_name:, api_key:, region:)
17
+ http = SauceHttp.new(UI, user_name, api_key, region)
18
+ begin
19
+ # http.is_available
20
+ http.is_access_authorized
21
+ size = File.size(payload).to_s
22
+ payload_data = File.open(payload, "rb")
23
+ return http.upload(app_name, app_description, payload_data, size)
24
+ rescue => exception
25
+ raise exception.to_s
26
+ end
27
+ end
28
+
29
+ # basic utility method to check file types that Sauce Labs will accept,
30
+ def self.file_extname(formats, path)
31
+ formats.each do |suffix|
32
+ return suffix if path.to_s.downcase.end_with? suffix.downcase
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,5 @@
1
+ module Fastlane
2
+ module Saucelabs
3
+ VERSION = File.read("version").strip
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ require 'fastlane/plugin/saucelabs/version'
2
+
3
+ module Fastlane
4
+ module Saucelabs
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::Saucelabs.all_classes.each do |current|
15
+ require current
16
+ end
metadata ADDED
@@ -0,0 +1,189 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fastlane-plugin-saucelabs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ platform: ruby
6
+ authors:
7
+ - ivan kat
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-09-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
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: fastlane
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.194.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 2.194.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
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: rake
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: rspec
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: rspec_junit_formatter
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '='
102
+ - !ruby/object:Gem::Version
103
+ version: 1.12.1
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
109
+ - !ruby/object:Gem::Version
110
+ version: 1.12.1
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-performance
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: rubocop-require_tools
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: simplecov
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description:
154
+ email: cloudkats@gmail.com
155
+ executables: []
156
+ extensions: []
157
+ extra_rdoc_files: []
158
+ files:
159
+ - LICENSE
160
+ - README.md
161
+ - lib/fastlane/plugin/saucelabs.rb
162
+ - lib/fastlane/plugin/saucelabs/actions/saucelabs_upload_action.rb
163
+ - lib/fastlane/plugin/saucelabs/helper/file_upload.rb
164
+ - lib/fastlane/plugin/saucelabs/helper/saucelabs_helper.rb
165
+ - lib/fastlane/plugin/saucelabs/version.rb
166
+ homepage: https://github.com/cloudkats/fastlane-plugin-saucelabs
167
+ licenses:
168
+ - MIT
169
+ metadata: {}
170
+ post_install_message:
171
+ rdoc_options: []
172
+ require_paths:
173
+ - lib
174
+ required_ruby_version: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ version: '2.5'
179
+ required_rubygems_version: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - ">="
182
+ - !ruby/object:Gem::Version
183
+ version: '0'
184
+ requirements: []
185
+ rubygems_version: 3.1.2
186
+ signing_key:
187
+ specification_version: 4
188
+ summary: Sauce Labs android & ios configuraiton
189
+ test_files: []