Skip to content

Commit

Permalink
wrapped yargs
Browse files Browse the repository at this point in the history
  • Loading branch information
timbrinded committed Nov 22, 2023
1 parent 90548c2 commit 3ef4cb1
Show file tree
Hide file tree
Showing 12 changed files with 797 additions and 150 deletions.
5 changes: 2 additions & 3 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,8 @@
"node-fetch": "^3.3.2",
"semver": "^7.5.4",
"viem": "^1.19.3",
"vitest": "1.0.0-beta.4",
"vitest": "1.0.0-beta.5",
"web3": "4.2.2",
"why-is-node-running": "^2.2.2",
"ws": "^8.14.2",
"yaml": "^2.3.4",
"yargs": "^17.7.2"
Expand All @@ -107,7 +106,7 @@
"prettier": "^3.1.0",
"tsup": "^7.2.0",
"tsx": "^4.1.2",
"typescript": "^5.2.2"
"typescript": "^5.3.2"
},
"publishConfig": {
"access": "public"
Expand Down
143 changes: 85 additions & 58 deletions packages/cli/src/cmds/entrypoint.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import "../internal/logging";
import log from "why-is-node-running";
import "@moonbeam-network/api-augment";
import yargs from "yargs";
import fs from "fs";
Expand All @@ -9,6 +8,7 @@ import { generateConfig } from "../internal/cmdFunctions/initialisation";
import { fetchArtifact } from "../internal/cmdFunctions/fetchArtifact";
import dotenv from "dotenv";
import { Effect, pipe } from "effect";
import * as Err from "../errors";
import { main } from "./main";
import { runNetworkCmdEffect } from "./runNetwork";
dotenv.config();
Expand All @@ -25,8 +25,10 @@ const findExistingConfig = (files: string[]): string | undefined => {

const defaultConfigFile = findExistingConfig(defaultConfigFiles) || "./moonwall.config.json";

const parseConfigFile = Effect.sync(() =>
const parseArgs = Effect.sync(() =>
yargs(hideBin(process.argv))
.usage("Usage: $0")
.version("2.0.0")
.options({
configFile: {
type: "string",
Expand All @@ -44,32 +46,15 @@ const setEnvVar = (key: string, value: string) =>
});

const setupConfigFileEnv = pipe(
parseConfigFile,
parseArgs,
Effect.flatMap((parsed) => setEnvVar("MOON_CONFIG_PATH", parsed.configFile))
);

// TODO: REMOVE THIS HACK ONCE YARGS REPLACED
let failedTests: number | false;

const cliStart = Effect.try(() => {
const argv = yargs(hideBin(process.argv))
.usage("Usage: $0")
.version("2.0.0")
.options({
configFile: {
type: "string",
alias: "c",
description: "path to MoonwallConfig file",
default: defaultConfigFile,
},
})
.parseSync();

if (!argv._.length) {
return main();
}
const processArgs = (args: any): { command: string; args?: object } => {
let commandChosen: string;
const argsObject: object = {};

return yargs(hideBin(process.argv))
yargs(hideBin(args))
.usage("Usage: $0")
.version("2.0.0")
.options({
Expand All @@ -81,15 +66,13 @@ const cliStart = Effect.try(() => {
},
})
.command(`init`, "Run tests for a given Environment", async () => {
const effect = Effect.tryPromise(() => generateConfig());

await Effect.runPromise(effect);
commandChosen = "init";
})
.command(
`download <bin> [ver] [path]`,
"Download x86 artifact from GitHub",
(yargs) => {
return yargs
(yargs) =>
yargs
.positional("bin", {
describe: "Name of artifact to download\n[ moonbeam | polkadot | *-runtime ]",
})
Expand All @@ -112,17 +95,15 @@ const cliStart = Effect.try(() => {
describe: "Rename downloaded file to this name",
alias: "o",
type: "string",
});
},
}),
async (argv) => {
const effect = Effect.tryPromise(() => fetchArtifact(argv));
await Effect.runPromise(effect);
commandChosen = "download";
argsObject["argv"] = argv;
}
)
.command(
`test <envName> [GrepTest]`,
"Run tests for a given Environment",

(yargs) =>
yargs
.positional("envName", {
Expand All @@ -133,27 +114,11 @@ const cliStart = Effect.try(() => {
type: "string",
description: "Pattern to grep test ID/Description to run",
}),

async ({ envName, GrepTest }) => {
process.env.MOON_RUN_SCRIPTS = "true";
const effect = testEffect(envName, { testNamePattern: GrepTest }).pipe(
Effect.catchTag("TestsFailedError", (error) => {
failedTests = error.fails;
return Effect.succeed(
console.log(`❌ ${error.fails} test file${error.fails !== 1 ? "s" : ""} failed`)
);
})
);

await Effect.runPromise(effect);

if (failedTests) {
process.exitCode = 1;
}
const timeout = 5;
setTimeout(function () {
log();
}, timeout * 1000);
argsObject["envName"] = envName;
argsObject["GrepTest"] = GrepTest;
commandChosen = "test";
}
)
.command(
Expand All @@ -170,22 +135,84 @@ const cliStart = Effect.try(() => {
}),
async (argv) => {
process.env.MOON_RUN_SCRIPTS = "true";
await Effect.runPromiseExit(runNetworkCmdEffect(argv as any));
argsObject["argv"] = argv;
commandChosen = "run";
}
)
.help("h")
.alias("h", "help")
.parse();

return { command: commandChosen, args: argsObject };
};

const cliStart = Effect.gen(function* (_) {
let commandChosen: string;
let args: object = {};
let failedTests: number | false;

const argv = yield* _(parseArgs);

if (!argv._.length) {
commandChosen = "mainmenu";
} else {
const processedArgs = yield* _(Effect.sync(() => processArgs(process.argv)));
commandChosen = processedArgs.command;
args = processedArgs.args;
}

switch (commandChosen) {
case "mainmenu":
yield* _(Effect.promise(main));
break;

case "init":
yield* _(Effect.tryPromise(() => generateConfig()));
break;

case "download":
yield* _(Effect.tryPromise(() => fetchArtifact(args["argv"])));
break;

case "test": {
yield* _(
testEffect(args["envName"], { testNamePattern: args["GrepTest"] }).pipe(
Effect.catchTag("TestsFailedError", (error) => {
failedTests = error.fails;
return Effect.succeed(
console.log(`❌ ${error.fails} test file${error.fails !== 1 ? "s" : ""} failed`)
);
})
)
);

if (failedTests) {
process.exitCode = 1;
}

break;
}

case "run":
yield* _(runNetworkCmdEffect(args["argv"]));
break;

default:
yield* _(new Err.InvalidCommandError({ command: commandChosen }));
break;
}
});

const cli = pipe(
const program = pipe(
setupConfigFileEnv,
Effect.flatMap(() => cliStart)
Effect.flatMap(() => cliStart),
Effect.uninterruptible,
Effect.disconnect
);

Effect.runPromise(cli)
Effect.runPromise(program)
.then(() => {
console.log("🏁 Moonwall Test Run finished");
console.log("🏁 Moonwall Process finished");
process.exit();
})
.catch(console.error);
2 changes: 1 addition & 1 deletion packages/cli/src/cmds/runNetwork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const runNetworkCmdEffect = (args) =>
Effect.filterOrFail(
Effect.sync(() => globalConfig.environments.find(({ name }) => name === args.envName)),
(env) => !!env,
() => new Err.EnvironmentMissingError(args.envName)
() => new Err.EnvironmentMissingError({ env: args.envName })
)
);

Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/cmds/runTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const testEffect = (envName: string, additionalArgs?: object) => {
Effect.filterOrFail(
Effect.sync(() => globalConfig.environments.find(({ name }) => name === envName)),
(env) => !!env,
() => new Err.EnvironmentMissingError(envName)
() => new Err.EnvironmentMissingError({ env: envName })
)
);

Expand Down Expand Up @@ -54,7 +54,7 @@ export const testEffect = (envName: string, additionalArgs?: object) => {
if (failed.length === 0) {
yield* _(Effect.succeed(() => console.log("✅ All tests passed")));
} else {
yield* _(Effect.fail(new Err.TestsFailedError(failed.length)));
yield* _(new Err.TestsFailedError({ fails: failed.length }));
}
});
};
Expand Down
9 changes: 5 additions & 4 deletions packages/cli/src/errors/configErrors.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
export class EnvironmentMissingError {
readonly _tag = "EnvironmentMissingError";
constructor(readonly env: string) {}
}
import { Data } from "effect";

export class EnvironmentMissingError extends Data.TaggedError("EnvironmentMissingError")<{
env: string;
}> {}

export class ConfigError {
readonly _tag = "ConfigError";
Expand Down
9 changes: 5 additions & 4 deletions packages/cli/src/errors/generalErrors.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export class TestsFailedError {
readonly _tag = "TestsFailedError";
constructor(readonly fails?: number) {}
}
import { Data } from "effect";

export class TestsFailedError extends Data.TaggedError("TestsFailedError")<{ fails?: number }> {}

export class CommonCheckError {
readonly _tag = "CommonCheckError";
Expand All @@ -10,3 +9,5 @@ export class CommonCheckError {
export class RunNetworkError {
readonly _tag = "RunNetworkError";
}

export class InvalidCommandError extends Data.TaggedError("InvalidCommand")<{ command: string }> {}
2 changes: 1 addition & 1 deletion packages/cli/src/internal/localNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ const webSocketProbe = (port: number) => {

const findPortsByPidEffect = (pid: number, timeout: number = 10000) =>
Effect.gen(function* (_) {
const end = Date.now() + timeout;
const end = yield* _(Effect.sync(() => Date.now() + timeout));

for (;;) {
const command = `lsof -i -n -P | grep LISTEN | grep ${pid} || true`;
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/lib/runnerContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export function describeSuite<T extends FoundationType>({
const globalConfig = yield* _(
Effect.tryPromise({
try: () => importAsyncConfig(),
catch: () => Err.ConfigError,
catch: () => new Err.ConfigError("Could not load config before running test"),
})
);

Expand Down
2 changes: 1 addition & 1 deletion packages/util/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
"rlp": "^3.0.0",
"semver": "^7.5.4",
"viem": "^1.19.3",
"vitest": "1.0.0-beta.4",
"vitest": "1.0.0-beta.5",
"web3": "4.2.2",
"ws": "^8.14.2",
"yaml": "^2.3.4",
Expand Down
Loading

0 comments on commit 3ef4cb1

Please sign in to comment.