@boltic/cli 1.0.6-beta.12 → 1.0.6-beta.14
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.
- package/README.md +415 -59
- package/commands/integration.js +202 -24
- package/helper/validation.js +45 -5
- package/package.json +3 -3
- package/templates/schemas.js +14 -14
package/README.md
CHANGED
|
@@ -1,149 +1,505 @@
|
|
|
1
1
|
# ⚡ Boltic CLI
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> **Professional CLI tool for creating, managing, and publishing Boltic Workflow integrations with enterprise-grade features and seamless developer experience.**
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@boltic/cli)
|
|
6
|
-
[](https://github.com
|
|
6
|
+
[](https://github.com/bolticio/cli)
|
|
7
7
|
[](./LICENSE)
|
|
8
8
|
[](https://github.com/bolticio/cli/actions/workflows/npm-publish.yml)
|
|
9
|
+
[](http://makeapullrequest.com)
|
|
10
|
+
[](https://github.com/bolticio/cli/graphs/commit-activity)
|
|
11
|
+
|
|
12
|
+
<div align="center">
|
|
13
|
+
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
**Streamline your integration development workflow with Boltic CLI**
|
|
17
|
+
|
|
18
|
+
[Features](#-features) • [Installation](#-installation) • [Quick Start](#-quick-start) • [Documentation](#-documentation) • [Contributing](#-contributing)
|
|
19
|
+
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 📋 Table of Contents
|
|
25
|
+
|
|
26
|
+
- [✨ Features](#-features)
|
|
27
|
+
- [🚀 Quick Start](#-quick-start)
|
|
28
|
+
- [📦 Installation](#-installation)
|
|
29
|
+
- [🔐 Authentication](#-authentication)
|
|
30
|
+
- [🧩 Integration Management](#-integration-management)
|
|
31
|
+
- [📚 Command Reference](#-command-reference)
|
|
32
|
+
- [🛠️ Development Workflow](#️-development-workflow)
|
|
33
|
+
- [🔧 Configuration](#-configuration)
|
|
34
|
+
- [🛡️ Security](#-security)
|
|
35
|
+
- [🐛 Troubleshooting](#-troubleshooting)
|
|
36
|
+
- [📖 Documentation](#-documentation)
|
|
37
|
+
- [🤝 Contributing](#-contributing)
|
|
38
|
+
- [📄 License](#-license)
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## ✨ Features
|
|
43
|
+
|
|
44
|
+
- 🔐 **Secure Authentication** - Enterprise-grade token management with secure storage
|
|
45
|
+
- 🚀 **Rapid Integration Development** - Create integrations in minutes, not hours
|
|
46
|
+
- 📦 **Smart Project Management** - Automated folder structure and configuration
|
|
47
|
+
- 🔄 **Real-time Synchronization** - Instant sync with Boltic Cloud platform
|
|
48
|
+
- 🎯 **Type-safe Development** - Support for Workflow Activities and Triggers
|
|
49
|
+
- 🎨 **Rich Interactive UI** - Beautiful command-line interface with progress indicators
|
|
50
|
+
- 📊 **Comprehensive Validation** - Built-in validation for all integration components
|
|
51
|
+
- 🔧 **Developer Experience** - Hot reload, debugging tools, and comprehensive error handling
|
|
52
|
+
- 🌐 **Multi-platform Support** - Works seamlessly on Windows, macOS, and Linux
|
|
53
|
+
- 📈 **Version Control Integration** - Git-friendly workflow with proper ignore patterns
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 🚀 Quick Start
|
|
58
|
+
|
|
59
|
+
Get up and running with Boltic CLI in under 2 minutes:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Install Boltic CLI globally
|
|
63
|
+
npm install -g @boltic/cli
|
|
64
|
+
|
|
65
|
+
# Authenticate with your Boltic account
|
|
66
|
+
boltic login
|
|
67
|
+
|
|
68
|
+
# Create your first integration
|
|
69
|
+
boltic integration create
|
|
70
|
+
|
|
71
|
+
# Sync your changes
|
|
72
|
+
boltic integration sync
|
|
73
|
+
|
|
74
|
+
# Submit for review
|
|
75
|
+
boltic integration submit
|
|
76
|
+
```
|
|
9
77
|
|
|
10
78
|
---
|
|
11
79
|
|
|
12
80
|
## 📦 Installation
|
|
13
81
|
|
|
14
|
-
|
|
82
|
+
### Prerequisites
|
|
83
|
+
|
|
84
|
+
- **Node.js** 18.0.0 or higher
|
|
85
|
+
- **npm** 8.0.0 or higher
|
|
86
|
+
- **Git** (for version control)
|
|
87
|
+
|
|
88
|
+
### Global Installation (Recommended)
|
|
15
89
|
|
|
16
90
|
```bash
|
|
17
91
|
npm install -g @boltic/cli
|
|
18
92
|
```
|
|
19
93
|
|
|
94
|
+
### Verify Installation
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
boltic --version
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Development Installation
|
|
101
|
+
|
|
102
|
+
For contributors and developers:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Clone the repository
|
|
106
|
+
git clone https://github.com/bolticio/cli.git
|
|
107
|
+
cd cli
|
|
108
|
+
|
|
109
|
+
# Install dependencies
|
|
110
|
+
npm install
|
|
111
|
+
|
|
112
|
+
# Link for development
|
|
113
|
+
npm link
|
|
114
|
+
|
|
115
|
+
# Run tests
|
|
116
|
+
npm test
|
|
117
|
+
```
|
|
118
|
+
|
|
20
119
|
---
|
|
21
120
|
|
|
22
121
|
## 🔐 Authentication
|
|
23
122
|
|
|
24
|
-
|
|
123
|
+
Boltic CLI uses a secure OAuth 2.0 flow with browser-based authentication for enhanced security and user experience.
|
|
124
|
+
|
|
125
|
+
### Initial Login
|
|
25
126
|
|
|
26
127
|
```bash
|
|
27
128
|
boltic login
|
|
28
129
|
```
|
|
29
130
|
|
|
30
|
-
|
|
131
|
+
The authentication process follows these steps:
|
|
132
|
+
|
|
133
|
+
1. **Browser Launch**: CLI automatically opens your default browser to the Boltic login page
|
|
134
|
+
2. **OAuth Flow**: Complete the authentication in your browser (email/password or SSO)
|
|
135
|
+
3. **Token Exchange**: CLI automatically exchanges the authorization code for access tokens
|
|
136
|
+
4. **Secure Storage**: Tokens are encrypted and stored in your system's keychain
|
|
137
|
+
|
|
138
|
+
### Authentication Flow
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# Start authentication
|
|
142
|
+
boltic login
|
|
143
|
+
|
|
144
|
+
# CLI will:
|
|
145
|
+
# 1. Generate a unique request code
|
|
146
|
+
# 2. Open browser to: https://console.fynd.com/auth/sign-in
|
|
147
|
+
# 3. Wait for you to complete login in browser
|
|
148
|
+
# 4. Poll for session data (up to 5 minutes)
|
|
149
|
+
# 5. Exchange session for bearer token
|
|
150
|
+
# 6. Store tokens securely
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Secure Token Storage
|
|
154
|
+
|
|
155
|
+
Your authentication credentials are securely stored using your system's native keychain:
|
|
156
|
+
|
|
157
|
+
- **macOS**: Keychain Access (`boltic-cli` service)
|
|
158
|
+
- **Windows**: Credential Manager (`boltic-cli` service)
|
|
159
|
+
- **Linux**: Secret Service API (`boltic-cli` service)
|
|
160
|
+
|
|
161
|
+
**Stored Credentials:**
|
|
162
|
+
|
|
163
|
+
- `token`: Bearer token for API authentication
|
|
164
|
+
- `session`: Session cookie for web requests
|
|
165
|
+
- `account_id`: Your Boltic account identifier
|
|
166
|
+
|
|
167
|
+
### Logout and Token Management
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# Clear all stored credentials
|
|
171
|
+
boltic logout
|
|
172
|
+
|
|
173
|
+
# Check authentication status
|
|
174
|
+
boltic integration list # Will prompt login if not authenticated
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Troubleshooting Authentication
|
|
178
|
+
|
|
179
|
+
#### Common Issues
|
|
180
|
+
|
|
181
|
+
**Browser doesn't open automatically:**
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Manual login URL will be displayed
|
|
185
|
+
# Copy and paste the URL into your browser
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Authentication timeout:**
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# Retry login (5-minute timeout)
|
|
192
|
+
boltic login
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Connection issues:**
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# Check network connectivity
|
|
199
|
+
ping console.fynd.com
|
|
200
|
+
|
|
201
|
+
# Try different environment
|
|
202
|
+
boltic env set fcz0
|
|
203
|
+
boltic login
|
|
204
|
+
```
|
|
31
205
|
|
|
32
206
|
---
|
|
33
207
|
|
|
34
208
|
## 🧩 Integration Management
|
|
35
209
|
|
|
36
|
-
###
|
|
210
|
+
### Creating New Integrations
|
|
37
211
|
|
|
38
212
|
```bash
|
|
39
213
|
boltic integration create
|
|
40
214
|
```
|
|
41
215
|
|
|
42
|
-
|
|
216
|
+
#### Interactive Setup Process
|
|
217
|
+
|
|
218
|
+
The CLI will guide you through:
|
|
219
|
+
|
|
220
|
+
1. **Integration Details**
|
|
221
|
+
- Name (alphanumeric + underscores only)
|
|
222
|
+
- Description (human-readable)
|
|
223
|
+
- AI-generated description
|
|
224
|
+
|
|
225
|
+
2. **Visual Assets**
|
|
226
|
+
- Icon selection (SVG format required)
|
|
227
|
+
- Brand colors and styling
|
|
228
|
+
|
|
229
|
+
3. **Integration Type**
|
|
230
|
+
- **Workflow Activity**: Reusable components for specific tasks
|
|
231
|
+
- **Workflow Trigger**: Event-driven components that initiate workflows
|
|
232
|
+
- **Both**: Create both types simultaneously
|
|
233
|
+
|
|
234
|
+
4. **Categorization**
|
|
235
|
+
- Integration Group (Analytics, CRM, ERP, Marketing, etc.)
|
|
236
|
+
- Tags and metadata
|
|
237
|
+
|
|
238
|
+
#### Generated Project Structure
|
|
239
|
+
|
|
240
|
+
```
|
|
241
|
+
my-integration/
|
|
242
|
+
├── schemas/
|
|
243
|
+
│ ├── resources/
|
|
244
|
+
│ │ └── resource1.json
|
|
245
|
+
│ ├── authentication.json
|
|
246
|
+
│ ├── base.json
|
|
247
|
+
│ └── webhook.json
|
|
248
|
+
├── Authentication.mdx
|
|
249
|
+
├── Documentation.mdx
|
|
250
|
+
└── spec.json
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**File Descriptions:**
|
|
43
254
|
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
- You can choose to create both types for the same integration
|
|
255
|
+
- **`schemas/`** - Schema definitions for the integration
|
|
256
|
+
- **`resources/`** - Resource-specific schemas (e.g., `resource1.json`)
|
|
257
|
+
- **`authentication.json`** - Authentication configuration and parameters
|
|
258
|
+
- **`base.json`** - Base integration configuration and parameters
|
|
259
|
+
- **`webhook.json`** - Webhook configuration (for trigger integrations)
|
|
50
260
|
|
|
51
|
-
-
|
|
52
|
-
|
|
261
|
+
- **`Authentication.mdx`** - Authentication documentation in Markdown format
|
|
262
|
+
- **`Documentation.mdx`** - General integration documentation
|
|
263
|
+
- **`spec.json`** - Integration specification and metadata
|
|
53
264
|
|
|
54
|
-
|
|
55
|
-
- e.g., Analytics, CRM, ERP, Marketing, Payment, Social Media, Other
|
|
265
|
+
### Managing Existing Integrations
|
|
56
266
|
|
|
57
|
-
|
|
267
|
+
#### Edit Integration
|
|
58
268
|
|
|
59
269
|
```bash
|
|
270
|
+
# Edit current integration
|
|
60
271
|
boltic integration edit
|
|
272
|
+
|
|
61
273
|
```
|
|
62
274
|
|
|
63
|
-
|
|
275
|
+
#### Sync Changes
|
|
64
276
|
|
|
65
277
|
```bash
|
|
278
|
+
# Sync all changes
|
|
66
279
|
boltic integration sync
|
|
67
280
|
```
|
|
68
281
|
|
|
69
|
-
|
|
282
|
+
#### Pull Latest Changes
|
|
70
283
|
|
|
71
284
|
```bash
|
|
285
|
+
# Pull latest from Boltic Cloud
|
|
286
|
+
boltic integration pull
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
#### Submit for Review
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
# Submit for publishing review
|
|
72
293
|
boltic integration submit
|
|
73
294
|
```
|
|
74
295
|
|
|
75
296
|
---
|
|
76
297
|
|
|
77
|
-
##
|
|
298
|
+
## 📚 Command Reference
|
|
78
299
|
|
|
79
|
-
|
|
80
|
-
| --------------------------- | -------------------------------------------------------- |
|
|
81
|
-
| `boltic login` | Authenticate with Boltic |
|
|
82
|
-
| `boltic integration create` | Create a new integration |
|
|
83
|
-
| `boltic integration sync` | Sync changes to your draft |
|
|
84
|
-
| `boltic integration submit` | Submit integration for review |
|
|
85
|
-
| `boltic integration pull` | Pull the latest changes of an integration from the Cloud |
|
|
86
|
-
| `boltic integration edit` | Edit an existing integration |
|
|
87
|
-
| `boltic help` | Show CLI help |
|
|
88
|
-
| `boltic version` | Display CLI version |
|
|
300
|
+
### Core Commands
|
|
89
301
|
|
|
90
|
-
|
|
302
|
+
| Command | Description | Options |
|
|
303
|
+
| ---------------- | --------------------------------- | ------- |
|
|
304
|
+
| `boltic login` | Authenticate with Boltic platform | |
|
|
305
|
+
| `boltic logout` | Clear stored credentials | |
|
|
306
|
+
| `boltic version` | Display CLI version | |
|
|
307
|
+
| `boltic help` | Show comprehensive help | |
|
|
91
308
|
|
|
92
|
-
|
|
309
|
+
### Integration Commands
|
|
310
|
+
|
|
311
|
+
| Command | Description | Options |
|
|
312
|
+
| --------------------------- | ------------------------- | --------------------- |
|
|
313
|
+
| `boltic integration create` | Create new integration | Interactive prompts |
|
|
314
|
+
| `boltic integration edit` | Edit existing integration | Interactive prompt |
|
|
315
|
+
| `boltic integration sync` | Sync local changes | Interactive prompt |
|
|
316
|
+
| `boltic integration pull` | Pull latest changes | Interactive prompt |
|
|
317
|
+
| `boltic integration submit` | Submit for review | |
|
|
318
|
+
| `boltic integration status` | Check integration status | Interactive selection |
|
|
319
|
+
| `boltic integration help` | Show integration help | |
|
|
320
|
+
|
|
321
|
+
### Help and Documentation
|
|
93
322
|
|
|
94
323
|
```bash
|
|
95
|
-
#
|
|
96
|
-
boltic
|
|
324
|
+
# General help
|
|
325
|
+
boltic help
|
|
326
|
+
|
|
327
|
+
# Command-specific help
|
|
328
|
+
boltic integration help
|
|
329
|
+
boltic login help
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## 🛠️ Development Workflow
|
|
97
335
|
|
|
98
|
-
|
|
336
|
+
### Typical Development Cycle
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
# 1. Start Development
|
|
99
340
|
boltic integration create
|
|
341
|
+
cd my-integration
|
|
342
|
+
|
|
343
|
+
# 2. Make Changes
|
|
344
|
+
# Edit your integration files...
|
|
100
345
|
|
|
101
|
-
#
|
|
346
|
+
# 3. Sync Changes
|
|
102
347
|
boltic integration sync
|
|
103
348
|
|
|
104
|
-
#
|
|
349
|
+
# 4. Iterate
|
|
350
|
+
# Make more changes and sync...
|
|
351
|
+
|
|
352
|
+
# 5. Submit for Review
|
|
105
353
|
boltic integration submit
|
|
354
|
+
```
|
|
106
355
|
|
|
107
|
-
|
|
108
|
-
boltic integration pull
|
|
356
|
+
---
|
|
109
357
|
|
|
110
|
-
|
|
111
|
-
|
|
358
|
+
## 🐛 Troubleshooting
|
|
359
|
+
|
|
360
|
+
### Common Issues
|
|
361
|
+
|
|
362
|
+
#### Authentication Problems
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
# Clear stored credentials
|
|
366
|
+
boltic logout
|
|
367
|
+
|
|
368
|
+
# Re-authenticate
|
|
369
|
+
boltic login
|
|
370
|
+
|
|
371
|
+
# Check connection
|
|
372
|
+
ping console.fynd.com
|
|
112
373
|
```
|
|
113
374
|
|
|
114
|
-
|
|
375
|
+
#### Sync Issues
|
|
115
376
|
|
|
116
|
-
|
|
377
|
+
```bash
|
|
378
|
+
# Check status
|
|
379
|
+
boltic integration status
|
|
117
380
|
|
|
118
|
-
|
|
381
|
+
# Force sync
|
|
382
|
+
boltic integration sync
|
|
119
383
|
|
|
120
|
-
|
|
121
|
-
- Retry `boltic login` if your token has expired.
|
|
384
|
+
```
|
|
122
385
|
|
|
123
|
-
|
|
386
|
+
#### Network Issues
|
|
124
387
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
388
|
+
```bash
|
|
389
|
+
# Test connectivity
|
|
390
|
+
ping console.fynd.com
|
|
128
391
|
|
|
129
|
-
|
|
392
|
+
# Check API status
|
|
393
|
+
boltic integration status
|
|
130
394
|
|
|
131
|
-
|
|
395
|
+
# Enable verbose logging for debugging
|
|
396
|
+
boltic --verbose integration sync
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Debug Mode
|
|
400
|
+
|
|
401
|
+
```bash
|
|
402
|
+
# Enable verbose logging
|
|
403
|
+
boltic --verbose integration sync
|
|
404
|
+
|
|
405
|
+
# Run with verbose output for any command
|
|
406
|
+
boltic --verbose integration create
|
|
407
|
+
boltic --verbose login
|
|
408
|
+
```
|
|
132
409
|
|
|
133
|
-
|
|
410
|
+
### Getting Help
|
|
134
411
|
|
|
135
412
|
```bash
|
|
136
|
-
#
|
|
413
|
+
# Comprehensive help
|
|
137
414
|
boltic help
|
|
138
415
|
|
|
139
|
-
#
|
|
416
|
+
# Command-specific help
|
|
140
417
|
boltic integration help
|
|
141
418
|
```
|
|
142
419
|
|
|
143
|
-
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## 📖 Documentation
|
|
423
|
+
|
|
424
|
+
### Official Resources
|
|
425
|
+
|
|
426
|
+
- 📚 **[Boltic Documentation](https://docs.boltic.io)** - Complete API reference and guides
|
|
427
|
+
- 🎥 **[Video Tutorials](https://boltic.io/tutorials)** - Step-by-step video guides
|
|
428
|
+
- 💡 **[Examples Repository](https://github.com/bolticio/examples)** - Real-world integration examples
|
|
429
|
+
- 🚀 **[Quick Start Guide](https://docs.boltic.io/quickstart)** - Get started in 5 minutes
|
|
430
|
+
|
|
431
|
+
### Community Resources
|
|
432
|
+
|
|
433
|
+
- 🐛 **[Issue Tracker](https://github.com/bolticio/cli/issues)** - Report bugs and request features
|
|
434
|
+
- 📝 **[Blog](https://boltic.io/blog)** - Latest updates and best practices
|
|
435
|
+
|
|
436
|
+
### CLI Documentation
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
# Open documentation in browser
|
|
440
|
+
boltic docs
|
|
441
|
+
```
|
|
144
442
|
|
|
145
443
|
---
|
|
146
444
|
|
|
147
|
-
##
|
|
445
|
+
## 🤝 Contributing
|
|
446
|
+
|
|
447
|
+
We welcome contributions from the community! Here's how you can help:
|
|
448
|
+
|
|
449
|
+
### Development Setup
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
# Fork and clone
|
|
453
|
+
git clone https://github.com/your-username/cli.git
|
|
454
|
+
cd cli
|
|
455
|
+
|
|
456
|
+
# Install dependencies
|
|
457
|
+
npm install
|
|
458
|
+
|
|
459
|
+
# Link for development
|
|
460
|
+
npm link
|
|
461
|
+
|
|
462
|
+
# Run tests
|
|
463
|
+
npm test
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Contribution Guidelines
|
|
467
|
+
|
|
468
|
+
1. **Fork the repository**
|
|
469
|
+
2. **Create a feature branch**: `git checkout -b feature/amazing-feature`
|
|
470
|
+
3. **Make your changes** with proper tests
|
|
471
|
+
4. **Run the test suite**: `npm test`
|
|
472
|
+
5. **Commit your changes**: `git commit -m 'Add amazing feature'`
|
|
473
|
+
6. **Push to the branch**: `git push origin feature/amazing-feature`
|
|
474
|
+
7. **Open a Pull Request**
|
|
475
|
+
|
|
476
|
+
### Code Standards
|
|
477
|
+
|
|
478
|
+
- Follow **ESLint** configuration
|
|
479
|
+
- Write **comprehensive tests** for new features
|
|
480
|
+
- Update **documentation** for API changes
|
|
481
|
+
- Follow **conventional commits** for commit messages
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
## 📄 License
|
|
486
|
+
|
|
487
|
+
This project is licensed under the **ISC License** - see the [LICENSE](LICENSE) file for details.
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
## 🙏 Acknowledgments
|
|
492
|
+
|
|
493
|
+
- **Boltic Team** - For building an amazing platform
|
|
494
|
+
- **Open Source Contributors** - For their valuable contributions
|
|
495
|
+
- **Community** - For feedback, bug reports, and feature requests
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
<div align="center">
|
|
500
|
+
|
|
501
|
+
**Made with ❤️ by the Boltic Team**
|
|
502
|
+
|
|
503
|
+
[Website](https://boltic.io) • [Documentation](https://docs.boltic.io) • [Support](https://support.boltic.io) • [Discord](https://discord.gg/boltic)
|
|
148
504
|
|
|
149
|
-
|
|
505
|
+
</div>
|
package/commands/integration.js
CHANGED
|
@@ -55,7 +55,7 @@ const commands = {
|
|
|
55
55
|
action: handleStatus,
|
|
56
56
|
},
|
|
57
57
|
test: {
|
|
58
|
-
description: "Run tests for the integration",
|
|
58
|
+
description: "Run tests for the integration with coverage",
|
|
59
59
|
action: handleTest,
|
|
60
60
|
},
|
|
61
61
|
help: {
|
|
@@ -927,6 +927,26 @@ function showHelp() {
|
|
|
927
927
|
Object.entries(commands).forEach(([cmd, details]) => {
|
|
928
928
|
console.log(chalk.bold(`${cmd}`) + ` - ${details.description}`);
|
|
929
929
|
});
|
|
930
|
+
|
|
931
|
+
console.log(chalk.cyan("\nTest Command Usage:"));
|
|
932
|
+
console.log(chalk.dim(" boltic integration test"));
|
|
933
|
+
console.log(chalk.dim(" boltic integration test --path /path/to/project"));
|
|
934
|
+
console.log(chalk.dim(" boltic integration test --config jest.config.js"));
|
|
935
|
+
console.log(chalk.dim(" boltic integration test --watchAll"));
|
|
936
|
+
console.log(chalk.dim(" boltic integration test --updateSnapshot"));
|
|
937
|
+
|
|
938
|
+
console.log(chalk.cyan("\nSupported Flags:"));
|
|
939
|
+
console.log(
|
|
940
|
+
chalk.dim(" --path <directory> Run tests in specific directory")
|
|
941
|
+
);
|
|
942
|
+
console.log(
|
|
943
|
+
chalk.dim(" --config <file> Use specific Jest config file")
|
|
944
|
+
);
|
|
945
|
+
console.log(
|
|
946
|
+
chalk.dim(" --watchAll Watch all files for changes")
|
|
947
|
+
);
|
|
948
|
+
console.log(chalk.dim(" --updateSnapshot Update snapshots"));
|
|
949
|
+
console.log(chalk.dim(" All other Jest CLI flags are supported"));
|
|
930
950
|
}
|
|
931
951
|
|
|
932
952
|
// Show detailed information about an integration
|
|
@@ -1054,7 +1074,9 @@ async function handleStatus() {
|
|
|
1054
1074
|
async function handleTest(args) {
|
|
1055
1075
|
// Parse command line arguments
|
|
1056
1076
|
let currentDir = process.cwd();
|
|
1077
|
+
let jestConfigFile = null;
|
|
1057
1078
|
const pathIndex = args.indexOf("--path");
|
|
1079
|
+
const configIndex = args.indexOf("--config");
|
|
1058
1080
|
|
|
1059
1081
|
if (pathIndex !== -1 && args[pathIndex + 1]) {
|
|
1060
1082
|
currentDir = args[pathIndex + 1];
|
|
@@ -1069,72 +1091,228 @@ async function handleTest(args) {
|
|
|
1069
1091
|
}
|
|
1070
1092
|
}
|
|
1071
1093
|
|
|
1094
|
+
if (configIndex !== -1 && args[configIndex + 1]) {
|
|
1095
|
+
jestConfigFile = args[configIndex + 1];
|
|
1096
|
+
// Validate the config file path
|
|
1097
|
+
const configPath = path.isAbsolute(jestConfigFile)
|
|
1098
|
+
? jestConfigFile
|
|
1099
|
+
: path.join(currentDir, jestConfigFile);
|
|
1100
|
+
|
|
1101
|
+
if (!fs.existsSync(configPath)) {
|
|
1102
|
+
console.error(
|
|
1103
|
+
chalk.red(
|
|
1104
|
+
`Error: Jest config file does not exist: ${configPath}`
|
|
1105
|
+
)
|
|
1106
|
+
);
|
|
1107
|
+
return;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1072
1111
|
const { spawn } = await import("child_process");
|
|
1073
1112
|
|
|
1074
1113
|
console.log(chalk.cyan.bold("\n🧪 Running integration tests...\n"));
|
|
1075
1114
|
|
|
1076
|
-
// Look for test directory
|
|
1115
|
+
// Look for test directory and test files
|
|
1077
1116
|
const testDirs = ["test", "tests", "__tests__"];
|
|
1078
1117
|
let testDir = null;
|
|
1118
|
+
let testFiles = [];
|
|
1079
1119
|
|
|
1120
|
+
// Check for test directories
|
|
1080
1121
|
for (const dir of testDirs) {
|
|
1081
|
-
|
|
1122
|
+
const testPath = path.join(currentDir, dir);
|
|
1123
|
+
if (fs.existsSync(testPath)) {
|
|
1082
1124
|
testDir = dir;
|
|
1125
|
+
// Find all test files in the directory
|
|
1126
|
+
const files = fs.readdirSync(testPath);
|
|
1127
|
+
testFiles = files.filter(
|
|
1128
|
+
(file) =>
|
|
1129
|
+
file.endsWith(".test.js") ||
|
|
1130
|
+
file.endsWith(".spec.js") ||
|
|
1131
|
+
file.endsWith(".test.ts") ||
|
|
1132
|
+
file.endsWith(".spec.ts")
|
|
1133
|
+
);
|
|
1083
1134
|
break;
|
|
1084
1135
|
}
|
|
1085
1136
|
}
|
|
1086
1137
|
|
|
1138
|
+
// If no test directory found, look for test files in current directory
|
|
1087
1139
|
if (!testDir) {
|
|
1140
|
+
const currentDirFiles = fs.readdirSync(currentDir);
|
|
1141
|
+
testFiles = currentDirFiles.filter(
|
|
1142
|
+
(file) =>
|
|
1143
|
+
file.endsWith(".test.js") ||
|
|
1144
|
+
file.endsWith(".spec.js") ||
|
|
1145
|
+
file.endsWith(".test.ts") ||
|
|
1146
|
+
file.endsWith(".spec.ts")
|
|
1147
|
+
);
|
|
1148
|
+
|
|
1149
|
+
if (testFiles.length === 0) {
|
|
1150
|
+
console.log(
|
|
1151
|
+
chalk.yellow(
|
|
1152
|
+
"⚠️ No test files found. Looked for: test, tests, __tests__ directories and *.test.js, *.spec.js, *.test.ts, *.spec.ts files"
|
|
1153
|
+
)
|
|
1154
|
+
);
|
|
1155
|
+
return;
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
if (testFiles.length === 0 && testDir) {
|
|
1088
1160
|
console.log(
|
|
1089
1161
|
chalk.yellow(
|
|
1090
|
-
|
|
1162
|
+
`⚠️ No test files found in ${testDir} directory. Looking for: *.test.js, *.spec.js, *.test.ts, *.spec.ts files`
|
|
1091
1163
|
)
|
|
1092
1164
|
);
|
|
1093
1165
|
return;
|
|
1094
1166
|
}
|
|
1095
1167
|
|
|
1096
|
-
console.log(chalk.dim(`📁 Found test directory: ${testDir}`));
|
|
1168
|
+
console.log(chalk.dim(`📁 Found test directory: ${testDir || currentDir}`));
|
|
1169
|
+
console.log(
|
|
1170
|
+
chalk.dim(
|
|
1171
|
+
`📋 Found ${testFiles.length} test file(s): ${testFiles.join(", ")}`
|
|
1172
|
+
)
|
|
1173
|
+
);
|
|
1097
1174
|
|
|
1098
|
-
// Check
|
|
1099
|
-
|
|
1100
|
-
|
|
1175
|
+
// Check for Jest configuration
|
|
1176
|
+
let jestConfigPath;
|
|
1177
|
+
if (jestConfigFile) {
|
|
1178
|
+
jestConfigPath = path.isAbsolute(jestConfigFile)
|
|
1179
|
+
? jestConfigFile
|
|
1180
|
+
: path.join(currentDir, jestConfigFile);
|
|
1181
|
+
} else {
|
|
1182
|
+
// Look for default config files
|
|
1183
|
+
const defaultConfigs = [
|
|
1184
|
+
"jest.config.cjs",
|
|
1185
|
+
"jest.config.js",
|
|
1186
|
+
"jest.config.json",
|
|
1187
|
+
];
|
|
1188
|
+
for (const configFile of defaultConfigs) {
|
|
1189
|
+
const configPath = path.join(currentDir, configFile);
|
|
1190
|
+
if (fs.existsSync(configPath)) {
|
|
1191
|
+
jestConfigPath = configPath;
|
|
1192
|
+
break;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1101
1196
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1197
|
+
const jestConfigExists = !!jestConfigPath;
|
|
1198
|
+
const configFileName = jestConfigPath
|
|
1199
|
+
? path.basename(jestConfigPath)
|
|
1200
|
+
: null;
|
|
1201
|
+
|
|
1202
|
+
console.log(
|
|
1203
|
+
chalk.dim(
|
|
1204
|
+
`⚙️ Jest configuration: ${jestConfigExists ? `Found ${configFileName}` : "Using default configuration"}`
|
|
1205
|
+
)
|
|
1206
|
+
);
|
|
1207
|
+
|
|
1208
|
+
// Prepare Jest arguments
|
|
1209
|
+
const jestArgs = ["jest"];
|
|
1210
|
+
|
|
1211
|
+
// Add basic Jest flags
|
|
1212
|
+
jestArgs.push("--coverage");
|
|
1213
|
+
jestArgs.push("--verbose");
|
|
1214
|
+
jestArgs.push("--colors");
|
|
1215
|
+
jestArgs.push("--passWithNoTests");
|
|
1216
|
+
|
|
1217
|
+
// Add config file if exists, otherwise use simple patterns
|
|
1218
|
+
if (jestConfigExists) {
|
|
1219
|
+
jestArgs.push("--config", jestConfigPath);
|
|
1220
|
+
} else {
|
|
1221
|
+
// Use simple test matching patterns
|
|
1222
|
+
if (testDir) {
|
|
1223
|
+
jestArgs.push(
|
|
1224
|
+
"--testMatch",
|
|
1225
|
+
`**/${testDir}/**/*.{test,spec}.{js,ts}`
|
|
1110
1226
|
);
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1227
|
+
} else {
|
|
1228
|
+
jestArgs.push("--testMatch", "**/*.{test,spec}.{js,ts}");
|
|
1113
1229
|
}
|
|
1230
|
+
jestArgs.push("--collectCoverageFrom", "lib/**/*.{js,ts}");
|
|
1231
|
+
jestArgs.push("--collectCoverageFrom", "src/**/*.{js,ts}");
|
|
1232
|
+
jestArgs.push("--collectCoverageFrom", "*.{js,ts}");
|
|
1233
|
+
jestArgs.push("--coveragePathIgnorePatterns", "/node_modules/");
|
|
1234
|
+
jestArgs.push("--coveragePathIgnorePatterns", "/tests/");
|
|
1114
1235
|
}
|
|
1115
1236
|
|
|
1116
|
-
|
|
1237
|
+
// Add any additional Jest arguments passed by user
|
|
1238
|
+
const additionalArgs = args.filter((arg, index) => {
|
|
1239
|
+
// Skip our custom flags and their values
|
|
1240
|
+
if (arg === "--path" || arg === "--config") return false;
|
|
1241
|
+
if (args[index - 1] === "--path" || args[index - 1] === "--config")
|
|
1242
|
+
return false;
|
|
1243
|
+
return true;
|
|
1244
|
+
});
|
|
1245
|
+
|
|
1246
|
+
if (additionalArgs.length > 0) {
|
|
1247
|
+
jestArgs.push(...additionalArgs);
|
|
1117
1248
|
console.log(
|
|
1118
|
-
chalk.
|
|
1119
|
-
|
|
1249
|
+
chalk.dim(
|
|
1250
|
+
`🔧 Additional Jest arguments: ${additionalArgs.join(" ")}`
|
|
1120
1251
|
)
|
|
1121
1252
|
);
|
|
1122
|
-
return;
|
|
1123
1253
|
}
|
|
1124
1254
|
|
|
1125
|
-
|
|
1255
|
+
console.log(chalk.dim(`🚀 Running command: npx ${jestArgs.join(" ")}`));
|
|
1256
|
+
console.log(chalk.cyan("─".repeat(50)));
|
|
1257
|
+
|
|
1258
|
+
// Run Jest with coverage
|
|
1126
1259
|
return new Promise((resolve, reject) => {
|
|
1127
|
-
const jestProcess = spawn("npx",
|
|
1260
|
+
const jestProcess = spawn("npx", jestArgs, {
|
|
1128
1261
|
stdio: "inherit",
|
|
1129
1262
|
shell: true,
|
|
1263
|
+
cwd: currentDir,
|
|
1130
1264
|
});
|
|
1131
1265
|
|
|
1132
1266
|
jestProcess.on("close", (code) => {
|
|
1267
|
+
console.log(chalk.cyan("─".repeat(50)));
|
|
1268
|
+
|
|
1133
1269
|
if (code === 0) {
|
|
1134
1270
|
console.log(chalk.green.bold("\n✅ All tests passed!"));
|
|
1271
|
+
|
|
1272
|
+
// Check for coverage directory
|
|
1273
|
+
const coverageDir = path.join(currentDir, "coverage");
|
|
1274
|
+
if (fs.existsSync(coverageDir)) {
|
|
1275
|
+
console.log(chalk.cyan("\n📊 Coverage Report Generated:"));
|
|
1276
|
+
console.log(chalk.dim(` Directory: ${coverageDir}`));
|
|
1277
|
+
|
|
1278
|
+
// Check for HTML report
|
|
1279
|
+
const htmlReportPath = path.join(
|
|
1280
|
+
coverageDir,
|
|
1281
|
+
"lcov-report",
|
|
1282
|
+
"index.html"
|
|
1283
|
+
);
|
|
1284
|
+
if (fs.existsSync(htmlReportPath)) {
|
|
1285
|
+
console.log(
|
|
1286
|
+
chalk.dim(` HTML Report: ${htmlReportPath}`)
|
|
1287
|
+
);
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
// Check for text report
|
|
1291
|
+
const textReportPath = path.join(coverageDir, "lcov.info");
|
|
1292
|
+
if (fs.existsSync(textReportPath)) {
|
|
1293
|
+
console.log(
|
|
1294
|
+
chalk.dim(` LCOV Report: ${textReportPath}`)
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
// Show test summary
|
|
1300
|
+
console.log(chalk.cyan("\n📋 Test Summary:"));
|
|
1301
|
+
console.log(chalk.dim(` Test files: ${testFiles.length}`));
|
|
1302
|
+
console.log(
|
|
1303
|
+
chalk.dim(` Test directory: ${testDir || currentDir}`)
|
|
1304
|
+
);
|
|
1305
|
+
console.log(chalk.green(" Status: PASSED"));
|
|
1135
1306
|
} else {
|
|
1136
1307
|
console.log(chalk.red.bold("\n❌ Some tests failed."));
|
|
1308
|
+
console.log(chalk.red(` Exit code: ${code}`));
|
|
1137
1309
|
}
|
|
1310
|
+
|
|
1311
|
+
console.log(
|
|
1312
|
+
chalk.cyan(
|
|
1313
|
+
"\n💡 Tip: Check the coverage directory for detailed coverage reports"
|
|
1314
|
+
)
|
|
1315
|
+
);
|
|
1138
1316
|
resolve(code);
|
|
1139
1317
|
});
|
|
1140
1318
|
|
package/helper/validation.js
CHANGED
|
@@ -52,8 +52,14 @@ const findResourceFieldsWithOptions = (schema, fileLabel, errors) => {
|
|
|
52
52
|
}
|
|
53
53
|
return resourceFields;
|
|
54
54
|
};
|
|
55
|
-
const findOperationFieldsWithOptions = (
|
|
55
|
+
const findOperationFieldsWithOptions = (
|
|
56
|
+
schema,
|
|
57
|
+
fileLabel,
|
|
58
|
+
errors,
|
|
59
|
+
expectedResourceName
|
|
60
|
+
) => {
|
|
56
61
|
const operationFields = [];
|
|
62
|
+
|
|
57
63
|
if (Array.isArray(schema?.parameters)) {
|
|
58
64
|
schema.parameters.forEach((param) => {
|
|
59
65
|
if (
|
|
@@ -66,12 +72,28 @@ const findOperationFieldsWithOptions = (schema, fileLabel, errors) => {
|
|
|
66
72
|
fileLabel,
|
|
67
73
|
errors
|
|
68
74
|
);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
75
|
+
param.meta.options.forEach((opt, index) => {
|
|
76
|
+
if (typeof opt.value === "string") {
|
|
77
|
+
const parts = opt.value.split(".");
|
|
78
|
+
if (parts.length < 2) {
|
|
79
|
+
errors.add(
|
|
80
|
+
`"operation" field in "${fileLabel}" has an invalid option at index ${index} with value "${opt.value}". Expected format "resource.operation".`
|
|
81
|
+
);
|
|
82
|
+
} else {
|
|
83
|
+
const resource = parts[0];
|
|
84
|
+
if (resource !== expectedResourceName) {
|
|
85
|
+
errors.add(
|
|
86
|
+
`"operation" field in "${fileLabel}" has an inconsistent resource prefix at index ${index}. Found "${resource}" but expected "${expectedResourceName}".`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
operationFields.push(opt.value);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
72
93
|
}
|
|
73
94
|
});
|
|
74
95
|
}
|
|
96
|
+
|
|
75
97
|
return operationFields;
|
|
76
98
|
};
|
|
77
99
|
|
|
@@ -228,6 +250,23 @@ const validateComponentSchemas = (schemas, errors) => {
|
|
|
228
250
|
errors.add(`"${schema.name}" is missing a description.`);
|
|
229
251
|
}
|
|
230
252
|
|
|
253
|
+
// 🚨 Validate for duplicate options with same label and value
|
|
254
|
+
if (Array.isArray(schema.meta.options)) {
|
|
255
|
+
const seen = new Set();
|
|
256
|
+
schema.meta.options.forEach((option, index) => {
|
|
257
|
+
if (option && typeof option === "object") {
|
|
258
|
+
const key = `${option.label}::${option.value}`;
|
|
259
|
+
if (seen.has(key)) {
|
|
260
|
+
errors.add(
|
|
261
|
+
`"${schema.name}" contains duplicate option at index ${index} with label "${option.label}" and value "${option.value}".`
|
|
262
|
+
);
|
|
263
|
+
} else {
|
|
264
|
+
seen.add(key);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
231
270
|
// Validate against the specific component type schema
|
|
232
271
|
validateComponentByType(schema, schema.meta.displayType, errors);
|
|
233
272
|
});
|
|
@@ -366,7 +405,8 @@ const validateResources = (resourcesDir, resourceFields, errors) => {
|
|
|
366
405
|
const operationFields = findOperationFieldsWithOptions(
|
|
367
406
|
schema,
|
|
368
407
|
`${resourceFile}.json`,
|
|
369
|
-
errors
|
|
408
|
+
errors,
|
|
409
|
+
resourceFile
|
|
370
410
|
);
|
|
371
411
|
|
|
372
412
|
operationFields.forEach((operation) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boltic/cli",
|
|
3
|
-
"version": "1.0.6-beta.
|
|
3
|
+
"version": "1.0.6-beta.14",
|
|
4
4
|
"description": "A powerful CLI tool for managing Boltic Workflow integrations",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -44,7 +44,8 @@
|
|
|
44
44
|
"keytar": "^7.9.0",
|
|
45
45
|
"open": "^10.1.0",
|
|
46
46
|
"uuid": "^11.1.0",
|
|
47
|
-
"lodash.isempty": "^4.4.0"
|
|
47
|
+
"lodash.isempty": "^4.4.0",
|
|
48
|
+
"jest": "^29.7.0"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
51
|
"@babel/core": "^7.26.9",
|
|
@@ -58,7 +59,6 @@
|
|
|
58
59
|
"eslint-config-prettier": "^10.0.2",
|
|
59
60
|
"eslint-plugin-prettier": "^5.2.3",
|
|
60
61
|
"husky": "^9.1.7",
|
|
61
|
-
"jest": "^29.7.0",
|
|
62
62
|
"lint-staged": "^15.4.3",
|
|
63
63
|
"nodemon": "^3.1.9",
|
|
64
64
|
"prettier": "^3.5.3"
|
package/templates/schemas.js
CHANGED
|
@@ -51,12 +51,22 @@ const base = (name, create_catalogue) => {
|
|
|
51
51
|
name: "secret",
|
|
52
52
|
meta: {
|
|
53
53
|
displayName: "Service Account",
|
|
54
|
-
displayType: "
|
|
54
|
+
displayType: "autocomplete",
|
|
55
55
|
placeholder: "Select Service Account",
|
|
56
56
|
description:
|
|
57
57
|
"Your service account credentials are encrypted & can be removed at any time.",
|
|
58
58
|
options: [],
|
|
59
|
-
|
|
59
|
+
config: {
|
|
60
|
+
urlType: "secret",
|
|
61
|
+
method: "get",
|
|
62
|
+
url: `/${name.toUpperCase()}?current_page=1&page_size=999`,
|
|
63
|
+
labelKey: "name",
|
|
64
|
+
valueKey: "_id",
|
|
65
|
+
},
|
|
66
|
+
htmlProps: {
|
|
67
|
+
showAddNew: true,
|
|
68
|
+
},
|
|
69
|
+
value: "",
|
|
60
70
|
validation: {
|
|
61
71
|
required: true,
|
|
62
72
|
},
|
|
@@ -66,22 +76,12 @@ const base = (name, create_catalogue) => {
|
|
|
66
76
|
name: "secret",
|
|
67
77
|
meta: {
|
|
68
78
|
displayName: "Service Account",
|
|
69
|
-
displayType: "
|
|
79
|
+
displayType: "hidden",
|
|
70
80
|
placeholder: "Select Service Account",
|
|
71
81
|
description:
|
|
72
82
|
"Your service account credentials are encrypted & can be removed at any time.",
|
|
73
83
|
options: [],
|
|
74
|
-
|
|
75
|
-
urlType: "secret",
|
|
76
|
-
method: "get",
|
|
77
|
-
url: `/${name.toUpperCase()}?current_page=1&page_size=999`,
|
|
78
|
-
labelKey: "name",
|
|
79
|
-
valueKey: "_id",
|
|
80
|
-
},
|
|
81
|
-
htmlProps: {
|
|
82
|
-
showAddNew: true,
|
|
83
|
-
},
|
|
84
|
-
value: "",
|
|
84
|
+
value: `__BOLTIC_INTEGRATION_${name.toUpperCase()}`,
|
|
85
85
|
validation: {
|
|
86
86
|
required: true,
|
|
87
87
|
},
|