@matimo/bruno 0.1.0
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 +174 -0
- package/definition.yaml +33 -0
- package/package.json +17 -0
- package/tools/bru-utils.ts +51 -0
- package/tools/bruno_add_request/definition.yaml +108 -0
- package/tools/bruno_add_request/index.ts +101 -0
- package/tools/bruno_create_collection/definition.yaml +46 -0
- package/tools/bruno_create_collection/index.ts +55 -0
- package/tools/bruno_get_collection_info/definition.yaml +61 -0
- package/tools/bruno_get_collection_info/index.ts +119 -0
- package/tools/bruno_import_openapi/definition.yaml +75 -0
- package/tools/bruno_import_openapi/index.ts +102 -0
- package/tools/bruno_list_collections/definition.yaml +49 -0
- package/tools/bruno_list_collections/index.ts +101 -0
- package/tools/bruno_run_collection/definition.yaml +131 -0
- package/tools/bruno_run_collection/index.ts +99 -0
- package/tools/bruno_run_request/definition.yaml +69 -0
- package/tools/bruno_run_request/index.ts +104 -0
package/README.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# @matimo/bruno
|
|
2
|
+
|
|
3
|
+
Bruno CLI tools for Matimo — Enable AI agents to autonomously manage, execute, and validate API test collections.
|
|
4
|
+
|
|
5
|
+
## 📦 Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @matimo/bruno
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 🚀 Quick Start
|
|
12
|
+
|
|
13
|
+
### TypeScript / JavaScript
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { MatimoInstance } from '@matimo/core';
|
|
17
|
+
|
|
18
|
+
const matimo = await MatimoInstance.init('./packages/bruno/tools');
|
|
19
|
+
|
|
20
|
+
// List all collections in workspace
|
|
21
|
+
const collections = await matimo.execute('bruno_list_collections', {
|
|
22
|
+
workspace_path: './collections'
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Get collection metadata before running
|
|
26
|
+
const info = await matimo.execute('bruno_get_collection_info', {
|
|
27
|
+
collection_path: './collections/payment-api'
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Run entire collection
|
|
31
|
+
const result = await matimo.execute('bruno_run_collection', {
|
|
32
|
+
collection_path: './collections/payment-api',
|
|
33
|
+
environment: 'staging',
|
|
34
|
+
report_path: './reports/staging-results.json'
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Run single request for debugging
|
|
38
|
+
const response = await matimo.execute('bruno_run_request', {
|
|
39
|
+
collection_path: './collections/auth',
|
|
40
|
+
request_name: 'Login',
|
|
41
|
+
environment: 'staging'
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Bootstrap from OpenAPI spec
|
|
45
|
+
const imported = await matimo.execute('bruno_import_openapi', {
|
|
46
|
+
spec_source: 'https://api.example.com/openapi.json',
|
|
47
|
+
output_directory: './collections',
|
|
48
|
+
collection_name: 'Generated API Tests'
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Create new collection
|
|
52
|
+
const created = await matimo.execute('bruno_create_collection', {
|
|
53
|
+
collection_path: './collections/new-service',
|
|
54
|
+
collection_name: 'New Service Tests'
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## 📋 Available Tools
|
|
59
|
+
|
|
60
|
+
### 1. `bruno_run_collection`
|
|
61
|
+
Execute a Bruno API collection with configurable environments, data files, and reporting.
|
|
62
|
+
|
|
63
|
+
**Parameters:**
|
|
64
|
+
- `collection_path` (required) — Path to collection file or directory
|
|
65
|
+
- `environment` — Environment name (dev, staging, prod)
|
|
66
|
+
- `env_file` — Path to environment file override
|
|
67
|
+
- `data_file` — CSV/JSON data file for data-driven testing
|
|
68
|
+
- `iteration_count` — Number of iterations to run
|
|
69
|
+
- `delay_ms` — Delay between requests
|
|
70
|
+
- `tags` — Comma-separated tags (run requests with ALL tags)
|
|
71
|
+
- `exclude_tags` — Comma-separated tags (skip requests with ANY tags)
|
|
72
|
+
- `tests_only` — Run only requests with tests/assertions
|
|
73
|
+
- `bail_on_failure` — Stop on first failure
|
|
74
|
+
- `parallel` — Run requests in parallel
|
|
75
|
+
- `sandbox_mode` — JavaScript execution mode ('safe' or 'developer')
|
|
76
|
+
- `report_format` — Report format (json, junit, html)
|
|
77
|
+
- `report_path` — Path to write report file
|
|
78
|
+
|
|
79
|
+
**Returns:** Collection execution results, summary, and report path
|
|
80
|
+
|
|
81
|
+
### 2. `bruno_run_request`
|
|
82
|
+
Execute a single request for targeted debugging and validation.
|
|
83
|
+
|
|
84
|
+
**Parameters:**
|
|
85
|
+
- `collection_path` (required) — Collection directory
|
|
86
|
+
- `request_name` (required) — Request name to execute
|
|
87
|
+
- `environment` — Environment name override
|
|
88
|
+
- `env_file` — Environment file override
|
|
89
|
+
- `sandbox_mode` — JavaScript execution mode
|
|
90
|
+
|
|
91
|
+
**Returns:** Request/response details and assertion results
|
|
92
|
+
|
|
93
|
+
### 3. `bruno_list_collections`
|
|
94
|
+
Discover all collections in a workspace.
|
|
95
|
+
|
|
96
|
+
**Parameters:**
|
|
97
|
+
- `workspace_path` (required) — Workspace directory
|
|
98
|
+
- `filter` — Filter by collection name (substring)
|
|
99
|
+
|
|
100
|
+
**Returns:** Array of collection metadata
|
|
101
|
+
|
|
102
|
+
### 4. `bruno_get_collection_info`
|
|
103
|
+
Introspect collection structure before execution.
|
|
104
|
+
|
|
105
|
+
**Parameters:**
|
|
106
|
+
- `collection_path` (required) — Collection path
|
|
107
|
+
|
|
108
|
+
**Returns:** Collection structure, requests, environments, variables
|
|
109
|
+
|
|
110
|
+
### 5. `bruno_import_openapi`
|
|
111
|
+
Bootstrap a collection from OpenAPI 3.0 specification.
|
|
112
|
+
|
|
113
|
+
**Parameters:**
|
|
114
|
+
- `spec_source` (required) — Path or URL to OpenAPI spec
|
|
115
|
+
- `output_directory` (required) — Where to create collection
|
|
116
|
+
- `collection_name` — Collection name
|
|
117
|
+
- `collection_format` — 'bru' or 'opencollection'
|
|
118
|
+
- `group_by` — Group by 'tags' or 'path'
|
|
119
|
+
- `insecure` — Skip TLS verification
|
|
120
|
+
|
|
121
|
+
**Returns:** Collection path and metadata
|
|
122
|
+
|
|
123
|
+
### 6. `bruno_create_collection`
|
|
124
|
+
Create a new empty collection scaffold.
|
|
125
|
+
|
|
126
|
+
**Parameters:**
|
|
127
|
+
- `collection_path` (required) — Collection creation path
|
|
128
|
+
- `collection_name` (required) — Collection name
|
|
129
|
+
|
|
130
|
+
**Returns:** Creation status and path
|
|
131
|
+
|
|
132
|
+
## 🔄 Agent Workflows
|
|
133
|
+
|
|
134
|
+
### Autonomous Test Execution
|
|
135
|
+
```
|
|
136
|
+
Agent discovers spec → import_openapi → set environment → run_collection → parse results
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Multi-Environment Validation
|
|
140
|
+
```
|
|
141
|
+
list_collections → for each environment: set_env + run_collection → compare results
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Targeted Debugging
|
|
145
|
+
```
|
|
146
|
+
get_collection_info → run_request (single endpoint) → analyze response
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Data-Driven Testing
|
|
150
|
+
```
|
|
151
|
+
run_collection with CSV file → multiple iterations → aggregate metrics
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## 🔐 Authentication
|
|
155
|
+
|
|
156
|
+
Tools use environment variables for credentials. Bruno CLI manages environment setup — tools wrap CLI execution.
|
|
157
|
+
|
|
158
|
+
## 📖 Prerequisites
|
|
159
|
+
|
|
160
|
+
- **Bruno CLI** installed globally: `npm install -g @usebruno/cli` (or `pnpm install -g @usebruno/cli`)
|
|
161
|
+
- **Node.js** 18+ required
|
|
162
|
+
- Bruno collections in `.bru` format or OpenAPI specs
|
|
163
|
+
|
|
164
|
+
## 🤝 Integration
|
|
165
|
+
|
|
166
|
+
Works with:
|
|
167
|
+
- **LangChain** — Convert to StructuredTool
|
|
168
|
+
- **CrewAI** — Convert to BaseTool
|
|
169
|
+
- **MCP** — Expose via JSON-RPC to Claude / other MCP clients
|
|
170
|
+
- **Native** — Direct SDK usage
|
|
171
|
+
|
|
172
|
+
## 📝 License
|
|
173
|
+
|
|
174
|
+
MIT
|
package/definition.yaml
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Bruno CLI Provider Definition
|
|
2
|
+
#
|
|
3
|
+
# This file defines the configuration for Bruno CLI tools.
|
|
4
|
+
# All Bruno tools reference this provider definition.
|
|
5
|
+
|
|
6
|
+
name: bruno-provider
|
|
7
|
+
type: provider
|
|
8
|
+
version: '1.0.0'
|
|
9
|
+
|
|
10
|
+
description: |
|
|
11
|
+
Bruno CLI Provider Configuration
|
|
12
|
+
|
|
13
|
+
All Bruno tools use the locally-installed Bruno CLI.
|
|
14
|
+
|
|
15
|
+
Setup:
|
|
16
|
+
1. Install Bruno CLI:
|
|
17
|
+
npm install -g @usebruno/cli
|
|
18
|
+
or
|
|
19
|
+
brew install bruno
|
|
20
|
+
|
|
21
|
+
2. Bruno CLI v3+ provides:
|
|
22
|
+
- Collection management (create, list, import)
|
|
23
|
+
- Request execution (run single or full suite)
|
|
24
|
+
- OpenAPI spec import and generation
|
|
25
|
+
- Test result reporting
|
|
26
|
+
|
|
27
|
+
Authentication:
|
|
28
|
+
Bruno CLI tools run locally and don't require credentials.
|
|
29
|
+
API keys for tested endpoints should be provided in environment variables.
|
|
30
|
+
|
|
31
|
+
Documentation:
|
|
32
|
+
- Bruno Docs: https://www.usebruno.com/
|
|
33
|
+
- CLI Reference: https://www.usebruno.com/docs/cli/cli-overview
|
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@matimo/bruno",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Bruno CLI tools for Matimo — API collection execution, import, and validation",
|
|
5
|
+
"files": [
|
|
6
|
+
"tools",
|
|
7
|
+
"README.md",
|
|
8
|
+
"definition.yaml"
|
|
9
|
+
],
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@usebruno/cli": "^3.3.0",
|
|
12
|
+
"@matimo/core": "0.1.0"
|
|
13
|
+
},
|
|
14
|
+
"peerDependencies": {
|
|
15
|
+
"matimo": "0.1.0-alpha.14"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { execFileSync } from 'child_process';
|
|
2
|
+
|
|
3
|
+
export const BRU_MIN_VERSION_STR = '1.0.0';
|
|
4
|
+
const BRU_MIN_VERSION = [1, 0, 0] as const;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Verify the Bruno CLI is installed and meets the minimum required version.
|
|
8
|
+
*
|
|
9
|
+
* - Throws if `bru` is not found in PATH (ENOENT).
|
|
10
|
+
* - Throws if the installed version is below {@link BRU_MIN_VERSION_STR}.
|
|
11
|
+
* - Skips silently if the version string cannot be parsed (graceful degradation).
|
|
12
|
+
*/
|
|
13
|
+
export function checkBruVersion(): void {
|
|
14
|
+
let versionOutput: string;
|
|
15
|
+
try {
|
|
16
|
+
versionOutput = execFileSync('bru', ['--version'], { encoding: 'utf-8', stdio: 'pipe' });
|
|
17
|
+
} catch (err) {
|
|
18
|
+
if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
19
|
+
throw new Error(
|
|
20
|
+
"Bruno CLI ('bru') is not installed or not in PATH. " +
|
|
21
|
+
'Install it with: npm install -g @usebruno/cli',
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
// Other error — skip version check (bru is installed but --version failed for another reason)
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const match = versionOutput.trim().match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
29
|
+
if (!match) return; // Unparseable output — skip check
|
|
30
|
+
|
|
31
|
+
const installed: [number, number, number] = [
|
|
32
|
+
parseInt(match[1], 10),
|
|
33
|
+
parseInt(match[2], 10),
|
|
34
|
+
parseInt(match[3], 10),
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const [iMaj, iMin, iPatch] = installed;
|
|
38
|
+
const [minMaj, minMin, minPatch] = BRU_MIN_VERSION;
|
|
39
|
+
|
|
40
|
+
const belowMin =
|
|
41
|
+
iMaj < minMaj ||
|
|
42
|
+
(iMaj === minMaj && iMin < minMin) ||
|
|
43
|
+
(iMaj === minMaj && iMin === minMin && iPatch < minPatch);
|
|
44
|
+
|
|
45
|
+
if (belowMin) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`Bruno CLI version ${versionOutput.trim()} is below the minimum required version ` +
|
|
48
|
+
`${BRU_MIN_VERSION_STR}. Upgrade with: npm install -g @usebruno/cli`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
name: bruno_add_request
|
|
2
|
+
description: Add a new HTTP request to a Bruno collection programmatically. Creates a .bru file with the specified method, URL, headers, body, and test assertions.
|
|
3
|
+
version: '1.0.0'
|
|
4
|
+
status: approved
|
|
5
|
+
|
|
6
|
+
parameters:
|
|
7
|
+
collection_path:
|
|
8
|
+
type: string
|
|
9
|
+
required: true
|
|
10
|
+
description: Path to Bruno collection directory
|
|
11
|
+
example: './api-tests/payment-api'
|
|
12
|
+
|
|
13
|
+
request_name:
|
|
14
|
+
type: string
|
|
15
|
+
required: true
|
|
16
|
+
description: Request name (becomes .bru filename, alphanumeric + hyphens)
|
|
17
|
+
example: 'get-users'
|
|
18
|
+
|
|
19
|
+
method:
|
|
20
|
+
type: string
|
|
21
|
+
required: true
|
|
22
|
+
description: HTTP method
|
|
23
|
+
enum: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS']
|
|
24
|
+
example: 'GET'
|
|
25
|
+
|
|
26
|
+
url:
|
|
27
|
+
type: string
|
|
28
|
+
required: true
|
|
29
|
+
description: Full request URL (can contain {variables})
|
|
30
|
+
example: 'https://api.example.com/users/{user_id}'
|
|
31
|
+
|
|
32
|
+
headers:
|
|
33
|
+
type: object
|
|
34
|
+
required: false
|
|
35
|
+
description: HTTP headers as key-value pairs
|
|
36
|
+
example:
|
|
37
|
+
Content-Type: 'application/json'
|
|
38
|
+
Authorization: 'Bearer {api_token}'
|
|
39
|
+
|
|
40
|
+
body:
|
|
41
|
+
type: string
|
|
42
|
+
required: false
|
|
43
|
+
description: Request body (JSON or raw text)
|
|
44
|
+
example: '{"name": "John", "email": "john@example.com"}'
|
|
45
|
+
|
|
46
|
+
tests:
|
|
47
|
+
type: string
|
|
48
|
+
required: false
|
|
49
|
+
description: Bruno test script (JavaScript assertions)
|
|
50
|
+
example: |
|
|
51
|
+
test("Status is 200", function() {
|
|
52
|
+
expect(res.getStatus()).to.equal(200);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
documentation:
|
|
56
|
+
type: string
|
|
57
|
+
required: false
|
|
58
|
+
description: Request documentation/description
|
|
59
|
+
example: 'Fetch list of all users from the system'
|
|
60
|
+
|
|
61
|
+
execution:
|
|
62
|
+
type: function
|
|
63
|
+
code: index.ts
|
|
64
|
+
timeout: 10000
|
|
65
|
+
|
|
66
|
+
output_schema:
|
|
67
|
+
type: object
|
|
68
|
+
properties:
|
|
69
|
+
success:
|
|
70
|
+
type: boolean
|
|
71
|
+
description: Whether request was created successfully
|
|
72
|
+
request_path:
|
|
73
|
+
type: string
|
|
74
|
+
description: Full path to created .bru file
|
|
75
|
+
request_name:
|
|
76
|
+
type: string
|
|
77
|
+
description: Request name
|
|
78
|
+
message:
|
|
79
|
+
type: string
|
|
80
|
+
description: Success or error message
|
|
81
|
+
|
|
82
|
+
examples:
|
|
83
|
+
- name: "Add GET request with headers"
|
|
84
|
+
params:
|
|
85
|
+
collection_path: "./api-tests/payment-api"
|
|
86
|
+
request_name: "get-transactions"
|
|
87
|
+
method: "GET"
|
|
88
|
+
url: "https://api.payment.com/v1/transactions"
|
|
89
|
+
headers:
|
|
90
|
+
Authorization: "Bearer {api_token}"
|
|
91
|
+
Accept: "application/json"
|
|
92
|
+
|
|
93
|
+
- name: "Add POST request with body and tests"
|
|
94
|
+
params:
|
|
95
|
+
collection_path: "./api-tests/payment-api"
|
|
96
|
+
request_name: "create-payment"
|
|
97
|
+
method: "POST"
|
|
98
|
+
url: "https://api.payment.com/v1/payments"
|
|
99
|
+
headers:
|
|
100
|
+
Content-Type: "application/json"
|
|
101
|
+
Authorization: "Bearer {api_token}"
|
|
102
|
+
body: '{"amount": 100, "currency": "USD", "description": "Payment for order"}'
|
|
103
|
+
tests: |
|
|
104
|
+
test("Payment created with 201", function() {
|
|
105
|
+
expect(res.getStatus()).to.equal(201);
|
|
106
|
+
expect(res.getBody().id).to.exist;
|
|
107
|
+
});
|
|
108
|
+
documentation: "Create a new payment transaction"
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { getGlobalMatimoLogger } from '@matimo/core';
|
|
2
|
+
import { promises as fs } from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
|
|
5
|
+
const logger = getGlobalMatimoLogger();
|
|
6
|
+
|
|
7
|
+
function generateBruContent(params: Record<string, unknown>): string {
|
|
8
|
+
const requestName = params.request_name as string;
|
|
9
|
+
const method = (params.method as string).toLowerCase();
|
|
10
|
+
const url = params.url as string;
|
|
11
|
+
const headers = (params.headers as Record<string, string>) || {};
|
|
12
|
+
const body = params.body as string | undefined;
|
|
13
|
+
const tests = params.tests as string | undefined;
|
|
14
|
+
const documentation = params.documentation as string | undefined;
|
|
15
|
+
|
|
16
|
+
let content = '';
|
|
17
|
+
|
|
18
|
+
content += `meta {\n name: ${requestName}\n type: http\n seq: 1\n}\n\n`;
|
|
19
|
+
|
|
20
|
+
if (documentation) {
|
|
21
|
+
content += `docs {\n ${documentation}\n}\n\n`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
content += `${method} {\n url: ${url}\n body: ${body ? 'json' : 'none'}\n auth: inherit\n}\n\n`;
|
|
25
|
+
|
|
26
|
+
if (Object.keys(headers).length > 0) {
|
|
27
|
+
content += `headers {\n`;
|
|
28
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
29
|
+
content += ` ${k}: ${v}\n`;
|
|
30
|
+
}
|
|
31
|
+
content += `}\n\n`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (body) {
|
|
35
|
+
content += `body:json {\n`;
|
|
36
|
+
content += body
|
|
37
|
+
.split('\n')
|
|
38
|
+
.map((line) => ` ${line}`)
|
|
39
|
+
.join('\n');
|
|
40
|
+
content += `\n}\n\n`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (tests) {
|
|
44
|
+
content += `tests {\n`;
|
|
45
|
+
content += tests
|
|
46
|
+
.split('\n')
|
|
47
|
+
.map((line) => ` ${line}`)
|
|
48
|
+
.join('\n');
|
|
49
|
+
content += `\n}\n`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return content;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default async function execute(params: Record<string, unknown>): Promise<unknown> {
|
|
56
|
+
const collectionPath = params.collection_path as string;
|
|
57
|
+
const requestName = params.request_name as string;
|
|
58
|
+
|
|
59
|
+
if (!collectionPath || !requestName) {
|
|
60
|
+
return {
|
|
61
|
+
success: false,
|
|
62
|
+
request_path: '',
|
|
63
|
+
request_name: '',
|
|
64
|
+
message: 'collection_path and request_name are required',
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
logger.info(`Adding request ${requestName} to collection at ${collectionPath}`);
|
|
70
|
+
|
|
71
|
+
const absoluteCollectionPath = path.resolve(collectionPath);
|
|
72
|
+
// Write requests into a dedicated requests/ subfolder (consistent with Bruno convention)
|
|
73
|
+
const requestsDir = path.join(absoluteCollectionPath, 'requests');
|
|
74
|
+
await fs.mkdir(requestsDir, { recursive: true });
|
|
75
|
+
|
|
76
|
+
const filename = `${requestName.toLowerCase().replace(/\s+/g, '-')}.bru`;
|
|
77
|
+
const requestPath = path.join(requestsDir, filename);
|
|
78
|
+
|
|
79
|
+
const content = generateBruContent(params);
|
|
80
|
+
await fs.writeFile(requestPath, content, 'utf-8');
|
|
81
|
+
|
|
82
|
+
logger.info(`Request written to ${requestPath}`);
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
success: true,
|
|
86
|
+
request_path: requestPath,
|
|
87
|
+
request_name: requestName,
|
|
88
|
+
message: `Request '${requestName}' added to collection successfully`,
|
|
89
|
+
};
|
|
90
|
+
} catch (error) {
|
|
91
|
+
logger.error(
|
|
92
|
+
`Add request failed: ${error instanceof Error ? error.message : String(error)}`
|
|
93
|
+
);
|
|
94
|
+
return {
|
|
95
|
+
success: false,
|
|
96
|
+
request_path: '',
|
|
97
|
+
request_name: requestName,
|
|
98
|
+
message: `Failed to add request: ${error instanceof Error ? error.message : String(error)}`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: bruno_create_collection
|
|
2
|
+
description: Create a new empty Bruno collection scaffold with directory structure and configuration. Enables agents to initialize new collections for API testing projects.
|
|
3
|
+
version: '1.0.0'
|
|
4
|
+
status: approved
|
|
5
|
+
|
|
6
|
+
parameters:
|
|
7
|
+
collection_path:
|
|
8
|
+
type: string
|
|
9
|
+
required: true
|
|
10
|
+
description: Path where new collection directory will be created
|
|
11
|
+
|
|
12
|
+
collection_name:
|
|
13
|
+
type: string
|
|
14
|
+
required: true
|
|
15
|
+
description: Name for the new collection
|
|
16
|
+
|
|
17
|
+
execution:
|
|
18
|
+
type: function
|
|
19
|
+
code: index.ts
|
|
20
|
+
timeout: 15000
|
|
21
|
+
|
|
22
|
+
output_schema:
|
|
23
|
+
type: object
|
|
24
|
+
properties:
|
|
25
|
+
success:
|
|
26
|
+
type: boolean
|
|
27
|
+
collection_path:
|
|
28
|
+
type: string
|
|
29
|
+
message:
|
|
30
|
+
type: string
|
|
31
|
+
errors:
|
|
32
|
+
type: array
|
|
33
|
+
items:
|
|
34
|
+
type: string
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
examples:
|
|
38
|
+
- name: "Create new collection for microservice testing"
|
|
39
|
+
params:
|
|
40
|
+
collection_path: "./collections/user-service"
|
|
41
|
+
collection_name: "User Service API Tests"
|
|
42
|
+
|
|
43
|
+
- name: "Bootstrap collection for integration tests"
|
|
44
|
+
params:
|
|
45
|
+
collection_path: "./collections/e2e-workflows"
|
|
46
|
+
collection_name: "End-to-End Workflows"
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { getGlobalMatimoLogger } from '@matimo/core';
|
|
2
|
+
import { promises as fs } from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
|
|
5
|
+
const logger = getGlobalMatimoLogger();
|
|
6
|
+
|
|
7
|
+
export default async function execute(params: Record<string, unknown>): Promise<unknown> {
|
|
8
|
+
const collectionPath = params.collection_path as string;
|
|
9
|
+
const collectionName = params.collection_name as string;
|
|
10
|
+
|
|
11
|
+
if (!collectionPath || !collectionName) {
|
|
12
|
+
return {
|
|
13
|
+
success: false,
|
|
14
|
+
collection_path: '',
|
|
15
|
+
message: 'collection_path and collection_name parameters are required',
|
|
16
|
+
errors: ['collection_path and collection_name parameters are required'],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
logger.info(`Creating collection: ${collectionName} at ${collectionPath}`);
|
|
22
|
+
|
|
23
|
+
const absolutePath = path.resolve(collectionPath);
|
|
24
|
+
await fs.mkdir(absolutePath, { recursive: true });
|
|
25
|
+
|
|
26
|
+
const brunoJson = {
|
|
27
|
+
version: '1',
|
|
28
|
+
name: collectionName,
|
|
29
|
+
type: 'collection',
|
|
30
|
+
ignore: [] as string[],
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const brunoJsonPath = path.join(absolutePath, 'bruno.json');
|
|
34
|
+
await fs.writeFile(brunoJsonPath, JSON.stringify(brunoJson, null, 2), 'utf-8');
|
|
35
|
+
|
|
36
|
+
logger.info('Collection created successfully');
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
success: true,
|
|
40
|
+
collection_path: absolutePath,
|
|
41
|
+
message: `Collection "${collectionName}" created at ${absolutePath}`,
|
|
42
|
+
errors: [],
|
|
43
|
+
};
|
|
44
|
+
} catch (error) {
|
|
45
|
+
logger.error(
|
|
46
|
+
`Create collection failed: ${error instanceof Error ? error.message : String(error)}`
|
|
47
|
+
);
|
|
48
|
+
return {
|
|
49
|
+
success: false,
|
|
50
|
+
collection_path: collectionPath,
|
|
51
|
+
message: 'Collection creation failed',
|
|
52
|
+
errors: [error instanceof Error ? error.message : String(error)],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: bruno_get_collection_info
|
|
2
|
+
description: Introspect a Bruno collection to get its structure, requests, environments, and configuration. Returns complete collection metadata for pre-flight validation before execution.
|
|
3
|
+
version: '1.0.0'
|
|
4
|
+
status: approved
|
|
5
|
+
|
|
6
|
+
parameters:
|
|
7
|
+
collection_path:
|
|
8
|
+
type: string
|
|
9
|
+
required: true
|
|
10
|
+
description: Path to Bruno collection file or directory
|
|
11
|
+
|
|
12
|
+
execution:
|
|
13
|
+
type: function
|
|
14
|
+
code: index.ts
|
|
15
|
+
timeout: 10000
|
|
16
|
+
|
|
17
|
+
output_schema:
|
|
18
|
+
type: object
|
|
19
|
+
properties:
|
|
20
|
+
success:
|
|
21
|
+
type: boolean
|
|
22
|
+
collection:
|
|
23
|
+
type: object
|
|
24
|
+
properties:
|
|
25
|
+
name:
|
|
26
|
+
type: string
|
|
27
|
+
path:
|
|
28
|
+
type: string
|
|
29
|
+
requests:
|
|
30
|
+
type: array
|
|
31
|
+
items:
|
|
32
|
+
type: object
|
|
33
|
+
properties:
|
|
34
|
+
name:
|
|
35
|
+
type: string
|
|
36
|
+
method:
|
|
37
|
+
type: string
|
|
38
|
+
url:
|
|
39
|
+
type: string
|
|
40
|
+
path:
|
|
41
|
+
type: string
|
|
42
|
+
tags:
|
|
43
|
+
type: array
|
|
44
|
+
items:
|
|
45
|
+
type: string
|
|
46
|
+
has_tests:
|
|
47
|
+
type: boolean
|
|
48
|
+
errors:
|
|
49
|
+
type: array
|
|
50
|
+
items:
|
|
51
|
+
type: string
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
examples:
|
|
55
|
+
- name: "Inspect collection structure"
|
|
56
|
+
params:
|
|
57
|
+
collection_path: "./collections/payment-api"
|
|
58
|
+
|
|
59
|
+
- name: "Get full metadata before running"
|
|
60
|
+
params:
|
|
61
|
+
collection_path: "./collections/auth-flow.bru"
|