fastlane 2.139.0 → 2.144.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +85 -72
  4. data/cert/lib/cert/options.rb +12 -5
  5. data/cert/lib/cert/runner.rb +13 -0
  6. data/deliver/lib/deliver/options.rb +28 -2
  7. data/deliver/lib/deliver/runner.rb +13 -2
  8. data/fastlane/lib/fastlane/action.rb +1 -1
  9. data/fastlane/lib/fastlane/actions/.hockey.rb.swp +0 -0
  10. data/fastlane/lib/fastlane/actions/.slack.rb.swp +0 -0
  11. data/fastlane/lib/fastlane/actions/.update_project_provisioning.rb.swp +0 -0
  12. data/fastlane/lib/fastlane/actions/README.md +2 -0
  13. data/fastlane/lib/fastlane/actions/app_store_build_number.rb +13 -5
  14. data/fastlane/lib/fastlane/actions/automatic_code_signing.rb +7 -1
  15. data/fastlane/lib/fastlane/actions/build_app.rb +157 -6
  16. data/fastlane/lib/fastlane/actions/build_ios_app.rb +28 -132
  17. data/fastlane/lib/fastlane/actions/build_mac_app.rb +46 -0
  18. data/fastlane/lib/fastlane/actions/clean_build_artifacts.rb +3 -0
  19. data/fastlane/lib/fastlane/actions/cocoapods.rb +2 -2
  20. data/fastlane/lib/fastlane/actions/crashlytics.rb +14 -2
  21. data/fastlane/lib/fastlane/actions/create_pull_request.rb +29 -0
  22. data/fastlane/lib/fastlane/actions/docs/{build_ios_app.md → build_app.md} +1 -1
  23. data/fastlane/lib/fastlane/actions/docs/frame_screenshots.md +22 -6
  24. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +22 -6
  25. data/fastlane/lib/fastlane/actions/ensure_git_branch.rb +1 -1
  26. data/fastlane/lib/fastlane/actions/ensure_xcode_version.rb +35 -7
  27. data/fastlane/lib/fastlane/actions/frame_screenshots.rb +2 -1
  28. data/fastlane/lib/fastlane/actions/get_github_release.rb +3 -0
  29. data/fastlane/lib/fastlane/actions/gradle.rb +43 -2
  30. data/fastlane/lib/fastlane/actions/gym.rb +3 -7
  31. data/fastlane/lib/fastlane/actions/import_from_git.rb +4 -0
  32. data/fastlane/lib/fastlane/actions/latest_testflight_build_number.rb +9 -3
  33. data/fastlane/lib/fastlane/actions/notarize.rb +183 -0
  34. data/fastlane/lib/fastlane/actions/pod_lib_lint.rb +7 -1
  35. data/fastlane/lib/fastlane/actions/run_tests.rb +5 -22
  36. data/fastlane/lib/fastlane/actions/s3.rb +5 -291
  37. data/fastlane/lib/fastlane/actions/set_github_release.rb +1 -1
  38. data/fastlane/lib/fastlane/actions/spm.rb +8 -0
  39. data/fastlane/lib/fastlane/actions/swiftlint.rb +45 -9
  40. data/fastlane/lib/fastlane/actions/update_code_signing_settings.rb +190 -0
  41. data/fastlane/lib/fastlane/actions/update_plist.rb +37 -2
  42. data/fastlane/lib/fastlane/actions/upload_symbols_to_crashlytics.rb +13 -3
  43. data/fastlane/lib/fastlane/actions/upload_to_app_store.rb +1 -0
  44. data/fastlane/lib/fastlane/fast_file.rb +13 -3
  45. data/fastlane/lib/fastlane/helper/adb_helper.rb +1 -1
  46. data/fastlane/lib/fastlane/helper/s3_client_helper.rb +56 -0
  47. data/fastlane/lib/fastlane/plugins/plugin_manager.rb +1 -1
  48. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +2 -0
  49. data/fastlane/lib/fastlane/runner.rb +23 -18
  50. data/fastlane/lib/fastlane/server/socket_server_action_command_executor.rb +1 -1
  51. data/fastlane/lib/fastlane/version.rb +1 -1
  52. data/fastlane/swift/Deliverfile.swift +1 -1
  53. data/fastlane/swift/DeliverfileProtocol.swift +3 -3
  54. data/fastlane/swift/Fastlane.swift +422 -45
  55. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.xcworkspace/xcuserdata/josh.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  56. data/fastlane/swift/Gymfile.swift +1 -1
  57. data/fastlane/swift/GymfileProtocol.swift +17 -1
  58. data/fastlane/swift/Matchfile.swift +1 -1
  59. data/fastlane/swift/MatchfileProtocol.swift +23 -3
  60. data/fastlane/swift/Precheckfile.swift +1 -1
  61. data/fastlane/swift/RubyCommand.swift +1 -1
  62. data/fastlane/swift/Scanfile.swift +1 -1
  63. data/fastlane/swift/ScanfileProtocol.swift +21 -1
  64. data/fastlane/swift/Screengrabfile.swift +1 -1
  65. data/fastlane/swift/Snapshotfile.swift +1 -1
  66. data/fastlane/swift/SnapshotfileProtocol.swift +9 -1
  67. data/fastlane_core/lib/fastlane_core/cert_checker.rb +28 -0
  68. data/fastlane_core/lib/fastlane_core/device_manager.rb +1 -1
  69. data/fastlane_core/lib/fastlane_core/ipa_file_analyser.rb +1 -0
  70. data/fastlane_core/lib/fastlane_core/keychain_importer.rb +2 -0
  71. data/fastlane_core/lib/fastlane_core/project.rb +27 -0
  72. data/fastlane_core/lib/fastlane_core/provisioning_profile.rb +15 -2
  73. data/frameit/lib/frameit/commands_generator.rb +25 -0
  74. data/frameit/lib/frameit/config_parser.rb +31 -9
  75. data/frameit/lib/frameit/device.rb +90 -0
  76. data/frameit/lib/frameit/device_types.rb +121 -5
  77. data/frameit/lib/frameit/editor.rb +28 -40
  78. data/frameit/lib/frameit/offsets.rb +8 -1
  79. data/frameit/lib/frameit/options.rb +81 -54
  80. data/frameit/lib/frameit/runner.rb +17 -7
  81. data/frameit/lib/frameit/screenshot.rb +35 -47
  82. data/frameit/lib/frameit/template_finder.rb +15 -12
  83. data/gym/lib/gym/code_signing_mapping.rb +32 -3
  84. data/gym/lib/gym/detect_values.rb +34 -2
  85. data/gym/lib/gym/generators/package_command_generator.rb +8 -0
  86. data/gym/lib/gym/generators/package_command_generator_xcode7.rb +52 -17
  87. data/gym/lib/gym/module.rb +8 -0
  88. data/gym/lib/gym/options.rb +25 -1
  89. data/gym/lib/gym/runner.rb +70 -21
  90. data/match/lib/match/change_password.rb +1 -1
  91. data/match/lib/match/encryption.rb +4 -0
  92. data/match/lib/match/encryption/openssl.rb +1 -1
  93. data/match/lib/match/generator.rb +17 -3
  94. data/match/lib/match/importer.rb +35 -20
  95. data/match/lib/match/module.rb +5 -2
  96. data/match/lib/match/nuke.rb +59 -17
  97. data/match/lib/match/options.rb +38 -15
  98. data/match/lib/match/runner.rb +24 -8
  99. data/match/lib/match/setup.rb +1 -1
  100. data/match/lib/match/spaceship_ensure.rb +19 -9
  101. data/match/lib/match/storage.rb +4 -0
  102. data/match/lib/match/storage/git_storage.rb +5 -2
  103. data/match/lib/match/storage/google_cloud_storage.rb +2 -2
  104. data/match/lib/match/storage/s3_storage.rb +162 -0
  105. data/pilot/lib/pilot/.manager.rb.swp +0 -0
  106. data/pilot/lib/pilot/build_manager.rb +24 -9
  107. data/scan/lib/scan/detect_values.rb +6 -1
  108. data/scan/lib/scan/manager.rb +18 -1
  109. data/scan/lib/scan/options.rb +28 -1
  110. data/scan/lib/scan/runner.rb +9 -7
  111. data/scan/lib/scan/slack_poster.rb +1 -1
  112. data/scan/lib/scan/test_command_generator.rb +12 -5
  113. data/screengrab/lib/screengrab/runner.rb +31 -18
  114. data/sigh/lib/sigh/.runner.rb.swp +0 -0
  115. data/snapshot/lib/snapshot/fixes/simulator_shared_pasteboard.rb +16 -0
  116. data/snapshot/lib/snapshot/options.rb +12 -1
  117. data/snapshot/lib/snapshot/simulator_launchers/launcher_configuration.rb +2 -0
  118. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +13 -0
  119. data/spaceship/lib/spaceship/connect_api/.DS_Store +0 -0
  120. data/spaceship/lib/spaceship/connect_api/models/.bundle_id.rb.swp +0 -0
  121. data/{gym/lib/gym/.runner.rb.swp → spaceship/lib/spaceship/connect_api/models/.bundle_id_capability.rb.swp} +0 -0
  122. data/spaceship/lib/spaceship/connect_api/models/app.rb +11 -0
  123. data/spaceship/lib/spaceship/connect_api/models/beta_feedback.rb +4 -0
  124. data/spaceship/lib/spaceship/connect_api/models/build.rb +1 -2
  125. data/spaceship/lib/spaceship/connect_api/models/certificate.rb +2 -0
  126. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +29 -0
  127. data/spaceship/lib/spaceship/portal/app.rb +11 -2
  128. data/spaceship/lib/spaceship/tunes/app_version.rb +6 -1
  129. data/spaceship/lib/spaceship/tunes/iap.rb +11 -11
  130. data/spaceship/lib/spaceship/tunes/iap_detail.rb +7 -3
  131. data/spaceship/lib/spaceship/tunes/iap_families.rb +12 -1
  132. data/spaceship/lib/spaceship/tunes/iap_family_details.rb +26 -17
  133. data/spaceship/lib/spaceship/tunes/iap_status.rb +5 -1
  134. data/spaceship/lib/spaceship/tunes/tunes_client.rb +2 -2
  135. data/supply/lib/supply/client.rb +1 -1
  136. metadata +63 -18
@@ -1,13 +1,9 @@
1
1
  module Fastlane
2
2
  module Actions
3
- require 'fastlane/actions/build_ios_app'
4
- class GymAction < BuildIosAppAction
5
- #####################################################
6
- # @!group Documentation
7
- #####################################################
8
-
3
+ require 'fastlane/actions/build_app'
4
+ class GymAction < BuildAppAction
9
5
  def self.description
10
- "Alias for the `build_ios_app` action"
6
+ "Alias for the `build_app` action"
11
7
  end
12
8
  end
13
9
  end
@@ -26,6 +26,10 @@ module Fastlane
26
26
  description: "The branch or tag to check-out on the repository",
27
27
  default_value: 'HEAD',
28
28
  optional: true),
29
+ FastlaneCore::ConfigItem.new(key: :dependencies,
30
+ description: "The array of additional Fastfiles in the repository",
31
+ default_value: [],
32
+ optional: true),
29
33
  FastlaneCore::ConfigItem.new(key: :path,
30
34
  description: "The path of the Fastfile in the repository",
31
35
  default_value: 'fastlane/Fastfile',
@@ -4,12 +4,17 @@ module Fastlane
4
4
  module Actions
5
5
  module SharedValues
6
6
  LATEST_TESTFLIGHT_BUILD_NUMBER = :LATEST_TESTFLIGHT_BUILD_NUMBER
7
+ LATEST_TESTFLIGHT_VERSION = :LATEST_TESTFLIGHT_VERSION
7
8
  end
8
9
 
9
10
  class LatestTestflightBuildNumberAction < Action
10
11
  def self.run(params)
11
- build_number = AppStoreBuildNumberAction.run(params)
12
- Actions.lane_context[SharedValues::LATEST_TESTFLIGHT_BUILD_NUMBER] = build_number
12
+ AppStoreBuildNumberAction.run(params)
13
+ build_nr = Actions.lane_context[SharedValues::LATEST_BUILD_NUMBER]
14
+ build_v = Actions.lane_context[SharedValues::LATEST_VERSION]
15
+ Actions.lane_context[SharedValues::LATEST_TESTFLIGHT_BUILD_NUMBER] = build_nr
16
+ Actions.lane_context[SharedValues::LATEST_TESTFLIGHT_VERSION] = build_v
17
+ return build_nr
13
18
  end
14
19
 
15
20
  #####################################################
@@ -93,7 +98,8 @@ module Fastlane
93
98
 
94
99
  def self.output
95
100
  [
96
- ['LATEST_TESTFLIGHT_BUILD_NUMBER', 'The latest build number of the latest version of the app uploaded to TestFlight']
101
+ ['LATEST_TESTFLIGHT_BUILD_NUMBER', 'The latest build number of the latest version of the app uploaded to TestFlight'],
102
+ ['LATEST_TESTFLIGHT_VERSION', 'The version of the latest build number']
97
103
  ]
98
104
  end
99
105
 
@@ -0,0 +1,183 @@
1
+ module Fastlane
2
+ module Actions
3
+ class NotarizeAction < Action
4
+ def self.run(params)
5
+ package_path = params[:package]
6
+ bundle_id = params[:bundle_id]
7
+ try_early_stapling = params[:try_early_stapling]
8
+ print_log = params[:print_log]
9
+ verbose = params[:verbose]
10
+
11
+ # Compress and read bundle identifier only for .app bundle.
12
+ compressed_package_path = nil
13
+ if File.extname(package_path) == '.app'
14
+ compressed_package_path = "#{package_path}.zip"
15
+ Actions.sh(
16
+ "ditto -c -k --rsrc --keepParent \"#{package_path}\" \"#{compressed_package_path}\"",
17
+ log: verbose
18
+ )
19
+
20
+ unless bundle_id
21
+ info_plist_path = File.join(package_path, 'Contents', 'Info.plist')
22
+ bundle_id = Actions.sh(
23
+ "/usr/libexec/PlistBuddy -c \"Print :CFBundleIdentifier\" \"#{info_plist_path}\"",
24
+ log: verbose
25
+ ).strip
26
+ end
27
+ end
28
+
29
+ UI.user_error!('Could not read bundle identifier, provide as a parameter') unless bundle_id
30
+
31
+ apple_id_account = CredentialsManager::AccountManager.new(user: params[:username])
32
+
33
+ # Add password as a temporary environment variable for altool.
34
+ # Use app specific password if specified.
35
+ ENV['FL_NOTARIZE_PASSWORD'] = ENV['FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD'] || apple_id_account.password
36
+
37
+ UI.message('Uploading package to notarization service, might take a while')
38
+
39
+ notarization_upload_command = "xcrun altool --notarize-app -t osx -f \"#{compressed_package_path || package_path}\" --primary-bundle-id #{bundle_id} -u #{apple_id_account.user} -p @env:FL_NOTARIZE_PASSWORD --output-format xml"
40
+ notarization_upload_command << " --asc-provider \"#{params[:asc_provider]}\"" if params[:asc_provider]
41
+
42
+ notarization_upload_response = Actions.sh(
43
+ notarization_upload_command,
44
+ log: verbose
45
+ )
46
+
47
+ FileUtils.rm_rf(compressed_package_path) if compressed_package_path
48
+
49
+ notarization_upload_plist = Plist.parse_xml(notarization_upload_response)
50
+ notarization_request_id = notarization_upload_plist['notarization-upload']['RequestUUID']
51
+
52
+ UI.success("Successfully uploaded package to notarization service with request identifier #{notarization_request_id}")
53
+
54
+ notarization_info = {}
55
+ while notarization_info.empty? || (notarization_info['Status'] == 'in progress')
56
+ if notarization_info.empty?
57
+ UI.message('Waiting to query request status')
58
+ elsif try_early_stapling
59
+ UI.message('Request in progress, trying early staple')
60
+
61
+ begin
62
+ self.staple(package_path, verbose)
63
+ UI.message('Successfully notarized and early stapled package.')
64
+
65
+ return
66
+ rescue
67
+ UI.message('Early staple failed, waiting to query again')
68
+ end
69
+ end
70
+
71
+ sleep(30)
72
+
73
+ UI.message('Querying request status')
74
+
75
+ notarization_info_response = Actions.sh(
76
+ "xcrun altool --notarization-info #{notarization_request_id} -u #{apple_id_account.user} -p @env:FL_NOTARIZE_PASSWORD --output-format xml",
77
+ log: verbose
78
+ )
79
+
80
+ notarization_info_plist = Plist.parse_xml(notarization_info_response)
81
+ notarization_info = notarization_info_plist['notarization-info']
82
+ end
83
+
84
+ log_url = notarization_info['LogFileURL']
85
+ ENV['FL_NOTARIZE_LOG_FILE_URL'] = log_url
86
+ log_suffix = ''
87
+ if log_url && print_log
88
+ log_response = Net::HTTP.get(URI(log_url))
89
+ log_json_object = JSON.parse(log_response)
90
+ log_suffix = ", with log:\n#{JSON.pretty_generate(log_json_object)}"
91
+ end
92
+
93
+ case notarization_info['Status']
94
+ when 'success'
95
+ UI.message('Stapling package')
96
+
97
+ self.staple(package_path, verbose)
98
+
99
+ UI.success("Successfully notarized and stapled package#{log_suffix}")
100
+ when 'invalid'
101
+ UI.user_error!("Could not notarize package with message '#{notarization_info['Status Message']}'#{log_suffix}")
102
+ else
103
+ UI.crash!("Could not notarize package with status '#{notarization_info['Status']}'#{log_suffix}")
104
+ end
105
+ ensure
106
+ ENV.delete('FL_NOTARIZE_PASSWORD')
107
+ end
108
+
109
+ def self.staple(package_path, verbose)
110
+ Actions.sh(
111
+ "xcrun stapler staple \"#{package_path}\"",
112
+ log: verbose
113
+ )
114
+ end
115
+
116
+ def self.description
117
+ 'Notarizes a macOS app'
118
+ end
119
+
120
+ def self.authors
121
+ ['zeplin']
122
+ end
123
+
124
+ def self.available_options
125
+ username = CredentialsManager::AppfileConfig.try_fetch_value(:apple_dev_portal_id)
126
+ username ||= CredentialsManager::AppfileConfig.try_fetch_value(:apple_id)
127
+
128
+ asc_provider = CredentialsManager::AppfileConfig.try_fetch_value(:itc_team_id)
129
+
130
+ [
131
+ FastlaneCore::ConfigItem.new(key: :package,
132
+ env_name: 'FL_NOTARIZE_PACKAGE',
133
+ description: 'Path to package to notarize, e.g. .app bundle or disk image',
134
+ is_string: true,
135
+ verify_block: proc do |value|
136
+ UI.user_error!("Could not find package at '#{value}'") unless File.exist?(value)
137
+ end),
138
+ FastlaneCore::ConfigItem.new(key: :try_early_stapling,
139
+ env_name: 'FL_NOTARIZE_TRY_EARLY_STAPLING',
140
+ description: 'Whether to try early stapling while the notarization request is in progress',
141
+ optional: true,
142
+ default_value: false,
143
+ type: Boolean),
144
+ FastlaneCore::ConfigItem.new(key: :bundle_id,
145
+ env_name: 'FL_NOTARIZE_BUNDLE_ID',
146
+ description: 'Bundle identifier to uniquely identify the package',
147
+ optional: true,
148
+ is_string: true),
149
+ FastlaneCore::ConfigItem.new(key: :username,
150
+ env_name: 'FL_NOTARIZE_USERNAME',
151
+ description: 'Apple ID username',
152
+ default_value: username,
153
+ default_value_dynamic: true),
154
+ FastlaneCore::ConfigItem.new(key: :asc_provider,
155
+ env_name: 'FL_NOTARIZE_ASC_PROVIDER',
156
+ description: 'Provider short name for accounts associated with multiple providers',
157
+ optional: true,
158
+ default_value: asc_provider),
159
+ FastlaneCore::ConfigItem.new(key: :print_log,
160
+ env_name: 'FL_NOTARIZE_PRINT_LOG',
161
+ description: 'Whether to print notarization log file, listing issues on failure and warnings on success',
162
+ optional: true,
163
+ default_value: false,
164
+ type: Boolean),
165
+ FastlaneCore::ConfigItem.new(key: :verbose,
166
+ env_name: 'FL_NOTARIZE_VERBOSE',
167
+ description: 'Whether to log requests',
168
+ optional: true,
169
+ default_value: false,
170
+ type: Boolean)
171
+ ]
172
+ end
173
+
174
+ def self.is_supported?(platform)
175
+ platform == :mac
176
+ end
177
+
178
+ def self.category
179
+ :code_signing
180
+ end
181
+ end
182
+ end
183
+ end
@@ -26,6 +26,7 @@ module Fastlane
26
26
  command << "--platforms=#{params[:platforms]}" if params[:platforms]
27
27
  command << "--skip-import-validation" if params[:skip_import_validation]
28
28
  command << "--skip-tests" if params[:skip_tests]
29
+ command << "--analyze" if params[:analyze]
29
30
 
30
31
  result = Actions.sh(command.join(' '))
31
32
  UI.success("Pod lib lint Successfully ⬆️ ")
@@ -144,7 +145,12 @@ module Fastlane
144
145
  description: "Lint skips building and running tests during validation (available since cocoapods >= 1.3)",
145
146
  type: Boolean,
146
147
  default_value: false,
147
- env_name: "FL_POD_LIB_LINT_SKIP_TESTS")
148
+ env_name: "FL_POD_LIB_LINT_SKIP_TESTS"),
149
+ FastlaneCore::ConfigItem.new(key: :analyze,
150
+ description: "Validate with the Xcode Static Analysis tool (available since cocoapods >= 1.6.1)",
151
+ type: Boolean,
152
+ default_value: false,
153
+ env_name: "FL_POD_LIB_LINT_ANALYZE")
148
154
  ]
149
155
  end
150
156
 
@@ -10,17 +10,10 @@ module Fastlane
10
10
  class RunTestsAction < Action
11
11
  def self.run(values)
12
12
  require 'scan'
13
- plist_files_before = []
13
+ manager = Scan::Manager.new
14
14
 
15
15
  begin
16
- destination = values[:destination] # save destination value which can be later overridden
17
- Scan.config = values # we set this here to auto-detect missing values, which we need later on
18
- unless values[:derived_data_path].to_s.empty?
19
- plist_files_before = test_summary_filenames(values[:derived_data_path])
20
- end
21
-
22
- values[:destination] = destination # restore destination value
23
- Scan::Manager.new.work(values)
16
+ manager.work(values)
24
17
 
25
18
  zip_build_products_path = Scan.cache[:zip_build_products_path]
26
19
  Actions.lane_context[SharedValues::SCAN_ZIP_BUILD_PRODUCTS_PATH] = zip_build_products_path if zip_build_products_path
@@ -37,8 +30,10 @@ module Fastlane
37
30
  end
38
31
  ensure
39
32
  unless values[:derived_data_path].to_s.empty?
33
+ plist_files_before = manager.plist_files_before || []
34
+
40
35
  Actions.lane_context[SharedValues::SCAN_DERIVED_DATA_PATH] = values[:derived_data_path]
41
- plist_files_after = test_summary_filenames(values[:derived_data_path])
36
+ plist_files_after = manager.test_summary_filenames(values[:derived_data_path])
42
37
  all_test_summaries = (plist_files_after - plist_files_before)
43
38
  Actions.lane_context[SharedValues::SCAN_GENERATED_PLIST_FILES] = all_test_summaries
44
39
  Actions.lane_context[SharedValues::SCAN_GENERATED_PLIST_FILE] = all_test_summaries.last
@@ -85,18 +80,6 @@ module Fastlane
85
80
 
86
81
  private_class_method
87
82
 
88
- def self.test_summary_filenames(derived_data_path)
89
- files = []
90
-
91
- # Xcode < 10
92
- files += Dir["#{derived_data_path}/**/Logs/Test/*TestSummaries.plist"]
93
-
94
- # Xcode 10
95
- files += Dir["#{derived_data_path}/**/Logs/Test/*.xcresult/TestSummaries.plist"]
96
-
97
- return files
98
- end
99
-
100
83
  def self.example_code
101
84
  [
102
85
  'run_tests',
@@ -1,4 +1,5 @@
1
1
  require 'fastlane/erb_template_helper'
2
+ require 'fastlane/helper/s3_client_helper'
2
3
  require 'ostruct'
3
4
  require 'uri'
4
5
  require 'cgi'
@@ -15,296 +16,9 @@ module Fastlane
15
16
  S3_VERSION_OUTPUT_PATH ||= :S3_VERSION_OUTPUT_PATH
16
17
  end
17
18
 
18
- S3_ARGS_MAP = {
19
- ipa: '-f',
20
- dsym: '-d',
21
- access_key: '-a',
22
- secret_access_key: '-s',
23
- bucket: '-b',
24
- region: '-r',
25
- acl: '--acl',
26
- source: '--source-dir',
27
- path: '-P'
28
- }
29
-
30
- # rubocop:disable Metrics/ClassLength
31
19
  class S3Action < Action
32
20
  def self.run(config)
33
- # Calling fetch on config so that default values will be used
34
- params = {}
35
- params[:ipa] = config[:ipa]
36
- params[:dsym] = config[:dsym]
37
- params[:access_key] = config[:access_key]
38
- params[:secret_access_key] = config[:secret_access_key]
39
- params[:bucket] = config[:bucket]
40
- params[:region] = config[:region]
41
- params[:acl] = config[:acl]
42
- params[:source] = config[:source]
43
- params[:path] = config[:path]
44
- params[:upload_metadata] = config[:upload_metadata]
45
- params[:plist_template_path] = config[:plist_template_path]
46
- params[:plist_file_name] = config[:plist_file_name]
47
- params[:html_template_path] = config[:html_template_path]
48
- params[:html_file_name] = config[:html_file_name]
49
- params[:version_template_path] = config[:version_template_path]
50
- params[:version_file_name] = config[:version_file_name]
51
-
52
- # Pulling parameters for other uses
53
- s3_region = params[:region]
54
- s3_access_key = params[:access_key]
55
- s3_secret_access_key = params[:secret_access_key]
56
- s3_bucket = params[:bucket]
57
- ipa_file = params[:ipa]
58
- dsym_file = params[:dsym]
59
- s3_path = params[:path]
60
- acl = params[:acl].to_sym
61
-
62
- UI.user_error!("No S3 access key given, pass using `access_key: 'key'`") unless s3_access_key.to_s.length > 0
63
- UI.user_error!("No S3 secret access key given, pass using `secret_access_key: 'secret key'`") unless s3_secret_access_key.to_s.length > 0
64
- UI.user_error!("No S3 bucket given, pass using `bucket: 'bucket'`") unless s3_bucket.to_s.length > 0
65
- UI.user_error!("No IPA file path given, pass using `ipa: 'ipa path'`") unless ipa_file.to_s.length > 0
66
-
67
- plist_template_path = params[:plist_template_path]
68
- plist_file_name = params[:plist_file_name]
69
- html_template_path = params[:html_template_path]
70
- html_file_name = params[:html_file_name]
71
- version_template_path = params[:version_template_path]
72
- version_file_name = params[:version_file_name]
73
-
74
- s3_client = self.s3_client(s3_access_key, s3_secret_access_key, s3_region)
75
- bucket = s3_client.buckets[s3_bucket]
76
-
77
- url_part = self.expand_path_with_substitutions_from_ipa_plist(ipa_file, s3_path)
78
-
79
- ipa_file_basename = File.basename(ipa_file)
80
- ipa_file_name = "#{url_part}#{ipa_file_basename}"
81
- ipa_file_data = File.open(ipa_file, 'rb')
82
-
83
- ipa_url = self.upload_file(bucket, ipa_file_name, ipa_file_data, acl)
84
-
85
- # Setting action and environment variables
86
- Actions.lane_context[SharedValues::S3_IPA_OUTPUT_PATH] = ipa_url
87
- ENV[SharedValues::S3_IPA_OUTPUT_PATH.to_s] = ipa_url
88
-
89
- if dsym_file
90
- dsym_file_basename = File.basename(dsym_file)
91
- dsym_file_name = "#{url_part}#{dsym_file_basename}"
92
- dsym_file_data = File.open(dsym_file, 'rb')
93
-
94
- dsym_url = self.upload_file(bucket, dsym_file_name, dsym_file_data, acl)
95
-
96
- # Setting action and environment variables
97
- Actions.lane_context[SharedValues::S3_DSYM_OUTPUT_PATH] = dsym_url
98
- ENV[SharedValues::S3_DSYM_OUTPUT_PATH.to_s] = dsym_url
99
-
100
- end
101
-
102
- if params[:upload_metadata] == false
103
- return true
104
- end
105
-
106
- #####################################
107
- #
108
- # html and plist building
109
- #
110
- #####################################
111
-
112
- # Gets info used for the plist
113
- info = FastlaneCore::IpaFileAnalyser.fetch_info_plist_file(ipa_file)
114
-
115
- build_num = info['CFBundleVersion']
116
- bundle_id = info['CFBundleIdentifier']
117
- bundle_version = info['CFBundleShortVersionString']
118
- title = CGI.escapeHTML(info['CFBundleName'])
119
- device_family = info['UIDeviceFamily']
120
- full_version = "#{bundle_version}.#{build_num}"
121
-
122
- # Creating plist and html names
123
- s3_domain = AWS::Core::Endpoints.hostname(s3_region, 's3') || 's3.amazonaws.com'
124
- plist_file_name ||= "#{url_part}#{URI.escape(title)}.plist"
125
- plist_url = URI::HTTPS.build(host: s3_domain, path: "/#{s3_bucket}/#{plist_file_name}").to_s
126
-
127
- html_file_name ||= "index.html"
128
-
129
- version_file_name ||= "version.json"
130
-
131
- # grabs module
132
- eth = Fastlane::ErbTemplateHelper
133
-
134
- # Creates plist from template
135
- if plist_template_path && File.exist?(plist_template_path)
136
- plist_template = eth.load_from_path(plist_template_path)
137
- else
138
- plist_template = eth.load("s3_plist_template")
139
- end
140
- plist_render = eth.render(plist_template, {
141
- url: ipa_url,
142
- ipa_url: ipa_url,
143
- build_num: build_num,
144
- bundle_id: bundle_id,
145
- bundle_version: bundle_version,
146
- title: title
147
- })
148
-
149
- # Creates html from template
150
- if html_template_path && File.exist?(html_template_path)
151
- html_template = eth.load_from_path(html_template_path)
152
- else
153
- html_template = eth.load("s3_html_template")
154
- end
155
-
156
- html_render = eth.render(html_template, {
157
- url: plist_url,
158
- plist_url: plist_url,
159
- ipa_url: ipa_url,
160
- build_num: build_num,
161
- bundle_id: bundle_id,
162
- bundle_version: bundle_version,
163
- title: title,
164
- device_family: device_family
165
- })
166
-
167
- # Creates version from template
168
- if version_template_path && File.exist?(version_template_path)
169
- version_template = eth.load_from_path(version_template_path)
170
- else
171
- version_template = eth.load("s3_version_template")
172
- end
173
- version_render = eth.render(version_template, {
174
- url: plist_url,
175
- plist_url: plist_url,
176
- ipa_url: ipa_url,
177
- build_num: build_num,
178
- bundle_version: bundle_version,
179
- full_version: full_version
180
- })
181
-
182
- #####################################
183
- #
184
- # html and plist uploading
185
- #
186
- #####################################
187
-
188
- plist_url = self.upload_file(bucket, plist_file_name, plist_render, acl)
189
- html_url = self.upload_file(bucket, html_file_name, html_render, acl)
190
- version_url = self.upload_file(bucket, version_file_name, version_render, acl)
191
-
192
- # Setting action and environment variables
193
- Actions.lane_context[SharedValues::S3_PLIST_OUTPUT_PATH] = plist_url
194
- ENV[SharedValues::S3_PLIST_OUTPUT_PATH.to_s] = plist_url
195
-
196
- Actions.lane_context[SharedValues::S3_HTML_OUTPUT_PATH] = html_url
197
- ENV[SharedValues::S3_HTML_OUTPUT_PATH.to_s] = html_url
198
-
199
- Actions.lane_context[SharedValues::S3_VERSION_OUTPUT_PATH] = version_url
200
- ENV[SharedValues::S3_VERSION_OUTPUT_PATH.to_s] = version_url
201
-
202
- UI.success("Successfully uploaded ipa file to '#{Actions.lane_context[SharedValues::S3_IPA_OUTPUT_PATH]}'")
203
-
204
- return true
205
- end
206
-
207
- # @return true if loading the AWS SDK from the 'aws-sdk' gem yields the expected v1 API, or false otherwise
208
- def self.load_from_original_gem_name
209
- begin
210
- # We don't use `Actions.verify_gem!` here, because we want to silently be OK with this gem not being
211
- # present, in case the user has already migrated to 'aws-sdk-v1' (see #load_from_v1_gem_name)
212
- Gem::Specification.find_by_name('aws-sdk')
213
- require 'aws-sdk'
214
- rescue Gem::LoadError
215
- UI.verbose("The 'aws-sdk' gem is not present")
216
- return false
217
- end
218
-
219
- UI.verbose("The 'aws-sdk' gem is present")
220
- true
221
- end
222
-
223
- def self.load_from_v1_gem_name
224
- Actions.verify_gem!('aws-sdk-v1')
225
- require 'aws-sdk-v1'
226
- end
227
-
228
- def self.v1_sdk_module_present?
229
- begin
230
- # Here we'll make sure that the `AWS` module is defined. If it is, the gem is the v1.x API.
231
- Object.const_get("AWS")
232
- rescue NameError
233
- UI.verbose("Couldn't find the needed `AWS` module in the 'aws-sdk' gem")
234
- return false
235
- end
236
-
237
- UI.verbose("Found the needed `AWS` module in the 'aws-sdk' gem")
238
- true
239
- end
240
-
241
- def self.s3_client(s3_access_key, s3_secret_access_key, s3_region)
242
- # The AWS SDK API changed completely in v2.x. The most stable way to keep using the V1 API is to
243
- # require the 'aws-sdk-v1' gem directly. However, for those customers who are using the 'aws-sdk'
244
- # gem at v1.x, we don't want to break their setup which currently works.
245
- #
246
- # Therefore, we will attempt to load the v1 API from the original gem name, but go on to load
247
- # from the aws-sdk-v1 gem name if necessary
248
- loaded_original_gem = load_from_original_gem_name
249
-
250
- if !loaded_original_gem || !v1_sdk_module_present?
251
- load_from_v1_gem_name
252
- UI.verbose("Loaded AWS SDK v1.x from the `aws-sdk-v1` gem")
253
- else
254
- UI.verbose("Loaded AWS SDK v1.x from the `aws-sdk` gem")
255
- end
256
-
257
- if s3_region
258
- s3_client = AWS::S3.new(
259
- access_key_id: s3_access_key,
260
- secret_access_key: s3_secret_access_key,
261
- region: s3_region
262
- )
263
- else
264
- s3_client = AWS::S3.new(
265
- access_key_id: s3_access_key,
266
- secret_access_key: s3_secret_access_key
267
- )
268
- end
269
- s3_client
270
- end
271
-
272
- def self.upload_file(bucket, file_name, file_data, acl)
273
- obj = bucket.objects.create(file_name, file_data, acl: acl)
274
-
275
- # When you enable versioning on a S3 bucket,
276
- # writing to an object will create an object version
277
- # instead of replacing the existing object.
278
- # http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/S3/ObjectVersion.html
279
- if obj.kind_of?(AWS::S3::ObjectVersion)
280
- obj = obj.object
281
- end
282
-
283
- # Return public url
284
- obj.public_url.to_s
285
- end
286
-
287
- #
288
- # NOT a fan of this as this was taken straight from Shenzhen
289
- # https://github.com/nomad/shenzhen/blob/986792db5d4d16a80c865a2748ee96ba63644821/lib/shenzhen/plugins/s3.rb#L32
290
- #
291
- # Need to find a way to not use this copied method
292
- #
293
- # AGAIN, I am not happy about this right now.
294
- # Using this for prototype reasons.
295
- #
296
- def self.expand_path_with_substitutions_from_ipa_plist(ipa, path)
297
- substitutions = path.scan(/\{CFBundle[^}]+\}/)
298
- return path if substitutions.empty?
299
- info = FastlaneCore::IpaFileAnalyser.fetch_info_plist_file(ipa) or return path
300
-
301
- substitutions.uniq.each do |substitution|
302
- key = substitution[1...-1]
303
- value = info[key]
304
- path.gsub!(Regexp.new(substitution), value) if value
305
- end
306
-
307
- return path
21
+ UI.user_error!("Please use the `aws_s3` plugin instead. Install using `fastlane add_plugin aws_s3`.")
308
22
  end
309
23
 
310
24
  def self.description
@@ -423,7 +137,7 @@ module Fastlane
423
137
  end
424
138
 
425
139
  def self.is_supported?(platform)
426
- platform == :ios
140
+ false
427
141
  end
428
142
 
429
143
  def self.example_code
@@ -434,8 +148,8 @@ module Fastlane
434
148
  access_key: ENV["S3_ACCESS_KEY"], # Required from user.
435
149
  secret_access_key: ENV["S3_SECRET_ACCESS_KEY"], # Required from user.
436
150
  bucket: ENV["S3_BUCKET"], # Required from user.
437
- ipa: "AppName.ipa", # Optional is you use `ipa` to build
438
- dsym: "AppName.app.dSYM.zip", # Optional is you use `ipa` to build
151
+ ipa: "AppName.ipa", # Optional if you use `ipa` to build
152
+ dsym: "AppName.app.dSYM.zip", # Optional if you use `ipa` to build
439
153
  path: "v{CFBundleShortVersionString}_b{CFBundleVersion}/", # This is actually the default.
440
154
  upload_metadata: true, # Upload version.json, plist and HTML. Set to false to skip uploading of these files.
441
155
  version_file_name: "app_version.json", # Name of the file to upload to S3. Defaults to "version.json"