Skip to content

Commit

Permalink
feat!: Refactor function commands (#1256)
Browse files Browse the repository at this point in the history
  • Loading branch information
brandenrodgers authored Nov 22, 2024
1 parent 6d004ec commit c34a566
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 74 deletions.
4 changes: 2 additions & 2 deletions bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const fetchCommand = require('../commands/fetch');
const filemanagerCommand = require('../commands/filemanager');
const secretsCommand = require('../commands/secrets');
const customObjectCommand = require('../commands/customObject');
const functionsCommand = require('../commands/functions');
const functionCommands = require('../commands/function');
const listCommand = require('../commands/list');
const openCommand = require('../commands/open');
const mvCommand = require('../commands/mv');
Expand Down Expand Up @@ -211,7 +211,7 @@ const argv = yargs
.command(filemanagerCommand)
.command(secretsCommand)
.command(customObjectCommand)
.command(functionsCommand)
.command(functionCommands)
.command({
...listCommand,
aliases: 'ls',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,65 +1,58 @@
// @ts-nocheck
import yargs from 'yargs';
import list from '../functions/list';
import deploy from '../functions/deploy';
import server from '../functions/server';
import { addAccountOptions, addConfigOptions } from '../../lib/commonOpts';
import list from '../function/list';
import deploy from '../function/deploy';
import server from '../function/server';

jest.mock('yargs');
jest.mock('../functions/list');
jest.mock('../functions/deploy');
jest.mock('../functions/server');
jest.mock('../function/list');
jest.mock('../function/deploy');
jest.mock('../function/server');
jest.mock('../../lib/commonOpts');
yargs.command.mockReturnValue(yargs);
yargs.demandCommand.mockReturnValue(yargs);

// Import this last so mocks apply
import functionsCommand from '../functions';
import functionCommands from '../function';

describe('commands/functions', () => {
describe('commands/function', () => {
describe('command', () => {
it('should have the correct command structure', () => {
expect(functionsCommand.command).toEqual('functions');
expect(functionCommands.command).toEqual(['function', 'functions']);
});
});

describe('describe', () => {
it('should provide a description', () => {
expect(functionsCommand.describe).toBeDefined();
expect(functionCommands.describe).toBeDefined();
});
});

describe('builder', () => {
const subcommands = [
['list', { ...list, aliases: 'ls' }],
['list', list],
['deploy', deploy],
['server', server],
];

it('should demand the command takes one positional argument', () => {
functionsCommand.builder(yargs);
functionCommands.builder(yargs);

expect(yargs.demandCommand).toHaveBeenCalledTimes(1);
expect(yargs.demandCommand).toHaveBeenCalledWith(1, '');
});

it('should support the correct options', () => {
functionsCommand.builder(yargs);

expect(addConfigOptions).toHaveBeenCalledTimes(1);
expect(addConfigOptions).toHaveBeenCalledWith(yargs);

expect(addAccountOptions).toHaveBeenCalledTimes(1);
expect(addAccountOptions).toHaveBeenCalledWith(yargs);
functionCommands.builder(yargs);
});

it('should add the correct number of sub commands', () => {
functionsCommand.builder(yargs);
functionCommands.builder(yargs);
expect(yargs.command).toHaveBeenCalledTimes(subcommands.length);
});

it.each(subcommands)('should attach the %s subcommand', (name, module) => {
functionsCommand.builder(yargs);
functionCommands.builder(yargs);
expect(yargs.command).toHaveBeenCalledWith(module);
});
});
Expand Down
6 changes: 2 additions & 4 deletions commands/__tests__/logs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,10 @@ describe('commands/logs', () => {
type: 'boolean',
}),
follow: expect.objectContaining({
alias: ['t', 'tail', 'f'],
alias: ['f'],
type: 'boolean',
}),
limit: expect.objectContaining({
alias: ['limit', 'n', 'max-count'],
type: 'number',
}),
});
Expand All @@ -72,9 +71,8 @@ describe('commands/logs', () => {

it('should set the correct conflicts', () => {
logsCommand.builder(yargs);
expect(yargs.conflicts).toHaveBeenCalledTimes(2);
expect(yargs.conflicts).toHaveBeenCalledTimes(1);
expect(yargs.conflicts).toHaveBeenCalledWith('follow', 'limit');
expect(yargs.conflicts).toHaveBeenCalledWith('functionName', 'endpoint');
});

it('should provide examples', () => {
Expand Down
20 changes: 20 additions & 0 deletions commands/function.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @ts-nocheck
const list = require('./function/list');
const deploy = require('./function/deploy');
const server = require('./function/server');
const { i18n } = require('../lib/lang');

const i18nKey = 'commands.function';

exports.command = ['function', 'functions'];
exports.describe = i18n(`${i18nKey}.describe`);

exports.builder = yargs => {
yargs
.command(list)
.command(deploy)
.command(server)
.demandCommand(1, '');

return yargs;
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const { outputBuildLog } = require('../../lib/serverlessLogs');
const { i18n } = require('../../lib/lang');
const { isHubSpotHttpError } = require('@hubspot/local-dev-lib/errors/index');

const i18nKey = 'commands.functions.subcommands.deploy';
const i18nKey = 'commands.function.subcommands.deploy';

exports.command = 'deploy <path>';
exports.describe = false;
Expand Down
4 changes: 2 additions & 2 deletions commands/functions/list.ts → commands/function/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ const { trackCommandUsage } = require('../../lib/usageTracking');
const { loadAndValidateOptions } = require('../../lib/validation');
const { i18n } = require('../../lib/lang');

const i18nKey = 'commands.functions.subcommands.list';
const i18nKey = 'commands.function.subcommands.list';
const { EXIT_CODES } = require('../../lib/enums/exitCodes');

exports.command = 'list';
exports.command = ['list', 'ls'];
exports.describe = i18n(`${i18nKey}.describe`);

exports.handler = async options => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const { start: startTestServer } = require('@hubspot/serverless-dev-runtime');
const { loadAndValidateOptions } = require('../../lib/validation');
const { i18n } = require('../../lib/lang');

const i18nKey = 'commands.functions.subcommands.server';
const i18nKey = 'commands.function.subcommands.server';

exports.command = 'server <path>';
exports.describe = false;
Expand Down
27 changes: 0 additions & 27 deletions commands/functions.ts

This file was deleted.

40 changes: 30 additions & 10 deletions commands/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const {
const { tailLogs } = require('../lib/serverlessLogs');
const { loadAndValidateOptions } = require('../lib/validation');
const { i18n } = require('../lib/lang');
const { promptUser } = require('../lib/prompts/promptUtils');
const { EXIT_CODES } = require('../lib/enums/exitCodes');
const { isHubSpotHttpError } = require('@hubspot/local-dev-lib/errors/index');

Expand All @@ -30,8 +31,15 @@ const handleLogsError = (e, accountId, functionPath) => {
}
};

const endpointLog = async (accountId, options) => {
const { latest, follow, compact, endpoint: functionPath } = options;
const endpointLog = async (accountId, functionPath, options) => {
const { limit, latest, follow, compact } = options;
const requestOptions = {
limit,
latest,
follow,
compact,
endpoint: functionPath,
};

logger.debug(
i18n(`${i18nKey}.gettingLogs`, {
Expand Down Expand Up @@ -70,7 +78,11 @@ const endpointLog = async (accountId, options) => {
}
} else {
try {
const { data } = await getFunctionLogs(accountId, functionPath, options);
const { data } = await getFunctionLogs(
accountId,
functionPath,
requestOptions
);
logsResp = data;
} catch (e) {
handleLogsError(e, accountId, functionPath);
Expand All @@ -79,7 +91,7 @@ const endpointLog = async (accountId, options) => {
}

if (logsResp) {
return outputLogs(logsResp, options);
return outputLogs(logsResp, requestOptions);
}
};

Expand All @@ -89,11 +101,21 @@ exports.describe = i18n(`${i18nKey}.describe`);
exports.handler = async options => {
await loadAndValidateOptions(options);

const { latest, derivedAccountId } = options;
const { endpoint: endpointArgValue, latest, derivedAccountId } = options;

trackCommandUsage('logs', { latest }, derivedAccountId);

endpointLog(derivedAccountId, options);
const { endpointPromptValue } = await promptUser({
name: 'endpointPromptValue',
message: i18n(`${i18nKey}.endpointPrompt`),
when: !endpointArgValue,
});

endpointLog(
derivedAccountId,
endpointArgValue || endpointPromptValue,
options
);
};

exports.builder = yargs => {
Expand All @@ -113,18 +135,16 @@ exports.builder = yargs => {
type: 'boolean',
},
follow: {
alias: ['t', 'tail', 'f'],
alias: ['f'],
describe: i18n(`${i18nKey}.options.follow.describe`),
type: 'boolean',
},
limit: {
alias: ['limit', 'n', 'max-count'],
describe: i18n(`${i18nKey}.options.limit.describe`),
type: 'number',
},
})
.conflicts('follow', 'limit')
.conflicts('functionName', 'endpoint');
.conflicts('follow', 'limit');

yargs.example([
['$0 logs my-endpoint', i18n(`${i18nKey}.examples.default`)],
Expand Down
11 changes: 6 additions & 5 deletions lang/en.lyaml
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,8 @@ en:
success:
upload: "Uploaded file from \"{{ src }}\" to \"{{ dest }}\" in the File Manager of account {{ accountId }}"
uploadComplete: "Uploading files to \"{{ dest }}\" in the File Manager is complete"
functions:
describe: "Commands for working with functions."
function:
describe: "Commands for managing CMS serverless functions."
subcommands:
deploy:
debug:
Expand All @@ -347,13 +347,13 @@ en:
loadingFailed: "Failed to build and deploy bundle for \"{{ functionPath }}\" on {{ account }}"
positionals:
path:
describe: "Path to .functions folder"
describe: "Path to the \".functions\" folder"
success:
deployed: "Built and deployed bundle from package.json for {{ functionPath }} on account {{ accountId }} in {{ buildTimeSeconds }}s."
list:
debug:
gettingFunctions: "Getting currently deployed functions"
describe: "List currently deployed functions"
describe: "List the currently deployed CMS serverless functions."
info:
noFunctions: "No functions found"
options:
Expand Down Expand Up @@ -447,13 +447,14 @@ en:
path:
describe: "Remote directory to list contents"
logs:
describe: "Get logs for a function."
describe: "View logs for a CMS serverless function."
errors:
noLogsFound: "No logs were found for the function path \"{{ functionPath }}\" in account \"{{ accountId }}\"."
examples:
default: "Get 5 most recent logs for function residing at /_hcms/api/my-endpoint"
follow: "Poll for and output logs for function residing at /_hcms/api/my-endpoint immediately upon new execution"
limit: "Get 10 most recent logs for function residing at /_hcms/api/my-endpoint"
endpointPrompt: "Enter a serverless function endpoint:"
gettingLogs: "Getting {{#if latest}}latest {{/if}}logs for function with path: {{ functionPath }}."
options:
compact:
Expand Down

0 comments on commit c34a566

Please sign in to comment.