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,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Mysigner
|
|
2
4
|
class CLI < Thor
|
|
3
5
|
module Concerns
|
|
@@ -14,12 +16,12 @@ module Mysigner
|
|
|
14
16
|
/no.*processed.*build/i,
|
|
15
17
|
/waiting.*for.*build/i
|
|
16
18
|
],
|
|
17
|
-
title:
|
|
19
|
+
title: 'Build Not Found',
|
|
18
20
|
suggestions: [
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
'Upload a build first: mysigner ship testflight',
|
|
22
|
+
'If already uploaded, wait 5-15 minutes for Apple to process it',
|
|
23
|
+
'Use --wait flag to poll for processing: mysigner ship appstore --wait',
|
|
24
|
+
'Sync your builds: mysigner sync ios'
|
|
23
25
|
]
|
|
24
26
|
},
|
|
25
27
|
|
|
@@ -30,12 +32,12 @@ module Mysigner
|
|
|
30
32
|
/processing.*complete/i,
|
|
31
33
|
/not.*ready/i
|
|
32
34
|
],
|
|
33
|
-
title:
|
|
35
|
+
title: 'Build Still Processing',
|
|
34
36
|
suggestions: [
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
'Apple typically takes 5-15 minutes to process builds',
|
|
38
|
+
'Use --wait flag to automatically wait: mysigner ship appstore --wait',
|
|
39
|
+
'Check App Store Connect for processing status',
|
|
40
|
+
'Increase timeout: mysigner ship appstore --wait --asc-timeout-seconds 1800'
|
|
39
41
|
]
|
|
40
42
|
},
|
|
41
43
|
|
|
@@ -46,12 +48,12 @@ module Mysigner
|
|
|
46
48
|
/provisioning.*expired/i,
|
|
47
49
|
/certificate.*expired/i
|
|
48
50
|
],
|
|
49
|
-
title:
|
|
51
|
+
title: 'Expired Profile or Certificate',
|
|
50
52
|
suggestions: [
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
'List your profiles: mysigner profiles',
|
|
54
|
+
'Check expiration dates in My Signer dashboard',
|
|
55
|
+
'Regenerate expired profiles in Apple Developer Portal',
|
|
56
|
+
'Download fresh profile: mysigner profile download <ID>'
|
|
55
57
|
]
|
|
56
58
|
},
|
|
57
59
|
|
|
@@ -62,12 +64,12 @@ module Mysigner
|
|
|
62
64
|
/missing.*profile/i,
|
|
63
65
|
/unable.*find.*profile/i
|
|
64
66
|
],
|
|
65
|
-
title:
|
|
67
|
+
title: 'Provisioning Profile Not Found',
|
|
66
68
|
suggestions: [
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
'List available profiles: mysigner profiles',
|
|
70
|
+
'Sync profiles from Apple: mysigner sync ios',
|
|
71
|
+
'Create profile in Apple Developer Portal',
|
|
72
|
+
'Check if profile is for correct Bundle ID'
|
|
71
73
|
]
|
|
72
74
|
},
|
|
73
75
|
|
|
@@ -78,11 +80,11 @@ module Mysigner
|
|
|
78
80
|
/no.*signing.*certificate/i,
|
|
79
81
|
/missing.*certificate/i
|
|
80
82
|
],
|
|
81
|
-
title:
|
|
83
|
+
title: 'Signing Certificate Not Found',
|
|
82
84
|
suggestions: [
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
'List certificates: mysigner certificates',
|
|
86
|
+
'Download and install: mysigner certificate download <ID>',
|
|
87
|
+
'Check Keychain Access for installed certificates',
|
|
86
88
|
"Run 'mysigner doctor' to diagnose signing issues"
|
|
87
89
|
]
|
|
88
90
|
},
|
|
@@ -94,12 +96,12 @@ module Mysigner
|
|
|
94
96
|
/bundle.*identifier.*not.*match/i,
|
|
95
97
|
/app.*id.*not.*found/i
|
|
96
98
|
],
|
|
97
|
-
title:
|
|
99
|
+
title: 'Bundle ID Issue',
|
|
98
100
|
suggestions: [
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
'Verify Bundle ID in Xcode matches Apple Developer Portal',
|
|
102
|
+
'List Bundle IDs: mysigner bundleid list',
|
|
103
|
+
'Register new Bundle ID: mysigner bundleid register <ID>',
|
|
104
|
+
'Check My Signer dashboard for registered apps'
|
|
103
105
|
]
|
|
104
106
|
},
|
|
105
107
|
|
|
@@ -110,12 +112,12 @@ module Mysigner
|
|
|
110
112
|
/app.*not.*found/i,
|
|
111
113
|
/unable.*find.*app/i
|
|
112
114
|
],
|
|
113
|
-
title:
|
|
115
|
+
title: 'App Not Found',
|
|
114
116
|
suggestions: [
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
'Ensure app exists in App Store Connect',
|
|
118
|
+
'Create app in App Store Connect first',
|
|
119
|
+
'Verify Bundle ID matches: check your Xcode project',
|
|
120
|
+
'Sync from App Store Connect: mysigner sync ios'
|
|
119
121
|
]
|
|
120
122
|
},
|
|
121
123
|
|
|
@@ -125,11 +127,11 @@ module Mysigner
|
|
|
125
127
|
/version.*already.*exists/i,
|
|
126
128
|
/duplicate.*version/i
|
|
127
129
|
],
|
|
128
|
-
title:
|
|
130
|
+
title: 'Version Already Exists',
|
|
129
131
|
suggestions: [
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
132
|
+
'Increment version in Xcode (CFBundleShortVersionString)',
|
|
133
|
+
'Or increment build number (CFBundleVersion)',
|
|
134
|
+
'Check existing versions in App Store Connect'
|
|
133
135
|
]
|
|
134
136
|
},
|
|
135
137
|
|
|
@@ -141,12 +143,12 @@ module Mysigner
|
|
|
141
143
|
/support.*url.*required/i,
|
|
142
144
|
/cannot.*submit.*missing/i
|
|
143
145
|
],
|
|
144
|
-
title:
|
|
146
|
+
title: 'Missing App Store Metadata',
|
|
145
147
|
suggestions: [
|
|
146
|
-
|
|
148
|
+
'Configure release in My Signer dashboard',
|
|
147
149
|
"Provide What's New via CLI: --whats-new \"Your text\"",
|
|
148
|
-
|
|
149
|
-
|
|
150
|
+
'Ensure support URL is set in App Store Connect',
|
|
151
|
+
'Complete app information in App Store Connect'
|
|
150
152
|
]
|
|
151
153
|
},
|
|
152
154
|
|
|
@@ -157,12 +159,12 @@ module Mysigner
|
|
|
157
159
|
/no.*xcarchive/i,
|
|
158
160
|
/.xcarchive.*not.*found/i
|
|
159
161
|
],
|
|
160
|
-
title:
|
|
162
|
+
title: 'Archive Not Found',
|
|
161
163
|
suggestions: [
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
'Build your app first: mysigner build',
|
|
165
|
+
'Or use: mysigner ship testflight (handles build automatically)',
|
|
166
|
+
'Check if archive path is correct',
|
|
167
|
+
'Verify Xcode build succeeded'
|
|
166
168
|
]
|
|
167
169
|
},
|
|
168
170
|
|
|
@@ -171,12 +173,12 @@ module Mysigner
|
|
|
171
173
|
/ipa.*not.*found/i,
|
|
172
174
|
/no.*ipa.*file/i
|
|
173
175
|
],
|
|
174
|
-
title:
|
|
176
|
+
title: 'IPA File Not Found',
|
|
175
177
|
suggestions: [
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
178
|
+
'Export IPA from archive: mysigner export <archive_path>',
|
|
179
|
+
'Or use: mysigner ship testflight (handles export automatically)',
|
|
180
|
+
'Check if export succeeded',
|
|
181
|
+
'Verify export method matches profile type'
|
|
180
182
|
]
|
|
181
183
|
}
|
|
182
184
|
}.freeze
|
|
@@ -190,12 +192,12 @@ module Mysigner
|
|
|
190
192
|
/no.*keystore/i,
|
|
191
193
|
/missing.*keystore/i
|
|
192
194
|
],
|
|
193
|
-
title:
|
|
195
|
+
title: 'Keystore Not Found',
|
|
194
196
|
suggestions: [
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
197
|
+
'Upload keystore: mysigner keystore upload <path>',
|
|
198
|
+
'List keystores: mysigner keystore list',
|
|
199
|
+
'Download keystore: mysigner keystore download <ID>',
|
|
200
|
+
'Check keystore path in build.gradle'
|
|
199
201
|
]
|
|
200
202
|
},
|
|
201
203
|
|
|
@@ -205,11 +207,11 @@ module Mysigner
|
|
|
205
207
|
/wrong.*password/i,
|
|
206
208
|
/incorrect.*password/i
|
|
207
209
|
],
|
|
208
|
-
title:
|
|
210
|
+
title: 'Keystore Password Issue',
|
|
209
211
|
suggestions: [
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
212
|
+
'Verify keystore password is correct',
|
|
213
|
+
'Check password in My Signer dashboard',
|
|
214
|
+
'Update keystore password: mysigner keystore update <ID>'
|
|
213
215
|
]
|
|
214
216
|
},
|
|
215
217
|
|
|
@@ -219,14 +221,14 @@ module Mysigner
|
|
|
219
221
|
/package.*not.*found/i,
|
|
220
222
|
/first.*build.*uploaded.*manually/i
|
|
221
223
|
],
|
|
222
|
-
title:
|
|
224
|
+
title: 'First Upload Required',
|
|
223
225
|
suggestions: [
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
226
|
+
'Google Play requires the FIRST build to be uploaded manually:',
|
|
227
|
+
' 1. Build AAB: mysigner android build',
|
|
228
|
+
' 2. Go to Play Console → Your App → Internal testing',
|
|
227
229
|
" 3. Click 'Create release' and upload the AAB",
|
|
228
|
-
|
|
229
|
-
|
|
230
|
+
' 4. Save the release (no need to roll out)',
|
|
231
|
+
'After that, mysigner ship will work for future uploads'
|
|
230
232
|
]
|
|
231
233
|
},
|
|
232
234
|
|
|
@@ -237,11 +239,11 @@ module Mysigner
|
|
|
237
239
|
/already.*used/i,
|
|
238
240
|
/duplicate.*version.*code/i
|
|
239
241
|
],
|
|
240
|
-
title:
|
|
242
|
+
title: 'Version Code Conflict',
|
|
241
243
|
suggestions: [
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
244
|
+
'Version code already exists on Google Play',
|
|
245
|
+
'Run the command again - mysigner auto-increments the version',
|
|
246
|
+
'Or manually increment versionCode in build.gradle'
|
|
245
247
|
]
|
|
246
248
|
},
|
|
247
249
|
|
|
@@ -252,13 +254,13 @@ module Mysigner
|
|
|
252
254
|
/service.*account.*json.*not.*found/i,
|
|
253
255
|
/no.*credentials/i
|
|
254
256
|
],
|
|
255
|
-
title:
|
|
257
|
+
title: 'Service Account Not Found',
|
|
256
258
|
suggestions: [
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
259
|
+
'Set up Google Play credentials in My Signer dashboard:',
|
|
260
|
+
' 1. Go to Play Console → API access → Service accounts',
|
|
261
|
+
' 2. Create a service account with Editor access',
|
|
262
|
+
' 3. Download the JSON key',
|
|
263
|
+
' 4. Upload to My Signer dashboard → Google Play Settings'
|
|
262
264
|
]
|
|
263
265
|
},
|
|
264
266
|
|
|
@@ -269,14 +271,14 @@ module Mysigner
|
|
|
269
271
|
/forbidden/i,
|
|
270
272
|
/access.*denied/i
|
|
271
273
|
],
|
|
272
|
-
title:
|
|
274
|
+
title: 'Service Account Permission Denied',
|
|
273
275
|
suggestions: [
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
276
|
+
'Service account lacks required permissions',
|
|
277
|
+
'In Play Console → API access:',
|
|
278
|
+
' 1. Find your service account',
|
|
277
279
|
" 2. Click 'Manage Play Console permissions'",
|
|
278
280
|
" 3. Grant 'Admin' or 'Release manager' access to the app",
|
|
279
|
-
|
|
281
|
+
'Note: Permission changes take ~15 minutes to propagate'
|
|
280
282
|
]
|
|
281
283
|
},
|
|
282
284
|
|
|
@@ -287,13 +289,13 @@ module Mysigner
|
|
|
287
289
|
/precondition.*check.*failed/i,
|
|
288
290
|
/track.*not.*ready/i
|
|
289
291
|
],
|
|
290
|
-
title:
|
|
292
|
+
title: 'Track Not Set Up in Play Console',
|
|
291
293
|
suggestions: [
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
294
|
+
'Complete track setup in Google Play Console:',
|
|
295
|
+
' For PRODUCTION: Complete store listing, content rating, pricing',
|
|
296
|
+
' For BETA/ALPHA: Create testing track and add testers',
|
|
297
|
+
' For INTERNAL: Add internal testers',
|
|
298
|
+
'Your AAB was uploaded - go to Play Console to finish setup'
|
|
297
299
|
]
|
|
298
300
|
},
|
|
299
301
|
|
|
@@ -304,12 +306,12 @@ module Mysigner
|
|
|
304
306
|
/no.*aab.*file/i,
|
|
305
307
|
/app.*bundle.*not.*found/i
|
|
306
308
|
],
|
|
307
|
-
title:
|
|
309
|
+
title: 'AAB File Not Found',
|
|
308
310
|
suggestions: [
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
311
|
+
'Build your Android app first: mysigner android build',
|
|
312
|
+
'Or use: mysigner ship internal (handles build automatically)',
|
|
313
|
+
'Check if Gradle build succeeded',
|
|
314
|
+
'Verify AAB path in build output'
|
|
313
315
|
]
|
|
314
316
|
},
|
|
315
317
|
|
|
@@ -320,28 +322,72 @@ module Mysigner
|
|
|
320
322
|
/wrong.*key/i,
|
|
321
323
|
/incorrect.*signature/i
|
|
322
324
|
],
|
|
323
|
-
title:
|
|
325
|
+
title: 'Signing Key Mismatch',
|
|
324
326
|
suggestions: [
|
|
325
|
-
|
|
327
|
+
'AAB is signed with a different key than expected',
|
|
326
328
|
"Verify keystore matches what's registered in Play Console",
|
|
327
|
-
|
|
328
|
-
|
|
329
|
+
'Check active keystore: mysigner keystore list --active',
|
|
330
|
+
'If using Google Play App Signing, upload the correct upload key'
|
|
329
331
|
]
|
|
330
332
|
}
|
|
331
333
|
}.freeze
|
|
332
334
|
|
|
333
335
|
# API/Connection error patterns
|
|
334
336
|
API_ERROR_PATTERNS = {
|
|
337
|
+
plan_upgrade_required: {
|
|
338
|
+
patterns: [
|
|
339
|
+
/plan_upgrade_required/i,
|
|
340
|
+
/upgrade.*required/i,
|
|
341
|
+
/requires?.*(free|pro|team|paid)/i
|
|
342
|
+
],
|
|
343
|
+
title: 'Plan Upgrade Required',
|
|
344
|
+
suggestions: [
|
|
345
|
+
'This feature is blocked by your current plan',
|
|
346
|
+
'Upgrade from the My Signer pricing page or dashboard to continue',
|
|
347
|
+
"Use 'mysigner switch' if you need to change to a different organization first"
|
|
348
|
+
]
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
quota_exhausted: {
|
|
352
|
+
patterns: [
|
|
353
|
+
/quota_exhausted/i,
|
|
354
|
+
/quota.*exceeded/i,
|
|
355
|
+
/limit.*reached/i,
|
|
356
|
+
/storage.*limit/i,
|
|
357
|
+
/upload.*limit/i
|
|
358
|
+
],
|
|
359
|
+
title: 'Plan Limit Reached',
|
|
360
|
+
suggestions: [
|
|
361
|
+
'Your organization has reached a plan limit for this feature',
|
|
362
|
+
'Free up capacity or upgrade your plan in the My Signer dashboard',
|
|
363
|
+
'Check the pricing page for the next plan tier and included limits'
|
|
364
|
+
]
|
|
365
|
+
},
|
|
366
|
+
|
|
367
|
+
seat_limit_reached: {
|
|
368
|
+
patterns: [
|
|
369
|
+
/seat.*limit/i,
|
|
370
|
+
/invite.*limit/i,
|
|
371
|
+
/member.*limit/i
|
|
372
|
+
],
|
|
373
|
+
title: 'Seat Limit Reached',
|
|
374
|
+
suggestions: [
|
|
375
|
+
'Your organization has reached its member or invite limit',
|
|
376
|
+
'Remove unused members or invitations, or upgrade to a plan with more seats',
|
|
377
|
+
"Use 'mysigner orgs' or the dashboard to confirm you are in the correct organization"
|
|
378
|
+
]
|
|
379
|
+
},
|
|
380
|
+
|
|
335
381
|
rate_limited: {
|
|
336
382
|
patterns: [
|
|
337
383
|
/rate.*limit/i,
|
|
338
384
|
/too.*many.*requests/i,
|
|
339
385
|
/429/
|
|
340
386
|
],
|
|
341
|
-
title:
|
|
387
|
+
title: 'Rate Limited',
|
|
342
388
|
suggestions: [
|
|
343
|
-
|
|
344
|
-
|
|
389
|
+
'Too many API requests - wait a moment and try again',
|
|
390
|
+
'If problem persists, check API status'
|
|
345
391
|
]
|
|
346
392
|
},
|
|
347
393
|
|
|
@@ -351,11 +397,11 @@ module Mysigner
|
|
|
351
397
|
/internal.*error/i,
|
|
352
398
|
/500|502|503|504/
|
|
353
399
|
],
|
|
354
|
-
title:
|
|
400
|
+
title: 'Server Error',
|
|
355
401
|
suggestions: [
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
402
|
+
'My Signer server encountered an error',
|
|
403
|
+
'Try again in a few moments',
|
|
404
|
+
'If problem persists, check service status or contact support'
|
|
359
405
|
]
|
|
360
406
|
},
|
|
361
407
|
|
|
@@ -364,11 +410,11 @@ module Mysigner
|
|
|
364
410
|
/timeout/i,
|
|
365
411
|
/timed.*out/i
|
|
366
412
|
],
|
|
367
|
-
title:
|
|
413
|
+
title: 'Request Timeout',
|
|
368
414
|
suggestions: [
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
415
|
+
'Request took too long to complete',
|
|
416
|
+
'Check your network connection',
|
|
417
|
+
'Try again - this may be temporary'
|
|
372
418
|
]
|
|
373
419
|
}
|
|
374
420
|
}.freeze
|
|
@@ -384,10 +430,8 @@ module Mysigner
|
|
|
384
430
|
IOS_ERROR_PATTERNS.merge(ANDROID_ERROR_PATTERNS).merge(API_ERROR_PATTERNS)
|
|
385
431
|
end
|
|
386
432
|
|
|
387
|
-
patterns.
|
|
388
|
-
if error_info[:patterns].any? { |pattern| error_message =~ pattern }
|
|
389
|
-
return error_info
|
|
390
|
-
end
|
|
433
|
+
patterns.each_value do |error_info|
|
|
434
|
+
return error_info if error_info[:patterns].any? { |pattern| error_message =~ pattern }
|
|
391
435
|
end
|
|
392
436
|
|
|
393
437
|
nil
|
|
@@ -398,33 +442,33 @@ module Mysigner
|
|
|
398
442
|
return nil unless error_info
|
|
399
443
|
|
|
400
444
|
lines = []
|
|
401
|
-
lines <<
|
|
402
|
-
lines <<
|
|
445
|
+
lines << ''
|
|
446
|
+
lines << ('=' * 70)
|
|
403
447
|
lines << " 💡 #{error_info[:title]}: How to fix"
|
|
404
|
-
lines <<
|
|
405
|
-
lines <<
|
|
448
|
+
lines << ('=' * 70)
|
|
449
|
+
lines << ''
|
|
406
450
|
|
|
407
451
|
error_info[:suggestions].each do |suggestion|
|
|
408
452
|
# Preserve indentation for multi-line suggestions
|
|
409
|
-
if suggestion.start_with?(
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
453
|
+
lines << if suggestion.start_with?(' ')
|
|
454
|
+
" #{suggestion}"
|
|
455
|
+
else
|
|
456
|
+
" → #{suggestion}"
|
|
457
|
+
end
|
|
414
458
|
end
|
|
415
459
|
|
|
416
|
-
lines <<
|
|
417
|
-
lines <<
|
|
460
|
+
lines << ''
|
|
461
|
+
lines << ' 📚 More help:'
|
|
418
462
|
lines << " • Run 'mysigner doctor' to check your setup"
|
|
419
463
|
lines << " • Run 'mysigner help <command>' for command options"
|
|
420
|
-
lines <<
|
|
464
|
+
lines << ''
|
|
421
465
|
|
|
422
466
|
lines.join("\n")
|
|
423
467
|
end
|
|
424
468
|
|
|
425
469
|
# Display actionable suggestions for an error (helper for CLI commands)
|
|
426
|
-
def show_actionable_suggestions(
|
|
427
|
-
error_info = find_suggestions_for_error(
|
|
470
|
+
def show_actionable_suggestions(error_or_message, platform: nil)
|
|
471
|
+
error_info = find_suggestions_for_error(actionable_error_lookup_text(error_or_message), platform: platform)
|
|
428
472
|
return false unless error_info
|
|
429
473
|
|
|
430
474
|
output = format_actionable_suggestions(error_info)
|
|
@@ -434,64 +478,74 @@ module Mysigner
|
|
|
434
478
|
|
|
435
479
|
# Enhanced error display that includes suggestions
|
|
436
480
|
def display_error_with_suggestions(error, platform: nil, context: {})
|
|
437
|
-
say
|
|
438
|
-
say
|
|
481
|
+
say ''
|
|
482
|
+
say '=' * 80, :red
|
|
439
483
|
say "✗ #{context[:title] || 'Error'}", :red
|
|
440
|
-
say
|
|
441
|
-
say
|
|
484
|
+
say '=' * 80, :red
|
|
485
|
+
say ''
|
|
442
486
|
say "Error: #{error.message}", :red
|
|
443
|
-
say
|
|
487
|
+
say ''
|
|
488
|
+
|
|
489
|
+
if error.respond_to?(:suggestion) && error.suggestion
|
|
490
|
+
say "Suggestion: #{error.suggestion}", :yellow
|
|
491
|
+
say ''
|
|
492
|
+
end
|
|
444
493
|
|
|
445
494
|
# Show actionable suggestions if available
|
|
446
|
-
show_actionable_suggestions(error
|
|
495
|
+
show_actionable_suggestions(error, platform: platform)
|
|
447
496
|
|
|
448
497
|
# Show additional context
|
|
449
|
-
if context[:archive_path] && File.exist?(context[:archive_path])
|
|
450
|
-
say "Archive saved at: #{context[:archive_path]}", :yellow
|
|
451
|
-
end
|
|
498
|
+
say "Archive saved at: #{context[:archive_path]}", :yellow if context[:archive_path] && File.exist?(context[:archive_path])
|
|
452
499
|
|
|
453
|
-
if context[:ipa_path] && File.exist?(context[:ipa_path])
|
|
454
|
-
say "IPA saved at: #{context[:ipa_path]}", :yellow
|
|
455
|
-
end
|
|
500
|
+
say "IPA saved at: #{context[:ipa_path]}", :yellow if context[:ipa_path] && File.exist?(context[:ipa_path])
|
|
456
501
|
|
|
457
|
-
if context[:aab_path] && File.exist?(context[:aab_path])
|
|
458
|
-
say "AAB saved at: #{context[:aab_path]}", :yellow
|
|
459
|
-
end
|
|
502
|
+
say "AAB saved at: #{context[:aab_path]}", :yellow if context[:aab_path] && File.exist?(context[:aab_path])
|
|
460
503
|
|
|
461
504
|
# Debug info
|
|
462
505
|
if ENV['DEBUG']
|
|
463
|
-
say
|
|
464
|
-
say
|
|
506
|
+
say ''
|
|
507
|
+
say 'Debug info:', :yellow
|
|
465
508
|
say " Error class: #{error.class}", :yellow
|
|
466
|
-
say
|
|
509
|
+
say ' Backtrace:', :yellow
|
|
467
510
|
error.backtrace&.first(5)&.each do |line|
|
|
468
511
|
say " #{line}", :yellow
|
|
469
512
|
end
|
|
470
513
|
else
|
|
471
|
-
say
|
|
514
|
+
say '💡 For more details, run with DEBUG=1', :yellow
|
|
472
515
|
end
|
|
473
516
|
|
|
474
|
-
say
|
|
517
|
+
say ''
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
def actionable_error_lookup_text(error_or_message)
|
|
521
|
+
return error_or_message.to_s unless error_or_message.respond_to?(:message)
|
|
522
|
+
|
|
523
|
+
[
|
|
524
|
+
(error_or_message.error_code if error_or_message.respond_to?(:error_code)),
|
|
525
|
+
error_or_message.message,
|
|
526
|
+
(error_or_message.suggestion if error_or_message.respond_to?(:suggestion))
|
|
527
|
+
].compact.join(' ')
|
|
475
528
|
end
|
|
476
529
|
|
|
477
530
|
# Quick reference suggestions for common operations
|
|
478
531
|
QUICK_REFERENCE = {
|
|
479
532
|
sync: {
|
|
480
|
-
ios:
|
|
481
|
-
android:
|
|
533
|
+
ios: 'mysigner sync ios',
|
|
534
|
+
android: 'mysigner sync android'
|
|
482
535
|
},
|
|
483
|
-
profiles:
|
|
484
|
-
certificates:
|
|
485
|
-
keystores:
|
|
486
|
-
doctor:
|
|
487
|
-
onboard:
|
|
488
|
-
login:
|
|
536
|
+
profiles: 'mysigner profiles',
|
|
537
|
+
certificates: 'mysigner certificates',
|
|
538
|
+
keystores: 'mysigner keystore list',
|
|
539
|
+
doctor: 'mysigner doctor',
|
|
540
|
+
onboard: 'mysigner onboard',
|
|
541
|
+
login: 'mysigner login'
|
|
489
542
|
}.freeze
|
|
490
543
|
|
|
491
544
|
# Get quick reference command
|
|
492
545
|
def quick_ref(operation, platform: nil)
|
|
493
546
|
ref = QUICK_REFERENCE[operation]
|
|
494
547
|
return ref unless ref.is_a?(Hash)
|
|
548
|
+
|
|
495
549
|
platform ? ref[platform] : ref[:ios]
|
|
496
550
|
end
|
|
497
551
|
end
|