Skip to content

Commit

Permalink
fix: allow overriding config file with cli flags (closes #419)
Browse files Browse the repository at this point in the history
  • Loading branch information
sinedied committed Mar 28, 2022
1 parent 541c23d commit f06d70c
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 45 deletions.
37 changes: 8 additions & 29 deletions src/cli/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { program, Option } from "commander";
import { program, Option, Command } from "commander";
import path from "path";
import { DEFAULT_CONFIG } from "../config";
import { logger, parsePort } from "../core";
import { parsePort } from "../core";
import { parseDevserverTimeout } from "../core";
import { start } from "./commands/start";
import updateNotifier from "update-notifier";
import { getFileOptions, swaCliConfigFilename } from "../core/utils/cli-config";
import { swaCliConfigFilename } from "../core/utils/cli-config";
import { configureOptions } from "../core/utils/options";
const pkg = require("../../package.json");

export const defaultStartContext = `.${path.sep}`;
Expand All @@ -14,7 +15,7 @@ export async function run(argv?: string[]) {
// Once a day, check for updates
updateNotifier({ pkg }).notify();

const cli = program
program
.name("swa")
.usage("<command> [options]")
.version(pkg.version, "-v, --version")
Expand Down Expand Up @@ -61,31 +62,9 @@ export async function run(argv?: string[]) {
.option("--open", "open the browser to the dev server", DEFAULT_CONFIG.open)
.option("--func-args <funcArgs>", "pass additional arguments to the func start command")

.action(async (context: string = `.${path.sep}`, options: SWACLIConfig) => {
const verbose = cli.opts().verbose;

// make sure the start command gets the right verbosity level
process.env.SWA_CLI_DEBUG = verbose;
if (verbose?.includes("silly")) {
// when silly level is set,
// propagate debugging level to other tools using the DEBUG environment variable
process.env.DEBUG = "*";
}
const fileOptions = await getFileOptions(context, cli.opts().config);

options = {
...options,
...fileOptions,
verbose,
};

if (cli.opts().printConfig) {
logger.log("", "swa");
logger.log("Options: ", "swa");
logger.log({ ...DEFAULT_CONFIG, ...options }, "swa");
}

await start(fileOptions.context ?? context, options);
.action(async (context: string = `.${path.sep}`, options: SWACLIConfig, command: Command) => {
const config = await configureOptions(context, options, command);
await start(config.context, config.options);
})

.addHelpText(
Expand Down
22 changes: 11 additions & 11 deletions src/core/utils/cli-config.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as path from "path";
import mockFs from "mock-fs";
import { defaultStartContext } from "../../cli";

import { getFileOptions } from "./cli-config";
import { getConfigFileOptions } from "./cli-config";

const mockConfig1 = {
$schema: "../../../schema/swa-cli.config.schema.json",
Expand Down Expand Up @@ -37,7 +37,7 @@ const mockConfig2 = {
},
};

describe("getFileOptions()", () => {
describe("getConfigFileOptions()", () => {
afterEach(() => {
mockFs.restore();
});
Expand All @@ -54,49 +54,49 @@ describe("getFileOptions()", () => {

it("Should return empty object if not found", async () => {
mockConfig();
expect(await getFileOptions("app", "")).toStrictEqual({});
expect(await getConfigFileOptions("app", "")).toStrictEqual({});
});

it("Should return empty object if config name is not found", async () => {
mockConfig();
expect(await getFileOptions("configName", "swa-cli.config.json")).toStrictEqual({});
expect(await getConfigFileOptions("configName", "swa-cli.config.json")).toStrictEqual({});
});

it("Should return proper config options", async () => {
mockConfig();
expect(await getFileOptions("app", "swa-cli.config.json")).toStrictEqual(mockConfig1.configurations.app);
expect(await getConfigFileOptions("app", "swa-cli.config.json")).toStrictEqual(mockConfig1.configurations.app);
});

it("Should only return a default config if there is only one config", async () => {
mockConfig();
expect(await getFileOptions(defaultStartContext, "swa-cli.config.json")).toStrictEqual({});
expect(await getConfigFileOptions(defaultStartContext, "swa-cli.config.json")).toStrictEqual({});
});

it("Should return a default config", async () => {
mockConfig(mockConfig2);
expect(await getFileOptions(defaultStartContext, "swa-cli.config.json")).toStrictEqual(mockConfig2.configurations.app);
expect(await getConfigFileOptions(defaultStartContext, "swa-cli.config.json")).toStrictEqual(mockConfig2.configurations.app);
});

it("Should return empty object if config file is not found", async () => {
expect(await getFileOptions(defaultStartContext, "swa-cli.config.json")).toStrictEqual({});
expect(await getConfigFileOptions(defaultStartContext, "swa-cli.config.json")).toStrictEqual({});
});

it("Should return proper config without path specified", async () => {
mockConfig(mockConfig1);
expect(await getFileOptions("app", "swa-cli.config.json")).toStrictEqual(mockConfig1.configurations.app);
expect(await getConfigFileOptions("app", "swa-cli.config.json")).toStrictEqual(mockConfig1.configurations.app);
});

it("Should change cwd to the config root dir if a config exists", async () => {
const configDir = path.resolve("../../");
mockFs({ "../../swa-cli.config.json": JSON.stringify(mockConfig1) });
expect(await getFileOptions("app", "../../swa-cli.config.json")).toStrictEqual(mockConfig1.configurations.app);
expect(await getConfigFileOptions("app", "../../swa-cli.config.json")).toStrictEqual(mockConfig1.configurations.app);
expect(process.cwd()).toBe(configDir);
});

it("Should not change cwd no config is specified or found", async () => {
const currentDir = path.resolve(".");
mockFs({ "../../swa-cli.config.json": JSON.stringify(mockConfig1) });
expect(await getFileOptions("app", "swa-cli.config.json")).toEqual({});
expect(await getConfigFileOptions("app", "swa-cli.config.json")).toEqual({});
expect(process.cwd()).toBe(currentDir);
});
});
11 changes: 6 additions & 5 deletions src/core/utils/cli-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ const { readFile } = fsPromises;

export const swaCliConfigFilename = "swa-cli.config.json";

export async function getFileOptions(context: string, configFilePath: string): Promise<SWACLIConfig & { context?: string }> {
export const configExists = (configFilePath: string) => fs.existsSync(configFilePath);

export async function getConfigFileOptions(context: string, configFilePath: string): Promise<SWACLIConfig & { context?: string }> {
configFilePath = path.resolve(configFilePath);
if (!fs.existsSync(configFilePath)) {
if (!configExists(configFilePath)) {
return {};
}

Expand All @@ -27,13 +29,13 @@ export async function getFileOptions(context: string, configFilePath: string): P
if (hasOnlyOneConfig && context === defaultStartContext) {
const [configName, config] = Object.entries(cliConfig.configurations)[0];
printConfigMsg(configName, configFilePath);
return { context: `.${path.sep}`, ...config };
return { ...config };
}

const config = cliConfig.configurations?.[context];
if (config) {
printConfigMsg(context, configFilePath);
return { context: `.${path.sep}`, ...config };
return { ...config };
}

return {};
Expand All @@ -55,5 +57,4 @@ function printConfigMsg(name: string, file: string) {
logger.log(`Using configuration "${name}" from file:`, "swa");
logger.log(`\t${file}`, "swa");
logger.log("", "swa");
logger.log(`Options passed in via CLI will be overridden by options in file.`, "swa");
}
50 changes: 50 additions & 0 deletions src/core/utils/options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Command, OptionValues } from "commander";
import { logger } from "./logger";
import { getConfigFileOptions } from "./cli-config";
import { DEFAULT_CONFIG } from "../../config";

export async function configureOptions(
context: string,
options: SWACLIConfig,
command: Command
): Promise<{ context: string; options: SWACLIConfig }> {
const verbose = options.verbose;
process.env.SWA_CLI_DEBUG = verbose;

if (verbose?.includes("silly")) {
// When silly level is set,
// propagate debugging level to other tools using the DEBUG environment variable
process.env.DEBUG = "*";
}

const userOptions = getUserOptions(command);
const configFileOptions = await getConfigFileOptions(context, options.config!);

options = {
...options,
...configFileOptions,
...userOptions,
};

if (options.printConfig) {
logger.log("", "swa");
logger.log("Options: ", "swa");
logger.log({ ...DEFAULT_CONFIG, ...options }, "swa");
}

return {
context: configFileOptions.context ?? context,
options,
};
}

function getUserOptions(command: Command) {
const userOptions: OptionValues = {};
const options = command.opts();
for (const option in options) {
if (command.getOptionValueSource(option) !== "default") {
userOptions[option] = options[option];
}
}
return userOptions as SWACLIConfig;
}

0 comments on commit f06d70c

Please sign in to comment.