fastlane 2.168.0 → 2.169.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +84 -84
  3. data/cert/lib/cert/.options.rb.swp +0 -0
  4. data/cert/lib/cert/.runner.rb.swp +0 -0
  5. data/cert/lib/cert/options.rb +2 -2
  6. data/deliver/lib/deliver/loader.rb +136 -18
  7. data/deliver/lib/deliver/upload_metadata.rb +4 -10
  8. data/deliver/lib/deliver/upload_screenshots.rb +1 -64
  9. data/fastlane/lib/fastlane/actions/docs/frame_screenshots.md +1 -1
  10. data/fastlane/lib/fastlane/actions/xcode_install.rb +8 -5
  11. data/fastlane/lib/fastlane/version.rb +1 -1
  12. data/fastlane/swift/Deliverfile.swift +1 -1
  13. data/fastlane/swift/DeliverfileProtocol.swift +1 -1
  14. data/fastlane/swift/Fastlane.swift +35 -14
  15. data/fastlane/swift/Gymfile.swift +1 -1
  16. data/fastlane/swift/GymfileProtocol.swift +5 -1
  17. data/fastlane/swift/Matchfile.swift +1 -1
  18. data/fastlane/swift/MatchfileProtocol.swift +1 -1
  19. data/fastlane/swift/Precheckfile.swift +1 -1
  20. data/fastlane/swift/PrecheckfileProtocol.swift +1 -1
  21. data/fastlane/swift/Scanfile.swift +1 -1
  22. data/fastlane/swift/ScanfileProtocol.swift +5 -1
  23. data/fastlane/swift/Screengrabfile.swift +1 -1
  24. data/fastlane/swift/ScreengrabfileProtocol.swift +1 -1
  25. data/fastlane/swift/Snapshotfile.swift +1 -1
  26. data/fastlane/swift/SnapshotfileProtocol.swift +1 -1
  27. data/gym/lib/gym/generators/build_command_generator.rb +1 -0
  28. data/gym/lib/gym/options.rb +7 -1
  29. data/{spaceship/lib/spaceship/connect_api/models/.app_screenshot.rb.swp → match/lib/match/.options.rb.swp} +0 -0
  30. data/scan/lib/scan/options.rb +7 -1
  31. data/scan/lib/scan/test_command_generator.rb +1 -0
  32. data/{spaceship/lib/spaceship/connect_api/models/.build.rb.swp → sigh/lib/sigh/.options.rb.swp} +0 -0
  33. data/snapshot/lib/assets/SnapshotHelper.swift +5 -1
  34. data/spaceship/lib/spaceship/client.rb +14 -0
  35. data/spaceship/lib/spaceship/connect_api/models/app.rb +13 -4
  36. data/spaceship/lib/spaceship/connect_api/models/app_info.rb +1 -0
  37. data/spaceship/lib/spaceship/connect_api/models/app_info_localization.rb +2 -0
  38. data/spaceship/lib/spaceship/connect_api/models/app_store_version.rb +1 -0
  39. data/spaceship/lib/spaceship/errors.rb +19 -0
  40. data/spaceship/lib/spaceship/two_step_or_factor_client.rb +18 -6
  41. metadata +22 -21
  42. data/spaceship/lib/spaceship/connect_api/models/.app.rb.swp +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 163e53283c2657d2e37607fefd6985e72a01946a0448bd5f07c11f399462b81c
4
- data.tar.gz: 3ad91b60198920341ca9725b227439a340ab997883fc40ecc5964b449502912a
3
+ metadata.gz: 89942043b1528ca3c3eff8b253e5c13a8fe910178b1670a553197f27260bb7d5
4
+ data.tar.gz: 476dffe7ef2b50121441191673e20041e4c91cdb8eecc5e1928a9f02930538b0
5
5
  SHA512:
6
- metadata.gz: 036c78bc28cf70e5a92682e54cd1c4ce22a99e5b8a6fef788b78e898200fe829927dbaa31b120bcfc6abe1504e235854fc94ee3415c854e845d7c68a7e250309
7
- data.tar.gz: 4f63a769059f91d26cf332c77c1eadceba29d0702d1222a41c6ccddfd2bcba91a8c53cbf83b0a04144d15c655361c93bd89f5f7769473549c1a5c86c1def4877
6
+ metadata.gz: 26f4595813c6d3bdea582beabb32f4824b170dc660cf576d01aa1e6c696781e7538c6740bf09246f492ed06ac05a15db5eb0de88e21ccc07ed00e24b373c9380
7
+ data.tar.gz: e711d070232cecbcb7749c47c0fa6ac72e19b137753856c39de6739a55fd6159d4943575f784eb06070e12ba2d02ba5aea478481b48be8b9561a360e0756fa27
data/README.md CHANGED
@@ -34,29 +34,29 @@ 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='kohki-miki'>
38
- <a href='https://github.com/giginet'>
39
- <img src='https://github.com/giginet.png?size=140'>
37
+ <td id='josh-holtz'>
38
+ <a href='https://github.com/joshdholtz'>
39
+ <img src='https://github.com/joshdholtz.png?size=140'>
40
40
  </a>
41
- <h4 align='center'><a href='https://twitter.com/giginet'>Kohki Miki</a></h4>
41
+ <h4 align='center'><a href='https://twitter.com/joshdholtz'>Josh Holtz</a></h4>
42
42
  </td>
43
- <td id='jérôme-lacoste'>
44
- <a href='https://github.com/lacostej'>
45
- <img src='https://github.com/lacostej.png?size=140'>
43
+ <td id='maksym-grebenets'>
44
+ <a href='https://github.com/mgrebenets'>
45
+ <img src='https://github.com/mgrebenets.png?size=140'>
46
46
  </a>
47
- <h4 align='center'><a href='https://twitter.com/lacostej'>Jérôme Lacoste</a></h4>
47
+ <h4 align='center'><a href='https://twitter.com/mgrebenets'>Maksym Grebenets</a></h4>
48
48
  </td>
49
- <td id='manu-wallner'>
50
- <a href='https://github.com/milch'>
51
- <img src='https://github.com/milch.png?size=140'>
49
+ <td id='matthew-ellis'>
50
+ <a href='https://github.com/matthewellis'>
51
+ <img src='https://github.com/matthewellis.png?size=140'>
52
52
  </a>
53
- <h4 align='center'><a href='https://twitter.com/acrooow'>Manu Wallner</a></h4>
53
+ <h4 align='center'><a href='https://twitter.com/mellis1995'>Matthew Ellis</a></h4>
54
54
  </td>
55
- <td id='jimmy-dee'>
56
- <a href='https://github.com/jdee'>
57
- <img src='https://github.com/jdee.png?size=140'>
55
+ <td id='aaron-brager'>
56
+ <a href='https://github.com/getaaron'>
57
+ <img src='https://github.com/getaaron.png?size=140'>
58
58
  </a>
59
- <h4 align='center'>Jimmy Dee</h4>
59
+ <h4 align='center'><a href='https://twitter.com/getaaron'>Aaron Brager</a></h4>
60
60
  </td>
61
61
  <td id='jorge-revuelta-h'>
62
62
  <a href='https://github.com/minuscorp'>
@@ -66,107 +66,81 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
66
66
  </td>
67
67
  </tr>
68
68
  <tr>
69
- <td id='aaron-brager'>
70
- <a href='https://github.com/getaaron'>
71
- <img src='https://github.com/getaaron.png?size=140'>
72
- </a>
73
- <h4 align='center'><a href='https://twitter.com/getaaron'>Aaron Brager</a></h4>
74
- </td>
75
- <td id='daniel-jankowski'>
76
- <a href='https://github.com/mollyIV'>
77
- <img src='https://github.com/mollyIV.png?size=140'>
78
- </a>
79
- <h4 align='center'><a href='https://twitter.com/mollyIV'>Daniel Jankowski</a></h4>
80
- </td>
81
- <td id='joshua-liebowitz'>
82
- <a href='https://github.com/taquitos'>
83
- <img src='https://github.com/taquitos.png?size=140'>
69
+ <td id='jan-piotrowski'>
70
+ <a href='https://github.com/janpio'>
71
+ <img src='https://github.com/janpio.png?size=140'>
84
72
  </a>
85
- <h4 align='center'><a href='https://twitter.com/taquitos'>Joshua Liebowitz</a></h4>
73
+ <h4 align='center'><a href='https://twitter.com/Sujan'>Jan Piotrowski</a></h4>
86
74
  </td>
87
- <td id='luka-mirosevic'>
88
- <a href='https://github.com/lmirosevic'>
89
- <img src='https://github.com/lmirosevic.png?size=140'>
75
+ <td id='kohki-miki'>
76
+ <a href='https://github.com/giginet'>
77
+ <img src='https://github.com/giginet.png?size=140'>
90
78
  </a>
91
- <h4 align='center'><a href='https://twitter.com/lmirosevic'>Luka Mirosevic</a></h4>
79
+ <h4 align='center'><a href='https://twitter.com/giginet'>Kohki Miki</a></h4>
92
80
  </td>
93
- <td id='matthew-ellis'>
94
- <a href='https://github.com/matthewellis'>
95
- <img src='https://github.com/matthewellis.png?size=140'>
81
+ <td id='max-ott'>
82
+ <a href='https://github.com/max-ott'>
83
+ <img src='https://github.com/max-ott.png?size=140'>
96
84
  </a>
97
- <h4 align='center'><a href='https://twitter.com/mellis1995'>Matthew Ellis</a></h4>
85
+ <h4 align='center'><a href='https://twitter.com/ott_max'>Max Ott</a></h4>
98
86
  </td>
99
- </tr>
100
- <tr>
101
87
  <td id='iulian-onofrei'>
102
88
  <a href='https://github.com/revolter'>
103
89
  <img src='https://github.com/revolter.png?size=140'>
104
90
  </a>
105
91
  <h4 align='center'><a href='https://twitter.com/Revolt666'>Iulian Onofrei</a></h4>
106
92
  </td>
107
- <td id='danielle-tomlinson'>
108
- <a href='https://github.com/endocrimes'>
109
- <img src='https://github.com/endocrimes.png?size=140'>
110
- </a>
111
- <h4 align='center'><a href='https://twitter.com/endocrimes'>Danielle Tomlinson</a></h4>
112
- </td>
113
- <td id='andrew-mcburney'>
114
- <a href='https://github.com/armcburney'>
115
- <img src='https://github.com/armcburney.png?size=140'>
116
- </a>
117
- <h4 align='center'><a href='https://twitter.com/armcburney'>Andrew McBurney</a></h4>
118
- </td>
119
- <td id='max-ott'>
120
- <a href='https://github.com/max-ott'>
121
- <img src='https://github.com/max-ott.png?size=140'>
122
- </a>
123
- <h4 align='center'><a href='https://twitter.com/ott_max'>Max Ott</a></h4>
124
- </td>
125
- <td id='jan-piotrowski'>
126
- <a href='https://github.com/janpio'>
127
- <img src='https://github.com/janpio.png?size=140'>
93
+ <td id='fumiya-nakamura'>
94
+ <a href='https://github.com/nafu'>
95
+ <img src='https://github.com/nafu.png?size=140'>
128
96
  </a>
129
- <h4 align='center'><a href='https://twitter.com/Sujan'>Jan Piotrowski</a></h4>
97
+ <h4 align='center'><a href='https://twitter.com/nafu003'>Fumiya Nakamura</a></h4>
130
98
  </td>
131
99
  </tr>
132
100
  <tr>
133
- <td id='olivier-halligon'>
134
- <a href='https://github.com/AliSoftware'>
135
- <img src='https://github.com/AliSoftware.png?size=140'>
136
- </a>
137
- <h4 align='center'><a href='https://twitter.com/aligatr'>Olivier Halligon</a></h4>
138
- </td>
139
101
  <td id='felix-krause'>
140
102
  <a href='https://github.com/KrauseFx'>
141
103
  <img src='https://github.com/KrauseFx.png?size=140'>
142
104
  </a>
143
105
  <h4 align='center'><a href='https://twitter.com/KrauseFx'>Felix Krause</a></h4>
144
106
  </td>
107
+ <td id='daniel-jankowski'>
108
+ <a href='https://github.com/mollyIV'>
109
+ <img src='https://github.com/mollyIV.png?size=140'>
110
+ </a>
111
+ <h4 align='center'><a href='https://twitter.com/mollyIV'>Daniel Jankowski</a></h4>
112
+ </td>
113
+ <td id='manu-wallner'>
114
+ <a href='https://github.com/milch'>
115
+ <img src='https://github.com/milch.png?size=140'>
116
+ </a>
117
+ <h4 align='center'><a href='https://twitter.com/acrooow'>Manu Wallner</a></h4>
118
+ </td>
145
119
  <td id='helmut-januschka'>
146
120
  <a href='https://github.com/hjanuschka'>
147
121
  <img src='https://github.com/hjanuschka.png?size=140'>
148
122
  </a>
149
123
  <h4 align='center'><a href='https://twitter.com/hjanuschka'>Helmut Januschka</a></h4>
150
124
  </td>
151
- <td id='maksym-grebenets'>
152
- <a href='https://github.com/mgrebenets'>
153
- <img src='https://github.com/mgrebenets.png?size=140'>
154
- </a>
155
- <h4 align='center'><a href='https://twitter.com/mgrebenets'>Maksym Grebenets</a></h4>
156
- </td>
157
- <td id='josh-holtz'>
158
- <a href='https://github.com/joshdholtz'>
159
- <img src='https://github.com/joshdholtz.png?size=140'>
125
+ <td id='danielle-tomlinson'>
126
+ <a href='https://github.com/endocrimes'>
127
+ <img src='https://github.com/endocrimes.png?size=140'>
160
128
  </a>
161
- <h4 align='center'><a href='https://twitter.com/joshdholtz'>Josh Holtz</a></h4>
129
+ <h4 align='center'><a href='https://twitter.com/endocrimes'>Danielle Tomlinson</a></h4>
162
130
  </td>
163
131
  </tr>
164
132
  <tr>
165
- <td id='fumiya-nakamura'>
166
- <a href='https://github.com/nafu'>
167
- <img src='https://github.com/nafu.png?size=140'>
133
+ <td id='andrew-mcburney'>
134
+ <a href='https://github.com/armcburney'>
135
+ <img src='https://github.com/armcburney.png?size=140'>
168
136
  </a>
169
- <h4 align='center'><a href='https://twitter.com/nafu003'>Fumiya Nakamura</a></h4>
137
+ <h4 align='center'><a href='https://twitter.com/armcburney'>Andrew McBurney</a></h4>
138
+ </td>
139
+ <td id='jérôme-lacoste'>
140
+ <a href='https://github.com/lacostej'>
141
+ <img src='https://github.com/lacostej.png?size=140'>
142
+ </a>
143
+ <h4 align='center'><a href='https://twitter.com/lacostej'>Jérôme Lacoste</a></h4>
170
144
  </td>
171
145
  <td id='stefan-natchev'>
172
146
  <a href='https://github.com/snatchev'>
@@ -174,6 +148,32 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
174
148
  </a>
175
149
  <h4 align='center'><a href='https://twitter.com/snatchev'>Stefan Natchev</a></h4>
176
150
  </td>
151
+ <td id='joshua-liebowitz'>
152
+ <a href='https://github.com/taquitos'>
153
+ <img src='https://github.com/taquitos.png?size=140'>
154
+ </a>
155
+ <h4 align='center'><a href='https://twitter.com/taquitos'>Joshua Liebowitz</a></h4>
156
+ </td>
157
+ <td id='jimmy-dee'>
158
+ <a href='https://github.com/jdee'>
159
+ <img src='https://github.com/jdee.png?size=140'>
160
+ </a>
161
+ <h4 align='center'>Jimmy Dee</h4>
162
+ </td>
163
+ </tr>
164
+ <tr>
165
+ <td id='olivier-halligon'>
166
+ <a href='https://github.com/AliSoftware'>
167
+ <img src='https://github.com/AliSoftware.png?size=140'>
168
+ </a>
169
+ <h4 align='center'><a href='https://twitter.com/aligatr'>Olivier Halligon</a></h4>
170
+ </td>
171
+ <td id='luka-mirosevic'>
172
+ <a href='https://github.com/lmirosevic'>
173
+ <img src='https://github.com/lmirosevic.png?size=140'>
174
+ </a>
175
+ <h4 align='center'><a href='https://twitter.com/lmirosevic'>Luka Mirosevic</a></h4>
176
+ </td>
177
177
  </table>
178
178
 
179
179
  Special thanks to all [contributors](https://github.com/fastlane/fastlane/graphs/contributors) for extending and improving _fastlane_.
@@ -119,11 +119,11 @@ module Cert
119
119
  default_value: false),
120
120
  FastlaneCore::ConfigItem.new(key: :platform,
121
121
  env_name: "CERT_PLATFORM",
122
- description: "Set the provisioning profile's platform (ios, macos)",
122
+ description: "Set the provisioning profile's platform (ios, macos, tvos)",
123
123
  default_value: "ios",
124
124
  verify_block: proc do |value|
125
125
  value = value.to_s
126
- pt = %w(macos ios)
126
+ pt = %w(macos ios tvos)
127
127
  UI.user_error!("Unsupported platform, must be: #{pt}") unless pt.include?(value)
128
128
  end)
129
129
  ]
@@ -2,6 +2,7 @@ require 'fastlane_core/languages'
2
2
  require 'spaceship/tunes/tunes'
3
3
 
4
4
  require_relative 'module'
5
+ require_relative 'app_screenshot'
5
6
  require_relative 'upload_metadata'
6
7
  require_relative 'languages'
7
8
 
@@ -13,6 +14,7 @@ module Deliver
13
14
  IMESSAGE_DIR_NAME = "iMessage".freeze
14
15
  DEFAULT_DIR_NAME = "default".freeze
15
16
 
17
+ EXPANDABLE_DIR_NAMES = [APPLE_TV_DIR_NAME, IMESSAGE_DIR_NAME].freeze
16
18
  SPECIAL_DIR_NAMES = [APPLE_TV_DIR_NAME, IMESSAGE_DIR_NAME, DEFAULT_DIR_NAME].freeze
17
19
 
18
20
  # Some exception directories may exist from other actions that should not be iterated through
@@ -20,35 +22,151 @@ module Deliver
20
22
  FRAMEIT_FONTS_DIR_NAME = "fonts".freeze
21
23
  META_DIR_NAMES = UploadMetadata::ALL_META_SUB_DIRS.map(&:downcase)
22
24
 
23
- EXCEPTION_DIRECTORIES = (META_DIR_NAMES << SUPPLY_DIR_NAME << FRAMEIT_FONTS_DIR_NAME).freeze
25
+ EXCEPTION_DIRECTORIES = (META_DIR_NAMES << SUPPLY_DIR_NAME << FRAMEIT_FONTS_DIR_NAME).freeze
24
26
 
25
- def self.language_folders(root, ignore_validation)
26
- folders = Dir.glob(File.join(root, '*'))
27
+ # A class that represents language folder under screenshots or metadata folder
28
+ class LanguageFolder
29
+ attr_reader :path
30
+
31
+ # @return [String] A normalized language name that corresponds to the directory's name
32
+ attr_reader :language
33
+
34
+ def self.available_languages
35
+ # 2020-08-24 - Available locales are not available as an endpoint in App Store Connect
36
+ # Update with Spaceship::Tunes.client.available_languages.sort (as long as endpoint is avilable)
37
+ Deliver::Languages::ALL_LANGUAGES
38
+ end
39
+
40
+ def self.allowed_directory_names_with_case
41
+ available_languages + SPECIAL_DIR_NAMES
42
+ end
43
+
44
+ # @param path [String] A directory path otherwise this initializer fails
45
+ # @param nested [Boolan] Whether given path is nested of another special directory.
46
+ # This affects `expandable?` to return `false` when this set to `true`.
47
+ def initialize(path, nested: false)
48
+ raise(ArgumentError, "Given path must be a directory path - #{path}") unless File.directory?(path)
49
+ @path = path
50
+ @language = self.class.available_languages.find { |lang| basename.casecmp?(lang) }
51
+ @nested = nested
52
+ end
53
+
54
+ def nested?
55
+ @nested
56
+ end
57
+
58
+ def valid?
59
+ self.class.allowed_directory_names_with_case.any? { |name| name.casecmp?(basename) }
60
+ end
61
+
62
+ def expandable?
63
+ !nested? && EXPANDABLE_DIR_NAMES.any? { |name| name.casecmp?(basename) }
64
+ end
65
+
66
+ def skip?
67
+ EXCEPTION_DIRECTORIES.map(&:downcase).include?(basename.downcase)
68
+ end
69
+
70
+ def file_paths(extensions = '{png,jpg,jpeg}')
71
+ Dir.glob(File.join(path, "*.#{extensions}"), File::FNM_CASEFOLD).sort
72
+ end
27
73
 
28
- # 2020-08-24 - Available locales are not available as an endpoint in App Store Connect
29
- # Update with Spaceship::Tunes.client.available_languages.sort (as long as endpoint is avilable)
30
- available_languages = Deliver::Languages::ALL_LANGUAGES
74
+ def framed_file_paths(extensions = '{png,jpg,jpeg}')
75
+ Dir.glob(File.join(path, "*_framed.#{extensions}"), File::FNM_CASEFOLD).sort
76
+ end
77
+
78
+ def basename
79
+ File.basename(@path)
80
+ end
81
+ end
82
+
83
+ # Returns the list of valid app screenshot
84
+ #
85
+ # @param root [String] A directory path
86
+ # @param ignore_validation [String] Set false not to raise the error when finding invalid folder name
87
+ # @return [Array<AppScreenshot>] The list of AppScreenshot that exist under given `root` directory
88
+ def self.load_app_screenshots(root, ignore_validation)
89
+ screenshots = language_folders(root, ignore_validation, true).flat_map do |language_folder|
90
+ paths = if language_folder.framed_file_paths.count > 0
91
+ UI.important("Framed screenshots are detected! 🖼 Non-framed screenshot files may be skipped. 🏃")
92
+ # watchOS screenshots can be picked up even when framed ones were found since frameit doesn't support watchOS screenshots
93
+ framed_or_watch, skipped = language_folder.file_paths.partition { |path| path.downcase.include?('framed') || path.downcase.include?('watch') }
94
+ skipped.each { |path| UI.important("🏃 Skipping screenshot file: #{path}") }
95
+ framed_or_watch
96
+ else
97
+ language_folder.file_paths
98
+ end
99
+ paths.map { |path| AppScreenshot.new(path, language_folder.language) }
100
+ end
101
+
102
+ errors = []
103
+ valid_screenshots = screenshots.select { |screenshot| validate_screenshot(screenshot, errors) }
104
+
105
+ unless errors.empty?
106
+ UI.important("Unaccepted device screenshots are detected! 🚫 Screenshot file will be skipped. 🏃")
107
+ errors.each { |error| UI.important(error) }
108
+ end
31
109
 
32
- allowed_directory_names_with_case = (available_languages + SPECIAL_DIR_NAMES)
33
- allowed_directory_names = allowed_directory_names_with_case.map(&:downcase).freeze
110
+ valid_screenshots
111
+ end
34
112
 
35
- selected_folders = folders.select do |path|
36
- File.directory?(path) && allowed_directory_names.include?(File.basename(path).downcase)
37
- end.sort
113
+ # Validate a screenshot and inform an error message via `errors` parameters. `errors` is mutated
114
+ # to append the messages and each message should contain the corresponding path to let users know which file gets the error.
115
+ #
116
+ # @param screenshot [AppScreenshot]
117
+ # @param errors [Array<String>] Pass an array object to add error messages when finding an error
118
+ # @return [Boolean] true if given screenshot is valid
119
+ def self.validate_screenshot(screenshot, errors)
120
+ # Given screenshot will be diagnosed and errors found are accumulated
121
+ errors_found = []
38
122
 
39
- # Gets list of folders that are not supported languages
40
- rejected_folders = folders.select do |path|
41
- normalized_path = File.basename(path).downcase
42
- File.directory?(path) && !allowed_directory_names.include?(normalized_path) && !EXCEPTION_DIRECTORIES.include?(normalized_path)
43
- end.sort
123
+ # Checking if the device type exists in spaceship
124
+ # Ex: iPhone 6.1 inch isn't supported in App Store Connect but need
125
+ # to have it in there for frameit support
126
+ if screenshot.device_type.nil?
127
+ errors_found << "🏃 Skipping screenshot file: #{screenshot.path} - Not an accepted App Store Connect device..."
128
+ end
129
+
130
+ # Merge errors found into given errors array
131
+ errors_found.each { |error| errors.push(error) }
132
+ errors_found.empty?
133
+ end
134
+
135
+ # Returns the list of language folders
136
+ #
137
+ # @param roort [String] A directory path to get the list of language folders
138
+ # @param ignore_validation [Boolean] Set false not to raise the error when finding invalid folder name
139
+ # @param expand_sub_folders [Boolean] Set true to expand special folders; such as "iMessage" to nested language folders
140
+ # @return [Array<LanguageFolder>] The list of LanguageFolder whose each of them
141
+ def self.language_folders(root, ignore_validation, expand_sub_folders = false)
142
+ folders = Dir.glob(File.join(root, '*'))
143
+ .select { |path| File.directory?(path) }
144
+ .map { |path| LanguageFolder.new(path, nested: false) }
145
+ .reject(&:skip?)
146
+
147
+ selected_folders, rejected_folders = folders.partition(&:valid?)
44
148
 
45
149
  if !ignore_validation && !rejected_folders.empty?
46
- rejected_folders = rejected_folders.map { |path| File.basename(path) }
150
+ rejected_folders = rejected_folders.map(&:basename)
47
151
  UI.user_error!("Unsupported directory name(s) for screenshots/metadata in '#{root}': #{rejected_folders.join(', ')}" \
48
- "\nValid directory names are: #{allowed_directory_names_with_case}" \
152
+ "\nValid directory names are: #{LanguageFolder.allowed_directory_names_with_case}" \
49
153
  "\n\nEnable 'ignore_language_directory_validation' to prevent this validation from happening")
50
154
  end
51
155
 
156
+ # Expand selected_folders for the special directories
157
+ if expand_sub_folders
158
+ selected_folders = selected_folders.flat_map do |folder|
159
+ if folder.expandable?
160
+ Dir.glob(File.join(folder.path, '*'))
161
+ .select { |p| File.directory?(p) }
162
+ .map { |p| LanguageFolder.new(p, nested: true) }
163
+ .select(&:valid?)
164
+ else
165
+ folder
166
+ end
167
+ end
168
+ end
169
+
52
170
  selected_folders
53
171
  end
54
172
  end
@@ -375,9 +375,7 @@ module Deliver
375
375
  # Check folder list (an empty folder signifies a language is required)
376
376
  ignore_validation = options[:ignore_language_directory_validation]
377
377
  Loader.language_folders(options[:metadata_path], ignore_validation).each do |lang_folder|
378
- next unless File.directory?(lang_folder) # We don't want to read txt as they are non localised
379
- language = File.basename(lang_folder)
380
- enabled_languages << language unless enabled_languages.include?(language)
378
+ enabled_languages << lang_folder.language unless enabled_languages.include?(lang_folder.language)
381
379
  end
382
380
 
383
381
  return unless enabled_languages.include?("default")
@@ -416,10 +414,7 @@ module Deliver
416
414
  # Check folder list (an empty folder signifies a language is required)
417
415
  ignore_validation = options[:ignore_language_directory_validation]
418
416
  Loader.language_folders(options[:metadata_path], ignore_validation).each do |lang_folder|
419
- next unless File.directory?(lang_folder) # We don't want to read txt as they are non localised
420
-
421
- language = File.basename(lang_folder)
422
- enabled_languages << language unless enabled_languages.include?(language)
417
+ enabled_languages << lang_folder.language unless enabled_languages.include?(lang_folder.language)
423
418
  end
424
419
 
425
420
  # Mapping to strings because :default symbol can be passed in
@@ -530,14 +525,13 @@ module Deliver
530
525
  # Load localised data
531
526
  ignore_validation = options[:ignore_language_directory_validation]
532
527
  Loader.language_folders(options[:metadata_path], ignore_validation).each do |lang_folder|
533
- language = File.basename(lang_folder)
534
528
  (LOCALISED_VERSION_VALUES.keys + LOCALISED_APP_VALUES.keys).each do |key|
535
- path = File.join(lang_folder, "#{key}.txt")
529
+ path = File.join(lang_folder.path, "#{key}.txt")
536
530
  next unless File.exist?(path)
537
531
 
538
532
  UI.message("Loading '#{path}'...")
539
533
  options[key] ||= {}
540
- options[key][language] ||= File.read(path)
534
+ options[key][lang_folder.language] ||= File.read(path)
541
535
  end
542
536
  end
543
537