mysigner 0.3.4 → 0.3.7
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/.github/workflows/ci.yml +2 -2
- data/CHANGELOG.md +47 -0
- data/Gemfile +0 -1
- data/Gemfile.lock +2 -6
- data/README.md +16 -16
- data/lib/mysigner/build/android_executor.rb +16 -21
- data/lib/mysigner/build/detector.rb +3 -1
- data/lib/mysigner/build/executor.rb +6 -1
- data/lib/mysigner/cli/auth_commands.rb +14 -3
- data/lib/mysigner/cli/build_commands.rb +14 -11
- data/lib/mysigner/cli/concerns/actionable_suggestions.rb +1 -2
- data/lib/mysigner/cli/concerns/api_helpers.rb +16 -3
- data/lib/mysigner/cli/concerns/error_handlers.rb +0 -1
- data/lib/mysigner/cli/concerns/helpers.rb +14 -14
- data/lib/mysigner/cli/diagnostic_commands.rb +16 -5
- data/lib/mysigner/cli/resource_commands.rb +8 -1
- data/lib/mysigner/client.rb +52 -0
- data/lib/mysigner/config.rb +9 -4
- data/lib/mysigner/export/exporter.rb +6 -1
- data/lib/mysigner/formatting.rb +23 -0
- data/lib/mysigner/signing/certificate_checker.rb +6 -6
- data/lib/mysigner/signing/keystore_manager.rb +2 -0
- data/lib/mysigner/signing/wizard.rb +2 -0
- data/lib/mysigner/upload/app_store_automation.rb +13 -1
- data/lib/mysigner/upload/app_store_submission.rb +2 -14
- data/lib/mysigner/upload/asc_rest_uploader.rb +44 -3
- data/lib/mysigner/upload/asc_submitter.rb +5 -0
- data/lib/mysigner/upload/play_store_uploader.rb +2 -7
- data/lib/mysigner/upload/uploader.rb +9 -366
- data/lib/mysigner/version.rb +1 -1
- data/lib/mysigner.rb +1 -0
- data/mysigner.gemspec +6 -2
- metadata +2 -20
- data/.travis.yml +0 -7
- data/MANUAL_TEST.md +0 -341
- data/bin/console +0 -15
- data/bin/setup +0 -11
- data/test_manual.rb +0 -103
data/MANUAL_TEST.md
DELETED
|
@@ -1,341 +0,0 @@
|
|
|
1
|
-
# Manual Testing Guide
|
|
2
|
-
|
|
3
|
-
## Prerequisites
|
|
4
|
-
|
|
5
|
-
1. Ruby 3.4.5 installed via rbenv
|
|
6
|
-
2. Bundle install completed (`bundle install`)
|
|
7
|
-
3. My Signer API running at `http://localhost:3000` (for Client tests)
|
|
8
|
-
4. Valid API token (get from My Signer dashboard)
|
|
9
|
-
|
|
10
|
-
## Running Automated Tests
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
# Run all tests
|
|
14
|
-
bundle exec rspec
|
|
15
|
-
|
|
16
|
-
# Run specific tests
|
|
17
|
-
bundle exec rspec spec/config_spec.rb # Config tests (18 examples)
|
|
18
|
-
bundle exec rspec spec/client_spec.rb # Client tests (15 examples)
|
|
19
|
-
|
|
20
|
-
# With documentation format
|
|
21
|
-
bundle exec rspec --format documentation
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Test 1: Config Management
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
# In the my-signer-cli directory
|
|
28
|
-
bundle exec irb
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
```ruby
|
|
32
|
-
require_relative 'lib/mysigner'
|
|
33
|
-
|
|
34
|
-
# Create config
|
|
35
|
-
config = Mysigner::Config.new
|
|
36
|
-
|
|
37
|
-
# Set values
|
|
38
|
-
config.api_url = "http://localhost:3000"
|
|
39
|
-
config.current_organization_id = 1
|
|
40
|
-
config.save_token_for_org(1, 'My Organization', 'your_token_here')
|
|
41
|
-
|
|
42
|
-
# Save config (creates ~/.mysigner/config.yml)
|
|
43
|
-
config.save
|
|
44
|
-
|
|
45
|
-
# Display config (token is masked)
|
|
46
|
-
config.display
|
|
47
|
-
# => {:api_url=>"http://localhost:3000", :current_organization=>"My Organization (ID: 1)", :current_token=>"your...here"}
|
|
48
|
-
|
|
49
|
-
# Check if valid
|
|
50
|
-
config.valid?
|
|
51
|
-
# => true
|
|
52
|
-
|
|
53
|
-
# Load config in new instance
|
|
54
|
-
new_config = Mysigner::Config.new
|
|
55
|
-
new_config.api_url
|
|
56
|
-
# => "http://localhost:3000"
|
|
57
|
-
|
|
58
|
-
# Clear config
|
|
59
|
-
config.clear
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## Test 2: API Client
|
|
63
|
-
|
|
64
|
-
**⚠️ Requires My Signer API running on http://localhost:3000**
|
|
65
|
-
|
|
66
|
-
```bash
|
|
67
|
-
bundle exec irb
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
```ruby
|
|
71
|
-
require_relative 'lib/mysigner'
|
|
72
|
-
|
|
73
|
-
# Create client
|
|
74
|
-
client = Mysigner::Client.new(
|
|
75
|
-
api_url: 'http://localhost:3000',
|
|
76
|
-
api_token: 'your_actual_token' # Get from My Signer dashboard
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
# Test connection
|
|
80
|
-
response = client.test_connection
|
|
81
|
-
puts response[:data]
|
|
82
|
-
# => {"status"=>"ok", "message"=>"My Signer API v1"}
|
|
83
|
-
|
|
84
|
-
# List organizations
|
|
85
|
-
response = client.get('/api/v1/organizations')
|
|
86
|
-
orgs = response[:data]['organizations']
|
|
87
|
-
puts orgs.first
|
|
88
|
-
# => {"id"=>1, "name"=>"My Org", ...}
|
|
89
|
-
|
|
90
|
-
# List devices for organization #1
|
|
91
|
-
response = client.get('/api/v1/organizations/1/devices')
|
|
92
|
-
devices = response[:data]['devices']
|
|
93
|
-
puts "Found #{devices.count} devices"
|
|
94
|
-
|
|
95
|
-
# Register a new device
|
|
96
|
-
response = client.post('/api/v1/organizations/1/devices', body: {
|
|
97
|
-
name: 'Test iPhone',
|
|
98
|
-
udid: '00008030-001A1B2C3D4E567F',
|
|
99
|
-
platform: 'IOS'
|
|
100
|
-
})
|
|
101
|
-
puts response[:data]
|
|
102
|
-
# => {"message"=>"Device registered successfully", "device"=>{...}}
|
|
103
|
-
|
|
104
|
-
# Error handling
|
|
105
|
-
begin
|
|
106
|
-
client.get('/api/v1/organizations/999') # Non-existent org
|
|
107
|
-
rescue Mysigner::NotFoundError => e
|
|
108
|
-
puts "Caught error: #{e.message}"
|
|
109
|
-
end
|
|
110
|
-
# => "Caught error: Not found: Organization not found"
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
## Test Results ✅
|
|
114
|
-
|
|
115
|
-
**All tests passing:**
|
|
116
|
-
- ✅ Total: 87 examples, 0 failures (16 pending)
|
|
117
|
-
- ✅ Ship tests: 34 examples, 0 failures
|
|
118
|
-
- ✅ Config: 18 examples, 0 failures
|
|
119
|
-
- ✅ Client: 15 examples, 0 failures
|
|
120
|
-
|
|
121
|
-
Note: 16 tests are pending because they require specific test project setups (tvOS, watchOS, macOS platforms, etc.)
|
|
122
|
-
|
|
123
|
-
## What's Working
|
|
124
|
-
|
|
125
|
-
### Config Class (`lib/mysigner/config.rb`)
|
|
126
|
-
- ✅ Save/load YAML configuration
|
|
127
|
-
- ✅ Store API credentials securely (600 permissions)
|
|
128
|
-
- ✅ Validate required fields
|
|
129
|
-
- ✅ Mask sensitive tokens in display
|
|
130
|
-
- ✅ Clear configuration
|
|
131
|
-
|
|
132
|
-
### Client Class (`lib/mysigner/client.rb`)
|
|
133
|
-
- ✅ GET/POST/PATCH/DELETE HTTP methods
|
|
134
|
-
- ✅ Bearer token authentication
|
|
135
|
-
- ✅ Automatic JSON encoding/decoding
|
|
136
|
-
- ✅ Retry with exponential backoff (3 attempts)
|
|
137
|
-
- ✅ Custom error classes:
|
|
138
|
-
- `UnauthorizedError` (401)
|
|
139
|
-
- `ForbiddenError` (403)
|
|
140
|
-
- `NotFoundError` (404)
|
|
141
|
-
- `ValidationError` (422) - with details
|
|
142
|
-
- `RateLimitError` (429) - with retry_after
|
|
143
|
-
- `ServerError` (500+)
|
|
144
|
-
- `ConnectionError` - network issues
|
|
145
|
-
- `TimeoutError` - request timeouts
|
|
146
|
-
|
|
147
|
-
## iOS Ship/Submit Commands
|
|
148
|
-
|
|
149
|
-
### Ship Targets
|
|
150
|
-
|
|
151
|
-
| Command | What it does |
|
|
152
|
-
|---------|--------------|
|
|
153
|
-
| `mysigner ship testflight` | Full workflow: Build → Export → Upload to TestFlight |
|
|
154
|
-
| `mysigner ship appstore` | Full workflow: Build → Export → Upload → Wait for processing → Submit for App Store review |
|
|
155
|
-
|
|
156
|
-
### Testing iOS Ship Commands
|
|
157
|
-
|
|
158
|
-
**Prerequisites:**
|
|
159
|
-
1. Logged in with `mysigner login`
|
|
160
|
-
2. App Store Connect credentials configured in dashboard
|
|
161
|
-
3. Navigate to an iOS project directory
|
|
162
|
-
|
|
163
|
-
```bash
|
|
164
|
-
# Navigate to iOS project
|
|
165
|
-
cd ~/path/to/your/ios-project
|
|
166
|
-
|
|
167
|
-
# Check project is detected
|
|
168
|
-
mysigner doctor
|
|
169
|
-
|
|
170
|
-
# Ship to TestFlight (beta testing)
|
|
171
|
-
mysigner ship testflight
|
|
172
|
-
|
|
173
|
-
# Ship to App Store (production)
|
|
174
|
-
mysigner ship appstore
|
|
175
|
-
|
|
176
|
-
# Ship with options
|
|
177
|
-
mysigner ship testflight --team YOUR_TEAM_ID # Override team
|
|
178
|
-
mysigner ship testflight --bundle-id com.app.id # Override bundle ID
|
|
179
|
-
mysigner ship testflight --scheme MyScheme # Specify scheme
|
|
180
|
-
mysigner ship appstore --wait # Wait for processing
|
|
181
|
-
|
|
182
|
-
# Advanced: Release type options (App Store only)
|
|
183
|
-
mysigner ship appstore --release-type AFTER_APPROVAL # Auto-release after approval
|
|
184
|
-
mysigner ship appstore --release-type MANUAL # Hold for manual release
|
|
185
|
-
mysigner ship appstore --release-type SCHEDULED --scheduled-date 2026-02-01T10:00:00Z
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### Submit Command (No Build)
|
|
189
|
-
|
|
190
|
-
Submit an existing build that's already uploaded:
|
|
191
|
-
|
|
192
|
-
```bash
|
|
193
|
-
# Submit latest iOS build for review
|
|
194
|
-
mysigner submit
|
|
195
|
-
|
|
196
|
-
# Submit specific build
|
|
197
|
-
mysigner submit --build-number 123
|
|
198
|
-
|
|
199
|
-
# Submit with metadata overrides
|
|
200
|
-
mysigner submit --whats-new "Bug fixes" --support-url https://example.com/support
|
|
201
|
-
|
|
202
|
-
# Submit with release type
|
|
203
|
-
mysigner submit --release-type MANUAL
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
### Error Handling
|
|
207
|
-
|
|
208
|
-
The CLI provides actionable error messages:
|
|
209
|
-
|
|
210
|
-
```
|
|
211
|
-
✗ App Store Connect credentials not configured
|
|
212
|
-
|
|
213
|
-
Quick fix:
|
|
214
|
-
mysigner doctor # Auto-configure now
|
|
215
|
-
|
|
216
|
-
Or manually:
|
|
217
|
-
1. Run: mysigner onboard
|
|
218
|
-
2. Follow Step 5 to add credentials
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
### Workflow Steps
|
|
222
|
-
|
|
223
|
-
**TestFlight (3 steps):**
|
|
224
|
-
1. Build xcarchive
|
|
225
|
-
2. Export IPA
|
|
226
|
-
3. Upload to TestFlight
|
|
227
|
-
|
|
228
|
-
**App Store (5 steps):**
|
|
229
|
-
1. Build xcarchive
|
|
230
|
-
2. Export IPA
|
|
231
|
-
3. Upload to App Store Connect
|
|
232
|
-
4. Wait for Apple to process build
|
|
233
|
-
5. Submit for App Store review
|
|
234
|
-
|
|
235
|
-
## Android Ship/Submit Commands
|
|
236
|
-
|
|
237
|
-
### Ship vs Submit
|
|
238
|
-
|
|
239
|
-
| Command | What it does |
|
|
240
|
-
|---------|--------------|
|
|
241
|
-
| `mysigner ship internal --platform android` | Full workflow: Build → Sign → Upload → Assign to track |
|
|
242
|
-
| `mysigner submit beta --platform android` | Promote existing version to different track (no build) |
|
|
243
|
-
|
|
244
|
-
### Auto-Increment Behavior
|
|
245
|
-
|
|
246
|
-
The CLI automatically increments version codes:
|
|
247
|
-
|
|
248
|
-
1. **Queries backend** for highest version code recorded for the app
|
|
249
|
-
2. **Increments** if local version ≤ highest
|
|
250
|
-
3. **Regenerates android folder** (for Expo projects) with new version
|
|
251
|
-
4. **Saves build record** to backend after successful upload
|
|
252
|
-
|
|
253
|
-
### Build Record Auto-Save
|
|
254
|
-
|
|
255
|
-
After successful upload, the CLI saves a build record to MySigner backend. This ensures:
|
|
256
|
-
- Next upload knows the correct version to use
|
|
257
|
-
- No "version code already used" errors
|
|
258
|
-
- Dashboard shows accurate version history
|
|
259
|
-
|
|
260
|
-
### Partial Failure Handling
|
|
261
|
-
|
|
262
|
-
When AAB uploads but track assignment fails (e.g., Play Console not configured):
|
|
263
|
-
|
|
264
|
-
```
|
|
265
|
-
✗ Upload Failed
|
|
266
|
-
Error: Google Play API error: Precondition check failed
|
|
267
|
-
|
|
268
|
-
💡 Google Play Console requires setup before publishing to beta:
|
|
269
|
-
For BETA/ALPHA tracks:
|
|
270
|
-
• Create a closed/open testing track in Play Console
|
|
271
|
-
• Add at least one tester email
|
|
272
|
-
|
|
273
|
-
✅ Your AAB was uploaded successfully!
|
|
274
|
-
→ Go to Play Console to complete track setup, then use:
|
|
275
|
-
mysigner submit beta --platform android --version-code VERSION
|
|
276
|
-
|
|
277
|
-
📝 Build v8 recorded (prevents version conflicts on retry)
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
The build record is still saved so your next `ship` command will use the next version code.
|
|
281
|
-
|
|
282
|
-
### Manual Testing Android Commands
|
|
283
|
-
|
|
284
|
-
```bash
|
|
285
|
-
# Navigate to an Android/Expo project
|
|
286
|
-
cd ~/path/to/your/app
|
|
287
|
-
|
|
288
|
-
# Ship to internal track
|
|
289
|
-
mysigner ship internal --platform android
|
|
290
|
-
|
|
291
|
-
# Ship to other tracks
|
|
292
|
-
mysigner ship alpha --platform android
|
|
293
|
-
mysigner ship beta --platform android
|
|
294
|
-
mysigner ship production --platform android
|
|
295
|
-
|
|
296
|
-
# Promote existing build to different track
|
|
297
|
-
mysigner submit beta --platform android --version-code 7
|
|
298
|
-
|
|
299
|
-
# List Android apps
|
|
300
|
-
mysigner android list
|
|
301
|
-
|
|
302
|
-
# Register app from current project
|
|
303
|
-
mysigner android init
|
|
304
|
-
|
|
305
|
-
# Manually add an app
|
|
306
|
-
mysigner android add com.example.app --name "My App"
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
## Implemented Commands
|
|
310
|
-
|
|
311
|
-
All major commands are implemented:
|
|
312
|
-
|
|
313
|
-
### Authentication
|
|
314
|
-
- `mysigner login` - Login with API token
|
|
315
|
-
- `mysigner logout` - Clear saved credentials
|
|
316
|
-
- `mysigner status` - Show current login status
|
|
317
|
-
- `mysigner switch` - Switch organizations
|
|
318
|
-
|
|
319
|
-
### iOS Commands
|
|
320
|
-
- `mysigner ship testflight` - Build and upload to TestFlight
|
|
321
|
-
- `mysigner ship appstore` - Build, upload, and submit to App Store
|
|
322
|
-
- `mysigner submit` - Submit existing build for review
|
|
323
|
-
- `mysigner build` - Build xcarchive only
|
|
324
|
-
- `mysigner export` - Export archive to IPA
|
|
325
|
-
- `mysigner upload testflight` - Upload existing IPA
|
|
326
|
-
|
|
327
|
-
### Android Commands
|
|
328
|
-
- `mysigner ship internal/alpha/beta/production --platform android`
|
|
329
|
-
- `mysigner submit TRACK --platform android`
|
|
330
|
-
- `mysigner keystore upload/download`
|
|
331
|
-
|
|
332
|
-
### Resource Management
|
|
333
|
-
- `mysigner devices` - List/add/update devices
|
|
334
|
-
- `mysigner profiles` - List/download profiles
|
|
335
|
-
- `mysigner certificates` - List/download certificates
|
|
336
|
-
- `mysigner orgs` - List organizations
|
|
337
|
-
|
|
338
|
-
### Diagnostics
|
|
339
|
-
- `mysigner doctor` - Health check and auto-fix
|
|
340
|
-
- `mysigner onboard` - Interactive setup wizard
|
|
341
|
-
|
data/bin/console
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require 'bundler/setup'
|
|
5
|
-
require 'mysigner'
|
|
6
|
-
|
|
7
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
|
8
|
-
# with your gem easier. You can also use a different console, if you like.
|
|
9
|
-
|
|
10
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
11
|
-
# require "pry"
|
|
12
|
-
# Pry.start
|
|
13
|
-
|
|
14
|
-
require 'irb'
|
|
15
|
-
IRB.start(__FILE__)
|
data/bin/setup
DELETED
data/test_manual.rb
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# Manual test script to verify Config and Client work
|
|
5
|
-
# Run with: bundle exec ruby test_manual.rb
|
|
6
|
-
|
|
7
|
-
require_relative 'lib/mysigner'
|
|
8
|
-
|
|
9
|
-
puts '=' * 60
|
|
10
|
-
puts 'My Signer CLI - Manual Test'
|
|
11
|
-
puts '=' * 60
|
|
12
|
-
puts
|
|
13
|
-
|
|
14
|
-
# Test 1: Config Management
|
|
15
|
-
puts '1. Testing Config Management'
|
|
16
|
-
puts '-' * 60
|
|
17
|
-
|
|
18
|
-
config = Mysigner::Config.new
|
|
19
|
-
puts '✅ Config instance created'
|
|
20
|
-
|
|
21
|
-
# Set some values
|
|
22
|
-
config.api_url = 'http://localhost:3000'
|
|
23
|
-
config.user_email = 'test@example.com'
|
|
24
|
-
config.current_organization_id = 1
|
|
25
|
-
config.save_token_for_org(1, 'Test Org', 'test_token_12345678')
|
|
26
|
-
|
|
27
|
-
puts '✅ Config values set:'
|
|
28
|
-
puts " - API URL: #{config.api_url}"
|
|
29
|
-
puts " - User Email: #{config.user_email}"
|
|
30
|
-
puts " - Current Token: #{config.display[:current_token]}"
|
|
31
|
-
puts " - Org ID: #{config.current_organization_id}"
|
|
32
|
-
|
|
33
|
-
# Save config
|
|
34
|
-
config.save
|
|
35
|
-
puts "✅ Config saved to #{Mysigner::Config::CONFIG_FILE}"
|
|
36
|
-
|
|
37
|
-
# Load config
|
|
38
|
-
new_config = Mysigner::Config.new
|
|
39
|
-
puts '✅ Config loaded from file'
|
|
40
|
-
puts " - API URL: #{new_config.api_url}"
|
|
41
|
-
puts " - Valid?: #{new_config.valid?}"
|
|
42
|
-
|
|
43
|
-
# Clean up
|
|
44
|
-
new_config.clear
|
|
45
|
-
puts '✅ Config cleared'
|
|
46
|
-
puts
|
|
47
|
-
|
|
48
|
-
# Test 2: API Client (requires running API server)
|
|
49
|
-
puts '2. Testing API Client'
|
|
50
|
-
puts '-' * 60
|
|
51
|
-
|
|
52
|
-
puts
|
|
53
|
-
puts '⚠️ Note: To test the API client, you need:'
|
|
54
|
-
puts ' 1. My Signer API running at http://localhost:3000'
|
|
55
|
-
puts ' 2. A valid API token'
|
|
56
|
-
puts
|
|
57
|
-
puts 'Example usage:'
|
|
58
|
-
puts
|
|
59
|
-
|
|
60
|
-
puts '# Create client'
|
|
61
|
-
puts 'client = Mysigner::Client.new('
|
|
62
|
-
puts " api_url: 'http://localhost:3000',"
|
|
63
|
-
puts " api_token: 'your_token_here'"
|
|
64
|
-
puts ')'
|
|
65
|
-
puts
|
|
66
|
-
|
|
67
|
-
puts '# Test connection'
|
|
68
|
-
puts 'response = client.test_connection'
|
|
69
|
-
puts "puts response[:data] # => { 'status' => 'ok', 'message' => '...' }"
|
|
70
|
-
puts
|
|
71
|
-
|
|
72
|
-
puts '# List organizations'
|
|
73
|
-
puts "response = client.get('/api/v1/organizations')"
|
|
74
|
-
puts "organizations = response[:data]['organizations']"
|
|
75
|
-
puts
|
|
76
|
-
|
|
77
|
-
puts '# List devices for org #1'
|
|
78
|
-
puts "response = client.get('/api/v1/organizations/1/devices')"
|
|
79
|
-
puts "devices = response[:data]['devices']"
|
|
80
|
-
puts
|
|
81
|
-
|
|
82
|
-
puts '# Register a new device'
|
|
83
|
-
puts "response = client.post('/api/v1/organizations/1/devices', body: {"
|
|
84
|
-
puts " name: 'Test iPhone',"
|
|
85
|
-
puts " udid: '00008030-001A1B2C3D4E567F',"
|
|
86
|
-
puts " platform: 'IOS'"
|
|
87
|
-
puts '})'
|
|
88
|
-
puts
|
|
89
|
-
|
|
90
|
-
puts '# Error handling'
|
|
91
|
-
puts 'begin'
|
|
92
|
-
puts " client.get('/api/v1/organizations/999') # Non-existent org"
|
|
93
|
-
puts 'rescue Mysigner::NotFoundError => e'
|
|
94
|
-
puts " puts \"Error: \#{e.message}\""
|
|
95
|
-
puts 'end'
|
|
96
|
-
puts
|
|
97
|
-
|
|
98
|
-
puts '=' * 60
|
|
99
|
-
puts '✅ All basic tests completed!'
|
|
100
|
-
puts '=' * 60
|
|
101
|
-
puts
|
|
102
|
-
puts 'To run automated tests: bundle exec rspec'
|
|
103
|
-
puts
|