fastlane 2.163.0 → 2.164.0

This diff has not been reviewed by any users.
Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +60 -60
  3. data/deliver/lib/deliver/queue_worker.rb +14 -29
  4. data/deliver/lib/deliver/upload_metadata.rb +7 -2
  5. data/deliver/lib/deliver/upload_screenshots.rb +3 -5
  6. data/fastlane/lib/fastlane/actions/docs/capture_ios_screenshots.md +1 -1
  7. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +9 -0
  8. data/fastlane/lib/fastlane/actions/import_from_git.rb +9 -1
  9. data/fastlane/lib/fastlane/actions/is_ci.rb +1 -1
  10. data/fastlane/lib/fastlane/actions/register_devices.rb +4 -1
  11. data/fastlane/lib/fastlane/actions/set_changelog.rb +31 -3
  12. data/fastlane/lib/fastlane/fast_file.rb +74 -23
  13. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +1 -0
  14. data/fastlane/lib/fastlane/version.rb +1 -1
  15. data/fastlane/swift/Deliverfile.swift +1 -1
  16. data/fastlane/swift/DeliverfileProtocol.swift +1 -1
  17. data/fastlane/swift/Fastlane.swift +16 -4
  18. data/fastlane/swift/Gymfile.swift +1 -1
  19. data/fastlane/swift/GymfileProtocol.swift +1 -1
  20. data/fastlane/swift/Matchfile.swift +1 -1
  21. data/fastlane/swift/MatchfileProtocol.swift +5 -1
  22. data/fastlane/swift/Precheckfile.swift +1 -1
  23. data/fastlane/swift/PrecheckfileProtocol.swift +1 -1
  24. data/fastlane/swift/Scanfile.swift +1 -1
  25. data/fastlane/swift/ScanfileProtocol.swift +1 -1
  26. data/fastlane/swift/Screengrabfile.swift +1 -1
  27. data/fastlane/swift/ScreengrabfileProtocol.swift +1 -1
  28. data/fastlane/swift/Snapshotfile.swift +1 -1
  29. data/fastlane/swift/SnapshotfileProtocol.swift +1 -1
  30. data/fastlane_core/lib/fastlane_core/device_manager.rb +8 -4
  31. data/fastlane_core/lib/fastlane_core/helper.rb +1 -1
  32. data/fastlane_core/lib/fastlane_core/keychain_importer.rb +1 -1
  33. data/match/lib/match/.commands_generator.rb.swp +0 -0
  34. data/match/lib/match/.importer.rb.swp +0 -0
  35. data/match/lib/match/.options.rb.swp +0 -0
  36. data/match/lib/match/importer.rb +33 -21
  37. data/match/lib/match/options.rb +6 -0
  38. data/scan/lib/scan/detect_values.rb +5 -8
  39. data/scan/lib/scan/runner.rb +2 -1
  40. data/sigh/lib/assets/resign.sh +1 -1
  41. data/sigh/lib/sigh/runner.rb +2 -2
  42. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +2 -1
  43. data/supply/lib/supply/uploader.rb +1 -1
  44. metadata +19 -18
  45. data/fastlane/lib/fastlane/actions/.register_device.rb.swp +0 -0
  46. data/fastlane/lib/fastlane/actions/.register_devices.rb.swp +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9018a049a27d02426f74370e23deb841ec641e4f446e6d334a7ae122223c1812
4
- data.tar.gz: 9c8f3652d0af272b012df00af5b191e78bcadc8da89aab7e8e4578bd40e5af31
3
+ metadata.gz: 8cdb3738f1c646ea1cbff438e63895c5001d876fb9aeb585c1750ee61cbd86a4
4
+ data.tar.gz: e19bd6d624de20687b690df55a2f906a69eecc9ea2ee45bf6ad6b58eb64c468c
5
5
  SHA512:
6
- metadata.gz: 10e7d05e7d169ca32bd90cb75e137c7acd9d04fdefc575d0e72bbe923e76e5ce121b6c528d82ea4acf78d0914d025e90fb7d01935cb147c4db60bc8dcb59dc00
7
- data.tar.gz: b2fa4c281f7f73fb6132588b6027a95c50f349e57c8c1093295b2f0757e5e0352fae18f59f5fb9070dc4927a2d87b99e2307fda64748b27ffbcf93901d99c810
6
+ metadata.gz: da9f5620643df9f24fbded5fe29445ad72c9601d7c370a8092d1874ab22f629389fc9c43cbed71a8fa27667d91c425aa1666a581bbd2f1b34578dc0067ba4684
7
+ data.tar.gz: a62090282896c1d8c65b2c789067a82f09f60089bc4fc963c104d4bfae0ef2d89e859484e744fd3e92e49f804c0d8cd5f315c6d5f392cd7bb1ee18f34efae631
data/README.md CHANGED
@@ -34,17 +34,17 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
34
34
  <!-- This table is regenerated and resorted on each release -->
35
35
  <table id='team'>
36
36
  <tr>
37
- <td id='andrew-mcburney'>
38
- <a href='https://github.com/armcburney'>
39
- <img src='https://github.com/armcburney.png?size=140'>
37
+ <td id='stefan-natchev'>
38
+ <a href='https://github.com/snatchev'>
39
+ <img src='https://github.com/snatchev.png?size=140'>
40
40
  </a>
41
- <h4 align='center'><a href='https://twitter.com/armcburney'>Andrew McBurney</a></h4>
41
+ <h4 align='center'><a href='https://twitter.com/snatchev'>Stefan Natchev</a></h4>
42
42
  </td>
43
- <td id='felix-krause'>
44
- <a href='https://github.com/KrauseFx'>
45
- <img src='https://github.com/KrauseFx.png?size=140'>
43
+ <td id='olivier-halligon'>
44
+ <a href='https://github.com/AliSoftware'>
45
+ <img src='https://github.com/AliSoftware.png?size=140'>
46
46
  </a>
47
- <h4 align='center'><a href='https://twitter.com/KrauseFx'>Felix Krause</a></h4>
47
+ <h4 align='center'><a href='https://twitter.com/aligatr'>Olivier Halligon</a></h4>
48
48
  </td>
49
49
  <td id='luka-mirosevic'>
50
50
  <a href='https://github.com/lmirosevic'>
@@ -52,31 +52,43 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
52
52
  </a>
53
53
  <h4 align='center'><a href='https://twitter.com/lmirosevic'>Luka Mirosevic</a></h4>
54
54
  </td>
55
- <td id='iulian-onofrei'>
56
- <a href='https://github.com/revolter'>
57
- <img src='https://github.com/revolter.png?size=140'>
55
+ <td id='joshua-liebowitz'>
56
+ <a href='https://github.com/taquitos'>
57
+ <img src='https://github.com/taquitos.png?size=140'>
58
58
  </a>
59
- <h4 align='center'><a href='https://twitter.com/Revolt666'>Iulian Onofrei</a></h4>
59
+ <h4 align='center'><a href='https://twitter.com/taquitos'>Joshua Liebowitz</a></h4>
60
60
  </td>
61
- <td id='jimmy-dee'>
62
- <a href='https://github.com/jdee'>
63
- <img src='https://github.com/jdee.png?size=140'>
61
+ <td id='manu-wallner'>
62
+ <a href='https://github.com/milch'>
63
+ <img src='https://github.com/milch.png?size=140'>
64
64
  </a>
65
- <h4 align='center'>Jimmy Dee</h4>
65
+ <h4 align='center'><a href='https://twitter.com/acrooow'>Manu Wallner</a></h4>
66
66
  </td>
67
67
  </tr>
68
68
  <tr>
69
+ <td id='maksym-grebenets'>
70
+ <a href='https://github.com/mgrebenets'>
71
+ <img src='https://github.com/mgrebenets.png?size=140'>
72
+ </a>
73
+ <h4 align='center'><a href='https://twitter.com/mgrebenets'>Maksym Grebenets</a></h4>
74
+ </td>
75
+ <td id='jorge-revuelta-h'>
76
+ <a href='https://github.com/minuscorp'>
77
+ <img src='https://github.com/minuscorp.png?size=140'>
78
+ </a>
79
+ <h4 align='center'><a href='https://twitter.com/minuscorp'>Jorge Revuelta H</a></h4>
80
+ </td>
69
81
  <td id='jan-piotrowski'>
70
82
  <a href='https://github.com/janpio'>
71
83
  <img src='https://github.com/janpio.png?size=140'>
72
84
  </a>
73
85
  <h4 align='center'><a href='https://twitter.com/Sujan'>Jan Piotrowski</a></h4>
74
86
  </td>
75
- <td id='joshua-liebowitz'>
76
- <a href='https://github.com/taquitos'>
77
- <img src='https://github.com/taquitos.png?size=140'>
87
+ <td id='helmut-januschka'>
88
+ <a href='https://github.com/hjanuschka'>
89
+ <img src='https://github.com/hjanuschka.png?size=140'>
78
90
  </a>
79
- <h4 align='center'><a href='https://twitter.com/taquitos'>Joshua Liebowitz</a></h4>
91
+ <h4 align='center'><a href='https://twitter.com/hjanuschka'>Helmut Januschka</a></h4>
80
92
  </td>
81
93
  <td id='max-ott'>
82
94
  <a href='https://github.com/max-ott'>
@@ -84,25 +96,13 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
84
96
  </a>
85
97
  <h4 align='center'><a href='https://twitter.com/ott_max'>Max Ott</a></h4>
86
98
  </td>
87
- <td id='manu-wallner'>
88
- <a href='https://github.com/milch'>
89
- <img src='https://github.com/milch.png?size=140'>
90
- </a>
91
- <h4 align='center'><a href='https://twitter.com/acrooow'>Manu Wallner</a></h4>
92
- </td>
93
- <td id='josh-holtz'>
94
- <a href='https://github.com/joshdholtz'>
95
- <img src='https://github.com/joshdholtz.png?size=140'>
96
- </a>
97
- <h4 align='center'><a href='https://twitter.com/joshdholtz'>Josh Holtz</a></h4>
98
- </td>
99
99
  </tr>
100
100
  <tr>
101
- <td id='jorge-revuelta-h'>
102
- <a href='https://github.com/minuscorp'>
103
- <img src='https://github.com/minuscorp.png?size=140'>
101
+ <td id='matthew-ellis'>
102
+ <a href='https://github.com/matthewellis'>
103
+ <img src='https://github.com/matthewellis.png?size=140'>
104
104
  </a>
105
- <h4 align='center'><a href='https://twitter.com/minuscorp'>Jorge Revuelta H</a></h4>
105
+ <h4 align='center'><a href='https://twitter.com/mellis1995'>Matthew Ellis</a></h4>
106
106
  </td>
107
107
  <td id='aaron-brager'>
108
108
  <a href='https://github.com/getaaron'>
@@ -110,17 +110,17 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
110
110
  </a>
111
111
  <h4 align='center'><a href='https://twitter.com/getaaron'>Aaron Brager</a></h4>
112
112
  </td>
113
- <td id='stefan-natchev'>
114
- <a href='https://github.com/snatchev'>
115
- <img src='https://github.com/snatchev.png?size=140'>
113
+ <td id='josh-holtz'>
114
+ <a href='https://github.com/joshdholtz'>
115
+ <img src='https://github.com/joshdholtz.png?size=140'>
116
116
  </a>
117
- <h4 align='center'><a href='https://twitter.com/snatchev'>Stefan Natchev</a></h4>
117
+ <h4 align='center'><a href='https://twitter.com/joshdholtz'>Josh Holtz</a></h4>
118
118
  </td>
119
- <td id='maksym-grebenets'>
120
- <a href='https://github.com/mgrebenets'>
121
- <img src='https://github.com/mgrebenets.png?size=140'>
119
+ <td id='jimmy-dee'>
120
+ <a href='https://github.com/jdee'>
121
+ <img src='https://github.com/jdee.png?size=140'>
122
122
  </a>
123
- <h4 align='center'><a href='https://twitter.com/mgrebenets'>Maksym Grebenets</a></h4>
123
+ <h4 align='center'>Jimmy Dee</h4>
124
124
  </td>
125
125
  <td id='jérôme-lacoste'>
126
126
  <a href='https://github.com/lacostej'>
@@ -130,17 +130,17 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
130
130
  </td>
131
131
  </tr>
132
132
  <tr>
133
- <td id='helmut-januschka'>
134
- <a href='https://github.com/hjanuschka'>
135
- <img src='https://github.com/hjanuschka.png?size=140'>
133
+ <td id='daniel-jankowski'>
134
+ <a href='https://github.com/mollyIV'>
135
+ <img src='https://github.com/mollyIV.png?size=140'>
136
136
  </a>
137
- <h4 align='center'><a href='https://twitter.com/hjanuschka'>Helmut Januschka</a></h4>
137
+ <h4 align='center'><a href='https://twitter.com/mollyIV'>Daniel Jankowski</a></h4>
138
138
  </td>
139
- <td id='matthew-ellis'>
140
- <a href='https://github.com/matthewellis'>
141
- <img src='https://github.com/matthewellis.png?size=140'>
139
+ <td id='andrew-mcburney'>
140
+ <a href='https://github.com/armcburney'>
141
+ <img src='https://github.com/armcburney.png?size=140'>
142
142
  </a>
143
- <h4 align='center'><a href='https://twitter.com/mellis1995'>Matthew Ellis</a></h4>
143
+ <h4 align='center'><a href='https://twitter.com/armcburney'>Andrew McBurney</a></h4>
144
144
  </td>
145
145
  <td id='kohki-miki'>
146
146
  <a href='https://github.com/giginet'>
@@ -154,11 +154,11 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
154
154
  </a>
155
155
  <h4 align='center'><a href='https://twitter.com/endocrimes'>Danielle Tomlinson</a></h4>
156
156
  </td>
157
- <td id='olivier-halligon'>
158
- <a href='https://github.com/AliSoftware'>
159
- <img src='https://github.com/AliSoftware.png?size=140'>
157
+ <td id='iulian-onofrei'>
158
+ <a href='https://github.com/revolter'>
159
+ <img src='https://github.com/revolter.png?size=140'>
160
160
  </a>
161
- <h4 align='center'><a href='https://twitter.com/aligatr'>Olivier Halligon</a></h4>
161
+ <h4 align='center'><a href='https://twitter.com/Revolt666'>Iulian Onofrei</a></h4>
162
162
  </td>
163
163
  </tr>
164
164
  <tr>
@@ -168,11 +168,11 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
168
168
  </a>
169
169
  <h4 align='center'><a href='https://twitter.com/nafu003'>Fumiya Nakamura</a></h4>
170
170
  </td>
171
- <td id='daniel-jankowski'>
172
- <a href='https://github.com/mollyIV'>
173
- <img src='https://github.com/mollyIV.png?size=140'>
171
+ <td id='felix-krause'>
172
+ <a href='https://github.com/KrauseFx'>
173
+ <img src='https://github.com/KrauseFx.png?size=140'>
174
174
  </a>
175
- <h4 align='center'><a href='https://twitter.com/mollyIV'>Daniel Jankowski</a></h4>
175
+ <h4 align='center'><a href='https://twitter.com/KrauseFx'>Felix Krause</a></h4>
176
176
  </td>
177
177
  </table>
178
178
 
@@ -6,9 +6,11 @@ module Deliver
6
6
  # Use this when you have all the items that you'll process in advance.
7
7
  # Simply enqueue them to this and call `QueueWorker#start`.
8
8
  class QueueWorker
9
+ NUMBER_OF_THREADS = Helper.test? ? 1 : [ENV.fetch("DELIVER_NUMBER_OF_THREADS", 10).to_i, 10].min
10
+
9
11
  # @param concurrency (Numeric) - A number of threads to be created
10
12
  # @param block (Proc) - A task you want to execute with enqueued items
11
- def initialize(concurrency, &block)
13
+ def initialize(concurrency = NUMBER_OF_THREADS, &block)
12
14
  @concurrency = concurrency
13
15
  @block = block
14
16
  @queue = Queue.new
@@ -19,46 +21,29 @@ module Deliver
19
21
  @queue.push(job)
20
22
  end
21
23
 
24
+ # @param jobs (Array<Object>) - An array of arbitary object that keeps parameters
25
+ def batch_enqueue(jobs)
26
+ raise(ArgumentError, "Enqueue Array instead of #{jobs.class}") unless jobs.kind_of?(Array)
27
+ jobs.each { |job| enqueue(job) }
28
+ end
29
+
22
30
  # Call this after you enqueuned all the jobs you want to process
23
31
  # This method blocks current thread until all the enqueued jobs are processed
24
32
  def start
33
+ @queue.close
34
+
25
35
  threads = []
26
36
  @concurrency.times do
27
37
  threads << Thread.new do
28
- while running? && !empty?
38
+ job = @queue.pop
39
+ while job
40
+ @block.call(job)
29
41
  job = @queue.pop
30
- @block.call(job) if job
31
42
  end
32
43
  end
33
44
  end
34
45
 
35
- wait_for_complete
36
46
  threads.each(&:join)
37
47
  end
38
-
39
- private
40
-
41
- def running?
42
- !@queue.closed?
43
- end
44
-
45
- def empty?
46
- @queue.empty?
47
- end
48
-
49
- def wait_for_complete
50
- wait_thread = Thread.new do
51
- loop do
52
- if @queue.empty?
53
- @queue.close
54
- break
55
- end
56
-
57
- sleep(1)
58
- end
59
- end
60
-
61
- wait_thread.join
62
- end
63
48
  end
64
49
  end
@@ -1,4 +1,5 @@
1
1
  require_relative 'module'
2
+ require_relative 'queue_worker'
2
3
 
3
4
  module Deliver
4
5
  # upload description, rating, etc.
@@ -197,22 +198,26 @@ module Deliver
197
198
  sleep(1)
198
199
 
199
200
  # Update app store version localizations
200
- app_store_version_localizations.each do |app_store_version_localization|
201
+ store_version_worker = Deliver::QueueWorker.new do |app_store_version_localization|
201
202
  attributes = localized_version_attributes_by_locale[app_store_version_localization.locale]
202
203
  if attributes
203
204
  UI.message("Uploading metadata to App Store Connect for localized version '#{app_store_version_localization.locale}'")
204
205
  app_store_version_localization.update(attributes: attributes)
205
206
  end
206
207
  end
208
+ store_version_worker.batch_enqueue(app_store_version_localizations)
209
+ store_version_worker.start
207
210
 
208
211
  # Update app info localizations
209
- app_info_localizations.each do |app_info_localization|
212
+ app_info_worker = Deliver::QueueWorker.new do |app_info_localization|
210
213
  attributes = localized_info_attributes_by_locale[app_info_localization.locale]
211
214
  if attributes
212
215
  UI.message("Uploading metadata to App Store Connect for localized info '#{app_info_localization.locale}'")
213
216
  app_info_localization.update(attributes: attributes)
214
217
  end
215
218
  end
219
+ app_info_worker.batch_enqueue(app_info_localizations)
220
+ app_info_worker.start
216
221
 
217
222
  # Update categories
218
223
  app_info = fetch_edit_app_info(app)
@@ -13,8 +13,6 @@ module Deliver
13
13
  DeleteScreenshotJob = Struct.new(:app_screenshot, :localization, :app_screenshot_set)
14
14
  UploadScreenshotJob = Struct.new(:app_screenshot_set, :path)
15
15
 
16
- NUMBER_OF_THREADS = Helper.test? ? 1 : [ENV.fetch("DELIVER_NUMBER_OF_THREADS", 10).to_i, 10].min
17
-
18
16
  def upload(options, screenshots)
19
17
  return if options[:skip_screenshots]
20
18
  return if options[:edit_live]
@@ -69,7 +67,7 @@ module Deliver
69
67
  def delete_screenshots(localizations, screenshots_per_language, tries: 5)
70
68
  tries -= 1
71
69
 
72
- worker = QueueWorker.new(NUMBER_OF_THREADS) do |job|
70
+ worker = QueueWorker.new do |job|
73
71
  start_time = Time.now
74
72
  target = "#{job.localization.locale} #{job.app_screenshot_set.screenshot_display_type} #{job.app_screenshot.id}"
75
73
  begin
@@ -115,7 +113,7 @@ module Deliver
115
113
  tries -= 1
116
114
 
117
115
  # Upload screenshots
118
- worker = QueueWorker.new(NUMBER_OF_THREADS) do |job|
116
+ worker = QueueWorker.new do |job|
119
117
  begin
120
118
  UI.verbose("Uploading '#{job.path}'...")
121
119
  start_time = Time.now
@@ -236,7 +234,7 @@ module Deliver
236
234
  iterator = AppScreenshotIterator.new(localizations)
237
235
 
238
236
  # Re-order screenshots within app_screenshot_set
239
- worker = QueueWorker.new(NUMBER_OF_THREADS) do |app_screenshot_set|
237
+ worker = QueueWorker.new do |app_screenshot_set|
240
238
  original_ids = app_screenshot_set.app_screenshots.map(&:id)
241
239
  sorted_ids = app_screenshot_set.app_screenshots.sort_by(&:file_name).map(&:id)
242
240
  if original_ids != sorted_ids
@@ -106,7 +106,7 @@ app.launch()
106
106
 
107
107
  ```objective-c
108
108
  XCUIApplication *app = [[XCUIApplication alloc] init];
109
- [Snapshot setupSnapshot:app];
109
+ [Snapshot setupSnapshot:app waitForAnimations:NO];
110
110
  [app launch];
111
111
  ```
112
112
 
@@ -492,6 +492,15 @@ fastlane match import
492
492
 
493
493
  You'll be prompted for the certificate (`.cer`), the private key (`.p12`) and the provisioning profiles (`.mobileprovision` or `.provisionprofile`) paths. _match_ will first validate the certificate (`.cer`) against the Developer Portal before importing the certificate, the private key and the provisioning profiles into the specified _match_ repository.
494
494
 
495
+ However if there is no access to the developer portal but there are certificates, private keys and profiles provided, you can use the `skip_certificate_matching` option to tell _match_ not to verify the certificates. Like this:
496
+
497
+ ```no-highlight
498
+ fastlane match import --skip_certificate_matching true
499
+ ```
500
+ This will skip login to Apple Developer Portal and will import the provided certificate, private key and profile directly to the certificates repo.
501
+
502
+ Please be careful when using this option and ensure the certificates and profiles match the type (development, adhoc, appstore, enterprise, developer_id) and are not revoked or expired.
503
+
495
504
  ### Manual Decrypt
496
505
 
497
506
  If you want to manually decrypt a file you can.
@@ -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!"
@@ -53,7 +53,10 @@ module Fastlane
53
53
  existing_devices = Spaceship::ConnectAPI::Device.all
54
54
 
55
55
  device_objs = new_devices.map do |device|
56
- 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
57
60
 
58
61
  device_platform = platform
59
62
 
@@ -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,
@@ -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
@@ -179,6 +179,7 @@ Style/MethodCallWithArgsParentheses:
179
179
  - private_lane
180
180
  - platform
181
181
  - to
182
+ - not_to
182
183
  - describe
183
184
  - it
184
185
  - be
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
- VERSION = '2.163.0'.freeze
2
+ VERSION = '2.164.0'.freeze
3
3
  DESCRIPTION = "The easiest way to automate beta deployments and releases for your iOS and Android apps".freeze
4
4
  MINIMUM_XCODE_RELEASE = "7.0".freeze
5
5
  RUBOCOP_REQUIREMENT = '0.49.1'.freeze
@@ -17,4 +17,4 @@ public class Deliverfile: DeliverfileProtocol {
17
17
  // during the `init` process, and you won't see this message
18
18
  }
19
19
 
20
- // Generated with fastlane 2.163.0
20
+ // Generated with fastlane 2.164.0
@@ -256,4 +256,4 @@ public extension DeliverfileProtocol {
256
256
 
257
257
  // Please don't remove the lines below
258
258
  // They are used to detect outdated files
259
- // FastlaneRunnerAPIVersion [0.9.46]
259
+ // FastlaneRunnerAPIVersion [0.9.47]
@@ -4783,6 +4783,7 @@ public func makeChangelogFromJenkins(fallbackChangelog: String = "",
4783
4783
  - templateName: The name of provisioning profile template. If the developer account has provisioning profile templates (aka: custom entitlements), the template name can be found by inspecting the Entitlements drop-down while creating/editing a provisioning profile (e.g. "Apple Pay Pass Suppression Development")
4784
4784
  - profileName: A custom name for the provisioning profile. This will replace the default provisioning profile name if specified
4785
4785
  - failOnNameTaken: Should the command fail if it was about to create a duplicate of an existing provisioning profile. It can happen due to issues on Apple Developer Portal, when profile to be recreated was not properly deleted first
4786
+ - skipCertificateMatching: Set to true if there is no access to Apple developer portal but there are certificates, keys and profiles provided. Only works with match import action
4786
4787
  - outputPath: Path in which to export certificates, key and profile
4787
4788
  - skipSetPartitionList: Skips setting the partition list (which can sometimes take a long time). Setting the partition list is usually needed to prevent Xcode from prompting to allow a cert to be used for signing
4788
4789
  - verbose: Print out extra information and all commands
@@ -4829,6 +4830,7 @@ public func match(type: Any = matchfile.type,
4829
4830
  templateName: Any? = matchfile.templateName,
4830
4831
  profileName: Any? = matchfile.profileName,
4831
4832
  failOnNameTaken: Bool = matchfile.failOnNameTaken,
4833
+ skipCertificateMatching: Bool = matchfile.skipCertificateMatching,
4832
4834
  outputPath: Any? = matchfile.outputPath,
4833
4835
  skipSetPartitionList: Bool = matchfile.skipSetPartitionList,
4834
4836
  verbose: Bool = matchfile.verbose)
@@ -4873,6 +4875,7 @@ public func match(type: Any = matchfile.type,
4873
4875
  RubyCommand.Argument(name: "template_name", value: templateName),
4874
4876
  RubyCommand.Argument(name: "profile_name", value: profileName),
4875
4877
  RubyCommand.Argument(name: "fail_on_name_taken", value: failOnNameTaken),
4878
+ RubyCommand.Argument(name: "skip_certificate_matching", value: skipCertificateMatching),
4876
4879
  RubyCommand.Argument(name: "output_path", value: outputPath),
4877
4880
  RubyCommand.Argument(name: "skip_set_partition_list", value: skipSetPartitionList),
4878
4881
  RubyCommand.Argument(name: "verbose", value: verbose)])
@@ -6612,6 +6615,8 @@ public func setBuildNumberRepository(useHgRevisionNumber: Bool = false,
6612
6615
  Set the changelog for all languages on App Store Connect
6613
6616
 
6614
6617
  - parameters:
6618
+ - apiKeyPath: Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)
6619
+ - apiKey: Your App Store Connect API Key information (https://docs.fastlane.tools/app-store-connect-api/#use-return-value-and-pass-in-as-an-option)
6615
6620
  - appIdentifier: The bundle identifier of your app
6616
6621
  - username: Your Apple ID Username
6617
6622
  - version: The version number to create/update
@@ -6624,15 +6629,19 @@ public func setBuildNumberRepository(useHgRevisionNumber: Bool = false,
6624
6629
  You can store the changelog in `./changelog.txt` and it will automatically get loaded from there. This integration is useful if you support e.g. 10 languages and want to use the same "What's new"-text for all languages.
6625
6630
  Defining the version is optional. _fastlane_ will try to automatically detect it if you don't provide one.
6626
6631
  */
6627
- public func setChangelog(appIdentifier: String,
6628
- username: String,
6632
+ public func setChangelog(apiKeyPath: String? = nil,
6633
+ apiKey: [String: Any]? = nil,
6634
+ appIdentifier: String,
6635
+ username: String? = nil,
6629
6636
  version: String? = nil,
6630
6637
  changelog: String? = nil,
6631
6638
  teamId: Any? = nil,
6632
6639
  teamName: String? = nil,
6633
6640
  platform: String = "ios")
6634
6641
  {
6635
- let command = RubyCommand(commandID: "", methodName: "set_changelog", className: nil, args: [RubyCommand.Argument(name: "app_identifier", value: appIdentifier),
6642
+ let command = RubyCommand(commandID: "", methodName: "set_changelog", className: nil, args: [RubyCommand.Argument(name: "api_key_path", value: apiKeyPath),
6643
+ RubyCommand.Argument(name: "api_key", value: apiKey),
6644
+ RubyCommand.Argument(name: "app_identifier", value: appIdentifier),
6636
6645
  RubyCommand.Argument(name: "username", value: username),
6637
6646
  RubyCommand.Argument(name: "version", value: version),
6638
6647
  RubyCommand.Argument(name: "changelog", value: changelog),
@@ -7704,6 +7713,7 @@ public func swiftlint(mode: Any = "lint",
7704
7713
  - templateName: The name of provisioning profile template. If the developer account has provisioning profile templates (aka: custom entitlements), the template name can be found by inspecting the Entitlements drop-down while creating/editing a provisioning profile (e.g. "Apple Pay Pass Suppression Development")
7705
7714
  - profileName: A custom name for the provisioning profile. This will replace the default provisioning profile name if specified
7706
7715
  - failOnNameTaken: Should the command fail if it was about to create a duplicate of an existing provisioning profile. It can happen due to issues on Apple Developer Portal, when profile to be recreated was not properly deleted first
7716
+ - skipCertificateMatching: Set to true if there is no access to Apple developer portal but there are certificates, keys and profiles provided. Only works with match import action
7707
7717
  - outputPath: Path in which to export certificates, key and profile
7708
7718
  - skipSetPartitionList: Skips setting the partition list (which can sometimes take a long time). Setting the partition list is usually needed to prevent Xcode from prompting to allow a cert to be used for signing
7709
7719
  - verbose: Print out extra information and all commands
@@ -7750,6 +7760,7 @@ public func syncCodeSigning(type: String = "development",
7750
7760
  templateName: String? = nil,
7751
7761
  profileName: String? = nil,
7752
7762
  failOnNameTaken: Bool = false,
7763
+ skipCertificateMatching: Bool = false,
7753
7764
  outputPath: String? = nil,
7754
7765
  skipSetPartitionList: Bool = false,
7755
7766
  verbose: Bool = false)
@@ -7794,6 +7805,7 @@ public func syncCodeSigning(type: String = "development",
7794
7805
  RubyCommand.Argument(name: "template_name", value: templateName),
7795
7806
  RubyCommand.Argument(name: "profile_name", value: profileName),
7796
7807
  RubyCommand.Argument(name: "fail_on_name_taken", value: failOnNameTaken),
7808
+ RubyCommand.Argument(name: "skip_certificate_matching", value: skipCertificateMatching),
7797
7809
  RubyCommand.Argument(name: "output_path", value: outputPath),
7798
7810
  RubyCommand.Argument(name: "skip_set_partition_list", value: skipSetPartitionList),
7799
7811
  RubyCommand.Argument(name: "verbose", value: verbose)])
@@ -9387,4 +9399,4 @@ public let snapshotfile = Snapshotfile()
9387
9399
 
9388
9400
  // Please don't remove the lines below
9389
9401
  // They are used to detect outdated files
9390
- // FastlaneRunnerAPIVersion [0.9.99]
9402
+ // FastlaneRunnerAPIVersion [0.9.100]
@@ -17,4 +17,4 @@ public class Gymfile: GymfileProtocol {
17
17
  // during the `init` process, and you won't see this message
18
18
  }
19
19
 
20
- // Generated with fastlane 2.163.0
20
+ // Generated with fastlane 2.164.0
@@ -184,4 +184,4 @@ public extension GymfileProtocol {
184
184
 
185
185
  // Please don't remove the lines below
186
186
  // They are used to detect outdated files
187
- // FastlaneRunnerAPIVersion [0.9.49]
187
+ // FastlaneRunnerAPIVersion [0.9.50]
@@ -17,4 +17,4 @@ public class Matchfile: MatchfileProtocol {
17
17
  // during the `init` process, and you won't see this message
18
18
  }
19
19
 
20
- // Generated with fastlane 2.163.0
20
+ // Generated with fastlane 2.164.0
@@ -122,6 +122,9 @@ public protocol MatchfileProtocol: class {
122
122
  /// Should the command fail if it was about to create a duplicate of an existing provisioning profile. It can happen due to issues on Apple Developer Portal, when profile to be recreated was not properly deleted first
123
123
  var failOnNameTaken: Bool { get }
124
124
 
125
+ /// Set to true if there is no access to Apple developer portal but there are certificates, keys and profiles provided. Only works with match import action
126
+ var skipCertificateMatching: Bool { get }
127
+
125
128
  /// Path in which to export certificates, key and profile
126
129
  var outputPath: String? { get }
127
130
 
@@ -173,6 +176,7 @@ public extension MatchfileProtocol {
173
176
  var templateName: String? { return nil }
174
177
  var profileName: String? { return nil }
175
178
  var failOnNameTaken: Bool { return false }
179
+ var skipCertificateMatching: Bool { return false }
176
180
  var outputPath: String? { return nil }
177
181
  var skipSetPartitionList: Bool { return false }
178
182
  var verbose: Bool { return false }
@@ -180,4 +184,4 @@ public extension MatchfileProtocol {
180
184
 
181
185
  // Please don't remove the lines below
182
186
  // They are used to detect outdated files
183
- // FastlaneRunnerAPIVersion [0.9.43]
187
+ // FastlaneRunnerAPIVersion [0.9.44]
@@ -17,4 +17,4 @@ public class Precheckfile: PrecheckfileProtocol {
17
17
  // during the `init` process, and you won't see this message
18
18
  }
19
19
 
20
- // Generated with fastlane 2.163.0
20
+ // Generated with fastlane 2.164.0
@@ -48,4 +48,4 @@ public extension PrecheckfileProtocol {
48
48
 
49
49
  // Please don't remove the lines below
50
50
  // They are used to detect outdated files
51
- // FastlaneRunnerAPIVersion [0.9.42]
51
+ // FastlaneRunnerAPIVersion [0.9.43]
@@ -17,4 +17,4 @@ public class Scanfile: ScanfileProtocol {
17
17
  // during the `init` process, and you won't see this message
18
18
  }
19
19
 
20
- // Generated with fastlane 2.163.0
20
+ // Generated with fastlane 2.164.0
@@ -260,4 +260,4 @@ public extension ScanfileProtocol {
260
260
 
261
261
  // Please don't remove the lines below
262
262
  // They are used to detect outdated files
263
- // FastlaneRunnerAPIVersion [0.9.54]
263
+ // FastlaneRunnerAPIVersion [0.9.55]
@@ -17,4 +17,4 @@ public class Screengrabfile: ScreengrabfileProtocol {
17
17
  // during the `init` process, and you won't see this message
18
18
  }
19
19
 
20
- // Generated with fastlane 2.163.0
20
+ // Generated with fastlane 2.164.0
@@ -96,4 +96,4 @@ public extension ScreengrabfileProtocol {
96
96
 
97
97
  // Please don't remove the lines below
98
98
  // They are used to detect outdated files
99
- // FastlaneRunnerAPIVersion [0.9.44]
99
+ // FastlaneRunnerAPIVersion [0.9.45]
@@ -17,4 +17,4 @@ public class Snapshotfile: SnapshotfileProtocol {
17
17
  // during the `init` process, and you won't see this message
18
18
  }
19
19
 
20
- // Generated with fastlane 2.163.0
20
+ // Generated with fastlane 2.164.0
@@ -184,4 +184,4 @@ public extension SnapshotfileProtocol {
184
184
 
185
185
  // Please don't remove the lines below
186
186
  // They are used to detect outdated files
187
- // FastlaneRunnerAPIVersion [0.9.38]
187
+ // FastlaneRunnerAPIVersion [0.9.39]
@@ -301,7 +301,7 @@ module FastlaneCore
301
301
  Helper.backticks("open -a #{simulator_path} --args -CurrentDeviceUDID #{device.udid}", print: FastlaneCore::Globals.verbose?)
302
302
  end
303
303
 
304
- def copy_logs(device, log_identity, logs_destination_dir)
304
+ def copy_logs(device, log_identity, logs_destination_dir, log_collection_start_time)
305
305
  logs_destination_dir = File.expand_path(logs_destination_dir)
306
306
  os_version = FastlaneCore::CommandExecutor.execute(command: 'sw_vers -productVersion', print_all: false, print_command: false)
307
307
 
@@ -310,7 +310,7 @@ module FastlaneCore
310
310
 
311
311
  are_logarchives_supported = device_supports_logarchives && host_computer_supports_logarchives
312
312
  if are_logarchives_supported
313
- copy_logarchive(device, log_identity, logs_destination_dir)
313
+ copy_logarchive(device, log_identity, logs_destination_dir, log_collection_start_time)
314
314
  else
315
315
  copy_logfile(device, log_identity, logs_destination_dir)
316
316
  end
@@ -340,13 +340,17 @@ module FastlaneCore
340
340
  UI.success("Copying file '#{logfile_src}' to '#{logfile_dst}'...")
341
341
  end
342
342
 
343
- def copy_logarchive(device, log_identity, logs_destination_dir)
343
+ def copy_logarchive(device, log_identity, logs_destination_dir, log_collection_start_time)
344
344
  require 'shellwords'
345
345
 
346
346
  logarchive_dst = File.join(logs_destination_dir, "system_logs-#{log_identity}.logarchive")
347
347
  FileUtils.rm_rf(logarchive_dst)
348
348
  FileUtils.mkdir_p(File.expand_path("..", logarchive_dst))
349
- command = "xcrun simctl spawn #{device.udid} log collect --output #{logarchive_dst.shellescape} 2>/dev/null"
349
+
350
+ logs_collection_start = log_collection_start_time.strftime('%Y-%m-%d %H:%M:%S')
351
+ command = "xcrun simctl spawn #{device.udid} log collect "
352
+ command << "--start '#{logs_collection_start}' "
353
+ command << "--output #{logarchive_dst.shellescape} 2>/dev/null"
350
354
  FastlaneCore::CommandExecutor.execute(command: command, print_all: false, print_command: true)
351
355
  end
352
356
  end
@@ -66,7 +66,7 @@ module FastlaneCore
66
66
 
67
67
  # @return true if it is enabled to execute external commands
68
68
  def self.sh_enabled?
69
- !self.test?
69
+ !self.test? || ENV["FORCE_SH_DURING_TESTS"]
70
70
  end
71
71
 
72
72
  # @return [boolean] true if building in a known CI environment
@@ -39,7 +39,7 @@ module FastlaneCore
39
39
  # See https://openradar.appspot.com/28524119
40
40
  if Helper.backticks('security -h | grep set-key-partition-list', print: false).length > 0
41
41
  command = "security set-key-partition-list"
42
- command << " -S apple-tool:,apple:"
42
+ command << " -S apple-tool:,apple:,codesign:"
43
43
  command << " -s" # This is a needed in Catalina to prevent "security: SecKeychainItemCopyAccess: A missing value was detected."
44
44
  command << " -k #{keychain_password.to_s.shellescape}"
45
45
  command << " #{keychain_path.shellescape}"
@@ -82,29 +82,41 @@ module Match
82
82
  output_dir_certs = File.join(storage.prefixed_working_directory, "certs", cert_type.to_s)
83
83
  output_dir_profiles = File.join(storage.prefixed_working_directory, "profiles", prov_type.to_s)
84
84
 
85
- # Need to get the cert id by comparing base64 encoded cert content with certificate content from the API responses
86
- token = api_token(params)
87
- if token
88
- UI.message("Creating authorization token for App Store Connect API")
89
- Spaceship::ConnectAPI.token = token
85
+ should_skip_certificate_matching = params[:skip_certificate_matching]
86
+ # In case there is no access to Apple Developer portal but we have the certificates, keys and profiles
87
+ if should_skip_certificate_matching
88
+ cert_name = File.basename(cert_path, ".*")
89
+ p12_name = File.basename(p12_path, ".*")
90
+
91
+ # Make dir if doesn't exist
92
+ FileUtils.mkdir_p(output_dir_certs)
93
+ dest_cert_path = File.join(output_dir_certs, "#{cert_name}.cer")
94
+ dest_p12_path = File.join(output_dir_certs, "#{p12_name}.p12")
90
95
  else
91
- UI.message("Login to App Store Connect (#{params[:username]})")
92
- Spaceship::ConnectAPI.login(params[:username], use_portal: true, use_tunes: false, portal_team_id: params[:team_id], team_name: params[:team_name])
96
+ # Need to get the cert id by comparing base64 encoded cert content with certificate content from the API responses
97
+ token = api_token(params)
98
+ if token
99
+ UI.message("Creating authorization token for App Store Connect API")
100
+ Spaceship::ConnectAPI.token = token
101
+ else
102
+ UI.message("Login to App Store Connect (#{params[:username]})")
103
+ Spaceship::ConnectAPI.login(params[:username], use_portal: true, use_tunes: false, portal_team_id: params[:team_id], team_name: params[:team_name])
104
+ end
105
+ certs = Spaceship::ConnectAPI::Certificate.all(filter: { certificateType: certificate_type })
106
+
107
+ # Base64 encode contents to find match from API to find a cert ID
108
+ cert_contents_base_64 = Base64.strict_encode64(File.binread(cert_path))
109
+ matching_cert = certs.find do |cert|
110
+ cert.certificate_content == cert_contents_base_64
111
+ end
112
+
113
+ UI.user_error!("This certificate cannot be imported - the certificate contents did not match with any available on the Developer Portal") if matching_cert.nil?
114
+
115
+ # Make dir if doesn't exist
116
+ FileUtils.mkdir_p(output_dir_certs)
117
+ dest_cert_path = File.join(output_dir_certs, "#{matching_cert.id}.cer")
118
+ dest_p12_path = File.join(output_dir_certs, "#{matching_cert.id}.p12")
93
119
  end
94
- certs = Spaceship::ConnectAPI::Certificate.all(filter: { certificateType: certificate_type })
95
-
96
- # Base64 encode contents to find match from API to find a cert ID
97
- cert_contents_base_64 = Base64.strict_encode64(File.binread(cert_path))
98
- matching_cert = certs.find do |cert|
99
- cert.certificate_content == cert_contents_base_64
100
- end
101
-
102
- UI.user_error!("This certificate cannot be imported - the certificate contents did not match with any available on the Developer Portal") if matching_cert.nil?
103
-
104
- # Make dir if doesn't exist
105
- FileUtils.mkdir_p(output_dir_certs)
106
- dest_cert_path = File.join(output_dir_certs, "#{matching_cert.id}.cer")
107
- dest_p12_path = File.join(output_dir_certs, "#{matching_cert.id}.p12")
108
120
 
109
121
  files_to_commit = [dest_cert_path, dest_p12_path]
110
122
 
@@ -283,6 +283,12 @@ module Match
283
283
  optional: true,
284
284
  type: Boolean,
285
285
  default_value: false),
286
+ FastlaneCore::ConfigItem.new(key: :skip_certificate_matching,
287
+ env_name: "MATCH_SKIP_CERTIFICATE_MATCHING",
288
+ description: "Set to true if there is no access to Apple developer portal but there are certificates, keys and profiles provided. Only works with match import action",
289
+ optional: true,
290
+ type: Boolean,
291
+ default_value: false),
286
292
  FastlaneCore::ConfigItem.new(key: :output_path,
287
293
  env_name: "MATCH_OUTPUT_PATH",
288
294
  description: "Path in which to export certificates, key and profile",
@@ -187,15 +187,12 @@ module Scan
187
187
  end
188
188
  end
189
189
 
190
+ # Convert array to lazy enumerable (evaluate map only when needed)
190
191
  # grab the first unempty evaluated array
191
- if default
192
- Scan.devices = [matches, default].lazy.map { |x|
193
- arr = x.call
194
- arr unless arr.empty?
195
- }.reject(&:nil?).first
196
- else
197
- Scan.devices = []
198
- end
192
+ Scan.devices = [matches, default].lazy.reject(&:nil?).map { |x|
193
+ arr = x.call
194
+ arr unless arr.empty?
195
+ }.reject(&:nil?).first
199
196
  end
200
197
 
201
198
  def self.min_xcode8?
@@ -16,6 +16,7 @@ module Scan
16
16
  class Runner
17
17
  def initialize
18
18
  @test_command_generator = TestCommandGenerator.new
19
+ @device_boot_datetime = DateTime.now
19
20
  end
20
21
 
21
22
  def run
@@ -184,7 +185,7 @@ module Scan
184
185
  UI.header("Collecting system logs")
185
186
  Scan.devices.each do |device|
186
187
  log_identity = "#{device.name}_#{device.os_type}_#{device.os_version}"
187
- FastlaneCore::Simulator.copy_logs(device, log_identity, Scan.config[:output_directory])
188
+ FastlaneCore::Simulator.copy_logs(device, log_identity, Scan.config[:output_directory], @device_boot_datetime)
188
189
  end
189
190
  end
190
191
 
@@ -535,7 +535,7 @@ function resign {
535
535
  fi
536
536
 
537
537
  # Check for and resign OnDemandResource folders
538
- ODR_DIR="$(dirname $APP_PATH)/OnDemandResources"
538
+ ODR_DIR="$(dirname "$APP_PATH")/OnDemandResources"
539
539
  if [ -d "$ODR_DIR" ]; then
540
540
  for assetpack in "$ODR_DIR"/*
541
541
  do
@@ -139,7 +139,7 @@ module Sigh
139
139
  # Skip certificates that failed to download
140
140
  next unless current_cert[:downloaded]
141
141
  file = Tempfile.new('cert')
142
- file.write(current_cert[:downloaded])
142
+ file.write(current_cert[:downloaded].force_encoding('UTF-8'))
143
143
  file.close
144
144
  if FastlaneCore::CertChecker.installed?(file.path)
145
145
  installed = true
@@ -315,7 +315,7 @@ module Sigh
315
315
  certificates = certificates.find_all do |c|
316
316
  file = Tempfile.new('cert')
317
317
  raw_data = Base64.decode64(c.certificate_content)
318
- file.write(raw_data)
318
+ file.write(raw_data.force_encoding("UTF-8"))
319
319
  file.close
320
320
 
321
321
  FastlaneCore::CertChecker.installed?(file.path)
@@ -18,6 +18,7 @@ module Snapshot
18
18
 
19
19
  def initialize(launcher_configuration: nil)
20
20
  @launcher_config = launcher_configuration
21
+ @device_boot_datetime = DateTime.now
21
22
  end
22
23
 
23
24
  def collected_errors
@@ -192,7 +193,7 @@ module Snapshot
192
193
 
193
194
  UI.header("Collecting system logs #{device_name} - #{language}")
194
195
  log_identity = Digest::MD5.hexdigest(components.join("-"))
195
- FastlaneCore::Simulator.copy_logs(device, log_identity, language_folder)
196
+ FastlaneCore::Simulator.copy_logs(device, log_identity, language_folder, @device_boot_datetime)
196
197
  end
197
198
  end
198
199
  end
@@ -111,7 +111,7 @@ module Supply
111
111
  releases = track.releases
112
112
 
113
113
  releases = releases.select { |r| r.status == status } if status
114
- releases = releases.select { |r| r.version_codes.map(&:to_s).include?(version_code.to_s) } if version_code
114
+ releases = releases.select { |r| (r.version_codes || []).map(&:to_s).include?(version_code.to_s) } if version_code
115
115
 
116
116
  if releases.size > 1
117
117
  UI.user_error!("More than one release found in this track. Please specify with the :version_code option to select a release.")
metadata CHANGED
@@ -1,35 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.163.0
4
+ version: 2.164.0
5
5
  platform: ruby
6
6
  authors:
7
- - Daniel Jankowski
8
- - Kohki Miki
9
7
  - Helmut Januschka
10
- - Danielle Tomlinson
8
+ - Luka Mirosevic
11
9
  - Fumiya Nakamura
12
- - Joshua Liebowitz
13
- - Jérôme Lacoste
14
- - Aaron Brager
15
- - Jorge Revuelta H
16
- - Iulian Onofrei
17
10
  - Jimmy Dee
11
+ - Maksym Grebenets
12
+ - Manu Wallner
13
+ - Danielle Tomlinson
18
14
  - Jan Piotrowski
19
- - Luka Mirosevic
20
- - Felix Krause
21
15
  - Max Ott
22
- - Stefan Natchev
23
- - Manu Wallner
16
+ - Iulian Onofrei
17
+ - Jérôme Lacoste
24
18
  - Matthew Ellis
19
+ - Olivier Halligon
25
20
  - Josh Holtz
26
- - Maksym Grebenets
21
+ - Jorge Revuelta H
22
+ - Aaron Brager
23
+ - Felix Krause
24
+ - Joshua Liebowitz
25
+ - Kohki Miki
26
+ - Stefan Natchev
27
+ - Daniel Jankowski
27
28
  - Andrew McBurney
28
- - Olivier Halligon
29
29
  autorequire:
30
30
  bindir: bin
31
31
  cert_chain: []
32
- date: 2020-10-12 00:00:00.000000000 Z
32
+ date: 2020-10-19 00:00:00.000000000 Z
33
33
  dependencies:
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: slack-notifier
@@ -984,8 +984,6 @@ files:
984
984
  - fastlane/lib/fastlane/action.rb
985
985
  - fastlane/lib/fastlane/action_collector.rb
986
986
  - fastlane/lib/fastlane/actions/.git_commit.rb.swp
987
- - fastlane/lib/fastlane/actions/.register_device.rb.swp
988
- - fastlane/lib/fastlane/actions/.register_devices.rb.swp
989
987
  - fastlane/lib/fastlane/actions/README.md
990
988
  - fastlane/lib/fastlane/actions/actions_helper.rb
991
989
  - fastlane/lib/fastlane/actions/adb.rb
@@ -1455,6 +1453,9 @@ files:
1455
1453
  - match/lib/assets/MatchfileTemplate.swift
1456
1454
  - match/lib/assets/READMETemplate.md
1457
1455
  - match/lib/match.rb
1456
+ - match/lib/match/.commands_generator.rb.swp
1457
+ - match/lib/match/.importer.rb.swp
1458
+ - match/lib/match/.options.rb.swp
1458
1459
  - match/lib/match/change_password.rb
1459
1460
  - match/lib/match/commands_generator.rb
1460
1461
  - match/lib/match/encryption.rb