sharetribe-cli 1.15.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/.eslintrc.json +29 -0
- package/.prettierrc +9 -0
- package/build.js +58 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +7 -0
- package/package.json +58 -0
- package/src/commands/assets/index.ts +338 -0
- package/src/commands/events/index.ts +289 -0
- package/src/commands/help.ts +19 -0
- package/src/commands/listing-approval.ts +121 -0
- package/src/commands/login.ts +43 -0
- package/src/commands/logout.ts +17 -0
- package/src/commands/notifications/index.ts +221 -0
- package/src/commands/process/aliases.ts +82 -0
- package/src/commands/process/combined.ts +62 -0
- package/src/commands/process/create.ts +35 -0
- package/src/commands/process/index.ts +309 -0
- package/src/commands/process/list.ts +75 -0
- package/src/commands/process/pull.ts +81 -0
- package/src/commands/process/push.ts +67 -0
- package/src/commands/search/index.ts +254 -0
- package/src/commands/stripe/index.ts +114 -0
- package/src/commands/version.ts +40 -0
- package/src/index.ts +131 -0
- package/src/types/index.ts +21 -0
- package/src/util/command-router.ts +41 -0
- package/src/util/help-formatter.ts +266 -0
- package/src/util/output.ts +83 -0
- package/test/help-comparison.test.ts +255 -0
- package/test/process-builder.test.ts +14 -0
- package/test/process-integration.test.ts +189 -0
- package/test/strict-comparison.test.ts +722 -0
- package/tsconfig.json +50 -0
- package/vitest.config.ts +12 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom help formatter to match flex-cli output exactly
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Command, Help } from 'commander';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Formats help text to match flex-cli style
|
|
10
|
+
*
|
|
11
|
+
* flex-cli format:
|
|
12
|
+
* - Description (no label)
|
|
13
|
+
* - VERSION section (for main help only)
|
|
14
|
+
* - USAGE section
|
|
15
|
+
* - COMMANDS section (flattened list of all leaf commands)
|
|
16
|
+
* - OPTIONS section (for subcommands only, not main)
|
|
17
|
+
* - Subcommand help instructions
|
|
18
|
+
*
|
|
19
|
+
* @param cmd - Commander command instance
|
|
20
|
+
* @returns Formatted help text matching flex-cli
|
|
21
|
+
*/
|
|
22
|
+
export function formatHelp(cmd: Command): string {
|
|
23
|
+
const parts: string[] = [];
|
|
24
|
+
const isRootCommand = !cmd.parent;
|
|
25
|
+
|
|
26
|
+
// Description (no label, just the text)
|
|
27
|
+
const description = cmd.description();
|
|
28
|
+
if (description) {
|
|
29
|
+
parts.push(description);
|
|
30
|
+
parts.push('');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// VERSION section (only for root command)
|
|
34
|
+
if (isRootCommand) {
|
|
35
|
+
const version = cmd.version();
|
|
36
|
+
if (version) {
|
|
37
|
+
parts.push('VERSION');
|
|
38
|
+
parts.push(` ${version}`);
|
|
39
|
+
parts.push('');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// USAGE section
|
|
44
|
+
parts.push('USAGE');
|
|
45
|
+
const usage = formatUsage(cmd);
|
|
46
|
+
parts.push(` $ ${usage}`);
|
|
47
|
+
parts.push('');
|
|
48
|
+
|
|
49
|
+
// COMMANDS section
|
|
50
|
+
// Note: If command has an action (options), don't show COMMANDS section (like flex-cli)
|
|
51
|
+
const allCommands = collectAllLeafCommands(cmd);
|
|
52
|
+
const hasAction = cmd.options.length > 0 && !isRootCommand;
|
|
53
|
+
|
|
54
|
+
if (allCommands.length > 0 && !hasAction) {
|
|
55
|
+
parts.push('COMMANDS');
|
|
56
|
+
|
|
57
|
+
// Calculate max command name length for alignment
|
|
58
|
+
const maxLength = Math.max(...allCommands.map(c => c.name.length));
|
|
59
|
+
|
|
60
|
+
for (const cmdInfo of allCommands) {
|
|
61
|
+
const paddedName = cmdInfo.name.padEnd(maxLength + 2);
|
|
62
|
+
parts.push(` ${paddedName}${cmdInfo.description}`);
|
|
63
|
+
}
|
|
64
|
+
parts.push('');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// OPTIONS section (only for subcommands, not root)
|
|
68
|
+
if (!isRootCommand) {
|
|
69
|
+
const options = cmd.options;
|
|
70
|
+
if (options.length > 0) {
|
|
71
|
+
parts.push('OPTIONS');
|
|
72
|
+
|
|
73
|
+
// Calculate max option flags length for alignment
|
|
74
|
+
const maxFlagsLength = Math.max(...options.map(opt => formatOptionFlags(opt).length));
|
|
75
|
+
|
|
76
|
+
for (const opt of options) {
|
|
77
|
+
const flags = formatOptionFlags(opt);
|
|
78
|
+
const paddedFlags = flags.padEnd(maxFlagsLength + 2);
|
|
79
|
+
const desc = opt.description || '';
|
|
80
|
+
parts.push(` ${paddedFlags}${desc}`);
|
|
81
|
+
}
|
|
82
|
+
parts.push('');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Subcommand help instructions (only for main and group commands without actions)
|
|
87
|
+
if (allCommands.length > 0 && !hasAction) {
|
|
88
|
+
parts.push('Subcommand help:');
|
|
89
|
+
const cmdName = getCommandName(cmd);
|
|
90
|
+
parts.push(` $ ${cmdName} help [COMMAND]`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Always add empty line at end to match flex-cli
|
|
94
|
+
parts.push('');
|
|
95
|
+
|
|
96
|
+
return parts.join('\n');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Recursively collects all commands (both parent and leaf commands)
|
|
101
|
+
*
|
|
102
|
+
* flex-cli shows ALL commands, including parent commands that have their own actions
|
|
103
|
+
* Example: both "events" and "events tail" are shown
|
|
104
|
+
*
|
|
105
|
+
* @param cmd - Commander command instance
|
|
106
|
+
* @returns Array of command info objects with name and description
|
|
107
|
+
*/
|
|
108
|
+
function collectAllLeafCommands(cmd: Command): Array<{ name: string; description: string }> {
|
|
109
|
+
const results: Array<{ name: string; description: string }> = [];
|
|
110
|
+
const commands = cmd.commands.filter(c => !c._hidden && c.name() !== 'help');
|
|
111
|
+
|
|
112
|
+
for (const subCmd of commands) {
|
|
113
|
+
const fullName = getCommandFullName(subCmd);
|
|
114
|
+
const subCommands = subCmd.commands.filter(c => !c._hidden);
|
|
115
|
+
|
|
116
|
+
// Add this command if it has an action or description
|
|
117
|
+
if (subCmd.description()) {
|
|
118
|
+
results.push({
|
|
119
|
+
name: fullName,
|
|
120
|
+
description: subCmd.description() || ''
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// If it has subcommands, recurse and add those too
|
|
125
|
+
if (subCommands.length > 0) {
|
|
126
|
+
const subResults = collectAllLeafCommands(subCmd);
|
|
127
|
+
for (const sub of subResults) {
|
|
128
|
+
results.push(sub);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Add "help" command at the beginning if this is root
|
|
134
|
+
if (!cmd.parent) {
|
|
135
|
+
results.unshift({
|
|
136
|
+
name: 'help',
|
|
137
|
+
description: 'display help for Flex CLI'
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Sort alphabetically by command name
|
|
142
|
+
results.sort((a, b) => a.name.localeCompare(b.name));
|
|
143
|
+
|
|
144
|
+
return results;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Gets the command name for usage (flex-cli vs sharetribe-cli)
|
|
149
|
+
*
|
|
150
|
+
* @param cmd - Commander command instance
|
|
151
|
+
* @returns Command name (e.g., "sharetribe-cli" or "sharetribe-cli process")
|
|
152
|
+
*/
|
|
153
|
+
function getCommandName(cmd: Command): string {
|
|
154
|
+
const names: string[] = [];
|
|
155
|
+
let current: Command | null = cmd;
|
|
156
|
+
|
|
157
|
+
while (current) {
|
|
158
|
+
if (current.name()) {
|
|
159
|
+
names.unshift(current.name());
|
|
160
|
+
}
|
|
161
|
+
current = current.parent;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Replace first name with "sharetribe-cli" (or "flex-cli" for reference)
|
|
165
|
+
if (names.length > 0) {
|
|
166
|
+
names[0] = 'sharetribe-cli';
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return names.join(' ');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Formats the USAGE line
|
|
174
|
+
*
|
|
175
|
+
* @param cmd - Commander command instance
|
|
176
|
+
* @returns Usage string (e.g., "sharetribe-cli [COMMAND]" or "sharetribe-cli process list")
|
|
177
|
+
*/
|
|
178
|
+
function formatUsage(cmd: Command): string {
|
|
179
|
+
const cmdName = getCommandName(cmd);
|
|
180
|
+
const commands = cmd.commands.filter(c => !c._hidden);
|
|
181
|
+
const hasOptions = cmd.options.length > 0;
|
|
182
|
+
const isRoot = !cmd.parent;
|
|
183
|
+
|
|
184
|
+
// Root command always shows [COMMAND] if it has subcommands
|
|
185
|
+
if (isRoot && commands.length > 0) {
|
|
186
|
+
return `${cmdName} [COMMAND]`;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// If command has options (its own action), don't show [COMMAND] even if it has subcommands
|
|
190
|
+
// This matches flex-cli behavior for commands like "process" which have both action and subcommands
|
|
191
|
+
if (commands.length > 0 && !hasOptions) {
|
|
192
|
+
// Has subcommands but no action
|
|
193
|
+
return `${cmdName} [COMMAND]`;
|
|
194
|
+
} else {
|
|
195
|
+
// Leaf command or command with action - just show the command path
|
|
196
|
+
return cmdName;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Gets the full command name including parent path
|
|
202
|
+
*
|
|
203
|
+
* @param cmd - Commander command instance
|
|
204
|
+
* @returns Full command name (e.g., "process list" or "events tail")
|
|
205
|
+
*/
|
|
206
|
+
function getCommandFullName(cmd: Command): string {
|
|
207
|
+
const names: string[] = [];
|
|
208
|
+
let current: Command | null = cmd;
|
|
209
|
+
|
|
210
|
+
while (current && current.parent) {
|
|
211
|
+
if (current.name()) {
|
|
212
|
+
names.unshift(current.name());
|
|
213
|
+
}
|
|
214
|
+
current = current.parent;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return names.join(' ');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Formats option flags for display
|
|
222
|
+
*
|
|
223
|
+
* @param opt - Commander option instance
|
|
224
|
+
* @returns Formatted flags string (e.g., "-m, --marketplace=MARKETPLACE_ID")
|
|
225
|
+
*/
|
|
226
|
+
function formatOptionFlags(opt: any): string {
|
|
227
|
+
// Commander option flags are in opt.flags (e.g., "-m, --marketplace <MARKETPLACE_ID>")
|
|
228
|
+
// We need to parse and reformat this to match flex-cli style
|
|
229
|
+
const flagsStr = opt.flags || '';
|
|
230
|
+
|
|
231
|
+
// Parse the flags string
|
|
232
|
+
// Format: "-m, --marketplace <VALUE>" or "--flag" or "-f"
|
|
233
|
+
const parts = flagsStr.split(/,\s*/);
|
|
234
|
+
const formatted: string[] = [];
|
|
235
|
+
|
|
236
|
+
for (const part of parts) {
|
|
237
|
+
const trimmed = part.trim();
|
|
238
|
+
|
|
239
|
+
// Check if it has a value placeholder (angle brackets or square brackets)
|
|
240
|
+
const valueMatch = trimmed.match(/^((?:-{1,2}[\w-]+))\s*[<\[]([^\]>]+)[\]>]/);
|
|
241
|
+
if (valueMatch) {
|
|
242
|
+
// Has a value: "-m <MARKETPLACE_ID>" or "--marketplace <MARKETPLACE_ID>"
|
|
243
|
+
const flag = valueMatch[1];
|
|
244
|
+
const valueName = valueMatch[2];
|
|
245
|
+
formatted.push(`${flag}=${valueName}`);
|
|
246
|
+
} else {
|
|
247
|
+
// No value: just the flag
|
|
248
|
+
formatted.push(trimmed);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return formatted.join(', ');
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Configures Commander.js to use custom help formatter
|
|
257
|
+
*
|
|
258
|
+
* @param program - Commander program instance
|
|
259
|
+
*/
|
|
260
|
+
export function configureHelp(program: Command): void {
|
|
261
|
+
program.configureHelp({
|
|
262
|
+
formatHelp: (cmd: Command, helper: Help) => {
|
|
263
|
+
return formatHelp(cmd);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output formatting utilities
|
|
3
|
+
*
|
|
4
|
+
* Must match flex-cli output format exactly
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Prints a table with headers and rows
|
|
11
|
+
*
|
|
12
|
+
* Matches flex-cli table formatting exactly
|
|
13
|
+
*/
|
|
14
|
+
export function printTable(headers: string[], rows: Array<Record<string, string>>): void {
|
|
15
|
+
if (rows.length === 0) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Calculate column widths
|
|
20
|
+
// flex-cli uses keywords (e.g., :version) which when stringified include the ':' prefix
|
|
21
|
+
// To match flex-cli widths, we add 1 to header length to simulate the ':' prefix
|
|
22
|
+
const widths: Record<string, number> = {};
|
|
23
|
+
for (const header of headers) {
|
|
24
|
+
widths[header] = header.length + 1; // +1 to match flex-cli keyword string behavior
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
for (const row of rows) {
|
|
28
|
+
for (const header of headers) {
|
|
29
|
+
const value = row[header] || '';
|
|
30
|
+
widths[header] = Math.max(widths[header] || 0, value.length);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Print empty line before table (like flex-cli)
|
|
35
|
+
console.log('');
|
|
36
|
+
|
|
37
|
+
// Print header with bold formatting
|
|
38
|
+
// flex-cli format: each column padded to (max_width + 1), with single space separator between columns
|
|
39
|
+
// Last column: padding but no separator (interpose doesn't add separator after last element)
|
|
40
|
+
const headerParts = headers.map((h, i) => {
|
|
41
|
+
const width = widths[h] || 0;
|
|
42
|
+
const padded = h.padEnd(width + 1);
|
|
43
|
+
return i === headers.length - 1 ? padded : padded + ' ';
|
|
44
|
+
});
|
|
45
|
+
const headerRow = headerParts.join('');
|
|
46
|
+
console.log(chalk.bold.black(headerRow));
|
|
47
|
+
|
|
48
|
+
// Print rows with same formatting
|
|
49
|
+
for (const row of rows) {
|
|
50
|
+
const rowParts = headers.map((h, i) => {
|
|
51
|
+
const value = row[h] || '';
|
|
52
|
+
const width = widths[h] || 0;
|
|
53
|
+
const padded = value.padEnd(width + 1);
|
|
54
|
+
return i === headers.length - 1 ? padded : padded + ' ';
|
|
55
|
+
});
|
|
56
|
+
const rowStr = rowParts.join('');
|
|
57
|
+
console.log(rowStr);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Print empty line after table (like flex-cli)
|
|
61
|
+
console.log('');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Prints an error message
|
|
66
|
+
*/
|
|
67
|
+
export function printError(message: string): void {
|
|
68
|
+
console.error(chalk.red(`Error: ${message}`));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Prints a success message
|
|
73
|
+
*/
|
|
74
|
+
export function printSuccess(message: string): void {
|
|
75
|
+
console.log(chalk.green(message));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Prints a warning message
|
|
80
|
+
*/
|
|
81
|
+
export function printWarning(message: string): void {
|
|
82
|
+
console.log(chalk.yellow(`Warning: ${message}`));
|
|
83
|
+
}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comprehensive help output comparison tests
|
|
3
|
+
*
|
|
4
|
+
* Tests that help output matches flex-cli for all commands
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect } from 'vitest';
|
|
8
|
+
import { execSync } from 'child_process';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Executes a CLI command and returns output
|
|
12
|
+
*/
|
|
13
|
+
function runCli(command: string, cli: 'flex' | 'sharetribe'): string {
|
|
14
|
+
const cliName = cli === 'flex' ? 'flex-cli' : 'sharetribe-cli';
|
|
15
|
+
try {
|
|
16
|
+
return execSync(`${cliName} ${command}`, {
|
|
17
|
+
encoding: 'utf-8',
|
|
18
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
19
|
+
});
|
|
20
|
+
} catch (error) {
|
|
21
|
+
if (error instanceof Error && 'stdout' in error && 'stderr' in error) {
|
|
22
|
+
const stdout = (error as any).stdout || '';
|
|
23
|
+
const stderr = (error as any).stderr || '';
|
|
24
|
+
return stdout + stderr;
|
|
25
|
+
}
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Normalizes help output for comparison (removes CLI name differences)
|
|
32
|
+
*/
|
|
33
|
+
function normalizeHelp(output: string, cliName: string): string {
|
|
34
|
+
return output
|
|
35
|
+
.replace(new RegExp(cliName, 'g'), 'CLI')
|
|
36
|
+
.replace(/\s+$/gm, ''); // Trim trailing spaces per line
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Compares help structure (sections present, not exact content)
|
|
41
|
+
*/
|
|
42
|
+
function compareHelpStructure(flexOutput: string, shareOutput: string, cmdName: string) {
|
|
43
|
+
// Both should have description
|
|
44
|
+
const flexLines = flexOutput.split('\n');
|
|
45
|
+
const shareLines = shareOutput.split('\n');
|
|
46
|
+
|
|
47
|
+
// First line should be description
|
|
48
|
+
expect(shareLines[0]).toBeTruthy();
|
|
49
|
+
expect(shareLines[0]).not.toMatch(/^USAGE|^OPTIONS|^COMMANDS/);
|
|
50
|
+
|
|
51
|
+
// Should have USAGE section
|
|
52
|
+
expect(shareOutput).toContain('USAGE');
|
|
53
|
+
|
|
54
|
+
// Check if flex has OPTIONS
|
|
55
|
+
if (flexOutput.includes('OPTIONS')) {
|
|
56
|
+
expect(shareOutput).toContain('OPTIONS');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Check if flex has COMMANDS
|
|
60
|
+
if (flexOutput.includes('COMMANDS')) {
|
|
61
|
+
expect(shareOutput).toContain('COMMANDS');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
describe('Help Comparison Tests', () => {
|
|
66
|
+
describe('Main help', () => {
|
|
67
|
+
it('has same structure as flex-cli', () => {
|
|
68
|
+
const flexOutput = runCli('--help', 'flex');
|
|
69
|
+
const shareOutput = runCli('--help', 'sharetribe');
|
|
70
|
+
|
|
71
|
+
expect(shareOutput).toContain('VERSION');
|
|
72
|
+
expect(shareOutput).toContain('USAGE');
|
|
73
|
+
expect(shareOutput).toContain('COMMANDS');
|
|
74
|
+
expect(shareOutput).toContain('Subcommand help:');
|
|
75
|
+
|
|
76
|
+
// Should NOT have OPTIONS in main help
|
|
77
|
+
const lines = shareOutput.split('\n');
|
|
78
|
+
const commandsIndex = lines.findIndex(l => l === 'COMMANDS');
|
|
79
|
+
const subcommandIndex = lines.findIndex(l => l.startsWith('Subcommand help:'));
|
|
80
|
+
const betweenLines = lines.slice(commandsIndex, subcommandIndex);
|
|
81
|
+
expect(betweenLines.some(l => l === 'OPTIONS')).toBe(false);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('commands are alphabetically sorted', () => {
|
|
85
|
+
const shareOutput = runCli('--help', 'sharetribe');
|
|
86
|
+
const lines = shareOutput.split('\n');
|
|
87
|
+
const commandsStartIndex = lines.findIndex(l => l === 'COMMANDS');
|
|
88
|
+
const commandLines = lines.slice(commandsStartIndex + 1).filter(l => l.match(/^\s+\w/));
|
|
89
|
+
|
|
90
|
+
const commandNames = commandLines.map(l => l.trim().split(/\s+/)[0]);
|
|
91
|
+
const sortedNames = [...commandNames].sort();
|
|
92
|
+
|
|
93
|
+
expect(commandNames).toEqual(sortedNames);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('ends with empty line', () => {
|
|
97
|
+
const shareOutput = runCli('--help', 'sharetribe');
|
|
98
|
+
expect(shareOutput).toMatch(/\n$/);
|
|
99
|
+
expect(shareOutput).toMatch(/\n\n$/);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('help process', () => {
|
|
104
|
+
it('matches flex-cli structure', () => {
|
|
105
|
+
const flexOutput = runCli('help process', 'flex');
|
|
106
|
+
const shareOutput = runCli('help process', 'sharetribe');
|
|
107
|
+
|
|
108
|
+
compareHelpStructure(flexOutput, shareOutput, 'process');
|
|
109
|
+
|
|
110
|
+
// Should have OPTIONS (process has --path and --transition options)
|
|
111
|
+
expect(shareOutput).toContain('OPTIONS');
|
|
112
|
+
expect(shareOutput).toContain('--path');
|
|
113
|
+
expect(shareOutput).toContain('--transition');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('has correct description', () => {
|
|
117
|
+
const shareOutput = runCli('help process', 'sharetribe');
|
|
118
|
+
const lines = shareOutput.split('\n');
|
|
119
|
+
expect(lines[0]).toBe('describe a process file');
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('has correct usage', () => {
|
|
123
|
+
const shareOutput = runCli('help process', 'sharetribe');
|
|
124
|
+
expect(shareOutput).toMatch(/\$ sharetribe-cli process$/m);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe('help process list', () => {
|
|
129
|
+
it('matches flex-cli structure', () => {
|
|
130
|
+
const flexOutput = runCli('help process list', 'flex');
|
|
131
|
+
const shareOutput = runCli('help process list', 'sharetribe');
|
|
132
|
+
|
|
133
|
+
compareHelpStructure(flexOutput, shareOutput, 'process list');
|
|
134
|
+
|
|
135
|
+
expect(shareOutput).toContain('OPTIONS');
|
|
136
|
+
expect(shareOutput).toContain('--process');
|
|
137
|
+
expect(shareOutput).toContain('--marketplace');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('has correct description', () => {
|
|
141
|
+
const shareOutput = runCli('help process list', 'sharetribe');
|
|
142
|
+
expect(shareOutput).toMatch(/^list all transaction processes/);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe('help events', () => {
|
|
147
|
+
it('matches flex-cli structure', () => {
|
|
148
|
+
const flexOutput = runCli('help events', 'flex');
|
|
149
|
+
const shareOutput = runCli('help events', 'sharetribe');
|
|
150
|
+
|
|
151
|
+
compareHelpStructure(flexOutput, shareOutput, 'events');
|
|
152
|
+
|
|
153
|
+
expect(shareOutput).toContain('OPTIONS');
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('has correct description', () => {
|
|
157
|
+
const shareOutput = runCli('help events', 'sharetribe');
|
|
158
|
+
expect(shareOutput).toMatch(/^Get a list of events\./);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe('help search', () => {
|
|
163
|
+
it('matches flex-cli structure', () => {
|
|
164
|
+
const flexOutput = runCli('help search', 'flex');
|
|
165
|
+
const shareOutput = runCli('help search', 'sharetribe');
|
|
166
|
+
|
|
167
|
+
compareHelpStructure(flexOutput, shareOutput, 'search');
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('has correct description', () => {
|
|
171
|
+
const shareOutput = runCli('help search', 'sharetribe');
|
|
172
|
+
expect(shareOutput).toMatch(/^list all search schemas/);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe('help notifications', () => {
|
|
177
|
+
it('has correct structure', () => {
|
|
178
|
+
const shareOutput = runCli('help notifications', 'sharetribe');
|
|
179
|
+
|
|
180
|
+
expect(shareOutput).toContain('USAGE');
|
|
181
|
+
expect(shareOutput).toContain('COMMANDS');
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
describe('help login', () => {
|
|
186
|
+
it('has correct structure', () => {
|
|
187
|
+
const shareOutput = runCli('help login', 'sharetribe');
|
|
188
|
+
|
|
189
|
+
expect(shareOutput).toContain('USAGE');
|
|
190
|
+
expect(shareOutput).toContain('$ sharetribe-cli login');
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe('help logout', () => {
|
|
195
|
+
it('has correct structure', () => {
|
|
196
|
+
const shareOutput = runCli('help logout', 'sharetribe');
|
|
197
|
+
|
|
198
|
+
expect(shareOutput).toContain('USAGE');
|
|
199
|
+
expect(shareOutput).toContain('$ sharetribe-cli logout');
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
describe('help version', () => {
|
|
204
|
+
it('has correct structure', () => {
|
|
205
|
+
const shareOutput = runCli('help version', 'sharetribe');
|
|
206
|
+
|
|
207
|
+
expect(shareOutput).toContain('USAGE');
|
|
208
|
+
expect(shareOutput).toContain('$ sharetribe-cli version');
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
describe('All help commands have consistent format', () => {
|
|
213
|
+
const commands = [
|
|
214
|
+
'help',
|
|
215
|
+
'events',
|
|
216
|
+
'events tail',
|
|
217
|
+
'login',
|
|
218
|
+
'logout',
|
|
219
|
+
'process',
|
|
220
|
+
'process list',
|
|
221
|
+
'process create',
|
|
222
|
+
'process push',
|
|
223
|
+
'process pull',
|
|
224
|
+
'process create-alias',
|
|
225
|
+
'process update-alias',
|
|
226
|
+
'process delete-alias',
|
|
227
|
+
'search',
|
|
228
|
+
'search set',
|
|
229
|
+
'search unset',
|
|
230
|
+
'notifications',
|
|
231
|
+
'notifications preview',
|
|
232
|
+
'notifications send',
|
|
233
|
+
'stripe',
|
|
234
|
+
'stripe update-version',
|
|
235
|
+
'version',
|
|
236
|
+
];
|
|
237
|
+
|
|
238
|
+
commands.forEach(cmd => {
|
|
239
|
+
it(`help ${cmd} - has description and USAGE`, () => {
|
|
240
|
+
const output = runCli(`help ${cmd}`, 'sharetribe');
|
|
241
|
+
const lines = output.split('\n').filter(l => l.trim());
|
|
242
|
+
|
|
243
|
+
// Should have at least description and USAGE
|
|
244
|
+
expect(lines.length).toBeGreaterThan(2);
|
|
245
|
+
expect(output).toContain('USAGE');
|
|
246
|
+
expect(output).toMatch(/\$ sharetribe-cli/);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it(`help ${cmd} - ends with empty line`, () => {
|
|
250
|
+
const output = runCli(`help ${cmd}`, 'sharetribe');
|
|
251
|
+
expect(output).toMatch(/\n\n$/);
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for process commands
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect } from 'vitest';
|
|
6
|
+
import { parseProcessFile } from 'sharetribe-flex-build-sdk';
|
|
7
|
+
|
|
8
|
+
describe('edn-process', () => {
|
|
9
|
+
it('should parse process definition structure', () => {
|
|
10
|
+
// This would test actual EDN parsing
|
|
11
|
+
// For now, verify the function exists and has correct signature
|
|
12
|
+
expect(typeof parseProcessFile).toBe('function');
|
|
13
|
+
});
|
|
14
|
+
});
|