mysigner 0.1.2 → 0.1.4
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 +4 -0
- data/.rubocop.yml +55 -0
- data/.rubocop_todo.yml +126 -0
- data/CHANGELOG.md +96 -0
- data/Gemfile +5 -3
- data/Gemfile.lock +38 -8
- data/README.md +14 -16
- data/Rakefile +5 -3
- data/bin/console +4 -3
- data/bin/setup +3 -0
- data/certificate_.cer +0 -0
- data/exe/mysigner +19 -2
- data/iOS_App_Store_Profile.mobileprovision +1 -0
- data/iOS_Distribution_Certificate.cer +1 -0
- data/lib/mysigner/build/android_executor.rb +83 -63
- 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/cleanup/private_keys_purger.rb +41 -0
- data/lib/mysigner/cli/auth_commands.rb +771 -764
- data/lib/mysigner/cli/build_commands.rb +962 -796
- 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 +44 -1
- data/lib/mysigner/cli/diagnostic_commands.rb +667 -636
- data/lib/mysigner/cli/resource_commands.rb +1153 -985
- data/lib/mysigner/cli/validate_commands.rb +25 -25
- data/lib/mysigner/cli.rb +11 -1
- data/lib/mysigner/client.rb +27 -19
- data/lib/mysigner/config.rb +161 -60
- data/lib/mysigner/export/exporter.rb +38 -37
- data/lib/mysigner/signing/certificate_checker.rb +18 -23
- data/lib/mysigner/signing/gradle_signing_injector.rb +67 -0
- data/lib/mysigner/signing/keystore_manager.rb +81 -61
- data/lib/mysigner/signing/validator.rb +38 -40
- data/lib/mysigner/signing/wizard.rb +329 -342
- data/lib/mysigner/upload/app_store_automation.rb +96 -49
- data/lib/mysigner/upload/app_store_submission.rb +87 -92
- data/lib/mysigner/upload/asc_rest_uploader.rb +119 -0
- data/lib/mysigner/upload/play_store_uploader.rb +164 -144
- data/lib/mysigner/upload/uploader.rb +136 -115
- data/lib/mysigner/version.rb +3 -1
- data/lib/mysigner.rb +13 -11
- data/mysigner.gemspec +36 -33
- data/profile_.mobileprovision +0 -0
- data/test_manual.rb +37 -36
- metadata +44 -17
- data/.DS_Store +0 -0
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'English'
|
|
1
4
|
require 'fileutils'
|
|
2
5
|
require 'json'
|
|
6
|
+
require 'tmpdir'
|
|
3
7
|
|
|
4
8
|
module Mysigner
|
|
5
9
|
module Upload
|
|
@@ -11,15 +15,39 @@ module Mysigner
|
|
|
11
15
|
TRANSPORTER_PATHS = [
|
|
12
16
|
'/Applications/Xcode.app/Contents/Developer/usr/bin/iTMSTransporter', # Bundled with Xcode (primary)
|
|
13
17
|
'/Applications/Transporter.app/Contents/itms/bin/iTMSTransporter', # Standalone Transporter app
|
|
14
|
-
'/usr/local/itms/bin/iTMSTransporter'
|
|
18
|
+
'/usr/local/itms/bin/iTMSTransporter' # Custom installation
|
|
15
19
|
].freeze
|
|
16
20
|
|
|
21
|
+
# Parses CFBundleVersion + CFBundleShortVersionString from an .ipa
|
|
22
|
+
# (reads Info.plist from the Payload/*.app/ inside the zip).
|
|
23
|
+
# Used by the new ASC REST upload flow in build_commands.rb.
|
|
24
|
+
def self.extract_ipa_info(ipa_path)
|
|
25
|
+
require 'open3'
|
|
26
|
+
result = { cf_bundle_version: nil, cf_bundle_short_version_string: nil, bundle_id: nil }
|
|
27
|
+
Dir.mktmpdir('mysigner-ipa-inspect-') do |tmp|
|
|
28
|
+
plist_path = File.join(tmp, 'Info.plist')
|
|
29
|
+
zip_out, status = Open3.capture2e('unzip', '-p', ipa_path, 'Payload/*.app/Info.plist')
|
|
30
|
+
return result unless status.success? && !zip_out.empty?
|
|
31
|
+
|
|
32
|
+
File.binwrite(plist_path, zip_out)
|
|
33
|
+
xml_out, xml_status = Open3.capture2e('plutil', '-convert', 'xml1', '-o', '-', plist_path)
|
|
34
|
+
return result unless xml_status.success?
|
|
35
|
+
|
|
36
|
+
result[:cf_bundle_version] = xml_out[%r{<key>CFBundleVersion</key>\s*<string>([^<]+)</string>}, 1]
|
|
37
|
+
result[:cf_bundle_short_version_string] = xml_out[%r{<key>CFBundleShortVersionString</key>\s*<string>([^<]+)</string>}, 1]
|
|
38
|
+
result[:bundle_id] = xml_out[%r{<key>CFBundleIdentifier</key>\s*<string>([^<]+)</string>}, 1]
|
|
39
|
+
end
|
|
40
|
+
result
|
|
41
|
+
rescue StandardError
|
|
42
|
+
{ cf_bundle_version: nil, cf_bundle_short_version_string: nil, bundle_id: nil }
|
|
43
|
+
end
|
|
44
|
+
|
|
17
45
|
def initialize(ipa_path, api_key:, api_issuer:, private_key:)
|
|
18
46
|
@ipa_path = File.expand_path(ipa_path)
|
|
19
47
|
@api_key = api_key
|
|
20
48
|
@api_issuer = api_issuer
|
|
21
49
|
@private_key = private_key
|
|
22
|
-
|
|
50
|
+
|
|
23
51
|
validate_ipa!
|
|
24
52
|
detect_transporter!
|
|
25
53
|
setup_private_key!
|
|
@@ -27,94 +55,90 @@ module Mysigner
|
|
|
27
55
|
|
|
28
56
|
def upload!(wait_for_processing: false)
|
|
29
57
|
say_uploading
|
|
30
|
-
|
|
58
|
+
|
|
31
59
|
begin
|
|
32
60
|
# Validate IPA first
|
|
33
61
|
validate_result = validate_ipa
|
|
34
|
-
unless validate_result[:success]
|
|
35
|
-
|
|
36
|
-
end
|
|
37
|
-
|
|
62
|
+
raise UploadError, "IPA validation failed: #{validate_result[:error]}" unless validate_result[:success]
|
|
63
|
+
|
|
38
64
|
# Upload to App Store Connect
|
|
39
65
|
upload_result = upload_ipa
|
|
40
|
-
unless upload_result[:success]
|
|
41
|
-
|
|
42
|
-
end
|
|
43
|
-
|
|
66
|
+
raise UploadError, "Upload failed: #{upload_result[:error]}" unless upload_result[:success]
|
|
67
|
+
|
|
44
68
|
say_success
|
|
45
|
-
|
|
69
|
+
|
|
46
70
|
# Optionally wait for processing
|
|
47
71
|
if wait_for_processing
|
|
48
72
|
say_waiting_for_processing
|
|
49
|
-
#
|
|
73
|
+
# NOTE: Build processing status is polled via the dashboard's sync API
|
|
50
74
|
# in build_commands.rb, not directly here. This flag is reserved for
|
|
51
75
|
# future use or manual uploads outside the `ship` command flow.
|
|
52
76
|
end
|
|
53
|
-
|
|
77
|
+
|
|
54
78
|
{
|
|
55
79
|
success: true,
|
|
56
|
-
message:
|
|
80
|
+
message: 'Upload completed successfully'
|
|
57
81
|
}
|
|
58
|
-
rescue => e
|
|
82
|
+
rescue StandardError => e
|
|
59
83
|
raise UploadError, "Upload failed: #{e.message}"
|
|
84
|
+
ensure
|
|
85
|
+
cleanup_private_key!
|
|
60
86
|
end
|
|
61
87
|
end
|
|
62
88
|
|
|
63
89
|
private
|
|
64
90
|
|
|
65
91
|
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
|
-
|
|
92
|
+
raise UploadError, "IPA file not found: #{@ipa_path}" unless File.exist?(@ipa_path)
|
|
93
|
+
|
|
94
|
+
raise UploadError, "Invalid file type: #{@ipa_path} (must be .ipa)" unless @ipa_path.end_with?('.ipa')
|
|
95
|
+
|
|
74
96
|
# Check file size (should be at least 10KB to catch truly corrupt files)
|
|
75
97
|
file_size = File.size(@ipa_path)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
98
|
+
return unless file_size < 10_000
|
|
99
|
+
|
|
100
|
+
raise UploadError, "IPA file seems too small: #{file_size} bytes (possible corruption)"
|
|
79
101
|
end
|
|
80
102
|
|
|
81
103
|
def detect_transporter!
|
|
82
104
|
# We primarily use xcrun altool, but check for iTMSTransporter as fallback
|
|
83
105
|
@transporter_path = TRANSPORTER_PATHS.find { |path| File.exist?(path) }
|
|
84
|
-
|
|
106
|
+
|
|
85
107
|
# Even if iTMSTransporter is not found, xcrun altool should work
|
|
86
108
|
# This is just for informational purposes
|
|
87
109
|
@using_altool = true
|
|
88
110
|
end
|
|
89
111
|
|
|
90
112
|
def setup_private_key!
|
|
91
|
-
#
|
|
92
|
-
#
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
@private_keys_dir = File.expand_path("~/.private_keys")
|
|
98
|
-
FileUtils.mkdir_p(@private_keys_dir)
|
|
99
|
-
|
|
113
|
+
# Phase 0: write the .p8 to a per-run tempdir (0600) and point altool
|
|
114
|
+
# there via API_PRIVATE_KEYS_DIR. #cleanup_private_key! in the upload!
|
|
115
|
+
# ensure block removes the tempdir, so the key never persists across
|
|
116
|
+
# invocations. Replaces the old ~/.private_keys/ persistent write.
|
|
117
|
+
@private_keys_dir = Dir.mktmpdir('mysigner-p8-')
|
|
100
118
|
@private_key_path = File.join(@private_keys_dir, "AuthKey_#{@api_key}.p8")
|
|
101
|
-
|
|
102
|
-
# Write the private key to disk
|
|
103
119
|
File.write(@private_key_path, @private_key)
|
|
104
|
-
File.chmod(
|
|
120
|
+
File.chmod(0o600, @private_key_path)
|
|
121
|
+
ENV['API_PRIVATE_KEYS_DIR'] = @private_keys_dir
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def cleanup_private_key!
|
|
125
|
+
FileUtils.rm_rf(@private_keys_dir) if @private_keys_dir && Dir.exist?(@private_keys_dir)
|
|
126
|
+
ENV.delete('API_PRIVATE_KEYS_DIR')
|
|
127
|
+
rescue StandardError
|
|
128
|
+
# Best-effort cleanup; never raise from ensure.
|
|
105
129
|
end
|
|
106
130
|
|
|
107
131
|
def validate_ipa
|
|
108
|
-
puts
|
|
109
|
-
puts
|
|
110
|
-
|
|
132
|
+
puts '📋 Validating IPA...'
|
|
133
|
+
puts ''
|
|
134
|
+
|
|
111
135
|
# Try altool first (simpler, works today)
|
|
112
136
|
if altool_available?
|
|
113
137
|
validate_with_altool
|
|
114
138
|
elsif @transporter_path
|
|
115
139
|
validate_with_transporter
|
|
116
140
|
else
|
|
117
|
-
puts
|
|
141
|
+
puts '⚠️ Skipping validation (no tools available)'
|
|
118
142
|
{ success: true } # Continue anyway
|
|
119
143
|
end
|
|
120
144
|
end
|
|
@@ -128,12 +152,12 @@ module Mysigner
|
|
|
128
152
|
'--apiKey', @api_key,
|
|
129
153
|
'--apiIssuer', @api_issuer
|
|
130
154
|
].join(' ')
|
|
131
|
-
|
|
155
|
+
|
|
132
156
|
output = `#{cmd} 2>&1`
|
|
133
|
-
success =
|
|
134
|
-
|
|
157
|
+
success = $CHILD_STATUS.success?
|
|
158
|
+
|
|
135
159
|
if success
|
|
136
|
-
puts
|
|
160
|
+
puts '✓ Validation passed (altool)'
|
|
137
161
|
{ success: true }
|
|
138
162
|
else
|
|
139
163
|
error_message = extract_error_from_output(output)
|
|
@@ -151,14 +175,14 @@ module Mysigner
|
|
|
151
175
|
'-f', @ipa_path,
|
|
152
176
|
'-apiKey', @api_key,
|
|
153
177
|
'-apiIssuer', @api_issuer,
|
|
154
|
-
'-t', 'Signiant'
|
|
178
|
+
'-t', 'Signiant' # Transport mode
|
|
155
179
|
].join(' ')
|
|
156
|
-
|
|
180
|
+
|
|
157
181
|
output = `#{cmd} 2>&1`
|
|
158
|
-
success =
|
|
159
|
-
|
|
182
|
+
success = $CHILD_STATUS.success?
|
|
183
|
+
|
|
160
184
|
if success
|
|
161
|
-
puts
|
|
185
|
+
puts '✓ Validation passed (iTMSTransporter)'
|
|
162
186
|
{ success: true }
|
|
163
187
|
else
|
|
164
188
|
error_message = extract_error_from_output(output)
|
|
@@ -168,24 +192,24 @@ module Mysigner
|
|
|
168
192
|
end
|
|
169
193
|
|
|
170
194
|
def upload_ipa
|
|
171
|
-
puts
|
|
172
|
-
puts
|
|
173
|
-
puts
|
|
174
|
-
|
|
195
|
+
puts ''
|
|
196
|
+
puts '☁️ Uploading to App Store Connect...'
|
|
197
|
+
puts ''
|
|
198
|
+
|
|
175
199
|
# Try altool first, fall back to iTMSTransporter
|
|
176
200
|
if altool_available?
|
|
177
201
|
upload_with_altool
|
|
178
202
|
elsif @transporter_path
|
|
179
203
|
upload_with_transporter
|
|
180
204
|
else
|
|
181
|
-
raise UploadError,
|
|
205
|
+
raise UploadError, 'No upload tool available. Please ensure Xcode is installed.'
|
|
182
206
|
end
|
|
183
207
|
end
|
|
184
208
|
|
|
185
209
|
def upload_with_altool
|
|
186
|
-
puts
|
|
187
|
-
puts
|
|
188
|
-
|
|
210
|
+
puts 'Using: xcrun altool'
|
|
211
|
+
puts ''
|
|
212
|
+
|
|
189
213
|
cmd = [
|
|
190
214
|
'xcrun', 'altool',
|
|
191
215
|
'--upload-app',
|
|
@@ -194,40 +218,38 @@ module Mysigner
|
|
|
194
218
|
'--apiKey', @api_key,
|
|
195
219
|
'--apiIssuer', @api_issuer
|
|
196
220
|
].join(' ')
|
|
197
|
-
|
|
221
|
+
|
|
198
222
|
# Capture full output for error detection
|
|
199
223
|
output = []
|
|
200
224
|
has_errors = false
|
|
201
|
-
|
|
225
|
+
|
|
202
226
|
# Run with live output
|
|
203
|
-
IO.popen(cmd, err: [
|
|
227
|
+
IO.popen(cmd, err: %i[child out]) do |io|
|
|
204
228
|
io.each_line do |line|
|
|
205
229
|
output << line
|
|
206
230
|
next if line.strip.empty?
|
|
207
|
-
|
|
231
|
+
|
|
208
232
|
# Detect errors
|
|
209
|
-
if line.include?('ERROR') || line.include?('UPLOAD FAILED')
|
|
210
|
-
|
|
211
|
-
end
|
|
212
|
-
|
|
233
|
+
has_errors = true if line.include?('ERROR') || line.include?('UPLOAD FAILED')
|
|
234
|
+
|
|
213
235
|
# Show progress indicators
|
|
214
|
-
if line.include?('Uploading') || line.include?('Processing') ||
|
|
236
|
+
if line.include?('Uploading') || line.include?('Processing') ||
|
|
215
237
|
line.include?('Verifying') || line.include?('Package')
|
|
216
238
|
print '.'
|
|
217
239
|
elsif line.include?('error') || line.include?('ERROR')
|
|
218
|
-
puts
|
|
240
|
+
puts ''
|
|
219
241
|
puts line
|
|
220
242
|
elsif line.include?('SUCCESS') || line.include?('No errors')
|
|
221
|
-
puts
|
|
243
|
+
puts ''
|
|
222
244
|
puts line
|
|
223
245
|
end
|
|
224
246
|
end
|
|
225
247
|
end
|
|
226
|
-
|
|
227
|
-
puts
|
|
228
|
-
|
|
248
|
+
|
|
249
|
+
puts '' # New line after progress dots
|
|
250
|
+
|
|
229
251
|
# Check both exit code and output for errors
|
|
230
|
-
if
|
|
252
|
+
if $CHILD_STATUS.success? && !has_errors
|
|
231
253
|
{ success: true }
|
|
232
254
|
else
|
|
233
255
|
error_msg = extract_error_from_output(output.join("\n"))
|
|
@@ -236,9 +258,9 @@ module Mysigner
|
|
|
236
258
|
end
|
|
237
259
|
|
|
238
260
|
def upload_with_transporter
|
|
239
|
-
puts
|
|
240
|
-
puts
|
|
241
|
-
|
|
261
|
+
puts 'Using: iTMSTransporter (future-proof)'
|
|
262
|
+
puts ''
|
|
263
|
+
|
|
242
264
|
# iTMSTransporter upload mode
|
|
243
265
|
# According to https://help.apple.com/itc/transporteruserguide/en.lproj/static.html
|
|
244
266
|
cmd = [
|
|
@@ -247,34 +269,34 @@ module Mysigner
|
|
|
247
269
|
'-f', @ipa_path,
|
|
248
270
|
'-apiKey', @api_key,
|
|
249
271
|
'-apiIssuer', @api_issuer,
|
|
250
|
-
'-t', 'Signiant'
|
|
272
|
+
'-t', 'Signiant' # Transport mode (can also use 'Aspera' or 'DAV')
|
|
251
273
|
].join(' ')
|
|
252
|
-
|
|
274
|
+
|
|
253
275
|
# Capture output
|
|
254
276
|
output = []
|
|
255
|
-
|
|
256
|
-
IO.popen(cmd, err: [
|
|
277
|
+
|
|
278
|
+
IO.popen(cmd, err: %i[child out]) do |io|
|
|
257
279
|
io.each_line do |line|
|
|
258
280
|
output << line
|
|
259
281
|
next if line.strip.empty?
|
|
260
|
-
|
|
282
|
+
|
|
261
283
|
# Show progress
|
|
262
|
-
if line.include?('Uploading') || line.include?('Processing') ||
|
|
284
|
+
if line.include?('Uploading') || line.include?('Processing') ||
|
|
263
285
|
line.include?('Verifying')
|
|
264
286
|
print '.'
|
|
265
287
|
elsif line.include?('ERROR')
|
|
266
|
-
puts
|
|
288
|
+
puts ''
|
|
267
289
|
puts line
|
|
268
290
|
elsif line.include?('SUCCESS')
|
|
269
|
-
puts
|
|
291
|
+
puts ''
|
|
270
292
|
puts line
|
|
271
293
|
end
|
|
272
294
|
end
|
|
273
295
|
end
|
|
274
|
-
|
|
275
|
-
puts
|
|
276
|
-
|
|
277
|
-
if
|
|
296
|
+
|
|
297
|
+
puts ''
|
|
298
|
+
|
|
299
|
+
if $CHILD_STATUS.success?
|
|
278
300
|
{ success: true }
|
|
279
301
|
else
|
|
280
302
|
error_msg = extract_error_from_output(output.join("\n"))
|
|
@@ -292,13 +314,13 @@ module Mysigner
|
|
|
292
314
|
error_lines = output.lines.select do |l|
|
|
293
315
|
l.include?('ERROR') || l.include?('error') || l.include?('Invalid')
|
|
294
316
|
end
|
|
295
|
-
|
|
317
|
+
|
|
296
318
|
if error_lines.any?
|
|
297
319
|
# Clean up and join error messages
|
|
298
320
|
cleaned_errors = error_lines.map(&:strip)
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
321
|
+
.reject { |l| l.empty? || l.start_with?('code :') || l.start_with?('iris-code') }
|
|
322
|
+
.join("\n")
|
|
323
|
+
|
|
302
324
|
# Add helpful context for common errors
|
|
303
325
|
if output.include?('Cannot determine the Apple ID from Bundle ID')
|
|
304
326
|
cleaned_errors += "\n\n💡 This usually means:\n"
|
|
@@ -318,44 +340,44 @@ module Mysigner
|
|
|
318
340
|
cleaned_errors += " 3. Add icon images for all required sizes\n"
|
|
319
341
|
cleaned_errors += " 4. Or use a tool like https://appicon.co to generate all sizes\n"
|
|
320
342
|
end
|
|
321
|
-
|
|
343
|
+
|
|
322
344
|
cleaned_errors
|
|
323
345
|
else
|
|
324
|
-
|
|
346
|
+
'Unknown error'
|
|
325
347
|
end
|
|
326
348
|
end
|
|
327
349
|
|
|
328
350
|
def say_uploading
|
|
329
|
-
puts
|
|
330
|
-
puts
|
|
351
|
+
puts '☁️ Uploading to TestFlight...'
|
|
352
|
+
puts ''
|
|
331
353
|
puts "IPA: #{File.basename(@ipa_path)}"
|
|
332
354
|
puts "Size: #{format_bytes(File.size(@ipa_path))}"
|
|
333
|
-
|
|
355
|
+
|
|
334
356
|
# Show which tool will be used
|
|
335
357
|
if altool_available?
|
|
336
|
-
puts
|
|
358
|
+
puts 'Tool: xcrun altool'
|
|
337
359
|
elsif @transporter_path
|
|
338
|
-
puts
|
|
360
|
+
puts 'Tool: iTMSTransporter (future-proof)'
|
|
339
361
|
else
|
|
340
|
-
puts
|
|
362
|
+
puts 'Tool: Auto-detect'
|
|
341
363
|
end
|
|
342
|
-
puts
|
|
364
|
+
puts ''
|
|
343
365
|
end
|
|
344
366
|
|
|
345
367
|
def say_success
|
|
346
|
-
puts
|
|
347
|
-
puts
|
|
348
|
-
puts
|
|
349
|
-
puts
|
|
350
|
-
puts
|
|
351
|
-
puts
|
|
352
|
-
puts
|
|
368
|
+
puts ''
|
|
369
|
+
puts '=' * 80
|
|
370
|
+
puts '✓ Upload succeeded!'
|
|
371
|
+
puts '=' * 80
|
|
372
|
+
puts ''
|
|
373
|
+
puts '🎉 Your build is now processing in App Store Connect'
|
|
374
|
+
puts ''
|
|
353
375
|
end
|
|
354
376
|
|
|
355
377
|
def say_waiting_for_processing
|
|
356
|
-
puts
|
|
357
|
-
puts
|
|
358
|
-
puts
|
|
378
|
+
puts '⏳ Waiting for App Store Connect to process the build...'
|
|
379
|
+
puts 'This may take 5-15 minutes...'
|
|
380
|
+
puts ''
|
|
359
381
|
end
|
|
360
382
|
|
|
361
383
|
def format_bytes(bytes)
|
|
@@ -370,4 +392,3 @@ module Mysigner
|
|
|
370
392
|
end
|
|
371
393
|
end
|
|
372
394
|
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
|
|
File without changes
|