fastlane 2.159.0 → 2.164.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +74 -74
  3. data/cert/lib/cert/options.rb +28 -1
  4. data/cert/lib/cert/runner.rb +50 -33
  5. data/deliver/lib/deliver/app_screenshot_iterator.rb +4 -4
  6. data/deliver/lib/deliver/module.rb +2 -0
  7. data/deliver/lib/deliver/options.rb +20 -4
  8. data/deliver/lib/deliver/queue_worker.rb +14 -29
  9. data/deliver/lib/deliver/runner.rb +36 -8
  10. data/deliver/lib/deliver/upload_metadata.rb +51 -10
  11. data/deliver/lib/deliver/upload_price_tier.rb +7 -2
  12. data/deliver/lib/deliver/upload_screenshots.rb +28 -13
  13. data/fastlane/lib/fastlane/actions/actions_helper.rb +20 -1
  14. data/fastlane/lib/fastlane/actions/app_store_build_number.rb +39 -3
  15. data/fastlane/lib/fastlane/actions/app_store_connect_api_key.rb +15 -1
  16. data/fastlane/lib/fastlane/actions/check_app_store_metadata.rb +1 -0
  17. data/fastlane/lib/fastlane/actions/clean_build_artifacts.rb +1 -0
  18. data/fastlane/lib/fastlane/actions/docs/capture_android_screenshots.md +2 -2
  19. data/fastlane/lib/fastlane/actions/docs/capture_ios_screenshots.md +2 -2
  20. data/fastlane/lib/fastlane/actions/docs/create_app_online.md +1 -1
  21. data/fastlane/lib/fastlane/actions/docs/frame_screenshots.md +3 -2
  22. data/fastlane/lib/fastlane/actions/docs/run_tests.md +2 -2
  23. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +12 -3
  24. data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +2 -2
  25. data/fastlane/lib/fastlane/actions/docs/upload_to_testflight.md +1 -1
  26. data/fastlane/lib/fastlane/actions/download_dsyms.rb +31 -6
  27. data/fastlane/lib/fastlane/actions/ensure_git_status_clean.rb +13 -2
  28. data/fastlane/lib/fastlane/actions/get_certificates.rb +1 -0
  29. data/fastlane/lib/fastlane/actions/get_provisioning_profile.rb +1 -0
  30. data/fastlane/lib/fastlane/actions/import_from_git.rb +9 -1
  31. data/fastlane/lib/fastlane/actions/is_ci.rb +1 -1
  32. data/fastlane/lib/fastlane/actions/latest_testflight_build_number.rb +15 -0
  33. data/fastlane/lib/fastlane/actions/register_device.rb +46 -5
  34. data/fastlane/lib/fastlane/actions/register_devices.rb +50 -16
  35. data/fastlane/lib/fastlane/actions/set_changelog.rb +31 -3
  36. data/fastlane/lib/fastlane/actions/sync_code_signing.rb +1 -0
  37. data/fastlane/lib/fastlane/actions/upload_to_app_store.rb +3 -2
  38. data/fastlane/lib/fastlane/fast_file.rb +74 -23
  39. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +1 -0
  40. data/fastlane/lib/fastlane/version.rb +1 -1
  41. data/fastlane/swift/Deliverfile.swift +1 -1
  42. data/fastlane/swift/DeliverfileProtocol.swift +13 -5
  43. data/fastlane/swift/Fastlane.swift +170 -44
  44. data/fastlane/swift/Gymfile.swift +1 -1
  45. data/fastlane/swift/GymfileProtocol.swift +1 -1
  46. data/fastlane/swift/LaneFileProtocol.swift +28 -36
  47. data/fastlane/swift/MainProcess.swift +1 -1
  48. data/fastlane/swift/Matchfile.swift +1 -1
  49. data/fastlane/swift/MatchfileProtocol.swift +20 -4
  50. data/fastlane/swift/Precheckfile.swift +1 -1
  51. data/fastlane/swift/PrecheckfileProtocol.swift +9 -1
  52. data/fastlane/swift/Scanfile.swift +1 -1
  53. data/fastlane/swift/ScanfileProtocol.swift +1 -1
  54. data/fastlane/swift/Screengrabfile.swift +1 -1
  55. data/fastlane/swift/ScreengrabfileProtocol.swift +1 -1
  56. data/fastlane/swift/Snapshotfile.swift +1 -1
  57. data/fastlane/swift/SnapshotfileProtocol.swift +1 -1
  58. data/fastlane/swift/main.swift +1 -1
  59. data/fastlane_core/lib/fastlane_core/analytics/analytics_session.rb +6 -7
  60. data/fastlane_core/lib/fastlane_core/device_manager.rb +8 -4
  61. data/fastlane_core/lib/fastlane_core/helper.rb +1 -1
  62. data/fastlane_core/lib/fastlane_core/keychain_importer.rb +3 -3
  63. data/frameit/lib/frameit/editor.rb +1 -0
  64. data/gym/lib/gym/generators/package_command_generator_xcode7.rb +2 -2
  65. data/match/lib/match/.commands_generator.rb.swp +0 -0
  66. data/match/lib/match/.importer.rb.swp +0 -0
  67. data/{spaceship/lib/spaceship/connect_api/models/.app.rb.swp → match/lib/match/.options.rb.swp} +0 -0
  68. data/match/lib/match/generator.rb +6 -1
  69. data/match/lib/match/importer.rb +63 -18
  70. data/match/lib/match/migrate.rb +13 -2
  71. data/match/lib/match/nuke.rb +65 -22
  72. data/match/lib/match/options.rb +33 -2
  73. data/match/lib/match/runner.rb +38 -10
  74. data/match/lib/match/spaceship_ensure.rb +27 -21
  75. data/match/lib/match/storage/google_cloud_storage.rb +20 -3
  76. data/match/lib/match/storage/s3_storage.rb +19 -3
  77. data/pilot/lib/pilot/options.rb +2 -2
  78. data/precheck/lib/precheck/options.rb +16 -0
  79. data/precheck/lib/precheck/runner.rb +20 -1
  80. data/scan/lib/scan/detect_values.rb +5 -8
  81. data/scan/lib/scan/runner.rb +2 -1
  82. data/sigh/lib/assets/resign.sh +1 -1
  83. data/sigh/lib/sigh/download_all.rb +16 -4
  84. data/sigh/lib/sigh/options.rb +21 -0
  85. data/sigh/lib/sigh/runner.rb +81 -39
  86. data/snapshot/lib/assets/SnapshotHelper.swift +4 -0
  87. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +2 -1
  88. data/spaceship/README.md +1 -1
  89. data/spaceship/lib/spaceship/client.rb +9 -4
  90. data/spaceship/lib/spaceship/connect_api.rb +25 -0
  91. data/spaceship/lib/spaceship/connect_api/api_client.rb +12 -3
  92. data/spaceship/lib/spaceship/connect_api/client.rb +13 -3
  93. data/spaceship/lib/spaceship/connect_api/models/app.rb +17 -9
  94. data/spaceship/lib/spaceship/connect_api/models/app_info.rb +1 -0
  95. data/spaceship/lib/spaceship/connect_api/models/app_screenshot.rb +3 -1
  96. data/spaceship/lib/spaceship/connect_api/models/app_screenshot_set.rb +2 -2
  97. data/spaceship/lib/spaceship/connect_api/models/app_store_version.rb +3 -5
  98. data/spaceship/lib/spaceship/connect_api/models/app_store_version_localization.rb +3 -5
  99. data/spaceship/lib/spaceship/connect_api/models/beta_tester.rb +2 -1
  100. data/spaceship/lib/spaceship/connect_api/models/certificate.rb +42 -0
  101. data/spaceship/lib/spaceship/connect_api/models/device.rb +5 -0
  102. data/spaceship/lib/spaceship/connect_api/models/profile.rb +7 -1
  103. data/spaceship/lib/spaceship/connect_api/models/user_invitation.rb +59 -0
  104. data/spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb +45 -2
  105. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +13 -0
  106. data/spaceship/lib/spaceship/connect_api/token.rb +6 -1
  107. data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +15 -7
  108. data/spaceship/lib/spaceship/connect_api/users/users.rb +40 -0
  109. data/spaceship/lib/spaceship/helper/net_http_generic_request.rb +11 -5
  110. data/supply/lib/supply/uploader.rb +1 -1
  111. metadata +21 -19
  112. data/spaceship/lib/spaceship/connect_api/models/.app_store_version.rb.swp +0 -0
@@ -7,7 +7,13 @@ module Fastlane
7
7
  # Raises an exception and stop the lane execution if the repo is not in a clean state
8
8
  class EnsureGitStatusCleanAction < Action
9
9
  def self.run(params)
10
- repo_status = Actions.sh("git status --porcelain")
10
+ if params[:ignored]
11
+ ignored_file = params[:ignored]
12
+ repo_status = Actions.sh("git status --porcelain --ignored #{ignored_file}")
13
+ else
14
+ repo_status = Actions.sh("git status --porcelain")
15
+ end
16
+
11
17
  repo_clean = repo_status.empty?
12
18
 
13
19
  if repo_clean
@@ -65,7 +71,12 @@ module Fastlane
65
71
  description: "The flag whether to show the git diff if the repo is dirty",
66
72
  optional: true,
67
73
  default_value: false,
68
- is_string: false)
74
+ is_string: false),
75
+ FastlaneCore::ConfigItem.new(key: :ignored,
76
+ env_name: "FL_ENSURE_GIT_STATUS_CLEAN_IGNORED_FILE",
77
+ description: "The flag whether to ignore file the git status if the repo is dirty",
78
+ optional: true,
79
+ is_string: true)
69
80
  ]
70
81
  end
71
82
 
@@ -13,6 +13,7 @@ module Fastlane
13
13
 
14
14
  begin
15
15
  Cert.config = params # we alread have the finished config
16
+ Cert.config[:api_key] ||= Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY]
16
17
 
17
18
  Cert::Runner.new.launch
18
19
  cert_file_path = ENV["CER_FILE_PATH"]
@@ -15,6 +15,7 @@ module Fastlane
15
15
  require 'credentials_manager/appfile_config'
16
16
 
17
17
  Sigh.config = values # we already have the finished config
18
+ Sigh.config[:api_key] ||= Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY]
18
19
 
19
20
  path = Sigh::Manager.start
20
21
 
@@ -19,6 +19,9 @@ module Fastlane
19
19
 
20
20
  def self.available_options
21
21
  [
22
+ # Because the `run` method is actually implemented in `fast_file.rb`,
23
+ # and because magic, some of the parameters on `ConfigItem`s (e.g.
24
+ # `conflicting_options`, `verify_block`) are completely ignored.
22
25
  FastlaneCore::ConfigItem.new(key: :url,
23
26
  description: "The URL of the repository to import the Fastfile from",
24
27
  default_value: nil),
@@ -38,6 +41,10 @@ module Fastlane
38
41
  description: "The version to checkout on the repository. Optimistic match operator or multiple conditions can be used to select the latest version within constraints",
39
42
  default_value: nil,
40
43
  is_string: false,
44
+ optional: true),
45
+ FastlaneCore::ConfigItem.new(key: :cache_path,
46
+ description: "The path to a directory where the repository should be cloned into. This is ignored if `version` is not specified. Defaults to `nil`, which causes the repository to be cloned on every call, to a temporary directory",
47
+ default_value: nil,
41
48
  optional: true)
42
49
  ]
43
50
  end
@@ -62,7 +69,8 @@ module Fastlane
62
69
  url: "git@github.com:fastlane/fastlane.git", # The URL of the repository to import the Fastfile from.
63
70
  branch: "HEAD", # The branch to checkout on the repository
64
71
  path: "fastlane/Fastfile", # The path of the Fastfile in the repository
65
- version: [">= 1.1.0", "< 2.0.0"] # The version to checkout on the repository. Multiple conditions can be used to select the latest version within constraints.
72
+ version: [">= 1.1.0", "< 2.0.0"], # The version to checkout on the repository. Multiple conditions can be used to select the latest version within constraints.
73
+ cache_path: "~/.cache/fastlane/imported" # A directory in which the repository will be added, which means that it will not be cloned again on subsequent calls.
66
74
  )'
67
75
  ]
68
76
  end
@@ -35,7 +35,7 @@ module Fastlane
35
35
 
36
36
  def self.example_code
37
37
  [
38
- 'if is_ci?
38
+ 'if is_ci
39
39
  puts "I\'m a computer"
40
40
  else
41
41
  say "Hi Human!"
@@ -37,6 +37,21 @@ module Fastlane
37
37
  user ||= CredentialsManager::AppfileConfig.try_fetch_value(:apple_id)
38
38
 
39
39
  [
40
+ FastlaneCore::ConfigItem.new(key: :api_key_path,
41
+ env_name: "APPSTORE_BUILD_NUMBER_API_KEY_PATH",
42
+ description: "Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)",
43
+ optional: true,
44
+ conflicting_options: [:api_key],
45
+ verify_block: proc do |value|
46
+ UI.user_error!("Couldn't find API key JSON file at path '#{value}'") unless File.exist?(value)
47
+ end),
48
+ FastlaneCore::ConfigItem.new(key: :api_key,
49
+ env_name: "APPSTORE_BUILD_NUMBER_API_KEY",
50
+ description: "Your App Store Connect API Key information (https://docs.fastlane.tools/app-store-connect-api/#use-return-value-and-pass-in-as-an-option)",
51
+ type: Hash,
52
+ optional: true,
53
+ sensitive: true,
54
+ conflicting_options: [:api_key_path]),
40
55
  FastlaneCore::ConfigItem.new(key: :live,
41
56
  short_option: "-l",
42
57
  env_name: "CURRENT_BUILD_NUMBER_LIVE",
@@ -11,23 +11,39 @@ module Fastlane
11
11
  require 'spaceship'
12
12
 
13
13
  name = params[:name]
14
+ platform = params[:platform]
14
15
  udid = params[:udid]
15
16
 
16
- credentials = CredentialsManager::AccountManager.new(user: params[:username])
17
- Spaceship.login(credentials.user, credentials.password)
18
- Spaceship.select_team
17
+ platform = Spaceship::ConnectAPI::BundleIdPlatform.map(platform)
18
+
19
+ if (token = api_token(params))
20
+ UI.message("Using App Store Connect API token...")
21
+ Spaceship::ConnectAPI.token = token
22
+ else
23
+ UI.message("Login to App Store Connect (#{params[:username]})")
24
+ credentials = CredentialsManager::AccountManager.new(user: params[:username])
25
+ Spaceship::ConnectAPI.login(credentials.user, credentials.password, use_portal: true, use_tunes: false)
26
+ UI.message("Login successful")
27
+ end
19
28
 
20
29
  begin
21
- Spaceship::Device.create!(name: name, udid: udid)
30
+ Spaceship::ConnectAPI::Device.create(name: name, platform: platform, udid: udid)
22
31
  rescue => ex
23
32
  UI.error(ex.to_s)
24
- UI.crash!("Failed to register new device (name: #{name}, UDID: #{udid})")
33
+ UI.crash!("Failed to register new device (name: #{name}, platform: #{platform}, UDID: #{udid})")
25
34
  end
26
35
 
27
36
  UI.success("Successfully registered new device")
28
37
  return udid
29
38
  end
30
39
 
40
+ def self.api_token(params)
41
+ params[:api_key] ||= Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY]
42
+ api_token ||= Spaceship::ConnectAPI::Token.create(params[:api_key]) if params[:api_key]
43
+ api_token ||= Spaceship::ConnectAPI::Token.from_json_file(params[:api_key_path]) if params[:api_key_path]
44
+ return api_token
45
+ end
46
+
31
47
  def self.description
32
48
  "Registers a new device to the Apple Dev Portal"
33
49
  end
@@ -35,14 +51,38 @@ module Fastlane
35
51
  def self.available_options
36
52
  user = CredentialsManager::AppfileConfig.try_fetch_value(:apple_dev_portal_id)
37
53
  user ||= CredentialsManager::AppfileConfig.try_fetch_value(:apple_id)
54
+ platform = Actions.lane_context[Actions::SharedValues::PLATFORM_NAME].to_s
38
55
 
39
56
  [
40
57
  FastlaneCore::ConfigItem.new(key: :name,
41
58
  env_name: "FL_REGISTER_DEVICE_NAME",
42
59
  description: "Provide the name of the device to register as"),
60
+ FastlaneCore::ConfigItem.new(key: :platform,
61
+ env_name: "FL_REGISTER_DEVICE_PLATFORM",
62
+ description: "Provide the platform of the device to register as (ios, mac)",
63
+ optional: true,
64
+ default_value: platform.empty? ? "ios" : platform,
65
+ verify_block: proc do |value|
66
+ UI.user_error!("The platform can only be ios or mac") unless %('ios', 'mac').include?(value)
67
+ end),
43
68
  FastlaneCore::ConfigItem.new(key: :udid,
44
69
  env_name: "FL_REGISTER_DEVICE_UDID",
45
70
  description: "Provide the UDID of the device to register as"),
71
+ FastlaneCore::ConfigItem.new(key: :api_key_path,
72
+ env_name: "FL_REGISTER_DEVICE_API_KEY_PATH",
73
+ description: "Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)",
74
+ optional: true,
75
+ conflicting_options: [:api_key],
76
+ verify_block: proc do |value|
77
+ UI.user_error!("Couldn't find API key JSON file at path '#{value}'") unless File.exist?(value)
78
+ end),
79
+ FastlaneCore::ConfigItem.new(key: :api_key,
80
+ env_name: "FL_REGISTER_DEVICE_API_KEY",
81
+ description: "Your App Store Connect API Key information (https://docs.fastlane.tools/app-store-connect-api/#use-return-value-and-pass-in-as-an-option)",
82
+ type: Hash,
83
+ optional: true,
84
+ sensitive: true,
85
+ conflicting_options: [:api_key_path]),
46
86
  FastlaneCore::ConfigItem.new(key: :team_id,
47
87
  env_name: "REGISTER_DEVICE_TEAM_ID",
48
88
  code_gen_sensitive: true,
@@ -66,6 +106,7 @@ module Fastlane
66
106
  FastlaneCore::ConfigItem.new(key: :username,
67
107
  env_name: "DELIVER_USER",
68
108
  description: "Optional: Your Apple ID",
109
+ optional: true,
69
110
  default_value: user,
70
111
  default_value_dynamic: true)
71
112
  ]
@@ -12,6 +12,8 @@ module Fastlane
12
12
  end
13
13
 
14
14
  def self.run(params)
15
+ platform = Spaceship::ConnectAPI::BundleIdPlatform.map(params[:platform])
16
+
15
17
  if params[:devices]
16
18
  new_devices = params[:devices].map do |name, udid|
17
19
  [udid, name]
@@ -37,40 +39,57 @@ module Fastlane
37
39
  end
38
40
 
39
41
  require 'spaceship'
40
- credentials = CredentialsManager::AccountManager.new(user: params[:username])
41
- Spaceship.login(credentials.user, credentials.password)
42
- Spaceship.select_team
43
-
44
- UI.message("Fetching list of currently registered devices...")
45
- all_platforms = Set[params[:platform]]
46
- new_devices.each do |device|
47
- next if device[2].nil?
48
- all_platforms.add(device[2])
42
+ if (token = api_token(params))
43
+ UI.message("Using App Store Connect API token...")
44
+ Spaceship::ConnectAPI.token = token
45
+ else
46
+ UI.message("Login to App Store Connect (#{params[:username]})")
47
+ credentials = CredentialsManager::AccountManager.new(user: params[:username])
48
+ Spaceship::ConnectAPI.login(credentials.user, credentials.password, use_portal: true, use_tunes: false)
49
+ UI.message("Login successful")
49
50
  end
50
- supported_platforms = all_platforms.select { |platform| self.is_supported?(platform.to_sym) }
51
51
 
52
- existing_devices = supported_platforms.flat_map { |platform| Spaceship::Device.all(mac: platform == "mac") }
52
+ UI.message("Fetching list of currently registered devices...")
53
+ existing_devices = Spaceship::ConnectAPI::Device.all
53
54
 
54
55
  device_objs = new_devices.map do |device|
55
- next if existing_devices.map(&:udid).include?(device[0])
56
+ if existing_devices.map(&:udid).map(&:downcase).include?(device[0].downcase)
57
+ UI.verbose("UDID #{device[0]} already exists - Skipping...")
58
+ next
59
+ end
60
+
61
+ device_platform = platform
56
62
 
57
63
  device_platform_supported = !device[2].nil? && self.is_supported?(device[2].to_sym)
58
- mac = (device_platform_supported ? device[2] : params[:platform]) == "mac"
64
+ if device_platform_supported
65
+ if device[2] == "mac"
66
+ device_platform = Spaceship::ConnectAPI::BundleIdPlatform::MAC_OS
67
+ else
68
+ device_platform = Spaceship::ConnectAPI::BundleIdPlatform::IOS
69
+ end
70
+ end
59
71
 
60
- try_create_device(name: device[1], udid: device[0], mac: mac)
72
+ try_create_device(name: device[1], platform: device_platform, udid: device[0])
61
73
  end
62
74
 
63
75
  UI.success("Successfully registered new devices.")
64
76
  return device_objs
65
77
  end
66
78
 
67
- def self.try_create_device(name: nil, udid: nil, mac: false)
68
- Spaceship::Device.create!(name: name, udid: udid, mac: mac)
79
+ def self.try_create_device(name: nil, platform: nil, udid: nil)
80
+ Spaceship::ConnectAPI::Device.create(name: name, platform: platform, udid: udid)
69
81
  rescue => ex
70
82
  UI.error(ex.to_s)
71
83
  UI.crash!("Failed to register new device (name: #{name}, UDID: #{udid})")
72
84
  end
73
85
 
86
+ def self.api_token(params)
87
+ params[:api_key] ||= Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY]
88
+ api_token ||= Spaceship::ConnectAPI::Token.create(params[:api_key]) if params[:api_key]
89
+ api_token ||= Spaceship::ConnectAPI::Token.from_json_file(params[:api_key_path]) if params[:api_key_path]
90
+ return api_token
91
+ end
92
+
74
93
  #####################################################
75
94
  # @!group Documentation
76
95
  #####################################################
@@ -98,6 +117,21 @@ module Fastlane
98
117
  verify_block: proc do |value|
99
118
  UI.user_error!("Could not find file '#{value}'") unless File.exist?(value)
100
119
  end),
120
+ FastlaneCore::ConfigItem.new(key: :api_key_path,
121
+ env_name: "FL_REGISTER_DEVICES_API_KEY_PATH",
122
+ description: "Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)",
123
+ optional: true,
124
+ conflicting_options: [:api_key],
125
+ verify_block: proc do |value|
126
+ UI.user_error!("Couldn't find API key JSON file at path '#{value}'") unless File.exist?(value)
127
+ end),
128
+ FastlaneCore::ConfigItem.new(key: :api_key,
129
+ env_name: "FL_REGISTER_DEVICES_API_KEY",
130
+ description: "Your App Store Connect API Key information (https://docs.fastlane.tools/app-store-connect-api/#use-return-value-and-pass-in-as-an-option)",
131
+ type: Hash,
132
+ optional: true,
133
+ sensitive: true,
134
+ conflicting_options: [:api_key_path]),
101
135
  FastlaneCore::ConfigItem.new(key: :team_id,
102
136
  env_name: "REGISTER_DEVICES_TEAM_ID",
103
137
  code_gen_sensitive: true,
@@ -6,9 +6,14 @@ module Fastlane
6
6
 
7
7
  # Team selection passed though FASTLANE_ITC_TEAM_ID and FASTLANE_ITC_TEAM_NAME environment variables
8
8
  # Prompts select team if multiple teams and none specified
9
- UI.message("Login to App Store Connect (#{params[:username]})")
10
- Spaceship::ConnectAPI.login(params[:username], use_portal: false, use_tunes: true)
11
- UI.message("Login successful")
9
+ if (token = self.api_token(params))
10
+ UI.message("Using App Store Connect API token...")
11
+ Spaceship::ConnectAPI.token = token
12
+ else
13
+ UI.message("Login to App Store Connect (#{params[:username]})")
14
+ Spaceship::ConnectAPI.login(params[:username], use_portal: false, use_tunes: true, tunes_team_id: params[:team_id], team_name: params[:team_name])
15
+ UI.message("Login successful")
16
+ end
12
17
 
13
18
  app = Spaceship::ConnectAPI::App.find(params[:app_identifier])
14
19
  UI.user_error!("Couldn't find app with identifier #{params[:app_identifier]}") if app.nil?
@@ -73,6 +78,13 @@ module Fastlane
73
78
  UI.success("👼 Successfully pushed the new changelog to for #{edit_version.version_string}")
74
79
  end
75
80
 
81
+ def self.api_token(params)
82
+ params[:api_key] ||= Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY]
83
+ api_token ||= Spaceship::ConnectAPI::Token.create(params[:api_key]) if params[:api_key]
84
+ api_token ||= Spaceship::ConnectAPI::Token.from_json_file(params[:api_key_path]) if params[:api_key_path]
85
+ return api_token
86
+ end
87
+
76
88
  def self.default_changelog_path
77
89
  File.join(FastlaneCore::FastlaneFolder.path.to_s, 'changelog.txt')
78
90
  end
@@ -98,6 +110,21 @@ module Fastlane
98
110
  user ||= CredentialsManager::AppfileConfig.try_fetch_value(:apple_id)
99
111
 
100
112
  [
113
+ FastlaneCore::ConfigItem.new(key: :api_key_path,
114
+ env_name: "FL_SET_CHANGELOG_API_KEY_PATH",
115
+ description: "Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)",
116
+ optional: true,
117
+ conflicting_options: [:api_key],
118
+ verify_block: proc do |value|
119
+ UI.user_error!("Couldn't find API key JSON file at path '#{value}'") unless File.exist?(value)
120
+ end),
121
+ FastlaneCore::ConfigItem.new(key: :api_key,
122
+ env_name: "FL_SET_CHANGELOG_API_KEY",
123
+ description: "Your App Store Connect API Key information (https://docs.fastlane.tools/app-store-connect-api/#use-return-value-and-pass-in-as-an-option)",
124
+ type: Hash,
125
+ optional: true,
126
+ sensitive: true,
127
+ conflicting_options: [:api_key_path]),
101
128
  FastlaneCore::ConfigItem.new(key: :app_identifier,
102
129
  short_option: "-a",
103
130
  env_name: "FASTLANE_APP_IDENTIFIER",
@@ -109,6 +136,7 @@ module Fastlane
109
136
  short_option: "-u",
110
137
  env_name: "FASTLANE_USERNAME",
111
138
  description: "Your Apple ID Username",
139
+ optional: true,
112
140
  default_value: user,
113
141
  default_value_dynamic: true),
114
142
  FastlaneCore::ConfigItem.new(key: :version,
@@ -10,6 +10,7 @@ module Fastlane
10
10
  require 'match'
11
11
 
12
12
  params.load_configuration_file("Matchfile")
13
+ params[:api_key] ||= Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY]
13
14
  Match::Runner.new.run(params)
14
15
 
15
16
  define_profile_type(params)
@@ -12,6 +12,7 @@ module Fastlane
12
12
  config[:screenshots_path] = Actions.lane_context[SharedValues::SNAPSHOT_SCREENSHOTS_PATH] if Actions.lane_context[SharedValues::SNAPSHOT_SCREENSHOTS_PATH]
13
13
  config[:ipa] = Actions.lane_context[SharedValues::IPA_OUTPUT_PATH] if Actions.lane_context[SharedValues::IPA_OUTPUT_PATH]
14
14
  config[:pkg] = Actions.lane_context[SharedValues::PKG_OUTPUT_PATH] if Actions.lane_context[SharedValues::PKG_OUTPUT_PATH]
15
+ config[:api_key] ||= Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY]
15
16
 
16
17
  return config if Helper.test?
17
18
  Deliver::Runner.new(config).run
@@ -26,7 +27,7 @@ module Fastlane
26
27
  [
27
28
  "Using _upload_to_app_store_ after _build_app_ and _capture_screenshots_ will automatically upload the latest ipa and screenshots with no other configuration.",
28
29
  "",
29
- "If you don't want a PDF report for App Store builds, use the `:force` option.",
30
+ "If you don't want to verify an HTML preview for App Store builds, use the `:force` option.",
30
31
  "This is useful when running _fastlane_ on your Continuous Integration server:",
31
32
  "`_upload_to_app_store_(force: true)`",
32
33
  "If your account is on multiple teams and you need to tell the `iTMSTransporter` which 'provider' to use, you can set the `:itc_provider` option to pass this info."
@@ -50,7 +51,7 @@ module Fastlane
50
51
  def self.example_code
51
52
  [
52
53
  'upload_to_app_store(
53
- force: true, # Set to true to skip PDF verification
54
+ force: true, # Set to true to skip verification of HTML preview
54
55
  itc_provider: "abcde12345" # pass a specific value to the iTMSTransporter -itc_provider option
55
56
  )',
56
57
  'deliver # alias for "upload_to_app_store"',
@@ -259,11 +259,20 @@ module Fastlane
259
259
  return return_value
260
260
  end
261
261
 
262
+ def find_tag(folder: nil, version: nil, remote: false)
263
+ req = Gem::Requirement.new(version)
264
+ all_tags = get_tags(folder: folder, remote: remote)
265
+
266
+ return all_tags.select { |t| req =~ FastlaneCore::TagVersion.new(t) }.last
267
+ end
268
+
262
269
  # @param url [String] The git URL to clone the repository from
263
270
  # @param branch [String] The branch to checkout in the repository
264
271
  # @param path [String] The path to the Fastfile
265
272
  # @param version [String, Array] Version requirement for repo tags
266
- def import_from_git(url: nil, branch: 'HEAD', path: 'fastlane/Fastfile', version: nil, dependencies: [])
273
+ # @param dependencies [Array] An optional array of additional Fastfiles in the repository
274
+ # @param cache_path [String] An optional path to a directory where the repository should be cloned into
275
+ def import_from_git(url: nil, branch: 'HEAD', path: 'fastlane/Fastfile', version: nil, dependencies: [], cache_path: nil) # rubocop:disable Metrics/PerceivedComplexity
267
276
  UI.user_error!("Please pass a path to the `import_from_git` action") if url.to_s.length == 0
268
277
 
269
278
  Actions.execute_action('import_from_git') do
@@ -271,41 +280,75 @@ module Fastlane
271
280
 
272
281
  action_launched('import_from_git')
273
282
 
283
+ is_eligible_for_caching = !version.nil? && !cache_path.nil?
284
+
285
+ UI.message("Eligible for caching") if is_eligible_for_caching
286
+
274
287
  # Checkout the repo
275
288
  repo_name = url.split("/").last
276
289
  checkout_param = branch
277
290
 
278
- Dir.mktmpdir("fl_clone") do |tmp_path|
279
- clone_folder = File.join(tmp_path, repo_name)
291
+ import_block = proc do |target_path|
292
+ clone_folder = File.join(target_path, repo_name)
280
293
 
281
294
  branch_option = "--branch #{branch}" if branch != 'HEAD'
282
295
 
283
296
  checkout_dependencies = dependencies.map(&:shellescape).join(" ")
284
297
 
285
- checkout_path = "#{path.shellescape} #{checkout_dependencies}"
286
-
287
- UI.message("Cloning remote git repo...")
288
- Helper.with_env_values('GIT_TERMINAL_PROMPT' => '0') do
289
- Actions.sh("git clone #{url.shellescape} #{clone_folder.shellescape} --depth 1 -n #{branch_option}")
298
+ # If the current call is eligible for caching, we check out all the
299
+ # files and directories. If not, we only check out the specified
300
+ # `path` and `dependencies`.
301
+ checkout_path = is_eligible_for_caching ? "" : "#{path.shellescape} #{checkout_dependencies}"
302
+
303
+ if Dir[clone_folder].empty?
304
+ UI.message("Cloning remote git repo...")
305
+ Helper.with_env_values('GIT_TERMINAL_PROMPT' => '0') do
306
+ # When using cached clones, we need the entire repository history
307
+ # so we can switch between tags or branches instantly, or else,
308
+ # it would defeat the caching's purpose.
309
+ depth = is_eligible_for_caching ? "" : "--depth 1"
310
+
311
+ Actions.sh("git clone #{url.shellescape} #{clone_folder.shellescape} #{depth} --no-checkout #{branch_option}")
312
+ end
290
313
  end
291
314
 
292
315
  unless version.nil?
293
- req = Gem::Requirement.new(version)
294
- all_tags = fetch_remote_tags(folder: clone_folder)
295
- checkout_param = all_tags.select { |t| req =~ FastlaneCore::TagVersion.new(t) }.last
316
+ if is_eligible_for_caching
317
+ checkout_param = find_tag(folder: clone_folder, version: version, remote: false)
318
+
319
+ if checkout_param.nil?
320
+ # Update the repo and try again before failing
321
+ UI.message("Updating git repo...")
322
+ Helper.with_env_values('GIT_TERMINAL_PROMPT' => '0') do
323
+ Actions.sh("cd #{clone_folder.shellescape} && git checkout #{branch} && git reset --hard && git pull --all")
324
+ end
325
+
326
+ checkout_param = find_tag(folder: clone_folder, version: version, remote: false)
327
+ else
328
+ UI.message("Found tag #{checkout_param}. No git repo update needed.")
329
+ end
330
+ else
331
+ checkout_param = find_tag(folder: clone_folder, version: version, remote: true)
332
+ end
333
+
296
334
  UI.user_error!("No tag found matching #{version.inspect}") if checkout_param.nil?
297
335
  end
298
336
 
299
337
  Actions.sh("cd #{clone_folder.shellescape} && git checkout #{checkout_param.shellescape} #{checkout_path}")
300
338
 
301
- # We also want to check out all the local actions of this fastlane setup
302
- containing = path.split(File::SEPARATOR)[0..-2]
303
- containing = "." if containing.count == 0
304
- actions_folder = File.join(containing, "actions")
305
- begin
306
- Actions.sh("cd #{clone_folder.shellescape} && git checkout #{checkout_param.shellescape} #{actions_folder.shellescape}")
307
- rescue
308
- # We don't care about a failure here, as local actions are optional
339
+ # Knowing that we check out all the files and directories when the
340
+ # current call is eligible for caching, we don't need to also
341
+ # explicitly check out the "actions" directory.
342
+ unless is_eligible_for_caching
343
+ # We also want to check out all the local actions of this fastlane setup
344
+ containing = path.split(File::SEPARATOR)[0..-2]
345
+ containing = "." if containing.count == 0
346
+ actions_folder = File.join(containing, "actions")
347
+ begin
348
+ Actions.sh("cd #{clone_folder.shellescape} && git checkout #{checkout_param.shellescape} #{actions_folder.shellescape}")
349
+ rescue
350
+ # We don't care about a failure here, as local actions are optional
351
+ end
309
352
  end
310
353
 
311
354
  return_value = nil
@@ -320,6 +363,12 @@ module Fastlane
320
363
 
321
364
  return return_value
322
365
  end
366
+
367
+ if is_eligible_for_caching
368
+ import_block.call(File.expand_path(cache_path))
369
+ else
370
+ Dir.mktmpdir("fl_clone", &import_block)
371
+ end
323
372
  end
324
373
  end
325
374
 
@@ -327,10 +376,12 @@ module Fastlane
327
376
  # @!group Versioning helpers
328
377
  #####################################################
329
378
 
330
- def fetch_remote_tags(folder: nil)
331
- UI.message("Fetching remote git tags...")
332
- Helper.with_env_values('GIT_TERMINAL_PROMPT' => '0') do
333
- Actions.sh("cd #{folder.shellescape} && git fetch --all --tags -q")
379
+ def get_tags(folder: nil, remote: false)
380
+ if remote
381
+ UI.message("Fetching remote git tags...")
382
+ Helper.with_env_values('GIT_TERMINAL_PROMPT' => '0') do
383
+ Actions.sh("cd #{folder.shellescape} && git fetch --all --tags -q")
384
+ end
334
385
  end
335
386
 
336
387
  # Fetch all possible tags