fastlane 2.190.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 +88 -88
- 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/zip.rb +3 -2
- data/fastlane/lib/fastlane/features.rb +3 -0
- 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 +13 -1
- 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 +1 -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 +2 -2
- data/produce/lib/produce/commands_generator.rb +28 -0
- data/produce/lib/produce/service.rb +15 -0
- 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/provisioning/provisioning.rb +5 -0
- data/spaceship/lib/spaceship/connect_api/users/users.rb +34 -1
- data/supply/lib/supply/uploader.rb +1 -1
- metadata +24 -21
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,11 +35,11 @@ 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
44
|
<td id='aaron-brager'>
|
|
45
45
|
<a href='https://github.com/getaaron'>
|
|
@@ -47,11 +47,17 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
|
|
|
47
47
|
</a>
|
|
48
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
|
+
</td>
|
|
56
|
+
<td id='luka-mirosevic'>
|
|
57
|
+
<a href='https://github.com/lmirosevic'>
|
|
58
|
+
<img src='https://github.com/lmirosevic.png' width='140px;'>
|
|
59
|
+
</a>
|
|
60
|
+
<h4 align='center'><a href='https://twitter.com/lmirosevic'>Luka Mirosevic</a></h4>
|
|
55
61
|
</td>
|
|
56
62
|
<td id='satoshi-namai'>
|
|
57
63
|
<a href='https://github.com/ainame'>
|
|
@@ -59,51 +65,51 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
|
|
|
59
65
|
</a>
|
|
60
66
|
<h4 align='center'><a href='https://twitter.com/ainame'>Satoshi Namai</a></h4>
|
|
61
67
|
</td>
|
|
62
|
-
<td id='manish-rathi'>
|
|
63
|
-
<a href='https://github.com/crazymanish'>
|
|
64
|
-
<img src='https://github.com/crazymanish.png' width='140px;'>
|
|
65
|
-
</a>
|
|
66
|
-
<h4 align='center'><a href='https://twitter.com/iammanishrathi'>Manish Rathi</a></h4>
|
|
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
|
-
<td id='
|
|
77
|
-
<a href='https://github.com/
|
|
78
|
-
<img src='https://github.com/
|
|
76
|
+
<td id='maksym-grebenets'>
|
|
77
|
+
<a href='https://github.com/mgrebenets'>
|
|
78
|
+
<img src='https://github.com/mgrebenets.png' width='140px;'>
|
|
79
79
|
</a>
|
|
80
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
80
|
+
<h4 align='center'><a href='https://twitter.com/mgrebenets'>Maksym Grebenets</a></h4>
|
|
81
81
|
</td>
|
|
82
|
-
<td id='
|
|
83
|
-
<a href='https://github.com/
|
|
84
|
-
<img src='https://github.com/
|
|
82
|
+
<td id='felix-krause'>
|
|
83
|
+
<a href='https://github.com/KrauseFx'>
|
|
84
|
+
<img src='https://github.com/KrauseFx.png' width='140px;'>
|
|
85
85
|
</a>
|
|
86
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
86
|
+
<h4 align='center'><a href='https://twitter.com/KrauseFx'>Felix Krause</a></h4>
|
|
87
87
|
</td>
|
|
88
|
-
<td id='
|
|
89
|
-
<a href='https://github.com/
|
|
90
|
-
<img src='https://github.com/
|
|
88
|
+
<td id='kohki-miki'>
|
|
89
|
+
<a href='https://github.com/giginet'>
|
|
90
|
+
<img src='https://github.com/giginet.png' width='140px;'>
|
|
91
91
|
</a>
|
|
92
|
-
<h4 align='center'><a href='https://twitter.com/
|
|
92
|
+
<h4 align='center'><a href='https://twitter.com/giginet'>Kohki Miki</a></h4>
|
|
93
93
|
</td>
|
|
94
|
-
<td id='
|
|
95
|
-
<a href='https://github.com/
|
|
96
|
-
<img src='https://github.com/
|
|
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
|
+
</td>
|
|
108
|
+
<td id='roger-oba'>
|
|
109
|
+
<a href='https://github.com/rogerluan'>
|
|
110
|
+
<img src='https://github.com/rogerluan.png' width='140px;'>
|
|
111
|
+
</a>
|
|
112
|
+
<h4 align='center'><a href='https://twitter.com/rogerluan_'>Roger Oba</a></h4>
|
|
107
113
|
</td>
|
|
108
114
|
<td id='matthew-ellis'>
|
|
109
115
|
<a href='https://github.com/matthewellis'>
|
|
@@ -111,31 +117,31 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
|
|
|
111
117
|
</a>
|
|
112
118
|
<h4 align='center'><a href='https://twitter.com/mellis1995'>Matthew Ellis</a></h4>
|
|
113
119
|
</td>
|
|
114
|
-
<td id='
|
|
115
|
-
<a href='https://github.com/
|
|
116
|
-
<img src='https://github.com/
|
|
117
|
-
</a>
|
|
118
|
-
<h4 align='center'><a href='https://twitter.com/KrauseFx'>Felix Krause</a></h4>
|
|
119
|
-
</td>
|
|
120
|
-
<td id='maksym-grebenets'>
|
|
121
|
-
<a href='https://github.com/mgrebenets'>
|
|
122
|
-
<img src='https://github.com/mgrebenets.png' width='140px;'>
|
|
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'><a href='https://twitter.com/
|
|
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'>
|
|
138
|
+
<h4 align='center'><a href='https://twitter.com/iammanishrathi'>Manish Rathi</a></h4>
|
|
139
|
+
</td>
|
|
140
|
+
<td id='danielle-tomlinson'>
|
|
141
|
+
<a href='https://github.com/endocrimes'>
|
|
142
|
+
<img src='https://github.com/endocrimes.png' width='140px;'>
|
|
143
|
+
</a>
|
|
144
|
+
<h4 align='center'><a href='https://twitter.com/endocrimes'>Danielle Tomlinson</a></h4>
|
|
139
145
|
</td>
|
|
140
146
|
<td id='joshua-liebowitz'>
|
|
141
147
|
<a href='https://github.com/taquitos'>
|
|
@@ -143,55 +149,49 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
|
|
|
143
149
|
</a>
|
|
144
150
|
<h4 align='center'><a href='https://twitter.com/taquitos'>Joshua Liebowitz</a></h4>
|
|
145
151
|
</td>
|
|
152
|
+
<td id='fumiya-nakamura'>
|
|
153
|
+
<a href='https://github.com/nafu'>
|
|
154
|
+
<img src='https://github.com/nafu.png' width='140px;'>
|
|
155
|
+
</a>
|
|
156
|
+
<h4 align='center'><a href='https://twitter.com/nafu003'>Fumiya Nakamura</a></h4>
|
|
157
|
+
</td>
|
|
146
158
|
<td id='jérôme-lacoste'>
|
|
147
159
|
<a href='https://github.com/lacostej'>
|
|
148
160
|
<img src='https://github.com/lacostej.png' width='140px;'>
|
|
149
161
|
</a>
|
|
150
162
|
<h4 align='center'><a href='https://twitter.com/lacostej'>Jérôme Lacoste</a></h4>
|
|
151
163
|
</td>
|
|
152
|
-
<td id='stefan-natchev'>
|
|
153
|
-
<a href='https://github.com/snatchev'>
|
|
154
|
-
<img src='https://github.com/snatchev.png' width='140px;'>
|
|
155
|
-
</a>
|
|
156
|
-
<h4 align='center'><a href='https://twitter.com/snatchev'>Stefan Natchev</a></h4>
|
|
157
|
-
</td>
|
|
158
|
-
<td id='iulian-onofrei'>
|
|
159
|
-
<a href='https://github.com/revolter'>
|
|
160
|
-
<img src='https://github.com/revolter.png' width='140px;'>
|
|
161
|
-
</a>
|
|
162
|
-
<h4 align='center'><a href='https://twitter.com/Revolt666'>Iulian Onofrei</a></h4>
|
|
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
|
|
@@ -52,8 +52,8 @@ module Fastlane
|
|
|
52
52
|
# The zip command is executed from the paths **parent** directory, as a result we use just the basename, which is the file or folder within
|
|
53
53
|
basename = File.basename(path)
|
|
54
54
|
|
|
55
|
-
command << output_path
|
|
56
|
-
command << basename
|
|
55
|
+
command << output_path.shellescape
|
|
56
|
+
command << basename.shellescape
|
|
57
57
|
|
|
58
58
|
unless include.empty?
|
|
59
59
|
command << "-i"
|
|
@@ -68,6 +68,7 @@ module Fastlane
|
|
|
68
68
|
command
|
|
69
69
|
end
|
|
70
70
|
end
|
|
71
|
+
|
|
71
72
|
def self.run(params)
|
|
72
73
|
Runner.new(params).run
|
|
73
74
|
end
|
|
@@ -2,3 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
# FastlaneCore::Feature.register(env_var: 'YOUR_FEATURE_SWITCH_ENV_VAR',
|
|
4
4
|
# description: 'Describe what this feature switch controls')
|
|
5
|
+
|
|
6
|
+
FastlaneCore::Feature.register(env_var: 'FASTLANE_ENABLE_BETA_DELIVER_SYNC_SCREENSHOTS',
|
|
7
|
+
description: 'Use a newly implemented screenshots synchronization logic')
|
|
@@ -59,6 +59,9 @@ public protocol DeliverfileProtocol: class {
|
|
|
59
59
|
/// Clear all previously uploaded screenshots before uploading the new ones
|
|
60
60
|
var overwriteScreenshots: Bool { get }
|
|
61
61
|
|
|
62
|
+
/// Sync screenshots with local ones. This is currently beta optionso set true to 'FASTLANE_ENABLE_BETA_DELIVER_SYNC_SCREENSHOTS' environment variable as well
|
|
63
|
+
var syncScreenshots: Bool { get }
|
|
64
|
+
|
|
62
65
|
/// Submit the new version for Review after uploading everything
|
|
63
66
|
var submitForReview: Bool { get }
|
|
64
67
|
|
|
@@ -209,6 +212,7 @@ public extension DeliverfileProtocol {
|
|
|
209
212
|
var skipAppVersionUpdate: Bool { return false }
|
|
210
213
|
var force: Bool { return false }
|
|
211
214
|
var overwriteScreenshots: Bool { return false }
|
|
215
|
+
var syncScreenshots: Bool { return false }
|
|
212
216
|
var submitForReview: Bool { return false }
|
|
213
217
|
var rejectIfPossible: Bool { return false }
|
|
214
218
|
var automaticRelease: Bool? { return nil }
|
|
@@ -256,4 +260,4 @@ public extension DeliverfileProtocol {
|
|
|
256
260
|
|
|
257
261
|
// Please don't remove the lines below
|
|
258
262
|
// They are used to detect outdated files
|
|
259
|
-
// FastlaneRunnerAPIVersion [0.9.
|
|
263
|
+
// FastlaneRunnerAPIVersion [0.9.79]
|
|
@@ -661,6 +661,7 @@ public func appledoc(input: [String],
|
|
|
661
661
|
- skipAppVersionUpdate: Don’t create or update the app version that is being prepared for submission
|
|
662
662
|
- force: Skip verification of HTML preview file
|
|
663
663
|
- overwriteScreenshots: Clear all previously uploaded screenshots before uploading the new ones
|
|
664
|
+
- syncScreenshots: Sync screenshots with local ones. This is currently beta optionso set true to 'FASTLANE_ENABLE_BETA_DELIVER_SYNC_SCREENSHOTS' environment variable as well
|
|
664
665
|
- submitForReview: Submit the new version for Review after uploading everything
|
|
665
666
|
- rejectIfPossible: Rejects the previously submitted build if it's in a state where it's possible
|
|
666
667
|
- automaticRelease: Should the app be automatically released once it's approved? (Can not be used together with `auto_release_date`)
|
|
@@ -731,6 +732,7 @@ public func appstore(apiKeyPath: OptionalConfigValue<String?> = .fastlaneDefault
|
|
|
731
732
|
skipAppVersionUpdate: OptionalConfigValue<Bool> = .fastlaneDefault(false),
|
|
732
733
|
force: OptionalConfigValue<Bool> = .fastlaneDefault(false),
|
|
733
734
|
overwriteScreenshots: OptionalConfigValue<Bool> = .fastlaneDefault(false),
|
|
735
|
+
syncScreenshots: OptionalConfigValue<Bool> = .fastlaneDefault(false),
|
|
734
736
|
submitForReview: OptionalConfigValue<Bool> = .fastlaneDefault(false),
|
|
735
737
|
rejectIfPossible: OptionalConfigValue<Bool> = .fastlaneDefault(false),
|
|
736
738
|
automaticRelease: OptionalConfigValue<Bool?> = .fastlaneDefault(nil),
|
|
@@ -794,6 +796,7 @@ public func appstore(apiKeyPath: OptionalConfigValue<String?> = .fastlaneDefault
|
|
|
794
796
|
let skipAppVersionUpdateArg = skipAppVersionUpdate.asRubyArgument(name: "skip_app_version_update", type: nil)
|
|
795
797
|
let forceArg = force.asRubyArgument(name: "force", type: nil)
|
|
796
798
|
let overwriteScreenshotsArg = overwriteScreenshots.asRubyArgument(name: "overwrite_screenshots", type: nil)
|
|
799
|
+
let syncScreenshotsArg = syncScreenshots.asRubyArgument(name: "sync_screenshots", type: nil)
|
|
797
800
|
let submitForReviewArg = submitForReview.asRubyArgument(name: "submit_for_review", type: nil)
|
|
798
801
|
let rejectIfPossibleArg = rejectIfPossible.asRubyArgument(name: "reject_if_possible", type: nil)
|
|
799
802
|
let automaticReleaseArg = automaticRelease.asRubyArgument(name: "automatic_release", type: nil)
|
|
@@ -856,6 +859,7 @@ public func appstore(apiKeyPath: OptionalConfigValue<String?> = .fastlaneDefault
|
|
|
856
859
|
skipAppVersionUpdateArg,
|
|
857
860
|
forceArg,
|
|
858
861
|
overwriteScreenshotsArg,
|
|
862
|
+
syncScreenshotsArg,
|
|
859
863
|
submitForReviewArg,
|
|
860
864
|
rejectIfPossibleArg,
|
|
861
865
|
automaticReleaseArg,
|
|
@@ -3668,6 +3672,7 @@ public func deleteKeychain(name: OptionalConfigValue<String?> = .fastlaneDefault
|
|
|
3668
3672
|
- skipAppVersionUpdate: Don’t create or update the app version that is being prepared for submission
|
|
3669
3673
|
- force: Skip verification of HTML preview file
|
|
3670
3674
|
- overwriteScreenshots: Clear all previously uploaded screenshots before uploading the new ones
|
|
3675
|
+
- syncScreenshots: Sync screenshots with local ones. This is currently beta optionso set true to 'FASTLANE_ENABLE_BETA_DELIVER_SYNC_SCREENSHOTS' environment variable as well
|
|
3671
3676
|
- submitForReview: Submit the new version for Review after uploading everything
|
|
3672
3677
|
- rejectIfPossible: Rejects the previously submitted build if it's in a state where it's possible
|
|
3673
3678
|
- automaticRelease: Should the app be automatically released once it's approved? (Can not be used together with `auto_release_date`)
|
|
@@ -3738,6 +3743,7 @@ public func deliver(apiKeyPath: OptionalConfigValue<String?> = .fastlaneDefault(
|
|
|
3738
3743
|
skipAppVersionUpdate: OptionalConfigValue<Bool> = .fastlaneDefault(deliverfile.skipAppVersionUpdate),
|
|
3739
3744
|
force: OptionalConfigValue<Bool> = .fastlaneDefault(deliverfile.force),
|
|
3740
3745
|
overwriteScreenshots: OptionalConfigValue<Bool> = .fastlaneDefault(deliverfile.overwriteScreenshots),
|
|
3746
|
+
syncScreenshots: OptionalConfigValue<Bool> = .fastlaneDefault(deliverfile.syncScreenshots),
|
|
3741
3747
|
submitForReview: OptionalConfigValue<Bool> = .fastlaneDefault(deliverfile.submitForReview),
|
|
3742
3748
|
rejectIfPossible: OptionalConfigValue<Bool> = .fastlaneDefault(deliverfile.rejectIfPossible),
|
|
3743
3749
|
automaticRelease: OptionalConfigValue<Bool?> = .fastlaneDefault(deliverfile.automaticRelease),
|
|
@@ -3801,6 +3807,7 @@ public func deliver(apiKeyPath: OptionalConfigValue<String?> = .fastlaneDefault(
|
|
|
3801
3807
|
let skipAppVersionUpdateArg = skipAppVersionUpdate.asRubyArgument(name: "skip_app_version_update", type: nil)
|
|
3802
3808
|
let forceArg = force.asRubyArgument(name: "force", type: nil)
|
|
3803
3809
|
let overwriteScreenshotsArg = overwriteScreenshots.asRubyArgument(name: "overwrite_screenshots", type: nil)
|
|
3810
|
+
let syncScreenshotsArg = syncScreenshots.asRubyArgument(name: "sync_screenshots", type: nil)
|
|
3804
3811
|
let submitForReviewArg = submitForReview.asRubyArgument(name: "submit_for_review", type: nil)
|
|
3805
3812
|
let rejectIfPossibleArg = rejectIfPossible.asRubyArgument(name: "reject_if_possible", type: nil)
|
|
3806
3813
|
let automaticReleaseArg = automaticRelease.asRubyArgument(name: "automatic_release", type: nil)
|
|
@@ -3863,6 +3870,7 @@ public func deliver(apiKeyPath: OptionalConfigValue<String?> = .fastlaneDefault(
|
|
|
3863
3870
|
skipAppVersionUpdateArg,
|
|
3864
3871
|
forceArg,
|
|
3865
3872
|
overwriteScreenshotsArg,
|
|
3873
|
+
syncScreenshotsArg,
|
|
3866
3874
|
submitForReviewArg,
|
|
3867
3875
|
rejectIfPossibleArg,
|
|
3868
3876
|
automaticReleaseArg,
|
|
@@ -12004,6 +12012,7 @@ public func uploadSymbolsToSentry(apiHost: String = "https://app.getsentry.com/a
|
|
|
12004
12012
|
- skipAppVersionUpdate: Don’t create or update the app version that is being prepared for submission
|
|
12005
12013
|
- force: Skip verification of HTML preview file
|
|
12006
12014
|
- overwriteScreenshots: Clear all previously uploaded screenshots before uploading the new ones
|
|
12015
|
+
- syncScreenshots: Sync screenshots with local ones. This is currently beta optionso set true to 'FASTLANE_ENABLE_BETA_DELIVER_SYNC_SCREENSHOTS' environment variable as well
|
|
12007
12016
|
- submitForReview: Submit the new version for Review after uploading everything
|
|
12008
12017
|
- rejectIfPossible: Rejects the previously submitted build if it's in a state where it's possible
|
|
12009
12018
|
- automaticRelease: Should the app be automatically released once it's approved? (Can not be used together with `auto_release_date`)
|
|
@@ -12074,6 +12083,7 @@ public func uploadToAppStore(apiKeyPath: OptionalConfigValue<String?> = .fastlan
|
|
|
12074
12083
|
skipAppVersionUpdate: OptionalConfigValue<Bool> = .fastlaneDefault(false),
|
|
12075
12084
|
force: OptionalConfigValue<Bool> = .fastlaneDefault(false),
|
|
12076
12085
|
overwriteScreenshots: OptionalConfigValue<Bool> = .fastlaneDefault(false),
|
|
12086
|
+
syncScreenshots: OptionalConfigValue<Bool> = .fastlaneDefault(false),
|
|
12077
12087
|
submitForReview: OptionalConfigValue<Bool> = .fastlaneDefault(false),
|
|
12078
12088
|
rejectIfPossible: OptionalConfigValue<Bool> = .fastlaneDefault(false),
|
|
12079
12089
|
automaticRelease: OptionalConfigValue<Bool?> = .fastlaneDefault(nil),
|
|
@@ -12137,6 +12147,7 @@ public func uploadToAppStore(apiKeyPath: OptionalConfigValue<String?> = .fastlan
|
|
|
12137
12147
|
let skipAppVersionUpdateArg = skipAppVersionUpdate.asRubyArgument(name: "skip_app_version_update", type: nil)
|
|
12138
12148
|
let forceArg = force.asRubyArgument(name: "force", type: nil)
|
|
12139
12149
|
let overwriteScreenshotsArg = overwriteScreenshots.asRubyArgument(name: "overwrite_screenshots", type: nil)
|
|
12150
|
+
let syncScreenshotsArg = syncScreenshots.asRubyArgument(name: "sync_screenshots", type: nil)
|
|
12140
12151
|
let submitForReviewArg = submitForReview.asRubyArgument(name: "submit_for_review", type: nil)
|
|
12141
12152
|
let rejectIfPossibleArg = rejectIfPossible.asRubyArgument(name: "reject_if_possible", type: nil)
|
|
12142
12153
|
let automaticReleaseArg = automaticRelease.asRubyArgument(name: "automatic_release", type: nil)
|
|
@@ -12199,6 +12210,7 @@ public func uploadToAppStore(apiKeyPath: OptionalConfigValue<String?> = .fastlan
|
|
|
12199
12210
|
skipAppVersionUpdateArg,
|
|
12200
12211
|
forceArg,
|
|
12201
12212
|
overwriteScreenshotsArg,
|
|
12213
|
+
syncScreenshotsArg,
|
|
12202
12214
|
submitForReviewArg,
|
|
12203
12215
|
rejectIfPossibleArg,
|
|
12204
12216
|
automaticReleaseArg,
|
|
@@ -13201,4 +13213,4 @@ public let snapshotfile = Snapshotfile()
|
|
|
13201
13213
|
|
|
13202
13214
|
// Please don't remove the lines below
|
|
13203
13215
|
// They are used to detect outdated files
|
|
13204
|
-
// FastlaneRunnerAPIVersion [0.9.
|
|
13216
|
+
// FastlaneRunnerAPIVersion [0.9.132]
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"macOS": "11.0"
|
|
52
52
|
},
|
|
53
53
|
"monterey": {
|
|
54
|
-
"HOMEBREW_VERSION": "3.2.
|
|
54
|
+
"HOMEBREW_VERSION": "3.2.6-34-g6bb3699",
|
|
55
55
|
"HOMEBREW_PREFIX": "/usr/local",
|
|
56
|
-
"Homebrew/homebrew-core": "
|
|
56
|
+
"Homebrew/homebrew-core": "b7523de28df0f0f819ff2c49c84611eec19f5455",
|
|
57
57
|
"CLT": "13.0.0.0.1.1626155413",
|
|
58
58
|
"Xcode": "13.0",
|
|
59
59
|
"macOS": "12.0"
|
|
@@ -3,6 +3,7 @@ require 'commander'
|
|
|
3
3
|
require 'fastlane/version'
|
|
4
4
|
require 'fastlane_core/ui/help_formatter'
|
|
5
5
|
require 'fastlane_core/configuration/config_item'
|
|
6
|
+
require 'fastlane_core/print_table'
|
|
6
7
|
require_relative 'module'
|
|
7
8
|
require_relative 'manager'
|
|
8
9
|
require_relative 'options'
|
|
@@ -196,6 +197,33 @@ module Produce
|
|
|
196
197
|
end
|
|
197
198
|
end
|
|
198
199
|
|
|
200
|
+
command :available_services do |c|
|
|
201
|
+
c.syntax = 'fastlane produce available_services -a APP_IDENTIFIER'
|
|
202
|
+
c.description = 'Displays a list of allowed Application Services for a specific app.'
|
|
203
|
+
c.example('Check Available Services', 'fastlane produce available_services -a com.example.app')
|
|
204
|
+
|
|
205
|
+
FastlaneCore::CommanderGenerator.new.generate(Produce::Options.available_options, command: c)
|
|
206
|
+
|
|
207
|
+
c.action do |args, options|
|
|
208
|
+
# Filter the options so that we can still build the configuration
|
|
209
|
+
allowed_keys = Produce::Options.available_options.collect(&:key)
|
|
210
|
+
Produce.config = FastlaneCore::Configuration.create(Produce::Options.available_options, options.__hash__.select { |key, value| allowed_keys.include?(key) })
|
|
211
|
+
|
|
212
|
+
require 'produce/service'
|
|
213
|
+
require 'terminal-table'
|
|
214
|
+
|
|
215
|
+
services = Produce::Service.available_services(options, args)
|
|
216
|
+
rows = services.map { |capabilities| [capabilities.name, capabilities.id, capabilities.description] }
|
|
217
|
+
table = Terminal::Table.new(
|
|
218
|
+
title: "Available Services",
|
|
219
|
+
headings: ['Name', 'ID', 'Description'],
|
|
220
|
+
rows: FastlaneCore::PrintTable.transform_output(rows),
|
|
221
|
+
style: { all_separators: true }
|
|
222
|
+
)
|
|
223
|
+
puts(table)
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
199
227
|
command :group do |c|
|
|
200
228
|
c.syntax = 'fastlane produce group'
|
|
201
229
|
c.description = 'Ensure that a specific App Group exists'
|
|
@@ -16,6 +16,10 @@ module Produce
|
|
|
16
16
|
self.new.disable(options, args)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
def self.available_services(options, args)
|
|
20
|
+
self.new.available_services(options, args)
|
|
21
|
+
end
|
|
22
|
+
|
|
19
23
|
def enable(options, _args)
|
|
20
24
|
unless bundle_id
|
|
21
25
|
UI.message("[DevCenter] App '#{Produce.config[:app_identifier]}' does not exist")
|
|
@@ -40,6 +44,17 @@ module Produce
|
|
|
40
44
|
UI.success("Done! Disabled #{disabled} services.")
|
|
41
45
|
end
|
|
42
46
|
|
|
47
|
+
def available_services(options, _args)
|
|
48
|
+
unless bundle_id
|
|
49
|
+
UI.message("[DevCenter] App '#{Produce.config[:app_identifier]}' does not exist")
|
|
50
|
+
return
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
UI.success("[DevCenter] App found '#{bundle_id.name}'")
|
|
54
|
+
UI.message("Fetching available services")
|
|
55
|
+
return Spaceship::ConnectAPI::Capabilities.all
|
|
56
|
+
end
|
|
57
|
+
|
|
43
58
|
def valid_services_for(options)
|
|
44
59
|
allowed_keys = [:access_wifi, :app_attest, :app_group, :apple_pay, :associated_domains, :auto_fill_credential, :car_play_audio_app, :car_play_messaging_app,
|
|
45
60
|
:car_play_navigation_app, :car_play_voip_calling_app, :class_kit, :icloud, :critical_alerts, :custom_network_protocol, :data_protection,
|
|
@@ -10,6 +10,7 @@ require 'spaceship/connect_api/tunes/tunes'
|
|
|
10
10
|
|
|
11
11
|
require 'spaceship/connect_api/models/bundle_id_capability'
|
|
12
12
|
require 'spaceship/connect_api/models/bundle_id'
|
|
13
|
+
require 'spaceship/connect_api/models/capabilities'
|
|
13
14
|
require 'spaceship/connect_api/models/certificate'
|
|
14
15
|
require 'spaceship/connect_api/models/device'
|
|
15
16
|
require 'spaceship/connect_api/models/profile'
|
|
@@ -423,6 +423,13 @@ module Spaceship
|
|
|
423
423
|
client.add_user_visible_apps(user_id: user_id, app_ids: [id])
|
|
424
424
|
end
|
|
425
425
|
end
|
|
426
|
+
|
|
427
|
+
def remove_users(client: nil, user_ids: nil)
|
|
428
|
+
client ||= Spaceship::ConnectAPI
|
|
429
|
+
user_ids.each do |user_id|
|
|
430
|
+
client.delete_user_visible_apps(user_id: user_id, app_ids: [id])
|
|
431
|
+
end
|
|
432
|
+
end
|
|
426
433
|
end
|
|
427
434
|
end
|
|
428
435
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require_relative '../model'
|
|
2
|
+
|
|
3
|
+
module Spaceship
|
|
4
|
+
class ConnectAPI
|
|
5
|
+
class Capabilities
|
|
6
|
+
include Spaceship::ConnectAPI::Model
|
|
7
|
+
|
|
8
|
+
attr_accessor :name
|
|
9
|
+
attr_accessor :description
|
|
10
|
+
|
|
11
|
+
attr_mapping({
|
|
12
|
+
"name" => "name",
|
|
13
|
+
"description" => "description",
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
def self.type
|
|
17
|
+
return "capabilities"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.all(client: nil)
|
|
21
|
+
client ||= Spaceship::ConnectAPI
|
|
22
|
+
resp = client.get_available_bundle_id_capabilities(bundle_id_id: id).all_pages
|
|
23
|
+
return resp.flat_map(&:to_models)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -54,6 +54,11 @@ module Spaceship
|
|
|
54
54
|
provisioning_request_client.get("bundleIds/#{bundle_id_id}/bundleIdCapabilities", params)
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
def get_available_bundle_id_capabilities(bundle_id_id:)
|
|
58
|
+
params = provisioning_request_client.build_params(filter: { bundleId: bundle_id_id })
|
|
59
|
+
provisioning_request_client.get("capabilities", params)
|
|
60
|
+
end
|
|
61
|
+
|
|
57
62
|
def post_bundle_id_capability(bundle_id_id:, capability_type:, settings: [])
|
|
58
63
|
body = {
|
|
59
64
|
data: {
|
|
@@ -28,8 +28,13 @@ module Spaceship
|
|
|
28
28
|
users_request_client.delete("users/#{user_id}")
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
#
|
|
31
|
+
# Add app permissions for user
|
|
32
|
+
# @deprecated Use {#post_user_visible_apps} instead.
|
|
32
33
|
def add_user_visible_apps(user_id: nil, app_ids: nil)
|
|
34
|
+
post_user_visible_apps(user_id: user_id, app_ids: app_ids)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def post_user_visible_apps(user_id: nil, app_ids: nil)
|
|
33
38
|
body = {
|
|
34
39
|
data: app_ids.map do |app_id|
|
|
35
40
|
{
|
|
@@ -42,6 +47,34 @@ module Spaceship
|
|
|
42
47
|
users_request_client.post("users/#{user_id}/relationships/visibleApps", body)
|
|
43
48
|
end
|
|
44
49
|
|
|
50
|
+
# Replace app permissions for user
|
|
51
|
+
def patch_user_visible_apps(user_id: nil, app_ids: nil)
|
|
52
|
+
body = {
|
|
53
|
+
data: app_ids.map do |app_id|
|
|
54
|
+
{
|
|
55
|
+
type: "apps",
|
|
56
|
+
id: app_id
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
users_request_client.patch("users/#{user_id}/relationships/visibleApps", body)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Remove app permissions for user
|
|
65
|
+
def delete_user_visible_apps(user_id: nil, app_ids: nil)
|
|
66
|
+
body = {
|
|
67
|
+
data: app_ids.map do |app_id|
|
|
68
|
+
{
|
|
69
|
+
type: "apps",
|
|
70
|
+
id: app_id
|
|
71
|
+
}
|
|
72
|
+
end
|
|
73
|
+
}
|
|
74
|
+
params = nil
|
|
75
|
+
users_request_client.delete("users/#{user_id}/relationships/visibleApps", params, body)
|
|
76
|
+
end
|
|
77
|
+
|
|
45
78
|
# Get app permissions for user
|
|
46
79
|
def get_user_visible_apps(user_id: id, limit: nil)
|
|
47
80
|
params = users_request_client.build_params(filter: {}, includes: nil, limit: limit, sort: nil)
|
|
@@ -302,7 +302,7 @@ module Supply
|
|
|
302
302
|
|
|
303
303
|
def upload_mapping(apk_version_codes)
|
|
304
304
|
mapping_paths = [Supply.config[:mapping]] unless (mapping_paths = Supply.config[:mapping_paths])
|
|
305
|
-
mapping_paths.
|
|
305
|
+
mapping_paths.product(apk_version_codes).each do |mapping_path, version_code|
|
|
306
306
|
if mapping_path
|
|
307
307
|
UI.message("Preparing mapping at path '#{mapping_path}', version code #{version_code} for upload...")
|
|
308
308
|
client.upload_mapping(mapping_path, version_code)
|
metadata
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fastlane
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.191.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
7
|
+
- Andrew McBurney
|
|
8
|
+
- Fumiya Nakamura
|
|
9
|
+
- Manu Wallner
|
|
10
|
+
- Jimmy Dee
|
|
11
|
+
- Satoshi Namai
|
|
12
|
+
- Josh Holtz
|
|
13
|
+
- Felix Krause
|
|
8
14
|
- Jérôme Lacoste
|
|
9
|
-
-
|
|
10
|
-
- Daniel Jankowski
|
|
11
|
-
- Stefan Natchev
|
|
12
|
-
- Luka Mirosevic
|
|
13
|
-
- Jorge Revuelta H
|
|
15
|
+
- Manish Rathi
|
|
14
16
|
- Kohki Miki
|
|
15
|
-
-
|
|
16
|
-
- Joshua Liebowitz
|
|
17
|
+
- Iulian Onofrei
|
|
17
18
|
- Matthew Ellis
|
|
18
|
-
-
|
|
19
|
-
- Josh Holtz
|
|
20
|
-
- Jimmy Dee
|
|
21
|
-
- Satoshi Namai
|
|
19
|
+
- Aaron Brager
|
|
22
20
|
- Danielle Tomlinson
|
|
23
|
-
-
|
|
21
|
+
- Max Ott
|
|
22
|
+
- Roger Oba
|
|
24
23
|
- Olivier Halligon
|
|
25
|
-
-
|
|
24
|
+
- Maksym Grebenets
|
|
26
25
|
- Jan Piotrowski
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
26
|
+
- Jorge Revuelta H
|
|
27
|
+
- Luka Mirosevic
|
|
28
|
+
- Daniel Jankowski
|
|
29
|
+
- Stefan Natchev
|
|
30
|
+
- Helmut Januschka
|
|
31
|
+
- Joshua Liebowitz
|
|
32
32
|
autorequire:
|
|
33
33
|
bindir: bin
|
|
34
34
|
cert_chain: []
|
|
35
|
-
date: 2021-08-
|
|
35
|
+
date: 2021-08-06 00:00:00.000000000 Z
|
|
36
36
|
dependencies:
|
|
37
37
|
- !ruby/object:Gem::Dependency
|
|
38
38
|
name: xcodeproj
|
|
@@ -971,8 +971,10 @@ files:
|
|
|
971
971
|
- deliver/lib/deliver/module.rb
|
|
972
972
|
- deliver/lib/deliver/options.rb
|
|
973
973
|
- deliver/lib/deliver/runner.rb
|
|
974
|
+
- deliver/lib/deliver/screenshot_comparable.rb
|
|
974
975
|
- deliver/lib/deliver/setup.rb
|
|
975
976
|
- deliver/lib/deliver/submit_for_review.rb
|
|
977
|
+
- deliver/lib/deliver/sync_screenshots.rb
|
|
976
978
|
- deliver/lib/deliver/upload_metadata.rb
|
|
977
979
|
- deliver/lib/deliver/upload_price_tier.rb
|
|
978
980
|
- deliver/lib/deliver/upload_screenshots.rb
|
|
@@ -1680,6 +1682,7 @@ files:
|
|
|
1680
1682
|
- spaceship/lib/spaceship/connect_api/models/build_delivery.rb
|
|
1681
1683
|
- spaceship/lib/spaceship/connect_api/models/bundle_id.rb
|
|
1682
1684
|
- spaceship/lib/spaceship/connect_api/models/bundle_id_capability.rb
|
|
1685
|
+
- spaceship/lib/spaceship/connect_api/models/capabilities.rb
|
|
1683
1686
|
- spaceship/lib/spaceship/connect_api/models/certificate.rb
|
|
1684
1687
|
- spaceship/lib/spaceship/connect_api/models/custom_app_organization.rb
|
|
1685
1688
|
- spaceship/lib/spaceship/connect_api/models/custom_app_user.rb
|