Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/b2c-cli/.mocharc.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"reporter": "spec",
"timeout": 60000,
"node-option": [
"import=tsx"
"import=tsx",
"conditions=development"
]
}
29 changes: 27 additions & 2 deletions packages/b2c-cli/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import headerPlugin from 'eslint-plugin-header';
import path from 'node:path';
import {fileURLToPath} from 'node:url';

import {copyrightHeader, sharedRules, oclifRules, prettierPlugin} from '../../eslint.config.mjs';
import {copyrightHeader, sharedRules, oclifRules, chaiTestRules, prettierPlugin} from '../../eslint.config.mjs';

const gitignorePath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '.gitignore');
headerPlugin.rules.header.meta.schema = false;
Expand All @@ -19,7 +19,7 @@ export default [
// node_modules must be explicitly ignored because the .gitignore pattern only covers
// packages/b2c-cli/node_modules, not the monorepo root node_modules
{
ignores: ['**/node_modules/**', 'test/functional/fixtures/**/*.js'],
ignores: ['**/node_modules/**', 'test/functional/fixtures/**/*.js', '**/node_modules/marked-terminal/**'],
},
includeIgnoreFile(gitignorePath),
...oclif,
Expand All @@ -39,4 +39,29 @@ export default [
...oclifRules,
},
},
{
files: ['test/**/*.ts'],
rules: {
...chaiTestRules,
// Tests use stubbing patterns that intentionally return undefined
'unicorn/no-useless-undefined': 'off',
// Some tests use void 0 to satisfy TS stub typings; allow it in tests
'no-void': 'off',
// Command tests frequently use `any` to avoid over-typing oclif command internals
'@typescript-eslint/no-explicit-any': 'off',
// Helper functions in tests are commonly declared within suites for clarity
'unicorn/consistent-function-scoping': 'off',
// Sinon default import is intentional and idiomatic in tests
'import/no-named-as-default-member': 'off',
// import/namespace behaves inconsistently across environments when parsing CJS modules like marked-terminal
'import/namespace': 'off',
},
},
{
files: ['src/commands/docs/**/*.ts'],
rules: {
// marked-terminal is CJS and breaks import/namespace static analysis
'import/namespace': 'off',
},
},
];
1 change: 1 addition & 0 deletions packages/b2c-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"oclif": "^4",
"prettier": "^3.6.2",
"shx": "^0.3.3",
"sinon": "^21.0.1",
"tsx": "^4.20.6",
"typescript": "^5"
},
Expand Down
9 changes: 7 additions & 2 deletions packages/b2c-cli/src/commands/code/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ export default class CodeDelete extends InstanceCommand<typeof CodeDelete> {
}),
};

protected operations = {
confirm,
deleteCodeVersion,
};

async run(): Promise<void> {
this.requireOAuthCredentials();

Expand All @@ -59,7 +64,7 @@ export default class CodeDelete extends InstanceCommand<typeof CodeDelete> {

// Confirm deletion unless --force is used
if (!this.flags.force) {
const confirmed = await confirm(
const confirmed = await this.operations.confirm(
t(
'commands.code.delete.confirm',
'Are you sure you want to delete code version "{{codeVersion}}" on {{hostname}}? (y/n)',
Expand All @@ -80,7 +85,7 @@ export default class CodeDelete extends InstanceCommand<typeof CodeDelete> {
}),
);

await deleteCodeVersion(this.instance, codeVersion);
await this.operations.deleteCodeVersion(this.instance, codeVersion);
this.log(t('commands.code.delete.deleted', 'Code version {{codeVersion}} deleted successfully', {codeVersion}));
}
}
15 changes: 11 additions & 4 deletions packages/b2c-cli/src/commands/code/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ export default class CodeDeploy extends CartridgeCommand<typeof CodeDeploy> {
}),
};

protected operations = {
uploadCartridges,
deleteCartridges,
getActiveCodeVersion,
reloadCodeVersion,
};

async run(): Promise<DeployResult> {
this.requireWebDavCredentials();
this.requireOAuthCredentials();
Expand All @@ -59,7 +66,7 @@ export default class CodeDeploy extends CartridgeCommand<typeof CodeDeploy> {
this.warn(
t('commands.code.deploy.noCodeVersion', 'No code version specified, discovering active code version...'),
);
const activeVersion = await getActiveCodeVersion(this.instance);
const activeVersion = await this.operations.getActiveCodeVersion(this.instance);
if (!activeVersion?.id) {
this.error(
t('commands.code.deploy.noActiveVersion', 'No active code version found. Specify one with --code-version.'),
Expand Down Expand Up @@ -119,17 +126,17 @@ export default class CodeDeploy extends CartridgeCommand<typeof CodeDeploy> {
try {
// Optionally delete existing cartridges first
if (this.flags.delete) {
await deleteCartridges(this.instance, cartridges);
await this.operations.deleteCartridges(this.instance, cartridges);
}

// Upload cartridges
await uploadCartridges(this.instance, cartridges);
await this.operations.uploadCartridges(this.instance, cartridges);

// Optionally reload code version
let reloaded = false;
if (this.flags.reload) {
try {
await reloadCodeVersion(this.instance, version);
await this.operations.reloadCodeVersion(this.instance, version);
reloaded = true;
} catch (error) {
this.logger?.debug(`Could not reload code version: ${error instanceof Error ? error.message : error}`);
Expand Down
6 changes: 5 additions & 1 deletion packages/b2c-cli/src/commands/code/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ export default class CodeWatch extends CartridgeCommand<typeof CodeWatch> {
...CartridgeCommand.cartridgeFlags,
};

protected operations = {
watchCartridges,
};

async run(): Promise<void> {
this.requireWebDavCredentials();
this.requireOAuthCredentials();
Expand All @@ -41,7 +45,7 @@ export default class CodeWatch extends CartridgeCommand<typeof CodeWatch> {
}

try {
const result = await watchCartridges(this.instance, this.cartridgePath, {
const result = await this.operations.watchCartridges(this.instance, this.cartridgePath, {
...this.cartridgeOptions,
onUpload: (files) => {
this.log(t('commands.code.watch.uploaded', '[UPLOAD] {{count}} file(s)', {count: files.length}));
Expand Down
6 changes: 5 additions & 1 deletion packages/b2c-cli/src/commands/docs/download.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ export default class DocsDownload extends InstanceCommand<typeof DocsDownload> {
}),
};

protected operations = {
downloadDocs,
};

async run(): Promise<DownloadDocsResult> {
this.requireServer();
this.requireWebDavCredentials();
Expand All @@ -50,7 +54,7 @@ export default class DocsDownload extends InstanceCommand<typeof DocsDownload> {
}),
);

const result = await downloadDocs(this.instance, {
const result = await this.operations.downloadDocs(this.instance, {
outputDir,
keepArchive,
});
Expand Down
8 changes: 6 additions & 2 deletions packages/b2c-cli/src/commands/docs/read.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/
import {Args, Flags} from '@oclif/core';
import {marked} from 'marked';
// eslint-disable-next-line import/namespace

import {markedTerminal} from 'marked-terminal';
import {BaseCommand} from '@salesforce/b2c-tooling-sdk/cli';
import {readDocByQuery, type DocEntry} from '@salesforce/b2c-tooling-sdk/operations/docs';
Expand Down Expand Up @@ -57,11 +57,15 @@ export default class DocsRead extends BaseCommand<typeof DocsRead> {
}),
};

protected operations = {
readDocByQuery,
};

async run(): Promise<ReadDocsResult> {
const {query} = this.args;
const {raw} = this.flags;

const result = readDocByQuery(query);
const result = this.operations.readDocByQuery(query);

if (!result) {
this.error(t('commands.docs.read.notFound', 'No documentation found matching: {{query}}', {query}), {
Expand Down
9 changes: 7 additions & 2 deletions packages/b2c-cli/src/commands/docs/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,18 @@ export default class DocsSchema extends BaseCommand<typeof DocsSchema> {
}),
};

protected operations = {
listSchemas,
readSchemaByQuery,
};

async run(): Promise<ListResult | SchemaResult> {
const {query} = this.args;
const {list} = this.flags;

// List mode
if (list) {
const entries = listSchemas();
const entries = this.operations.listSchemas();

if (this.jsonEnabled()) {
return {entries};
Expand All @@ -72,7 +77,7 @@ export default class DocsSchema extends BaseCommand<typeof DocsSchema> {
this.error(t('commands.docs.schema.queryRequired', 'Schema name is required. Use --list to see all schemas.'));
}

const result = readSchemaByQuery(query);
const result = this.operations.readSchemaByQuery(query);

if (!result) {
this.error(t('commands.docs.schema.notFound', 'No schema found matching: {{query}}', {query}), {
Expand Down
9 changes: 7 additions & 2 deletions packages/b2c-cli/src/commands/docs/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,18 @@ export default class DocsSearch extends BaseCommand<typeof DocsSearch> {
}),
};

protected operations = {
listDocs,
searchDocs,
};

async run(): Promise<ListDocsResponse | SearchDocsResponse> {
const {query} = this.args;
const {limit, list} = this.flags;

// List mode
if (list) {
const entries = listDocs();
const entries = this.operations.listDocs();

if (this.jsonEnabled()) {
return {entries};
Expand Down Expand Up @@ -109,7 +114,7 @@ export default class DocsSearch extends BaseCommand<typeof DocsSearch> {
);
}

const results = searchDocs(query, limit);
const results = this.operations.searchDocs(query, limit);

const response: SearchDocsResponse = {
query,
Expand Down
8 changes: 6 additions & 2 deletions packages/b2c-cli/src/commands/job/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ export default class JobExport extends JobCommand<typeof JobExport> {
}),
};

protected operations = {
siteArchiveExportToPath,
};

async run(): Promise<SiteArchiveExportResult & {localPath?: string}> {
this.requireOAuthCredentials();
this.requireWebDavCredentials();
Expand All @@ -114,7 +118,7 @@ export default class JobExport extends JobCommand<typeof JobExport> {
'no-download': noDownload,
'zip-only': zipOnly,
timeout,
'show-log': showLog,
'show-log': showLog = true,
} = this.flags;

const hostname = this.resolvedConfig.values.hostname!;
Expand Down Expand Up @@ -173,7 +177,7 @@ export default class JobExport extends JobCommand<typeof JobExport> {
this.log(t('commands.job.export.dataUnits', 'Data units: {{dataUnits}}', {dataUnits: JSON.stringify(dataUnits)}));

try {
const result = await siteArchiveExportToPath(this.instance, dataUnits, output, {
const result = await this.operations.siteArchiveExportToPath(this.instance, dataUnits, output, {
keepArchive: keepArchive || noDownload,
extractZip: !zipOnly,
waitOptions: {
Expand Down
8 changes: 6 additions & 2 deletions packages/b2c-cli/src/commands/job/import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,16 @@ export default class JobImport extends JobCommand<typeof JobImport> {
}),
};

protected operations = {
siteArchiveImport,
};

async run(): Promise<SiteArchiveImportResult> {
this.requireOAuthCredentials();
this.requireWebDavCredentials();

const {target} = this.args;
const {'keep-archive': keepArchive, remote, timeout, 'show-log': showLog} = this.flags;
const {'keep-archive': keepArchive, remote, timeout, 'show-log': showLog = true} = this.flags;

const hostname = this.resolvedConfig.values.hostname!;

Expand Down Expand Up @@ -107,7 +111,7 @@ export default class JobImport extends JobCommand<typeof JobImport> {
try {
const importTarget = remote ? {remoteFilename: target} : target;

const result = await siteArchiveImport(this.instance, importTarget, {
const result = await this.operations.siteArchiveImport(this.instance, importTarget, {
keepArchive,
waitOptions: {
timeout: timeout ? timeout * 1000 : undefined,
Expand Down
9 changes: 7 additions & 2 deletions packages/b2c-cli/src/commands/job/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ export default class JobRun extends JobCommand<typeof JobRun> {
}),
};

protected operations = {
executeJob,
waitForJob,
};

async run(): Promise<JobExecution> {
this.requireOAuthCredentials();

Expand Down Expand Up @@ -106,7 +111,7 @@ export default class JobRun extends JobCommand<typeof JobRun> {

let execution: JobExecution;
try {
execution = await executeJob(this.instance, jobId, {
execution = await this.operations.executeJob(this.instance, jobId, {
parameters: rawBody ? undefined : parameters,
body: rawBody,
waitForRunning: !noWaitRunning,
Expand Down Expand Up @@ -213,7 +218,7 @@ export default class JobRun extends JobCommand<typeof JobRun> {
this.log(t('commands.job.run.waiting', 'Waiting for job to complete...'));

try {
const execution = await waitForJob(this.instance, jobId, executionId, {
const execution = await this.operations.waitForJob(this.instance, jobId, executionId, {
timeout: timeout ? timeout * 1000 : undefined,
onProgress: (exec, elapsed) => {
if (!this.jsonEnabled()) {
Expand Down
6 changes: 5 additions & 1 deletion packages/b2c-cli/src/commands/job/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ export default class JobSearch extends InstanceCommand<typeof JobSearch> {
}),
};

protected operations = {
searchJobExecutions,
};

async run(): Promise<JobExecutionSearchResult> {
this.requireOAuthCredentials();

Expand All @@ -90,7 +94,7 @@ export default class JobSearch extends InstanceCommand<typeof JobSearch> {
}),
);

const results = await searchJobExecutions(this.instance, {
const results = await this.operations.searchJobExecutions(this.instance, {
jobId,
status,
count,
Expand Down
6 changes: 5 additions & 1 deletion packages/b2c-cli/src/commands/job/wait.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ export default class JobWait extends JobCommand<typeof JobWait> {
}),
};

protected operations = {
waitForJob,
};

async run(): Promise<JobExecution> {
this.requireOAuthCredentials();

Expand All @@ -60,7 +64,7 @@ export default class JobWait extends JobCommand<typeof JobWait> {
);

try {
const execution = await waitForJob(this.instance, jobId, executionId, {
const execution = await this.operations.waitForJob(this.instance, jobId, executionId, {
timeout: timeout ? timeout * 1000 : undefined,
pollInterval: pollInterval * 1000,
onProgress: (exec, elapsed) => {
Expand Down
Loading