fastlane 2.163.0 → 2.164.0

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