fastlane 2.187.0 → 2.191.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 +94 -94
- data/deliver/lib/deliver/app_screenshot.rb +2 -1
- data/deliver/lib/deliver/app_screenshot_iterator.rb +2 -2
- data/deliver/lib/deliver/loader.rb +1 -1
- data/deliver/lib/deliver/options.rb +6 -0
- data/deliver/lib/deliver/runner.rb +9 -1
- data/deliver/lib/deliver/screenshot_comparable.rb +62 -0
- data/deliver/lib/deliver/sync_screenshots.rb +200 -0
- data/fastlane/lib/fastlane/actions/app_store_connect_api_key.rb +1 -1
- data/fastlane/lib/fastlane/actions/appledoc.rb +45 -45
- data/fastlane/lib/fastlane/actions/automatic_code_signing.rb +1 -2
- data/fastlane/lib/fastlane/actions/bundle_install.rb +13 -1
- data/fastlane/lib/fastlane/actions/clean_cocoapods_cache.rb +25 -1
- data/fastlane/lib/fastlane/actions/docs/capture_android_screenshots.md +2 -2
- data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +2 -2
- data/fastlane/lib/fastlane/actions/gradle.rb +1 -1
- data/fastlane/lib/fastlane/actions/update_icloud_container_identifiers.rb +1 -4
- data/fastlane/lib/fastlane/actions/update_info_plist.rb +1 -1
- data/fastlane/lib/fastlane/actions/update_keychain_access_groups.rb +1 -4
- data/fastlane/lib/fastlane/actions/update_plist.rb +1 -1
- data/fastlane/lib/fastlane/actions/update_project_provisioning.rb +2 -2
- data/fastlane/lib/fastlane/actions/update_urban_airship_configuration.rb +0 -1
- data/fastlane/lib/fastlane/actions/update_url_schemes.rb +15 -26
- data/fastlane/lib/fastlane/actions/upload_app_privacy_details_to_app_store.rb +1 -2
- data/fastlane/lib/fastlane/actions/upload_symbols_to_sentry.rb +3 -10
- data/fastlane/lib/fastlane/actions/validate_play_store_json_key.rb +40 -44
- data/fastlane/lib/fastlane/actions/version_get_podspec.rb +1 -2
- data/fastlane/lib/fastlane/actions/xcode_server_get_assets.rb +3 -3
- data/fastlane/lib/fastlane/actions/zip.rb +86 -21
- data/fastlane/lib/fastlane/documentation/markdown_docs_generator.rb +1 -1
- data/fastlane/lib/fastlane/features.rb +3 -0
- data/fastlane/lib/fastlane/plugins/template/.circleci/config.yml +1 -1
- data/fastlane/lib/fastlane/plugins/template/.github/workflows/test.yml +1 -1
- data/fastlane/lib/fastlane/version.rb +1 -1
- data/fastlane/swift/Deliverfile.swift +1 -1
- data/fastlane/swift/DeliverfileProtocol.swift +5 -1
- data/fastlane/swift/Fastlane.swift +108 -46
- data/fastlane/swift/Gymfile.swift +1 -1
- data/fastlane/swift/GymfileProtocol.swift +1 -1
- data/fastlane/swift/Matchfile.swift +1 -1
- data/fastlane/swift/MatchfileProtocol.swift +1 -1
- data/fastlane/swift/Precheckfile.swift +1 -1
- data/fastlane/swift/PrecheckfileProtocol.swift +1 -1
- data/fastlane/swift/Scanfile.swift +1 -1
- data/fastlane/swift/ScanfileProtocol.swift +5 -1
- data/fastlane/swift/Screengrabfile.swift +1 -1
- data/fastlane/swift/ScreengrabfileProtocol.swift +1 -1
- data/fastlane/swift/Snapshotfile.swift +1 -1
- data/fastlane/swift/SnapshotfileProtocol.swift +1 -1
- data/fastlane/swift/formatting/Brewfile.lock.json +17 -9
- data/fastlane_core/lib/fastlane_core/keychain_importer.rb +11 -4
- data/fastlane_core/lib/fastlane_core/ui/disable_colors.rb +1 -0
- data/pilot/lib/pilot.rb +0 -1
- data/precheck/lib/precheck/module.rb +2 -0
- data/precheck/lib/precheck/options.rb +3 -3
- data/produce/lib/produce/commands_generator.rb +28 -0
- data/produce/lib/produce/service.rb +15 -0
- data/scan/lib/scan/detect_values.rb +22 -13
- data/scan/lib/scan/module.rb +1 -0
- data/scan/lib/scan/options.rb +12 -1
- data/scan/lib/scan/test_command_generator.rb +29 -6
- data/scan/lib/scan/xcpretty_reporter_options_generator.rb +1 -1
- data/screengrab/lib/screengrab/runner.rb +2 -2
- data/sigh/lib/sigh/options.rb +2 -1
- data/spaceship/lib/spaceship/client.rb +19 -3
- data/spaceship/lib/spaceship/connect_api.rb +1 -0
- data/spaceship/lib/spaceship/connect_api/models/app.rb +7 -0
- data/spaceship/lib/spaceship/connect_api/models/capabilities.rb +27 -0
- data/spaceship/lib/spaceship/connect_api/models/user.rb +17 -3
- data/spaceship/lib/spaceship/connect_api/models/user_invitation.rb +26 -5
- data/spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb +5 -0
- data/spaceship/lib/spaceship/connect_api/testflight/client.rb +3 -0
- data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +39 -0
- data/spaceship/lib/spaceship/connect_api/token.rb +2 -1
- data/spaceship/lib/spaceship/connect_api/tunes/client.rb +3 -0
- data/spaceship/lib/spaceship/connect_api/users/client.rb +3 -0
- data/spaceship/lib/spaceship/connect_api/users/users.rb +58 -3
- data/spaceship/lib/spaceship/tunes/tunes_client.rb +3 -0
- data/supply/lib/supply/client.rb +7 -1
- data/supply/lib/supply/options.rb +5 -0
- data/supply/lib/supply/uploader.rb +1 -1
- metadata +26 -28
- data/fastlane/lib/fastlane/.erb_template_helper.rb.swp +0 -0
- data/gym/lib/gym/generators/.package_command_generator_xcode7.rb.swp +0 -0
- data/pilot/lib/pilot/features.rb +0 -0
- data/spaceship/lib/spaceship/.DS_Store +0 -0
- data/spaceship/lib/spaceship/connect_api/models/.app_store_version_submission.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: 191c5f2f91fe567ba6f0c35848e69c0b921480ef1f2076bd531b774b6773bada
|
|
4
|
+
data.tar.gz: 6cf068574ea7ea72ac092791021fc78c2d1486d9e6f03772cc9564420e98a989
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: aacb03423627e0dc324915167515f0a4c8faebd6349c9a989320332baa668782f7dfbd0c20899e0905fcffc3d3ad3f8e254e05f75b30facff9744636b37c3c00
|
|
7
|
+
data.tar.gz: fa30c4044f3e3dffa7b53ed4a48d9e6fa2805649538077e2134f41eeada06e9bc66f4821124a5e59fb29542727aa8df9b278660ae522fbab134bee4427c6bc13
|
data/README.md
CHANGED
|
@@ -35,43 +35,43 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
|
|
|
35
35
|
<!-- This table is regenerated and resorted on each release -->
|
|
36
36
|
<table id='team'>
|
|
37
37
|
<tr>
|
|
38
|
-
<td id='
|
|
39
|
-
<a href='https://github.com/
|
|
40
|
-
<img src='https://github.com/
|
|
38
|
+
<td id='josh-holtz'>
|
|
39
|
+
<a href='https://github.com/joshdholtz'>
|
|
40
|
+
<img src='https://github.com/joshdholtz.png' width='140px;'>
|
|
41
41
|
</a>
|
|
42
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
42
|
+
<h4 align='center'><a href='https://twitter.com/joshdholtz'>Josh Holtz</a></h4>
|
|
43
43
|
</td>
|
|
44
|
-
<td id='
|
|
45
|
-
<a href='https://github.com/
|
|
46
|
-
<img src='https://github.com/
|
|
44
|
+
<td id='aaron-brager'>
|
|
45
|
+
<a href='https://github.com/getaaron'>
|
|
46
|
+
<img src='https://github.com/getaaron.png' width='140px;'>
|
|
47
47
|
</a>
|
|
48
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
48
|
+
<h4 align='center'><a href='https://twitter.com/getaaron'>Aaron Brager</a></h4>
|
|
49
49
|
</td>
|
|
50
|
-
<td id='
|
|
51
|
-
<a href='https://github.com/
|
|
52
|
-
<img src='https://github.com/
|
|
50
|
+
<td id='daniel-jankowski'>
|
|
51
|
+
<a href='https://github.com/mollyIV'>
|
|
52
|
+
<img src='https://github.com/mollyIV.png' width='140px;'>
|
|
53
53
|
</a>
|
|
54
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
54
|
+
<h4 align='center'><a href='https://twitter.com/mollyIV'>Daniel Jankowski</a></h4>
|
|
55
55
|
</td>
|
|
56
|
-
<td id='
|
|
57
|
-
<a href='https://github.com/
|
|
58
|
-
<img src='https://github.com/
|
|
56
|
+
<td id='luka-mirosevic'>
|
|
57
|
+
<a href='https://github.com/lmirosevic'>
|
|
58
|
+
<img src='https://github.com/lmirosevic.png' width='140px;'>
|
|
59
59
|
</a>
|
|
60
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
60
|
+
<h4 align='center'><a href='https://twitter.com/lmirosevic'>Luka Mirosevic</a></h4>
|
|
61
61
|
</td>
|
|
62
|
-
<td id='
|
|
63
|
-
<a href='https://github.com/
|
|
64
|
-
<img src='https://github.com/
|
|
62
|
+
<td id='satoshi-namai'>
|
|
63
|
+
<a href='https://github.com/ainame'>
|
|
64
|
+
<img src='https://github.com/ainame.png' width='140px;'>
|
|
65
65
|
</a>
|
|
66
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
66
|
+
<h4 align='center'><a href='https://twitter.com/ainame'>Satoshi Namai</a></h4>
|
|
67
67
|
</td>
|
|
68
68
|
</tr>
|
|
69
69
|
<tr>
|
|
70
|
-
<td id='
|
|
71
|
-
<a href='https://github.com/
|
|
72
|
-
<img src='https://github.com/
|
|
70
|
+
<td id='max-ott'>
|
|
71
|
+
<a href='https://github.com/max-ott'>
|
|
72
|
+
<img src='https://github.com/max-ott.png' width='140px;'>
|
|
73
73
|
</a>
|
|
74
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
74
|
+
<h4 align='center'><a href='https://twitter.com/ott_max'>Max Ott</a></h4>
|
|
75
75
|
</td>
|
|
76
76
|
<td id='maksym-grebenets'>
|
|
77
77
|
<a href='https://github.com/mgrebenets'>
|
|
@@ -79,119 +79,119 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
|
|
|
79
79
|
</a>
|
|
80
80
|
<h4 align='center'><a href='https://twitter.com/mgrebenets'>Maksym Grebenets</a></h4>
|
|
81
81
|
</td>
|
|
82
|
+
<td id='felix-krause'>
|
|
83
|
+
<a href='https://github.com/KrauseFx'>
|
|
84
|
+
<img src='https://github.com/KrauseFx.png' width='140px;'>
|
|
85
|
+
</a>
|
|
86
|
+
<h4 align='center'><a href='https://twitter.com/KrauseFx'>Felix Krause</a></h4>
|
|
87
|
+
</td>
|
|
82
88
|
<td id='kohki-miki'>
|
|
83
89
|
<a href='https://github.com/giginet'>
|
|
84
90
|
<img src='https://github.com/giginet.png' width='140px;'>
|
|
85
91
|
</a>
|
|
86
92
|
<h4 align='center'><a href='https://twitter.com/giginet'>Kohki Miki</a></h4>
|
|
87
93
|
</td>
|
|
88
|
-
<td id='
|
|
89
|
-
<a href='https://github.com/
|
|
90
|
-
<img src='https://github.com/
|
|
91
|
-
</a>
|
|
92
|
-
<h4 align='center'><a href='https://twitter.com/Revolt666'>Iulian Onofrei</a></h4>
|
|
93
|
-
</td>
|
|
94
|
-
<td id='manish-rathi'>
|
|
95
|
-
<a href='https://github.com/crazymanish'>
|
|
96
|
-
<img src='https://github.com/crazymanish.png' width='140px;'>
|
|
94
|
+
<td id='helmut-januschka'>
|
|
95
|
+
<a href='https://github.com/hjanuschka'>
|
|
96
|
+
<img src='https://github.com/hjanuschka.png' width='140px;'>
|
|
97
97
|
</a>
|
|
98
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
98
|
+
<h4 align='center'><a href='https://twitter.com/hjanuschka'>Helmut Januschka</a></h4>
|
|
99
99
|
</td>
|
|
100
100
|
</tr>
|
|
101
101
|
<tr>
|
|
102
|
-
<td id='
|
|
103
|
-
<a href='https://github.com/
|
|
104
|
-
<img src='https://github.com/
|
|
102
|
+
<td id='jimmy-dee'>
|
|
103
|
+
<a href='https://github.com/jdee'>
|
|
104
|
+
<img src='https://github.com/jdee.png' width='140px;'>
|
|
105
105
|
</a>
|
|
106
|
-
<h4 align='center'
|
|
106
|
+
<h4 align='center'>Jimmy Dee</h4>
|
|
107
107
|
</td>
|
|
108
|
-
<td id='
|
|
109
|
-
<a href='https://github.com/
|
|
110
|
-
<img src='https://github.com/
|
|
108
|
+
<td id='roger-oba'>
|
|
109
|
+
<a href='https://github.com/rogerluan'>
|
|
110
|
+
<img src='https://github.com/rogerluan.png' width='140px;'>
|
|
111
111
|
</a>
|
|
112
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
112
|
+
<h4 align='center'><a href='https://twitter.com/rogerluan_'>Roger Oba</a></h4>
|
|
113
113
|
</td>
|
|
114
|
-
<td id='
|
|
115
|
-
<a href='https://github.com/
|
|
116
|
-
<img src='https://github.com/
|
|
114
|
+
<td id='matthew-ellis'>
|
|
115
|
+
<a href='https://github.com/matthewellis'>
|
|
116
|
+
<img src='https://github.com/matthewellis.png' width='140px;'>
|
|
117
117
|
</a>
|
|
118
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
118
|
+
<h4 align='center'><a href='https://twitter.com/mellis1995'>Matthew Ellis</a></h4>
|
|
119
119
|
</td>
|
|
120
|
-
<td id='
|
|
121
|
-
<a href='https://github.com/
|
|
122
|
-
<img src='https://github.com/
|
|
120
|
+
<td id='jorge-revuelta-h'>
|
|
121
|
+
<a href='https://github.com/minuscorp'>
|
|
122
|
+
<img src='https://github.com/minuscorp.png' width='140px;'>
|
|
123
123
|
</a>
|
|
124
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
124
|
+
<h4 align='center'><a href='https://twitter.com/minuscorp'>Jorge Revuelta H</a></h4>
|
|
125
125
|
</td>
|
|
126
|
-
<td id='
|
|
127
|
-
<a href='https://github.com/
|
|
128
|
-
<img src='https://github.com/
|
|
126
|
+
<td id='jan-piotrowski'>
|
|
127
|
+
<a href='https://github.com/janpio'>
|
|
128
|
+
<img src='https://github.com/janpio.png' width='140px;'>
|
|
129
129
|
</a>
|
|
130
|
-
<h4 align='center'>
|
|
130
|
+
<h4 align='center'><a href='https://twitter.com/Sujan'>Jan Piotrowski</a></h4>
|
|
131
131
|
</td>
|
|
132
132
|
</tr>
|
|
133
133
|
<tr>
|
|
134
|
-
<td id='
|
|
135
|
-
<a href='https://github.com/
|
|
136
|
-
<img src='https://github.com/
|
|
134
|
+
<td id='manish-rathi'>
|
|
135
|
+
<a href='https://github.com/crazymanish'>
|
|
136
|
+
<img src='https://github.com/crazymanish.png' width='140px;'>
|
|
137
137
|
</a>
|
|
138
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
138
|
+
<h4 align='center'><a href='https://twitter.com/iammanishrathi'>Manish Rathi</a></h4>
|
|
139
139
|
</td>
|
|
140
|
-
<td id='
|
|
141
|
-
<a href='https://github.com/
|
|
142
|
-
<img src='https://github.com/
|
|
140
|
+
<td id='danielle-tomlinson'>
|
|
141
|
+
<a href='https://github.com/endocrimes'>
|
|
142
|
+
<img src='https://github.com/endocrimes.png' width='140px;'>
|
|
143
143
|
</a>
|
|
144
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
144
|
+
<h4 align='center'><a href='https://twitter.com/endocrimes'>Danielle Tomlinson</a></h4>
|
|
145
145
|
</td>
|
|
146
|
-
<td id='
|
|
147
|
-
<a href='https://github.com/
|
|
148
|
-
<img src='https://github.com/
|
|
146
|
+
<td id='joshua-liebowitz'>
|
|
147
|
+
<a href='https://github.com/taquitos'>
|
|
148
|
+
<img src='https://github.com/taquitos.png' width='140px;'>
|
|
149
149
|
</a>
|
|
150
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
150
|
+
<h4 align='center'><a href='https://twitter.com/taquitos'>Joshua Liebowitz</a></h4>
|
|
151
151
|
</td>
|
|
152
|
-
<td id='
|
|
153
|
-
<a href='https://github.com/
|
|
154
|
-
<img src='https://github.com/
|
|
152
|
+
<td id='fumiya-nakamura'>
|
|
153
|
+
<a href='https://github.com/nafu'>
|
|
154
|
+
<img src='https://github.com/nafu.png' width='140px;'>
|
|
155
155
|
</a>
|
|
156
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
156
|
+
<h4 align='center'><a href='https://twitter.com/nafu003'>Fumiya Nakamura</a></h4>
|
|
157
157
|
</td>
|
|
158
|
-
<td id='
|
|
159
|
-
<a href='https://github.com/
|
|
160
|
-
<img src='https://github.com/
|
|
158
|
+
<td id='jérôme-lacoste'>
|
|
159
|
+
<a href='https://github.com/lacostej'>
|
|
160
|
+
<img src='https://github.com/lacostej.png' width='140px;'>
|
|
161
161
|
</a>
|
|
162
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
162
|
+
<h4 align='center'><a href='https://twitter.com/lacostej'>Jérôme Lacoste</a></h4>
|
|
163
163
|
</td>
|
|
164
164
|
</tr>
|
|
165
165
|
<tr>
|
|
166
|
-
<td id='
|
|
167
|
-
<a href='https://github.com/
|
|
168
|
-
<img src='https://github.com/
|
|
166
|
+
<td id='manu-wallner'>
|
|
167
|
+
<a href='https://github.com/milch'>
|
|
168
|
+
<img src='https://github.com/milch.png' width='140px;'>
|
|
169
169
|
</a>
|
|
170
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
170
|
+
<h4 align='center'><a href='https://twitter.com/acrooow'>Manu Wallner</a></h4>
|
|
171
171
|
</td>
|
|
172
|
-
<td id='
|
|
173
|
-
<a href='https://github.com/
|
|
174
|
-
<img src='https://github.com/
|
|
172
|
+
<td id='andrew-mcburney'>
|
|
173
|
+
<a href='https://github.com/armcburney'>
|
|
174
|
+
<img src='https://github.com/armcburney.png' width='140px;'>
|
|
175
175
|
</a>
|
|
176
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
176
|
+
<h4 align='center'><a href='https://twitter.com/armcburney'>Andrew McBurney</a></h4>
|
|
177
177
|
</td>
|
|
178
|
-
<td id='
|
|
179
|
-
<a href='https://github.com/
|
|
180
|
-
<img src='https://github.com/
|
|
178
|
+
<td id='olivier-halligon'>
|
|
179
|
+
<a href='https://github.com/AliSoftware'>
|
|
180
|
+
<img src='https://github.com/AliSoftware.png' width='140px;'>
|
|
181
181
|
</a>
|
|
182
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
182
|
+
<h4 align='center'><a href='https://twitter.com/aligatr'>Olivier Halligon</a></h4>
|
|
183
183
|
</td>
|
|
184
|
-
<td id='
|
|
185
|
-
<a href='https://github.com/
|
|
186
|
-
<img src='https://github.com/
|
|
184
|
+
<td id='iulian-onofrei'>
|
|
185
|
+
<a href='https://github.com/revolter'>
|
|
186
|
+
<img src='https://github.com/revolter.png' width='140px;'>
|
|
187
187
|
</a>
|
|
188
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
188
|
+
<h4 align='center'><a href='https://twitter.com/Revolt666'>Iulian Onofrei</a></h4>
|
|
189
189
|
</td>
|
|
190
|
-
<td id='
|
|
191
|
-
<a href='https://github.com/
|
|
192
|
-
<img src='https://github.com/
|
|
190
|
+
<td id='stefan-natchev'>
|
|
191
|
+
<a href='https://github.com/snatchev'>
|
|
192
|
+
<img src='https://github.com/snatchev.png' width='140px;'>
|
|
193
193
|
</a>
|
|
194
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
194
|
+
<h4 align='center'><a href='https://twitter.com/snatchev'>Stefan Natchev</a></h4>
|
|
195
195
|
</td>
|
|
196
196
|
</tr>
|
|
197
197
|
</table>
|
|
@@ -324,7 +324,8 @@ module Deliver
|
|
|
324
324
|
is_3rd_gen = [
|
|
325
325
|
"iPad Pro (12.9-inch) (3rd generation)", # default simulator name has this
|
|
326
326
|
"iPad Pro (12.9-inch) (4th generation)", # default simulator name has this
|
|
327
|
-
"ipadPro129" # downloaded screenshots name has this
|
|
327
|
+
"ipadPro129", # downloaded screenshots name has this,
|
|
328
|
+
"3GEN" # downloaded screenshots name from App Store Connect API has this
|
|
328
329
|
].any? { |key| filename.include?(key) }
|
|
329
330
|
if is_3rd_gen
|
|
330
331
|
if screen_size == ScreenSize::IOS_IPAD_PRO
|
|
@@ -85,8 +85,8 @@ module Deliver
|
|
|
85
85
|
app_screenshot_set ||= localization.create_app_screenshot_set(attributes: { screenshotDisplayType: display_type })
|
|
86
86
|
|
|
87
87
|
# iterate over screenshots per display size with index
|
|
88
|
-
screenshots.each do |screenshot|
|
|
89
|
-
yield(localization, app_screenshot_set, screenshot)
|
|
88
|
+
screenshots.each.with_index do |screenshot, index|
|
|
89
|
+
yield(localization, app_screenshot_set, screenshot, index)
|
|
90
90
|
end
|
|
91
91
|
end
|
|
92
92
|
end
|
|
@@ -82,7 +82,7 @@ module Deliver
|
|
|
82
82
|
#
|
|
83
83
|
# @param root [String] A directory path
|
|
84
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
|
|
85
|
+
# @return [Array<Deliver::AppScreenshot>] The list of AppScreenshot that exist under given `root` directory
|
|
86
86
|
def self.load_app_screenshots(root, ignore_validation)
|
|
87
87
|
screenshots = language_folders(root, ignore_validation, true).flat_map do |language_folder|
|
|
88
88
|
paths = if language_folder.framed_file_paths.count > 0
|
|
@@ -162,6 +162,12 @@ module Deliver
|
|
|
162
162
|
description: "Clear all previously uploaded screenshots before uploading the new ones",
|
|
163
163
|
type: Boolean,
|
|
164
164
|
default_value: false),
|
|
165
|
+
FastlaneCore::ConfigItem.new(key: :sync_screenshots,
|
|
166
|
+
env_name: "DELIVER_SYNC_SCREENSHOTS",
|
|
167
|
+
description: "Sync screenshots with local ones. This is currently beta option" \
|
|
168
|
+
"so set true to 'FASTLANE_ENABLE_BETA_DELIVER_SYNC_SCREENSHOTS' environment variable as well",
|
|
169
|
+
type: Boolean,
|
|
170
|
+
default_value: false),
|
|
165
171
|
FastlaneCore::ConfigItem.new(key: :submit_for_review,
|
|
166
172
|
env_name: "DELIVER_SUBMIT_FOR_REVIEW",
|
|
167
173
|
description: "Submit the new version for Review after uploading everything",
|
|
@@ -10,6 +10,7 @@ require_relative 'submit_for_review'
|
|
|
10
10
|
require_relative 'upload_price_tier'
|
|
11
11
|
require_relative 'upload_metadata'
|
|
12
12
|
require_relative 'upload_screenshots'
|
|
13
|
+
require_relative 'sync_screenshots'
|
|
13
14
|
require_relative 'detect_values'
|
|
14
15
|
|
|
15
16
|
module Deliver
|
|
@@ -143,7 +144,14 @@ module Deliver
|
|
|
143
144
|
|
|
144
145
|
# Commit
|
|
145
146
|
upload_metadata.upload(options)
|
|
146
|
-
|
|
147
|
+
|
|
148
|
+
if options[:sync_screenshots]
|
|
149
|
+
sync_screenshots = SyncScreenshots.new(app: Deliver.cache[:app], platform: Spaceship::ConnectAPI::Platform.map(options[:platform]))
|
|
150
|
+
sync_screenshots.sync(screenshots)
|
|
151
|
+
else
|
|
152
|
+
upload_screenshots.upload(options, screenshots)
|
|
153
|
+
end
|
|
154
|
+
|
|
147
155
|
UploadPriceTier.new.upload(options)
|
|
148
156
|
end
|
|
149
157
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require 'spaceship/connect_api/models/app_screenshot'
|
|
2
|
+
require 'spaceship/connect_api/models/app_screenshot_set'
|
|
3
|
+
|
|
4
|
+
require_relative 'app_screenshot'
|
|
5
|
+
|
|
6
|
+
module Deliver
|
|
7
|
+
# This clsas enables you to compare equality between different representations of the screenshots
|
|
8
|
+
# in the standard API `Array#-` that requires objects to implements `eql?` and `hash`.
|
|
9
|
+
class ScreenshotComparable
|
|
10
|
+
# A unique key value that is consist of locale, filename, and checksum.
|
|
11
|
+
attr_reader :key
|
|
12
|
+
|
|
13
|
+
# A hash object that contains the source data of this representation class
|
|
14
|
+
attr_reader :context
|
|
15
|
+
|
|
16
|
+
def self.create_from_local(screenshot:, app_screenshot_set:)
|
|
17
|
+
raise ArgumentError unless screenshot.kind_of?(Deliver::AppScreenshot)
|
|
18
|
+
raise ArgumentError unless app_screenshot_set.kind_of?(Spaceship::ConnectAPI::AppScreenshotSet)
|
|
19
|
+
|
|
20
|
+
new(
|
|
21
|
+
path: "#{screenshot.language}/#{File.basename(screenshot.path)}",
|
|
22
|
+
checksum: calculate_checksum(screenshot.path),
|
|
23
|
+
context: {
|
|
24
|
+
screenshot: screenshot,
|
|
25
|
+
app_screenshot_set: app_screenshot_set
|
|
26
|
+
}
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.create_from_remote(app_screenshot:, locale:)
|
|
31
|
+
raise ArgumentError unless app_screenshot.kind_of?(Spaceship::ConnectAPI::AppScreenshot)
|
|
32
|
+
raise ArgumentError unless locale.kind_of?(String)
|
|
33
|
+
|
|
34
|
+
new(
|
|
35
|
+
path: "#{locale}/#{app_screenshot.file_name}",
|
|
36
|
+
checksum: app_screenshot.source_file_checksum,
|
|
37
|
+
context: {
|
|
38
|
+
app_screenshot: app_screenshot,
|
|
39
|
+
locale: locale
|
|
40
|
+
}
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.calculate_checksum(path)
|
|
45
|
+
bytes = File.binread(path)
|
|
46
|
+
Digest::MD5.hexdigest(bytes)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def initialize(path:, checksum:, context:)
|
|
50
|
+
@key = "#{path}/#{checksum}"
|
|
51
|
+
@context = context
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def eql?(other)
|
|
55
|
+
key == other.key
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def hash
|
|
59
|
+
key.hash
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
require 'fastlane_core'
|
|
2
|
+
require 'digest/md5'
|
|
3
|
+
require 'naturally'
|
|
4
|
+
|
|
5
|
+
require_relative 'app_screenshot'
|
|
6
|
+
require_relative 'app_screenshot_iterator'
|
|
7
|
+
require_relative 'loader'
|
|
8
|
+
require_relative 'screenshot_comparable'
|
|
9
|
+
|
|
10
|
+
module Deliver
|
|
11
|
+
class SyncScreenshots
|
|
12
|
+
DeleteScreenshotJob = Struct.new(:app_screenshot, :locale)
|
|
13
|
+
UploadScreenshotJob = Struct.new(:app_screenshot_set, :path)
|
|
14
|
+
|
|
15
|
+
class UploadResult
|
|
16
|
+
attr_reader :asset_delivery_state_counts, :failing_screenshots
|
|
17
|
+
|
|
18
|
+
def initialize(asset_delivery_state_counts:, failing_screenshots:)
|
|
19
|
+
@asset_delivery_state_counts = asset_delivery_state_counts
|
|
20
|
+
@failing_screenshots = failing_screenshots
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def processing?
|
|
24
|
+
@asset_delivery_state_counts.fetch('UPLOAD_COMPLETE', 0) > 0
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def screenshot_count
|
|
28
|
+
@asset_delivery_state_counts.fetch('COMPLETE', 0)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def initialize(app:, platform:)
|
|
33
|
+
@app = app
|
|
34
|
+
@platform = platform
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def sync_from_path(screenshots_path)
|
|
38
|
+
# load local screenshots
|
|
39
|
+
screenshots = Deliver::Loader.load_app_screenshots(screenshots_path, true)
|
|
40
|
+
sync(screenshots)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def sync(screenshots)
|
|
44
|
+
UI.important('This is currently a beta feature in fastlane. This may cause some errors on your environment.')
|
|
45
|
+
|
|
46
|
+
unless FastlaneCore::Feature.enabled?('FASTLANE_ENABLE_BETA_DELIVER_SYNC_SCREENSHOTS')
|
|
47
|
+
UI.user_error!('Please set a value to "FASTLANE_ENABLE_BETA_DELIVER_SYNC_SCREENSHOTS" environment variable ' \
|
|
48
|
+
'if you acknowleage the risk and try this out.')
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
UI.important("Will begin uploading snapshots for '#{version.version_string}' on App Store Connect")
|
|
52
|
+
|
|
53
|
+
# enable localizations that will be used
|
|
54
|
+
screenshots_per_language = screenshots.group_by(&:language)
|
|
55
|
+
enable_localizations(screenshots_per_language.keys)
|
|
56
|
+
|
|
57
|
+
# create iterator
|
|
58
|
+
localizations = fetch_localizations
|
|
59
|
+
iterator = Deliver::AppScreenshotIterator.new(localizations)
|
|
60
|
+
|
|
61
|
+
# sync local screenshots with remote settings by deleting and uploading
|
|
62
|
+
UI.message("Starting with the upload of screenshots...")
|
|
63
|
+
replace_screenshots(iterator, screenshots)
|
|
64
|
+
|
|
65
|
+
# ensure screenshots within screenshot sets are sorted in right order
|
|
66
|
+
sort_screenshots(iterator)
|
|
67
|
+
|
|
68
|
+
UI.important('Screenshots are synced successfully!')
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def enable_localizations(locales)
|
|
72
|
+
localizations = fetch_localizations
|
|
73
|
+
locales_to_enable = locales - localizations.map(&:locale)
|
|
74
|
+
Helper.show_loading_indicator("Activating localizations for #{locales_to_enable.join(', ')}...")
|
|
75
|
+
locales_to_enable.each do |locale|
|
|
76
|
+
version.create_app_store_version_localization(attributes: { locale: locale })
|
|
77
|
+
end
|
|
78
|
+
Helper.hide_loading_indicator
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def replace_screenshots(iterator, screenshots, retries = 3)
|
|
82
|
+
# delete and upload screenshots to get App Store Connect in sync
|
|
83
|
+
do_replace_screenshots(iterator, screenshots, create_delete_worker, create_upload_worker)
|
|
84
|
+
|
|
85
|
+
# wait for screenshots to be processed on App Store Connect end and
|
|
86
|
+
# ensure the number of uploaded screenshots matches the one in local
|
|
87
|
+
result = wait_for_complete(iterator)
|
|
88
|
+
return if !result.processing? && result.screenshot_count == screenshots.count
|
|
89
|
+
|
|
90
|
+
if retries.zero?
|
|
91
|
+
UI.crash!("Retried uploading screenshots #{retries} but there are still failures of processing screenshots." \
|
|
92
|
+
"Check App Store Connect console to work out which screenshots processed unsuccessfully.")
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# retry with deleting failing screenshots
|
|
96
|
+
result.failing_screenshots.each(&:delete!)
|
|
97
|
+
replace_screenshots(iterator, screenshots, retries - 1)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# This is a testable method that focuses on figuring out what to update
|
|
101
|
+
def do_replace_screenshots(iterator, screenshots, delete_worker, upload_worker)
|
|
102
|
+
remote_screenshots = iterator.each_app_screenshot.map do |localization, app_screenshot_set, app_screenshot|
|
|
103
|
+
ScreenshotComparable.create_from_remote(app_screenshot: app_screenshot, locale: localization.locale)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
local_screenshots = iterator.each_local_screenshot(screenshots.group_by(&:language)).map do |localization, app_screenshot_set, screenshot, index|
|
|
107
|
+
if index >= 10
|
|
108
|
+
UI.user_error!("Found #{localization.locale} has more than 10 screenshots for #{app_screenshot_set.screenshot_display_type}. "\
|
|
109
|
+
"Make sure containts only necessary screenshots.")
|
|
110
|
+
end
|
|
111
|
+
ScreenshotComparable.create_from_local(screenshot: screenshot, app_screenshot_set: app_screenshot_set)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Thanks to `Array#-` API and `ScreenshotComparable`, working out diffs between local screenshot directory and App Store Connect
|
|
115
|
+
# is as easy as you can see below. The former one finds what is missing in local and the latter one is visa versa.
|
|
116
|
+
screenshots_to_delete = remote_screenshots - local_screenshots
|
|
117
|
+
screenshots_to_upload = local_screenshots - remote_screenshots
|
|
118
|
+
|
|
119
|
+
delete_jobs = screenshots_to_delete.map { |x| DeleteScreenshotJob.new(x.context[:app_screenshot], x.context[:locale]) }
|
|
120
|
+
delete_worker.batch_enqueue(delete_jobs)
|
|
121
|
+
delete_worker.start
|
|
122
|
+
|
|
123
|
+
upload_jobs = screenshots_to_upload.map { |x| UploadScreenshotJob.new(x.context[:app_screenshot_set], x.context[:screenshot].path) }
|
|
124
|
+
upload_worker.batch_enqueue(upload_jobs)
|
|
125
|
+
upload_worker.start
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def wait_for_complete(iterator)
|
|
129
|
+
retry_count = 0
|
|
130
|
+
Helper.show_loading_indicator("Waiting for all the screenshots processed...")
|
|
131
|
+
loop do
|
|
132
|
+
failing_screenshots = []
|
|
133
|
+
state_counts = iterator.each_app_screenshot.map { |_, _, app_screenshot| app_screenshot }.each_with_object({}) do |app_screenshot, hash|
|
|
134
|
+
state = app_screenshot.asset_delivery_state['state']
|
|
135
|
+
hash[state] ||= 0
|
|
136
|
+
hash[state] += 1
|
|
137
|
+
failing_screenshots << app_screenshot if app_screenshot.error?
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
result = UploadResult.new(asset_delivery_state_counts: state_counts, failing_screenshots: failing_screenshots)
|
|
141
|
+
return result unless result.processing?
|
|
142
|
+
|
|
143
|
+
# sleep with exponential backoff
|
|
144
|
+
interval = 5 + (2**retry_count)
|
|
145
|
+
UI.message("There are still incomplete screenshots. Will check the states again in #{interval} secs - #{state_counts}")
|
|
146
|
+
sleep(interval)
|
|
147
|
+
retry_count += 1
|
|
148
|
+
end
|
|
149
|
+
ensure
|
|
150
|
+
Helper.hide_loading_indicator
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def sort_screenshots(iterator)
|
|
154
|
+
Helper.show_loading_indicator("Sorting screenshots uploaded...")
|
|
155
|
+
sort_worker = create_sort_worker
|
|
156
|
+
sort_worker.batch_enqueue(iterator.each_app_screenshot_set.to_a.map { |_, set| set })
|
|
157
|
+
sort_worker.start
|
|
158
|
+
Helper.hide_loading_indicator
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
private
|
|
162
|
+
|
|
163
|
+
def version
|
|
164
|
+
@version ||= @app.get_edit_app_store_version(platform: @platform)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def fetch_localizations
|
|
168
|
+
version.get_app_store_version_localizations
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def create_upload_worker
|
|
172
|
+
FastlaneCore::QueueWorker.new do |job|
|
|
173
|
+
UI.verbose("Uploading '#{job.path}'...")
|
|
174
|
+
start_time = Time.now
|
|
175
|
+
job.app_screenshot_set.upload_screenshot(path: job.path, wait_for_processing: false)
|
|
176
|
+
UI.message("Uploaded '#{job.path}'... (#{Time.now - start_time} secs)")
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def create_delete_worker
|
|
181
|
+
FastlaneCore::QueueWorker.new do |job|
|
|
182
|
+
target = "id=#{job.app_screenshot.id} #{job.locale} #{job.app_screenshot.file_name}"
|
|
183
|
+
UI.verbose("Deleting '#{target}'")
|
|
184
|
+
start_time = Time.now
|
|
185
|
+
job.app_screenshot.delete!
|
|
186
|
+
UI.message("Deleted '#{target}' - (#{Time.now - start_time} secs)")
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def create_sort_worker
|
|
191
|
+
FastlaneCore::QueueWorker.new do |app_screenshot_set|
|
|
192
|
+
original_ids = app_screenshot_set.app_screenshots.map(&:id)
|
|
193
|
+
sorted_ids = Naturally.sort(app_screenshot_set.app_screenshots, by: :file_name).map(&:id)
|
|
194
|
+
if original_ids != sorted_ids
|
|
195
|
+
app_screenshot_set.reorder_screenshots(app_screenshot_ids: sorted_ids)
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|