fastlane 2.150.0.rc1 → 2.150.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,16 +9,18 @@ module Fastlane
9
9
  Spaceship::Tunes.select_team
10
10
  UI.message("Login successful")
11
11
 
12
- app = Spaceship::Application.find(params[:app_identifier]) || Spaceship::Application.find(params[:app_identifier], mac: true)
12
+ app = Spaceship::ConnectAPI::App.find(params[:app_identifier])
13
13
  UI.user_error!("Couldn't find app with identifier #{params[:app_identifier]}") if app.nil?
14
14
 
15
15
  version_number = params[:version]
16
- platform = params[:platform]
16
+ platform = Spaceship::ConnectAPI::Platform.map(params[:platform])
17
+
17
18
  unless version_number
18
19
  # Automatically fetch the latest version
19
20
  UI.message("Fetching the latest version for this app")
20
- if app.edit_version(platform: platform) && app.edit_version(platform: platform).version
21
- version_number = app.edit_version(platform: platform).version
21
+ edit_version = app.get_edit_app_store_version(platform: platform)
22
+ if edit_version
23
+ version_number = edit_version.version_string
22
24
  else
23
25
  UI.message("You have to specify a new version number: ")
24
26
  version_number = STDIN.gets.strip
@@ -42,31 +44,32 @@ module Fastlane
42
44
 
43
45
  UI.important("Going to update the changelog to:\n\n#{changelog}\n\n")
44
46
 
45
- if (v = app.edit_version(platform: platform))
46
- if v.version != version_number
47
+ edit_version = app.get_edit_app_store_version(platform: platform)
48
+ if edit_version
49
+ if edit_version.version_string != version_number
47
50
  # Version is already there, make sure it matches the one we want to create
48
- UI.message("Changing existing version number from '#{v.version}' to '#{version_number}'")
49
- v.version = version_number
50
- v.save!
51
+ UI.message("Changing existing version number from '#{edit_version.version_string}' to '#{version_number}'")
52
+ edit_version = edit_version.update(attributes: {
53
+ versionString: version_number
54
+ })
51
55
  else
52
- UI.message("Updating changelog for existing version #{v.version}")
56
+ UI.message("Updating changelog for existing version #{edit_version.version_string}")
53
57
  end
54
58
  else
55
59
  UI.message("Creating the new version: #{version_number}")
56
- app.create_version!(version_number)
57
- app = Spaceship::Application.find(params[:app_identifier]) # Replace with .reload method once available
58
- v = app.edit_version(platform: platform)
60
+ attributes = { versionString: version_number, platform: platform }
61
+ edit_version = Spaceship::ConnectAPI.post_app_store_version(app_id: app.id, attributes: attributes).first
59
62
  end
60
63
 
61
- v.release_notes.languages.each do |lang|
62
- v.release_notes[lang] = changelog
64
+ localizations = edit_version.get_app_store_version_localizations
65
+ localizations.each do |localization|
66
+ UI.message("Updating changelog for the '#{localization.locale}'")
67
+ localization.update(attributes: {
68
+ whatsNew: changelog
69
+ })
63
70
  end
64
71
 
65
- UI.message("Found and updated changelog for the following languages: #{v.release_notes.languages.join(', ')}")
66
- UI.message("Uploading changes to App Store Connect...")
67
- v.save!
68
-
69
- UI.success("👼 Successfully pushed the new changelog to #{v.url}")
72
+ UI.success("👼 Successfully pushed the new changelog to for #{edit_version.version_string}")
70
73
  end
71
74
 
72
75
  def self.default_changelog_path
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
- VERSION = '2.150.0.rc1'.freeze
2
+ VERSION = '2.150.0.rc2'.freeze
3
3
  DESCRIPTION = "The easiest way to automate beta deployments and releases for your iOS and Android apps".freeze
4
4
  MINIMUM_XCODE_RELEASE = "7.0".freeze
5
5
  RUBOCOP_REQUIREMENT = '0.49.1'.freeze
@@ -85,13 +85,24 @@ module Produce
85
85
  end
86
86
 
87
87
  # 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
88
+ # Instead of using the user's value `UK English` spaceship should send `en-UK`
90
89
  def language
91
90
  @language = Produce.config[:language]
92
91
 
93
92
  unless FastlaneCore::Languages::ALL_LANGUAGES.include?(@language)
94
- UI.user_error!("Please enter one of available languages: #{FastlaneCore::Languages::ALL_LANGUAGES}")
93
+ mapped_language = Spaceship::Tunes::LanguageConverter.from_standard_to_itc_locale(@language)
94
+ if mapped_language.to_s.empty?
95
+ message = [
96
+ "Sending language name is deprecated. Could not map '#{@language}' to a locale.",
97
+ "Please enter one of available languages: #{FastlaneCore::Languages::ALL_LANGUAGES}"
98
+ ].join("\n")
99
+ UI.user_error!(message)
100
+ end
101
+
102
+ UI.deprecated("Sending language name is deprecated. '#{@language}' has been mapped to '#{mapped_language}'.")
103
+ UI.deprecated("Please enter one of available languages: #{FastlaneCore::Languages::ALL_LANGUAGES}")
104
+
105
+ @language = mapped_language
95
106
  end
96
107
 
97
108
  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 [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,66 @@
1
+ require 'faraday' # HTTP Client
2
+ require 'faraday-cookie_jar'
3
+ require 'faraday_middleware'
4
+
5
+ module Spaceship
6
+ class ConnectAPI
7
+ module FileUploader
8
+ def self.upload(upload_operation, payload)
9
+ # {
10
+ # "method": "PUT",
11
+ # "url": "https://some-url-apple-gives-us",
12
+ # "length": 57365,
13
+ # "offset": 0,
14
+ # "requestHeaders": [
15
+ # {
16
+ # "name": "Content-Type",
17
+ # "value": "image/png"
18
+ # }
19
+ # ]
20
+ # }
21
+
22
+ headers = {}
23
+ upload_operation["requestHeaders"].each do |hash|
24
+ headers[hash["name"]] = hash["value"]
25
+ end
26
+
27
+ client.send(
28
+ upload_operation["method"].downcase,
29
+ upload_operation["url"],
30
+ payload,
31
+ headers
32
+ )
33
+ end
34
+
35
+ def self.client
36
+ options = {
37
+ request: {
38
+ timeout: (ENV["SPACESHIP_TIMEOUT"] || 300).to_i,
39
+ open_timeout: (ENV["SPACESHIP_TIMEOUT"] || 300).to_i
40
+ }
41
+ }
42
+
43
+ @client ||= Faraday.new(options) do |c|
44
+ c.response(:json, content_type: /\bjson$/)
45
+ c.response(:xml, content_type: /\bxml$/)
46
+ c.response(:plist, content_type: /\bplist$/)
47
+ c.adapter(Faraday.default_adapter)
48
+
49
+ if ENV['SPACESHIP_DEBUG']
50
+ # for debugging only
51
+ # This enables tracking of networking requests using Charles Web Proxy
52
+ c.proxy = "https://127.0.0.1:8888"
53
+ c.ssl[:verify_mode] = OpenSSL::SSL::VERIFY_NONE
54
+ elsif ENV["SPACESHIP_PROXY"]
55
+ c.proxy = ENV["SPACESHIP_PROXY"]
56
+ c.ssl[:verify_mode] = OpenSSL::SSL::VERIFY_NONE if ENV["SPACESHIP_PROXY_SSL_VERIFY_NONE"]
57
+ end
58
+
59
+ if ENV["DEBUG"]
60
+ puts("To run spaceship through a local proxy, use SPACESHIP_DEBUG")
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -91,10 +91,14 @@ module Spaceship
91
91
 
92
92
  def self.map_value_from_itc(key, value)
93
93
  if ["gamblingAndContests", "unrestrictedWebAccess"].include?(key)
94
- return LEGACY_BOOLEAN_VALUE_ITC_MAP[value]
94
+ new_value = LEGACY_BOOLEAN_VALUE_ITC_MAP[value]
95
+ return value if new_value.nil?
96
+ return new_value
95
97
  else
96
98
  return LEGACY_RATING_VALUE_ITC_MAP[value]
97
99
  end
100
+
101
+ return value
98
102
  end
99
103
 
100
104
  #
@@ -55,15 +55,24 @@ module Spaceship
55
55
  end
56
56
 
57
57
  def self.create(name: nil, version_string: nil, sku: nil, primary_locale: nil, bundle_id: nil, platforms: nil)
58
- Spaceship::ConnectAPI.post_app(name: name, version_string: version_string, sku: sku, primary_locale: primary_locale, bundle_id: bundle_id, platforms: platforms)
58
+ Spaceship::ConnectAPI.post_app(
59
+ name: name,
60
+ version_string: version_string,
61
+ sku: sku, primary_locale:
62
+ primary_locale,
63
+ bundle_id: bundle_id,
64
+ platforms: platforms,
65
+ territory_ids: territory_ids,
66
+ available_in_new_territories: available_in_new_territories
67
+ )
59
68
  end
60
69
 
61
70
  def self.get(app_id: nil, includes: "appStoreVersions")
62
71
  return Spaceship::ConnectAPI.get_app(app_id: app_id, includes: includes).first
63
72
  end
64
73
 
65
- def update(attributes: nil)
66
- return Spaceship::ConnectAPI.patch_app(app_id: id, attributes: attributes)
74
+ def update(attributes: nil, app_price_tier_id: nil, territory_ids: nil)
75
+ return Spaceship::ConnectAPI.patch_app(app_id: id, attributes: attributes, app_price_tier_id: app_price_tier_id, territory_ids: territory_ids)
67
76
  end
68
77
 
69
78
  #
@@ -95,11 +104,6 @@ module Spaceship
95
104
  return resp.to_models
96
105
  end
97
106
 
98
- def update_app_price_tier(app_price_tier_id: nil)
99
- resp = Spaceship::ConnectAPI.patch_app_app_prices(app_id: id, app_price_tier_id: app_price_tier_id)
100
- return resp.first
101
- end
102
-
103
107
  #
104
108
  # App Store Versions
105
109
  #
@@ -38,19 +38,11 @@ module Spaceship
38
38
  #
39
39
 
40
40
  def update(filter: {}, includes: nil, limit: nil, sort: nil)
41
- Spaceship::ConnectAPI.patch_app_info(app_info_id: id)
41
+ Spaceship::ConnectAPI.patch_app_info(app_info_id: id).first
42
42
  end
43
43
 
44
- def update_categories(primary_category_id: nil, secondary_category_id: nil, primary_subcategory_one_id: nil, primary_subcategory_two_id: nil, secondary_subcategory_one_id: nil, secondary_subcategory_two_id: nil)
45
- Spaceship::ConnectAPI.patch_app_info_categories(
46
- app_info_id: id,
47
- primary_category_id: primary_category_id,
48
- secondary_category_id: secondary_category_id,
49
- primary_subcategory_one_id: primary_subcategory_one_id,
50
- primary_subcategory_two_id: primary_subcategory_two_id,
51
- secondary_subcategory_one_id: secondary_subcategory_one_id,
52
- secondary_subcategory_two_id: secondary_subcategory_two_id
53
- )
44
+ def update_categories(category_id_map: nil)
45
+ Spaceship::ConnectAPI.patch_app_info_categories(app_info_id: id, category_id_map: category_id_map).first
54
46
  end
55
47
 
56
48
  def delete!(filter: {}, includes: nil, limit: nil, sort: nil)
@@ -0,0 +1,77 @@
1
+ require_relative '../model'
2
+ require_relative '../file_uploader'
3
+
4
+ module Spaceship
5
+ class ConnectAPI
6
+ class AppPreview
7
+ include Spaceship::ConnectAPI::Model
8
+
9
+ attr_accessor :file_size
10
+ attr_accessor :file_name
11
+ attr_accessor :source_file_checksum
12
+ attr_accessor :preview_frame_time_code
13
+ attr_accessor :mime_type
14
+ attr_accessor :video_url
15
+ attr_accessor :preview_image
16
+ attr_accessor :upload_operations
17
+ attr_accessor :asset_deliver_state
18
+ attr_accessor :upload
19
+
20
+ attr_mapping({
21
+ "fileSize" => "file_size",
22
+ "fileName" => "file_name",
23
+ "sourceFileChecksum" => "source_file_checksum",
24
+ "previewFrameTimeCode" => "preview_frame_time_code",
25
+ "mimeType" => "mime_type",
26
+ "videoUrl" => "video_url",
27
+ "previewImage" => "preview_image",
28
+ "uploadOperations" => "upload_operations",
29
+ "assetDeliveryState" => "asset_delivery_state",
30
+ "uploaded" => "uploaded"
31
+ })
32
+
33
+ def self.type
34
+ return "appPreviews"
35
+ end
36
+
37
+ #
38
+ # API
39
+ #
40
+
41
+ def self.create(app_preview_set_id: nil, path: nil)
42
+ require 'faraday'
43
+
44
+ filename = File.basename(path)
45
+ filesize = File.size(path)
46
+ payload = File.binread(path)
47
+
48
+ post_attributes = {
49
+ fileSize: filesize,
50
+ fileName: filename
51
+ }
52
+
53
+ post_resp = Spaceship::ConnectAPI.post_app_preview(
54
+ app_preview_set_id: app_preview_set_id,
55
+ attributes: post_attributes
56
+ ).to_models.first
57
+
58
+ upload_operation = post_resp.upload_operations.first
59
+ Spaceship::ConnectAPI::FileUploader.upload(upload_operation, payload)
60
+
61
+ patch_attributes = {
62
+ uploaded: true,
63
+ sourceFileChecksum: "checksum-holder"
64
+ }
65
+
66
+ Spaceship::ConnectAPI.patch_app_preview(
67
+ app_preview_id: post_resp.id,
68
+ attributes: patch_attributes
69
+ ).to_models.first
70
+ end
71
+
72
+ def delete!(filter: {}, includes: nil, limit: nil, sort: nil)
73
+ Spaceship::ConnectAPI.delete_app_preview(app_preview_id: id)
74
+ end
75
+ end
76
+ end
77
+ end