fastlane 2.150.0.rc1 → 2.150.0.rc6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/deliver/lib/deliver/download_screenshots.rb +48 -26
  3. data/deliver/lib/deliver/runner.rb +0 -17
  4. data/deliver/lib/deliver/submit_for_review.rb +79 -32
  5. data/deliver/lib/deliver/upload_metadata.rb +92 -21
  6. data/deliver/lib/deliver/upload_price_tier.rb +9 -2
  7. data/deliver/lib/deliver/upload_screenshots.rb +61 -9
  8. data/fastlane/lib/fastlane/actions/.hockey.rb.swp +0 -0
  9. data/fastlane/lib/fastlane/actions/.slack.rb.swp +0 -0
  10. data/fastlane/lib/fastlane/actions/.update_project_provisioning.rb.swp +0 -0
  11. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +78 -85
  12. data/fastlane/lib/fastlane/actions/set_changelog.rb +23 -20
  13. data/fastlane/lib/fastlane/version.rb +1 -1
  14. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.xcworkspace/xcuserdata/josh.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  15. data/fastlane_core/lib/fastlane_core/build_watcher.rb +4 -4
  16. data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +89 -52
  17. data/pilot/lib/pilot/.manager.rb.swp +0 -0
  18. data/produce/lib/produce/itunes_connect.rb +43 -5
  19. data/spaceship/lib/spaceship/client.rb +4 -3
  20. data/spaceship/lib/spaceship/connect_api.rb +5 -1
  21. data/spaceship/lib/spaceship/{.DS_Store → connect_api/.DS_Store} +0 -0
  22. data/spaceship/lib/spaceship/connect_api/client.rb +50 -20
  23. data/spaceship/lib/spaceship/connect_api/file_uploader.rb +98 -0
  24. data/spaceship/lib/spaceship/connect_api/models/age_rating_declaration.rb +6 -2
  25. data/spaceship/lib/spaceship/connect_api/models/app.rb +35 -13
  26. data/spaceship/lib/spaceship/connect_api/models/app_info.rb +4 -11
  27. data/spaceship/lib/spaceship/connect_api/models/app_preview.rb +129 -0
  28. data/spaceship/lib/spaceship/connect_api/models/app_preview_set.rb +71 -0
  29. data/spaceship/lib/spaceship/connect_api/models/app_review_attachment.rb +18 -28
  30. data/spaceship/lib/spaceship/connect_api/models/app_screenshot.rb +88 -59
  31. data/spaceship/lib/spaceship/connect_api/models/app_screenshot_set.rb +26 -2
  32. data/spaceship/lib/spaceship/connect_api/models/app_store_version.rb +1 -0
  33. data/spaceship/lib/spaceship/connect_api/models/app_store_version_localization.rb +16 -0
  34. data/spaceship/lib/spaceship/connect_api/models/territory.rb +27 -0
  35. data/spaceship/lib/spaceship/connect_api/models/user.rb +2 -1
  36. data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +215 -74
  37. data/spaceship/lib/spaceship/connect_api/users/users.rb +13 -0
  38. metadata +16 -7
@@ -239,64 +239,101 @@ module FastlaneCore
239
239
  # escaping problems in its accompanying shell script.
240
240
  class JavaTransporterExecutor < TransporterExecutor
241
241
  def build_upload_command(username, password, source = "/tmp", provider_short_name = "")
242
- [
243
- Helper.transporter_java_executable_path.shellescape,
244
- "-Djava.ext.dirs=#{Helper.transporter_java_ext_dir.shellescape}",
245
- '-XX:NewSize=2m',
246
- '-Xms32m',
247
- '-Xmx1024m',
248
- '-Xms1024m',
249
- '-Djava.awt.headless=true',
250
- '-Dsun.net.http.retryPost=false',
251
- java_code_option,
252
- '-m upload',
253
- "-u #{username.shellescape}",
254
- "-p #{password.shellescape}",
255
- "-f #{source.shellescape}",
256
- additional_upload_parameters, # that's here, because the user might overwrite the -t option
257
- '-k 100000',
258
- ("-itc_provider #{provider_short_name}" unless provider_short_name.to_s.empty?),
259
- '2>&1' # cause stderr to be written to stdout
260
- ].compact.join(' ') # compact gets rid of the possibly nil ENV value
242
+ if Helper.mac? && Helper.xcode_at_least?(11)
243
+ [
244
+ 'xcrun iTMSTransporter',
245
+ '-m upload',
246
+ "-u #{username.shellescape}",
247
+ "-p #{password.shellescape}",
248
+ "-f #{source.shellescape}",
249
+ additional_upload_parameters, # that's here, because the user might overwrite the -t option
250
+ '-k 100000',
251
+ ("-itc_provider #{provider_short_name}" unless provider_short_name.to_s.empty?),
252
+ '2>&1' # cause stderr to be written to stdout
253
+ ].compact.join(' ') # compact gets rid of the possibly nil ENV value
254
+ else
255
+ [
256
+ Helper.transporter_java_executable_path.shellescape,
257
+ "-Djava.ext.dirs=#{Helper.transporter_java_ext_dir.shellescape}",
258
+ '-XX:NewSize=2m',
259
+ '-Xms32m',
260
+ '-Xmx1024m',
261
+ '-Xms1024m',
262
+ '-Djava.awt.headless=true',
263
+ '-Dsun.net.http.retryPost=false',
264
+ java_code_option,
265
+ '-m upload',
266
+ "-u #{username.shellescape}",
267
+ "-p #{password.shellescape}",
268
+ "-f #{source.shellescape}",
269
+ additional_upload_parameters, # that's here, because the user might overwrite the -t option
270
+ '-k 100000',
271
+ ("-itc_provider #{provider_short_name}" unless provider_short_name.to_s.empty?),
272
+ '2>&1' # cause stderr to be written to stdout
273
+ ].compact.join(' ') # compact gets rid of the possibly nil ENV value
274
+ end
261
275
  end
262
276
 
263
277
  def build_download_command(username, password, apple_id, destination = "/tmp", provider_short_name = "")
264
- [
265
- Helper.transporter_java_executable_path.shellescape,
266
- "-Djava.ext.dirs=#{Helper.transporter_java_ext_dir.shellescape}",
267
- '-XX:NewSize=2m',
268
- '-Xms32m',
269
- '-Xmx1024m',
270
- '-Xms1024m',
271
- '-Djava.awt.headless=true',
272
- '-Dsun.net.http.retryPost=false',
273
- java_code_option,
274
- '-m lookupMetadata',
275
- "-u #{username.shellescape}",
276
- "-p #{password.shellescape}",
277
- "-apple_id #{apple_id.shellescape}",
278
- "-destination #{destination.shellescape}",
279
- ("-itc_provider #{provider_short_name}" unless provider_short_name.to_s.empty?),
280
- '2>&1' # cause stderr to be written to stdout
281
- ].compact.join(' ')
278
+ if Helper.mac? && Helper.xcode_at_least?(11)
279
+ [
280
+ 'xcrun iTMSTransporter',
281
+ '-m lookupMetadata',
282
+ "-u #{username.shellescape}",
283
+ "-p #{password.shellescape}",
284
+ "-apple_id #{apple_id.shellescape}",
285
+ "-destination #{destination.shellescape}",
286
+ ("-itc_provider #{provider_short_name}" unless provider_short_name.to_s.empty?),
287
+ '2>&1' # cause stderr to be written to stdout
288
+ ].compact.join(' ')
289
+ else
290
+ [
291
+ Helper.transporter_java_executable_path.shellescape,
292
+ "-Djava.ext.dirs=#{Helper.transporter_java_ext_dir.shellescape}",
293
+ '-XX:NewSize=2m',
294
+ '-Xms32m',
295
+ '-Xmx1024m',
296
+ '-Xms1024m',
297
+ '-Djava.awt.headless=true',
298
+ '-Dsun.net.http.retryPost=false',
299
+ java_code_option,
300
+ '-m lookupMetadata',
301
+ "-u #{username.shellescape}",
302
+ "-p #{password.shellescape}",
303
+ "-apple_id #{apple_id.shellescape}",
304
+ "-destination #{destination.shellescape}",
305
+ ("-itc_provider #{provider_short_name}" unless provider_short_name.to_s.empty?),
306
+ '2>&1' # cause stderr to be written to stdout
307
+ ].compact.join(' ')
308
+ end
282
309
  end
283
310
 
284
311
  def build_provider_ids_command(username, password)
285
- [
286
- Helper.transporter_java_executable_path.shellescape,
287
- "-Djava.ext.dirs=#{Helper.transporter_java_ext_dir.shellescape}",
288
- '-XX:NewSize=2m',
289
- '-Xms32m',
290
- '-Xmx1024m',
291
- '-Xms1024m',
292
- '-Djava.awt.headless=true',
293
- '-Dsun.net.http.retryPost=false',
294
- java_code_option,
295
- '-m provider',
296
- "-u #{username.shellescape}",
297
- "-p #{password.shellescape}",
298
- '2>&1' # cause stderr to be written to stdout
299
- ].compact.join(' ')
312
+ if Helper.mac? && Helper.xcode_at_least?(11)
313
+ [
314
+ 'xcrun iTMSTransporter',
315
+ '-m provider',
316
+ "-u #{username.shellescape}",
317
+ "-p #{password.shellescape}",
318
+ '2>&1' # cause stderr to be written to stdout
319
+ ].compact.join(' ')
320
+ else
321
+ [
322
+ Helper.transporter_java_executable_path.shellescape,
323
+ "-Djava.ext.dirs=#{Helper.transporter_java_ext_dir.shellescape}",
324
+ '-XX:NewSize=2m',
325
+ '-Xms32m',
326
+ '-Xmx1024m',
327
+ '-Xms1024m',
328
+ '-Djava.awt.headless=true',
329
+ '-Dsun.net.http.retryPost=false',
330
+ java_code_option,
331
+ '-m provider',
332
+ "-u #{username.shellescape}",
333
+ "-p #{password.shellescape}",
334
+ '2>&1' # cause stderr to be written to stdout
335
+ ].compact.join(' ')
336
+ end
300
337
  end
301
338
 
302
339
  def java_code_option
@@ -21,6 +21,13 @@ module Produce
21
21
  UI.success("App '#{Produce.config[:app_identifier]}' already exists (#{application.id}), nothing to do on App Store Connect")
22
22
  # Nothing to do here
23
23
  else
24
+ emails = Produce.config[:itc_users] || []
25
+ user_ids = []
26
+ unless emails.empty?
27
+ UI.message("Verifying users exist before creating app...")
28
+ user_ids = find_user_ids(emails: emails)
29
+ end
30
+
24
31
  UI.success("Creating new app '#{Produce.config[:app_name]}' on App Store Connect")
25
32
 
26
33
  platforms = Produce.config[:platforms] || [Produce.config[:platform]]
@@ -29,7 +36,6 @@ module Produce
29
36
  Spaceship::ConnectAPI::Platform.map(platform)
30
37
  end
31
38
 
32
- # Produce.config[:company_name]
33
39
  # Produce.config[:itc_users]
34
40
  application = Spaceship::ConnectAPI::App.create(
35
41
  name: Produce.config[:app_name],
@@ -37,7 +43,8 @@ module Produce
37
43
  sku: Produce.config[:sku].to_s,
38
44
  primary_locale: language,
39
45
  bundle_id: app_identifier,
40
- platforms: platforms
46
+ platforms: platforms,
47
+ company_name: Produce.config[:company_name]
41
48
  )
42
49
 
43
50
  application = fetch_application
@@ -60,12 +67,32 @@ module Produce
60
67
  application.ensure_version!(Produce.config[:app_version], platform: platform) if Produce.config[:app_version]
61
68
  end
62
69
 
70
+ # Add users to app
71
+ unless user_ids.empty?
72
+ application.add_users(user_ids: user_ids)
73
+ UI.message("Successfuly added #{user_ids.size} #{user_ids.count == 1 ? 'user' : 'users'} to app")
74
+ end
75
+
63
76
  UI.success("Successfully created new app '#{Produce.config[:app_name]}' on App Store Connect with ID #{application.id}")
64
77
  end
65
78
 
66
79
  return application.id
67
80
  end
68
81
 
82
+ def find_user_ids(emails: nil)
83
+ emails ||= []
84
+ users = Spaceship::ConnectAPI::User.all.select do |user|
85
+ emails.include?(user.email)
86
+ end
87
+
88
+ diff_emails = emails - users.map(&:email)
89
+ unless diff_emails.empty?
90
+ raise "Could not find users with emails of: #{diff_emails.join(',')}"
91
+ end
92
+
93
+ return users.map(&:id)
94
+ end
95
+
69
96
  private
70
97
 
71
98
  def platform
@@ -85,13 +112,24 @@ module Produce
85
112
  end
86
113
 
87
114
  # Makes sure to get the value for the language
88
- # Instead of using the user's value `UK English` spaceship should send
89
- # `English_UK` to the server
115
+ # Instead of using the user's value `UK English` spaceship should send `en-UK`
90
116
  def language
91
117
  @language = Produce.config[:language]
92
118
 
93
119
  unless FastlaneCore::Languages::ALL_LANGUAGES.include?(@language)
94
- UI.user_error!("Please enter one of available languages: #{FastlaneCore::Languages::ALL_LANGUAGES}")
120
+ mapped_language = Spaceship::Tunes::LanguageConverter.from_standard_to_itc_locale(@language)
121
+ if mapped_language.to_s.empty?
122
+ message = [
123
+ "Sending language name is deprecated. Could not map '#{@language}' to a locale.",
124
+ "Please enter one of available languages: #{FastlaneCore::Languages::ALL_LANGUAGES}"
125
+ ].join("\n")
126
+ UI.user_error!(message)
127
+ end
128
+
129
+ UI.deprecated("Sending language name is deprecated. '#{@language}' has been mapped to '#{mapped_language}'.")
130
+ UI.deprecated("Please enter one of available languages: #{FastlaneCore::Languages::ALL_LANGUAGES}")
131
+
132
+ @language = mapped_language
95
133
  end
96
134
 
97
135
  return @language
@@ -194,15 +194,16 @@ module Spaceship
194
194
  self.new(cookie: another_client.instance_variable_get(:@cookie), current_team_id: another_client.team_id)
195
195
  end
196
196
 
197
- def initialize(cookie: nil, current_team_id: nil)
197
+ def initialize(cookie: nil, current_team_id: nil, timeout: nil)
198
198
  options = {
199
199
  request: {
200
- timeout: (ENV["SPACESHIP_TIMEOUT"] || 300).to_i,
201
- open_timeout: (ENV["SPACESHIP_TIMEOUT"] || 300).to_i
200
+ timeout: (ENV["SPACESHIP_TIMEOUT"] || timeout || 300).to_i,
201
+ open_timeout: (ENV["SPACESHIP_TIMEOUT"] || timeout || 300).to_i
202
202
  }
203
203
  }
204
204
  @current_team_id = current_team_id
205
205
  @cookie = cookie || HTTP::CookieJar.new
206
+
206
207
  @client = Faraday.new(self.class.hostname, options) do |c|
207
208
  c.response(:json, content_type: /\bjson$/)
208
209
  c.response(:xml, content_type: /\bxml$/)
@@ -1,6 +1,7 @@
1
1
  require 'spaceship/connect_api/model'
2
2
  require 'spaceship/connect_api/response'
3
3
  require 'spaceship/connect_api/token'
4
+ require 'spaceship/connect_api/file_uploader'
4
5
 
5
6
  require 'spaceship/connect_api/provisioning/provisioning'
6
7
  require 'spaceship/connect_api/testflight/testflight'
@@ -35,6 +36,8 @@ require 'spaceship/connect_api/models/age_rating_declaration'
35
36
  require 'spaceship/connect_api/models/app_category'
36
37
  require 'spaceship/connect_api/models/app_info'
37
38
  require 'spaceship/connect_api/models/app_info_localization'
39
+ require 'spaceship/connect_api/models/app_preview_set'
40
+ require 'spaceship/connect_api/models/app_preview'
38
41
  require 'spaceship/connect_api/models/app_price'
39
42
  require 'spaceship/connect_api/models/app_price_tier'
40
43
  require 'spaceship/connect_api/models/app_review_attachment'
@@ -47,6 +50,7 @@ require 'spaceship/connect_api/models/app_store_version_phased_release'
47
50
  require 'spaceship/connect_api/models/app_store_version'
48
51
  require 'spaceship/connect_api/models/idfa_declaration'
49
52
  require 'spaceship/connect_api/models/reset_ratings_request'
53
+ require 'spaceship/connect_api/models/territory'
50
54
 
51
55
  module Spaceship
52
56
  class ConnectAPI
@@ -84,7 +88,7 @@ module Spaceship
84
88
  case platform.to_sym
85
89
  when :appletvos, :tvos
86
90
  return Spaceship::ConnectAPI::Platform::TV_OS
87
- when :osx, :macos
91
+ when :osx, :macos, :mac
88
92
  return Spaceship::ConnectAPI::Platform::MAC_OS
89
93
  when :ios
90
94
  return Spaceship::ConnectAPI::Platform::IOS
@@ -13,7 +13,7 @@ module Spaceship
13
13
  # Instantiates a client with cookie session or a JWT token.
14
14
  def initialize(cookie: nil, current_team_id: nil, token: nil)
15
15
  if token.nil?
16
- super(cookie: cookie, current_team_id: current_team_id)
16
+ super(cookie: cookie, current_team_id: current_team_id, timeout: 1200)
17
17
  else
18
18
  options = {
19
19
  request: {
@@ -78,46 +78,76 @@ module Spaceship
78
78
  end
79
79
 
80
80
  def get(url_or_path, params = nil)
81
- response = request(:get) do |req|
82
- req.url(url_or_path)
83
- req.options.params_encoder = Faraday::NestedParamsEncoder
84
- req.params = params if params
85
- req.headers['Content-Type'] = 'application/json'
81
+ response = with_asc_retry do
82
+ request(:get) do |req|
83
+ req.url(url_or_path)
84
+ req.options.params_encoder = Faraday::NestedParamsEncoder
85
+ req.params = params if params
86
+ req.headers['Content-Type'] = 'application/json'
87
+ end
86
88
  end
87
89
  handle_response(response)
88
90
  end
89
91
 
90
92
  def post(url_or_path, body)
91
- response = request(:post) do |req|
92
- req.url(url_or_path)
93
- req.body = body.to_json
94
- req.headers['Content-Type'] = 'application/json'
93
+ response = with_asc_retry do
94
+ request(:post) do |req|
95
+ req.url(url_or_path)
96
+ req.body = body.to_json
97
+ req.headers['Content-Type'] = 'application/json'
98
+ end
95
99
  end
96
100
  handle_response(response)
97
101
  end
98
102
 
99
103
  def patch(url_or_path, body)
100
- response = request(:patch) do |req|
101
- req.url(url_or_path)
102
- req.body = body.to_json
103
- req.headers['Content-Type'] = 'application/json'
104
+ response = with_asc_retry do
105
+ request(:patch) do |req|
106
+ req.url(url_or_path)
107
+ req.body = body.to_json
108
+ req.headers['Content-Type'] = 'application/json'
109
+ end
104
110
  end
105
111
  handle_response(response)
106
112
  end
107
113
 
108
114
  def delete(url_or_path, params = nil, body = nil)
109
- response = request(:delete) do |req|
110
- req.url(url_or_path)
111
- req.options.params_encoder = Faraday::NestedParamsEncoder if params
112
- req.params = params if params
113
- req.body = body.to_json if body
114
- req.headers['Content-Type'] = 'application/json' if body
115
+ response = with_asc_retry do
116
+ request(:delete) do |req|
117
+ req.url(url_or_path)
118
+ req.options.params_encoder = Faraday::NestedParamsEncoder if params
119
+ req.params = params if params
120
+ req.body = body.to_json if body
121
+ req.headers['Content-Type'] = 'application/json' if body
122
+ end
115
123
  end
116
124
  handle_response(response)
117
125
  end
118
126
 
119
127
  protected
120
128
 
129
+ def with_asc_retry(tries = 5, &_block)
130
+ tries = 1 if Object.const_defined?("SpecHelper")
131
+ response = yield
132
+
133
+ tries -= 1
134
+ status = response.status if response
135
+
136
+ if [500, 504].include?(status)
137
+ msg = "Timeout received! Retrying after 3 seconds (remaining: #{tries})..."
138
+ raise msg
139
+ end
140
+
141
+ return response
142
+ rescue => error
143
+ puts(error) if Spaceship::Globals.verbose?
144
+ if tries.zero?
145
+ return response
146
+ else
147
+ retry
148
+ end
149
+ end
150
+
121
151
  def handle_response(response)
122
152
  if (200...300).cover?(response.status) && (response.body.nil? || response.body.empty?)
123
153
  return
@@ -0,0 +1,98 @@
1
+ require 'faraday' # HTTP Client
2
+ require 'faraday-cookie_jar'
3
+ require 'faraday_middleware'
4
+
5
+ require 'spaceship/globals'
6
+
7
+ module Spaceship
8
+ class ConnectAPI
9
+ module FileUploader
10
+ def self.upload(upload_operations, bytes)
11
+ # {
12
+ # "method": "PUT",
13
+ # "url": "https://some-url-apple-gives-us",
14
+ # "length": 57365,
15
+ # "offset": 0,
16
+ # "requestHeaders": [
17
+ # {
18
+ # "name": "Content-Type",
19
+ # "value": "image/png"
20
+ # }
21
+ # ]
22
+ # }
23
+
24
+ upload_operations.each_with_index do |upload_operation, index|
25
+ headers = {}
26
+ upload_operation["requestHeaders"].each do |hash|
27
+ headers[hash["name"]] = hash["value"]
28
+ end
29
+
30
+ offset = upload_operation["offset"]
31
+ length = upload_operation["length"]
32
+
33
+ puts("Uploading file (part #{index + 1})...") if Spaceship::Globals.verbose?
34
+ with_retry do
35
+ client.send(
36
+ upload_operation["method"].downcase,
37
+ upload_operation["url"],
38
+ bytes[offset, length],
39
+ headers
40
+ )
41
+ end
42
+ end
43
+ puts("Uploading complete!") if Spaceship::Globals.verbose?
44
+ end
45
+
46
+ def self.with_retry(tries = 5, &_block)
47
+ tries = 1 if Object.const_defined?("SpecHelper")
48
+ response = yield
49
+
50
+ tries -= 1
51
+
52
+ unless (200...300).cover?(response.status)
53
+ msg = "Received status of #{response.status}! Retrying after 3 seconds (remaining: #{tries})..."
54
+ raise msg
55
+ end
56
+
57
+ return response
58
+ rescue => error
59
+ puts(error) if Spaceship::Globals.verbose?
60
+ if tries.zero?
61
+ raise "Failed to upload file after retries... Received #{response.status}"
62
+ else
63
+ retry
64
+ end
65
+ end
66
+
67
+ def self.client
68
+ options = {
69
+ request: {
70
+ timeout: (ENV["SPACESHIP_TIMEOUT"] || 300).to_i,
71
+ open_timeout: (ENV["SPACESHIP_TIMEOUT"] || 300).to_i
72
+ }
73
+ }
74
+
75
+ @client ||= Faraday.new(options) do |c|
76
+ c.response(:json, content_type: /\bjson$/)
77
+ c.response(:xml, content_type: /\bxml$/)
78
+ c.response(:plist, content_type: /\bplist$/)
79
+ c.adapter(Faraday.default_adapter)
80
+
81
+ if ENV['SPACESHIP_DEBUG']
82
+ # for debugging only
83
+ # This enables tracking of networking requests using Charles Web Proxy
84
+ c.proxy = "https://127.0.0.1:8888"
85
+ c.ssl[:verify_mode] = OpenSSL::SSL::VERIFY_NONE
86
+ elsif ENV["SPACESHIP_PROXY"]
87
+ c.proxy = ENV["SPACESHIP_PROXY"]
88
+ c.ssl[:verify_mode] = OpenSSL::SSL::VERIFY_NONE if ENV["SPACESHIP_PROXY_SSL_VERIFY_NONE"]
89
+ end
90
+
91
+ if ENV["DEBUG"]
92
+ puts("To run spaceship through a local proxy, use SPACESHIP_DEBUG")
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end