mysigner 0.1.1 → 0.1.3
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/.githooks/pre-commit +15 -0
- data/.githooks/pre-push +21 -0
- data/.github/workflows/ci.yml +29 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +55 -0
- data/.rubocop_todo.yml +112 -0
- data/CHANGELOG.md +96 -0
- data/Gemfile +5 -3
- data/Gemfile.lock +38 -8
- data/README.md +87 -17
- data/Rakefile +5 -3
- data/bin/console +4 -3
- data/bin/setup +3 -0
- data/exe/mysigner +2 -1
- data/lib/mysigner/build/android_executor.rb +46 -52
- data/lib/mysigner/build/android_parser.rb +33 -40
- data/lib/mysigner/build/configurator.rb +17 -16
- data/lib/mysigner/build/detector.rb +39 -50
- data/lib/mysigner/build/error_analyzer.rb +70 -68
- data/lib/mysigner/build/executor.rb +30 -37
- data/lib/mysigner/build/parser.rb +18 -18
- data/lib/mysigner/cli/auth_commands.rb +735 -752
- data/lib/mysigner/cli/build_commands.rb +697 -721
- data/lib/mysigner/cli/concerns/actionable_suggestions.rb +208 -154
- data/lib/mysigner/cli/concerns/api_helpers.rb +46 -54
- data/lib/mysigner/cli/concerns/error_handlers.rb +247 -237
- data/lib/mysigner/cli/concerns/helpers.rb +12 -1
- data/lib/mysigner/cli/diagnostic_commands.rb +659 -635
- data/lib/mysigner/cli/resource_commands.rb +1266 -822
- data/lib/mysigner/cli/validate_commands.rb +161 -0
- data/lib/mysigner/cli.rb +5 -1
- data/lib/mysigner/client.rb +27 -19
- data/lib/mysigner/config.rb +93 -56
- data/lib/mysigner/export/exporter.rb +32 -36
- data/lib/mysigner/signing/certificate_checker.rb +18 -23
- data/lib/mysigner/signing/keystore_manager.rb +34 -39
- data/lib/mysigner/signing/validator.rb +38 -40
- data/lib/mysigner/signing/wizard.rb +329 -342
- data/lib/mysigner/upload/app_store_automation.rb +51 -49
- data/lib/mysigner/upload/app_store_submission.rb +87 -92
- data/lib/mysigner/upload/play_store_uploader.rb +98 -115
- data/lib/mysigner/upload/uploader.rb +101 -109
- data/lib/mysigner/version.rb +3 -1
- data/lib/mysigner.rb +13 -11
- data/mysigner.gemspec +36 -33
- data/test_manual.rb +37 -36
- metadata +38 -16
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'English'
|
|
1
4
|
require 'fileutils'
|
|
2
5
|
require 'json'
|
|
3
6
|
|
|
@@ -11,7 +14,7 @@ module Mysigner
|
|
|
11
14
|
TRANSPORTER_PATHS = [
|
|
12
15
|
'/Applications/Xcode.app/Contents/Developer/usr/bin/iTMSTransporter', # Bundled with Xcode (primary)
|
|
13
16
|
'/Applications/Transporter.app/Contents/itms/bin/iTMSTransporter', # Standalone Transporter app
|
|
14
|
-
'/usr/local/itms/bin/iTMSTransporter'
|
|
17
|
+
'/usr/local/itms/bin/iTMSTransporter' # Custom installation
|
|
15
18
|
].freeze
|
|
16
19
|
|
|
17
20
|
def initialize(ipa_path, api_key:, api_issuer:, private_key:)
|
|
@@ -19,7 +22,7 @@ module Mysigner
|
|
|
19
22
|
@api_key = api_key
|
|
20
23
|
@api_issuer = api_issuer
|
|
21
24
|
@private_key = private_key
|
|
22
|
-
|
|
25
|
+
|
|
23
26
|
validate_ipa!
|
|
24
27
|
detect_transporter!
|
|
25
28
|
setup_private_key!
|
|
@@ -27,35 +30,31 @@ module Mysigner
|
|
|
27
30
|
|
|
28
31
|
def upload!(wait_for_processing: false)
|
|
29
32
|
say_uploading
|
|
30
|
-
|
|
33
|
+
|
|
31
34
|
begin
|
|
32
35
|
# Validate IPA first
|
|
33
36
|
validate_result = validate_ipa
|
|
34
|
-
unless validate_result[:success]
|
|
35
|
-
|
|
36
|
-
end
|
|
37
|
-
|
|
37
|
+
raise UploadError, "IPA validation failed: #{validate_result[:error]}" unless validate_result[:success]
|
|
38
|
+
|
|
38
39
|
# Upload to App Store Connect
|
|
39
40
|
upload_result = upload_ipa
|
|
40
|
-
unless upload_result[:success]
|
|
41
|
-
|
|
42
|
-
end
|
|
43
|
-
|
|
41
|
+
raise UploadError, "Upload failed: #{upload_result[:error]}" unless upload_result[:success]
|
|
42
|
+
|
|
44
43
|
say_success
|
|
45
|
-
|
|
44
|
+
|
|
46
45
|
# Optionally wait for processing
|
|
47
46
|
if wait_for_processing
|
|
48
47
|
say_waiting_for_processing
|
|
49
|
-
#
|
|
48
|
+
# NOTE: Build processing status is polled via the dashboard's sync API
|
|
50
49
|
# in build_commands.rb, not directly here. This flag is reserved for
|
|
51
50
|
# future use or manual uploads outside the `ship` command flow.
|
|
52
51
|
end
|
|
53
|
-
|
|
52
|
+
|
|
54
53
|
{
|
|
55
54
|
success: true,
|
|
56
|
-
message:
|
|
55
|
+
message: 'Upload completed successfully'
|
|
57
56
|
}
|
|
58
|
-
rescue => e
|
|
57
|
+
rescue StandardError => e
|
|
59
58
|
raise UploadError, "Upload failed: #{e.message}"
|
|
60
59
|
end
|
|
61
60
|
end
|
|
@@ -63,25 +62,21 @@ module Mysigner
|
|
|
63
62
|
private
|
|
64
63
|
|
|
65
64
|
def validate_ipa!
|
|
66
|
-
unless File.exist?(@ipa_path)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
unless @ipa_path.end_with?('.ipa')
|
|
71
|
-
raise UploadError, "Invalid file type: #{@ipa_path} (must be .ipa)"
|
|
72
|
-
end
|
|
73
|
-
|
|
65
|
+
raise UploadError, "IPA file not found: #{@ipa_path}" unless File.exist?(@ipa_path)
|
|
66
|
+
|
|
67
|
+
raise UploadError, "Invalid file type: #{@ipa_path} (must be .ipa)" unless @ipa_path.end_with?('.ipa')
|
|
68
|
+
|
|
74
69
|
# Check file size (should be at least 10KB to catch truly corrupt files)
|
|
75
70
|
file_size = File.size(@ipa_path)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
71
|
+
return unless file_size < 10_000
|
|
72
|
+
|
|
73
|
+
raise UploadError, "IPA file seems too small: #{file_size} bytes (possible corruption)"
|
|
79
74
|
end
|
|
80
75
|
|
|
81
76
|
def detect_transporter!
|
|
82
77
|
# We primarily use xcrun altool, but check for iTMSTransporter as fallback
|
|
83
78
|
@transporter_path = TRANSPORTER_PATHS.find { |path| File.exist?(path) }
|
|
84
|
-
|
|
79
|
+
|
|
85
80
|
# Even if iTMSTransporter is not found, xcrun altool should work
|
|
86
81
|
# This is just for informational purposes
|
|
87
82
|
@using_altool = true
|
|
@@ -91,30 +86,30 @@ module Mysigner
|
|
|
91
86
|
# iTMSTransporter looks for .p8 files in these locations:
|
|
92
87
|
# - ./private_keys/AuthKey_<KEY_ID>.p8
|
|
93
88
|
# - ~/private_keys/AuthKey_<KEY_ID>.p8
|
|
94
|
-
# - ~/.private_keys/AuthKey_<KEY_ID>.p8
|
|
89
|
+
# - ~/.private_keys/AuthKey_<KEY_ID>.p8
|
|
95
90
|
# - ~/.appstoreconnect/private_keys/AuthKey_<KEY_ID>.p8
|
|
96
|
-
|
|
97
|
-
@private_keys_dir = File.expand_path(
|
|
91
|
+
|
|
92
|
+
@private_keys_dir = File.expand_path('~/.private_keys')
|
|
98
93
|
FileUtils.mkdir_p(@private_keys_dir)
|
|
99
|
-
|
|
94
|
+
|
|
100
95
|
@private_key_path = File.join(@private_keys_dir, "AuthKey_#{@api_key}.p8")
|
|
101
|
-
|
|
96
|
+
|
|
102
97
|
# Write the private key to disk
|
|
103
98
|
File.write(@private_key_path, @private_key)
|
|
104
|
-
File.chmod(
|
|
99
|
+
File.chmod(0o600, @private_key_path) # Secure permissions
|
|
105
100
|
end
|
|
106
101
|
|
|
107
102
|
def validate_ipa
|
|
108
|
-
puts
|
|
109
|
-
puts
|
|
110
|
-
|
|
103
|
+
puts '📋 Validating IPA...'
|
|
104
|
+
puts ''
|
|
105
|
+
|
|
111
106
|
# Try altool first (simpler, works today)
|
|
112
107
|
if altool_available?
|
|
113
108
|
validate_with_altool
|
|
114
109
|
elsif @transporter_path
|
|
115
110
|
validate_with_transporter
|
|
116
111
|
else
|
|
117
|
-
puts
|
|
112
|
+
puts '⚠️ Skipping validation (no tools available)'
|
|
118
113
|
{ success: true } # Continue anyway
|
|
119
114
|
end
|
|
120
115
|
end
|
|
@@ -128,12 +123,12 @@ module Mysigner
|
|
|
128
123
|
'--apiKey', @api_key,
|
|
129
124
|
'--apiIssuer', @api_issuer
|
|
130
125
|
].join(' ')
|
|
131
|
-
|
|
126
|
+
|
|
132
127
|
output = `#{cmd} 2>&1`
|
|
133
|
-
success =
|
|
134
|
-
|
|
128
|
+
success = $CHILD_STATUS.success?
|
|
129
|
+
|
|
135
130
|
if success
|
|
136
|
-
puts
|
|
131
|
+
puts '✓ Validation passed (altool)'
|
|
137
132
|
{ success: true }
|
|
138
133
|
else
|
|
139
134
|
error_message = extract_error_from_output(output)
|
|
@@ -151,14 +146,14 @@ module Mysigner
|
|
|
151
146
|
'-f', @ipa_path,
|
|
152
147
|
'-apiKey', @api_key,
|
|
153
148
|
'-apiIssuer', @api_issuer,
|
|
154
|
-
'-t', 'Signiant'
|
|
149
|
+
'-t', 'Signiant' # Transport mode
|
|
155
150
|
].join(' ')
|
|
156
|
-
|
|
151
|
+
|
|
157
152
|
output = `#{cmd} 2>&1`
|
|
158
|
-
success =
|
|
159
|
-
|
|
153
|
+
success = $CHILD_STATUS.success?
|
|
154
|
+
|
|
160
155
|
if success
|
|
161
|
-
puts
|
|
156
|
+
puts '✓ Validation passed (iTMSTransporter)'
|
|
162
157
|
{ success: true }
|
|
163
158
|
else
|
|
164
159
|
error_message = extract_error_from_output(output)
|
|
@@ -168,24 +163,24 @@ module Mysigner
|
|
|
168
163
|
end
|
|
169
164
|
|
|
170
165
|
def upload_ipa
|
|
171
|
-
puts
|
|
172
|
-
puts
|
|
173
|
-
puts
|
|
174
|
-
|
|
166
|
+
puts ''
|
|
167
|
+
puts '☁️ Uploading to App Store Connect...'
|
|
168
|
+
puts ''
|
|
169
|
+
|
|
175
170
|
# Try altool first, fall back to iTMSTransporter
|
|
176
171
|
if altool_available?
|
|
177
172
|
upload_with_altool
|
|
178
173
|
elsif @transporter_path
|
|
179
174
|
upload_with_transporter
|
|
180
175
|
else
|
|
181
|
-
raise UploadError,
|
|
176
|
+
raise UploadError, 'No upload tool available. Please ensure Xcode is installed.'
|
|
182
177
|
end
|
|
183
178
|
end
|
|
184
179
|
|
|
185
180
|
def upload_with_altool
|
|
186
|
-
puts
|
|
187
|
-
puts
|
|
188
|
-
|
|
181
|
+
puts 'Using: xcrun altool'
|
|
182
|
+
puts ''
|
|
183
|
+
|
|
189
184
|
cmd = [
|
|
190
185
|
'xcrun', 'altool',
|
|
191
186
|
'--upload-app',
|
|
@@ -194,40 +189,38 @@ module Mysigner
|
|
|
194
189
|
'--apiKey', @api_key,
|
|
195
190
|
'--apiIssuer', @api_issuer
|
|
196
191
|
].join(' ')
|
|
197
|
-
|
|
192
|
+
|
|
198
193
|
# Capture full output for error detection
|
|
199
194
|
output = []
|
|
200
195
|
has_errors = false
|
|
201
|
-
|
|
196
|
+
|
|
202
197
|
# Run with live output
|
|
203
|
-
IO.popen(cmd, err: [
|
|
198
|
+
IO.popen(cmd, err: %i[child out]) do |io|
|
|
204
199
|
io.each_line do |line|
|
|
205
200
|
output << line
|
|
206
201
|
next if line.strip.empty?
|
|
207
|
-
|
|
202
|
+
|
|
208
203
|
# Detect errors
|
|
209
|
-
if line.include?('ERROR') || line.include?('UPLOAD FAILED')
|
|
210
|
-
|
|
211
|
-
end
|
|
212
|
-
|
|
204
|
+
has_errors = true if line.include?('ERROR') || line.include?('UPLOAD FAILED')
|
|
205
|
+
|
|
213
206
|
# Show progress indicators
|
|
214
|
-
if line.include?('Uploading') || line.include?('Processing') ||
|
|
207
|
+
if line.include?('Uploading') || line.include?('Processing') ||
|
|
215
208
|
line.include?('Verifying') || line.include?('Package')
|
|
216
209
|
print '.'
|
|
217
210
|
elsif line.include?('error') || line.include?('ERROR')
|
|
218
|
-
puts
|
|
211
|
+
puts ''
|
|
219
212
|
puts line
|
|
220
213
|
elsif line.include?('SUCCESS') || line.include?('No errors')
|
|
221
|
-
puts
|
|
214
|
+
puts ''
|
|
222
215
|
puts line
|
|
223
216
|
end
|
|
224
217
|
end
|
|
225
218
|
end
|
|
226
|
-
|
|
227
|
-
puts
|
|
228
|
-
|
|
219
|
+
|
|
220
|
+
puts '' # New line after progress dots
|
|
221
|
+
|
|
229
222
|
# Check both exit code and output for errors
|
|
230
|
-
if
|
|
223
|
+
if $CHILD_STATUS.success? && !has_errors
|
|
231
224
|
{ success: true }
|
|
232
225
|
else
|
|
233
226
|
error_msg = extract_error_from_output(output.join("\n"))
|
|
@@ -236,9 +229,9 @@ module Mysigner
|
|
|
236
229
|
end
|
|
237
230
|
|
|
238
231
|
def upload_with_transporter
|
|
239
|
-
puts
|
|
240
|
-
puts
|
|
241
|
-
|
|
232
|
+
puts 'Using: iTMSTransporter (future-proof)'
|
|
233
|
+
puts ''
|
|
234
|
+
|
|
242
235
|
# iTMSTransporter upload mode
|
|
243
236
|
# According to https://help.apple.com/itc/transporteruserguide/en.lproj/static.html
|
|
244
237
|
cmd = [
|
|
@@ -247,34 +240,34 @@ module Mysigner
|
|
|
247
240
|
'-f', @ipa_path,
|
|
248
241
|
'-apiKey', @api_key,
|
|
249
242
|
'-apiIssuer', @api_issuer,
|
|
250
|
-
'-t', 'Signiant'
|
|
243
|
+
'-t', 'Signiant' # Transport mode (can also use 'Aspera' or 'DAV')
|
|
251
244
|
].join(' ')
|
|
252
|
-
|
|
245
|
+
|
|
253
246
|
# Capture output
|
|
254
247
|
output = []
|
|
255
|
-
|
|
256
|
-
IO.popen(cmd, err: [
|
|
248
|
+
|
|
249
|
+
IO.popen(cmd, err: %i[child out]) do |io|
|
|
257
250
|
io.each_line do |line|
|
|
258
251
|
output << line
|
|
259
252
|
next if line.strip.empty?
|
|
260
|
-
|
|
253
|
+
|
|
261
254
|
# Show progress
|
|
262
|
-
if line.include?('Uploading') || line.include?('Processing') ||
|
|
255
|
+
if line.include?('Uploading') || line.include?('Processing') ||
|
|
263
256
|
line.include?('Verifying')
|
|
264
257
|
print '.'
|
|
265
258
|
elsif line.include?('ERROR')
|
|
266
|
-
puts
|
|
259
|
+
puts ''
|
|
267
260
|
puts line
|
|
268
261
|
elsif line.include?('SUCCESS')
|
|
269
|
-
puts
|
|
262
|
+
puts ''
|
|
270
263
|
puts line
|
|
271
264
|
end
|
|
272
265
|
end
|
|
273
266
|
end
|
|
274
|
-
|
|
275
|
-
puts
|
|
276
|
-
|
|
277
|
-
if
|
|
267
|
+
|
|
268
|
+
puts ''
|
|
269
|
+
|
|
270
|
+
if $CHILD_STATUS.success?
|
|
278
271
|
{ success: true }
|
|
279
272
|
else
|
|
280
273
|
error_msg = extract_error_from_output(output.join("\n"))
|
|
@@ -292,13 +285,13 @@ module Mysigner
|
|
|
292
285
|
error_lines = output.lines.select do |l|
|
|
293
286
|
l.include?('ERROR') || l.include?('error') || l.include?('Invalid')
|
|
294
287
|
end
|
|
295
|
-
|
|
288
|
+
|
|
296
289
|
if error_lines.any?
|
|
297
290
|
# Clean up and join error messages
|
|
298
291
|
cleaned_errors = error_lines.map(&:strip)
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
292
|
+
.reject { |l| l.empty? || l.start_with?('code :') || l.start_with?('iris-code') }
|
|
293
|
+
.join("\n")
|
|
294
|
+
|
|
302
295
|
# Add helpful context for common errors
|
|
303
296
|
if output.include?('Cannot determine the Apple ID from Bundle ID')
|
|
304
297
|
cleaned_errors += "\n\n💡 This usually means:\n"
|
|
@@ -318,44 +311,44 @@ module Mysigner
|
|
|
318
311
|
cleaned_errors += " 3. Add icon images for all required sizes\n"
|
|
319
312
|
cleaned_errors += " 4. Or use a tool like https://appicon.co to generate all sizes\n"
|
|
320
313
|
end
|
|
321
|
-
|
|
314
|
+
|
|
322
315
|
cleaned_errors
|
|
323
316
|
else
|
|
324
|
-
|
|
317
|
+
'Unknown error'
|
|
325
318
|
end
|
|
326
319
|
end
|
|
327
320
|
|
|
328
321
|
def say_uploading
|
|
329
|
-
puts
|
|
330
|
-
puts
|
|
322
|
+
puts '☁️ Uploading to TestFlight...'
|
|
323
|
+
puts ''
|
|
331
324
|
puts "IPA: #{File.basename(@ipa_path)}"
|
|
332
325
|
puts "Size: #{format_bytes(File.size(@ipa_path))}"
|
|
333
|
-
|
|
326
|
+
|
|
334
327
|
# Show which tool will be used
|
|
335
328
|
if altool_available?
|
|
336
|
-
puts
|
|
329
|
+
puts 'Tool: xcrun altool'
|
|
337
330
|
elsif @transporter_path
|
|
338
|
-
puts
|
|
331
|
+
puts 'Tool: iTMSTransporter (future-proof)'
|
|
339
332
|
else
|
|
340
|
-
puts
|
|
333
|
+
puts 'Tool: Auto-detect'
|
|
341
334
|
end
|
|
342
|
-
puts
|
|
335
|
+
puts ''
|
|
343
336
|
end
|
|
344
337
|
|
|
345
338
|
def say_success
|
|
346
|
-
puts
|
|
347
|
-
puts
|
|
348
|
-
puts
|
|
349
|
-
puts
|
|
350
|
-
puts
|
|
351
|
-
puts
|
|
352
|
-
puts
|
|
339
|
+
puts ''
|
|
340
|
+
puts '=' * 80
|
|
341
|
+
puts '✓ Upload succeeded!'
|
|
342
|
+
puts '=' * 80
|
|
343
|
+
puts ''
|
|
344
|
+
puts '🎉 Your build is now processing in App Store Connect'
|
|
345
|
+
puts ''
|
|
353
346
|
end
|
|
354
347
|
|
|
355
348
|
def say_waiting_for_processing
|
|
356
|
-
puts
|
|
357
|
-
puts
|
|
358
|
-
puts
|
|
349
|
+
puts '⏳ Waiting for App Store Connect to process the build...'
|
|
350
|
+
puts 'This may take 5-15 minutes...'
|
|
351
|
+
puts ''
|
|
359
352
|
end
|
|
360
353
|
|
|
361
354
|
def format_bytes(bytes)
|
|
@@ -370,4 +363,3 @@ module Mysigner
|
|
|
370
363
|
end
|
|
371
364
|
end
|
|
372
365
|
end
|
|
373
|
-
|
data/lib/mysigner/version.rb
CHANGED
data/lib/mysigner.rb
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Mysigner
|
|
2
4
|
class Error < StandardError; end
|
|
3
5
|
end
|
|
4
6
|
|
|
5
|
-
require
|
|
6
|
-
require
|
|
7
|
-
require
|
|
8
|
-
require
|
|
9
|
-
require
|
|
10
|
-
require
|
|
11
|
-
require
|
|
12
|
-
require
|
|
13
|
-
require
|
|
14
|
-
require
|
|
15
|
-
require
|
|
7
|
+
require 'mysigner/version'
|
|
8
|
+
require 'mysigner/config'
|
|
9
|
+
require 'mysigner/client'
|
|
10
|
+
require 'mysigner/build/detector'
|
|
11
|
+
require 'mysigner/build/parser'
|
|
12
|
+
require 'mysigner/build/configurator'
|
|
13
|
+
require 'mysigner/build/executor'
|
|
14
|
+
require 'mysigner/signing/validator'
|
|
15
|
+
require 'mysigner/export/exporter'
|
|
16
|
+
require 'mysigner/upload/uploader'
|
|
17
|
+
require 'mysigner/cli'
|
data/mysigner.gemspec
CHANGED
|
@@ -1,32 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
|
|
2
|
-
lib = File.expand_path(
|
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
-
require
|
|
5
|
+
require 'mysigner/version'
|
|
5
6
|
|
|
6
7
|
Gem::Specification.new do |spec|
|
|
7
|
-
spec.name =
|
|
8
|
+
spec.name = 'mysigner'
|
|
8
9
|
spec.version = Mysigner::VERSION
|
|
9
|
-
spec.authors = [
|
|
10
|
-
spec.email = [
|
|
10
|
+
spec.authors = ['Jurgen Leka']
|
|
11
|
+
spec.email = ['lekacoding@gmail.com']
|
|
11
12
|
|
|
12
|
-
spec.summary =
|
|
13
|
-
spec.description =
|
|
14
|
-
spec.homepage =
|
|
15
|
-
spec.license =
|
|
13
|
+
spec.summary = 'CLI tool for iOS and Android code signing automation via My Signer API'
|
|
14
|
+
spec.description = "Command-line interface for managing iOS certificates, devices, provisioning profiles, and Android keystores. Build, sign, and upload to App Store Connect and Google Play with simple commands like 'mysigner ship testflight' and 'mysigner ship internal --platform android'."
|
|
15
|
+
spec.homepage = 'https://mysigner.dev'
|
|
16
|
+
spec.license = 'Apache-2.0'
|
|
16
17
|
|
|
17
|
-
spec.required_ruby_version =
|
|
18
|
+
spec.required_ruby_version = '>= 3.2.0'
|
|
18
19
|
|
|
19
20
|
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
|
20
21
|
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
|
21
22
|
if spec.respond_to?(:metadata)
|
|
22
|
-
spec.metadata[
|
|
23
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
|
23
24
|
|
|
24
|
-
spec.metadata[
|
|
25
|
-
spec.metadata[
|
|
26
|
-
spec.metadata[
|
|
25
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
|
26
|
+
spec.metadata['changelog_uri'] = 'https://mysigner.dev/docs/changelog'
|
|
27
|
+
spec.metadata['documentation_uri'] = 'https://mysigner.dev/docs/commands'
|
|
28
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
27
29
|
else
|
|
28
|
-
raise
|
|
29
|
-
|
|
30
|
+
raise 'RubyGems 2.0 or newer is required to protect against ' \
|
|
31
|
+
'public gem pushes.'
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
spec.post_install_message = <<~MSG
|
|
@@ -50,29 +52,30 @@ Gem::Specification.new do |spec|
|
|
|
50
52
|
|
|
51
53
|
# Specify which files should be added to the gem when it is released.
|
|
52
54
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
53
|
-
spec.files
|
|
55
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
54
56
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
55
57
|
end
|
|
56
|
-
spec.bindir =
|
|
58
|
+
spec.bindir = 'exe'
|
|
57
59
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
58
|
-
spec.require_paths = [
|
|
60
|
+
spec.require_paths = ['lib']
|
|
59
61
|
|
|
60
62
|
# Runtime dependencies
|
|
61
|
-
spec.
|
|
62
|
-
spec.
|
|
63
|
-
spec.
|
|
64
|
-
spec.
|
|
65
|
-
spec.
|
|
66
|
-
spec.
|
|
67
|
-
spec.
|
|
68
|
-
|
|
63
|
+
spec.add_dependency 'base64', '~> 0.2'
|
|
64
|
+
spec.add_dependency 'faraday', '~> 2.14'
|
|
65
|
+
spec.add_dependency 'faraday-retry', '~> 2.2'
|
|
66
|
+
spec.add_dependency 'plist', '~> 3.7'
|
|
67
|
+
spec.add_dependency 'reline', '~> 0.5'
|
|
68
|
+
spec.add_dependency 'thor', '~> 1.4'
|
|
69
|
+
spec.add_dependency 'xcodeproj', '~> 1.27'
|
|
70
|
+
|
|
69
71
|
# Android/Google Play dependencies
|
|
70
|
-
spec.
|
|
71
|
-
spec.
|
|
72
|
+
spec.add_dependency 'google-apis-androidpublisher_v3', '~> 0.54'
|
|
73
|
+
spec.add_dependency 'googleauth', '~> 1.11'
|
|
72
74
|
|
|
73
75
|
# Development dependencies
|
|
74
|
-
spec.add_development_dependency
|
|
75
|
-
spec.add_development_dependency
|
|
76
|
-
spec.add_development_dependency
|
|
77
|
-
spec.add_development_dependency
|
|
76
|
+
spec.add_development_dependency 'bundler', '~> 2.5'
|
|
77
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
|
78
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
|
79
|
+
spec.add_development_dependency 'rubocop', '~> 1.79'
|
|
80
|
+
spec.add_development_dependency 'webmock', '~> 3.24'
|
|
78
81
|
end
|