fastlane 2.11.0 → 2.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/fastlane/lib/fastlane/actions/opt_out_usage.rb +6 -6
- data/fastlane/lib/fastlane/documentation/docs_generator.rb +2 -2
- data/fastlane/lib/fastlane/fastlane_require.rb +8 -1
- data/fastlane/lib/fastlane/version.rb +1 -1
- data/fastlane_core/lib/fastlane_core/ui/fastlane_runner.rb +3 -2
- data/fastlane_core/lib/fastlane_core/ui/github_issue_inspector_reporter.rb +1 -3
- data/fastlane_core/lib/fastlane_core/update_checker/update_checker.rb +1 -1
- data/pilot/lib/pilot/commands_generator.rb +4 -3
- data/pilot/lib/pilot/tester_manager.rb +2 -6
- data/scan/lib/scan/detect_values.rb +15 -0
- data/scan/lib/scan/options.rb +21 -0
- data/scan/lib/scan/slack_poster.rb +3 -0
- data/scan/lib/scan/test_command_generator.rb +5 -0
- data/screengrab/lib/screengrab/runner.rb +6 -8
- data/snapshot/README.md +1 -1
- data/snapshot/lib/snapshot/fixes/README.md +1 -1
- data/snapshot/lib/snapshot/reports_generator.rb +1 -0
- data/spaceship/lib/spaceship/client.rb +52 -0
- data/spaceship/lib/spaceship/spaceauth_runner.rb +6 -1
- data/spaceship/lib/spaceship/tunes/app_version.rb +6 -0
- data/spaceship/lib/spaceship/tunes/tester.rb +1 -1
- data/spaceship/lib/spaceship/tunes/tunes_client.rb +100 -21
- metadata +3 -14
- data/fastlane/lib/.DS_Store +0 -0
- data/fastlane/lib/assets/.DS_Store +0 -0
- data/fastlane/lib/assets/completions/.DS_Store +0 -0
- data/fastlane/lib/fastlane/.DS_Store +0 -0
- data/fastlane/lib/fastlane/actions/.DS_Store +0 -0
- data/fastlane/lib/fastlane/actions/device_grid/.DS_Store +0 -0
- data/fastlane_core/lib/.DS_Store +0 -0
- data/fastlane_core/lib/fastlane_core/.DS_Store +0 -0
- data/snapshot/lib/.DS_Store +0 -0
- data/spaceship/lib/.DS_Store +0 -0
- data/spaceship/lib/spaceship/.DS_Store +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b1b63ff2fa7ae1f6bb83ee77cdd83530f36a7be
|
4
|
+
data.tar.gz: 4a03adb249cc48ad1eb0ce05a0857162d03ea8fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58cdcf0f0b64a3b56de09792a95b686fdcc4c9d6caa45cc16af7462de6f0f0f7605fe3323389c0ae6b97b87e6caa48d7dc57fcb9734c940e1dbc96a2c29b5e1b
|
7
|
+
data.tar.gz: d32509f435ad25c115a469686ee4a7faace5bbaa4313180f12d5908d2aa6185390b66522ce0330ba1abae9c0394d2722aaa77fa88eb931707600ab4bf015880e
|
@@ -12,11 +12,11 @@ module Fastlane
|
|
12
12
|
|
13
13
|
def self.details
|
14
14
|
[
|
15
|
-
"By default, fastlane will
|
16
|
-
"No personal information is
|
17
|
-
"https://github.com/fastlane/enhancer
|
18
|
-
"
|
19
|
-
].join('')
|
15
|
+
"By default, fastlane will track what actions are being used",
|
16
|
+
"No personal information is shared. More information available on",
|
17
|
+
"https://github.com/fastlane/enhancer",
|
18
|
+
"Add `opt_out_usage` at the top of your Fastfile"
|
19
|
+
].join(' ')
|
20
20
|
end
|
21
21
|
|
22
22
|
def self.author
|
@@ -29,7 +29,7 @@ module Fastlane
|
|
29
29
|
|
30
30
|
def self.example_code
|
31
31
|
[
|
32
|
-
'opt_out_usage'
|
32
|
+
'opt_out_usage # add this to the top of your Fastfile'
|
33
33
|
]
|
34
34
|
end
|
35
35
|
|
@@ -36,8 +36,8 @@ module Fastlane
|
|
36
36
|
end
|
37
37
|
|
38
38
|
output << "This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run."
|
39
|
-
output << "More information about fastlane can be found on [
|
40
|
-
output << "The documentation of fastlane can be found on [
|
39
|
+
output << "More information about fastlane can be found on [fastlane.tools](https://fastlane.tools)."
|
40
|
+
output << "The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools)."
|
41
41
|
output << ""
|
42
42
|
|
43
43
|
File.write(output_path, output.join("\n"))
|
@@ -2,7 +2,7 @@ module Fastlane
|
|
2
2
|
class FastlaneRequire
|
3
3
|
class << self
|
4
4
|
def install_gem_if_needed(gem_name: nil, require_gem: true)
|
5
|
-
gem_require_name = gem_name
|
5
|
+
gem_require_name = format_gem_require_name(gem_name)
|
6
6
|
|
7
7
|
# check if it's installed
|
8
8
|
if gem_installed?(gem_name)
|
@@ -62,6 +62,13 @@ module Fastlane
|
|
62
62
|
|
63
63
|
return gems.first
|
64
64
|
end
|
65
|
+
|
66
|
+
def format_gem_require_name(gem_name)
|
67
|
+
# from "fastlane-plugin-xcversion" to "fastlane/plugin/xcversion"
|
68
|
+
gem_name = gem_name.tr("-", "/") if gem_name.start_with? "fastlane-plugin-"
|
69
|
+
|
70
|
+
return gem_name
|
71
|
+
end
|
65
72
|
end
|
66
73
|
end
|
67
74
|
end
|
@@ -140,16 +140,17 @@ module Commander
|
|
140
140
|
# use a bit of Ruby duck-typing to check whether the unknown exception type implements the right
|
141
141
|
# method. If so, we'll present any returned error info in the manner of a user_error!
|
142
142
|
error_info = e.respond_to?(:preferred_error_info) ? e.preferred_error_info : nil
|
143
|
+
should_show_github_issues = e.respond_to?(:show_github_issues) ? e.show_github_issues : true
|
143
144
|
|
144
145
|
if error_info
|
145
146
|
error_info = error_info.join("\n\t") if error_info.kind_of?(Array)
|
146
147
|
|
147
|
-
show_github_issues(error_info)
|
148
|
+
show_github_issues(error_info) if should_show_github_issues
|
148
149
|
|
149
150
|
display_user_error!(e, error_info)
|
150
151
|
else
|
151
152
|
# Pass the error instead of a message so that the inspector can do extra work to simplify the query
|
152
|
-
show_github_issues(e)
|
153
|
+
show_github_issues(e) if should_show_github_issues
|
153
154
|
|
154
155
|
# From https://stackoverflow.com/a/4789702/445598
|
155
156
|
# We do this to make the actual error message red and therefore more visible
|
@@ -29,7 +29,6 @@ module Fastlane
|
|
29
29
|
puts "Found no similar issues. To create a new issue, please visit:"
|
30
30
|
puts "https://github.com/#{inspector.repo_owner}/#{inspector.repo_name}/issues/new"
|
31
31
|
puts "Run `fastlane env` to append the fastlane environment to your issue"
|
32
|
-
print_open_link_hint(true)
|
33
32
|
end
|
34
33
|
|
35
34
|
# Called when there have been networking issues in creating the report.
|
@@ -37,7 +36,6 @@ module Fastlane
|
|
37
36
|
puts "Could not access the GitHub API, you may have better luck via the website."
|
38
37
|
puts "https://github.com/#{inspector.repo_owner}/#{inspector.repo_name}/search?q=#{query}&type=Issues&utf8=✓"
|
39
38
|
puts "Error: #{error.name}"
|
40
|
-
print_open_link_hint(true)
|
41
39
|
end
|
42
40
|
|
43
41
|
private
|
@@ -54,7 +52,7 @@ module Fastlane
|
|
54
52
|
|
55
53
|
def print_open_link_hint(newline = false)
|
56
54
|
puts "" if newline
|
57
|
-
puts "🔗
|
55
|
+
puts "🔗 You can ⌘ + double-click on links to open them directly in your browser." if Helper.mac?
|
58
56
|
end
|
59
57
|
end
|
60
58
|
end
|
@@ -79,7 +79,7 @@ module FastlaneCore
|
|
79
79
|
def self.update_command(gem_name: "fastlane")
|
80
80
|
if Helper.bundler?
|
81
81
|
"bundle update #{gem_name.downcase}"
|
82
|
-
elsif Helper.contained_fastlane?
|
82
|
+
elsif Helper.contained_fastlane? || Helper.homebrew?
|
83
83
|
"fastlane update_fastlane"
|
84
84
|
else
|
85
85
|
"sudo gem update #{gem_name.downcase}"
|
@@ -31,11 +31,12 @@ module Pilot
|
|
31
31
|
begin
|
32
32
|
mgr.public_send(action, config)
|
33
33
|
rescue => ex
|
34
|
-
|
35
|
-
|
34
|
+
message = "[#{address}]: #{ex}"
|
35
|
+
failures << message
|
36
|
+
UI.error(message)
|
36
37
|
end
|
37
38
|
end
|
38
|
-
UI.user_error!("Some operations failed: #{failures}") unless failures.empty?
|
39
|
+
UI.user_error!("Some operations failed: #{failures.join(', ')}") unless failures.empty?
|
39
40
|
end
|
40
41
|
|
41
42
|
def run
|
@@ -118,12 +118,8 @@ module Pilot
|
|
118
118
|
begin
|
119
119
|
int_testers = Spaceship::Tunes::Tester::Internal.all
|
120
120
|
ext_testers = Spaceship::Tunes::Tester::External.all
|
121
|
-
rescue
|
122
|
-
|
123
|
-
UI.user_error!("You don't have the permission to list the testers of your whole team. Please provide an app identifier to list all testers of a specific application.")
|
124
|
-
else
|
125
|
-
raise ex
|
126
|
-
end
|
121
|
+
rescue Spaceship::Client::InsufficientPermissions
|
122
|
+
UI.user_error!("You don't have the permission to list the testers of your whole team. Please provide an app identifier to list all testers of a specific application.")
|
127
123
|
end
|
128
124
|
|
129
125
|
list_global(int_testers, "Internal Testers")
|
@@ -36,9 +36,24 @@ module Scan
|
|
36
36
|
|
37
37
|
default_derived_data
|
38
38
|
|
39
|
+
coerce_to_array_of_strings(:only_testing)
|
40
|
+
coerce_to_array_of_strings(:skip_testing)
|
41
|
+
|
39
42
|
return config
|
40
43
|
end
|
41
44
|
|
45
|
+
def self.coerce_to_array_of_strings(config_key)
|
46
|
+
config_value = Scan.config[config_key]
|
47
|
+
|
48
|
+
return if config_value.nil?
|
49
|
+
|
50
|
+
# splitting on comma allows us to support comma-separated lists of values
|
51
|
+
# from the command line, even though the ConfigItem is not defined as an
|
52
|
+
# Array type
|
53
|
+
config_value = config_value.split(',') unless config_value.kind_of?(Array)
|
54
|
+
Scan.config[config_key] = config_value.map(&:to_s)
|
55
|
+
end
|
56
|
+
|
42
57
|
def self.default_derived_data
|
43
58
|
return unless Scan.config[:derived_data_path].to_s.empty?
|
44
59
|
default_path = Scan.project.build_settings(key: "BUILT_PRODUCTS_DIR")
|
data/scan/lib/scan/options.rb
CHANGED
@@ -3,6 +3,11 @@ require "credentials_manager"
|
|
3
3
|
|
4
4
|
module Scan
|
5
5
|
class Options
|
6
|
+
def self.verify_type(item_name, acceptable_types, value)
|
7
|
+
type_ok = [Array, String].any? { |type| value.kind_of?(type) }
|
8
|
+
UI.user_error!("'#{item_name}' should be of type #{acceptable_types.join(' or ')} but found: #{value.class.name}") unless type_ok
|
9
|
+
end
|
10
|
+
|
6
11
|
def self.available_options
|
7
12
|
containing = Helper.fastlane_enabled? ? './fastlane' : '.'
|
8
13
|
|
@@ -166,6 +171,22 @@ module Scan
|
|
166
171
|
verify_block: proc do |value|
|
167
172
|
UI.user_error!("File not found at path '#{File.expand_path(value)}'") unless File.exist?(value)
|
168
173
|
end),
|
174
|
+
FastlaneCore::ConfigItem.new(key: :only_testing,
|
175
|
+
env_name: "SCAN_ONLY_TESTING",
|
176
|
+
description: "Array of strings matching Test Bundle/Test Suite/Test Cases to run",
|
177
|
+
optional: true,
|
178
|
+
is_string: false,
|
179
|
+
verify_block: proc do |value|
|
180
|
+
verify_type('only_testing', [Array, String], value)
|
181
|
+
end),
|
182
|
+
FastlaneCore::ConfigItem.new(key: :skip_testing,
|
183
|
+
env_name: "SCAN_SKIP_TESTING",
|
184
|
+
description: "Array of strings matching Test Bundle/Test Suite/Test Cases to skip",
|
185
|
+
optional: true,
|
186
|
+
is_string: false,
|
187
|
+
verify_block: proc do |value|
|
188
|
+
verify_type('skip_testing', [Array, String], value)
|
189
|
+
end),
|
169
190
|
FastlaneCore::ConfigItem.new(key: :slack_url,
|
170
191
|
short_option: "-i",
|
171
192
|
env_name: "SLACK_URL",
|
@@ -51,7 +51,10 @@ module Scan
|
|
51
51
|
|
52
52
|
if result.code.to_i == 200
|
53
53
|
UI.success('Successfully sent Slack notification')
|
54
|
+
elsif result.code.to_i == 404
|
55
|
+
UI.error("The Slack URL you provided could not be reached (404)")
|
54
56
|
else
|
57
|
+
UI.error("The Slack notification could not be sent:")
|
55
58
|
UI.error(result.to_s)
|
56
59
|
end
|
57
60
|
end
|
@@ -41,6 +41,11 @@ module Scan
|
|
41
41
|
options << "-xcconfig '#{config[:xcconfig]}'" if config[:xcconfig]
|
42
42
|
options << config[:xcargs] if config[:xcargs]
|
43
43
|
|
44
|
+
# detect_values will ensure that these values are present as Arrays if
|
45
|
+
# they are present at all
|
46
|
+
options += config[:only_testing].map { |test_id| "-only-testing:#{test_id}" } if config[:only_testing]
|
47
|
+
options += config[:skip_testing].map { |test_id| "-skip-testing:#{test_id}" } if config[:skip_testing]
|
48
|
+
|
44
49
|
options
|
45
50
|
end
|
46
51
|
|
@@ -187,16 +187,14 @@ module Screengrab
|
|
187
187
|
|
188
188
|
def uninstall_apks(device_serial, app_package_name, tests_package_name)
|
189
189
|
UI.message 'Uninstalling app APK'
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
UI.user_error! "App APK could not be uninstalled" if apk_uninstall_output.include?("Failure [")
|
190
|
+
run_adb_command("adb -s #{device_serial} uninstall #{app_package_name}",
|
191
|
+
print_all: true,
|
192
|
+
print_command: true)
|
194
193
|
|
195
194
|
UI.message 'Uninstalling tests APK'
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
UI.user_error! "Tests APK could not be uninstalled" if apk_uninstall_output.include?("Failure [")
|
195
|
+
run_adb_command("adb -s #{device_serial} uninstall #{tests_package_name}",
|
196
|
+
print_all: true,
|
197
|
+
print_command: true)
|
200
198
|
end
|
201
199
|
|
202
200
|
def grant_permissions(device_serial)
|
data/snapshot/README.md
CHANGED
@@ -334,7 +334,7 @@ _snapshot_ finds all these entries using a regex. The number of _snapshot_ outpu
|
|
334
334
|
|
335
335
|
If you find a better way to do any of this, please submit an issue on GitHub or even a pull request :+1:
|
336
336
|
|
337
|
-
|
337
|
+
Radar [23062925](https://openradar.appspot.com/radar?id=5056366381105152) has been resolved with Xcode 8.3, so it's now possible to actually take screenshots from the simulator. We'll keep using the old approach for now, since many of you still want to use older versions of Xcode.
|
338
338
|
|
339
339
|
# Tips
|
340
340
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
### Fixes
|
2
2
|
|
3
3
|
This directory contains all the files we don't actually want to have, but are necessary due to open radars, e.g.
|
4
|
-
|
4
|
+
|
5
5
|
- [rdar://23323159](https://openradar.appspot.com/radar?id=6127019184095232): Screenshots are broken when simulator is not scaled at 100%
|
@@ -53,6 +53,7 @@ module Snapshot
|
|
53
53
|
'iPhone6' => "iPhone6 (4.7-Inch)",
|
54
54
|
'iPhone5' => "iPhone5 (4-Inch)",
|
55
55
|
'iPhone4' => "iPhone4 (3.5-Inch)",
|
56
|
+
'iPhone SE' => "iPhone SE",
|
56
57
|
'iPad2' => "iPad2",
|
57
58
|
'iPadAir2' => 'iPad Air 2',
|
58
59
|
'iPadPro(12.9-inch)' => 'iPad Air Pro (12.9 inch)',
|
@@ -50,6 +50,21 @@ module Spaceship
|
|
50
50
|
# Raised when no user credentials were passed at all
|
51
51
|
class NoUserCredentialsError < BasicPreferredInfoError; end
|
52
52
|
|
53
|
+
# User doesn't have enough permission for given action
|
54
|
+
class InsufficientPermissions < BasicPreferredInfoError
|
55
|
+
TITLE = 'Insufficient permissions for your Apple ID:'.freeze
|
56
|
+
|
57
|
+
def preferred_error_info
|
58
|
+
message ? [TITLE, message] : nil
|
59
|
+
end
|
60
|
+
|
61
|
+
# We don't want to show similar GitHub issues, as the error message
|
62
|
+
# should be pretty clear
|
63
|
+
def show_github_issues
|
64
|
+
false
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
53
68
|
class UnexpectedResponse < StandardError
|
54
69
|
attr_reader :error_info
|
55
70
|
|
@@ -426,13 +441,50 @@ module Spaceship
|
|
426
441
|
end
|
427
442
|
|
428
443
|
if content.nil?
|
444
|
+
# Check if the failure is due to missing permissions (iTunes Connect)
|
445
|
+
if response.body && response.body["messages"] && response.body["messages"]["error"].include?("Forbidden")
|
446
|
+
raise_insuffient_permission_error!
|
447
|
+
end
|
448
|
+
|
429
449
|
raise UnexpectedResponse, response.body
|
450
|
+
elsif content.kind_of?(Hash) && (content["resultString"] || "").include?("NotAllowed")
|
451
|
+
# example content when doing a Developer Portal action with not enough permission
|
452
|
+
# => {"responseId"=>"e5013d83-c5cb-4ba0-bb62-734a8d56007f",
|
453
|
+
# "resultCode"=>1200,
|
454
|
+
# "resultString"=>"webservice.certificate.downloadNotAllowed",
|
455
|
+
# "userString"=>"You are not permitted to download this certificate.",
|
456
|
+
# "creationTimestamp"=>"2017-01-26T22:44:13Z",
|
457
|
+
# "protocolVersion"=>"QH65B2",
|
458
|
+
# "userLocale"=>"en_US",
|
459
|
+
# "requestUrl"=>"https://developer.apple.com/services-account/QH65B2/account/ios/certificate/downloadCertificateContent.action",
|
460
|
+
# "httpCode"=>200}
|
461
|
+
raise_insuffient_permission_error!(additional_error_string: content["userString"])
|
430
462
|
else
|
431
463
|
store_csrf_tokens(response)
|
432
464
|
content
|
433
465
|
end
|
434
466
|
end
|
435
467
|
|
468
|
+
# This also gets called from subclasses
|
469
|
+
def raise_insuffient_permission_error!(additional_error_string: nil)
|
470
|
+
# get the method name of the request that failed
|
471
|
+
# `block in` is used very often for requests when surrounded for paging or retrying blocks
|
472
|
+
# The ! is part of some methods when they modify or delete a resource, so we don't want to show it
|
473
|
+
# Using `sub` instead of `delete` as we don't want to allow multiple matches
|
474
|
+
calling_method_name = caller_locations(2, 2).first.label.sub("block in", "").delete("!").strip
|
475
|
+
begin
|
476
|
+
team_id = "(Team ID #{self.team_id}) "
|
477
|
+
rescue
|
478
|
+
# Showing the team ID is something that's nice to have, however it might cause an exception
|
479
|
+
# when the user doesn't have any permission at all (e.g. failing at login)
|
480
|
+
# we still want the error message to show the actual string, but without the team_id in that case
|
481
|
+
team_id = ""
|
482
|
+
end
|
483
|
+
error_message = "User #{self.user} #{team_id}doesn't have enough permission for the following action: #{calling_method_name}"
|
484
|
+
error_message += " (#{additional_error_string})" if additional_error_string.to_s.length > 0
|
485
|
+
raise InsufficientPermissions, error_message
|
486
|
+
end
|
487
|
+
|
436
488
|
private
|
437
489
|
|
438
490
|
def directory_accessible?(path)
|
@@ -33,7 +33,12 @@ module Spaceship
|
|
33
33
|
# Example:
|
34
34
|
# name: DES5c148586daa451e55afb017aa62418f91
|
35
35
|
# value: HSARMTKNSRVTWFlaF/ek8asaa9lymMA0dN8JQ6pY7B3F5kdqTxJvMT19EVEFX8EQudB/uNwBHOHzaa30KYTU/eCP/UF7vGTgxs6PAnlVWKscWssOVHfP2IKWUPaa4Dn+I6ilA7eAFQsiaaVT
|
36
|
-
cookies = YAML.safe_load(
|
36
|
+
cookies = YAML.safe_load(
|
37
|
+
itc_cookie_content,
|
38
|
+
[HTTP::Cookie, Time], # classes whitelist
|
39
|
+
[], # symbols whitelist
|
40
|
+
true # allow YAML aliases
|
41
|
+
)
|
37
42
|
|
38
43
|
# We remove all the un-needed cookies
|
39
44
|
cookies.select! do |cookie|
|
@@ -45,6 +45,11 @@ module Spaceship
|
|
45
45
|
# @return (Bool) Should the app automatically be released once it's approved?
|
46
46
|
attr_accessor :release_on_approval
|
47
47
|
|
48
|
+
# @return (Fixnum) Milliseconds for releasing in GMT (e.g. 1480435200000 = Tue, 29 Nov 2016 16:00:00 GMT).
|
49
|
+
# Use nil to unset. Setting this will supercede the release_on_approval field, so this field must be nil
|
50
|
+
# for release_on_approval to be used.
|
51
|
+
attr_accessor :auto_release_date
|
52
|
+
|
48
53
|
# @return (Bool)
|
49
54
|
attr_accessor :can_beta_test
|
50
55
|
|
@@ -135,6 +140,7 @@ module Spaceship
|
|
135
140
|
'largeAppIcon.value.originalFileName' => :app_icon_original_name,
|
136
141
|
'largeAppIcon.value.url' => :app_icon_url,
|
137
142
|
'releaseOnApproval.value' => :release_on_approval,
|
143
|
+
'autoReleaseDate.value' => :auto_release_date,
|
138
144
|
'status' => :raw_status,
|
139
145
|
'preReleaseBuild.buildVersion' => :build_version,
|
140
146
|
'supportsAppleWatch' => :supports_apple_watch,
|
@@ -104,7 +104,7 @@ module Spaceship
|
|
104
104
|
# @param last_name (String) (optional): The last name of the new tester
|
105
105
|
# @param groups (Array) (option): Names/IDs of existing groups for the new tester
|
106
106
|
# @example
|
107
|
-
# Spaceship::Tunes::Tester.external.create!(email: "tester@mathiascarignani.com", first_name: "Cary", last_name:"Bennett", groups:["Testers"])
|
107
|
+
# Spaceship::Tunes::Tester.external.create!(email: "tester@mathiascarignani.com", first_name: "Cary", last_name: "Bennett", groups: ["Testers"])
|
108
108
|
# @return (Tester): The newly created tester
|
109
109
|
def create!(email: nil, first_name: nil, last_name: nil, groups: nil)
|
110
110
|
data = client.create_tester!(tester: self,
|
@@ -46,9 +46,7 @@ module Spaceship
|
|
46
46
|
|
47
47
|
# @return (Array) A list of all available teams
|
48
48
|
def teams
|
49
|
-
|
50
|
-
r = request(:get, "ra/user/detail")
|
51
|
-
@teams = parse_response(r, 'data')['associatedAccounts'].sort_by do |team|
|
49
|
+
user_details_data['associatedAccounts'].sort_by do |team|
|
52
50
|
[
|
53
51
|
team['contentProvider']['name'],
|
54
52
|
team['contentProvider']['contentProviderId']
|
@@ -214,10 +212,13 @@ module Spaceship
|
|
214
212
|
errors << different_error if different_error
|
215
213
|
|
216
214
|
if errors.count > 0 # they are separated by `.` by default
|
215
|
+
# Sample `error` content: [["Forbidden"]]
|
217
216
|
if errors.count == 1 and errors.first == "You haven't made any changes."
|
218
217
|
# This is a special error which we really don't care about
|
219
218
|
elsif errors.count == 1 and errors.first.include?("try again later")
|
220
219
|
raise ITunesConnectTemporaryError.new, errors.first
|
220
|
+
elsif errors.count == 1 and errors.first.include?("Forbidden")
|
221
|
+
raise_insuffient_permission_error!
|
221
222
|
else
|
222
223
|
raise ITunesConnectError.new, errors.join(' ')
|
223
224
|
end
|
@@ -596,14 +597,61 @@ module Spaceship
|
|
596
597
|
Spaceship::Tunes::AppVersionRef.factory(data)
|
597
598
|
end
|
598
599
|
|
600
|
+
# Fetch the general information of the user, is used by various methods across spaceship
|
601
|
+
# Sample return value
|
602
|
+
# => {"associatedAccounts"=>
|
603
|
+
# [{"contentProvider"=>{"contentProviderId"=>11142800, "name"=>"Felix Krause", "contentProviderTypes"=>["Purple Software"]}, "roles"=>["Developer"], "lastLogin"=>1468784113000}],
|
604
|
+
# "sessionToken"=>{"dsId"=>"8501011116", "contentProviderId"=>18111111, "expirationDate"=>nil, "ipAddress"=>nil},
|
605
|
+
# "permittedActivities"=>
|
606
|
+
# {"EDIT"=>
|
607
|
+
# ["UserManagementSelf",
|
608
|
+
# "GameCenterTestData",
|
609
|
+
# "AppAddonCreation"],
|
610
|
+
# "REPORT"=>
|
611
|
+
# ["UserManagementSelf",
|
612
|
+
# "AppAddonCreation"],
|
613
|
+
# "VIEW"=>
|
614
|
+
# ["TestFlightAppExternalTesterManagement",
|
615
|
+
# ...
|
616
|
+
# "HelpGeneral",
|
617
|
+
# "HelpApplicationLoader"]},
|
618
|
+
# "preferredCurrencyCode"=>"EUR",
|
619
|
+
# "preferredCountryCode"=>nil,
|
620
|
+
# "countryOfOrigin"=>"AT",
|
621
|
+
# "isLocaleNameReversed"=>false,
|
622
|
+
# "feldsparToken"=>nil,
|
623
|
+
# "feldsparChannelName"=>nil,
|
624
|
+
# "hasPendingFeldsparBindingRequest"=>false,
|
625
|
+
# "isLegalUser"=>false,
|
626
|
+
# "userId"=>"1771111155",
|
627
|
+
# "firstname"=>"Detlef",
|
628
|
+
# "lastname"=>"Mueller",
|
629
|
+
# "isEmailInvalid"=>false,
|
630
|
+
# "hasContractInfo"=>false,
|
631
|
+
# "canEditITCUsersAndRoles"=>false,
|
632
|
+
# "canViewITCUsersAndRoles"=>true,
|
633
|
+
# "canEditIAPUsersAndRoles"=>false,
|
634
|
+
# "transporterEnabled"=>false,
|
635
|
+
# "contentProviderFeatures"=>["APP_SILOING", "PROMO_CODE_REDESIGN", ...],
|
636
|
+
# "contentProviderType"=>"Purple Software",
|
637
|
+
# "displayName"=>"Detlef",
|
638
|
+
# "contentProviderId"=>"18742800",
|
639
|
+
# "userFeatures"=>[],
|
640
|
+
# "visibility"=>true,
|
641
|
+
# "DYCVisibility"=>false,
|
642
|
+
# "contentProvider"=>"Felix Krause",
|
643
|
+
# "userName"=>"detlef@krausefx.com"}
|
644
|
+
def user_details_data
|
645
|
+
return @_cached_user_details if @_cached_user_details
|
646
|
+
r = request(:get, '/WebObjects/iTunesConnect.woa/ra/user/detail')
|
647
|
+
@_cached_user_details = parse_response(r, 'data')
|
648
|
+
end
|
649
|
+
|
599
650
|
# Fetches the User Detail information from ITC. This gets called often and almost never changes
|
600
651
|
# so we cache it
|
601
652
|
# @return [UserDetail] the response
|
602
653
|
def user_detail_data
|
603
|
-
|
604
|
-
r = request(:get, '/WebObjects/iTunesConnect.woa/ra/user/detail')
|
605
|
-
data = parse_response(r, 'data')
|
606
|
-
@cached = Spaceship::Tunes::UserDetail.factory(data)
|
654
|
+
@_cached_user_detail_data ||= Spaceship::Tunes::UserDetail.factory(user_details_data)
|
607
655
|
end
|
608
656
|
|
609
657
|
#####################################################
|
@@ -631,7 +679,13 @@ module Spaceship
|
|
631
679
|
# Build trains fail randomly very often
|
632
680
|
# we need to catch those errors and retry
|
633
681
|
# https://github.com/fastlane/fastlane/issues/6419
|
634
|
-
|
682
|
+
retry_error_messages = [
|
683
|
+
"ITC.response.error.OPERATION_FAILED",
|
684
|
+
"Internal Server Error",
|
685
|
+
"Service Unavailable"
|
686
|
+
].freeze
|
687
|
+
|
688
|
+
if retry_error_messages.any? { |message| ex.to_s.include?(message) }
|
635
689
|
tries -= 1
|
636
690
|
if tries > 0
|
637
691
|
logger.warn("Received temporary server error from iTunes Connect. Retrying the request...")
|
@@ -870,6 +924,10 @@ module Spaceship
|
|
870
924
|
parse_response(r, 'data')['users']
|
871
925
|
end
|
872
926
|
|
927
|
+
# Returns a list of available testing groups
|
928
|
+
# e.g.
|
929
|
+
# {"b6f65dbd-c845-4d91-bc39-0b661d608970" => "Boarding",
|
930
|
+
# "70402368-9deb-409f-9a26-bb3f215dfee3" => "Automatic"}
|
873
931
|
def groups
|
874
932
|
return @cached_groups if @cached_groups
|
875
933
|
r = request(:get, '/WebObjects/iTunesConnect.woa/ra/users/pre/ext')
|
@@ -881,21 +939,42 @@ module Spaceship
|
|
881
939
|
raise "Action not provided for this tester type." unless url
|
882
940
|
|
883
941
|
tester_data = {
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
942
|
+
emailAddress: {
|
943
|
+
value: email
|
944
|
+
},
|
945
|
+
firstName: {
|
946
|
+
value: first_name || ""
|
947
|
+
},
|
948
|
+
lastName: {
|
949
|
+
value: last_name || ""
|
950
|
+
},
|
951
|
+
testing: {
|
952
|
+
value: true
|
953
|
+
}
|
954
|
+
}
|
955
|
+
|
956
|
+
if groups
|
957
|
+
tester_data[:groups] = groups.map do |group_name_or_group_id|
|
958
|
+
if self.groups.value?(group_name_or_group_id)
|
959
|
+
# This is an existing group, let's use that, the user specified the group name
|
960
|
+
group_name = group_name_or_group_id
|
961
|
+
group_id = self.groups.key(group_name_or_group_id)
|
962
|
+
elsif self.groups.key?(group_name_or_group_id)
|
963
|
+
# This is an existing group, let's use that, the user specified the group ID
|
964
|
+
group_name = self.groups[group_name_or_group_id]
|
965
|
+
group_id = group_name_or_group_id
|
966
|
+
else
|
967
|
+
group_name = group_name_or_group_id
|
968
|
+
group_id = nil # this is expected by the iTC API
|
969
|
+
end
|
970
|
+
|
971
|
+
{
|
972
|
+
"id" => group_id,
|
973
|
+
"name" => {
|
974
|
+
"value" => group_name
|
895
975
|
}
|
896
976
|
}
|
897
|
-
|
898
|
-
tester_data[:groups] = groups.map { |x| { "id" => x } }
|
977
|
+
end
|
899
978
|
end
|
900
979
|
|
901
980
|
data = { testers: [tester_data] }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Felix Krause
|
@@ -14,7 +14,7 @@ authors:
|
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
|
-
date: 2017-01-
|
17
|
+
date: 2017-01-27 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: slack-notifier
|
@@ -739,15 +739,12 @@ files:
|
|
739
739
|
- deliver/lib/deliver/upload_price_tier.rb
|
740
740
|
- deliver/lib/deliver/upload_screenshots.rb
|
741
741
|
- fastlane/README.md
|
742
|
-
- fastlane/lib/.DS_Store
|
743
|
-
- fastlane/lib/assets/.DS_Store
|
744
742
|
- fastlane/lib/assets/Actions.md.erb
|
745
743
|
- fastlane/lib/assets/AppfileTemplate
|
746
744
|
- fastlane/lib/assets/AppfileTemplateAndroid
|
747
745
|
- fastlane/lib/assets/AvailablePlugins.md.erb
|
748
746
|
- fastlane/lib/assets/DefaultFastfileTemplate
|
749
747
|
- fastlane/lib/assets/FastfileTemplateAndroid
|
750
|
-
- fastlane/lib/assets/completions/.DS_Store
|
751
748
|
- fastlane/lib/assets/completions/completion.bash
|
752
749
|
- fastlane/lib/assets/completions/completion.sh
|
753
750
|
- fastlane/lib/assets/completions/completion.zsh
|
@@ -758,10 +755,8 @@ files:
|
|
758
755
|
- fastlane/lib/assets/s3_plist_template.erb
|
759
756
|
- fastlane/lib/assets/s3_version_template.erb
|
760
757
|
- fastlane/lib/fastlane.rb
|
761
|
-
- fastlane/lib/fastlane/.DS_Store
|
762
758
|
- fastlane/lib/fastlane/action.rb
|
763
759
|
- fastlane/lib/fastlane/action_collector.rb
|
764
|
-
- fastlane/lib/fastlane/actions/.DS_Store
|
765
760
|
- fastlane/lib/fastlane/actions/README.md
|
766
761
|
- fastlane/lib/fastlane/actions/actions_helper.rb
|
767
762
|
- fastlane/lib/fastlane/actions/adb.rb
|
@@ -802,7 +797,6 @@ files:
|
|
802
797
|
- fastlane/lib/fastlane/actions/delete_keychain.rb
|
803
798
|
- fastlane/lib/fastlane/actions/deliver.rb
|
804
799
|
- fastlane/lib/fastlane/actions/deploygate.rb
|
805
|
-
- fastlane/lib/fastlane/actions/device_grid/.DS_Store
|
806
800
|
- fastlane/lib/fastlane/actions/device_grid/README.md
|
807
801
|
- fastlane/lib/fastlane/actions/dotgpg_environment.rb
|
808
802
|
- fastlane/lib/fastlane/actions/download.rb
|
@@ -1013,10 +1007,8 @@ files:
|
|
1013
1007
|
- fastlane/lib/fastlane/tools.rb
|
1014
1008
|
- fastlane/lib/fastlane/version.rb
|
1015
1009
|
- fastlane_core/README.md
|
1016
|
-
- fastlane_core/lib/.DS_Store
|
1017
1010
|
- fastlane_core/lib/assets/XMLTemplate.xml.erb
|
1018
1011
|
- fastlane_core/lib/fastlane_core.rb
|
1019
|
-
- fastlane_core/lib/fastlane_core/.DS_Store
|
1020
1012
|
- fastlane_core/lib/fastlane_core/cert_checker.rb
|
1021
1013
|
- fastlane_core/lib/fastlane_core/command_executor.rb
|
1022
1014
|
- fastlane_core/lib/fastlane_core/configuration/commander_generator.rb
|
@@ -1172,7 +1164,6 @@ files:
|
|
1172
1164
|
- sigh/lib/sigh/resign.rb
|
1173
1165
|
- sigh/lib/sigh/runner.rb
|
1174
1166
|
- snapshot/README.md
|
1175
|
-
- snapshot/lib/.DS_Store
|
1176
1167
|
- snapshot/lib/assets/SnapfileTemplate
|
1177
1168
|
- snapshot/lib/assets/SnapshotHelper.swift
|
1178
1169
|
- snapshot/lib/assets/SnapshotHelper2-3.swift
|
@@ -1197,11 +1188,9 @@ files:
|
|
1197
1188
|
- snapshot/lib/snapshot/test_command_generator.rb
|
1198
1189
|
- snapshot/lib/snapshot/update.rb
|
1199
1190
|
- spaceship/README.md
|
1200
|
-
- spaceship/lib/.DS_Store
|
1201
1191
|
- spaceship/lib/assets/languageMapping.json
|
1202
1192
|
- spaceship/lib/assets/languageMappingReadable.json
|
1203
1193
|
- spaceship/lib/spaceship.rb
|
1204
|
-
- spaceship/lib/spaceship/.DS_Store
|
1205
1194
|
- spaceship/lib/spaceship/babosa_fix.rb
|
1206
1195
|
- spaceship/lib/spaceship/base.rb
|
1207
1196
|
- spaceship/lib/spaceship/client.rb
|
@@ -1305,7 +1294,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1305
1294
|
version: '0'
|
1306
1295
|
requirements: []
|
1307
1296
|
rubyforge_project:
|
1308
|
-
rubygems_version: 2.
|
1297
|
+
rubygems_version: 2.5.1
|
1309
1298
|
signing_key:
|
1310
1299
|
specification_version: 4
|
1311
1300
|
summary: The easiest way to automate beta deployments and releases for your iOS and
|
data/fastlane/lib/.DS_Store
DELETED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/fastlane_core/lib/.DS_Store
DELETED
Binary file
|
Binary file
|
data/snapshot/lib/.DS_Store
DELETED
Binary file
|
data/spaceship/lib/.DS_Store
DELETED
Binary file
|
Binary file
|