fastlane 2.168.0 → 2.173.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.
- checksums.yaml +4 -4
- data/README.md +68 -68
- data/cert/lib/cert/options.rb +2 -2
- data/deliver/lib/deliver/app_screenshot.rb +5 -7
- data/deliver/lib/deliver/app_screenshot_validator.rb +108 -0
- data/deliver/lib/deliver/commands_generator.rb +1 -1
- data/deliver/lib/deliver/loader.rb +123 -21
- data/deliver/lib/deliver/setup.rb +8 -3
- data/deliver/lib/deliver/upload_metadata.rb +6 -10
- data/deliver/lib/deliver/upload_screenshots.rb +1 -64
- data/fastlane/lib/fastlane/actions/add_git_tag.rb +12 -3
- data/fastlane/lib/fastlane/actions/artifactory.rb +36 -3
- data/fastlane/lib/fastlane/actions/build_app.rb +3 -1
- data/fastlane/lib/fastlane/actions/create_pull_request.rb +16 -1
- data/fastlane/lib/fastlane/actions/create_xcframework.rb +118 -0
- data/fastlane/lib/fastlane/actions/docs/frame_screenshots.md +1 -1
- data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +1 -1
- data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +4 -0
- data/fastlane/lib/fastlane/actions/docs/upload_to_testflight.md +5 -1
- data/fastlane/lib/fastlane/actions/download_app_privacy_details_from_app_store.rb +142 -0
- data/fastlane/lib/fastlane/actions/download_dsyms.rb +0 -1
- data/fastlane/lib/fastlane/actions/git_commit.rb +6 -2
- data/fastlane/lib/fastlane/actions/github_api.rb +14 -3
- data/fastlane/lib/fastlane/actions/nexus_upload.rb +1 -0
- data/fastlane/lib/fastlane/actions/onesignal.rb +13 -3
- data/fastlane/lib/fastlane/actions/pod_push.rb +9 -0
- data/fastlane/lib/fastlane/actions/push_to_git_remote.rb +9 -1
- data/fastlane/lib/fastlane/actions/register_device.rb +1 -1
- data/fastlane/lib/fastlane/actions/register_devices.rb +2 -1
- data/fastlane/lib/fastlane/actions/set_github_release.rb +21 -8
- data/fastlane/lib/fastlane/actions/slack.rb +4 -5
- data/fastlane/lib/fastlane/actions/spm.rb +2 -2
- data/fastlane/lib/fastlane/actions/swiftlint.rb +4 -4
- data/fastlane/lib/fastlane/actions/upload_app_privacy_details_to_app_store.rb +291 -0
- data/fastlane/lib/fastlane/actions/xcode_install.rb +8 -5
- data/fastlane/lib/fastlane/cli_tools_distributor.rb +3 -0
- data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +1 -1
- data/fastlane/lib/fastlane/swift_fastlane_api_generator.rb +3 -0
- data/fastlane/lib/fastlane/version.rb +1 -1
- data/fastlane/swift/Deliverfile.swift +2 -2
- data/fastlane/swift/DeliverfileProtocol.swift +2 -2
- data/fastlane/swift/Fastlane.swift +267 -45
- data/fastlane/swift/Gymfile.swift +2 -2
- data/fastlane/swift/GymfileProtocol.swift +15 -3
- data/fastlane/swift/Matchfile.swift +2 -2
- data/fastlane/swift/MatchfileProtocol.swift +2 -2
- data/fastlane/swift/Precheckfile.swift +2 -2
- data/fastlane/swift/PrecheckfileProtocol.swift +6 -2
- data/fastlane/swift/Scanfile.swift +2 -2
- data/fastlane/swift/ScanfileProtocol.swift +18 -2
- data/fastlane/swift/Screengrabfile.swift +2 -2
- data/fastlane/swift/ScreengrabfileProtocol.swift +2 -2
- data/fastlane/swift/Snapshotfile.swift +2 -2
- data/fastlane/swift/SnapshotfileProtocol.swift +15 -3
- data/fastlane_core/lib/fastlane_core/helper.rb +2 -2
- data/fastlane_core/lib/fastlane_core/ipa_file_analyser.rb +41 -16
- data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +3 -4
- data/fastlane_core/lib/fastlane_core/project.rb +19 -6
- data/frameit/lib/frameit/device_types.rb +7 -1
- data/gym/lib/gym/error_handler.rb +8 -0
- data/gym/lib/gym/generators/build_command_generator.rb +3 -0
- data/gym/lib/gym/generators/package_command_generator_xcode7.rb +2 -2
- data/gym/lib/gym/options.rb +19 -3
- data/match/lib/match/encryption/openssl.rb +4 -2
- data/match/lib/match/runner.rb +1 -1
- data/match/lib/match/storage/git_storage.rb +14 -10
- data/precheck/lib/precheck/options.rb +6 -1
- data/precheck/lib/precheck/rule_processor.rb +1 -1
- data/precheck/lib/precheck/runner.rb +1 -1
- data/scan/lib/scan/options.rb +22 -1
- data/scan/lib/scan/runner.rb +6 -1
- data/scan/lib/scan/slack_poster.rb +4 -1
- data/scan/lib/scan/test_command_generator.rb +3 -0
- data/screengrab/lib/screengrab/runner.rb +2 -0
- data/sigh/lib/sigh/runner.rb +1 -1
- data/snapshot/lib/assets/SnapshotHelper.swift +6 -2
- data/snapshot/lib/snapshot/options.rb +17 -2
- data/snapshot/lib/snapshot/update.rb +1 -1
- data/spaceship/lib/spaceship/client.rb +28 -1
- data/spaceship/lib/spaceship/connect_api.rb +6 -0
- data/spaceship/lib/spaceship/connect_api/api_client.rb +1 -1
- data/spaceship/lib/spaceship/connect_api/models/app.rb +19 -4
- data/spaceship/lib/spaceship/connect_api/models/app_data_usage.rb +59 -0
- data/spaceship/lib/spaceship/connect_api/models/app_data_usage_category.rb +65 -0
- data/spaceship/lib/spaceship/connect_api/models/app_data_usage_data_protection.rb +27 -0
- data/spaceship/lib/spaceship/connect_api/models/app_data_usage_grouping.rb +18 -0
- data/spaceship/lib/spaceship/connect_api/models/app_data_usage_purposes.rb +37 -0
- data/spaceship/lib/spaceship/connect_api/models/app_data_usages_publish_state.rb +36 -0
- data/spaceship/lib/spaceship/connect_api/models/app_info.rb +1 -0
- data/spaceship/lib/spaceship/connect_api/models/app_info_localization.rb +2 -0
- data/spaceship/lib/spaceship/connect_api/models/app_store_version.rb +8 -1
- data/spaceship/lib/spaceship/connect_api/models/beta_group.rb +9 -0
- data/spaceship/lib/spaceship/connect_api/models/device.rb +30 -0
- data/spaceship/lib/spaceship/connect_api/response.rb +3 -1
- data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +12 -0
- data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +103 -0
- data/spaceship/lib/spaceship/errors.rb +19 -0
- data/spaceship/lib/spaceship/two_step_or_factor_client.rb +19 -6
- data/spaceship/lib/spaceship/upgrade_2fa_later_client.rb +91 -0
- metadata +44 -23
- data/fastlane/lib/fastlane/actions/.download_dsyms.rb.swp +0 -0
- data/spaceship/lib/spaceship/connect_api/models/.app.rb.swp +0 -0
- data/spaceship/lib/spaceship/connect_api/models/.app_screenshot.rb.swp +0 -0
- data/spaceship/lib/spaceship/connect_api/models/.build.rb.swp +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 84a3a2b2d4fc8ec05b2b67244f2a41b643b7a3596b42eafcd76e409681d419a8
|
|
4
|
+
data.tar.gz: 4843a267b0adad749d4a5670decd3d875285b387bbbd0df01c286b8ee5d64f9a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b11081f274dfda7fb57b9de1940b7aeef425938b2f9811063b49306e82ddd274ac1f2c12f12ddfc6a750216438387d383da4c8a2ca504d768e9dff80c2b52bf1
|
|
7
|
+
data.tar.gz: 13c125644f4d2b7e2a8678c327b65aaeb9569b36acef098b6a229d79808ca472b1887ad30a917e40452725cc20386fb073417d8201d43c674420562bad7818dd
|
data/README.md
CHANGED
|
@@ -34,49 +34,49 @@ 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='
|
|
38
|
-
<a href='https://github.com/
|
|
39
|
-
<img src='https://github.com/
|
|
37
|
+
<td id='daniel-jankowski'>
|
|
38
|
+
<a href='https://github.com/mollyIV'>
|
|
39
|
+
<img src='https://github.com/mollyIV.png?size=140'>
|
|
40
40
|
</a>
|
|
41
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
41
|
+
<h4 align='center'><a href='https://twitter.com/mollyIV'>Daniel Jankowski</a></h4>
|
|
42
42
|
</td>
|
|
43
|
-
<td id='
|
|
44
|
-
<a href='https://github.com/
|
|
45
|
-
<img src='https://github.com/
|
|
43
|
+
<td id='helmut-januschka'>
|
|
44
|
+
<a href='https://github.com/hjanuschka'>
|
|
45
|
+
<img src='https://github.com/hjanuschka.png?size=140'>
|
|
46
46
|
</a>
|
|
47
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
47
|
+
<h4 align='center'><a href='https://twitter.com/hjanuschka'>Helmut Januschka</a></h4>
|
|
48
48
|
</td>
|
|
49
|
-
<td id='
|
|
50
|
-
<a href='https://github.com/
|
|
51
|
-
<img src='https://github.com/
|
|
49
|
+
<td id='jan-piotrowski'>
|
|
50
|
+
<a href='https://github.com/janpio'>
|
|
51
|
+
<img src='https://github.com/janpio.png?size=140'>
|
|
52
52
|
</a>
|
|
53
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
53
|
+
<h4 align='center'><a href='https://twitter.com/Sujan'>Jan Piotrowski</a></h4>
|
|
54
54
|
</td>
|
|
55
|
-
<td id='
|
|
56
|
-
<a href='https://github.com/
|
|
57
|
-
<img src='https://github.com/
|
|
55
|
+
<td id='luka-mirosevic'>
|
|
56
|
+
<a href='https://github.com/lmirosevic'>
|
|
57
|
+
<img src='https://github.com/lmirosevic.png?size=140'>
|
|
58
58
|
</a>
|
|
59
|
-
<h4 align='center'>
|
|
59
|
+
<h4 align='center'><a href='https://twitter.com/lmirosevic'>Luka Mirosevic</a></h4>
|
|
60
60
|
</td>
|
|
61
|
-
<td id='
|
|
62
|
-
<a href='https://github.com/
|
|
63
|
-
<img src='https://github.com/
|
|
61
|
+
<td id='felix-krause'>
|
|
62
|
+
<a href='https://github.com/KrauseFx'>
|
|
63
|
+
<img src='https://github.com/KrauseFx.png?size=140'>
|
|
64
64
|
</a>
|
|
65
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
65
|
+
<h4 align='center'><a href='https://twitter.com/KrauseFx'>Felix Krause</a></h4>
|
|
66
66
|
</td>
|
|
67
67
|
</tr>
|
|
68
68
|
<tr>
|
|
69
|
-
<td id='
|
|
70
|
-
<a href='https://github.com/
|
|
71
|
-
<img src='https://github.com/
|
|
69
|
+
<td id='jimmy-dee'>
|
|
70
|
+
<a href='https://github.com/jdee'>
|
|
71
|
+
<img src='https://github.com/jdee.png?size=140'>
|
|
72
72
|
</a>
|
|
73
|
-
<h4 align='center'
|
|
73
|
+
<h4 align='center'>Jimmy Dee</h4>
|
|
74
74
|
</td>
|
|
75
|
-
<td id='
|
|
76
|
-
<a href='https://github.com/
|
|
77
|
-
<img src='https://github.com/
|
|
75
|
+
<td id='kohki-miki'>
|
|
76
|
+
<a href='https://github.com/giginet'>
|
|
77
|
+
<img src='https://github.com/giginet.png?size=140'>
|
|
78
78
|
</a>
|
|
79
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
79
|
+
<h4 align='center'><a href='https://twitter.com/giginet'>Kohki Miki</a></h4>
|
|
80
80
|
</td>
|
|
81
81
|
<td id='joshua-liebowitz'>
|
|
82
82
|
<a href='https://github.com/taquitos'>
|
|
@@ -84,11 +84,11 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
|
|
|
84
84
|
</a>
|
|
85
85
|
<h4 align='center'><a href='https://twitter.com/taquitos'>Joshua Liebowitz</a></h4>
|
|
86
86
|
</td>
|
|
87
|
-
<td id='
|
|
88
|
-
<a href='https://github.com/
|
|
89
|
-
<img src='https://github.com/
|
|
87
|
+
<td id='fumiya-nakamura'>
|
|
88
|
+
<a href='https://github.com/nafu'>
|
|
89
|
+
<img src='https://github.com/nafu.png?size=140'>
|
|
90
90
|
</a>
|
|
91
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
91
|
+
<h4 align='center'><a href='https://twitter.com/nafu003'>Fumiya Nakamura</a></h4>
|
|
92
92
|
</td>
|
|
93
93
|
<td id='matthew-ellis'>
|
|
94
94
|
<a href='https://github.com/matthewellis'>
|
|
@@ -98,17 +98,11 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
|
|
|
98
98
|
</td>
|
|
99
99
|
</tr>
|
|
100
100
|
<tr>
|
|
101
|
-
<td id='
|
|
102
|
-
<a href='https://github.com/
|
|
103
|
-
<img src='https://github.com/
|
|
104
|
-
</a>
|
|
105
|
-
<h4 align='center'><a href='https://twitter.com/Revolt666'>Iulian Onofrei</a></h4>
|
|
106
|
-
</td>
|
|
107
|
-
<td id='danielle-tomlinson'>
|
|
108
|
-
<a href='https://github.com/endocrimes'>
|
|
109
|
-
<img src='https://github.com/endocrimes.png?size=140'>
|
|
101
|
+
<td id='maksym-grebenets'>
|
|
102
|
+
<a href='https://github.com/mgrebenets'>
|
|
103
|
+
<img src='https://github.com/mgrebenets.png?size=140'>
|
|
110
104
|
</a>
|
|
111
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
105
|
+
<h4 align='center'><a href='https://twitter.com/mgrebenets'>Maksym Grebenets</a></h4>
|
|
112
106
|
</td>
|
|
113
107
|
<td id='andrew-mcburney'>
|
|
114
108
|
<a href='https://github.com/armcburney'>
|
|
@@ -122,37 +116,31 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
|
|
|
122
116
|
</a>
|
|
123
117
|
<h4 align='center'><a href='https://twitter.com/ott_max'>Max Ott</a></h4>
|
|
124
118
|
</td>
|
|
125
|
-
<td id='jan-piotrowski'>
|
|
126
|
-
<a href='https://github.com/janpio'>
|
|
127
|
-
<img src='https://github.com/janpio.png?size=140'>
|
|
128
|
-
</a>
|
|
129
|
-
<h4 align='center'><a href='https://twitter.com/Sujan'>Jan Piotrowski</a></h4>
|
|
130
|
-
</td>
|
|
131
|
-
</tr>
|
|
132
|
-
<tr>
|
|
133
119
|
<td id='olivier-halligon'>
|
|
134
120
|
<a href='https://github.com/AliSoftware'>
|
|
135
121
|
<img src='https://github.com/AliSoftware.png?size=140'>
|
|
136
122
|
</a>
|
|
137
123
|
<h4 align='center'><a href='https://twitter.com/aligatr'>Olivier Halligon</a></h4>
|
|
138
124
|
</td>
|
|
139
|
-
<td id='
|
|
140
|
-
<a href='https://github.com/
|
|
141
|
-
<img src='https://github.com/
|
|
125
|
+
<td id='iulian-onofrei'>
|
|
126
|
+
<a href='https://github.com/revolter'>
|
|
127
|
+
<img src='https://github.com/revolter.png?size=140'>
|
|
142
128
|
</a>
|
|
143
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
129
|
+
<h4 align='center'><a href='https://twitter.com/Revolt666'>Iulian Onofrei</a></h4>
|
|
144
130
|
</td>
|
|
145
|
-
|
|
146
|
-
<
|
|
147
|
-
<
|
|
131
|
+
</tr>
|
|
132
|
+
<tr>
|
|
133
|
+
<td id='aaron-brager'>
|
|
134
|
+
<a href='https://github.com/getaaron'>
|
|
135
|
+
<img src='https://github.com/getaaron.png?size=140'>
|
|
148
136
|
</a>
|
|
149
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
137
|
+
<h4 align='center'><a href='https://twitter.com/getaaron'>Aaron Brager</a></h4>
|
|
150
138
|
</td>
|
|
151
|
-
<td id='
|
|
152
|
-
<a href='https://github.com/
|
|
153
|
-
<img src='https://github.com/
|
|
139
|
+
<td id='manu-wallner'>
|
|
140
|
+
<a href='https://github.com/milch'>
|
|
141
|
+
<img src='https://github.com/milch.png?size=140'>
|
|
154
142
|
</a>
|
|
155
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
143
|
+
<h4 align='center'><a href='https://twitter.com/acrooow'>Manu Wallner</a></h4>
|
|
156
144
|
</td>
|
|
157
145
|
<td id='josh-holtz'>
|
|
158
146
|
<a href='https://github.com/joshdholtz'>
|
|
@@ -160,20 +148,32 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
|
|
|
160
148
|
</a>
|
|
161
149
|
<h4 align='center'><a href='https://twitter.com/joshdholtz'>Josh Holtz</a></h4>
|
|
162
150
|
</td>
|
|
163
|
-
|
|
164
|
-
<
|
|
165
|
-
<
|
|
166
|
-
<a href='https://github.com/nafu'>
|
|
167
|
-
<img src='https://github.com/nafu.png?size=140'>
|
|
151
|
+
<td id='danielle-tomlinson'>
|
|
152
|
+
<a href='https://github.com/endocrimes'>
|
|
153
|
+
<img src='https://github.com/endocrimes.png?size=140'>
|
|
168
154
|
</a>
|
|
169
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
155
|
+
<h4 align='center'><a href='https://twitter.com/endocrimes'>Danielle Tomlinson</a></h4>
|
|
156
|
+
</td>
|
|
157
|
+
<td id='jérôme-lacoste'>
|
|
158
|
+
<a href='https://github.com/lacostej'>
|
|
159
|
+
<img src='https://github.com/lacostej.png?size=140'>
|
|
160
|
+
</a>
|
|
161
|
+
<h4 align='center'><a href='https://twitter.com/lacostej'>Jérôme Lacoste</a></h4>
|
|
170
162
|
</td>
|
|
163
|
+
</tr>
|
|
164
|
+
<tr>
|
|
171
165
|
<td id='stefan-natchev'>
|
|
172
166
|
<a href='https://github.com/snatchev'>
|
|
173
167
|
<img src='https://github.com/snatchev.png?size=140'>
|
|
174
168
|
</a>
|
|
175
169
|
<h4 align='center'><a href='https://twitter.com/snatchev'>Stefan Natchev</a></h4>
|
|
176
170
|
</td>
|
|
171
|
+
<td id='jorge-revuelta-h'>
|
|
172
|
+
<a href='https://github.com/minuscorp'>
|
|
173
|
+
<img src='https://github.com/minuscorp.png?size=140'>
|
|
174
|
+
</a>
|
|
175
|
+
<h4 align='center'><a href='https://twitter.com/minuscorp'>Jorge Revuelta H</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_.
|
data/cert/lib/cert/options.rb
CHANGED
|
@@ -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
|
]
|
|
@@ -82,15 +82,12 @@ module Deliver
|
|
|
82
82
|
# @param path (String) path to the screenshot file
|
|
83
83
|
# @param language (String) Language of this screenshot (e.g. English)
|
|
84
84
|
# @param screen_size (Deliver::AppScreenshot::ScreenSize) the screen size, which
|
|
85
|
-
# will automatically be calculated when you don't set it.
|
|
85
|
+
# will automatically be calculated when you don't set it. (Deprecated)
|
|
86
86
|
def initialize(path, language, screen_size = nil)
|
|
87
|
+
UI.deprecated('`screen_size` for Deliver::AppScreenshot.new is deprecated in favor of the default behavior to calculate size automatically. Passed value is no longer validated.') if screen_size
|
|
87
88
|
self.path = path
|
|
88
89
|
self.language = language
|
|
89
|
-
screen_size
|
|
90
|
-
|
|
91
|
-
self.screen_size = screen_size
|
|
92
|
-
|
|
93
|
-
UI.error("Looks like the screenshot given (#{path}) does not match the requirements of #{screen_size}") unless self.is_valid?
|
|
90
|
+
self.screen_size = screen_size || self.class.calculate_screen_size(path)
|
|
94
91
|
end
|
|
95
92
|
|
|
96
93
|
# The iTC API requires a different notation for the device
|
|
@@ -161,6 +158,7 @@ module Deliver
|
|
|
161
158
|
|
|
162
159
|
# Validates the given screenshots (size and format)
|
|
163
160
|
def is_valid?
|
|
161
|
+
UI.deprecated('Deliver::AppScreenshot#is_valid? is deprecated in favor of Deliver::AppScreenshotValidator')
|
|
164
162
|
return false unless ["png", "PNG", "jpg", "JPG", "jpeg", "JPEG"].include?(self.path.split(".").last)
|
|
165
163
|
|
|
166
164
|
return self.screen_size == self.class.calculate_screen_size(self.path)
|
|
@@ -350,7 +348,7 @@ module Deliver
|
|
|
350
348
|
end
|
|
351
349
|
end
|
|
352
350
|
|
|
353
|
-
|
|
351
|
+
nil
|
|
354
352
|
end
|
|
355
353
|
end
|
|
356
354
|
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
require 'fastimage'
|
|
2
|
+
|
|
3
|
+
module Deliver
|
|
4
|
+
class AppScreenshotValidator
|
|
5
|
+
# A simple structure that holds error information as well as formatted error messages consistently
|
|
6
|
+
# Set `to_skip` to `true` when just needing to skip uploading rather than causing a crash.
|
|
7
|
+
class ValidationError
|
|
8
|
+
# Constants that can be given to `type` param
|
|
9
|
+
INVALID_SCREEN_SIZE = 'Invalid screen size'.freeze
|
|
10
|
+
UNACCEPTABLE_DEVICE = 'Not an accepted App Store Connect device'.freeze
|
|
11
|
+
INVALID_FILE_EXTENSION = 'Invalid file extension'.freeze
|
|
12
|
+
FILE_EXTENSION_MISMATCH = 'File extension mismatches its image format'.freeze
|
|
13
|
+
|
|
14
|
+
attr_reader :type, :path, :debug_info, :to_skip
|
|
15
|
+
|
|
16
|
+
def initialize(type: nil, path: nil, debug_info: nil, to_skip: false)
|
|
17
|
+
@type = type
|
|
18
|
+
@path = path
|
|
19
|
+
@debug_info = debug_info
|
|
20
|
+
@to_skip = to_skip
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_s
|
|
24
|
+
"#{to_skip ? '🏃 Skipping' : '🚫 Error'}: #{path} - #{type} (#{debug_info})"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def inspect
|
|
28
|
+
"\"#{type}\""
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Access each array by symbol returned from FastImage.type
|
|
33
|
+
ALLOWED_SCREENSHOT_FILE_EXTENSION = { png: ['png', 'PNG'], jpeg: ['jpg', 'JPG', 'jpeg', 'JPEG'] }.freeze
|
|
34
|
+
|
|
35
|
+
APP_SCREENSHOT_SPEC_URL = 'https://help.apple.com/app-store-connect/#/devd274dd925'.freeze
|
|
36
|
+
|
|
37
|
+
# Validate a screenshot and inform an error message via `errors` parameter. `errors` is mutated
|
|
38
|
+
# to append the messages and each message should contain the corresponding path to let users know which file is throwing the error.
|
|
39
|
+
#
|
|
40
|
+
# @param screenshot [AppScreenshot]
|
|
41
|
+
# @param errors [Array<Deliver::AppScreenshotValidator::ValidationError>] Pass an array object to add validation errors when detecting errors.
|
|
42
|
+
# This will be mutated to add more error objects as validation detects errors.
|
|
43
|
+
# @return [Boolean] true if given screenshot is valid
|
|
44
|
+
def self.validate(screenshot, errors)
|
|
45
|
+
# Given screenshot will be diagnosed and errors found are accumulated
|
|
46
|
+
errors_found = []
|
|
47
|
+
|
|
48
|
+
validate_screen_size(screenshot, errors_found)
|
|
49
|
+
validate_device_type(screenshot, errors_found)
|
|
50
|
+
validate_file_extension_and_format(screenshot, errors_found)
|
|
51
|
+
|
|
52
|
+
# Merge errors found into given errors array
|
|
53
|
+
errors_found.each { |error| errors.push(error) }
|
|
54
|
+
errors_found.empty?
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.validate_screen_size(screenshot, errors_found)
|
|
58
|
+
if screenshot.screen_size.nil?
|
|
59
|
+
errors_found << ValidationError.new(type: ValidationError::INVALID_SCREEN_SIZE,
|
|
60
|
+
path: screenshot.path,
|
|
61
|
+
debug_info: "Actual size is #{get_formatted_size(screenshot)}. See the specifications to fix #{APP_SCREENSHOT_SPEC_URL}")
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Checking if the device type exists in spaceship
|
|
66
|
+
# Ex: iPhone 6.1 inch isn't supported in App Store Connect but need
|
|
67
|
+
# to have it in there for frameit support
|
|
68
|
+
def self.validate_device_type(screenshot, errors_found)
|
|
69
|
+
if !screenshot.screen_size.nil? && screenshot.device_type.nil?
|
|
70
|
+
errors_found << ValidationError.new(type: ValidationError::UNACCEPTABLE_DEVICE,
|
|
71
|
+
path: screenshot.path,
|
|
72
|
+
debug_info: "Screen size #{screenshot.screen_size} is not accepted. See the specifications to fix #{APP_SCREENSHOT_SPEC_URL}",
|
|
73
|
+
to_skip: true)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def self.validate_file_extension_and_format(screenshot, errors_found)
|
|
78
|
+
extension = File.extname(screenshot.path).delete('.')
|
|
79
|
+
valid_file_extensions = ALLOWED_SCREENSHOT_FILE_EXTENSION.values.flatten
|
|
80
|
+
is_valid_extension = valid_file_extensions.include?(extension)
|
|
81
|
+
|
|
82
|
+
unless is_valid_extension
|
|
83
|
+
errors_found << ValidationError.new(type: ValidationError::INVALID_FILE_EXTENSION,
|
|
84
|
+
path: screenshot.path,
|
|
85
|
+
debug_info: "Only #{valid_file_extensions.join(', ')} are allowed")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
format = FastImage.type(screenshot.path)
|
|
89
|
+
is_extension_matched = ALLOWED_SCREENSHOT_FILE_EXTENSION[format] &&
|
|
90
|
+
ALLOWED_SCREENSHOT_FILE_EXTENSION[format].include?(extension)
|
|
91
|
+
|
|
92
|
+
# This error only appears when file extension is valid
|
|
93
|
+
if is_valid_extension && !is_extension_matched
|
|
94
|
+
expected_extension = ALLOWED_SCREENSHOT_FILE_EXTENSION[format].first
|
|
95
|
+
expected_filename = File.basename(screenshot.path, File.extname(screenshot.path)) + ".#{expected_extension}"
|
|
96
|
+
errors_found << ValidationError.new(type: ValidationError::FILE_EXTENSION_MISMATCH,
|
|
97
|
+
path: screenshot.path,
|
|
98
|
+
debug_info: %(Actual format is "#{format}". Rename the filename to "#{expected_filename}".))
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def self.get_formatted_size(screenshot)
|
|
103
|
+
size = FastImage.size(screenshot.path)
|
|
104
|
+
return size.join('x') if size
|
|
105
|
+
nil
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
require 'fastlane_core/languages'
|
|
2
|
-
require 'spaceship/tunes/tunes'
|
|
3
|
-
|
|
4
1
|
require_relative 'module'
|
|
2
|
+
require_relative 'app_screenshot'
|
|
3
|
+
require_relative 'app_screenshot_validator'
|
|
5
4
|
require_relative 'upload_metadata'
|
|
6
5
|
require_relative 'languages'
|
|
7
6
|
|
|
@@ -13,6 +12,7 @@ module Deliver
|
|
|
13
12
|
IMESSAGE_DIR_NAME = "iMessage".freeze
|
|
14
13
|
DEFAULT_DIR_NAME = "default".freeze
|
|
15
14
|
|
|
15
|
+
EXPANDABLE_DIR_NAMES = [APPLE_TV_DIR_NAME, IMESSAGE_DIR_NAME].freeze
|
|
16
16
|
SPECIAL_DIR_NAMES = [APPLE_TV_DIR_NAME, IMESSAGE_DIR_NAME, DEFAULT_DIR_NAME].freeze
|
|
17
17
|
|
|
18
18
|
# Some exception directories may exist from other actions that should not be iterated through
|
|
@@ -20,35 +20,137 @@ module Deliver
|
|
|
20
20
|
FRAMEIT_FONTS_DIR_NAME = "fonts".freeze
|
|
21
21
|
META_DIR_NAMES = UploadMetadata::ALL_META_SUB_DIRS.map(&:downcase)
|
|
22
22
|
|
|
23
|
-
EXCEPTION_DIRECTORIES =
|
|
23
|
+
EXCEPTION_DIRECTORIES = (META_DIR_NAMES << SUPPLY_DIR_NAME << FRAMEIT_FONTS_DIR_NAME).freeze
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
# A class that represents language folder under screenshots or metadata folder
|
|
26
|
+
class LanguageFolder
|
|
27
|
+
attr_reader :path
|
|
28
|
+
|
|
29
|
+
# @return [String] A normalized language name that corresponds to the directory's name
|
|
30
|
+
attr_reader :language
|
|
31
|
+
|
|
32
|
+
def self.available_languages
|
|
33
|
+
# 2020-08-24 - Available locales are not available as an endpoint in App Store Connect
|
|
34
|
+
# Update with Spaceship::Tunes.client.available_languages.sort (as long as endpoint is avilable)
|
|
35
|
+
Deliver::Languages::ALL_LANGUAGES
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.allowed_directory_names_with_case
|
|
39
|
+
available_languages + SPECIAL_DIR_NAMES
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @param path [String] A directory path otherwise this initializer fails
|
|
43
|
+
# @param nested [Boolan] Whether given path is nested of another special directory.
|
|
44
|
+
# This affects `expandable?` to return `false` when this set to `true`.
|
|
45
|
+
def initialize(path, nested: false)
|
|
46
|
+
raise(ArgumentError, "Given path must be a directory path - #{path}") unless File.directory?(path)
|
|
47
|
+
@path = path
|
|
48
|
+
@language = self.class.available_languages.find { |lang| basename.casecmp?(lang) }
|
|
49
|
+
@nested = nested
|
|
50
|
+
end
|
|
27
51
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
52
|
+
def nested?
|
|
53
|
+
@nested
|
|
54
|
+
end
|
|
31
55
|
|
|
32
|
-
|
|
33
|
-
|
|
56
|
+
def valid?
|
|
57
|
+
self.class.allowed_directory_names_with_case.any? { |name| name.casecmp?(basename) }
|
|
58
|
+
end
|
|
34
59
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
end
|
|
60
|
+
def expandable?
|
|
61
|
+
!nested? && EXPANDABLE_DIR_NAMES.any? { |name| name.casecmp?(basename) }
|
|
62
|
+
end
|
|
38
63
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
64
|
+
def skip?
|
|
65
|
+
EXCEPTION_DIRECTORIES.map(&:downcase).include?(basename.downcase)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def file_paths(extensions = '{png,jpg,jpeg}')
|
|
69
|
+
Dir.glob(File.join(path, "*.#{extensions}"), File::FNM_CASEFOLD).sort
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def framed_file_paths(extensions = '{png,jpg,jpeg}')
|
|
73
|
+
Dir.glob(File.join(path, "*_framed.#{extensions}"), File::FNM_CASEFOLD).sort
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def basename
|
|
77
|
+
File.basename(@path)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Returns the list of valid app screenshot. When detecting invalid screenshots, this will cause an error.
|
|
82
|
+
#
|
|
83
|
+
# @param root [String] A directory path
|
|
84
|
+
# @param ignore_validation [String] Set false not to raise the error when finding invalid folder name
|
|
85
|
+
# @return [Array<AppScreenshot>] The list of AppScreenshot that exist under given `root` directory
|
|
86
|
+
def self.load_app_screenshots(root, ignore_validation)
|
|
87
|
+
screenshots = language_folders(root, ignore_validation, true).flat_map do |language_folder|
|
|
88
|
+
paths = if language_folder.framed_file_paths.count > 0
|
|
89
|
+
UI.important("Framed screenshots are detected! 🖼 Non-framed screenshot files may be skipped. 🏃")
|
|
90
|
+
# watchOS screenshots can be picked up even when framed ones were found since frameit doesn't support watchOS screenshots
|
|
91
|
+
framed_or_watch, skipped = language_folder.file_paths.partition { |path| path.downcase.include?('framed') || path.downcase.include?('watch') }
|
|
92
|
+
skipped.each { |path| UI.important("🏃 Skipping screenshot file: #{path}") }
|
|
93
|
+
framed_or_watch
|
|
94
|
+
else
|
|
95
|
+
language_folder.file_paths
|
|
96
|
+
end
|
|
97
|
+
paths.map { |path| AppScreenshot.new(path, language_folder.language) }
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
errors = []
|
|
101
|
+
valid_screenshots = screenshots.select { |screenshot| Deliver::AppScreenshotValidator.validate(screenshot, errors) }
|
|
102
|
+
|
|
103
|
+
errors_to_skip, errors_to_crash = errors.partition(&:to_skip)
|
|
104
|
+
|
|
105
|
+
unless errors_to_skip.empty?
|
|
106
|
+
UI.important("🏃 Screenshots to be skipped are detected!")
|
|
107
|
+
errors_to_skip.each { |error| UI.message(error) }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
unless errors_to_crash.empty?
|
|
111
|
+
UI.important("🚫 Invalid screenshots were detected! Here are the reasons:")
|
|
112
|
+
errors_to_crash.each { |error| UI.error(error) }
|
|
113
|
+
UI.user_error!("Canceled uploading screenshots. Please check the error messages above and fix the screenshots.")
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
valid_screenshots
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Returns the list of language folders
|
|
120
|
+
#
|
|
121
|
+
# @param roort [String] A directory path to get the list of language folders
|
|
122
|
+
# @param ignore_validation [Boolean] Set false not to raise the error when finding invalid folder name
|
|
123
|
+
# @param expand_sub_folders [Boolean] Set true to expand special folders; such as "iMessage" to nested language folders
|
|
124
|
+
# @return [Array<LanguageFolder>] The list of LanguageFolder whose each of them
|
|
125
|
+
def self.language_folders(root, ignore_validation, expand_sub_folders = false)
|
|
126
|
+
folders = Dir.glob(File.join(root, '*'))
|
|
127
|
+
.select { |path| File.directory?(path) }
|
|
128
|
+
.map { |path| LanguageFolder.new(path, nested: false) }
|
|
129
|
+
.reject(&:skip?)
|
|
130
|
+
|
|
131
|
+
selected_folders, rejected_folders = folders.partition(&:valid?)
|
|
44
132
|
|
|
45
133
|
if !ignore_validation && !rejected_folders.empty?
|
|
46
|
-
rejected_folders = rejected_folders.map
|
|
134
|
+
rejected_folders = rejected_folders.map(&:basename)
|
|
47
135
|
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}" \
|
|
136
|
+
"\nValid directory names are: #{LanguageFolder.allowed_directory_names_with_case}" \
|
|
49
137
|
"\n\nEnable 'ignore_language_directory_validation' to prevent this validation from happening")
|
|
50
138
|
end
|
|
51
139
|
|
|
140
|
+
# Expand selected_folders for the special directories
|
|
141
|
+
if expand_sub_folders
|
|
142
|
+
selected_folders = selected_folders.flat_map do |folder|
|
|
143
|
+
if folder.expandable?
|
|
144
|
+
Dir.glob(File.join(folder.path, '*'))
|
|
145
|
+
.select { |p| File.directory?(p) }
|
|
146
|
+
.map { |p| LanguageFolder.new(p, nested: true) }
|
|
147
|
+
.select(&:valid?)
|
|
148
|
+
else
|
|
149
|
+
folder
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
52
154
|
selected_folders
|
|
53
155
|
end
|
|
54
156
|
end
|