fastlane 2.13.0 → 2.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/credentials_manager/lib/credentials_manager.rb +1 -1
  3. data/fastlane/lib/fastlane/actions/ipa.rb +2 -1
  4. data/fastlane/lib/fastlane/actions/mailgun.rb +15 -2
  5. data/fastlane/lib/fastlane/actions/scan.rb +14 -0
  6. data/fastlane/lib/fastlane/documentation/docs_generator.rb +24 -1
  7. data/fastlane/lib/fastlane/environment_printer.rb +2 -1
  8. data/fastlane/lib/fastlane/fast_file.rb +4 -4
  9. data/fastlane/lib/fastlane/version.rb +1 -1
  10. data/fastlane_core/lib/fastlane_core.rb +1 -1
  11. data/fastlane_core/lib/fastlane_core/configuration/config_item.rb +44 -2
  12. data/fastlane_core/lib/fastlane_core/device_manager.rb +15 -0
  13. data/fastlane_core/lib/fastlane_core/helper.rb +1 -1
  14. data/fastlane_core/lib/fastlane_core/ui/disable_colors.rb +4 -4
  15. data/frameit/lib/frameit/config_parser.rb +8 -13
  16. data/frameit/lib/frameit/editor.rb +3 -2
  17. data/gym/lib/gym/options.rb +4 -2
  18. data/match/README.md +2 -2
  19. data/match/lib/match.rb +5 -19
  20. data/match/lib/match/generator.rb +8 -1
  21. data/match/lib/match/git_helper.rb +3 -1
  22. data/match/lib/match/nuke.rb +18 -14
  23. data/match/lib/match/options.rb +13 -2
  24. data/match/lib/match/runner.rb +20 -8
  25. data/match/lib/match/table_printer.rb +5 -4
  26. data/match/lib/match/utils.rb +12 -8
  27. data/scan/lib/scan/options.rb +24 -1
  28. data/scan/lib/scan/runner.rb +12 -11
  29. data/scan/lib/scan/test_command_generator.rb +10 -2
  30. data/sigh/lib/sigh/download_all.rb +1 -1
  31. data/sigh/lib/sigh/runner.rb +2 -2
  32. data/snapshot/lib/snapshot/options.rb +2 -1
  33. data/snapshot/lib/snapshot/runner.rb +12 -12
  34. data/spaceship/lib/spaceship.rb +1 -0
  35. data/spaceship/lib/spaceship/base.rb +27 -4
  36. data/spaceship/lib/spaceship/client.rb +3 -2
  37. data/spaceship/lib/spaceship/du/du_client.rb +26 -16
  38. data/spaceship/lib/spaceship/portal/app.rb +1 -1
  39. data/spaceship/lib/spaceship/portal/person.rb +53 -0
  40. data/spaceship/lib/spaceship/portal/persons.rb +49 -0
  41. data/spaceship/lib/spaceship/portal/portal.rb +2 -0
  42. data/spaceship/lib/spaceship/portal/portal_client.rb +69 -10
  43. data/spaceship/lib/spaceship/portal/provisioning_profile.rb +29 -1
  44. data/spaceship/lib/spaceship/tunes/application.rb +11 -1
  45. data/spaceship/lib/spaceship/tunes/iap.rb +113 -0
  46. data/spaceship/lib/spaceship/tunes/iap_detail.rb +185 -0
  47. data/spaceship/lib/spaceship/tunes/iap_families.rb +62 -0
  48. data/spaceship/lib/spaceship/tunes/iap_family_details.rb +59 -0
  49. data/spaceship/lib/spaceship/tunes/iap_family_list.rb +33 -0
  50. data/spaceship/lib/spaceship/tunes/iap_list.rb +72 -0
  51. data/spaceship/lib/spaceship/tunes/iap_status.rb +48 -0
  52. data/spaceship/lib/spaceship/tunes/iap_type.rb +45 -0
  53. data/spaceship/lib/spaceship/tunes/tunes.rb +1 -0
  54. data/spaceship/lib/spaceship/tunes/tunes_client.rb +163 -1
  55. metadata +21 -5
@@ -8,6 +8,7 @@ require 'spaceship/helper/net_http_generic_request'
8
8
  require 'spaceship/helper/plist_middleware'
9
9
  require 'spaceship/ui'
10
10
  require 'tmpdir'
11
+ require 'cgi'
11
12
 
12
13
  Faraday::Utils.default_params_encoder = Faraday::FlatParamsEncoder
13
14
 
@@ -78,8 +79,8 @@ module Spaceship
78
79
 
79
80
  [
80
81
  "Apple provided the following error info:",
81
- @error_info['resultString'],
82
- @error_info['userString']
82
+ CGI.unescapeHTML(@error_info['resultString']),
83
+ CGI.unescapeHTML(@error_info['userString'])
83
84
  ].compact.uniq # sometimes 'resultString' and 'userString' are the same value
84
85
  end
85
86
  end
@@ -15,49 +15,59 @@ module Spaceship
15
15
  #####################################################
16
16
 
17
17
  def upload_screenshot(app_version, upload_file, content_provider_id, sso_token_for_image, device, is_messages)
18
- upload_file(app_version, upload_file, '/upload/image', content_provider_id, sso_token_for_image, screenshot_picture_type(device, is_messages))
18
+ upload_file(app_version: app_version, upload_file: upload_file, path: '/upload/image', content_provider_id: content_provider_id, sso_token: sso_token_for_image, du_validation_rule_set: screenshot_picture_type(device, is_messages))
19
+ end
20
+
21
+ def upload_purchase_review_screenshot(app_id, upload_file, content_provider_id, sso_token_for_image)
22
+ upload_file(app_id: app_id, upload_file: upload_file, path: '/upload/image', content_provider_id: content_provider_id, sso_token: sso_token_for_image, du_validation_rule_set: 'MZPFT.SortedScreenShot')
19
23
  end
20
24
 
21
25
  def upload_large_icon(app_version, upload_file, content_provider_id, sso_token_for_image)
22
- upload_file(app_version, upload_file, '/upload/image', content_provider_id, sso_token_for_image, 'MZPFT.LargeApplicationIcon')
26
+ upload_file(app_version: app_version, upload_file: upload_file, path: '/upload/image', content_provider_id: content_provider_id, sso_token: sso_token_for_image, du_validation_rule_set: 'MZPFT.LargeApplicationIcon')
23
27
  end
24
28
 
25
29
  def upload_watch_icon(app_version, upload_file, content_provider_id, sso_token_for_image)
26
- upload_file(app_version, upload_file, '/upload/image', content_provider_id, sso_token_for_image, 'MZPFT.GizmoAppIcon')
30
+ upload_file(app_version: app_version, upload_file: upload_file, path: '/upload/image', content_provider_id: content_provider_id, sso_token: sso_token_for_image, du_validation_rule_set: 'MZPFT.GizmoAppIcon')
27
31
  end
28
32
 
29
33
  def upload_geojson(app_version, upload_file, content_provider_id, sso_token_for_image)
30
- upload_file(app_version, upload_file, '/upload/geo-json', content_provider_id, sso_token_for_image)
34
+ upload_file(app_version: app_version, upload_file: upload_file, path: '/upload/geo-json', content_provider_id: content_provider_id, sso_token: sso_token_for_image)
31
35
  end
32
36
 
33
37
  def upload_trailer(app_version, upload_file, content_provider_id, sso_token_for_video)
34
- upload_file(app_version, upload_file, '/upload/purple-video', content_provider_id, sso_token_for_video)
38
+ upload_file(app_version: app_version, upload_file: upload_file, path: '/upload/purple-video', content_provider_id: content_provider_id, sso_token: sso_token_for_video)
35
39
  end
36
40
 
37
41
  def upload_trailer_preview(app_version, upload_file, content_provider_id, sso_token_for_image)
38
- upload_file(app_version, upload_file, '/upload/app-screenshot-image', content_provider_id, sso_token_for_image)
42
+ upload_file(app_version: app_version, upload_file: upload_file, path: '/upload/app-screenshot-image', content_provider_id: content_provider_id, sso_token: sso_token_for_image)
39
43
  end
40
44
 
41
45
  private
42
46
 
43
- def upload_file(app_version, upload_file, path, content_provider_id, sso_token, du_validation_rule_set = nil)
47
+ def upload_file(app_version: nil, upload_file: nil, path: nil, content_provider_id: nil, sso_token: nil, du_validation_rule_set: nil, app_id: nil)
44
48
  raise "File #{upload_file.file_path} is empty" if upload_file.file_size == 0
45
49
 
46
- version = app_version.version
47
- app_id = app_version.application.apple_id
48
- app_type = app_version.app_type
49
-
50
- referrer = app_version.application.url
50
+ if app_id
51
+ app_id = app_id
52
+ app_type = nil
53
+ version = nil
54
+ referrer = nil
55
+ else
56
+ version = app_version.version
57
+ app_id = app_version.application.apple_id
58
+ app_type = app_version.app_type
59
+ referrer = app_version.application.url
60
+ end
51
61
 
52
62
  r = request(:post) do |req|
53
63
  req.url "#{self.class.hostname}#{path}"
54
64
  req.body = upload_file.bytes
55
65
  req.headers['Accept'] = 'application/json, text/plain, */*'
56
66
  req.headers['Content-Type'] = upload_file.content_type
57
- req.headers['X-Apple-Upload-Referrer'] = referrer
58
- req.headers['Referrer'] = referrer
67
+ req.headers['X-Apple-Upload-Referrer'] = referrer if referrer
68
+ req.headers['Referrer'] = referrer if referrer
59
69
  req.headers['X-Apple-Upload-AppleId'] = app_id
60
- req.headers['X-Apple-Jingle-Correlation-Key'] = "#{app_type}:AdamId=#{app_id}:Version=#{version}"
70
+ req.headers['X-Apple-Jingle-Correlation-Key'] = "#{app_type}:AdamId=#{app_id}:Version=#{version}" if app_type
61
71
  req.headers['X-Apple-Upload-itctoken'] = sso_token
62
72
  req.headers['X-Apple-Upload-ContentProviderId'] = content_provider_id
63
73
  req.headers['X-Original-Filename'] = upload_file.file_name
@@ -67,7 +77,7 @@ module Spaceship
67
77
  end
68
78
 
69
79
  if r.status == 500 and r.body.include?("Server Error")
70
- return upload_file(app_version, upload_file, path, content_provider_id, sso_token, du_validation_rule_set)
80
+ return upload_file(app_version: app_version, upload_file: upload_file, path: path, content_provider_id: content_provider_id, sso_token: sso_token, du_validation_rule_set: du_validation_rule_set, app_id: app_id)
71
81
  end
72
82
 
73
83
  parse_upload_response(r)
@@ -103,7 +103,7 @@ module Spaceship
103
103
  # @return (App) The app you're looking for. This is nil if the app can't be found.
104
104
  def find(bundle_id, mac: false)
105
105
  all(mac: mac).find do |app|
106
- app.bundle_id == bundle_id
106
+ return app if app.bundle_id.casecmp(bundle_id) == 0
107
107
  end
108
108
  end
109
109
  end
@@ -0,0 +1,53 @@
1
+ module Spaceship
2
+ module Portal
3
+ class Person < PortalBase
4
+ # @return (String) Person Id
5
+ attr_accessor :person_id
6
+
7
+ # @return (String) First name
8
+ attr_accessor :firstname
9
+
10
+ # @return (String) Last name
11
+ attr_accessor :lastname
12
+
13
+ # @return (String) Email Address
14
+ attr_accessor :email_address
15
+
16
+ # @return (String) Developer status (active, inactive)
17
+ attr_accessor :developer_status
18
+
19
+ # @return (String) Joined Date
20
+ attr_accessor :joined
21
+
22
+ # @return (String) Id in Team scope
23
+ attr_accessor :team_member_id
24
+
25
+ # @return (String) Role (member, admin or agent)
26
+ attr_accessor :type
27
+
28
+ attr_mapping(
29
+ 'personId' => :person_id,
30
+ 'firstName' => :firstname,
31
+ 'lastName' => :lastname,
32
+ 'email' => :email_address,
33
+ 'developerStatus' => :developer_status,
34
+ 'dateJoined' => :joined,
35
+ 'teamMemberId' => :team_member_id
36
+ )
37
+
38
+ class << self
39
+ def factory(attrs)
40
+ self.new(attrs)
41
+ end
42
+ end
43
+
44
+ def remove!
45
+ client.team_remove_member!(team_member_id)
46
+ end
47
+
48
+ def change_role(role)
49
+ client.team_set_role(team_member_id, role)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,49 @@
1
+ module Spaceship
2
+ module Portal
3
+ class Persons < PortalBase
4
+ class << self
5
+ def all
6
+ members = client.team_members
7
+ all_members = []
8
+ member = factory_member(members["members"], "member")
9
+ admins = factory_member(members["admins"], "admin")
10
+ agent = factory_member(members["agent"], "agent")
11
+
12
+ all_members.concat(member)
13
+ all_members.concat(admins)
14
+ all_members << agent
15
+
16
+ return all_members
17
+ end
18
+
19
+ def factory_member(members, type)
20
+ if members.kind_of?(Hash)
21
+ attrs = members
22
+ attrs[:type] = type
23
+ return Spaceship::Portal::Person.factory(attrs)
24
+ end
25
+ final_members = []
26
+ members.each do |member|
27
+ attrs = member
28
+ attrs[:type] = type
29
+ final_members << Spaceship::Portal::Person.factory(attrs)
30
+ end
31
+ return final_members
32
+ end
33
+
34
+ def find(email)
35
+ all.each do |member|
36
+ if member.email_address == email
37
+ return member
38
+ end
39
+ end
40
+ return nil
41
+ end
42
+
43
+ def invite(email, role)
44
+ client.team_invite(email, role)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -6,3 +6,5 @@ require 'spaceship/portal/certificate'
6
6
  require 'spaceship/portal/device'
7
7
  require 'spaceship/portal/provisioning_profile'
8
8
  require 'spaceship/portal/portal_client'
9
+ require 'spaceship/portal/persons'
10
+ require 'spaceship/portal/person'
@@ -236,6 +236,62 @@ module Spaceship
236
236
  parse_response(r)
237
237
  end
238
238
 
239
+ #####################################################
240
+ # @!group Team
241
+ #####################################################
242
+ def team_members
243
+ response = request(:post) do |req|
244
+ req.url "/services-account/#{PROTOCOL_VERSION}/account/getTeamMembers"
245
+ req.body = {
246
+ teamId: team_id
247
+ }.to_json
248
+ req.headers['Content-Type'] = 'application/json'
249
+ end
250
+ parse_response(response)
251
+ end
252
+
253
+ def team_set_role(team_member_id, role)
254
+ ensure_csrf(Spaceship::Portal::Persons)
255
+ response = request(:post) do |req|
256
+ req.url "/services-account/#{PROTOCOL_VERSION}/account/setTeamMemberRoles"
257
+ req.body = {
258
+ teamId: team_id,
259
+ role: role,
260
+ teamMemberIds: [team_member_id]
261
+ }.to_json
262
+ req.headers['Content-Type'] = 'application/json'
263
+ end
264
+ parse_response(response)
265
+ end
266
+
267
+ def team_remove_member!(team_member_id)
268
+ ensure_csrf(Spaceship::Portal::Persons)
269
+ response = request(:post) do |req|
270
+ req.url "/services-account/#{PROTOCOL_VERSION}/account/removeTeamMembers"
271
+ req.body = {
272
+ teamId: team_id,
273
+ teamMemberIds: [team_member_id]
274
+ }.to_json
275
+ req.headers['Content-Type'] = 'application/json'
276
+ end
277
+ parse_response(response)
278
+ end
279
+
280
+ def team_invite(email, role)
281
+ ensure_csrf(Spaceship::Portal::Persons)
282
+ response = request(:post) do |req|
283
+ req.url "/services-account/#{PROTOCOL_VERSION}/account/sendInvites"
284
+ req.body = {
285
+ invites: [
286
+ { recipientEmail: email, recipientRole: role }
287
+ ],
288
+ teamId: team_id
289
+ }.to_json
290
+ req.headers['Content-Type'] = 'application/json'
291
+ end
292
+ parse_response(response)
293
+ end
294
+
239
295
  #####################################################
240
296
  # @!group Devices
241
297
  #####################################################
@@ -427,20 +483,23 @@ module Spaceship
427
483
  parse_response(r)
428
484
  end
429
485
 
430
- def repair_provisioning_profile!(profile_id, name, distribution_method, app_id, certificate_ids, device_ids, mac: false)
486
+ def repair_provisioning_profile!(profile_id, name, distribution_method, app_id, certificate_ids, device_ids, mac: false, sub_platform: nil)
431
487
  ensure_csrf(Spaceship::ProvisioningProfile) do
432
488
  fetch_csrf_token_for_provisioning
433
489
  end
434
490
 
435
- r = request(:post, "account/#{platform_slug(mac)}/profile/regenProvisioningProfile.action", {
436
- teamId: team_id,
437
- provisioningProfileId: profile_id,
438
- provisioningProfileName: name,
439
- appIdId: app_id,
440
- distributionType: distribution_method,
441
- certificateIds: certificate_ids.join(','),
442
- deviceIds: device_ids
443
- })
491
+ params = {
492
+ teamId: team_id,
493
+ provisioningProfileId: profile_id,
494
+ provisioningProfileName: name,
495
+ appIdId: app_id,
496
+ distributionType: distribution_method,
497
+ certificateIds: certificate_ids.join(','),
498
+ deviceIds: device_ids
499
+ }
500
+ params[:subPlatform] = sub_platform if sub_platform
501
+
502
+ r = request(:post, "account/#{platform_slug(mac)}/profile/regenProvisioningProfile.action", params)
444
503
 
445
504
  parse_response(r, 'provisioningProfile')
446
505
  end
@@ -65,6 +65,11 @@ module Spaceship
65
65
  # "ios"
66
66
  attr_accessor :platform
67
67
 
68
+ # @return (String) The supported sub_platform for this profile
69
+ # @example
70
+ # "tvOS"
71
+ attr_accessor :sub_platform
72
+
68
73
  # No information about this attribute
69
74
  attr_accessor :managing_app
70
75
 
@@ -136,6 +141,7 @@ module Spaceship
136
141
  'type' => :type,
137
142
  'version' => :version,
138
143
  'proProPlatform' => :platform,
144
+ 'proProSubPlatform' => :sub_platform,
139
145
  'managingApp' => :managing_app,
140
146
  'appId' => :app
141
147
  })
@@ -206,6 +212,8 @@ module Spaceship
206
212
  app = Spaceship::App.find(bundle_id, mac: mac)
207
213
  raise "Could not find app with bundle id '#{bundle_id}'" unless app
208
214
 
215
+ raise "Invalid sub_platform #{sub_platform}, valid values are tvOS" if !sub_platform.nil? and sub_platform != 'tvOS'
216
+
209
217
  # Fill in sensible default values
210
218
  name ||= [bundle_id, self.pretty_type].join(' ')
211
219
 
@@ -278,6 +286,20 @@ module Spaceship
278
286
  end
279
287
  end
280
288
 
289
+ # @return (Array) Returns all profiles registered for this account
290
+ # If you're calling this from a subclass (like AdHoc), this will
291
+ # only return the profiles that are of this type
292
+ def all_tvos
293
+ profiles = all(mac: false)
294
+ tv_os_profiles = []
295
+ profiles.each do |tv_os_profile|
296
+ if tv_os_profile.tvos?
297
+ tv_os_profiles << tv_os_profile
298
+ end
299
+ end
300
+ return tv_os_profiles
301
+ end
302
+
281
303
  # @return (Array) Returns an array of provisioning
282
304
  # profiles matching the bundle identifier
283
305
  # Returns [] if no profiles were found
@@ -385,7 +407,8 @@ module Spaceship
385
407
  app.app_id,
386
408
  certificates.map(&:id),
387
409
  devices.map(&:id),
388
- mac: mac?
410
+ mac: mac?,
411
+ sub_platform: tvos? ? 'tvOS' : nil
389
412
  )
390
413
  end
391
414
 
@@ -425,6 +448,11 @@ module Spaceship
425
448
  platform == 'mac'
426
449
  end
427
450
 
451
+ # @return (Bool) Is this a tvos provisioning profile?
452
+ def tvos?
453
+ sub_platform == 'tvOS'
454
+ end
455
+
428
456
  def devices
429
457
  fetch_details
430
458
 
@@ -63,7 +63,7 @@ module Spaceship
63
63
  # as either the App ID or the bundle identifier
64
64
  def find(identifier, mac: false)
65
65
  all.find do |app|
66
- (app.apple_id == identifier.to_s || app.bundle_id == identifier) &&
66
+ ((app.apple_id && app.apple_id.casecmp(identifier.to_s) == 0) || (app.bundle_id && app.bundle_id.casecmp(identifier.to_s) == 0)) &&
67
67
  app.version_sets.any? { |v| (mac ? ["osx"] : ["ios", "appletvos"]).include?(v.platform) }
68
68
  end
69
69
  end
@@ -249,6 +249,16 @@ module Spaceship
249
249
  client.availability(self.apple_id)
250
250
  end
251
251
 
252
+ #####################################################
253
+ # @!group in_app_purchases
254
+ #####################################################
255
+ # Get base In-App-Purchases object
256
+ def in_app_purchases
257
+ attrs = {}
258
+ attrs[:application] = self
259
+ Tunes::IAP.factory(attrs)
260
+ end
261
+
252
262
  #####################################################
253
263
  # @!group Builds
254
264
  #####################################################
@@ -0,0 +1,113 @@
1
+ require 'spaceship/tunes/iap_list'
2
+ require 'spaceship/tunes/iap_detail'
3
+ require 'spaceship/tunes/iap_status'
4
+ require 'spaceship/tunes/iap_type'
5
+ require 'spaceship/tunes/iap_family_list'
6
+ require 'spaceship/tunes/iap_families'
7
+ require 'spaceship/tunes/iap_family_details'
8
+ require 'spaceship/tunes/iap_families'
9
+
10
+ module Spaceship
11
+ module Tunes
12
+ class IAP < TunesBase
13
+ # @return (Spaceship::Tunes::Application) A reference to the application
14
+ attr_accessor :application
15
+
16
+ class << self
17
+ def factory(attrs)
18
+ return self.new(attrs)
19
+ end
20
+ end
21
+
22
+ # @return (Spaceship::Tunes::IAPFamilies) A reference to the familie list
23
+ def families
24
+ attrs = {}
25
+ attrs[:application] = self.application
26
+ Tunes::IAPFamilies.factory(attrs)
27
+ end
28
+
29
+ # Creates a new In-App-Purchese on iTunes Connect
30
+ # if the In-App-Purchase already exists an exception is raised. Spaceship::TunesClient::ITunesConnectError
31
+ # @param type (String): The Type of the in-app-purchase (Spaceship::Tunes::IAPType::CONSUMABLE,Spaceship::Tunes::IAPType::NON_CONSUMABLE,Spaceship::Tunes::IAPType::RECURRING,Spaceship::Tunes::IAPType::NON_RENEW_SUBSCRIPTION)
32
+ # @param versions (Hash): a Hash of the languages
33
+ # @example: {
34
+ # 'de-DE': {
35
+ # name: "Name shown in AppStore",
36
+ # description: "Description of the In app Purchase"
37
+ #
38
+ # }
39
+ # }
40
+ # @param reference_name (String): iTC Reference Name
41
+ # @param product_id (String): A unique ID for your in-app-purchase
42
+ # @param bundle_id (String): The bundle ID must match the one you used in Xcode. It
43
+ # @param cleared_for_sale (Boolean): Is this In-App-Purchase Cleared for Sale
44
+ # @param review_notes (String): Review Notes
45
+ # @param review_screenshot (String): Path to the screenshot (should be 640x940 PNG)
46
+ # @param pricing_intervals (Hash): a Hash of the languages
47
+ # @example:
48
+ # [
49
+ # {
50
+ # country: "WW",
51
+ # begin_date: nil,
52
+ # end_date: nil,
53
+ # tier: 1
54
+ # }
55
+ # ]
56
+ # @param family_id (String) Only used on RECURRING purchases, assigns the In-App-Purchase to a specific familie
57
+ # @param subscription_free_trial (String) Free Trial duration (1w,1m,3m....)
58
+ # @param subscription_duration (String) 1w,1m.....
59
+ def create!(type: "consumable",
60
+ versions: nil,
61
+ reference_name: nil,
62
+ product_id: nil,
63
+ cleared_for_sale: true,
64
+ review_notes: nil,
65
+ review_screenshot: nil,
66
+ pricing_intervals: nil,
67
+ family_id: nil,
68
+ subscription_free_trial: nil,
69
+ subscription_duration: nil)
70
+
71
+ client.create_iap!(app_id: self.application.apple_id,
72
+ type: type,
73
+ versions: versions,
74
+ reference_name: reference_name,
75
+ product_id: product_id,
76
+ cleared_for_sale: cleared_for_sale,
77
+ review_notes: review_notes,
78
+ review_screenshot: review_screenshot,
79
+ pricing_intervals: pricing_intervals,
80
+ family_id: family_id,
81
+ subscription_duration: subscription_duration,
82
+ subscription_free_trial: subscription_free_trial)
83
+ end
84
+
85
+ # find a specific product
86
+ # @param product_id (String) Product Id
87
+ def find(product_id)
88
+ all.each do |product|
89
+ if product.product_id == product_id
90
+ return product
91
+ end
92
+ end
93
+ return nil
94
+ end
95
+
96
+ # return all available In-App-Purchase's of current app
97
+ # this is not paged inside iTC-API so if you have a lot if IAP's (2k+)
98
+ # it might take some time to load, same as it takes when you load the list via iTunes Connect
99
+ def all(include_deleted: false)
100
+ r = client.iaps(app_id: self.application.apple_id)
101
+ return_iaps = []
102
+ r.each do |product|
103
+ attrs = product
104
+ attrs[:application] = self.application
105
+ loaded_iap = Tunes::IAPList.factory(attrs)
106
+ next if loaded_iap.status == "deleted" && !include_deleted
107
+ return_iaps << loaded_iap
108
+ end
109
+ return_iaps
110
+ end
111
+ end
112
+ end
113
+ end