fastlane 2.13.0 → 2.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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