From 210e0502ca05c2f29b1016d943b73c870430f091 Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Fri, 28 Jan 2022 09:29:04 -0500 Subject: [PATCH] Feature/put serve behind feature flag (#455) * Add build-time feature flag capabilities * Toggle `bw serve` command with `serve` flag * Run linter and prettier --- .gitignore | 2 ++ config/config.js | 30 ++++++++++++++++++++++++++++++ config/development.json | 5 +++++ config/production.json | 5 +++++ spec/utils.spec.ts | 27 +++++++++++++++++++++++++++ src/flags.ts | 5 +++++ src/program.ts | 34 ++++++++++++++++++---------------- src/utils.ts | 15 +++++++++++++++ webpack.config.js | 12 ++++++++++-- 9 files changed, 117 insertions(+), 18 deletions(-) create mode 100644 config/config.js create mode 100644 config/development.json create mode 100644 config/production.json create mode 100644 spec/utils.spec.ts create mode 100644 src/flags.ts diff --git a/.gitignore b/.gitignore index ab57381ff3..b6c18808b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ node_modules build dist + +config/local.json diff --git a/config/config.js b/config/config.js new file mode 100644 index 0000000000..81e2d619fe --- /dev/null +++ b/config/config.js @@ -0,0 +1,30 @@ +function load(envName) { + return { + ...loadConfig(envName), + ...loadConfig("local"), + }; +} + +function log(configObj) { + const repeatNum = 50; + console.log(`${"=".repeat(repeatNum)}\nenvConfig`); + console.log(JSON.stringify(configObj, null, 2)); + console.log(`${"=".repeat(repeatNum)}`); +} + +function loadConfig(configName) { + try { + return require(`./${configName}.json`); + } catch (e) { + if (e instanceof Error && e.code === "MODULE_NOT_FOUND") { + return {}; + } else { + throw e; + } + } +} + +module.exports = { + load, + log, +}; diff --git a/config/development.json b/config/development.json new file mode 100644 index 0000000000..d8e5c04e7e --- /dev/null +++ b/config/development.json @@ -0,0 +1,5 @@ +{ + "flags": { + "serve": true + } +} diff --git a/config/production.json b/config/production.json new file mode 100644 index 0000000000..f72d5f41c4 --- /dev/null +++ b/config/production.json @@ -0,0 +1,5 @@ +{ + "flags": { + "serve": false + } +} diff --git a/spec/utils.spec.ts b/spec/utils.spec.ts new file mode 100644 index 0000000000..c7d47075ef --- /dev/null +++ b/spec/utils.spec.ts @@ -0,0 +1,27 @@ +import { FlagName } from "../src/flags"; +import { CliUtils } from "../src/utils"; +describe("flagEnabled", () => { + it("is true if flag is null", () => { + process.env.FLAGS = JSON.stringify({ test: null }); + + expect(CliUtils.flagEnabled("test" as FlagName)).toBe(true); + }); + + it("is true if flag is undefined", () => { + process.env.FLAGS = JSON.stringify({}); + + expect(CliUtils.flagEnabled("test" as FlagName)).toBe(true); + }); + + it("is true if flag is true", () => { + process.env.FLAGS = JSON.stringify({ test: true }); + + expect(CliUtils.flagEnabled("test" as FlagName)).toBe(true); + }); + + it("is false if flag is false", () => { + process.env.FLAGS = JSON.stringify({ test: false }); + + expect(CliUtils.flagEnabled("test" as FlagName)).toBe(false); + }); +}); diff --git a/src/flags.ts b/src/flags.ts new file mode 100644 index 0000000000..b0db46132d --- /dev/null +++ b/src/flags.ts @@ -0,0 +1,5 @@ +export type Flags = { + serve?: boolean; +}; + +export type FlagName = keyof Flags; diff --git a/src/program.ts b/src/program.ts index 850e79fe81..2fc43fad77 100644 --- a/src/program.ts +++ b/src/program.ts @@ -468,22 +468,24 @@ export class Program extends BaseProgram { this.processResponse(response); }); - program - .command("serve") - .description("Start a RESTful API webserver.") - .option("--port ", "The port to run your API webserver on. Default port is 8087.") - .on("--help", () => { - writeLn("\n Examples:"); - writeLn(""); - writeLn(" bw serve"); - writeLn(" bw serve --port 8080"); - writeLn("", true); - }) - .action(async (cmd) => { - await this.exitIfNotAuthed(); - const command = new ServeCommand(this.main); - await command.run(cmd); - }); + if (CliUtils.flagEnabled("serve")) { + program + .command("serve") + .description("Start a RESTful API webserver.") + .option("--port ", "The port to run your API webserver on. Default port is 8087.") + .on("--help", () => { + writeLn("\n Examples:"); + writeLn(""); + writeLn(" bw serve"); + writeLn(" bw serve --port 8080"); + writeLn("", true); + }) + .action(async (cmd) => { + await this.exitIfNotAuthed(); + const command = new ServeCommand(this.main); + await command.run(cmd); + }); + } } protected processResponse(response: Response, exitImmediately = false) { diff --git a/src/utils.ts b/src/utils.ts index a3c5317725..2a822684b4 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -9,6 +9,7 @@ import { CollectionView } from "jslib-common/models/view/collectionView"; import { FolderView } from "jslib-common/models/view/folderView"; import { NodeUtils } from "jslib-common/misc/nodeUtils"; +import { FlagName, Flags } from "./flags"; export class CliUtils { static writeLn(s: string, finalLine: boolean = false, error: boolean = false) { @@ -174,4 +175,18 @@ export class CliUtils { static convertBooleanOption(optionValue: any) { return optionValue || optionValue === "" ? true : false; } + + static flagEnabled(flag: FlagName) { + return this.flags[flag] == null || this.flags[flag]; + } + + private static get flags(): Flags { + const envFlags = process.env.FLAGS; + + if (typeof envFlags === "string") { + return JSON.parse(envFlags) as Flags; + } else { + return envFlags as Flags; + } + } } diff --git a/webpack.config.js b/webpack.config.js index a54bc8f893..ab3375664d 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -4,12 +4,16 @@ const { CleanWebpackPlugin } = require("clean-webpack-plugin"); const CopyWebpackPlugin = require("copy-webpack-plugin"); const nodeExternals = require("webpack-node-externals"); const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin"); +const config = require("./config/config"); if (process.env.NODE_ENV == null) { process.env.NODE_ENV = "development"; } const ENV = (process.env.ENV = process.env.NODE_ENV); +const envConfig = config.load(ENV); +config.log(envConfig); + const moduleRules = [ { test: /\.ts$/, @@ -39,9 +43,13 @@ const plugins = [ resourceRegExp: /^encoding$/, contextRegExp: /node-fetch/, }), + new webpack.EnvironmentPlugin({ + BWCLI_ENV: ENV, + FLAGS: envConfig.flags, + }), ]; -const config = { +const webpackConfig = { mode: ENV, target: "node", devtool: ENV === "development" ? "eval-source-map" : "source-map", @@ -70,4 +78,4 @@ const config = { externals: [nodeExternals()], }; -module.exports = config; +module.exports = webpackConfig;