fastlane 2.29.0 → 2.29.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e2d6217752222539765f18e46a3582ad5a321161
4
- data.tar.gz: 221fa664a19e757b4afea97366750538d5a93c1a
3
+ metadata.gz: 4df803cb7188d41a48f3d759d9c163b6ba0727f9
4
+ data.tar.gz: b85c21bdcbf222cf50d54cc090b8c8e4e9b7fd8f
5
5
  SHA512:
6
- metadata.gz: 526b2ce145766d25900135abb2167722cf2a2d11570fed52b03d345262dceabbf231a91f0e062923b4efeb3b8cbb7124b2d2cff7a27eeef8589df981524c87b7
7
- data.tar.gz: 27ac8cc060cd9968f0ec44c291bd99b28934d8b1cd4782088fd00b61c6f4cb8e124c153b0107d19901dfd64c4f327c9f6827501f97fc5767de608a5fc2712f4f
6
+ metadata.gz: 447d8827823088b25927f9013be1b6c2013722981a599556848fc83c4b2e0b50a4879deede3f592940f603cb6aab7dde33ba84aa364bef795e67b11cee7271fb
7
+ data.tar.gz: dbd5145ed06f18ada1d6efd993ffc1821753c52c7b4e515ef865c4dcbb863d82545c79b893fdc770048cbd0f5059c24cd3fd15aab434a86dc4c4a606fb92b002
@@ -118,13 +118,13 @@
118
118
  margin-right: 20px;
119
119
  }
120
120
 
121
- .app-review-information {
121
+ .app-minor-information {
122
122
  margin-left: 15px;
123
123
  margin-right: 15px;
124
124
  margin-top: 22px;
125
125
  }
126
126
 
127
- .app-review-information-key {
127
+ .app-minor-information-key {
128
128
  font-weight: 700;
129
129
  }
130
130
  </style>
@@ -241,20 +241,37 @@
241
241
 
242
242
  <hr />
243
243
  <% end # end data %>
244
+ <% if @options[:trade_representative_contact_information] %>
245
+ <div class="app-minor-information">
246
+ <div class="cat-headline">Trade Representative Contact Information</div>
247
+ <dl class="app-minor-information">
248
+ <% @options[:trade_representative_contact_information].each do |key, value| %>
249
+ <dt class="app-minor-information-key">
250
+ <%= key.to_s.capitalize.gsub("_", " ") %>
251
+ </dt>
252
+ <dd class="app-minor-information-text">
253
+ <%= (value || '').gsub("\n", "<br />") %>
254
+ </dd>
255
+ <% end %>
256
+ </dl>
257
+ </div>
258
+ <hr />
259
+ <% end %>
260
+
244
261
  <% if @options[:app_review_information] %>
245
- <div class="app-review-information">
262
+ <div class="app-minor-information">
246
263
  <div class="cat-headline">Review Information</div>
247
- <dl class="app-review-information">
264
+ <dl class="app-minor-information">
248
265
  <% @options[:app_review_information].each do |key, value| %>
249
- <dt class="app-review-information-key">
266
+ <dt class="app-minor-information-key">
250
267
  <%= key.to_s.capitalize.gsub("_", " ") %>
251
268
  </dt>
252
- <dd class="app-review-information-text">
269
+ <dd class="app-minor-information-text">
253
270
  <%= (value || '').gsub("\n", "<br />") %>
254
271
  </dd>
255
272
  <% end %>
256
273
  </dl>
257
274
  </div>
258
- <% end %>
275
+ <% end %>
259
276
  </body>
260
277
  </html>
@@ -228,6 +228,10 @@ module Deliver
228
228
  description: "Metadata: The english name of the secondary second sub category(e.g. `Educational`, `Puzzle`)",
229
229
  optional: true,
230
230
  is_string: true),
231
+ FastlaneCore::ConfigItem.new(key: :trade_representative_contact_information,
232
+ description: "Metadata: A hash containing the trade representative contact information",
233
+ optional: true,
234
+ is_string: false),
231
235
  FastlaneCore::ConfigItem.new(key: :app_review_information,
232
236
  description: "Metadata: A hash containing the review information",
233
237
  optional: true,
@@ -66,6 +66,17 @@ module Deliver
66
66
  UI.message("Writing to '#{resulting_path}'")
67
67
  end
68
68
 
69
+ # Trade Representative Contact Information
70
+ UploadMetadata::TRADE_REPRESENTATIVE_CONTACT_INFORMATION_VALUES.each do |key, option_name|
71
+ content = v.send(key).to_s
72
+ content << "\n"
73
+ base_dir = File.join(path, UploadMetadata::TRADE_REPRESENTATIVE_CONTACT_INFORMATION_DIR)
74
+ FileUtils.mkdir_p(base_dir)
75
+ resulting_path = File.join(base_dir, "#{option_name}.txt")
76
+ File.write(resulting_path, content)
77
+ UI.message("Writing to '#{resulting_path}'")
78
+ end
79
+
69
80
  # Review information
70
81
  UploadMetadata::REVIEW_INFORMATION_VALUES.each do |key, option_name|
71
82
  content = v.send(key).to_s
@@ -15,6 +15,23 @@ module Deliver
15
15
  :primary_first_sub_category, :primary_second_sub_category,
16
16
  :secondary_first_sub_category, :secondary_second_sub_category]
17
17
 
18
+ # Trade Representative Contact Information values
19
+ TRADE_REPRESENTATIVE_CONTACT_INFORMATION_VALUES = {
20
+ trade_representative_trade_name: :trade_name,
21
+ trade_representative_first_name: :first_name,
22
+ trade_representative_last_name: :last_name,
23
+ trade_representative_address_line_1: :adderss_line1,
24
+ trade_representative_address_line_2: :adderss_line2,
25
+ trade_representative_address_line_3: :adderss_line3,
26
+ trade_representative_city_name: :city_name,
27
+ trade_representative_state: :state,
28
+ trade_representative_country: :country,
29
+ trade_representative_postal_code: :postal_code,
30
+ trade_representative_phone_number: :phone_number,
31
+ trade_representative_email: :email_address,
32
+ trade_representative_is_displayed_on_app_store: :is_displayed_on_app_store
33
+ }
34
+
18
35
  # Review information values
19
36
  REVIEW_INFORMATION_VALUES = {
20
37
  review_first_name: :first_name,
@@ -32,6 +49,9 @@ module Deliver
32
49
  # Non localized app details values, that are editable in live state
33
50
  NON_LOCALISED_LIVE_VALUES = [:privacy_url]
34
51
 
52
+ # Directory name it contains trade representative contact information
53
+ TRADE_REPRESENTATIVE_CONTACT_INFORMATION_DIR = "trade_representative_contact_information"
54
+
35
55
  # Directory name it contains review information
36
56
  REVIEW_INFORMATION_DIR = "review_information"
37
57
 
@@ -92,6 +112,7 @@ module Deliver
92
112
 
93
113
  v.release_on_approval = options[:automatic_release]
94
114
 
115
+ set_trade_representative_contact_information(v, options)
95
116
  set_review_information(v, options)
96
117
  set_app_rating(v, options)
97
118
 
@@ -198,6 +219,17 @@ module Deliver
198
219
  options[key] ||= File.read(path)
199
220
  end
200
221
 
222
+ # Load trade representative contact information
223
+ options[:trade_representative_contact_information] ||= {}
224
+ TRADE_REPRESENTATIVE_CONTACT_INFORMATION_VALUES.values.each do |option_name|
225
+ path = File.join(options[:metadata_path], TRADE_REPRESENTATIVE_CONTACT_INFORMATION_DIR, "#{option_name}.txt")
226
+ next unless File.exist?(path)
227
+ next if options[:trade_representative_contact_information][option_name].to_s.length > 0
228
+
229
+ UI.message("Loading '#{path}'...")
230
+ options[:trade_representative_contact_information][option_name] ||= File.read(path)
231
+ end
232
+
201
233
  # Load review information
202
234
  options[:app_review_information] ||= {}
203
235
  REVIEW_INFORMATION_VALUES.values.each do |option_name|
@@ -212,6 +244,16 @@ module Deliver
212
244
 
213
245
  private
214
246
 
247
+ def set_trade_representative_contact_information(v, options)
248
+ return unless options[:trade_representative_contact_information]
249
+ info = options[:trade_representative_contact_information]
250
+ UI.user_error!("`trade_representative_contact_information` must be a hash", show_github_issues: true) unless info.kind_of?(Hash)
251
+
252
+ TRADE_REPRESENTATIVE_CONTACT_INFORMATION_VALUES.each do |key, option_name|
253
+ v.send("#{key}=", info[option_name].chomp) if info[option_name].chomp
254
+ end
255
+ end
256
+
215
257
  def set_review_information(v, options)
216
258
  return unless options[:app_review_information]
217
259
  info = options[:app_review_information]
@@ -57,8 +57,7 @@ module Fastlane
57
57
  update_needed.each do |tool_info|
58
58
  tool = tool_info[0]
59
59
  local_version = Gem::Version.new(highest_versions[tool].version)
60
- update_url = FastlaneCore::UpdateChecker.generate_fetch_url(tool)
61
- latest_version = FastlaneCore::UpdateChecker.fetch_latest(update_url)
60
+ latest_version = FastlaneCore::UpdateChecker.fetch_latest(tool)
62
61
  UI.message("Updating #{tool} from #{local_version} to #{latest_version} ... 🚀")
63
62
 
64
63
  # Approximate_recommendation will create a string like "~> 0.10" from a version 0.10.0, e.g. one that is valid for versions >= 0.10 and <1.0
@@ -73,7 +73,29 @@ module Fastlane
73
73
  else
74
74
  puts "Couldn't find action for the given filter.".red
75
75
  puts "==========================================\n".red
76
+
76
77
  print_all # show all available actions instead
78
+ print_suggestions(filter)
79
+ end
80
+ end
81
+
82
+ def self.print_suggestions(filter)
83
+ if !filter.nil? && filter.length > 1
84
+ action_names = []
85
+ all_actions(nil) do |action_ref, action_name|
86
+ action_names << action_name
87
+ end
88
+
89
+ corrections = []
90
+
91
+ if !Gem.loaded_specs["did_you_mean"].nil? && Gem.loaded_specs["did_you_mean"].version >= Gem::Version.new('1.1.0')
92
+ spell_checker = DidYouMean::SpellChecker.new(dictionary: action_names)
93
+ corrections << spell_checker.correct(filter).compact
94
+ end
95
+
96
+ corrections << action_names.select { |name| name.include? filter }
97
+
98
+ puts "Did you mean: #{corrections.flatten.uniq.join(', ')}?".green unless corrections.flatten.empty?
77
99
  end
78
100
  end
79
101
 
@@ -62,17 +62,16 @@ module Fastlane
62
62
  table << "|--------|---------|\n"
63
63
  plugin_manager.available_plugins.each do |plugin|
64
64
  begin
65
- installed_version = Fastlane::ActionCollector.determine_version(plugin)
66
- update_url = FastlaneCore::UpdateChecker.generate_fetch_url(plugin)
67
- latest_version = FastlaneCore::UpdateChecker.fetch_latest(update_url)
68
- if Gem::Version.new(installed_version) == Gem::Version.new(latest_version)
69
- update_status = "✅ Up-To-Date"
70
- else
71
- update_status = "🚫 Update available"
65
+ installed_version = Fastlane::ActionCollector.determine_version(plugin)
66
+ latest_version = FastlaneCore::UpdateChecker.fetch_latest(plugin)
67
+ if Gem::Version.new(installed_version) == Gem::Version.new(latest_version)
68
+ update_status = "✅ Up-To-Date"
69
+ else
70
+ update_status = "🚫 Update available"
71
+ end
72
+ rescue
73
+ update_status = "💥 Check failed"
72
74
  end
73
- rescue
74
- update_status = "💥 Check failed"
75
- end
76
75
  table << "| #{plugin} | #{installed_version} | #{update_status} |\n"
77
76
  end
78
77
 
@@ -107,9 +106,8 @@ module Fastlane
107
106
 
108
107
  next unless fastlane_tools.include?(current_gem.name.to_sym)
109
108
  begin
110
- update_url = FastlaneCore::UpdateChecker.generate_fetch_url(current_gem.name)
111
- latest_version = FastlaneCore::UpdateChecker.fetch_latest(update_url)
112
- if Gem::Version.new(current_gem.version) == Gem::Version.new(latest_version)
109
+ latest_version = FastlaneCore::UpdateChecker.fetch_latest(current_gem.name)
110
+ if Gem::Version.new(current_gem.version) >= Gem::Version.new(latest_version)
113
111
  update_status = "✅ Up-To-Date"
114
112
  else
115
113
  update_status = "🚫 Update available"
@@ -33,6 +33,7 @@ module Fastlane
33
33
  UI.verbose(caller.join("\n"))
34
34
  UI.user_error!("The action '#{action}' is no longer bundled with fastlane. You can install it using `fastlane add_plugin #{action}`")
35
35
  else
36
+ Fastlane::ActionsList.print_suggestions(action)
36
37
  UI.user_error!("Action '#{action}' not available, run `fastlane actions` to get a full list")
37
38
  end
38
39
  end
@@ -1,4 +1,4 @@
1
1
  module Fastlane
2
- VERSION = '2.29.0'.freeze
2
+ VERSION = '2.29.1'.freeze
3
3
  DESCRIPTION = "The easiest way to automate beta deployments and releases for your iOS and Android apps".freeze
4
4
  end
@@ -112,7 +112,11 @@ module FastlaneCore
112
112
  end
113
113
 
114
114
  def self.fetch_latest(gem_name)
115
- JSON.parse(Excon.get("https://rubygems.org/api/v1/gems/#{gem_name}.json").body)["version"]
115
+ JSON.parse(Excon.get(generate_fetch_url(gem_name)).body)["version"]
116
+ end
117
+
118
+ def self.generate_fetch_url(gem_name)
119
+ "https://rubygems.org/api/v1/gems/#{gem_name}.json"
116
120
  end
117
121
 
118
122
  # (optional) Returns the app identifier for the current tool
@@ -16,7 +16,9 @@ module Match
16
16
 
17
17
  unless password
18
18
  if !UI.interactive?
19
- UI.error "No password found neither in environment nor in local keychain. Bailing out as in non interactive mode."
19
+ UI.error "Neither the MATCH_PASSWORD environment variable nor the local keychain contained a password."
20
+ UI.error "Bailing out instead of asking for a password, since this is non-interactive mode."
21
+ UI.error "Try setting the MATCH_PASSWORD environment variable, or temporarily enable interactive mode to store a password."
20
22
  else
21
23
  UI.important "Enter the passphrase that should be used to encrypt/decrypt your certificates"
22
24
  UI.important "This passphrase is specific per repository and will be stored in your local keychain"
@@ -6,19 +6,28 @@ module Pilot
6
6
  class TesterManager < Manager
7
7
  def add_tester(options)
8
8
  start(options)
9
-
10
9
  app = find_app(app_filter: config[:apple_id] || config[:app_identifier])
11
10
  UI.user_error!("You must provide either a Apple ID for the app (with the `:apple_id` option) or app identifier (with the `:app_identifier` option)") unless app
12
11
 
13
- tester = find_or_create_tester(email: config[:email], first_name: config[:first_name], last_name: config[:last_name])
14
-
12
+ tester = find_app_tester(email: config[:email], app: app)
13
+ tester ||= create_tester(
14
+ email: config[:email],
15
+ first_name: config[:first_name],
16
+ last_name: config[:last_name],
17
+ app: app
18
+ )
15
19
  begin
16
20
  groups = Spaceship::TestFlight::Group.add_tester_to_groups!(tester: tester, app: app, groups: config[:groups])
17
21
  if tester.kind_of?(Spaceship::Tunes::Tester::Internal)
18
22
  UI.success("Successfully added tester to app #{app.name}")
19
23
  else
20
- group_names = groups.map(&:name).join(", ")
21
- UI.success("Successfully added tester to app #{app.name} in group(s) #{group_names}")
24
+ # tester was added to the group(s) in the above add_tester_to_groups() call, now we need to let the user know which group(s)
25
+ if config[:groups]
26
+ group_names = groups.map(&:name).join(", ")
27
+ UI.success("Successfully added tester to group(s): #{group_names} in app: #{app.name}")
28
+ else
29
+ UI.success("Successfully added tester to the default tester group in app: #{app.name}")
30
+ end
22
31
  end
23
32
  rescue => ex
24
33
  UI.error("Could not add #{tester.email} to app: #{app.name}")
@@ -91,21 +100,51 @@ module Pilot
91
100
  nil
92
101
  end
93
102
 
94
- def find_or_create_tester(email: nil, first_name: nil, last_name: nil)
95
- tester = Spaceship::Tunes::Tester::Internal.find(config[:email])
96
- tester ||= Spaceship::Tunes::Tester::External.find(config[:email])
103
+ def find_app_tester(email: nil, app: nil)
104
+ current_user = Spaceship::Members.find(Spaceship::Tunes.client.user)
105
+ if current_user.admin?
106
+ tester = Spaceship::Tunes::Tester::Internal.find(email)
107
+ tester ||= Spaceship::Tunes::Tester::External.find(email)
108
+ elsif current_user.app_manager?
109
+ unless app
110
+ UI.user_error!("Account #{current_user.email_address} is only an 'App Manager' and therefore you must also define what app this tester (#{email}) should be added to")
111
+ end
112
+ tester = Spaceship::Tunes::Tester::Internal.find_by_app(app.apple_id, email)
113
+ tester ||= Spaceship::Tunes::Tester::External.find_by_app(app.apple_id, email)
114
+ else
115
+ UI.user_error!("Account #{current_user.email} doesn't have a role that is allowed to administer app testers, current roles: #{current_user.roles}")
116
+ tester = nil
117
+ end
97
118
 
98
119
  if tester
99
- UI.success("Existing tester #{tester.email}")
120
+ UI.success("Found existing tester #{email}")
121
+ end
122
+
123
+ return tester
124
+ end
125
+
126
+ def create_tester(email: nil, first_name: nil, last_name: nil, app: nil)
127
+ current_user = Spaceship::Members.find(Spaceship::Tunes.client.user)
128
+ if current_user.admin?
129
+ tester = Spaceship::Tunes::Tester::External.create!(email: email,
130
+ first_name: first_name,
131
+ last_name: last_name)
132
+ UI.success("Successfully added tester: #{email} to your account")
133
+ elsif current_user.app_manager?
134
+
135
+ Spaceship::TestFlight::Tester.create_app_level_tester(app_id: app.apple_id,
136
+ first_name: first_name,
137
+ last_name: last_name,
138
+ email: email)
139
+ tester = Spaceship::Tunes::Tester::External.find_by_app(app.apple_id, email)
140
+ UI.success("Successfully added tester: #{email} to app: #{app.name}")
100
141
  else
101
- tester = Spaceship::Tunes::Tester::External.create!(email: config[:email],
102
- first_name: config[:first_name],
103
- last_name: config[:last_name])
104
- UI.success("Successfully added tester: #{tester.email} to your account")
142
+ UI.user_error!("Current account doesn't have permission to create a tester")
105
143
  end
144
+
106
145
  return tester
107
146
  rescue => ex
108
- UI.error("Could not create tester #{config[:email]}")
147
+ UI.error("Could not create tester #{email}")
109
148
  raise ex
110
149
  end
111
150
 
@@ -176,7 +176,12 @@ module Snapshot
176
176
  FastlaneCore::ConfigItem.new(key: :test_target_name,
177
177
  env_name: "SNAPSHOT_TEST_TARGET_NAME",
178
178
  description: "The name of the target you want to test (if you desire to override the Target Application from Xcode)",
179
- optional: true)
179
+ optional: true),
180
+ FastlaneCore::ConfigItem.new(key: :namespace_log_files,
181
+ env_name: "SNAPSHOT_NAMESPACE_LOG_FILES",
182
+ description: "Separate the log files per device and per language",
183
+ optional: true,
184
+ is_string: false)
180
185
  ]
181
186
  end
182
187
  end
@@ -171,7 +171,7 @@ module Snapshot
171
171
 
172
172
  open_simulator_for_device(device_type)
173
173
 
174
- command = TestCommandGenerator.generate(device_type: device_type)
174
+ command = TestCommandGenerator.generate(device_type: device_type, language: language, locale: locale)
175
175
 
176
176
  if locale
177
177
  UI.header("#{device_type} - #{language} (#{locale})")
@@ -208,7 +208,7 @@ module Snapshot
208
208
  end
209
209
  end)
210
210
 
211
- raw_output = File.read(TestCommandGenerator.xcodebuild_log_path)
211
+ raw_output = File.read(TestCommandGenerator.xcodebuild_log_path(device_type: device_type, language: language, locale: locale))
212
212
 
213
213
  dir_name = locale || language
214
214
 
@@ -2,7 +2,7 @@ module Snapshot
2
2
  # Responsible for building the fully working xcodebuild command
3
3
  class TestCommandGenerator
4
4
  class << self
5
- def generate(device_type: nil)
5
+ def generate(device_type: nil, language: nil, locale: nil)
6
6
  parts = prefix
7
7
  parts << "xcodebuild"
8
8
  parts += options
@@ -10,7 +10,7 @@ module Snapshot
10
10
  parts += build_settings
11
11
  parts += actions
12
12
  parts += suffix
13
- parts += pipe
13
+ parts += pipe(device_type, language, locale)
14
14
 
15
15
  parts
16
16
  end
@@ -62,8 +62,9 @@ module Snapshot
62
62
  []
63
63
  end
64
64
 
65
- def pipe
66
- ["| tee #{xcodebuild_log_path.shellescape} | xcpretty #{Snapshot.config[:xcpretty_args]}"]
65
+ def pipe(device_type, language, locale)
66
+ log_path = xcodebuild_log_path(device_type: device_type, language: language, locale: locale)
67
+ ["| tee #{log_path.shellescape} | xcpretty #{Snapshot.config[:xcpretty_args]}"]
67
68
  end
68
69
 
69
70
  def find_device(device_name, os_version = Snapshot.config[:ios_version])
@@ -108,8 +109,17 @@ module Snapshot
108
109
  return ["-destination '#{value}'"]
109
110
  end
110
111
 
111
- def xcodebuild_log_path
112
- file_name = "#{Snapshot.project.app_name}-#{Snapshot.config[:scheme]}.log"
112
+ def xcodebuild_log_path(device_type: nil, language: nil, locale: nil)
113
+ name_components = [Snapshot.project.app_name, Snapshot.config[:scheme]]
114
+
115
+ if Snapshot.config[:namespace_log_files]
116
+ name_components << device_type if device_type
117
+ name_components << language if language
118
+ name_components << locale if locale
119
+ end
120
+
121
+ file_name = "#{name_components.join('-')}.log"
122
+
113
123
  containing = File.expand_path(Snapshot.config[:buildlog_path])
114
124
  FileUtils.mkdir_p(containing)
115
125
 
@@ -111,16 +111,15 @@ module Spaceship::TestFlight
111
111
  handle_response(response)
112
112
  end
113
113
 
114
- def post_tester(app_id: nil, tester: nil)
114
+ def create_app_level_tester(app_id: nil, first_name: nil, last_name: nil, email: nil)
115
115
  assert_required_params(__method__, binding)
116
-
117
116
  url = "providers/#{team_id}/apps/#{app_id}/testers"
118
117
  response = request(:post) do |req|
119
118
  req.url url
120
119
  req.body = {
121
- "email" => tester.email,
122
- "firstName" => tester.first_name,
123
- "lastName" => tester.last_name
120
+ "email" => email,
121
+ "firstName" => first_name,
122
+ "lastName" => last_name
124
123
  }.to_json
125
124
  req.headers['Content-Type'] = 'application/json'
126
125
  end
@@ -46,8 +46,12 @@ module Spaceship::TestFlight
46
46
  # is not enough to add the tester to a group. If this isn't done the next request would fail.
47
47
  # This is a bug we reported to the iTunes Connect team, as it also happens on the iTunes Connect UI on 18. April 2017
48
48
  def add_tester!(tester)
49
- # This post request makes the account-level tester available to the app
50
- tester_data = client.post_tester(app_id: self.app_id, tester: tester)
49
+ # This post request creates an account-level tester and then makes it available to the app, or just makes
50
+ # it available to the app if it already exists
51
+ tester_data = client.create_app_level_tester(app_id: self.app_id,
52
+ first_name: tester.first_name,
53
+ last_name: tester.last_name,
54
+ email: tester.email)
51
55
  # This put request adds the tester to the group
52
56
  client.put_tester_to_group(group_id: self.id, tester_id: tester_data['id'], app_id: self.app_id)
53
57
  end
@@ -27,6 +27,13 @@ module Spaceship::TestFlight
27
27
  self.all(app_id: app_id).find { |tester| tester.email == email }
28
28
  end
29
29
 
30
+ def self.create_app_level_tester(app_id: nil, first_name: nil, last_name: nil, email: nil)
31
+ client.create_app_level_tester(app_id: app_id,
32
+ first_name: first_name,
33
+ last_name: last_name,
34
+ email: email)
35
+ end
36
+
30
37
  def remove_from_app!(app_id: nil)
31
38
  client.delete_tester_from_app(app_id: app_id, tester_id: self.tester_id)
32
39
  end
@@ -71,6 +71,48 @@ module Spaceship
71
71
  # @return (Spaceship::Tunes::TransitAppFile) the structure containing information about the geo json. Can be nil
72
72
  attr_accessor :transit_app_file
73
73
 
74
+ ####
75
+ # Trade Representative Contact Information
76
+ ####
77
+ # @return (String) Trade Representative Contact Information Trade Name. This attribute isn't editable
78
+ attr_accessor :trade_representative_trade_name
79
+
80
+ # @return (String) Trade Representative Contact Information First Name
81
+ attr_accessor :trade_representative_first_name
82
+
83
+ # @return (String) Trade Representative Contact Information Last Name
84
+ attr_accessor :trade_representative_last_name
85
+
86
+ # @return (String) Trade Representative Contact Information Address Line 1
87
+ attr_accessor :trade_representative_address_line_1
88
+
89
+ # @return (String) Trade Representative Contact Information Address Line 2
90
+ attr_accessor :trade_representative_address_line_2
91
+
92
+ # @return (String) Trade Representative Contact Information Address Line 3
93
+ attr_accessor :trade_representative_address_line_3
94
+
95
+ # @return (String) Trade Representative Contact Information City Name
96
+ attr_accessor :trade_representative_city_name
97
+
98
+ # @return (String) Trade Representative Contact Information State
99
+ attr_accessor :trade_representative_state
100
+
101
+ # @return (String) Trade Representative Contact Information Country
102
+ attr_accessor :trade_representative_country
103
+
104
+ # @return (String) Trade Representative Contact Information Postal Code
105
+ attr_accessor :trade_representative_postal_code
106
+
107
+ # @return (String) Trade Representative Contact Information Phone Number
108
+ attr_accessor :trade_representative_phone_number
109
+
110
+ # @return (String) Trade Representative Contact Information Email Address
111
+ attr_accessor :trade_representative_email
112
+
113
+ # @return (Boolean) Display Trade Representative Contact Information on the Korean App Store or not
114
+ attr_accessor :trade_representative_is_displayed_on_app_store
115
+
74
116
  ####
75
117
  # App Review Information
76
118
  ####
@@ -150,6 +192,22 @@ module Spaceship
150
192
  # GeoJson
151
193
  # 'transitAppFile.value' => :transit_app_file
152
194
 
195
+ # Trade Representative Contact Information
196
+
197
+ 'appStoreInfo.tradeName.value' => :trade_representative_trade_name,
198
+ 'appStoreInfo.firstName.value' => :trade_representative_first_name,
199
+ 'appStoreInfo.lastName.value' => :trade_representative_last_name,
200
+ 'appStoreInfo.addressLine1.value' => :trade_representative_address_line_1,
201
+ 'appStoreInfo.addressLine2.value' => :trade_representative_address_line_2,
202
+ 'appStoreInfo.addressLine3.value' => :trade_representative_address_line_3,
203
+ 'appStoreInfo.cityName.value' => :trade_representative_city_name,
204
+ 'appStoreInfo.state.value' => :trade_representative_state,
205
+ 'appStoreInfo.country.value' => :trade_representative_country,
206
+ 'appStoreInfo.postalCode.value' => :trade_representative_postal_code,
207
+ 'appStoreInfo.phoneNumber.value' => :trade_representative_phone_number,
208
+ 'appStoreInfo.emailAddress.value' => :trade_representative_email,
209
+ 'appStoreInfo.shouldDisplayInStore.value' => :trade_representative_is_displayed_on_app_store,
210
+
153
211
  # App Review Information
154
212
  'appReviewInfo.firstName.value' => :review_first_name,
155
213
  'appReviewInfo.lastName.value' => :review_last_name,
@@ -16,6 +16,15 @@ module Spaceship
16
16
  'dsId' => :user_id
17
17
  )
18
18
 
19
+ ROLES = {
20
+ admin: 'admin',
21
+ app_manager: 'appmanager',
22
+ sales: 'sales',
23
+ developer: 'developer',
24
+ marketing: 'marketing',
25
+ reports: 'reports'
26
+ }
27
+
19
28
  def roles
20
29
  parsed_roles = []
21
30
  raw_data["roles"].each do |role|
@@ -24,6 +33,14 @@ module Spaceship
24
33
  return parsed_roles
25
34
  end
26
35
 
36
+ def admin?
37
+ roles.include?(ROLES[:admin])
38
+ end
39
+
40
+ def app_manager?
41
+ roles.include?(ROLES[:app_manager])
42
+ end
43
+
27
44
  def preferred_currency
28
45
  currency_base = raw_data["preferredCurrency"]["value"]
29
46
  return {
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.29.0
4
+ version: 2.29.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felix Krause
@@ -15,7 +15,7 @@ authors:
15
15
  autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
- date: 2017-05-09 00:00:00.000000000 Z
18
+ date: 2017-05-11 00:00:00.000000000 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: slack-notifier
@@ -1257,6 +1257,7 @@ files:
1257
1257
  - spaceship/lib/assets/languageMapping.json
1258
1258
  - spaceship/lib/assets/languageMappingReadable.json
1259
1259
  - spaceship/lib/spaceship.rb
1260
+ - spaceship/lib/spaceship/.DS_Store
1260
1261
  - spaceship/lib/spaceship/babosa_fix.rb
1261
1262
  - spaceship/lib/spaceship/base.rb
1262
1263
  - spaceship/lib/spaceship/client.rb
@@ -1386,7 +1387,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1386
1387
  version: '0'
1387
1388
  requirements: []
1388
1389
  rubyforge_project:
1389
- rubygems_version: 2.5.1
1390
+ rubygems_version: 2.2.5
1390
1391
  signing_key:
1391
1392
  specification_version: 4
1392
1393
  summary: The easiest way to automate beta deployments and releases for your iOS and