From e86f0f37605f87952fc82e00241dbbaa549e7a75 Mon Sep 17 00:00:00 2001 From: Neil Macneale V Date: Tue, 3 Oct 2023 11:33:22 -0700 Subject: [PATCH 1/5] Move endpoint commands into a topic, with aliases to the old commands --- package.json | 13 +++++- src/commands/delete-endpoint.js | 31 ------------- .../{add-endpoint.ts => endpoint/add.ts} | 17 +++---- src/commands/endpoint/list.ts | 33 ++++++++++++++ src/commands/endpoint/remove.ts | 45 +++++++++++++++++++ src/commands/list-endpoints.js | 43 ------------------ 6 files changed, 99 insertions(+), 83 deletions(-) delete mode 100644 src/commands/delete-endpoint.js rename src/commands/{add-endpoint.ts => endpoint/add.ts} (87%) create mode 100644 src/commands/endpoint/list.ts create mode 100644 src/commands/endpoint/remove.ts delete mode 100644 src/commands/list-endpoints.js diff --git a/package.json b/package.json index 49b7f0ad..0e0bb90c 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,18 @@ "@oclif/plugin-help", "@oclif/plugin-plugins" ], - "topicSeparator": " " + "topicSeparator": " ", + "topics": { + "endpoint": { + "description": "Manage endpoints in ~/.fauna-shell." + }, + "project": { + "description": "Manage project settings in .fauna-project." + }, + "stack": { + "description": "Manage stacks in the current project." + } + } }, "repository": "fauna/fauna-shell", "scripts": { diff --git a/src/commands/delete-endpoint.js b/src/commands/delete-endpoint.js deleted file mode 100644 index 972f6e03..00000000 --- a/src/commands/delete-endpoint.js +++ /dev/null @@ -1,31 +0,0 @@ -const { deleteEndpointOrError } = require("../lib/misc.js"); -const { Args } = require("@oclif/core"); -const FaunaCommand = require("../lib/fauna-command.js").default; - -class DeleteEndpoint extends FaunaCommand { - async run() { - const alias = this.args.endpoint_alias; - return deleteEndpointOrError(alias).catch((err) => { - this.error(err.message, 1); - }); - } -} - -DeleteEndpoint.description = ` -Deletes a connection endpoint. -`; - -DeleteEndpoint.examples = ["$ fauna delete-endpoint endpoint_alias"]; - -// clear the default FaunaCommand flags that accept --host, --port, etc. -DeleteEndpoint.flags = {}; - -DeleteEndpoint.args = { - // eslint-disable-next-line camelcase - endpoint_alias: Args.string({ - required: true, - description: "Fauna server endpoint alias", - }), -}; - -module.exports = DeleteEndpoint; diff --git a/src/commands/add-endpoint.ts b/src/commands/endpoint/add.ts similarity index 87% rename from src/commands/add-endpoint.ts rename to src/commands/endpoint/add.ts index fe1ce121..a35aa8d7 100644 --- a/src/commands/add-endpoint.ts +++ b/src/commands/endpoint/add.ts @@ -1,7 +1,7 @@ import { Flags, Args, Command, ux } from "@oclif/core"; import { input, confirm } from "@inquirer/prompts"; -import { Endpoint, ShellConfig, getRootConfigPath } from "../lib/config"; -import FaunaClient from "../lib/fauna-client"; +import { Endpoint, ShellConfig, getRootConfigPath } from "../../lib/config"; +import FaunaClient from "../../lib/fauna-client"; export default class AddEndpointCommand extends Command { static args = { @@ -10,14 +10,12 @@ export default class AddEndpointCommand extends Command { }), }; - static description = ` -Adds an endpoint to ~/.fauna-shell. -`; + static description = "Adds an endpoint to ~/.fauna-shell."; static examples = [ - "$ fauna add-endpoint", - "$ fauna add-endpoint localhost --url http://localhost:8443/ --key secret", - "$ fauna add-endpoint localhost --set-default", + "$ fauna endpoint add", + "$ fauna endpoint add localhost --url http://localhost:8443/ --key secret", + "$ fauna endpoint add localhost --set-default", ]; static flags = { @@ -38,6 +36,9 @@ Adds an endpoint to ~/.fauna-shell. }), }; + static aliases = ["add-endpoint"]; + static deprecateAliases = true; + async run() { const config = ShellConfig.read({}); diff --git a/src/commands/endpoint/list.ts b/src/commands/endpoint/list.ts new file mode 100644 index 00000000..83c51e9e --- /dev/null +++ b/src/commands/endpoint/list.ts @@ -0,0 +1,33 @@ +import { Command } from "@oclif/core"; +import { ShellConfig } from "../../lib/config"; +import chalk from "chalk"; + +export default class ListEndpointCommand extends Command { + static flags = {}; + + static description = "Lists endpoints in ~/.fauna-shell."; + + static examples = ["$ fauna endpoint list"]; + + static aliases = ["list-endpoints"]; + static deprecateAliases = true; + + async run() { + const config = ShellConfig.read({}); + + await this.execute(config); + } + + async execute(config: ShellConfig) { + await this.parse(); + + this.log("Available endpoints:"); + for (const key of Object.keys(config.rootConfig.endpoints)) { + if (config.rootConfig.defaultEndpoint === key) { + this.log(chalk.green("* ") + key); + } else { + this.log(" " + key); + } + } + } +} diff --git a/src/commands/endpoint/remove.ts b/src/commands/endpoint/remove.ts new file mode 100644 index 00000000..d54db2be --- /dev/null +++ b/src/commands/endpoint/remove.ts @@ -0,0 +1,45 @@ +import { Args, Command } from "@oclif/core"; +import { ShellConfig } from "../../lib/config"; + +export default class DeleteEndpointCommand extends Command { + static description = "Deletes an endpoint from ~/.fauna-shell."; + + static examples = ["$ fauna endpoint remove my_endpoint"]; + + static flags = {}; + + static args = { + name: Args.string({ + required: true, + description: "Endpoint name", + }), + }; + + static aliases = ["delete-endpoint"]; + static deprecateAliases = true; + + async run() { + const config = ShellConfig.read({}); + + await this.execute(config); + } + + async execute(config: ShellConfig) { + const { args } = await this.parse(); + const name = args.name; + + if (config.rootConfig.endpoints[name] === undefined) { + this.error(`No such endpoint ${name}`); + } + + // Clear the default if `name` is the default. + if (config.rootConfig.defaultEndpoint === name) { + config.rootConfig.defaultEndpoint = undefined; + } + delete config.rootConfig.endpoints[name]; + + config.saveRootConfig(); + + this.log(`Removed endpoint ${name}`); + } +} diff --git a/src/commands/list-endpoints.js b/src/commands/list-endpoints.js deleted file mode 100644 index c64d5c31..00000000 --- a/src/commands/list-endpoints.js +++ /dev/null @@ -1,43 +0,0 @@ -const { loadEndpoints } = require("../lib/misc.js"); -const FaunaCommand = require("../lib/fauna-command.js").default; - -class ListEndpointsCommand extends FaunaCommand { - async run() { - return loadEndpoints() - .then((endpoints) => { - var keys = Object.keys(endpoints); - if (keys.length === 0) { - throw new Error( - "No endpoints defined.\nSee fauna add-endpoint --help for more details." - ); - } else { - keys.forEach((endpoint) => { - // skip the key that stores the default endpoint - if (endpoint === "default") { - // in JS return skips this iteration. - return; - } - var enabled = ""; - if (endpoint === endpoints.default) { - enabled = " *"; - } - this.log(`${endpoint}${enabled}`); - }); - } - }) - .catch((err) => { - this.error(err.message); - }); - } -} - -ListEndpointsCommand.description = ` -Lists connection endpoints. -`; - -ListEndpointsCommand.examples = ["$ fauna list-endpoints"]; - -// clear the default FaunaCommand flags that accept --host, --port, etc. -ListEndpointsCommand.flags = {}; - -module.exports = ListEndpointsCommand; From b3626799442edcc4f15eff0960cf93291d6104d4 Mon Sep 17 00:00:00 2001 From: Neil Macneale V Date: Tue, 3 Oct 2023 13:07:12 -0700 Subject: [PATCH 2/5] Fix warning and log messages to use capitals and period --- src/commands/endpoint/add.ts | 2 +- src/commands/endpoint/remove.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/endpoint/add.ts b/src/commands/endpoint/add.ts index a35aa8d7..8462aad5 100644 --- a/src/commands/endpoint/add.ts +++ b/src/commands/endpoint/add.ts @@ -103,7 +103,7 @@ export default class AddEndpointCommand extends Command { } } catch (e) { ux.action.stop(); - console.log("Warning: could not connect to fauna"); + console.log("Warning: could not connect to Fauna"); } finally { await client.close(); } diff --git a/src/commands/endpoint/remove.ts b/src/commands/endpoint/remove.ts index d54db2be..3fe9d8c8 100644 --- a/src/commands/endpoint/remove.ts +++ b/src/commands/endpoint/remove.ts @@ -40,6 +40,6 @@ export default class DeleteEndpointCommand extends Command { config.saveRootConfig(); - this.log(`Removed endpoint ${name}`); + this.log(`Removed endpoint ${name}.`); } } From 5d1a0b3d5e2501c5c95e3e4027073fc1d12a3817 Mon Sep 17 00:00:00 2001 From: Neil Macneale V Date: Tue, 3 Oct 2023 13:07:31 -0700 Subject: [PATCH 3/5] Add tests for the remaining endpoint commands --- test/commands/endpoint.test.ts | 116 ++++++++++++++++++++++++++++++-- test/commands/endpoints.test.js | 47 ------------- 2 files changed, 112 insertions(+), 51 deletions(-) delete mode 100644 test/commands/endpoints.test.js diff --git a/test/commands/endpoint.test.ts b/test/commands/endpoint.test.ts index 6bde94b6..c2890ac8 100644 --- a/test/commands/endpoint.test.ts +++ b/test/commands/endpoint.test.ts @@ -1,7 +1,9 @@ import { expect, test } from "@oclif/test"; import { ShellConfig, getRootConfigPath } from "../../src/lib/config"; import sinon, { SinonStub } from "sinon"; -import AddEndpointCommand from "../../src/commands/add-endpoint"; +import AddEndpointCommand from "../../src/commands/endpoint/add"; +import ListEndpointCommand from "../../src/commands/endpoint/list"; +import RemoveEndpointCommand from "../../src/commands/endpoint/remove"; import { Config } from "@oclif/core"; const rootConfigPath = getRootConfigPath(); @@ -18,7 +20,7 @@ const stubbedRootConfig = ( return config as any; }; -describe("add-endpoint", () => { +describe("endpoint:add", () => { test .add("config", () => stubbedRootConfig({ @@ -45,7 +47,7 @@ describe("add-endpoint", () => { ) .it("adds an endpoint", (ctx) => { expect(ctx.stdout).to.equal( - `Saved endpoint foobar to ${rootConfigPath}\n` + `Warning: could not connect to Fauna\nSaved endpoint foobar to ${rootConfigPath}\n` ); expect(ctx.config.rootConfig).to.deep.equal({ defaultEndpoint: "my-endpoint", @@ -96,7 +98,7 @@ describe("add-endpoint", () => { ) .it("sets default endpoint", (ctx) => { expect(ctx.stdout).to.equal( - `Saved endpoint foobar to ${rootConfigPath}\n` + `Warning: could not connect to Fauna\nSaved endpoint foobar to ${rootConfigPath}\n` ); expect(ctx.config.rootConfig).to.deep.equal({ defaultEndpoint: "foobar", @@ -120,3 +122,109 @@ describe("add-endpoint", () => { expect(ctx.config.saveRootConfig.calledOnce).to.be.true; }); }); + +describe("endpoint:list", () => { + test + .add("config", () => + stubbedRootConfig({ + default: "my-endpoint", + "my-endpoint": { + url: "http://bar.baz", + secret: "fn3333", + }, + "other-endpoint": { + url: "http://bar.baz", + secret: "fn3333", + }, + }) + ) + .stdout() + .do((ctx) => + new ListEndpointCommand([], new Config({} as any)).execute(ctx.config) + ) + .it("lists endpoints", (ctx) => { + expect(ctx.stdout).to.equal( + `Available endpoints:\n* my-endpoint\n other-endpoint\n` + ); + expect(ctx.config.saveRootConfig.calledOnce).to.be.false; + }); +}); + +describe("endpoint:remove", () => { + test + .add("config", () => + stubbedRootConfig({ + default: "my-endpoint", + "my-endpoint": { + url: "http://bar.baz", + secret: "fn3333", + }, + "other-endpoint": { + url: "http://bar.baz", + secret: "fn3333", + }, + }) + ) + .stdout() + .do((ctx) => + new RemoveEndpointCommand( + ["other-endpoint"], + new Config({} as any) + ).execute(ctx.config) + ) + .it("removes an endpoint", (ctx) => { + expect(ctx.stdout).to.equal(`Removed endpoint other-endpoint.\n`); + expect(ctx.config.rootConfig).to.deep.equal({ + defaultEndpoint: "my-endpoint", + endpoints: { + "my-endpoint": { + url: "http://bar.baz", + secret: "fn3333", + // These graphql bits are only saved if they differ from the + // default. + graphqlHost: "graphql.fauna.com", + graphqlPort: 443, + }, + }, + }); + expect(ctx.config.saveRootConfig.calledOnce).to.be.true; + }); + + test + .add("config", () => + stubbedRootConfig({ + default: "my-endpoint", + "my-endpoint": { + url: "http://bar.baz", + secret: "fn3333", + }, + "other-endpoint": { + url: "http://bar.baz", + secret: "fn3333", + }, + }) + ) + .stdout() + .do((ctx) => + new RemoveEndpointCommand(["my-endpoint"], new Config({} as any)).execute( + ctx.config + ) + ) + .it("clears the default if needed", (ctx) => { + expect(ctx.stdout).to.equal(`Removed endpoint my-endpoint.\n`); + expect(ctx.config.rootConfig).to.deep.equal({ + defaultEndpoint: undefined, + endpoints: { + "other-endpoint": { + url: "http://bar.baz", + secret: "fn3333", + // These graphql bits are only saved if they differ from the + // default. + graphqlHost: "graphql.fauna.com", + graphqlPort: 443, + }, + }, + }); + expect(ctx.config.saveRootConfig.calledOnce).to.be.true; + }); +}); diff --git a/test/commands/endpoints.test.js b/test/commands/endpoints.test.js deleted file mode 100644 index 0d31cd9e..00000000 --- a/test/commands/endpoints.test.js +++ /dev/null @@ -1,47 +0,0 @@ -const { expect, test } = require("@oclif/test"); -const fs = require("fs"); -const ini = require("ini"); -const { getConfigFile } = require("../../src/lib/misc"); - -const configMock = { - default: "local", - cloud: { - domain: "db.fauna.com", - scheme: "https", - secret: "secret", - graphqlHost: "graphql.fauna.com", - }, - local: { - domain: "127.0.0.1", - scheme: "http", - secret: "secret", - graphqlHost: "127.0.0.1", - }, -}; - -describe("endpoints", () => { - const originalReadFile = fs.readFile; - - test - .stub(fs, "readFile", (file, enc, cb) => { - if (file !== getConfigFile()) return originalReadFile(file, enc, cb); - cb(null, ini.encode(configMock)); - }) - .stdout() - .command(["list-endpoints"]) - .it("runs list-endpoints", (ctx) => { - expect(ctx.stdout).to.contain("cloud\nlocal *\n"); - }); - - test - .stub(fs, "readFile", (file, enc, cb) => { - if (file !== getConfigFile()) return originalReadFile(file, enc, cb); - cb(null, ini.encode({})); - }) - .stdout() - .command(["list-endpoints"]) - .catch((err) => { - expect(err.message).to.contain("No endpoints defined"); - }) - .it("runs list-endpoints when no endpoints defined"); -}); From 27d761a2f28adc34fbd1d460c5862c9bd5364667 Mon Sep 17 00:00:00 2001 From: Neil Macneale V Date: Tue, 3 Oct 2023 13:20:18 -0700 Subject: [PATCH 4/5] Fix linter things --- src/commands/endpoint/add.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/commands/endpoint/add.ts b/src/commands/endpoint/add.ts index 8462aad5..06d66809 100644 --- a/src/commands/endpoint/add.ts +++ b/src/commands/endpoint/add.ts @@ -84,13 +84,7 @@ export default class AddEndpointCommand extends Command { })); const secret = - flags?.secret ?? - (await input({ - message: "Database Secret", - validate: async (secret) => { - return true; - }, - })); + flags?.secret ?? (await input({ message: "Database Secret" })); ux.action.start("Checking secret"); From bbe89e3c930256e027084e30be7d5c31695a0f3d Mon Sep 17 00:00:00 2001 From: Neil Macneale V Date: Tue, 3 Oct 2023 16:56:22 -0700 Subject: [PATCH 5/5] Update to 'Compute the frustum of the wangledinger' (imperative mood) --- src/commands/endpoint/add.ts | 2 +- src/commands/endpoint/list.ts | 2 +- src/commands/endpoint/remove.ts | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/commands/endpoint/add.ts b/src/commands/endpoint/add.ts index 06d66809..fc39fed9 100644 --- a/src/commands/endpoint/add.ts +++ b/src/commands/endpoint/add.ts @@ -10,7 +10,7 @@ export default class AddEndpointCommand extends Command { }), }; - static description = "Adds an endpoint to ~/.fauna-shell."; + static description = "Add an endpoint to ~/.fauna-shell."; static examples = [ "$ fauna endpoint add", diff --git a/src/commands/endpoint/list.ts b/src/commands/endpoint/list.ts index 83c51e9e..263a223f 100644 --- a/src/commands/endpoint/list.ts +++ b/src/commands/endpoint/list.ts @@ -5,7 +5,7 @@ import chalk from "chalk"; export default class ListEndpointCommand extends Command { static flags = {}; - static description = "Lists endpoints in ~/.fauna-shell."; + static description = "List endpoints in ~/.fauna-shell."; static examples = ["$ fauna endpoint list"]; diff --git a/src/commands/endpoint/remove.ts b/src/commands/endpoint/remove.ts index 3fe9d8c8..effdcf3a 100644 --- a/src/commands/endpoint/remove.ts +++ b/src/commands/endpoint/remove.ts @@ -1,8 +1,8 @@ import { Args, Command } from "@oclif/core"; import { ShellConfig } from "../../lib/config"; -export default class DeleteEndpointCommand extends Command { - static description = "Deletes an endpoint from ~/.fauna-shell."; +export default class RemoveEndpointCommand extends Command { + static description = "Remove an endpoint from ~/.fauna-shell."; static examples = ["$ fauna endpoint remove my_endpoint"];