diff --git a/__tests__/unit/core-cli/commands/command.test.ts b/__tests__/unit/core-cli/commands/command.test.ts index 04b1e69505..6478eee944 100644 --- a/__tests__/unit/core-cli/commands/command.test.ts +++ b/__tests__/unit/core-cli/commands/command.test.ts @@ -1,7 +1,7 @@ import { Container } from "@arkecosystem/core-cli"; import { Console } from "@arkecosystem/core-test-framework"; import Joi from "@hapi/joi"; -import { Command } from "@packages/core-cli/src/commands"; +import { Command, DiscoverConfig } from "@packages/core-cli/src/commands"; import { setGracefulCleanup } from "tmp"; @Container.injectable() @@ -72,14 +72,14 @@ describe("Command", () => { }); describe("#initialize", () => { - it("should initialize the command", () => { - expect(cmd.initialize()).resolves.toBeUndefined(); + it("should initialize the command", async () => { + await expect(cmd.initialize()).resolves.toBeUndefined(); }); }); describe("#interact", () => { - it("should interact with the user", () => { - expect(cmd.interact()).resolves.toBeUndefined(); + it("should interact with the user", async () => { + await expect(cmd.interact()).resolves.toBeUndefined(); }); }); @@ -97,6 +97,19 @@ describe("Command", () => { await cmd.run(); }); + it("should run the command without a network and token if network is detected from config", async () => { + const spyOnDiscover = jest.spyOn(DiscoverConfig.prototype, "discover").mockResolvedValue({ + token: "token", + network: "testnet", + }); + + await cmd.run(); + + expect(spyOnDiscover).toHaveBeenCalledTimes(2); + expect(cmd.getFlag("token")).toEqual("token"); + expect(cmd.getFlag("network")).toEqual("testnet"); + }); + it("should run the command in interactive mode", async () => { cmd.register(["env:paths", "--interaction"]); @@ -135,7 +148,7 @@ describe("Command", () => { describe("#execute", () => { it("should execute the command", async () => { - expect(cmd.execute()).resolves.toBeUndefined(); + await expect(cmd.execute()).resolves.toBeUndefined(); }); }); @@ -143,6 +156,7 @@ describe("Command", () => { it("should display the help", () => { let output; jest.spyOn(cli.app.get(Container.Identifiers.Box), "render").mockImplementation( + // @ts-ignore (message: string) => (output = message), ); diff --git a/__tests__/unit/core-cli/commands/discover-config.test.ts b/__tests__/unit/core-cli/commands/discover-config.test.ts new file mode 100644 index 0000000000..2e3a4c1da8 --- /dev/null +++ b/__tests__/unit/core-cli/commands/discover-config.test.ts @@ -0,0 +1,50 @@ +import { Console } from "@arkecosystem/core-test-framework"; +import { DiscoverConfig } from "@packages/core-cli/src/commands"; +import { ensureDirSync, writeJSON } from "fs-extra"; +import { join } from "path"; +import { dirSync, setGracefulCleanup } from "tmp"; + +let cli; +let cmd; +let configPath; +const config = { token: "token", network: "testnet" }; + +jest.mock("env-paths", () => () => ({ + config: configPath, +})); + +beforeAll(() => setGracefulCleanup()); + +beforeEach(() => { + cli = new Console(); + + cmd = cli.app.resolve(DiscoverConfig); + + configPath = join(dirSync().name, "token-core"); +}); + +describe("DiscoverConfig", () => { + it("should return undefined if configuration can't be found", async () => { + await expect(cmd.discover()).resolves.toEqual(undefined); + }); + + it("should return configuration if found on default config location", async () => { + ensureDirSync(join(configPath, "testnet")); + + await writeJSON(join(configPath, "testnet", "config.json"), config); + + await expect(cmd.discover("token", "testnet")).resolves.toEqual(config); + }); + + it("should return configuration if found on CORE_PATH_CONFIG location", async () => { + process.env.CORE_PATH_CONFIG = join(configPath, "testnet"); + + ensureDirSync(join(configPath, "testnet")); + + await writeJSON(join(configPath, "testnet", "config.json"), config); + + await expect(cmd.discover()).resolves.toEqual(config); + + delete process.env.CORE_PATH_CONFIG; + }); +}); diff --git a/__tests__/unit/core-cli/commands/discover-network.test.ts b/__tests__/unit/core-cli/commands/discover-network.test.ts index c3f9fba2bb..b69954f0ae 100644 --- a/__tests__/unit/core-cli/commands/discover-network.test.ts +++ b/__tests__/unit/core-cli/commands/discover-network.test.ts @@ -1,6 +1,5 @@ import { Console } from "@arkecosystem/core-test-framework"; import { DiscoverNetwork } from "@packages/core-cli/src/commands"; -import envPaths from "env-paths"; import { ensureDirSync } from "fs-extra"; import prompts from "prompts"; import { dirSync, setGracefulCleanup } from "tmp"; @@ -16,32 +15,18 @@ beforeEach(() => { cmd = cli.app.resolve(DiscoverNetwork); - configPath = envPaths("ark", { suffix: "core" }).config; + configPath = dirSync().name; }); describe("DiscoverNetwork", () => { it("should throw if no configurations can be detected", async () => { await expect(cmd.discover(configPath)).rejects.toThrow(); - - delete process.env.CORE_PATH_CONFIG; - }); - - it("should throw if no configurations can be detected (with environment variable as path)", async () => { - process.env.CORE_PATH_CONFIG = dirSync().name; - - await expect(cmd.discover(configPath)).rejects.toThrow(); - - delete process.env.CORE_PATH_CONFIG; }); it("should choose the first network if only a single network is found", async () => { - process.env.CORE_PATH_CONFIG = dirSync().name; - - ensureDirSync(`${process.env.CORE_PATH_CONFIG}/mainnet`); + ensureDirSync(`${configPath}/mainnet`); await expect(cmd.discover(configPath)).resolves.toBe("mainnet"); - - delete process.env.CORE_PATH_CONFIG; }); it("should throw if the given path does not exist", async () => { @@ -49,41 +34,29 @@ describe("DiscoverNetwork", () => { }); it("should choose the selected network if multiple networks are found", async () => { - process.env.CORE_PATH_CONFIG = dirSync().name; - - ensureDirSync(`${process.env.CORE_PATH_CONFIG}/mainnet`); - ensureDirSync(`${process.env.CORE_PATH_CONFIG}/devnet`); + ensureDirSync(`${configPath}/mainnet`); + ensureDirSync(`${configPath}/devnet`); prompts.inject(["devnet", true]); await expect(cmd.discover(configPath)).resolves.toBe("devnet"); - - delete process.env.CORE_PATH_CONFIG; }); it("should throw if the network selection is not confirmed", async () => { - process.env.CORE_PATH_CONFIG = dirSync().name; - - ensureDirSync(`${process.env.CORE_PATH_CONFIG}/mainnet`); - ensureDirSync(`${process.env.CORE_PATH_CONFIG}/devnet`); + ensureDirSync(`${configPath}/mainnet`); + ensureDirSync(`${configPath}/devnet`); prompts.inject(["devnet", false]); await expect(cmd.discover(configPath)).rejects.toThrow("You'll need to confirm the network to continue."); - - delete process.env.CORE_PATH_CONFIG; }); it("should throw if the network selection is not valid", async () => { - process.env.CORE_PATH_CONFIG = dirSync().name; - - ensureDirSync(`${process.env.CORE_PATH_CONFIG}/mainnet`); - ensureDirSync(`${process.env.CORE_PATH_CONFIG}/devnet`); + ensureDirSync(`${configPath}/mainnet`); + ensureDirSync(`${configPath}/devnet`); prompts.inject(["randomnet", true]); await expect(cmd.discover(configPath)).rejects.toThrow(`The given network "randomnet" is not valid.`); - - delete process.env.CORE_PATH_CONFIG; }); }); diff --git a/packages/core-cli/src/commands/command.ts b/packages/core-cli/src/commands/command.ts index 3558e4f507..36446405ce 100644 --- a/packages/core-cli/src/commands/command.ts +++ b/packages/core-cli/src/commands/command.ts @@ -11,6 +11,7 @@ import { Identifiers, inject, injectable, postConstruct } from "../ioc"; import { Output } from "../output"; import { Config, Environment } from "../services"; import { CommandHelp } from "./command-help"; +import { DiscoverConfig } from "./discover-config"; import { DiscoverNetwork } from "./discover-network"; /** @@ -183,10 +184,15 @@ export abstract class Command { */ public async run(): Promise { try { + await this.detectConfig(); + if (this.requiresNetwork) { await this.detectNetwork(); } + // Check for configuration again after network was chosen + await this.detectConfig(); + if (this.input.hasFlag("token") && this.input.hasFlag("network")) { this.app .rebind(Identifiers.ApplicationPaths) @@ -284,6 +290,17 @@ export abstract class Command { return this.input.hasFlag(name); } + private async detectConfig(): Promise { + const config = await this.app + .resolve(DiscoverConfig) + .discover(this.input.getFlag("token"), this.input.getFlag("network")); + + if (config) { + this.input.setFlag("token", config.token); + this.input.setFlag("network", config.network); + } + } + /** * @private * @returns {Promise} diff --git a/packages/core-cli/src/commands/discover-config.ts b/packages/core-cli/src/commands/discover-config.ts new file mode 100644 index 0000000000..abe1b97b75 --- /dev/null +++ b/packages/core-cli/src/commands/discover-config.ts @@ -0,0 +1,35 @@ +import envPaths from "env-paths"; +import { readJSON } from "fs-extra"; +import { join } from "path"; + +import { injectable } from "../ioc"; + +interface Config { + token: string; + network: string; +} + +/** + * @export + * @class DiscoverNetwork + */ +@injectable() +export class DiscoverConfig { + /** + * @returns {Promise} + * @memberof DiscoverNetwork + * @param token + * @param network + */ + public async discover(token: string = "", network: string = ""): Promise { + try { + return await readJSON(join(process.env.CORE_PATH_CONFIG!, "config.json")); + } catch {} + + try { + return await readJSON(join(envPaths(token, { suffix: "core" }).config, network, "config.json")); + } catch {} + + return undefined; + } +} diff --git a/packages/core-cli/src/commands/discover-network.ts b/packages/core-cli/src/commands/discover-network.ts index 914f549e57..3f7956f192 100644 --- a/packages/core-cli/src/commands/discover-network.ts +++ b/packages/core-cli/src/commands/discover-network.ts @@ -16,10 +16,6 @@ export class DiscoverNetwork { * @memberof DiscoverNetwork */ public async discover(path: string): Promise { - if (process.env.CORE_PATH_CONFIG) { - path = process.env.CORE_PATH_CONFIG; - } - if (!existsSync(path)) { throw new Error(`The [${path}] directory does not exist.`); } diff --git a/packages/core-cli/src/commands/index.ts b/packages/core-cli/src/commands/index.ts index 65d2e27aff..6f2fd27be2 100644 --- a/packages/core-cli/src/commands/index.ts +++ b/packages/core-cli/src/commands/index.ts @@ -1,4 +1,5 @@ export * from "./command-help"; export * from "./command"; export * from "./discover-commands"; +export * from "./discover-config"; export * from "./discover-network"; diff --git a/packages/core/bin/config/devnet/config.json b/packages/core/bin/config/devnet/config.json new file mode 100644 index 0000000000..c9d8413e07 --- /dev/null +++ b/packages/core/bin/config/devnet/config.json @@ -0,0 +1,4 @@ +{ + "token": "ark", + "network": "devnet" +} diff --git a/packages/core/bin/config/mainnet/config.json b/packages/core/bin/config/mainnet/config.json new file mode 100644 index 0000000000..745012fb18 --- /dev/null +++ b/packages/core/bin/config/mainnet/config.json @@ -0,0 +1,4 @@ +{ + "token": "ark", + "network": "mainnet" +} diff --git a/packages/core/bin/config/testnet/config.json b/packages/core/bin/config/testnet/config.json new file mode 100644 index 0000000000..60c9d925dc --- /dev/null +++ b/packages/core/bin/config/testnet/config.json @@ -0,0 +1,4 @@ +{ + "token": "ark", + "network": "testnet" +} diff --git a/packages/core/package.json b/packages/core/package.json index 2efa2db42f..4cda518bdf 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -28,17 +28,17 @@ "debug:forger": "node --inspect-brk yarn ark forger:run", "debug:relay": "node --inspect-brk yarn ark relay:run", "debug:start": "node --inspect-brk yarn ark core:run", - "core:devnet": "cross-env CORE_PATH_CONFIG=./bin/config/devnet yarn ark core:run --network=devnet", - "core:mainnet": "cross-env CORE_PATH_CONFIG=./bin/config/mainnet yarn ark core:run --network=mainnet", - "core:testnet": "cross-env CORE_PATH_CONFIG=./bin/config/testnet yarn ark core:run --env=test --network=testnet", - "relay:devnet": "cross-env CORE_PATH_CONFIG=./bin/config/devnet yarn ark relay:run --network=devnet", - "relay:mainnet": "cross-env CORE_PATH_CONFIG=./bin/config/mainnet yarn ark relay:run --network=mainnet", - "relay:testnet": "cross-env CORE_PATH_CONFIG=./bin/config/testnet yarn ark relay:run --env=test --network=testnet", - "forger:devnet": "cross-env CORE_PATH_CONFIG=./bin/config/devnet yarn ark forger:run --network=devnet", - "forger:mainnet": "cross-env CORE_PATH_CONFIG=./bin/config/mainnet yarn ark forger:run --network=mainnet", - "forger:testnet": "cross-env CORE_PATH_CONFIG=./bin/config/testnet yarn ark forger:run --env=test --network=testnet", - "full:testnet": "cross-env CORE_PATH_CONFIG=./bin/config/testnet yarn ark core:run --networkStart --env=test --network=testnet", - "manager:testnet": "cross-env CORE_PATH_CONFIG=./bin/config/testnet yarn ark manager:run --env=test --network=testnet", + "core:devnet": "cross-env CORE_PATH_CONFIG=./bin/config/devnet yarn ark core:run", + "core:mainnet": "cross-env CORE_PATH_CONFIG=./bin/config/mainnet yarn ark core:run", + "core:testnet": "cross-env CORE_PATH_CONFIG=./bin/config/testnet yarn ark core:run --env=test", + "relay:devnet": "cross-env CORE_PATH_CONFIG=./bin/config/devnet yarn ark relay:run", + "relay:mainnet": "cross-env CORE_PATH_CONFIG=./bin/config/mainnet yarn ark relay:run", + "relay:testnet": "cross-env CORE_PATH_CONFIG=./bin/config/testnet yarn ark relay:run --env=test", + "forger:devnet": "cross-env CORE_PATH_CONFIG=./bin/config/devnet yarn ark forger:run", + "forger:mainnet": "cross-env CORE_PATH_CONFIG=./bin/config/mainnet yarn ark forger:run", + "forger:testnet": "cross-env CORE_PATH_CONFIG=./bin/config/testnet yarn ark forger:run --env=test", + "full:testnet": "cross-env CORE_PATH_CONFIG=./bin/config/testnet yarn ark core:run --networkStart", + "manager:testnet": "cross-env CORE_PATH_CONFIG=./bin/config/testnet yarn ark manager:run --env=test", "prepublishOnly": "yarn build" }, "dependencies": {