fastlane_hotfix 2.165.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 (868) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -0
  3. data/LICENSE +21 -0
  4. data/README.md +208 -0
  5. data/bin/bin-proxy +19 -0
  6. data/bin/fastlane +23 -0
  7. data/cert/README.md +17 -0
  8. data/cert/lib/cert.rb +4 -0
  9. data/cert/lib/cert/commands_generator.rb +60 -0
  10. data/cert/lib/cert/module.rb +16 -0
  11. data/cert/lib/cert/options.rb +132 -0
  12. data/cert/lib/cert/runner.rb +239 -0
  13. data/credentials_manager/README.md +64 -0
  14. data/credentials_manager/lib/credentials_manager.rb +7 -0
  15. data/credentials_manager/lib/credentials_manager/account_manager.rb +157 -0
  16. data/credentials_manager/lib/credentials_manager/appfile_config.rb +196 -0
  17. data/credentials_manager/lib/credentials_manager/cli.rb +69 -0
  18. data/deliver/README.md +17 -0
  19. data/deliver/lib/assets/DeliverfileDefault +3 -0
  20. data/deliver/lib/assets/DeliverfileDefault.swift +13 -0
  21. data/deliver/lib/assets/ScreenshotsHelp +7 -0
  22. data/deliver/lib/assets/summary.html.erb +299 -0
  23. data/deliver/lib/deliver.rb +15 -0
  24. data/deliver/lib/deliver/app_screenshot.rb +354 -0
  25. data/deliver/lib/deliver/app_screenshot_iterator.rb +95 -0
  26. data/deliver/lib/deliver/commands_generator.rb +190 -0
  27. data/deliver/lib/deliver/detect_values.rb +102 -0
  28. data/deliver/lib/deliver/download_screenshots.rb +76 -0
  29. data/deliver/lib/deliver/generate_summary.rb +13 -0
  30. data/deliver/lib/deliver/html_generator.rb +78 -0
  31. data/deliver/lib/deliver/languages.rb +7 -0
  32. data/deliver/lib/deliver/loader.rb +55 -0
  33. data/deliver/lib/deliver/module.rb +18 -0
  34. data/deliver/lib/deliver/options.rb +465 -0
  35. data/deliver/lib/deliver/queue_worker.rb +49 -0
  36. data/deliver/lib/deliver/runner.rb +233 -0
  37. data/deliver/lib/deliver/setup.rb +199 -0
  38. data/deliver/lib/deliver/submit_for_review.rb +214 -0
  39. data/deliver/lib/deliver/upload_metadata.rb +688 -0
  40. data/deliver/lib/deliver/upload_price_tier.rb +40 -0
  41. data/deliver/lib/deliver/upload_screenshots.rb +333 -0
  42. data/fastlane/README.md +11 -0
  43. data/fastlane/lib/assets/ActionDetails.md.erb +106 -0
  44. data/fastlane/lib/assets/Actions.md.erb +43 -0
  45. data/fastlane/lib/assets/AppfileTemplate +6 -0
  46. data/fastlane/lib/assets/AppfileTemplate.swift +7 -0
  47. data/fastlane/lib/assets/AppfileTemplateAndroid +2 -0
  48. data/fastlane/lib/assets/DefaultFastfileTemplate +20 -0
  49. data/fastlane/lib/assets/DefaultFastfileTemplate.swift +13 -0
  50. data/fastlane/lib/assets/completions/completion.bash +23 -0
  51. data/fastlane/lib/assets/completions/completion.fish +39 -0
  52. data/fastlane/lib/assets/completions/completion.sh +12 -0
  53. data/fastlane/lib/assets/completions/completion.zsh +23 -0
  54. data/fastlane/lib/assets/custom_action_template.rb +82 -0
  55. data/fastlane/lib/assets/mailgun_html_template.erb +142 -0
  56. data/fastlane/lib/assets/report_template.xml.erb +15 -0
  57. data/fastlane/lib/assets/s3_html_template.erb +105 -0
  58. data/fastlane/lib/assets/s3_plist_template.erb +31 -0
  59. data/fastlane/lib/assets/s3_version_template.erb +4 -0
  60. data/fastlane/lib/fastlane.rb +53 -0
  61. data/fastlane/lib/fastlane/action.rb +198 -0
  62. data/fastlane/lib/fastlane/action_collector.rb +35 -0
  63. data/fastlane/lib/fastlane/actions/README.md +5 -0
  64. data/fastlane/lib/fastlane/actions/actions_helper.rb +185 -0
  65. data/fastlane/lib/fastlane/actions/adb.rb +78 -0
  66. data/fastlane/lib/fastlane/actions/adb_devices.rb +71 -0
  67. data/fastlane/lib/fastlane/actions/add_extra_platforms.rb +45 -0
  68. data/fastlane/lib/fastlane/actions/add_git_tag.rb +122 -0
  69. data/fastlane/lib/fastlane/actions/app_store_build_number.rb +249 -0
  70. data/fastlane/lib/fastlane/actions/app_store_connect_api_key.rb +134 -0
  71. data/fastlane/lib/fastlane/actions/appaloosa.rb +266 -0
  72. data/fastlane/lib/fastlane/actions/appetize.rb +188 -0
  73. data/fastlane/lib/fastlane/actions/appetize_viewing_url_generator.rb +146 -0
  74. data/fastlane/lib/fastlane/actions/appium.rb +206 -0
  75. data/fastlane/lib/fastlane/actions/appledoc.rb +226 -0
  76. data/fastlane/lib/fastlane/actions/appstore.rb +14 -0
  77. data/fastlane/lib/fastlane/actions/apteligent.rb +105 -0
  78. data/fastlane/lib/fastlane/actions/artifactory.rb +157 -0
  79. data/fastlane/lib/fastlane/actions/automatic_code_signing.rb +226 -0
  80. data/fastlane/lib/fastlane/actions/backup_file.rb +41 -0
  81. data/fastlane/lib/fastlane/actions/backup_xcarchive.rb +135 -0
  82. data/fastlane/lib/fastlane/actions/badge.rb +155 -0
  83. data/fastlane/lib/fastlane/actions/build_and_upload_to_appetize.rb +107 -0
  84. data/fastlane/lib/fastlane/actions/build_android_app.rb +14 -0
  85. data/fastlane/lib/fastlane/actions/build_app.rb +165 -0
  86. data/fastlane/lib/fastlane/actions/build_ios_app.rb +47 -0
  87. data/fastlane/lib/fastlane/actions/build_mac_app.rb +46 -0
  88. data/fastlane/lib/fastlane/actions/bundle_install.rb +156 -0
  89. data/fastlane/lib/fastlane/actions/capture_android_screenshots.rb +63 -0
  90. data/fastlane/lib/fastlane/actions/capture_ios_screenshots.rb +61 -0
  91. data/fastlane/lib/fastlane/actions/capture_screenshots.rb +14 -0
  92. data/fastlane/lib/fastlane/actions/carthage.rb +230 -0
  93. data/fastlane/lib/fastlane/actions/cert.rb +14 -0
  94. data/fastlane/lib/fastlane/actions/changelog_from_git_commits.rb +197 -0
  95. data/fastlane/lib/fastlane/actions/chatwork.rb +94 -0
  96. data/fastlane/lib/fastlane/actions/check_app_store_metadata.rb +54 -0
  97. data/fastlane/lib/fastlane/actions/clean_build_artifacts.rb +72 -0
  98. data/fastlane/lib/fastlane/actions/clean_cocoapods_cache.rb +52 -0
  99. data/fastlane/lib/fastlane/actions/clear_derived_data.rb +70 -0
  100. data/fastlane/lib/fastlane/actions/clipboard.rb +52 -0
  101. data/fastlane/lib/fastlane/actions/cloc.rb +89 -0
  102. data/fastlane/lib/fastlane/actions/cocoapods.rb +170 -0
  103. data/fastlane/lib/fastlane/actions/commit_github_file.rb +186 -0
  104. data/fastlane/lib/fastlane/actions/commit_version_bump.rb +301 -0
  105. data/fastlane/lib/fastlane/actions/copy_artifacts.rb +114 -0
  106. data/fastlane/lib/fastlane/actions/crashlytics.rb +211 -0
  107. data/fastlane/lib/fastlane/actions/create_app_on_managed_play_store.rb +174 -0
  108. data/fastlane/lib/fastlane/actions/create_app_online.rb +75 -0
  109. data/fastlane/lib/fastlane/actions/create_keychain.rb +177 -0
  110. data/fastlane/lib/fastlane/actions/create_pull_request.rb +265 -0
  111. data/fastlane/lib/fastlane/actions/danger.rb +131 -0
  112. data/fastlane/lib/fastlane/actions/debug.rb +32 -0
  113. data/fastlane/lib/fastlane/actions/default_platform.rb +47 -0
  114. data/fastlane/lib/fastlane/actions/delete_keychain.rb +68 -0
  115. data/fastlane/lib/fastlane/actions/deliver.rb +14 -0
  116. data/fastlane/lib/fastlane/actions/deploygate.rb +210 -0
  117. data/fastlane/lib/fastlane/actions/device_grid/README.md +157 -0
  118. data/fastlane/lib/fastlane/actions/docs/build_app.md +245 -0
  119. data/fastlane/lib/fastlane/actions/docs/capture_android_screenshots.md +333 -0
  120. data/fastlane/lib/fastlane/actions/docs/capture_ios_screenshots.md +371 -0
  121. data/fastlane/lib/fastlane/actions/docs/check_app_store_metadata.md +103 -0
  122. data/fastlane/lib/fastlane/actions/docs/create_app_online.md +282 -0
  123. data/fastlane/lib/fastlane/actions/docs/frame_screenshots.md +349 -0
  124. data/fastlane/lib/fastlane/actions/docs/get_certificates.md +86 -0
  125. data/fastlane/lib/fastlane/actions/docs/get_provisioning_profile.md +223 -0
  126. data/fastlane/lib/fastlane/actions/docs/get_push_certificate.md +134 -0
  127. data/fastlane/lib/fastlane/actions/docs/run_tests.md +151 -0
  128. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +573 -0
  129. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +725 -0
  130. data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +203 -0
  131. data/fastlane/lib/fastlane/actions/docs/upload_to_testflight.md +250 -0
  132. data/fastlane/lib/fastlane/actions/dotgpg_environment.rb +57 -0
  133. data/fastlane/lib/fastlane/actions/download.rb +76 -0
  134. data/fastlane/lib/fastlane/actions/download_dsyms.rb +369 -0
  135. data/fastlane/lib/fastlane/actions/download_from_play_store.rb +61 -0
  136. data/fastlane/lib/fastlane/actions/dsym_zip.rb +93 -0
  137. data/fastlane/lib/fastlane/actions/echo.rb +14 -0
  138. data/fastlane/lib/fastlane/actions/ensure_bundle_exec.rb +59 -0
  139. data/fastlane/lib/fastlane/actions/ensure_env_vars.rb +58 -0
  140. data/fastlane/lib/fastlane/actions/ensure_git_branch.rb +69 -0
  141. data/fastlane/lib/fastlane/actions/ensure_git_status_clean.rb +92 -0
  142. data/fastlane/lib/fastlane/actions/ensure_no_debug_code.rb +135 -0
  143. data/fastlane/lib/fastlane/actions/ensure_xcode_version.rb +125 -0
  144. data/fastlane/lib/fastlane/actions/environment_variable.rb +77 -0
  145. data/fastlane/lib/fastlane/actions/erb.rb +96 -0
  146. data/fastlane/lib/fastlane/actions/fastlane_version.rb +15 -0
  147. data/fastlane/lib/fastlane/actions/flock.rb +82 -0
  148. data/fastlane/lib/fastlane/actions/frame_screenshots.rb +64 -0
  149. data/fastlane/lib/fastlane/actions/frameit.rb +14 -0
  150. data/fastlane/lib/fastlane/actions/gcovr.rb +163 -0
  151. data/fastlane/lib/fastlane/actions/get_build_number.rb +106 -0
  152. data/fastlane/lib/fastlane/actions/get_build_number_repository.rb +120 -0
  153. data/fastlane/lib/fastlane/actions/get_certificates.rb +77 -0
  154. data/fastlane/lib/fastlane/actions/get_github_release.rb +166 -0
  155. data/fastlane/lib/fastlane/actions/get_info_plist_value.rb +78 -0
  156. data/fastlane/lib/fastlane/actions/get_ipa_info_plist_value.rb +82 -0
  157. data/fastlane/lib/fastlane/actions/get_managed_play_store_publishing_rights.rb +120 -0
  158. data/fastlane/lib/fastlane/actions/get_provisioning_profile.rb +101 -0
  159. data/fastlane/lib/fastlane/actions/get_push_certificate.rb +87 -0
  160. data/fastlane/lib/fastlane/actions/get_version_number.rb +200 -0
  161. data/fastlane/lib/fastlane/actions/git_add.rb +93 -0
  162. data/fastlane/lib/fastlane/actions/git_branch.rb +61 -0
  163. data/fastlane/lib/fastlane/actions/git_commit.rb +80 -0
  164. data/fastlane/lib/fastlane/actions/git_pull.rb +64 -0
  165. data/fastlane/lib/fastlane/actions/git_submodule_update.rb +52 -0
  166. data/fastlane/lib/fastlane/actions/git_tag_exists.rb +74 -0
  167. data/fastlane/lib/fastlane/actions/github_api.rb +262 -0
  168. data/fastlane/lib/fastlane/actions/google_play_track_release_names.rb +74 -0
  169. data/fastlane/lib/fastlane/actions/google_play_track_version_codes.rb +77 -0
  170. data/fastlane/lib/fastlane/actions/gradle.rb +329 -0
  171. data/fastlane/lib/fastlane/actions/gym.rb +10 -0
  172. data/fastlane/lib/fastlane/actions/hg_add_tag.rb +48 -0
  173. data/fastlane/lib/fastlane/actions/hg_commit_version_bump.rb +183 -0
  174. data/fastlane/lib/fastlane/actions/hg_ensure_clean_status.rb +53 -0
  175. data/fastlane/lib/fastlane/actions/hg_push.rb +64 -0
  176. data/fastlane/lib/fastlane/actions/hipchat.rb +200 -0
  177. data/fastlane/lib/fastlane/actions/hockey.rb +406 -0
  178. data/fastlane/lib/fastlane/actions/ifttt.rb +96 -0
  179. data/fastlane/lib/fastlane/actions/import.rb +49 -0
  180. data/fastlane/lib/fastlane/actions/import_certificate.rb +77 -0
  181. data/fastlane/lib/fastlane/actions/import_from_git.rb +83 -0
  182. data/fastlane/lib/fastlane/actions/increment_build_number.rb +117 -0
  183. data/fastlane/lib/fastlane/actions/increment_version_number.rb +180 -0
  184. data/fastlane/lib/fastlane/actions/install_on_device.rb +95 -0
  185. data/fastlane/lib/fastlane/actions/install_provisioning_profile.rb +58 -0
  186. data/fastlane/lib/fastlane/actions/install_xcode_plugin.rb +91 -0
  187. data/fastlane/lib/fastlane/actions/installr.rb +132 -0
  188. data/fastlane/lib/fastlane/actions/ipa.rb +246 -0
  189. data/fastlane/lib/fastlane/actions/is_ci.rb +51 -0
  190. data/fastlane/lib/fastlane/actions/jazzy.rb +56 -0
  191. data/fastlane/lib/fastlane/actions/jira.rb +115 -0
  192. data/fastlane/lib/fastlane/actions/lane_context.rb +60 -0
  193. data/fastlane/lib/fastlane/actions/last_git_commit.rb +58 -0
  194. data/fastlane/lib/fastlane/actions/last_git_tag.rb +60 -0
  195. data/fastlane/lib/fastlane/actions/latest_testflight_build_number.rb +155 -0
  196. data/fastlane/lib/fastlane/actions/lcov.rb +102 -0
  197. data/fastlane/lib/fastlane/actions/mailgun.rb +197 -0
  198. data/fastlane/lib/fastlane/actions/make_changelog_from_jenkins.rb +81 -0
  199. data/fastlane/lib/fastlane/actions/match.rb +14 -0
  200. data/fastlane/lib/fastlane/actions/min_fastlane_version.rb +57 -0
  201. data/fastlane/lib/fastlane/actions/modify_services.rb +173 -0
  202. data/fastlane/lib/fastlane/actions/nexus_upload.rb +230 -0
  203. data/fastlane/lib/fastlane/actions/notarize.rb +193 -0
  204. data/fastlane/lib/fastlane/actions/notification.rb +75 -0
  205. data/fastlane/lib/fastlane/actions/notify.rb +40 -0
  206. data/fastlane/lib/fastlane/actions/number_of_commits.rb +75 -0
  207. data/fastlane/lib/fastlane/actions/oclint.rb +269 -0
  208. data/fastlane/lib/fastlane/actions/onesignal.rb +186 -0
  209. data/fastlane/lib/fastlane/actions/opt_out_crash_reporting.rb +33 -0
  210. data/fastlane/lib/fastlane/actions/opt_out_usage.rb +40 -0
  211. data/fastlane/lib/fastlane/actions/pem.rb +14 -0
  212. data/fastlane/lib/fastlane/actions/pilot.rb +14 -0
  213. data/fastlane/lib/fastlane/actions/pod_lib_lint.rb +189 -0
  214. data/fastlane/lib/fastlane/actions/pod_push.rb +173 -0
  215. data/fastlane/lib/fastlane/actions/podio_item.rb +217 -0
  216. data/fastlane/lib/fastlane/actions/precheck.rb +14 -0
  217. data/fastlane/lib/fastlane/actions/println.rb +14 -0
  218. data/fastlane/lib/fastlane/actions/produce.rb +14 -0
  219. data/fastlane/lib/fastlane/actions/prompt.rb +119 -0
  220. data/fastlane/lib/fastlane/actions/push_git_tags.rb +76 -0
  221. data/fastlane/lib/fastlane/actions/push_to_git_remote.rb +127 -0
  222. data/fastlane/lib/fastlane/actions/puts.rb +68 -0
  223. data/fastlane/lib/fastlane/actions/read_podspec.rb +90 -0
  224. data/fastlane/lib/fastlane/actions/recreate_schemes.rb +46 -0
  225. data/fastlane/lib/fastlane/actions/register_device.rb +151 -0
  226. data/fastlane/lib/fastlane/actions/register_devices.rb +214 -0
  227. data/fastlane/lib/fastlane/actions/reset_git_repo.rb +121 -0
  228. data/fastlane/lib/fastlane/actions/reset_simulator_contents.rb +92 -0
  229. data/fastlane/lib/fastlane/actions/resign.rb +132 -0
  230. data/fastlane/lib/fastlane/actions/restore_file.rb +44 -0
  231. data/fastlane/lib/fastlane/actions/rocket.rb +83 -0
  232. data/fastlane/lib/fastlane/actions/rsync.rb +74 -0
  233. data/fastlane/lib/fastlane/actions/ruby_version.rb +56 -0
  234. data/fastlane/lib/fastlane/actions/run_tests.rb +114 -0
  235. data/fastlane/lib/fastlane/actions/s3.rb +174 -0
  236. data/fastlane/lib/fastlane/actions/say.rb +56 -0
  237. data/fastlane/lib/fastlane/actions/scan.rb +14 -0
  238. data/fastlane/lib/fastlane/actions/scp.rb +114 -0
  239. data/fastlane/lib/fastlane/actions/screengrab.rb +14 -0
  240. data/fastlane/lib/fastlane/actions/set_build_number_repository.rb +76 -0
  241. data/fastlane/lib/fastlane/actions/set_changelog.rb +204 -0
  242. data/fastlane/lib/fastlane/actions/set_github_release.rb +274 -0
  243. data/fastlane/lib/fastlane/actions/set_info_plist_value.rb +92 -0
  244. data/fastlane/lib/fastlane/actions/set_pod_key.rb +78 -0
  245. data/fastlane/lib/fastlane/actions/setup_ci.rb +132 -0
  246. data/fastlane/lib/fastlane/actions/setup_circle_ci.rb +58 -0
  247. data/fastlane/lib/fastlane/actions/setup_jenkins.rb +202 -0
  248. data/fastlane/lib/fastlane/actions/setup_travis.rb +57 -0
  249. data/fastlane/lib/fastlane/actions/sh.rb +71 -0
  250. data/fastlane/lib/fastlane/actions/sigh.rb +14 -0
  251. data/fastlane/lib/fastlane/actions/skip_docs.rb +52 -0
  252. data/fastlane/lib/fastlane/actions/slack.rb +288 -0
  253. data/fastlane/lib/fastlane/actions/slather.rb +329 -0
  254. data/fastlane/lib/fastlane/actions/snapshot.rb +14 -0
  255. data/fastlane/lib/fastlane/actions/sonar.rb +177 -0
  256. data/fastlane/lib/fastlane/actions/spaceship_logs.rb +135 -0
  257. data/fastlane/lib/fastlane/actions/spaceship_stats.rb +73 -0
  258. data/fastlane/lib/fastlane/actions/splunkmint.rb +156 -0
  259. data/fastlane/lib/fastlane/actions/spm.rb +138 -0
  260. data/fastlane/lib/fastlane/actions/ssh.rb +162 -0
  261. data/fastlane/lib/fastlane/actions/supply.rb +14 -0
  262. data/fastlane/lib/fastlane/actions/swiftlint.rb +240 -0
  263. data/fastlane/lib/fastlane/actions/sync_code_signing.rb +109 -0
  264. data/fastlane/lib/fastlane/actions/team_id.rb +42 -0
  265. data/fastlane/lib/fastlane/actions/team_name.rb +42 -0
  266. data/fastlane/lib/fastlane/actions/testfairy.rb +285 -0
  267. data/fastlane/lib/fastlane/actions/testflight.rb +14 -0
  268. data/fastlane/lib/fastlane/actions/tryouts.rb +149 -0
  269. data/fastlane/lib/fastlane/actions/twitter.rb +89 -0
  270. data/fastlane/lib/fastlane/actions/typetalk.rb +93 -0
  271. data/fastlane/lib/fastlane/actions/unlock_keychain.rb +132 -0
  272. data/fastlane/lib/fastlane/actions/update_app_group_identifiers.rb +91 -0
  273. data/fastlane/lib/fastlane/actions/update_app_identifier.rb +124 -0
  274. data/fastlane/lib/fastlane/actions/update_code_signing_settings.rb +203 -0
  275. data/fastlane/lib/fastlane/actions/update_fastlane.rb +137 -0
  276. data/fastlane/lib/fastlane/actions/update_icloud_container_identifiers.rb +99 -0
  277. data/fastlane/lib/fastlane/actions/update_info_plist.rb +143 -0
  278. data/fastlane/lib/fastlane/actions/update_keychain_access_groups.rb +94 -0
  279. data/fastlane/lib/fastlane/actions/update_plist.rb +115 -0
  280. data/fastlane/lib/fastlane/actions/update_project_code_signing.rb +76 -0
  281. data/fastlane/lib/fastlane/actions/update_project_provisioning.rb +173 -0
  282. data/fastlane/lib/fastlane/actions/update_project_team.rb +95 -0
  283. data/fastlane/lib/fastlane/actions/update_urban_airship_configuration.rb +91 -0
  284. data/fastlane/lib/fastlane/actions/update_url_schemes.rb +123 -0
  285. data/fastlane/lib/fastlane/actions/upload_symbols_to_crashlytics.rb +231 -0
  286. data/fastlane/lib/fastlane/actions/upload_symbols_to_sentry.rb +165 -0
  287. data/fastlane/lib/fastlane/actions/upload_to_app_store.rb +67 -0
  288. data/fastlane/lib/fastlane/actions/upload_to_play_store.rb +80 -0
  289. data/fastlane/lib/fastlane/actions/upload_to_play_store_internal_app_sharing.rb +78 -0
  290. data/fastlane/lib/fastlane/actions/upload_to_testflight.rb +119 -0
  291. data/fastlane/lib/fastlane/actions/validate_play_store_json_key.rb +104 -0
  292. data/fastlane/lib/fastlane/actions/verify_build.rb +199 -0
  293. data/fastlane/lib/fastlane/actions/verify_pod_keys.rb +67 -0
  294. data/fastlane/lib/fastlane/actions/verify_xcode.rb +159 -0
  295. data/fastlane/lib/fastlane/actions/version_bump_podspec.rb +105 -0
  296. data/fastlane/lib/fastlane/actions/version_get_podspec.rb +71 -0
  297. data/fastlane/lib/fastlane/actions/xcode_install.rb +105 -0
  298. data/fastlane/lib/fastlane/actions/xcode_select.rb +68 -0
  299. data/fastlane/lib/fastlane/actions/xcode_server_get_assets.rb +312 -0
  300. data/fastlane/lib/fastlane/actions/xcodebuild.rb +641 -0
  301. data/fastlane/lib/fastlane/actions/xcov.rb +66 -0
  302. data/fastlane/lib/fastlane/actions/xctool.rb +55 -0
  303. data/fastlane/lib/fastlane/actions/xcversion.rb +55 -0
  304. data/fastlane/lib/fastlane/actions/zip.rb +120 -0
  305. data/fastlane/lib/fastlane/auto_complete.rb +82 -0
  306. data/fastlane/lib/fastlane/boolean.rb +5 -0
  307. data/fastlane/lib/fastlane/cli_tools_distributor.rb +207 -0
  308. data/fastlane/lib/fastlane/command_line_handler.rb +49 -0
  309. data/fastlane/lib/fastlane/commands_generator.rb +369 -0
  310. data/fastlane/lib/fastlane/configuration_helper.rb +26 -0
  311. data/fastlane/lib/fastlane/core_ext/bundler_monkey_patch.rb +14 -0
  312. data/fastlane/lib/fastlane/documentation/actions_list.rb +214 -0
  313. data/fastlane/lib/fastlane/documentation/docs_generator.rb +89 -0
  314. data/fastlane/lib/fastlane/documentation/markdown_docs_generator.rb +228 -0
  315. data/fastlane/lib/fastlane/environment_printer.rb +303 -0
  316. data/fastlane/lib/fastlane/erb_template_helper.rb +30 -0
  317. data/fastlane/lib/fastlane/fast_file.rb +439 -0
  318. data/fastlane/lib/fastlane/fastlane_require.rb +75 -0
  319. data/fastlane/lib/fastlane/features.rb +4 -0
  320. data/fastlane/lib/fastlane/helper/README.md +29 -0
  321. data/fastlane/lib/fastlane/helper/adb_helper.rb +66 -0
  322. data/fastlane/lib/fastlane/helper/crashlytics_helper.rb +157 -0
  323. data/fastlane/lib/fastlane/helper/dotenv_helper.rb +50 -0
  324. data/fastlane/lib/fastlane/helper/gem_helper.rb +26 -0
  325. data/fastlane/lib/fastlane/helper/git_helper.rb +137 -0
  326. data/fastlane/lib/fastlane/helper/gradle_helper.rb +62 -0
  327. data/fastlane/lib/fastlane/helper/lane_helper.rb +13 -0
  328. data/fastlane/lib/fastlane/helper/podspec_helper.rb +75 -0
  329. data/fastlane/lib/fastlane/helper/s3_client_helper.rb +78 -0
  330. data/fastlane/lib/fastlane/helper/sh_helper.rb +134 -0
  331. data/fastlane/lib/fastlane/helper/xcodeproj_helper.rb +12 -0
  332. data/fastlane/lib/fastlane/helper/xcversion_helper.rb +25 -0
  333. data/fastlane/lib/fastlane/junit_generator.rb +27 -0
  334. data/fastlane/lib/fastlane/lane.rb +97 -0
  335. data/fastlane/lib/fastlane/lane_list.rb +137 -0
  336. data/fastlane/lib/fastlane/lane_manager.rb +130 -0
  337. data/fastlane/lib/fastlane/lane_manager_base.rb +92 -0
  338. data/fastlane/lib/fastlane/markdown_table_formatter.rb +62 -0
  339. data/fastlane/lib/fastlane/new_action.rb +47 -0
  340. data/fastlane/lib/fastlane/one_off.rb +45 -0
  341. data/fastlane/lib/fastlane/other_action.rb +29 -0
  342. data/fastlane/lib/fastlane/plugins/plugin_fetcher.rb +55 -0
  343. data/fastlane/lib/fastlane/plugins/plugin_generator.rb +86 -0
  344. data/fastlane/lib/fastlane/plugins/plugin_generator_ui.rb +19 -0
  345. data/fastlane/lib/fastlane/plugins/plugin_info.rb +49 -0
  346. data/fastlane/lib/fastlane/plugins/plugin_info_collector.rb +159 -0
  347. data/fastlane/lib/fastlane/plugins/plugin_manager.rb +399 -0
  348. data/fastlane/lib/fastlane/plugins/plugin_search.rb +46 -0
  349. data/fastlane/lib/fastlane/plugins/plugin_update_manager.rb +70 -0
  350. data/fastlane/lib/fastlane/plugins/plugins.rb +12 -0
  351. data/fastlane/lib/fastlane/plugins/template/%gem_name%.gemspec.erb +35 -0
  352. data/fastlane/lib/fastlane/plugins/template/.circleci/config.yml +43 -0
  353. data/fastlane/lib/fastlane/plugins/template/.github/workflows/test.yml +29 -0
  354. data/fastlane/lib/fastlane/plugins/template/.gitignore +12 -0
  355. data/fastlane/lib/fastlane/plugins/template/.rspec +5 -0
  356. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +188 -0
  357. data/fastlane/lib/fastlane/plugins/template/.travis.yml +4 -0
  358. data/fastlane/lib/fastlane/plugins/template/Gemfile +6 -0
  359. data/fastlane/lib/fastlane/plugins/template/LICENSE.erb +21 -0
  360. data/fastlane/lib/fastlane/plugins/template/README.md.erb +52 -0
  361. data/fastlane/lib/fastlane/plugins/template/Rakefile +9 -0
  362. data/fastlane/lib/fastlane/plugins/template/fastlane/Fastfile.erb +3 -0
  363. data/fastlane/lib/fastlane/plugins/template/fastlane/Pluginfile.erb +1 -0
  364. data/fastlane/lib/fastlane/plugins/template/lib/fastlane/plugin/%plugin_name%.rb.erb +16 -0
  365. data/fastlane/lib/fastlane/plugins/template/lib/fastlane/plugin/%plugin_name%/actions/%plugin_name%_action.rb.erb +47 -0
  366. data/fastlane/lib/fastlane/plugins/template/lib/fastlane/plugin/%plugin_name%/helper/%plugin_name%_helper.rb.erb +16 -0
  367. data/fastlane/lib/fastlane/plugins/template/lib/fastlane/plugin/%plugin_name%/version.rb.erb +5 -0
  368. data/fastlane/lib/fastlane/plugins/template/spec/%plugin_name%_action_spec.rb.erb +9 -0
  369. data/fastlane/lib/fastlane/plugins/template/spec/spec_helper.rb.erb +15 -0
  370. data/fastlane/lib/fastlane/runner.rb +378 -0
  371. data/fastlane/lib/fastlane/server/action_command.rb +61 -0
  372. data/fastlane/lib/fastlane/server/action_command_return.rb +14 -0
  373. data/fastlane/lib/fastlane/server/command_executor.rb +7 -0
  374. data/fastlane/lib/fastlane/server/command_parser.rb +44 -0
  375. data/fastlane/lib/fastlane/server/control_command.rb +23 -0
  376. data/fastlane/lib/fastlane/server/json_return_value_processor.rb +72 -0
  377. data/fastlane/lib/fastlane/server/socket_server.rb +238 -0
  378. data/fastlane/lib/fastlane/server/socket_server_action_command_executor.rb +101 -0
  379. data/fastlane/lib/fastlane/setup/setup.rb +355 -0
  380. data/fastlane/lib/fastlane/setup/setup_android.rb +97 -0
  381. data/fastlane/lib/fastlane/setup/setup_ios.rb +504 -0
  382. data/fastlane/lib/fastlane/shells.rb +6 -0
  383. data/fastlane/lib/fastlane/supported_platforms.rb +28 -0
  384. data/fastlane/lib/fastlane/swift_fastlane_api_generator.rb +477 -0
  385. data/fastlane/lib/fastlane/swift_fastlane_function.rb +419 -0
  386. data/fastlane/lib/fastlane/swift_lane_manager.rb +296 -0
  387. data/fastlane/lib/fastlane/swift_runner_upgrader.rb +210 -0
  388. data/fastlane/lib/fastlane/tools.rb +33 -0
  389. data/fastlane/lib/fastlane/version.rb +6 -0
  390. data/fastlane/swift/Actions.swift +16 -0
  391. data/fastlane/swift/Appfile.swift +15 -0
  392. data/fastlane/swift/ArgumentProcessor.swift +89 -0
  393. data/fastlane/swift/ControlCommand.swift +74 -0
  394. data/fastlane/swift/Deliverfile.swift +20 -0
  395. data/fastlane/swift/DeliverfileProtocol.swift +259 -0
  396. data/fastlane/swift/Fastfile.swift +16 -0
  397. data/fastlane/swift/Fastlane.swift +9402 -0
  398. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.pbxproj +434 -0
  399. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  400. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  401. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/xcshareddata/xcschemes/FastlaneRunner.xcscheme +97 -0
  402. data/fastlane/swift/FastlaneSwiftRunner/README.txt +10 -0
  403. data/fastlane/swift/Gymfile.swift +20 -0
  404. data/fastlane/swift/GymfileProtocol.swift +187 -0
  405. data/fastlane/swift/LaneFileProtocol.swift +149 -0
  406. data/fastlane/swift/MainProcess.swift +77 -0
  407. data/fastlane/swift/Matchfile.swift +20 -0
  408. data/fastlane/swift/MatchfileProtocol.swift +187 -0
  409. data/fastlane/swift/Plugins.swift +16 -0
  410. data/fastlane/swift/Precheckfile.swift +20 -0
  411. data/fastlane/swift/PrecheckfileProtocol.swift +51 -0
  412. data/fastlane/swift/RubyCommand.swift +157 -0
  413. data/fastlane/swift/RubyCommandable.swift +43 -0
  414. data/fastlane/swift/Runner.swift +275 -0
  415. data/fastlane/swift/RunnerArgument.swift +20 -0
  416. data/fastlane/swift/Scanfile.swift +20 -0
  417. data/fastlane/swift/ScanfileProtocol.swift +263 -0
  418. data/fastlane/swift/Screengrabfile.swift +20 -0
  419. data/fastlane/swift/ScreengrabfileProtocol.swift +99 -0
  420. data/fastlane/swift/Snapshotfile.swift +20 -0
  421. data/fastlane/swift/SnapshotfileProtocol.swift +187 -0
  422. data/fastlane/swift/SocketClient.swift +327 -0
  423. data/fastlane/swift/SocketClientDelegateProtocol.swift +21 -0
  424. data/fastlane/swift/SocketResponse.swift +82 -0
  425. data/fastlane/swift/formatting/Brewfile +1 -0
  426. data/fastlane/swift/formatting/Brewfile.lock.json +47 -0
  427. data/fastlane/swift/formatting/Rakefile +18 -0
  428. data/fastlane/swift/main.swift +47 -0
  429. data/fastlane/swift/upgrade_manifest.json +1 -0
  430. data/fastlane_core/README.md +79 -0
  431. data/fastlane_core/lib/assets/XMLTemplate.xml.erb +12 -0
  432. data/fastlane_core/lib/fastlane_core.rb +46 -0
  433. data/fastlane_core/lib/fastlane_core/analytics/action_completion_context.rb +34 -0
  434. data/fastlane_core/lib/fastlane_core/analytics/action_launch_context.rb +38 -0
  435. data/fastlane_core/lib/fastlane_core/analytics/analytics_event_builder.rb +23 -0
  436. data/fastlane_core/lib/fastlane_core/analytics/analytics_ingester_client.rb +54 -0
  437. data/fastlane_core/lib/fastlane_core/analytics/analytics_session.rb +70 -0
  438. data/fastlane_core/lib/fastlane_core/analytics/app_identifier_guesser.rb +64 -0
  439. data/fastlane_core/lib/fastlane_core/android_package_name_guesser.rb +79 -0
  440. data/fastlane_core/lib/fastlane_core/build_watcher.rb +96 -0
  441. data/fastlane_core/lib/fastlane_core/cert_checker.rb +144 -0
  442. data/fastlane_core/lib/fastlane_core/command_executor.rb +100 -0
  443. data/fastlane_core/lib/fastlane_core/configuration/commander_generator.rb +103 -0
  444. data/fastlane_core/lib/fastlane_core/configuration/config_item.rb +321 -0
  445. data/fastlane_core/lib/fastlane_core/configuration/configuration.rb +332 -0
  446. data/fastlane_core/lib/fastlane_core/configuration/configuration_file.rb +182 -0
  447. data/fastlane_core/lib/fastlane_core/core_ext/cfpropertylist.rb +23 -0
  448. data/fastlane_core/lib/fastlane_core/core_ext/shellwords.rb +63 -0
  449. data/fastlane_core/lib/fastlane_core/core_ext/string.rb +17 -0
  450. data/fastlane_core/lib/fastlane_core/device_manager.rb +374 -0
  451. data/fastlane_core/lib/fastlane_core/env.rb +9 -0
  452. data/fastlane_core/lib/fastlane_core/fastlane_folder.rb +72 -0
  453. data/fastlane_core/lib/fastlane_core/fastlane_pty.rb +57 -0
  454. data/fastlane_core/lib/fastlane_core/feature/feature.rb +51 -0
  455. data/fastlane_core/lib/fastlane_core/features.rb +4 -0
  456. data/fastlane_core/lib/fastlane_core/globals.rb +27 -0
  457. data/fastlane_core/lib/fastlane_core/helper.rb +437 -0
  458. data/fastlane_core/lib/fastlane_core/ios_app_identifier_guesser.rb +112 -0
  459. data/fastlane_core/lib/fastlane_core/ipa_file_analyser.rb +63 -0
  460. data/fastlane_core/lib/fastlane_core/ipa_upload_package_builder.rb +52 -0
  461. data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +595 -0
  462. data/fastlane_core/lib/fastlane_core/keychain_importer.rb +120 -0
  463. data/fastlane_core/lib/fastlane_core/languages.rb +16 -0
  464. data/fastlane_core/lib/fastlane_core/module.rb +31 -0
  465. data/fastlane_core/lib/fastlane_core/pkg_file_analyser.rb +51 -0
  466. data/fastlane_core/lib/fastlane_core/pkg_upload_package_builder.rb +48 -0
  467. data/fastlane_core/lib/fastlane_core/print_table.rb +131 -0
  468. data/fastlane_core/lib/fastlane_core/project.rb +509 -0
  469. data/fastlane_core/lib/fastlane_core/provisioning_profile.rb +124 -0
  470. data/fastlane_core/lib/fastlane_core/string_filters.rb +51 -0
  471. data/fastlane_core/lib/fastlane_core/swag.rb +85 -0
  472. data/fastlane_core/lib/fastlane_core/tag_version.rb +31 -0
  473. data/fastlane_core/lib/fastlane_core/test_parser.rb +107 -0
  474. data/fastlane_core/lib/fastlane_core/ui/disable_colors.rb +17 -0
  475. data/fastlane_core/lib/fastlane_core/ui/errors.rb +1 -0
  476. data/fastlane_core/lib/fastlane_core/ui/errors/fastlane_common_error.rb +19 -0
  477. data/fastlane_core/lib/fastlane_core/ui/errors/fastlane_crash.rb +11 -0
  478. data/fastlane_core/lib/fastlane_core/ui/errors/fastlane_error.rb +25 -0
  479. data/fastlane_core/lib/fastlane_core/ui/errors/fastlane_exception.rb +19 -0
  480. data/fastlane_core/lib/fastlane_core/ui/errors/fastlane_shell_error.rb +11 -0
  481. data/fastlane_core/lib/fastlane_core/ui/fastlane_runner.rb +294 -0
  482. data/fastlane_core/lib/fastlane_core/ui/github_issue_inspector_reporter.rb +62 -0
  483. data/fastlane_core/lib/fastlane_core/ui/implementations/shell.rb +159 -0
  484. data/fastlane_core/lib/fastlane_core/ui/interface.rb +205 -0
  485. data/fastlane_core/lib/fastlane_core/ui/ui.rb +26 -0
  486. data/fastlane_core/lib/fastlane_core/update_checker/changelog.rb +37 -0
  487. data/fastlane_core/lib/fastlane_core/update_checker/update_checker.rb +109 -0
  488. data/frameit/README.md +17 -0
  489. data/frameit/lib/assets/empty.png +0 -0
  490. data/frameit/lib/frameit.rb +13 -0
  491. data/frameit/lib/frameit/commands_generator.rb +140 -0
  492. data/frameit/lib/frameit/config_parser.rb +136 -0
  493. data/frameit/lib/frameit/dependency_checker.rb +22 -0
  494. data/frameit/lib/frameit/device.rb +90 -0
  495. data/frameit/lib/frameit/device_types.rb +144 -0
  496. data/frameit/lib/frameit/editor.rb +560 -0
  497. data/frameit/lib/frameit/frame_downloader.rb +85 -0
  498. data/frameit/lib/frameit/mac_editor.rb +35 -0
  499. data/frameit/lib/frameit/module.rb +42 -0
  500. data/frameit/lib/frameit/offsets.rb +28 -0
  501. data/frameit/lib/frameit/options.rb +112 -0
  502. data/frameit/lib/frameit/runner.rb +97 -0
  503. data/frameit/lib/frameit/screenshot.rb +134 -0
  504. data/frameit/lib/frameit/strings_parser.rb +46 -0
  505. data/frameit/lib/frameit/template_finder.rb +45 -0
  506. data/frameit/lib/frameit/trim_box.rb +35 -0
  507. data/gym/README.md +17 -0
  508. data/gym/lib/assets/GymfileTemplate +13 -0
  509. data/gym/lib/assets/GymfileTemplate.swift +13 -0
  510. data/gym/lib/assets/wrap_xcodebuild/xcbuild-safe.sh +61 -0
  511. data/gym/lib/gym.rb +9 -0
  512. data/gym/lib/gym/code_signing_mapping.rb +210 -0
  513. data/gym/lib/gym/commands_generator.rb +78 -0
  514. data/gym/lib/gym/detect_values.rb +206 -0
  515. data/gym/lib/gym/error_handler.rb +306 -0
  516. data/gym/lib/gym/generators/README.md +1 -0
  517. data/gym/lib/gym/generators/build_command_generator.rb +147 -0
  518. data/gym/lib/gym/generators/package_command_generator.rb +68 -0
  519. data/gym/lib/gym/generators/package_command_generator_xcode7.rb +232 -0
  520. data/gym/lib/gym/manager.rb +22 -0
  521. data/gym/lib/gym/module.rb +74 -0
  522. data/gym/lib/gym/options.rb +286 -0
  523. data/gym/lib/gym/runner.rb +365 -0
  524. data/gym/lib/gym/xcode.rb +27 -0
  525. data/gym/lib/gym/xcodebuild_fixes/README.md +9 -0
  526. data/gym/lib/gym/xcodebuild_fixes/generic_archive_fix.rb +35 -0
  527. data/match/README.md +17 -0
  528. data/match/lib/assets/MatchfileTemplate +11 -0
  529. data/match/lib/assets/MatchfileTemplate.swift +9 -0
  530. data/match/lib/assets/READMETemplate.md +59 -0
  531. data/match/lib/match.rb +14 -0
  532. data/match/lib/match/change_password.rb +53 -0
  533. data/match/lib/match/commands_generator.rb +190 -0
  534. data/match/lib/match/encryption.rb +49 -0
  535. data/match/lib/match/encryption/interface.rb +17 -0
  536. data/match/lib/match/encryption/openssl.rb +161 -0
  537. data/match/lib/match/generator.rb +122 -0
  538. data/match/lib/match/importer.rb +157 -0
  539. data/match/lib/match/migrate.rb +109 -0
  540. data/match/lib/match/module.rb +32 -0
  541. data/match/lib/match/nuke.rb +350 -0
  542. data/match/lib/match/options.rb +315 -0
  543. data/match/lib/match/runner.rb +369 -0
  544. data/match/lib/match/setup.rb +40 -0
  545. data/match/lib/match/spaceship_ensure.rb +97 -0
  546. data/match/lib/match/storage.rb +46 -0
  547. data/match/lib/match/storage/git_storage.rb +250 -0
  548. data/match/lib/match/storage/google_cloud_storage.rb +382 -0
  549. data/match/lib/match/storage/interface.rb +119 -0
  550. data/match/lib/match/storage/s3_storage.rb +205 -0
  551. data/match/lib/match/table_printer.rb +51 -0
  552. data/match/lib/match/utils.rb +75 -0
  553. data/pem/README.md +17 -0
  554. data/pem/lib/pem.rb +4 -0
  555. data/pem/lib/pem/commands_generator.rb +47 -0
  556. data/pem/lib/pem/manager.rb +112 -0
  557. data/pem/lib/pem/module.rb +19 -0
  558. data/pem/lib/pem/options.rb +103 -0
  559. data/pilot/README.md +17 -0
  560. data/pilot/lib/pilot.rb +9 -0
  561. data/pilot/lib/pilot/build_manager.rb +546 -0
  562. data/pilot/lib/pilot/commands_generator.rb +174 -0
  563. data/pilot/lib/pilot/features.rb +0 -0
  564. data/pilot/lib/pilot/manager.rb +90 -0
  565. data/pilot/lib/pilot/module.rb +11 -0
  566. data/pilot/lib/pilot/options.rb +303 -0
  567. data/pilot/lib/pilot/tester_exporter.rb +58 -0
  568. data/pilot/lib/pilot/tester_importer.rb +53 -0
  569. data/pilot/lib/pilot/tester_manager.rb +168 -0
  570. data/pilot/lib/pilot/tester_util.rb +0 -0
  571. data/precheck/README.md +17 -0
  572. data/precheck/lib/assets/PrecheckfileTemplate +27 -0
  573. data/precheck/lib/assets/PrecheckfileTemplate.swift +19 -0
  574. data/precheck/lib/precheck.rb +3 -0
  575. data/precheck/lib/precheck/commands_generator.rb +74 -0
  576. data/precheck/lib/precheck/item_to_check.rb +58 -0
  577. data/precheck/lib/precheck/module.rb +21 -0
  578. data/precheck/lib/precheck/options.rb +104 -0
  579. data/precheck/lib/precheck/rule.rb +171 -0
  580. data/precheck/lib/precheck/rule_check_result.rb +19 -0
  581. data/precheck/lib/precheck/rule_processor.rb +265 -0
  582. data/precheck/lib/precheck/rules/abstract_text_match_rule.rb +80 -0
  583. data/precheck/lib/precheck/rules/all.rb +1 -0
  584. data/precheck/lib/precheck/rules/copyright_date_rule.rb +37 -0
  585. data/precheck/lib/precheck/rules/curse_words_rule.rb +62 -0
  586. data/precheck/lib/precheck/rules/custom_text_rule.rb +35 -0
  587. data/precheck/lib/precheck/rules/free_stuff_iap_rule.rb +31 -0
  588. data/precheck/lib/precheck/rules/future_functionality_rule.rb +33 -0
  589. data/precheck/lib/precheck/rules/negative_apple_sentiment_rule.rb +37 -0
  590. data/precheck/lib/precheck/rules/other_platforms_rule.rb +43 -0
  591. data/precheck/lib/precheck/rules/placeholder_words_rule.rb +31 -0
  592. data/precheck/lib/precheck/rules/rules_data/curse_word_hashes/en_us.txt +349 -0
  593. data/precheck/lib/precheck/rules/test_words_rule.rb +30 -0
  594. data/precheck/lib/precheck/rules/unreachable_urls_rule.rb +47 -0
  595. data/precheck/lib/precheck/runner.rb +197 -0
  596. data/produce/README.md +17 -0
  597. data/produce/lib/produce.rb +6 -0
  598. data/produce/lib/produce/available_default_languages.rb +51 -0
  599. data/produce/lib/produce/cloud_container.rb +82 -0
  600. data/produce/lib/produce/commands_generator.rb +236 -0
  601. data/produce/lib/produce/developer_center.rb +143 -0
  602. data/produce/lib/produce/group.rb +90 -0
  603. data/produce/lib/produce/itunes_connect.rb +139 -0
  604. data/produce/lib/produce/manager.rb +15 -0
  605. data/produce/lib/produce/merchant.rb +121 -0
  606. data/produce/lib/produce/module.rb +14 -0
  607. data/produce/lib/produce/options.rb +184 -0
  608. data/produce/lib/produce/service.rb +319 -0
  609. data/scan/README.md +17 -0
  610. data/scan/lib/assets/ScanfileTemplate +16 -0
  611. data/scan/lib/assets/ScanfileTemplate.swift +13 -0
  612. data/scan/lib/scan.rb +10 -0
  613. data/scan/lib/scan/commands_generator.rb +78 -0
  614. data/scan/lib/scan/detect_values.rb +224 -0
  615. data/scan/lib/scan/error_handler.rb +57 -0
  616. data/scan/lib/scan/manager.rb +38 -0
  617. data/scan/lib/scan/module.rb +32 -0
  618. data/scan/lib/scan/options.rb +445 -0
  619. data/scan/lib/scan/runner.rb +197 -0
  620. data/scan/lib/scan/slack_poster.rb +60 -0
  621. data/scan/lib/scan/test_command_generator.rb +174 -0
  622. data/scan/lib/scan/test_result_parser.rb +33 -0
  623. data/scan/lib/scan/xcpretty_reporter_options_generator.rb +85 -0
  624. data/screengrab/README.md +17 -0
  625. data/screengrab/lib/assets/ScreengrabfileTemplate +15 -0
  626. data/screengrab/lib/assets/ScreengrabfileTemplate.swift +15 -0
  627. data/screengrab/lib/screengrab.rb +7 -0
  628. data/screengrab/lib/screengrab/android_environment.rb +91 -0
  629. data/screengrab/lib/screengrab/commands_generator.rb +70 -0
  630. data/screengrab/lib/screengrab/dependency_checker.rb +58 -0
  631. data/screengrab/lib/screengrab/detect_values.rb +16 -0
  632. data/screengrab/lib/screengrab/module.rb +26 -0
  633. data/screengrab/lib/screengrab/options.rb +148 -0
  634. data/screengrab/lib/screengrab/page.html.erb +190 -0
  635. data/screengrab/lib/screengrab/reports_generator.rb +36 -0
  636. data/screengrab/lib/screengrab/runner.rb +449 -0
  637. data/screengrab/lib/screengrab/setup.rb +24 -0
  638. data/sigh/README.md +17 -0
  639. data/sigh/lib/assets/resign.sh +909 -0
  640. data/sigh/lib/sigh.rb +4 -0
  641. data/sigh/lib/sigh/commands_generator.rb +154 -0
  642. data/sigh/lib/sigh/download_all.rb +112 -0
  643. data/sigh/lib/sigh/local_manage.rb +145 -0
  644. data/sigh/lib/sigh/manager.rb +47 -0
  645. data/sigh/lib/sigh/module.rb +42 -0
  646. data/sigh/lib/sigh/options.rb +187 -0
  647. data/sigh/lib/sigh/repair.rb +34 -0
  648. data/sigh/lib/sigh/resign.rb +220 -0
  649. data/sigh/lib/sigh/runner.rb +402 -0
  650. data/snapshot/README.md +17 -0
  651. data/snapshot/lib/assets/SnapfileTemplate +37 -0
  652. data/snapshot/lib/assets/SnapfileTemplate.swift +41 -0
  653. data/snapshot/lib/assets/SnapshotHelper.swift +301 -0
  654. data/snapshot/lib/assets/SnapshotHelperXcode8.swift +172 -0
  655. data/snapshot/lib/snapshot.rb +19 -0
  656. data/snapshot/lib/snapshot/collector.rb +140 -0
  657. data/snapshot/lib/snapshot/commands_generator.rb +115 -0
  658. data/snapshot/lib/snapshot/dependency_checker.rb +69 -0
  659. data/snapshot/lib/snapshot/detect_values.rb +86 -0
  660. data/snapshot/lib/snapshot/error_handler.rb +24 -0
  661. data/snapshot/lib/snapshot/fixes/README.md +5 -0
  662. data/snapshot/lib/snapshot/fixes/hardware_keyboard_fix.rb +27 -0
  663. data/snapshot/lib/snapshot/fixes/simulator_shared_pasteboard.rb +16 -0
  664. data/snapshot/lib/snapshot/fixes/simulator_zoom_fix.rb +27 -0
  665. data/snapshot/lib/snapshot/latest_os_version.rb +34 -0
  666. data/snapshot/lib/snapshot/module.rb +44 -0
  667. data/snapshot/lib/snapshot/options.rb +290 -0
  668. data/snapshot/lib/snapshot/page.html.erb +285 -0
  669. data/snapshot/lib/snapshot/reports_generator.rb +139 -0
  670. data/snapshot/lib/snapshot/reset_simulators.rb +122 -0
  671. data/snapshot/lib/snapshot/runner.rb +146 -0
  672. data/snapshot/lib/snapshot/screenshot_flatten.rb +20 -0
  673. data/snapshot/lib/snapshot/screenshot_rotate.rb +36 -0
  674. data/snapshot/lib/snapshot/setup.rb +58 -0
  675. data/snapshot/lib/snapshot/simulator_launchers/launcher_configuration.rb +62 -0
  676. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher.rb +219 -0
  677. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +200 -0
  678. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_xcode_8.rb +113 -0
  679. data/snapshot/lib/snapshot/test_command_generator.rb +108 -0
  680. data/snapshot/lib/snapshot/test_command_generator_base.rb +128 -0
  681. data/snapshot/lib/snapshot/test_command_generator_xcode_8.rb +70 -0
  682. data/snapshot/lib/snapshot/update.rb +38 -0
  683. data/spaceship/README.md +183 -0
  684. data/spaceship/lib/assets/displayFamilies.json +181 -0
  685. data/spaceship/lib/assets/languageMapping.json +306 -0
  686. data/spaceship/lib/assets/languageMappingReadable.json +30 -0
  687. data/spaceship/lib/spaceship.rb +30 -0
  688. data/spaceship/lib/spaceship/base.rb +310 -0
  689. data/spaceship/lib/spaceship/client.rb +913 -0
  690. data/spaceship/lib/spaceship/commands_generator.rb +53 -0
  691. data/spaceship/lib/spaceship/connect_api.rb +116 -0
  692. data/spaceship/lib/spaceship/connect_api/api_client.rb +279 -0
  693. data/spaceship/lib/spaceship/connect_api/client.rb +216 -0
  694. data/spaceship/lib/spaceship/connect_api/file_uploader.rb +99 -0
  695. data/spaceship/lib/spaceship/connect_api/model.rb +172 -0
  696. data/spaceship/lib/spaceship/connect_api/models/age_rating_declaration.rb +114 -0
  697. data/spaceship/lib/spaceship/connect_api/models/app.rb +388 -0
  698. data/spaceship/lib/spaceship/connect_api/models/app_category.rb +94 -0
  699. data/spaceship/lib/spaceship/connect_api/models/app_info.rb +95 -0
  700. data/spaceship/lib/spaceship/connect_api/models/app_info_localization.rb +39 -0
  701. data/spaceship/lib/spaceship/connect_api/models/app_preview.rb +131 -0
  702. data/spaceship/lib/spaceship/connect_api/models/app_preview_set.rb +100 -0
  703. data/spaceship/lib/spaceship/connect_api/models/app_price.rb +22 -0
  704. data/spaceship/lib/spaceship/connect_api/models/app_price_point.rb +26 -0
  705. data/spaceship/lib/spaceship/connect_api/models/app_price_tier.rb +12 -0
  706. data/spaceship/lib/spaceship/connect_api/models/app_screenshot.rb +187 -0
  707. data/spaceship/lib/spaceship/connect_api/models/app_screenshot_set.rb +153 -0
  708. data/spaceship/lib/spaceship/connect_api/models/app_store_review_attachment.rb +71 -0
  709. data/spaceship/lib/spaceship/connect_api/models/app_store_review_detail.rb +51 -0
  710. data/spaceship/lib/spaceship/connect_api/models/app_store_version.rb +217 -0
  711. data/spaceship/lib/spaceship/connect_api/models/app_store_version_localization.rb +85 -0
  712. data/spaceship/lib/spaceship/connect_api/models/app_store_version_phased_release.rb +57 -0
  713. data/spaceship/lib/spaceship/connect_api/models/app_store_version_release_request.rb +12 -0
  714. data/spaceship/lib/spaceship/connect_api/models/app_store_version_submission.rb +26 -0
  715. data/spaceship/lib/spaceship/connect_api/models/beta_app_localization.rb +28 -0
  716. data/spaceship/lib/spaceship/connect_api/models/beta_app_review_detail.rb +32 -0
  717. data/spaceship/lib/spaceship/connect_api/models/beta_app_review_submission.rb +26 -0
  718. data/spaceship/lib/spaceship/connect_api/models/beta_build_localization.rb +20 -0
  719. data/spaceship/lib/spaceship/connect_api/models/beta_build_metric.rb +24 -0
  720. data/spaceship/lib/spaceship/connect_api/models/beta_feedback.rb +75 -0
  721. data/spaceship/lib/spaceship/connect_api/models/beta_group.rb +41 -0
  722. data/spaceship/lib/spaceship/connect_api/models/beta_screenshot.rb +18 -0
  723. data/spaceship/lib/spaceship/connect_api/models/beta_tester.rb +57 -0
  724. data/spaceship/lib/spaceship/connect_api/models/beta_tester_metric.rb +44 -0
  725. data/spaceship/lib/spaceship/connect_api/models/build.rb +172 -0
  726. data/spaceship/lib/spaceship/connect_api/models/build_beta_detail.rb +61 -0
  727. data/spaceship/lib/spaceship/connect_api/models/build_delivery.rb +36 -0
  728. data/spaceship/lib/spaceship/connect_api/models/bundle_id.rb +58 -0
  729. data/spaceship/lib/spaceship/connect_api/models/bundle_id_capability.rb +71 -0
  730. data/spaceship/lib/spaceship/connect_api/models/certificate.rb +102 -0
  731. data/spaceship/lib/spaceship/connect_api/models/custom_app_organization.rb +43 -0
  732. data/spaceship/lib/spaceship/connect_api/models/custom_app_user.rb +41 -0
  733. data/spaceship/lib/spaceship/connect_api/models/device.rb +58 -0
  734. data/spaceship/lib/spaceship/connect_api/models/idfa_declaration.rb +41 -0
  735. data/spaceship/lib/spaceship/connect_api/models/pre_release_version.rb +20 -0
  736. data/spaceship/lib/spaceship/connect_api/models/profile.rb +97 -0
  737. data/spaceship/lib/spaceship/connect_api/models/reset_ratings_request.rb +26 -0
  738. data/spaceship/lib/spaceship/connect_api/models/sandbox_tester.rb +64 -0
  739. data/spaceship/lib/spaceship/connect_api/models/territory.rb +27 -0
  740. data/spaceship/lib/spaceship/connect_api/models/user.rb +51 -0
  741. data/spaceship/lib/spaceship/connect_api/models/user_invitation.rb +59 -0
  742. data/spaceship/lib/spaceship/connect_api/provisioning/client.rb +92 -0
  743. data/spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb +143 -0
  744. data/spaceship/lib/spaceship/connect_api/response.rb +67 -0
  745. data/spaceship/lib/spaceship/connect_api/spaceship.rb +102 -0
  746. data/spaceship/lib/spaceship/connect_api/testflight/client.rb +24 -0
  747. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +391 -0
  748. data/spaceship/lib/spaceship/connect_api/token.rb +102 -0
  749. data/spaceship/lib/spaceship/connect_api/token_refresh_middleware.rb +24 -0
  750. data/spaceship/lib/spaceship/connect_api/tunes/client.rb +24 -0
  751. data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +1045 -0
  752. data/spaceship/lib/spaceship/connect_api/users/client.rb +24 -0
  753. data/spaceship/lib/spaceship/connect_api/users/users.rb +80 -0
  754. data/spaceship/lib/spaceship/du/du_client.rb +138 -0
  755. data/spaceship/lib/spaceship/du/upload_file.rb +58 -0
  756. data/spaceship/lib/spaceship/du/utilities.rb +99 -0
  757. data/spaceship/lib/spaceship/errors.rb +82 -0
  758. data/spaceship/lib/spaceship/globals.rb +12 -0
  759. data/spaceship/lib/spaceship/helper/net_http_generic_request.rb +20 -0
  760. data/spaceship/lib/spaceship/helper/plist_middleware.rb +16 -0
  761. data/spaceship/lib/spaceship/helper/rels_middleware.rb +28 -0
  762. data/spaceship/lib/spaceship/launcher.rb +99 -0
  763. data/spaceship/lib/spaceship/module.rb +8 -0
  764. data/spaceship/lib/spaceship/playground.rb +75 -0
  765. data/spaceship/lib/spaceship/portal/app.rb +201 -0
  766. data/spaceship/lib/spaceship/portal/app_group.rb +73 -0
  767. data/spaceship/lib/spaceship/portal/app_service.rb +87 -0
  768. data/spaceship/lib/spaceship/portal/certificate.rb +365 -0
  769. data/spaceship/lib/spaceship/portal/cloud_container.rb +74 -0
  770. data/spaceship/lib/spaceship/portal/device.rb +191 -0
  771. data/spaceship/lib/spaceship/portal/invite.rb +53 -0
  772. data/spaceship/lib/spaceship/portal/key.rb +101 -0
  773. data/spaceship/lib/spaceship/portal/legacy_wrapper.rb +21 -0
  774. data/spaceship/lib/spaceship/portal/merchant.rb +86 -0
  775. data/spaceship/lib/spaceship/portal/passbook.rb +78 -0
  776. data/spaceship/lib/spaceship/portal/person.rb +62 -0
  777. data/spaceship/lib/spaceship/portal/persons.rb +67 -0
  778. data/spaceship/lib/spaceship/portal/portal.rb +17 -0
  779. data/spaceship/lib/spaceship/portal/portal_base.rb +16 -0
  780. data/spaceship/lib/spaceship/portal/portal_client.rb +862 -0
  781. data/spaceship/lib/spaceship/portal/provisioning_profile.rb +559 -0
  782. data/spaceship/lib/spaceship/portal/provisioning_profile_template.rb +52 -0
  783. data/spaceship/lib/spaceship/portal/spaceship.rb +154 -0
  784. data/spaceship/lib/spaceship/portal/ui/select_team.rb +116 -0
  785. data/spaceship/lib/spaceship/portal/website_push.rb +88 -0
  786. data/spaceship/lib/spaceship/provider.rb +13 -0
  787. data/spaceship/lib/spaceship/spaceauth_runner.rb +74 -0
  788. data/spaceship/lib/spaceship/stats_middleware.rb +65 -0
  789. data/spaceship/lib/spaceship/test_flight.rb +10 -0
  790. data/spaceship/lib/spaceship/test_flight/app_test_info.rb +40 -0
  791. data/spaceship/lib/spaceship/test_flight/base.rb +39 -0
  792. data/spaceship/lib/spaceship/test_flight/beta_review_info.rb +19 -0
  793. data/spaceship/lib/spaceship/test_flight/build.rb +242 -0
  794. data/spaceship/lib/spaceship/test_flight/build_trains.rb +50 -0
  795. data/spaceship/lib/spaceship/test_flight/client.rb +361 -0
  796. data/spaceship/lib/spaceship/test_flight/export_compliance.rb +12 -0
  797. data/spaceship/lib/spaceship/test_flight/group.rb +131 -0
  798. data/spaceship/lib/spaceship/test_flight/test_info.rb +56 -0
  799. data/spaceship/lib/spaceship/test_flight/tester.rb +136 -0
  800. data/spaceship/lib/spaceship/tunes/app_analytics.rb +168 -0
  801. data/spaceship/lib/spaceship/tunes/app_details.rb +147 -0
  802. data/spaceship/lib/spaceship/tunes/app_image.rb +51 -0
  803. data/spaceship/lib/spaceship/tunes/app_ratings.rb +58 -0
  804. data/spaceship/lib/spaceship/tunes/app_review.rb +55 -0
  805. data/spaceship/lib/spaceship/tunes/app_review_attachment.rb +49 -0
  806. data/spaceship/lib/spaceship/tunes/app_screenshot.rb +12 -0
  807. data/spaceship/lib/spaceship/tunes/app_status.rb +63 -0
  808. data/spaceship/lib/spaceship/tunes/app_submission.rb +161 -0
  809. data/spaceship/lib/spaceship/tunes/app_trailer.rb +64 -0
  810. data/spaceship/lib/spaceship/tunes/app_version.rb +970 -0
  811. data/spaceship/lib/spaceship/tunes/app_version_common.rb +35 -0
  812. data/spaceship/lib/spaceship/tunes/app_version_generated_promocodes.rb +28 -0
  813. data/spaceship/lib/spaceship/tunes/app_version_history.rb +52 -0
  814. data/spaceship/lib/spaceship/tunes/app_version_promocodes.rb +27 -0
  815. data/spaceship/lib/spaceship/tunes/app_version_ref.rb +15 -0
  816. data/spaceship/lib/spaceship/tunes/app_version_states_history.rb +27 -0
  817. data/spaceship/lib/spaceship/tunes/application.rb +453 -0
  818. data/spaceship/lib/spaceship/tunes/availability.rb +164 -0
  819. data/spaceship/lib/spaceship/tunes/b2b_organization.rb +50 -0
  820. data/spaceship/lib/spaceship/tunes/b2b_user.rb +30 -0
  821. data/spaceship/lib/spaceship/tunes/build.rb +263 -0
  822. data/spaceship/lib/spaceship/tunes/build_details.rb +184 -0
  823. data/spaceship/lib/spaceship/tunes/build_train.rb +181 -0
  824. data/spaceship/lib/spaceship/tunes/developer_response.rb +23 -0
  825. data/spaceship/lib/spaceship/tunes/device_type.rb +17 -0
  826. data/spaceship/lib/spaceship/tunes/display_family.rb +84 -0
  827. data/spaceship/lib/spaceship/tunes/errors.rb +17 -0
  828. data/spaceship/lib/spaceship/tunes/iap.rb +168 -0
  829. data/spaceship/lib/spaceship/tunes/iap_detail.rb +264 -0
  830. data/spaceship/lib/spaceship/tunes/iap_families.rb +68 -0
  831. data/spaceship/lib/spaceship/tunes/iap_family_details.rb +90 -0
  832. data/spaceship/lib/spaceship/tunes/iap_family_list.rb +28 -0
  833. data/spaceship/lib/spaceship/tunes/iap_list.rb +76 -0
  834. data/spaceship/lib/spaceship/tunes/iap_status.rb +56 -0
  835. data/spaceship/lib/spaceship/tunes/iap_subscription_pricing_info.rb +46 -0
  836. data/spaceship/lib/spaceship/tunes/iap_subscription_pricing_tier.rb +25 -0
  837. data/spaceship/lib/spaceship/tunes/iap_type.rb +45 -0
  838. data/spaceship/lib/spaceship/tunes/language_converter.rb +65 -0
  839. data/spaceship/lib/spaceship/tunes/language_item.rb +61 -0
  840. data/spaceship/lib/spaceship/tunes/legacy_wrapper.rb +13 -0
  841. data/spaceship/lib/spaceship/tunes/member.rb +84 -0
  842. data/spaceship/lib/spaceship/tunes/members.rb +35 -0
  843. data/spaceship/lib/spaceship/tunes/pricing_info.rb +42 -0
  844. data/spaceship/lib/spaceship/tunes/pricing_tier.rb +25 -0
  845. data/spaceship/lib/spaceship/tunes/sandbox_tester.rb +74 -0
  846. data/spaceship/lib/spaceship/tunes/spaceship.rb +39 -0
  847. data/spaceship/lib/spaceship/tunes/territory.rb +39 -0
  848. data/spaceship/lib/spaceship/tunes/transit_app_file.rb +23 -0
  849. data/spaceship/lib/spaceship/tunes/tunes.rb +35 -0
  850. data/spaceship/lib/spaceship/tunes/tunes_base.rb +17 -0
  851. data/spaceship/lib/spaceship/tunes/tunes_client.rb +1644 -0
  852. data/spaceship/lib/spaceship/tunes/user_detail.rb +15 -0
  853. data/spaceship/lib/spaceship/tunes/version_set.rb +26 -0
  854. data/spaceship/lib/spaceship/two_step_or_factor_client.rb +346 -0
  855. data/spaceship/lib/spaceship/ui.rb +27 -0
  856. data/supply/README.md +17 -0
  857. data/supply/lib/supply.rb +53 -0
  858. data/supply/lib/supply/apk_listing.rb +14 -0
  859. data/supply/lib/supply/client.rb +551 -0
  860. data/supply/lib/supply/commands_generator.rb +67 -0
  861. data/supply/lib/supply/languages.rb +88 -0
  862. data/supply/lib/supply/listing.rb +32 -0
  863. data/supply/lib/supply/options.rb +324 -0
  864. data/supply/lib/supply/reader.rb +41 -0
  865. data/supply/lib/supply/release_listing.rb +18 -0
  866. data/supply/lib/supply/setup.rb +122 -0
  867. data/supply/lib/supply/uploader.rb +480 -0
  868. metadata +1832 -0
@@ -0,0 +1,35 @@
1
+ require_relative 'tunes_base'
2
+ require_relative 'application'
3
+ require_relative 'iap'
4
+ require_relative 'version_set'
5
+ require_relative 'app_version'
6
+ require_relative 'app_version_common'
7
+ require_relative 'app_submission'
8
+ require_relative 'tunes_client'
9
+ require_relative 'language_item'
10
+ require_relative 'app_status'
11
+ require_relative 'app_image'
12
+ require_relative 'app_ratings'
13
+ require_relative 'app_version_ref'
14
+ require_relative 'app_version_history'
15
+ require_relative 'app_version_states_history'
16
+ require_relative 'transit_app_file'
17
+ require_relative 'user_detail'
18
+ require_relative 'app_screenshot'
19
+ require_relative 'language_converter'
20
+ require_relative 'build'
21
+ require_relative 'build_details'
22
+ require_relative 'build_train'
23
+ require_relative 'device_type'
24
+ require_relative 'app_trailer'
25
+ require_relative 'sandbox_tester'
26
+ require_relative 'app_details'
27
+ require_relative 'pricing_tier'
28
+ require_relative 'territory'
29
+ require_relative 'availability'
30
+ require_relative 'members'
31
+ require_relative 'member'
32
+
33
+ require_relative 'app_version_promocodes'
34
+ require_relative 'app_version_generated_promocodes'
35
+ require_relative 'app_analytics'
@@ -0,0 +1,17 @@
1
+ require_relative '../base'
2
+
3
+ module Spaceship
4
+ module Tunes
5
+ class TunesBase < Spaceship::Base
6
+ class << self
7
+ def client
8
+ (
9
+ @client or
10
+ Spaceship::Tunes.client or
11
+ raise "Please login using `Spaceship::Tunes.login('user', 'password')`"
12
+ )
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,1644 @@
1
+ require "securerandom"
2
+ require_relative '../client'
3
+ require_relative '../du/du_client'
4
+ require_relative '../du/upload_file'
5
+ require_relative 'app_version_common'
6
+ require_relative 'app_version_ref'
7
+ require_relative 'availability'
8
+ require_relative 'errors'
9
+ require_relative 'iap_subscription_pricing_tier'
10
+ require_relative 'pricing_tier'
11
+ require_relative 'territory'
12
+ require_relative 'user_detail'
13
+ module Spaceship
14
+ # rubocop:disable Metrics/ClassLength
15
+ class TunesClient < Spaceship::Client
16
+ # Legacy support
17
+ ITunesConnectError = Tunes::Error
18
+ ITunesConnectTemporaryError = Tunes::TemporaryError
19
+ ITunesConnectPotentialServerError = Tunes::PotentialServerError
20
+
21
+ attr_reader :du_client
22
+
23
+ def initialize
24
+ super
25
+
26
+ @du_client = DUClient.new
27
+ end
28
+
29
+ class << self
30
+ # trailer preview screenshots are required to have a specific size
31
+ def video_preview_resolution_for(device, is_portrait)
32
+ resolutions = {
33
+ 'iphone4' => [1136, 640],
34
+ 'iphone6' => [1334, 750],
35
+ 'iphone6Plus' => [2208, 1242],
36
+ 'iphone58' => [2436, 1125],
37
+ 'iphone65' => [2688, 1242],
38
+ 'ipad' => [1024, 768],
39
+ 'ipad105' => [2224, 1668],
40
+ 'ipadPro' => [2732, 2048],
41
+ 'ipadPro11' => [2388, 1668],
42
+ 'ipadPro129' => [2732, 2048]
43
+ }
44
+
45
+ r = resolutions[device]
46
+ r = [r[1], r[0]] if is_portrait
47
+ r
48
+ end
49
+ end
50
+
51
+ #####################################################
52
+ # @!group Init and Login
53
+ #####################################################
54
+
55
+ def self.hostname
56
+ "https://appstoreconnect.apple.com/WebObjects/iTunesConnect.woa/"
57
+ end
58
+
59
+ # Shows a team selection for the user in the terminal. This should not be
60
+ # called on CI systems
61
+ #
62
+ # @param team_id (String) (optional): The ID of an App Store Connect team
63
+ # @param team_name (String) (optional): The name of an App Store Connect team
64
+ def select_team(team_id: nil, team_name: nil)
65
+ t_id = (team_id || ENV['FASTLANE_ITC_TEAM_ID'] || '').strip
66
+ t_name = (team_name || ENV['FASTLANE_ITC_TEAM_NAME'] || '').strip
67
+
68
+ if t_name.length > 0 && t_id.length.zero? # we prefer IDs over names, they are unique
69
+ puts("Looking for App Store Connect Team with name #{t_name}") if Spaceship::Globals.verbose?
70
+
71
+ teams.each do |t|
72
+ t_id = t['contentProvider']['contentProviderId'].to_s if t['contentProvider']['name'].casecmp(t_name).zero?
73
+ end
74
+
75
+ puts("Could not find team with name '#{t_name}', trying to fallback to default team") if t_id.length.zero?
76
+ end
77
+
78
+ t_id = teams.first['contentProvider']['contentProviderId'].to_s if teams.count == 1
79
+
80
+ if t_id.length > 0
81
+ puts("Looking for App Store Connect Team with ID #{t_id}") if Spaceship::Globals.verbose?
82
+
83
+ # actually set the team id here
84
+ self.team_id = t_id
85
+ return self.team_id
86
+ end
87
+
88
+ # user didn't specify a team... #thisiswhywecanthavenicethings
89
+ loop do
90
+ puts("Multiple #{'App Store Connect teams'.yellow} found, please enter the number of the team you want to use: ")
91
+ if ENV["FASTLANE_HIDE_TEAM_INFORMATION"].to_s.length == 0
92
+ puts("Note: to automatically choose the team, provide either the App Store Connect Team ID, or the Team Name in your fastlane/Appfile:")
93
+ puts("Alternatively you can pass the team name or team ID using the `FASTLANE_ITC_TEAM_ID` or `FASTLANE_ITC_TEAM_NAME` environment variable")
94
+ first_team = teams.first["contentProvider"]
95
+ puts("")
96
+ puts(" itc_team_id \"#{first_team['contentProviderId']}\"")
97
+ puts("")
98
+ puts("or")
99
+ puts("")
100
+ puts(" itc_team_name \"#{first_team['name']}\"")
101
+ puts("")
102
+ end
103
+
104
+ # We're not using highline here, as spaceship doesn't have a dependency to fastlane_core or highline
105
+ teams.each_with_index do |team, i|
106
+ puts("#{i + 1}) \"#{team['contentProvider']['name']}\" (#{team['contentProvider']['contentProviderId']})")
107
+ end
108
+
109
+ unless Spaceship::Client::UserInterface.interactive?
110
+ puts("Multiple teams found on App Store Connect, Your Terminal is running in non-interactive mode! Cannot continue from here.")
111
+ puts("Please check that you set FASTLANE_ITC_TEAM_ID or FASTLANE_ITC_TEAM_NAME to the right value.")
112
+ raise "Multiple App Store Connect Teams found; unable to choose, terminal not interactive!"
113
+ end
114
+
115
+ selected = ($stdin.gets || '').strip.to_i - 1
116
+ team_to_use = teams[selected] if selected >= 0
117
+
118
+ if team_to_use
119
+ self.team_id = team_to_use['contentProvider']['contentProviderId'].to_s # actually set the team id here
120
+ return self.team_id
121
+ end
122
+ end
123
+ end
124
+
125
+ def send_login_request(user, password)
126
+ clear_user_cached_data
127
+ result = send_shared_login_request(user, password)
128
+
129
+ store_cookie
130
+
131
+ return result
132
+ end
133
+
134
+ # Sometimes we get errors or info nested in our data
135
+ # This method allows you to pass in a set of keys to check for
136
+ # along with the name of the sub_section of your original data
137
+ # where we should check
138
+ # Returns a mapping of keys to data array if we find anything, otherwise, empty map
139
+ def fetch_errors_in_data(data_section: nil, sub_section_name: nil, keys: nil)
140
+ if data_section && sub_section_name
141
+ sub_section = data_section[sub_section_name]
142
+ else
143
+ sub_section = data_section
144
+ end
145
+
146
+ unless sub_section
147
+ return {}
148
+ end
149
+
150
+ error_map = {}
151
+ keys.each do |key|
152
+ errors = sub_section.fetch(key, [])
153
+ error_map[key] = errors if errors.count > 0
154
+ end
155
+ return error_map
156
+ end
157
+
158
+ # rubocop:disable Metrics/PerceivedComplexity
159
+ # If the response is coming from a flaky api, set flaky_api_call to true so we retry a little.
160
+ # Patience is a virtue.
161
+ def handle_itc_response(raw, flaky_api_call: false)
162
+ return unless raw
163
+ return unless raw.kind_of?(Hash)
164
+
165
+ data = raw['data'] || raw # sometimes it's with data, sometimes it isn't
166
+
167
+ error_keys = ["sectionErrorKeys", "validationErrors", "serviceErrors"]
168
+ info_keys = ["sectionInfoKeys", "sectionWarningKeys"]
169
+ error_and_info_keys_to_check = error_keys + info_keys
170
+
171
+ errors_in_data = fetch_errors_in_data(data_section: data, keys: error_and_info_keys_to_check)
172
+ errors_in_version_info = fetch_errors_in_data(data_section: data, sub_section_name: "versionInfo", keys: error_and_info_keys_to_check)
173
+
174
+ # If we have any errors or "info" we need to treat them as warnings or errors
175
+ if errors_in_data.count == 0 && errors_in_version_info.count == 0
176
+ logger.debug("Request was successful")
177
+ end
178
+
179
+ # We pass on the `current_language` so that the error message tells the user
180
+ # what language the error was caused in
181
+ handle_response_hash = lambda do |hash, current_language = nil|
182
+ errors = []
183
+ if hash.kind_of?(Hash)
184
+ current_language ||= hash["language"]
185
+
186
+ hash.each do |key, value|
187
+ errors += handle_response_hash.call(value, current_language)
188
+
189
+ next unless key == 'errorKeys' && value.kind_of?(Array) && value.count > 0
190
+ # Prepend the error with the language so it's easier to understand for the user
191
+ errors += value.collect do |current_error_message|
192
+ current_language ? "[#{current_language}]: #{current_error_message}" : current_error_message
193
+ end
194
+ end
195
+ elsif hash.kind_of?(Array)
196
+ hash.each do |value|
197
+ errors += handle_response_hash.call(value)
198
+ end
199
+ # else: We don't care about simple values
200
+ end
201
+ return errors
202
+ end
203
+
204
+ errors = handle_response_hash.call(data)
205
+
206
+ # Search at data level, as well as "versionInfo" level for errors
207
+ errors_in_data = fetch_errors_in_data(data_section: data, keys: error_keys)
208
+ errors_in_version_info = fetch_errors_in_data(data_section: data, sub_section_name: "versionInfo", keys: error_keys)
209
+
210
+ errors += errors_in_data.values if errors_in_data.values
211
+ errors += errors_in_version_info.values if errors_in_version_info.values
212
+ errors = errors.flat_map { |value| value }
213
+
214
+ # Sometimes there is a different kind of error in the JSON response
215
+ # e.g. {"warn"=>nil, "error"=>["operation_failed"], "info"=>nil}
216
+ different_error = raw.fetch('messages', {}).fetch('error', nil)
217
+ errors << different_error if different_error
218
+
219
+ if errors.count > 0 # they are separated by `.` by default
220
+ # Sample `error` content: [["Forbidden"]]
221
+ if errors.count == 1 && errors.first == "You haven't made any changes."
222
+ # This is a special error which we really don't care about
223
+ elsif errors.count == 1 && errors.first.include?("try again later")
224
+ raise ITunesConnectTemporaryError.new, errors.first
225
+ elsif errors.count == 1 && errors.first.include?("Forbidden")
226
+ raise_insufficient_permission_error!
227
+ elsif flaky_api_call
228
+ raise ITunesConnectPotentialServerError.new, errors.join(' ')
229
+ else
230
+ raise ITunesConnectError.new, errors.join(' ')
231
+ end
232
+ end
233
+
234
+ # Search at data level, as well as "versionInfo" level for info and warnings
235
+ info_in_data = fetch_errors_in_data(data_section: data, keys: info_keys)
236
+ info_in_version_info = fetch_errors_in_data(data_section: data, sub_section_name: "versionInfo", keys: info_keys)
237
+
238
+ info_in_data.each do |info_key, info_value|
239
+ puts(info_value)
240
+ end
241
+
242
+ info_in_version_info.each do |info_key, info_value|
243
+ puts(info_value)
244
+ end
245
+
246
+ return data
247
+ end
248
+ # rubocop:enable Metrics/PerceivedComplexity
249
+
250
+ #####################################################
251
+ # @!group Applications
252
+ #####################################################
253
+
254
+ def applications
255
+ r = request(:get, 'ra/apps/manageyourapps/summary/v2')
256
+ parse_response(r, 'data')['summaries']
257
+ end
258
+
259
+ def app_details(app_id)
260
+ r = request(:get, "ra/apps/#{app_id}/details")
261
+ parse_response(r, 'data')
262
+ end
263
+
264
+ def bundle_details(app_id)
265
+ r = request(:get, "ra/appbundles/metadetail/#{app_id}")
266
+ parse_response(r, 'data')
267
+ end
268
+
269
+ def update_app_details!(app_id, data)
270
+ r = request(:post) do |req|
271
+ req.url("ra/apps/#{app_id}/details")
272
+ req.body = data.to_json
273
+ req.headers['Content-Type'] = 'application/json'
274
+ end
275
+
276
+ handle_itc_response(r.body)
277
+ end
278
+
279
+ # Creates a new application on App Store Connect
280
+ # @param name (String): The name of your app as it will appear on the App Store.
281
+ # This can't be longer than 255 characters.
282
+ # @param primary_language (String): If localized app information isn't available in an
283
+ # App Store territory, the information from your primary language will be used instead.
284
+ # @param version *DEPRECATED: Use `Spaceship::Tunes::Application.ensure_version!` method instead*
285
+ # (String): The version number is shown on the App Store and should match the one you used in Xcode.
286
+ # @param sku (String): A unique ID for your app that is not visible on the App Store.
287
+ # @param bundle_id (String): The bundle ID must match the one you used in Xcode. It
288
+ # can't be changed after you submit your first build.
289
+ def create_application!(name: nil, primary_language: nil, version: nil, sku: nil, bundle_id: nil, bundle_id_suffix: nil, company_name: nil, platform: nil, platforms: nil, itunes_connect_users: nil)
290
+ puts("The `version` parameter is deprecated. Use `Spaceship::Tunes::Application.ensure_version!` method instead") if version
291
+
292
+ # First, we need to fetch the data from Apple, which we then modify with the user's values
293
+ primary_language ||= "English"
294
+ platform ||= "ios"
295
+ r = request(:get, "ra/apps/create/v2/?platformString=#{platform}")
296
+ data = parse_response(r, 'data')
297
+
298
+ # Now fill in the values we have
299
+ # some values are nil, that's why there is a hash
300
+ data['name'] = { value: name }
301
+ data['bundleId'] = { value: bundle_id }
302
+ data['primaryLanguage'] = { value: primary_language }
303
+ data['primaryLocaleCode'] = { value: primary_language.to_itc_locale }
304
+ data['vendorId'] = { value: sku }
305
+ data['bundleIdSuffix'] = { value: bundle_id_suffix }
306
+ data['companyName'] = { value: company_name } if company_name
307
+ data['enabledPlatformsForCreation'] = { value: [platform] }
308
+
309
+ data['initialPlatform'] = platform
310
+ data['enabledPlatformsForCreation'] = { value: platforms || [platform] }
311
+
312
+ unless itunes_connect_users.nil?
313
+ data['iTunesConnectUsers']['grantedAllUsers'] = false
314
+ data['iTunesConnectUsers']['grantedUsers'] = data['iTunesConnectUsers']['availableUsers'].select { |user| itunes_connect_users.include?(user['username']) }
315
+ end
316
+
317
+ # Now send back the modified hash
318
+ r = request(:post) do |req|
319
+ req.url('ra/apps/create/v2')
320
+ req.body = data.to_json
321
+ req.headers['Content-Type'] = 'application/json'
322
+ end
323
+
324
+ data = parse_response(r, 'data')
325
+ handle_itc_response(data)
326
+ end
327
+
328
+ def create_version!(app_id, version_number, platform = 'ios')
329
+ r = request(:post) do |req|
330
+ req.url("ra/apps/#{app_id}/platforms/#{platform}/versions/create/")
331
+ req.body = {
332
+ version: {
333
+ value: version_number.to_s
334
+ }
335
+ }.to_json
336
+ req.headers['Content-Type'] = 'application/json'
337
+ end
338
+
339
+ data = parse_response(r, 'data')
340
+ handle_itc_response(data)
341
+ end
342
+
343
+ def get_available_bundle_ids(platform: nil)
344
+ platform ||= "ios"
345
+ r = request(:get, "ra/apps/create/v2/?platformString=#{platform}")
346
+ data = parse_response(r, 'data')
347
+ return data['bundleIds'].keys
348
+ end
349
+
350
+ def get_resolution_center(app_id, platform)
351
+ r = request(:get, "ra/apps/#{app_id}/platforms/#{platform}/resolutionCenter?v=latest")
352
+ parse_response(r, 'data')
353
+ end
354
+
355
+ def post_resolution_center(app_id, platform, thread_id, version_id, version_number, from, message_body)
356
+ r = request(:post) do |req|
357
+ req.url("ra/apps/#{app_id}/platforms/#{platform}/resolutionCenter")
358
+ req.body = {
359
+ appNotes: {
360
+ threads: [{
361
+ id: thread_id,
362
+ versionId: version_id,
363
+ version: version_number,
364
+ messages: [{
365
+ from: from,
366
+ date: DateTime.now.strftime('%Q'),
367
+ body: message_body,
368
+ tokens: []
369
+ }]
370
+ }]
371
+ }
372
+ }.to_json
373
+ req.headers['Content-Type'] = 'application/json'
374
+ end
375
+
376
+ data = parse_response(r, 'data')
377
+ handle_itc_response(data)
378
+ end
379
+
380
+ def get_ratings(app_id, platform, version_id = '', storefront = '')
381
+ # if storefront or version_id is empty api fails
382
+ rating_url = "ra/apps/#{app_id}/platforms/#{platform}/reviews/summary"
383
+ params = {}
384
+ params['storefront'] = storefront unless storefront.empty?
385
+ params['version_id'] = version_id unless version_id.empty?
386
+
387
+ r = request(:get, rating_url, params)
388
+ parse_response(r, 'data')
389
+ end
390
+
391
+ def get_reviews(app_id, platform, storefront, version_id, upto_date = nil)
392
+ index = 0
393
+ per_page = 100 # apple default
394
+ all_reviews = []
395
+
396
+ upto_date = Time.parse(upto_date) unless upto_date.nil?
397
+
398
+ loop do
399
+ rating_url = "ra/apps/#{app_id}/platforms/#{platform}/reviews?"
400
+ rating_url << "sort=REVIEW_SORT_ORDER_MOST_RECENT"
401
+ rating_url << "&index=#{index}"
402
+ rating_url << "&storefront=#{storefront}" unless storefront.empty?
403
+ rating_url << "&versionId=#{version_id}" unless version_id.empty?
404
+
405
+ r = request(:get, rating_url)
406
+ all_reviews.concat(parse_response(r, 'data')['reviews'])
407
+
408
+ # The following lines throw errors when there are no reviews so exit out of the loop before them if the app has no reviews
409
+ break if all_reviews.count == 0
410
+
411
+ last_review_date = Time.at(all_reviews[-1]['value']['lastModified'] / 1000)
412
+
413
+ if upto_date && last_review_date < upto_date
414
+ all_reviews = all_reviews.select { |review| Time.at(review['value']['lastModified'] / 1000) > upto_date }
415
+ break
416
+ end
417
+
418
+ if all_reviews.count < parse_response(r, 'data')['reviewCount']
419
+ index += per_page
420
+ else
421
+ break
422
+ end
423
+ end
424
+
425
+ all_reviews
426
+ end
427
+
428
+ #####################################################
429
+ # @!group AppVersions
430
+ #####################################################
431
+
432
+ def app_version(app_id, is_live, platform: nil)
433
+ raise "app_id is required" unless app_id
434
+
435
+ # First we need to fetch the IDs for the edit / live version
436
+ r = request(:get, "ra/apps/#{app_id}/overview")
437
+ platforms = parse_response(r, 'data')['platforms']
438
+
439
+ platform = Spaceship::Tunes::AppVersionCommon.find_platform(platforms, search_platform: platform)
440
+ return nil unless platform
441
+
442
+ version_id = Spaceship::Tunes::AppVersionCommon.find_version_id(platform, is_live)
443
+ return nil unless version_id
444
+
445
+ version_platform = platform['platformString']
446
+
447
+ app_version_data(app_id, version_platform: version_platform, version_id: version_id)
448
+ end
449
+
450
+ def app_version_data(app_id, version_platform: nil, version_id: nil)
451
+ raise "app_id is required" unless app_id
452
+ raise "version_platform is required" unless version_platform
453
+ raise "version_id is required" unless version_id
454
+
455
+ r = request(:get, "ra/apps/#{app_id}/platforms/#{version_platform}/versions/#{version_id}")
456
+ parse_response(r, 'data')
457
+ end
458
+
459
+ def update_app_version!(app_id, version_id, data)
460
+ raise "app_id is required" unless app_id
461
+ raise "version_id is required" unless version_id.to_i > 0
462
+
463
+ with_tunes_retry do
464
+ r = request(:post) do |req|
465
+ req.url("ra/apps/#{app_id}/platforms/ios/versions/#{version_id}")
466
+ req.body = data.to_json
467
+ req.headers['Content-Type'] = 'application/json'
468
+ end
469
+
470
+ handle_itc_response(r.body, flaky_api_call: true)
471
+ end
472
+ end
473
+
474
+ #####################################################
475
+ # @!group Members
476
+ #####################################################
477
+
478
+ def members
479
+ r = request(:get, "ra/users/itc")
480
+ parse_response(r, 'data')["users"]
481
+ end
482
+
483
+ def reinvite_member(email)
484
+ request(:post, "ra/users/itc/#{email}/resendInvitation")
485
+ end
486
+
487
+ def delete_member!(user_id, email)
488
+ payload = []
489
+ payload << {
490
+ dsId: user_id,
491
+ email: email
492
+ }
493
+ request(:post) do |req|
494
+ req.url("ra/users/itc/delete")
495
+ req.body = payload.to_json
496
+ req.headers['Content-Type'] = 'application/json'
497
+ end
498
+ end
499
+
500
+ def create_member!(firstname: nil, lastname: nil, email_address: nil, roles: [], apps: [])
501
+ r = request(:get, "ra/users/itc/create")
502
+ data = parse_response(r, 'data')
503
+
504
+ data["user"]["firstName"] = { value: firstname }
505
+ data["user"]["lastName"] = { value: lastname }
506
+ data["user"]["emailAddress"] = { value: email_address }
507
+
508
+ roles << "admin" if roles.length == 0
509
+
510
+ data["user"]["roles"] = []
511
+ roles.each do |role|
512
+ # find role from template
513
+ data["roles"].each do |template_role|
514
+ if template_role["value"]["name"] == role
515
+ data["user"]["roles"] << template_role
516
+ end
517
+ end
518
+ end
519
+
520
+ if apps.length == 0
521
+ data["user"]["userSoftwares"] = { value: { grantAllSoftware: true, grantedSoftwareAdamIds: [] } }
522
+ else
523
+ data["user"]["userSoftwares"] = { value: { grantAllSoftware: false, grantedSoftwareAdamIds: apps } }
524
+ end
525
+
526
+ # send the changes back to Apple
527
+ r = request(:post) do |req|
528
+ req.url("ra/users/itc/create")
529
+ req.body = data.to_json
530
+ req.headers['Content-Type'] = 'application/json'
531
+ end
532
+ handle_itc_response(r.body)
533
+ end
534
+
535
+ def update_member_roles!(member, roles: [], apps: [])
536
+ r = request(:get, "ra/users/itc/#{member.user_id}/roles")
537
+ data = parse_response(r, 'data')
538
+
539
+ roles << "admin" if roles.length == 0
540
+
541
+ data["user"]["roles"] = []
542
+ roles.each do |role|
543
+ # find role from template
544
+ data["roles"].each do |template_role|
545
+ if template_role["value"]["name"] == role
546
+ data["user"]["roles"] << template_role
547
+ end
548
+ end
549
+ end
550
+
551
+ if apps.length == 0
552
+ data["user"]["userSoftwares"] = { value: { grantAllSoftware: true, grantedSoftwareAdamIds: [] } }
553
+ else
554
+ data["user"]["userSoftwares"] = { value: { grantAllSoftware: false, grantedSoftwareAdamIds: apps } }
555
+ end
556
+
557
+ # send the changes back to Apple
558
+ r = request(:post) do |req|
559
+ req.url("ra/users/itc/#{member.user_id}/roles")
560
+ req.body = data.to_json
561
+ req.headers['Content-Type'] = 'application/json'
562
+ end
563
+ handle_itc_response(r.body)
564
+ end
565
+
566
+ #####################################################
567
+ # @!group AppAnalytics
568
+ #####################################################
569
+
570
+ def time_series_analytics(app_ids, measures, start_time, end_time, frequency, view_by)
571
+ data = {
572
+ adamId: app_ids,
573
+ dimensionFilters: [],
574
+ endTime: end_time,
575
+ frequency: frequency,
576
+ group: group_for_view_by(view_by, measures),
577
+ measures: measures,
578
+ startTime: start_time
579
+ }
580
+
581
+ r = request(:post) do |req|
582
+ req.url("https://analytics.itunes.apple.com/analytics/api/v1/data/time-series")
583
+ req.body = data.to_json
584
+ req.headers['Content-Type'] = 'application/json'
585
+ req.headers['X-Requested-By'] = 'analytics.itunes.apple.com'
586
+ end
587
+
588
+ data = parse_response(r)
589
+ end
590
+
591
+ #####################################################
592
+ # @!group Pricing
593
+ #####################################################
594
+
595
+ def update_price_tier!(app_id, price_tier)
596
+ r = request(:get, "ra/apps/#{app_id}/pricing/intervals")
597
+ data = parse_response(r, 'data')
598
+
599
+ # preOrder isn't needed for for the request and has some
600
+ # values that can cause a failure (invalid dates) so we are removing it
601
+ data.delete('preOrder')
602
+
603
+ first_price = (data["pricingIntervalsFieldTO"]["value"] || []).count == 0 # first price
604
+ data["pricingIntervalsFieldTO"]["value"] ||= []
605
+ data["pricingIntervalsFieldTO"]["value"] << {} if data["pricingIntervalsFieldTO"]["value"].count == 0
606
+ data["pricingIntervalsFieldTO"]["value"].first["tierStem"] = price_tier.to_s
607
+
608
+ effective_date = (first_price ? nil : Time.now.to_i * 1000)
609
+ data["pricingIntervalsFieldTO"]["value"].first["priceTierEffectiveDate"] = effective_date
610
+ data["pricingIntervalsFieldTO"]["value"].first["priceTierEndDate"] = nil
611
+ data["countriesChanged"] = first_price
612
+ data["theWorld"] = true
613
+
614
+ if first_price # first price, need to set all countries
615
+ data["countries"] = supported_countries.collect do |c|
616
+ c.delete('region') # we don't care about le region
617
+ c
618
+ end
619
+ end
620
+
621
+ # send the changes back to Apple
622
+ r = request(:post) do |req|
623
+ req.url("ra/apps/#{app_id}/pricing/intervals")
624
+ req.body = data.to_json
625
+ req.headers['Content-Type'] = 'application/json'
626
+ end
627
+ handle_itc_response(r.body)
628
+ end
629
+
630
+ def transform_to_raw_pricing_intervals(app_id = nil, purchase_id = nil, pricing_intervals = 5, subscription_price_target = nil)
631
+ intervals_array = []
632
+ if pricing_intervals
633
+ intervals_array = pricing_intervals.map do |interval|
634
+ {
635
+ "value" => {
636
+ "tierStem" => interval[:tier],
637
+ "priceTierEffectiveDate" => interval[:begin_date],
638
+ "priceTierEndDate" => interval[:end_date],
639
+ "country" => interval[:country] || "WW",
640
+ "grandfathered" => interval[:grandfathered]
641
+ }
642
+ }
643
+ end
644
+ end
645
+
646
+ if subscription_price_target
647
+ pricing_calculator = iap_subscription_pricing_target(app_id: app_id, purchase_id: purchase_id, currency: subscription_price_target[:currency], tier: subscription_price_target[:tier])
648
+ intervals_array = pricing_calculator.map do |language_code, value|
649
+ existing_interval =
650
+ if pricing_intervals
651
+ pricing_intervals.find { |interval| interval[:country] == language_code }
652
+ end
653
+ grandfathered =
654
+ if existing_interval
655
+ existing_interval[:grandfathered].clone
656
+ else
657
+ { "value" => "FUTURE_NONE" }
658
+ end
659
+
660
+ {
661
+ "value" => {
662
+ "tierStem" => value["tierStem"],
663
+ "priceTierEffectiveDate" => value["priceTierEffectiveDate"],
664
+ "priceTierEndDate" => value["priceTierEndDate"],
665
+ "country" => language_code,
666
+ "grandfathered" => grandfathered
667
+ }
668
+ }
669
+ end
670
+ end
671
+
672
+ intervals_array
673
+ end
674
+
675
+ def price_tier(app_id)
676
+ r = request(:get, "ra/apps/#{app_id}/pricing/intervals")
677
+ data = parse_response(r, 'data')
678
+
679
+ begin
680
+ data["pricingIntervalsFieldTO"]["value"].first["tierStem"]
681
+ rescue
682
+ nil
683
+ end
684
+ end
685
+
686
+ # Returns an array of all available pricing tiers
687
+ #
688
+ # @note Although this information is publicly available, the current spaceship implementation requires you to have a logged in client to access it
689
+ #
690
+ # @return [Array] the PricingTier objects (Spaceship::Tunes::PricingTier)
691
+ # [{
692
+ # "tierStem": "0",
693
+ # "tierName": "Free",
694
+ # "pricingInfo": [{
695
+ # "country": "United States",
696
+ # "countryCode": "US",
697
+ # "currencySymbol": "$",
698
+ # "currencyCode": "USD",
699
+ # "wholesalePrice": 0.0,
700
+ # "retailPrice": 0.0,
701
+ # "fRetailPrice": "$0.00",
702
+ # "fWholesalePrice": "$0.00"
703
+ # }, {
704
+ # ...
705
+ # }, {
706
+ # ...
707
+ def pricing_tiers
708
+ @pricing_tiers ||= begin
709
+ r = request(:get, 'ra/apps/pricing/matrix')
710
+ data = parse_response(r, 'data')['pricingTiers']
711
+ data.map { |tier| Spaceship::Tunes::PricingTier.factory(tier) }
712
+ end
713
+ end
714
+
715
+ #####################################################
716
+ # @!group Availability
717
+ #####################################################
718
+ # Updates the availability
719
+ #
720
+ # @note Although this information is publicly available, the current spaceship implementation requires you to have a logged in client to access it
721
+ # @param app_id (String): The id of your app
722
+ # @param availability (Availability): The availability update
723
+ #
724
+ # @return [Spaceship::Tunes::Availability] the new Availability
725
+ def update_availability!(app_id, availability)
726
+ r = request(:get, "ra/apps/#{app_id}/pricing/intervals")
727
+ data = parse_response(r, 'data')
728
+
729
+ data["countriesChanged"] = true
730
+ data["countries"] = availability.territories.map { |territory| { 'code' => territory.code } }
731
+ data["theWorld"] = availability.include_future_territories.nil? ? true : availability.include_future_territories
732
+
733
+ # InitializespreOrder (if needed)
734
+ data["preOrder"] ||= {}
735
+
736
+ # Sets app_available_date to nil if cleared_for_preorder if false
737
+ # This is need for apps that have never set either of these before
738
+ # API will error out if cleared_for_preorder is false and app_available_date has a date
739
+ cleared_for_preorder = availability.cleared_for_preorder
740
+ app_available_date = cleared_for_preorder ? availability.app_available_date : nil
741
+ data["b2bAppEnabled"] = availability.b2b_app_enabled
742
+ data["educationalDiscount"] = availability.educational_discount
743
+ data["preOrder"]["clearedForPreOrder"] = { "value" => cleared_for_preorder, "isEditable" => true, "isRequired" => true, "errorKeys" => nil }
744
+ data["preOrder"]["appAvailableDate"] = { "value" => app_available_date, "isEditable" => true, "isRequired" => true, "errorKeys" => nil }
745
+ data["b2bUsers"] = availability.b2b_app_enabled ? availability.b2b_users.map { |user| { "value" => { "add" => user.add, "delete" => user.delete, "dsUsername" => user.ds_username } } } : []
746
+ data["b2bOrganizations"] = availability.b2b_app_enabled ? availability.b2b_organizations.map { |org| { "value" => { "type" => org.type, "depCustomerId" => org.dep_customer_id, "organizationId" => org.dep_organization_id, "name" => org.name } } } : []
747
+ # send the changes back to Apple
748
+ r = request(:post) do |req|
749
+ req.url("ra/apps/#{app_id}/pricing/intervals")
750
+ req.body = data.to_json
751
+ req.headers['Content-Type'] = 'application/json'
752
+ end
753
+ handle_itc_response(r.body)
754
+ data = parse_response(r, 'data')
755
+ Spaceship::Tunes::Availability.factory(data)
756
+ end
757
+
758
+ def availability(app_id)
759
+ r = request(:get, "ra/apps/#{app_id}/pricing/intervals")
760
+ data = parse_response(r, 'data')
761
+ Spaceship::Tunes::Availability.factory(data)
762
+ end
763
+
764
+ # Returns an array of all supported territories
765
+ #
766
+ # @note Although this information is publicly available, the current spaceship implementation requires you to have a logged in client to access it
767
+ #
768
+ # @return [Array] the Territory objects (Spaceship::Tunes::Territory)
769
+ def supported_territories
770
+ data = supported_countries
771
+ data.map { |country| Spaceship::Tunes::Territory.factory(country) }
772
+ end
773
+
774
+ # An array of supported countries
775
+ # [{
776
+ # "code": "AL",
777
+ # "name": "Albania",
778
+ # "region": "Europe"
779
+ # }, {
780
+ # ...
781
+ def supported_countries
782
+ r = request(:get, "ra/apps/pricing/supportedCountries")
783
+ parse_response(r, 'data')
784
+ end
785
+
786
+ def available_languages
787
+ r = request(:get, "ra/ref")
788
+ parse_response(r, 'data')['detailLocales']
789
+ end
790
+
791
+ #####################################################
792
+ # @!group App Icons
793
+ #####################################################
794
+ # Uploads a large icon
795
+ # @param app_version (AppVersion): The version of your app
796
+ # @param upload_image (UploadFile): The icon to upload
797
+ # @return [JSON] the response
798
+ def upload_large_icon(app_version, upload_image)
799
+ raise "app_version is required" unless app_version
800
+ raise "upload_image is required" unless upload_image
801
+
802
+ du_client.upload_large_icon(app_version, upload_image, content_provider_id, sso_token_for_image)
803
+ end
804
+
805
+ # Uploads a watch icon
806
+ # @param app_version (AppVersion): The version of your app
807
+ # @param upload_image (UploadFile): The icon to upload
808
+ # @return [JSON] the response
809
+ def upload_watch_icon(app_version, upload_image)
810
+ raise "app_version is required" unless app_version
811
+ raise "upload_image is required" unless upload_image
812
+
813
+ du_client.upload_watch_icon(app_version, upload_image, content_provider_id, sso_token_for_image)
814
+ end
815
+
816
+ # Uploads an In-App-Purchase Promotional image
817
+ # @param upload_image (UploadFile): The icon to upload
818
+ # @return [JSON] the image data, ready to be added to an In-App-Purchase
819
+ def upload_purchase_merch_screenshot(app_id, upload_image)
820
+ data = du_client.upload_purchase_merch_screenshot(app_id, upload_image, content_provider_id, sso_token_for_image)
821
+ {
822
+ "images" => [
823
+ {
824
+ "id" => nil,
825
+ "image" => {
826
+ "value" => {
827
+ "assetToken" => data["token"],
828
+ "originalFileName" => upload_image.file_name,
829
+ "height" => data["height"],
830
+ "width" => data["width"],
831
+ "checksum" => data["md5"]
832
+ },
833
+ "isEditable" => true,
834
+ "isREquired" => false,
835
+ "errorKeys" => nil
836
+ },
837
+ "status" => "proposed"
838
+ }
839
+ ],
840
+ "showByDefault" => true,
841
+ "isActive" => false
842
+ }
843
+ end
844
+
845
+ # Uploads an In-App-Purchase Review screenshot
846
+ # @param app_id (AppId): The id of the app
847
+ # @param upload_image (UploadFile): The icon to upload
848
+ # @return [JSON] the screenshot data, ready to be added to an In-App-Purchase
849
+ def upload_purchase_review_screenshot(app_id, upload_image)
850
+ data = du_client.upload_purchase_review_screenshot(app_id, upload_image, content_provider_id, sso_token_for_image)
851
+ {
852
+ "value" => {
853
+ "assetToken" => data["token"],
854
+ "sortOrder" => 0,
855
+ "type" => du_client.get_picture_type(upload_image),
856
+ "originalFileName" => upload_image.file_name,
857
+ "size" => data["length"],
858
+ "height" => data["height"],
859
+ "width" => data["width"],
860
+ "checksum" => data["md5"]
861
+ }
862
+ }
863
+ end
864
+
865
+ # Uploads a screenshot
866
+ # @param app_version (AppVersion): The version of your app
867
+ # @param upload_image (UploadFile): The image to upload
868
+ # @param device (string): The target device
869
+ # @param is_messages (Bool): True if the screenshot is for iMessage
870
+ # @return [JSON] the response
871
+ def upload_screenshot(app_version, upload_image, device, is_messages)
872
+ raise "app_version is required" unless app_version
873
+ raise "upload_image is required" unless upload_image
874
+ raise "device is required" unless device
875
+
876
+ du_client.upload_screenshot(app_version, upload_image, content_provider_id, sso_token_for_image, device, is_messages)
877
+ end
878
+
879
+ # Uploads an iMessage screenshot
880
+ # @param app_version (AppVersion): The version of your app
881
+ # @param upload_image (UploadFile): The image to upload
882
+ # @param device (string): The target device
883
+ # @return [JSON] the response
884
+ def upload_messages_screenshot(app_version, upload_image, device)
885
+ raise "app_version is required" unless app_version
886
+ raise "upload_image is required" unless upload_image
887
+ raise "device is required" unless device
888
+
889
+ du_client.upload_messages_screenshot(app_version, upload_image, content_provider_id, sso_token_for_image, device)
890
+ end
891
+
892
+ # Uploads the transit app file
893
+ # @param app_version (AppVersion): The version of your app
894
+ # @param upload_file (UploadFile): The image to upload
895
+ # @return [JSON] the response
896
+ def upload_geojson(app_version, upload_file)
897
+ raise "app_version is required" unless app_version
898
+ raise "upload_file is required" unless upload_file
899
+
900
+ du_client.upload_geojson(app_version, upload_file, content_provider_id, sso_token_for_image)
901
+ end
902
+
903
+ # Uploads the transit app file
904
+ # @param app_version (AppVersion): The version of your app
905
+ # @param upload_trailer (UploadFile): The trailer to upload
906
+ # @return [JSON] the response
907
+ def upload_trailer(app_version, upload_trailer)
908
+ raise "app_version is required" unless app_version
909
+ raise "upload_trailer is required" unless upload_trailer
910
+
911
+ du_client.upload_trailer(app_version, upload_trailer, content_provider_id, sso_token_for_video)
912
+ end
913
+
914
+ # Uploads the trailer preview
915
+ # @param app_version (AppVersion): The version of your app
916
+ # @param upload_trailer_preview (UploadFile): The trailer preview to upload
917
+ # @param device (string): The target device
918
+ # @return [JSON] the response
919
+ def upload_trailer_preview(app_version, upload_trailer_preview, device)
920
+ raise "app_version is required" unless app_version
921
+ raise "upload_trailer_preview is required" unless upload_trailer_preview
922
+ raise "device is required" unless device
923
+
924
+ du_client.upload_trailer_preview(app_version, upload_trailer_preview, content_provider_id, sso_token_for_image, device)
925
+ end
926
+
927
+ #####################################################
928
+ # @!review attachment file
929
+ #####################################################
930
+ # Uploads a attachment file
931
+ # @param app_version (AppVersion): The version of your app(must be edit version)
932
+ # @param upload_attachment_file (file): File to upload
933
+ # @return [JSON] the response
934
+ def upload_app_review_attachment(app_version, upload_attachment_file)
935
+ raise "app_version is required" unless app_version
936
+ raise "app_version must be live version" if app_version.is_live?
937
+ raise "upload_attachment_file is required" unless upload_attachment_file
938
+
939
+ du_client.upload_app_review_attachment(app_version, upload_attachment_file, content_provider_id, sso_token_for_image)
940
+ end
941
+
942
+ # Fetches the App Version Reference information from ITC
943
+ # @return [AppVersionRef] the response
944
+ def ref_data
945
+ r = request(:get, '/WebObjects/iTunesConnect.woa/ra/apps/version/ref')
946
+ data = parse_response(r, 'data')
947
+ Spaceship::Tunes::AppVersionRef.factory(data)
948
+ end
949
+
950
+ # Fetches the User Detail information from ITC. This gets called often and almost never changes
951
+ # so we cache it
952
+ # @return [UserDetail] the response
953
+ def user_detail_data
954
+ @_cached_user_detail_data ||= Spaceship::Tunes::UserDetail.factory(user_details_data, self)
955
+ end
956
+
957
+ #####################################################
958
+ # @!group CandiateBuilds
959
+ #####################################################
960
+
961
+ def candidate_builds(app_id, version_id)
962
+ r = request(:get, "ra/apps/#{app_id}/versions/#{version_id}/candidateBuilds")
963
+ parse_response(r, 'data')['builds']
964
+ end
965
+
966
+ #####################################################
967
+ # @!group Build Trains
968
+ #####################################################
969
+
970
+ # rubocop:disable Metrics/BlockNesting
971
+ # @param (testing_type) internal or external
972
+ def build_trains(app_id, testing_type, tries = 5, platform: nil)
973
+ raise "app_id is required" unless app_id
974
+ url = "ra/apps/#{app_id}/trains/?testingType=#{testing_type}"
975
+ url += "&platform=#{platform}" unless platform.nil?
976
+ r = request(:get, url)
977
+ return parse_response(r, 'data')
978
+ rescue Spaceship::Client::UnexpectedResponse => ex
979
+ # Build trains fail randomly very often
980
+ # we need to catch those errors and retry
981
+ # https://github.com/fastlane/fastlane/issues/6419
982
+ retry_error_messages = [
983
+ "ITC.response.error.OPERATION_FAILED",
984
+ "Internal Server Error",
985
+ "Service Unavailable"
986
+ ].freeze
987
+
988
+ if retry_error_messages.any? { |message| ex.to_s.include?(message) }
989
+ tries -= 1
990
+ if tries > 0
991
+ logger.warn("Received temporary server error from App Store Connect. Retrying the request...")
992
+ sleep(3) unless Object.const_defined?("SpecHelper")
993
+ retry
994
+ end
995
+ end
996
+
997
+ raise Spaceship::Client::UnexpectedResponse, "Temporary App Store Connect error: #{ex}"
998
+ end
999
+ # rubocop:enable Metrics/BlockNesting
1000
+
1001
+ def update_build_trains!(app_id, testing_type, data)
1002
+ raise "app_id is required" unless app_id
1003
+
1004
+ # The request fails if this key is present in the data
1005
+ data.delete("dailySubmissionCountByPlatform")
1006
+
1007
+ r = request(:post) do |req|
1008
+ req.url("ra/apps/#{app_id}/testingTypes/#{testing_type}/trains/")
1009
+ req.body = data.to_json
1010
+ req.headers['Content-Type'] = 'application/json'
1011
+ end
1012
+
1013
+ handle_itc_response(r.body)
1014
+ end
1015
+
1016
+ def remove_testflight_build_from_review!(app_id: nil, train: nil, build_number: nil, platform: 'ios')
1017
+ r = request(:post) do |req|
1018
+ req.url("ra/apps/#{app_id}/platforms/#{platform}/trains/#{train}/builds/#{build_number}/reject")
1019
+ req.body = {}.to_json
1020
+ req.headers['Content-Type'] = 'application/json'
1021
+ end
1022
+ handle_itc_response(r.body)
1023
+ end
1024
+
1025
+ # All build trains, even if there is no TestFlight
1026
+ def all_build_trains(app_id: nil, platform: 'ios')
1027
+ platform = 'ios' if platform.nil?
1028
+ r = request(:get, "ra/apps/#{app_id}/buildHistory?platform=#{platform}")
1029
+ handle_itc_response(r.body)
1030
+ end
1031
+
1032
+ def all_builds_for_train(app_id: nil, train: nil, platform: 'ios')
1033
+ platform = 'ios' if platform.nil?
1034
+ r = request(:get, "ra/apps/#{app_id}/trains/#{train}/buildHistory?platform=#{platform}")
1035
+ handle_itc_response(r.body)
1036
+ end
1037
+
1038
+ def build_details(app_id: nil, train: nil, build_number: nil, platform: nil)
1039
+ r = request(:get, "ra/apps/#{app_id}/platforms/#{platform || 'ios'}/trains/#{train}/builds/#{build_number}/details")
1040
+ handle_itc_response(r.body)
1041
+ end
1042
+
1043
+ def update_build_information!(app_id: nil,
1044
+ train: nil,
1045
+ build_number: nil,
1046
+
1047
+ # optional:
1048
+ whats_new: nil,
1049
+ description: nil,
1050
+ feedback_email: nil,
1051
+ platform: 'ios')
1052
+ url = "ra/apps/#{app_id}/platforms/#{platform}/trains/#{train}/builds/#{build_number}/testInformation"
1053
+
1054
+ build_info = get_build_info_for_review(app_id: app_id, train: train, build_number: build_number, platform: platform)
1055
+ build_info["details"].each do |current|
1056
+ current["whatsNew"]["value"] = whats_new if whats_new
1057
+ current["description"]["value"] = description if description
1058
+ current["feedbackEmail"]["value"] = feedback_email if feedback_email
1059
+ end
1060
+
1061
+ review_user_name = build_info['reviewUserName']['value']
1062
+ review_password = build_info['reviewPassword']['value']
1063
+ build_info['reviewAccountRequired']['value'] = (review_user_name.to_s + review_password.to_s).length > 0
1064
+
1065
+ # Now send everything back to iTC
1066
+ r = request(:post) do |req| # same URL, but a POST request
1067
+ req.url(url)
1068
+ req.body = build_info.to_json
1069
+ req.headers['Content-Type'] = 'application/json'
1070
+ end
1071
+ handle_itc_response(r.body)
1072
+ end
1073
+
1074
+ # rubocop:disable Metrics/ParameterLists
1075
+ def submit_testflight_build_for_review!(app_id: nil, train: nil, build_number: nil, platform: 'ios',
1076
+ # Required Metadata:
1077
+ changelog: nil,
1078
+ description: nil,
1079
+ feedback_email: nil,
1080
+ marketing_url: nil,
1081
+ first_name: nil,
1082
+ last_name: nil,
1083
+ review_email: nil,
1084
+ phone_number: nil,
1085
+ significant_change: false,
1086
+
1087
+ # Optional Metadata:
1088
+ privacy_policy_url: nil,
1089
+ review_user_name: nil,
1090
+ review_password: nil,
1091
+ review_notes: nil,
1092
+ encryption: false,
1093
+ encryption_updated: false,
1094
+ is_exempt: false,
1095
+ proprietary: false,
1096
+ third_party: false)
1097
+
1098
+ build_info = get_build_info_for_review(app_id: app_id, train: train, build_number: build_number, platform: platform)
1099
+ # Now fill in the values provided by the user
1100
+
1101
+ # First the localized values:
1102
+ build_info['details'].each do |current|
1103
+ current['whatsNew']['value'] = changelog if changelog
1104
+ current['description']['value'] = description if description
1105
+ current['feedbackEmail']['value'] = feedback_email if feedback_email
1106
+ current['marketingUrl']['value'] = marketing_url if marketing_url
1107
+ current['privacyPolicyUrl']['value'] = privacy_policy_url if privacy_policy_url
1108
+ current['pageLanguageValue'] = current['language'] # There is no valid reason why we need this, only iTC being iTC
1109
+ end
1110
+
1111
+ review_info = {
1112
+ "significantChange" => {
1113
+ "value" => significant_change
1114
+ },
1115
+ "buildTestInformationTO" => build_info,
1116
+ "exportComplianceTO" => {
1117
+ "usesEncryption" => {
1118
+ "value" => encryption
1119
+ },
1120
+ "encryptionUpdated" => {
1121
+ "value" => encryption_updated
1122
+ },
1123
+ "isExempt" => {
1124
+ "value" => is_exempt
1125
+ },
1126
+ "containsProprietaryCryptography" => {
1127
+ "value" => proprietary
1128
+ },
1129
+ "containsThirdPartyCryptography" => {
1130
+ "value" => third_party
1131
+ }
1132
+ }
1133
+ }
1134
+
1135
+ r = request(:post) do |req| # same URL, but a POST request
1136
+ req.url("ra/apps/#{app_id}/platforms/#{platform}/trains/#{train}/builds/#{build_number}/review/submit")
1137
+
1138
+ req.body = review_info.to_json
1139
+ req.headers['Content-Type'] = 'application/json'
1140
+ end
1141
+ handle_itc_response(r.body)
1142
+ end
1143
+ # rubocop:enable Metrics/ParameterLists
1144
+
1145
+ def get_build_info_for_review(app_id: nil, train: nil, build_number: nil, platform: 'ios')
1146
+ url = "ra/apps/#{app_id}/platforms/#{platform}/trains/#{train}/builds/#{build_number}/testInformation"
1147
+ r = request(:get) do |req|
1148
+ req.url(url)
1149
+ req.headers['Content-Type'] = 'application/json'
1150
+ end
1151
+ handle_itc_response(r.body)
1152
+
1153
+ r.body['data']
1154
+ end
1155
+
1156
+ #####################################################
1157
+ # @!group Submit for Review
1158
+ #####################################################
1159
+
1160
+ def prepare_app_submissions(app_id, version)
1161
+ raise "app_id is required" unless app_id
1162
+ raise "version is required" unless version
1163
+
1164
+ r = request(:get) do |req|
1165
+ req.url("ra/apps/#{app_id}/versions/#{version}/submit/summary")
1166
+ req.headers['Content-Type'] = 'application/json'
1167
+ end
1168
+
1169
+ handle_itc_response(r.body)
1170
+ parse_response(r, 'data')
1171
+ end
1172
+
1173
+ def send_app_submission(app_id, version, data)
1174
+ raise "app_id is required" unless app_id
1175
+
1176
+ # ra/apps/1039164429/version/submit/complete
1177
+ r = request(:post) do |req|
1178
+ req.url("ra/apps/#{app_id}/versions/#{version}/submit/complete")
1179
+ req.body = data.to_json
1180
+ req.headers['Content-Type'] = 'application/json'
1181
+ end
1182
+
1183
+ handle_itc_response(r.body)
1184
+
1185
+ # App Store Connect still returns a success status code even the submission
1186
+ # was failed because of Ad ID Info / Export Compliance. This checks for any section error
1187
+ # keys in returned adIdInfo / exportCompliance and prints them out.
1188
+ ad_id_error_keys = r.body.fetch('data').fetch('adIdInfo').fetch('sectionErrorKeys')
1189
+ export_error_keys = r.body.fetch('data').fetch('exportCompliance').fetch('sectionErrorKeys')
1190
+ if ad_id_error_keys.any?
1191
+ raise "Something wrong with your Ad ID information: #{ad_id_error_keys}."
1192
+ elsif export_error_keys.any?
1193
+ raise "Something wrong with your Export Compliance: #{export_error_keys}"
1194
+ elsif r.body.fetch('messages').fetch('info').last == "Successful POST"
1195
+ # success
1196
+ else
1197
+ raise "Something went wrong when submitting the app for review. Make sure to pass valid options to submit your app for review"
1198
+ end
1199
+
1200
+ parse_response(r, 'data')
1201
+ end
1202
+
1203
+ #####################################################
1204
+ # @!group release
1205
+ #####################################################
1206
+
1207
+ def release!(app_id, version)
1208
+ raise "app_id is required" unless app_id
1209
+ raise "version is required" unless version
1210
+
1211
+ r = request(:post) do |req|
1212
+ req.url("ra/apps/#{app_id}/versions/#{version}/releaseToStore")
1213
+ req.headers['Content-Type'] = 'application/json'
1214
+ req.body = app_id.to_s
1215
+ end
1216
+
1217
+ handle_itc_response(r.body)
1218
+ parse_response(r, 'data')
1219
+ end
1220
+
1221
+ #####################################################
1222
+ # @!group release to all users
1223
+ #####################################################
1224
+
1225
+ def release_to_all_users!(app_id, version)
1226
+ raise "app_id is required" unless app_id
1227
+ raise "version is required" unless version
1228
+
1229
+ r = request(:post) do |req|
1230
+ req.url("ra/apps/#{app_id}/versions/#{version}/phasedRelease/state/COMPLETE")
1231
+ req.headers['Content-Type'] = 'application/json'
1232
+ req.body = app_id.to_s
1233
+ end
1234
+
1235
+ handle_itc_response(r.body)
1236
+ parse_response(r, 'data')
1237
+ end
1238
+
1239
+ #####################################################
1240
+ # @!group in-app-purchases
1241
+ #####################################################
1242
+
1243
+ # Returns list of all available In-App-Purchases
1244
+ def iaps(app_id: nil)
1245
+ r = request(:get, "ra/apps/#{app_id}/iaps")
1246
+ return r.body["data"]
1247
+ end
1248
+
1249
+ # Returns list of all available Families
1250
+ def iap_families(app_id: nil)
1251
+ r = request(:get, "ra/apps/#{app_id}/iaps/families")
1252
+ return r.body["data"]
1253
+ end
1254
+
1255
+ # Deletes a In-App-Purchases
1256
+ def delete_iap!(app_id: nil, purchase_id: nil)
1257
+ r = request(:delete, "ra/apps/#{app_id}/iaps/#{purchase_id}")
1258
+ handle_itc_response(r)
1259
+ end
1260
+
1261
+ # Loads the full In-App-Purchases
1262
+ def load_iap(app_id: nil, purchase_id: nil)
1263
+ r = request(:get, "ra/apps/#{app_id}/iaps/#{purchase_id}")
1264
+ parse_response(r, 'data')
1265
+ end
1266
+
1267
+ # Submit the In-App-Purchase for review
1268
+ def submit_iap!(app_id: nil, purchase_id: nil)
1269
+ r = request(:post, "ra/apps/#{app_id}/iaps/#{purchase_id}/submission")
1270
+ handle_itc_response(r)
1271
+ end
1272
+
1273
+ # Loads the full In-App-Purchases-Family
1274
+ def load_iap_family(app_id: nil, family_id: nil)
1275
+ r = request(:get, "ra/apps/#{app_id}/iaps/family/#{family_id}")
1276
+ parse_response(r, 'data')
1277
+ end
1278
+
1279
+ # Loads the full In-App-Purchases-Pricing-Matrix
1280
+ # note: the matrix is the same for any app_id
1281
+ #
1282
+ # @param app_id (String) The Apple ID of any app
1283
+ # @return ([Spaceship::Tunes::IAPSubscriptionPricingTier]) An array of pricing tiers
1284
+ def subscription_pricing_tiers(app_id)
1285
+ @subscription_pricing_tiers ||= begin
1286
+ r = request(:get, "ra/apps/#{app_id}/iaps/pricing/matrix/recurring")
1287
+ data = parse_response(r, "data")["pricingTiers"]
1288
+ data.map { |tier| Spaceship::Tunes::IAPSubscriptionPricingTier.factory(tier) }
1289
+ end
1290
+ end
1291
+
1292
+ # updates an In-App-Purchases-Family
1293
+ def update_iap_family!(app_id: nil, family_id: nil, data: nil)
1294
+ with_tunes_retry do
1295
+ r = request(:put) do |req|
1296
+ req.url("ra/apps/#{app_id}/iaps/family/#{family_id}/")
1297
+ req.body = data.to_json
1298
+ req.headers['Content-Type'] = 'application/json'
1299
+ end
1300
+ handle_itc_response(r.body)
1301
+ end
1302
+ end
1303
+
1304
+ # updates an In-App-Purchases
1305
+ def update_iap!(app_id: nil, purchase_id: nil, data: nil)
1306
+ with_tunes_retry do
1307
+ r = request(:put) do |req|
1308
+ req.url("ra/apps/#{app_id}/iaps/#{purchase_id}")
1309
+ req.body = data.to_json
1310
+ req.headers['Content-Type'] = 'application/json'
1311
+ end
1312
+ handle_itc_response(r.body)
1313
+ end
1314
+ end
1315
+
1316
+ def update_recurring_iap_pricing!(app_id: nil, purchase_id: nil, pricing_intervals: nil)
1317
+ with_tunes_retry do
1318
+ r = request(:post) do |req|
1319
+ pricing_data = {}
1320
+ req.url("ra/apps/#{app_id}/iaps/#{purchase_id}/pricing/subscriptions")
1321
+ pricing_data["subscriptions"] = pricing_intervals
1322
+ req.body = pricing_data.to_json
1323
+ req.headers['Content-Type'] = 'application/json'
1324
+ end
1325
+ handle_itc_response(r.body)
1326
+ end
1327
+ end
1328
+
1329
+ def load_recurring_iap_pricing(app_id: nil, purchase_id: nil)
1330
+ r = request(:get, "ra/apps/#{app_id}/iaps/#{purchase_id}/pricing")
1331
+ parse_response(r, 'data')
1332
+ end
1333
+
1334
+ def create_iap_family(app_id: nil, name: nil, product_id: nil, reference_name: nil, versions: [])
1335
+ r = request(:get, "ra/apps/#{app_id}/iaps/family/template")
1336
+ data = parse_response(r, 'data')
1337
+
1338
+ data['activeAddOns'][0]['productId'] = { value: product_id }
1339
+ data['activeAddOns'][0]['referenceName'] = { value: reference_name }
1340
+ data['name'] = { value: name }
1341
+ data["details"]["value"] = versions
1342
+
1343
+ r = request(:post) do |req|
1344
+ req.url("ra/apps/#{app_id}/iaps/family/")
1345
+ req.body = data.to_json
1346
+ req.headers['Content-Type'] = 'application/json'
1347
+ end
1348
+ handle_itc_response(r.body)
1349
+ end
1350
+
1351
+ # returns pricing goal array
1352
+ def iap_subscription_pricing_target(app_id: nil, purchase_id: nil, currency: nil, tier: nil)
1353
+ r = request(:get, "ra/apps/#{app_id}/iaps/#{purchase_id}/pricing/equalize/#{currency}/#{tier}")
1354
+ parse_response(r, 'data')
1355
+ end
1356
+
1357
+ # Creates an In-App-Purchases
1358
+ def create_iap!(app_id: nil, type: nil, versions: nil, reference_name: nil, product_id: nil, cleared_for_sale: true, merch_screenshot: nil, review_notes: nil, review_screenshot: nil, pricing_intervals: nil, family_id: nil, subscription_duration: nil, subscription_free_trial: nil)
1359
+ # Load IAP Template based on Type
1360
+ type ||= "consumable"
1361
+ r = request(:get, "ra/apps/#{app_id}/iaps/#{type}/template")
1362
+ data = parse_response(r, 'data')
1363
+
1364
+ # Now fill in the values we have
1365
+ # some values are nil, that's why there is a hash
1366
+ data['familyId'] = family_id.to_s if family_id
1367
+ data['productId'] = { value: product_id }
1368
+ data['referenceName'] = { value: reference_name }
1369
+ data['clearedForSale'] = { value: cleared_for_sale }
1370
+
1371
+ data['pricingDurationType'] = { value: subscription_duration } if subscription_duration
1372
+ data['freeTrialDurationType'] = { value: subscription_free_trial } if subscription_free_trial
1373
+
1374
+ # pricing tier
1375
+ if pricing_intervals
1376
+ data['pricingIntervals'] = []
1377
+ pricing_intervals.each do |interval|
1378
+ data['pricingIntervals'] << {
1379
+ value: {
1380
+ country: interval[:country] || "WW",
1381
+ tierStem: interval[:tier].to_s,
1382
+ priceTierEndDate: interval[:end_date],
1383
+ priceTierEffectiveDate: interval[:begin_date]
1384
+ }
1385
+ }
1386
+ end
1387
+ end
1388
+
1389
+ versions_array = []
1390
+ versions.each do |k, v|
1391
+ versions_array << {
1392
+ value: {
1393
+ description: { value: v[:description] },
1394
+ name: { value: v[:name] },
1395
+ localeCode: k.to_s
1396
+ }
1397
+ }
1398
+ end
1399
+ data["versions"][0]["details"]["value"] = versions_array
1400
+ data['versions'][0]["reviewNotes"] = { value: review_notes }
1401
+
1402
+ if merch_screenshot
1403
+ # Upload App Store Promotional image (Optional)
1404
+ upload_file = UploadFile.from_path(merch_screenshot)
1405
+ merch_data = upload_purchase_merch_screenshot(app_id, upload_file)
1406
+ data["versions"][0]["merch"] = merch_data
1407
+ end
1408
+
1409
+ if review_screenshot
1410
+ # Upload Screenshot:
1411
+ upload_file = UploadFile.from_path(review_screenshot)
1412
+ screenshot_data = upload_purchase_review_screenshot(app_id, upload_file)
1413
+ data["versions"][0]["reviewScreenshot"] = screenshot_data
1414
+ end
1415
+
1416
+ # Now send back the modified hash
1417
+ r = request(:post) do |req|
1418
+ req.url("ra/apps/#{app_id}/iaps")
1419
+ req.body = data.to_json
1420
+ req.headers['Content-Type'] = 'application/json'
1421
+ end
1422
+ handle_itc_response(r.body)
1423
+ end
1424
+
1425
+ # Retrieves app-specific shared secret key
1426
+ def get_shared_secret(app_id: nil)
1427
+ r = request(:get, "ra/apps/#{app_id}/iaps/appSharedSecret")
1428
+ data = parse_response(r, 'data')
1429
+ data['sharedSecret']
1430
+ end
1431
+
1432
+ # Generates app-specific shared secret key
1433
+ def generate_shared_secret(app_id: nil)
1434
+ r = request(:post, "ra/apps/#{app_id}/iaps/appSharedSecret")
1435
+ data = parse_response(r, 'data')
1436
+ data['sharedSecret']
1437
+ end
1438
+
1439
+ #####################################################
1440
+ # @!group Sandbox Testers
1441
+ #####################################################
1442
+ def sandbox_testers(tester_class)
1443
+ url = tester_class.url[:index]
1444
+ r = request(:get, url)
1445
+ parse_response(r, 'data')
1446
+ end
1447
+
1448
+ def create_sandbox_tester!(tester_class: nil, email: nil, password: nil, first_name: nil, last_name: nil, country: nil)
1449
+ url = tester_class.url[:create]
1450
+ r = request(:post) do |req|
1451
+ req.url(url)
1452
+ req.body = {
1453
+ user: {
1454
+ emailAddress: { value: email },
1455
+ password: { value: password },
1456
+ confirmPassword: { value: password },
1457
+ firstName: { value: first_name },
1458
+ lastName: { value: last_name },
1459
+ storeFront: { value: country },
1460
+ birthDay: { value: 1 },
1461
+ birthMonth: { value: 1 },
1462
+ secretQuestion: { value: SecureRandom.hex },
1463
+ secretAnswer: { value: SecureRandom.hex },
1464
+ sandboxAccount: nil
1465
+ }
1466
+ }.to_json
1467
+ req.headers['Content-Type'] = 'application/json'
1468
+ end
1469
+ response_object = parse_response(r, 'data')
1470
+ errors = response_object['sectionErrorKeys']
1471
+ raise ITunesConnectError, errors.join(' ') unless errors.empty?
1472
+ response_object['user']
1473
+ end
1474
+
1475
+ def delete_sandbox_testers!(tester_class, emails)
1476
+ url = tester_class.url[:delete]
1477
+ request(:post) do |req|
1478
+ req.url(url)
1479
+ req.body = emails.map do |email|
1480
+ {
1481
+ emailAddress: {
1482
+ value: email
1483
+ }
1484
+ }
1485
+ end.to_json
1486
+ req.headers['Content-Type'] = 'application/json'
1487
+ end
1488
+ true
1489
+ end
1490
+
1491
+ #####################################################
1492
+ # @!group State History
1493
+ #####################################################
1494
+ def versions_history(app_id, platform)
1495
+ r = request(:get, "ra/apps/#{app_id}/stateHistory?platform=#{platform}")
1496
+ parse_response(r, 'data')['versions']
1497
+ end
1498
+
1499
+ def version_states_history(app_id, platform, version_id)
1500
+ r = request(:get, "ra/apps/#{app_id}/versions/#{version_id}/stateHistory?platform=#{platform}")
1501
+ parse_response(r, 'data')
1502
+ end
1503
+
1504
+ #####################################################
1505
+ # @!group Promo codes
1506
+ #####################################################
1507
+ def app_promocodes(app_id: nil)
1508
+ r = request(:get, "ra/apps/#{app_id}/promocodes/versions")
1509
+ parse_response(r, 'data')['versions']
1510
+ end
1511
+
1512
+ def generate_app_version_promocodes!(app_id: nil, version_id: nil, quantity: nil)
1513
+ data = [{
1514
+ numberOfCodes: quantity,
1515
+ agreedToContract: true,
1516
+ versionId: version_id
1517
+ }]
1518
+ url = "ra/apps/#{app_id}/promocodes/versions"
1519
+ r = request(:post) do |req|
1520
+ req.url(url)
1521
+ req.body = data.to_json
1522
+ req.headers['Content-Type'] = 'application/json'
1523
+ end
1524
+ parse_response(r, 'data')
1525
+ end
1526
+
1527
+ def app_promocodes_history(app_id: nil)
1528
+ r = request(:get, "ra/apps/#{app_id}/promocodes/history")
1529
+ parse_response(r, 'data')['requests']
1530
+ end
1531
+
1532
+ #####################################################
1533
+ # @!group reject
1534
+ #####################################################
1535
+
1536
+ def reject!(app_id, version)
1537
+ raise "app_id is required" unless app_id
1538
+ raise "version is required" unless version
1539
+
1540
+ r = request(:post) do |req|
1541
+ req.url("ra/apps/#{app_id}/versions/#{version}/reject")
1542
+ req.headers['Content-Type'] = 'application/json'
1543
+ req.body = app_id.to_s
1544
+ end
1545
+
1546
+ handle_itc_response(r.body)
1547
+ parse_response(r, 'data')
1548
+ end
1549
+
1550
+ private
1551
+
1552
+ def with_tunes_retry(tries = 5, potential_server_error_tries = 3, &_block)
1553
+ return yield
1554
+ rescue Spaceship::TunesClient::ITunesConnectTemporaryError => ex
1555
+ seconds_to_sleep = 60
1556
+ unless (tries -= 1).zero?
1557
+ msg = "App Store Connect temporary error received: '#{ex.message}'. Retrying after #{seconds_to_sleep} seconds (remaining: #{tries})..."
1558
+ puts(msg)
1559
+ logger.warn(msg)
1560
+ sleep(seconds_to_sleep) unless Object.const_defined?("SpecHelper")
1561
+ retry
1562
+ end
1563
+ raise ex # re-raise the exception
1564
+ rescue Spaceship::TunesClient::ITunesConnectPotentialServerError => ex
1565
+ seconds_to_sleep = 10
1566
+ unless (potential_server_error_tries -= 1).zero?
1567
+ msg = "Potential server error received: '#{ex.message}'. Retrying after 10 seconds (remaining: #{potential_server_error_tries})..."
1568
+ puts(msg)
1569
+ logger.warn(msg)
1570
+ sleep(seconds_to_sleep) unless Object.const_defined?("SpecHelper")
1571
+ retry
1572
+ end
1573
+ raise ex
1574
+ end
1575
+
1576
+ def clear_user_cached_data
1577
+ @content_provider_id = nil
1578
+ @sso_token_for_image = nil
1579
+ @sso_token_for_video = nil
1580
+ end
1581
+
1582
+ # the contentProviderIr found in the UserDetail instance
1583
+ def content_provider_id
1584
+ @content_provider_id ||= user_detail_data.content_provider_id
1585
+ end
1586
+
1587
+ # the ssoTokenForImage found in the AppVersionRef instance
1588
+ def sso_token_for_image
1589
+ @sso_token_for_image ||= ref_data.sso_token_for_image
1590
+ end
1591
+
1592
+ # the ssoTokenForVideo found in the AppVersionRef instance
1593
+ def sso_token_for_video
1594
+ @sso_token_for_video ||= ref_data.sso_token_for_video
1595
+ end
1596
+
1597
+ # generates group hash used in the analytics time_series API.
1598
+ # Using rank=DESCENDING and limit=3 as this is what the App Store Connect analytics dashboard uses.
1599
+ def group_for_view_by(view_by, measures)
1600
+ if view_by.nil? || measures.nil?
1601
+ return nil
1602
+ else
1603
+ return {
1604
+ metric: measures.first,
1605
+ dimension: view_by,
1606
+ rank: "DESCENDING",
1607
+ limit: 3
1608
+ }
1609
+ end
1610
+ end
1611
+
1612
+ def update_tester_from_app!(tester, app_id, testing)
1613
+ url = tester.class.url(app_id)[:update_by_app]
1614
+ data = {
1615
+ users: [
1616
+ {
1617
+ emailAddress: {
1618
+ value: tester.email
1619
+ },
1620
+ firstName: {
1621
+ value: tester.first_name
1622
+ },
1623
+ lastName: {
1624
+ value: tester.last_name
1625
+ },
1626
+ testing: {
1627
+ value: testing
1628
+ }
1629
+ }
1630
+ ]
1631
+ }
1632
+
1633
+ r = request(:post) do |req|
1634
+ req.url(url)
1635
+ req.body = data.to_json
1636
+ req.headers['Content-Type'] = 'application/json'
1637
+ end
1638
+
1639
+ data = parse_response(r, 'data')
1640
+ handle_itc_response(data)
1641
+ end
1642
+ end
1643
+ # rubocop:enable Metrics/ClassLength
1644
+ end