diff --git a/packages/cli/src/__tests__/e2e/infra.spec.ts b/packages/cli/src/__tests__/e2e/infra.spec.ts index 6b22a82eab..ced96aa993 100644 --- a/packages/cli/src/__tests__/e2e/infra.spec.ts +++ b/packages/cli/src/__tests__/e2e/infra.spec.ts @@ -199,6 +199,68 @@ describe("e2e tests for infra command", () => { ]); }); + test("Should correctly fetch default & local module", async () => { + await runW3CLI( + ["infra", "up"], + getTestCaseDir(4), + ); + + await waitForPorts([ + { port: 5001, expected: true }, + { port: 8546, expected: true }, + ]); + + await runW3CLI( + ["infra", "down"], + getTestCaseDir(4), + ); + }); + + test("Should correctly open one process for default module because modules flag overwrites it", async () => { + await runW3CLI( + ["infra", "up", "--modules=eth-ens-ipfs"], + getTestCaseDir(4), + ); + + await waitForPorts([ + { port: 5001, expected: true }, + ]); + + await runW3CLI( + ["infra", "down", "--modules=eth-ens-ipfs"], + getTestCaseDir(4), + ); + }); + + test("Should throw because default module declared in manifest is not recognized", async () => { + const { stderr } = await runW3CLI( + ["infra", "up", "--manifest=./web3api.infra.wrong.yaml"], + getTestCaseDir(4), + ); + + expect(stderr).toContain( + `Module random-module not found as default\nDefault Modules available: ` + ); + }); + + test("Should correctly fetch different local modules when they are declared as folder or file", async () => { + await runW3CLI( + ["infra", "up"], + getTestCaseDir(4), + ); + + await waitForPorts([ + { port: 5001, expected: true }, + { port: 8546, expected: true }, + { port: 8547, expected: true }, + ]); + + await runW3CLI( + ["infra", "down"], + getTestCaseDir(4), + ); + }); + test("Tears down environment", async () => { await runW3CLI( ["infra", "up"], diff --git a/packages/cli/src/lib/infra/Infra.ts b/packages/cli/src/lib/infra/Infra.ts index 1d96fc7736..dfc9e3683b 100644 --- a/packages/cli/src/lib/infra/Infra.ts +++ b/packages/cli/src/lib/infra/Infra.ts @@ -8,7 +8,7 @@ import { import { InfraManifest } from "@web3api/core-js"; import path from "path"; -import fs, { readdirSync } from "fs"; +import fs, { lstatSync, readdirSync } from "fs"; import YAML from "js-yaml"; import { copySync } from "fs-extra"; @@ -100,12 +100,10 @@ export class Infra { > { const modulesWithPaths = await this._fetchModules(); - const s = await this._dockerCompose.commands.config({ + return await this._dockerCompose.commands.config({ ...this._defaultDockerOptions, config: modulesWithPaths.map((m) => m.path), }); - - return s; } public async getVars(): Promise { @@ -147,12 +145,20 @@ export class Infra { infraManifest, } = this._config; - const manifestModules = Object.entries(infraManifest?.modules ?? {}).map( - ([name, value]) => ({ + const manifestModules: NamedModule[] = Object.entries( + infraManifest?.modules ?? {} + ).map(([name, value]) => { + if (value === "default") { + return { + name, + path: this._fetchPathForDefaultModule(name), + }; + } + return { name, ...value, - }) - ); + }; + }); if (!modulesToUse || !modulesToUse.length) { return manifestModules; @@ -282,7 +288,7 @@ export class Infra { return this._fetchedModulesData; } - const modules = await this.getFilteredModules(); + const modules = this.getFilteredModules(); if (!modules.length) { throw new Error("No modules to fetch"); @@ -330,10 +336,12 @@ export class Infra { const basePath = path.join(this.getCacheModulesPath(), "local"); for (const module of modules) { - const modulePath = path.join(basePath, module.name); - + const isFile = lstatSync(module.path).isFile(); + const modulePath = path.join( + basePath, + isFile ? module.path : module.name + ); copySync(module.path, modulePath); - const composePath = this.tryResolveComposeFile( modulePath, this._defaultModuleComposePaths @@ -352,6 +360,21 @@ export class Infra { return Object.prototype.hasOwnProperty.call(object, "path"); } + private _fetchPathForDefaultModule(module: string): string { + const defaultModules = readdirSync(this._config.defaultInfraModulesPath); + const defaultModulePath = defaultModules.find( + (defaultModules) => defaultModules === module + ); + if (!defaultModulePath) { + throw new Error( + `Module ${module} not found as default\nDefault Modules available: ${defaultModules + .map((m) => `\n- ${m}`) + .join("")}` + ); + } + return path.join(this._config.defaultInfraModulesPath, defaultModulePath); + } + private tryResolveComposeFile( moduleDir: string, pathsToTry: string[], @@ -363,7 +386,9 @@ export class Infra { ); } - const pathToTry = path.join(moduleDir, pathsToTry[0]); + const pathToTry = lstatSync(moduleDir).isFile() + ? moduleDir + : path.join(moduleDir, pathsToTry[0]); if (fs.existsSync(pathToTry)) { return pathToTry; diff --git a/packages/js/core/src/manifest/formats/web3api.infra/0.0.1-prealpha.2.ts b/packages/js/core/src/manifest/formats/web3api.infra/0.0.1-prealpha.2.ts new file mode 100644 index 0000000000..46c58ba19c --- /dev/null +++ b/packages/js/core/src/manifest/formats/web3api.infra/0.0.1-prealpha.2.ts @@ -0,0 +1,38 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +/* tslint:disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export type DefaultModule = "default"; + +export interface InfraManifest { + format: "0.0.1-prealpha.2"; + dockerCompose?: string; + env?: { + /** + * This interface was referenced by `undefined`'s JSON-Schema definition + * via the `patternProperty` "^.*$". + */ + [k: string]: string | number; + }; + modules: { + /** + * This interface was referenced by `undefined`'s JSON-Schema definition + * via the `patternProperty` "^.*$". + */ + [k: string]: RemoteModule | LocalModule | DefaultModule; + }; + __type: "InfraManifest"; +} +export interface RemoteModule { + package: string; + registry: string; + version: string; + dockerComposePath?: string; +} +export interface LocalModule { + path: string; +} diff --git a/packages/js/core/src/manifest/formats/web3api.infra/index.ts b/packages/js/core/src/manifest/formats/web3api.infra/index.ts index 572ea35a01..c9eecf54ed 100644 --- a/packages/js/core/src/manifest/formats/web3api.infra/index.ts +++ b/packages/js/core/src/manifest/formats/web3api.infra/index.ts @@ -8,21 +8,27 @@ import { InfraManifest as InfraManifest0_0_1_prealpha_1 } from "./0.0.1-prealpha.1"; +import { + InfraManifest as InfraManifest0_0_1_prealpha_2 +} from "./0.0.1-prealpha.2"; export { InfraManifest0_0_1_prealpha_1, + InfraManifest0_0_1_prealpha_2, }; export enum InfraManifestFormats { "0.0.1-prealpha.1" = "0.0.1-prealpha.1", + "0.0.1-prealpha.2" = "0.0.1-prealpha.2", } export type AnyInfraManifest = | InfraManifest0_0_1_prealpha_1 + | InfraManifest0_0_1_prealpha_2 -export type InfraManifest = InfraManifest0_0_1_prealpha_1; +export type InfraManifest = InfraManifest0_0_1_prealpha_2; -export const latestInfraManifestFormat = InfraManifestFormats["0.0.1-prealpha.1"] +export const latestInfraManifestFormat = InfraManifestFormats["0.0.1-prealpha.2"] export { migrateInfraManifest } from "./migrate"; diff --git a/packages/js/core/src/manifest/formats/web3api.infra/migrate.ts b/packages/js/core/src/manifest/formats/web3api.infra/migrate.ts index 4df5755244..083e038bcf 100644 --- a/packages/js/core/src/manifest/formats/web3api.infra/migrate.ts +++ b/packages/js/core/src/manifest/formats/web3api.infra/migrate.ts @@ -11,6 +11,9 @@ import { latestInfraManifestFormat } from "."; +import { + migrate as migrate_0_0_1_prealpha_1_to_0_0_1_prealpha_2 +} from "./migrators/0.0.1-prealpha.1_to_0.0.1-prealpha.2"; import { Tracer } from "@web3api/tracing-js"; @@ -19,6 +22,7 @@ type Migrator = { }; export const migrators: Migrator = { + "0.0.1-prealpha.1": migrate_0_0_1_prealpha_1_to_0_0_1_prealpha_2, }; export const migrateInfraManifest = Tracer.traceFunc( @@ -34,6 +38,13 @@ export const migrateInfraManifest = Tracer.traceFunc( throw new Error(`Unrecognized InfraManifestFormat "${manifest.format}"`); } - throw new Error(`This should never happen, InfraManifest migrators is empty. from: ${from}, to: ${to}`); + const migrator = migrators[from]; + if (!migrator) { + throw new Error( + `Migrator from InfraManifestFormat "${from}" to "${to}" is not available` + ); + } + + return migrator(manifest); } ); diff --git a/packages/js/core/src/manifest/formats/web3api.infra/migrators/0.0.1-prealpha.1_to_0.0.1-prealpha.2.ts b/packages/js/core/src/manifest/formats/web3api.infra/migrators/0.0.1-prealpha.1_to_0.0.1-prealpha.2.ts new file mode 100644 index 0000000000..a0732788eb --- /dev/null +++ b/packages/js/core/src/manifest/formats/web3api.infra/migrators/0.0.1-prealpha.1_to_0.0.1-prealpha.2.ts @@ -0,0 +1,11 @@ +/* eslint-disable @typescript-eslint/naming-convention */ + +import { InfraManifest as OldManifest } from "../0.0.1-prealpha.1"; +import { InfraManifest as NewManifest } from "../0.0.1-prealpha.2"; + +export function migrate(old: OldManifest): NewManifest { + return { + ...old, + format: "0.0.1-prealpha.2", + }; +} diff --git a/packages/js/core/src/manifest/formats/web3api.infra/validate.ts b/packages/js/core/src/manifest/formats/web3api.infra/validate.ts index 8dd98b807c..57bf1acf04 100644 --- a/packages/js/core/src/manifest/formats/web3api.infra/validate.ts +++ b/packages/js/core/src/manifest/formats/web3api.infra/validate.ts @@ -10,6 +10,7 @@ import { } from "."; import schema_0_0_1_prealpha_1 from "@web3api/manifest-schemas/formats/web3api.infra/0.0.1-prealpha.1.json"; +import schema_0_0_1_prealpha_2 from "@web3api/manifest-schemas/formats/web3api.infra/0.0.1-prealpha.2.json"; import { Tracer } from "@web3api/tracing-js" import { @@ -25,6 +26,7 @@ type InfraManifestSchemas = { const schemas: InfraManifestSchemas = { "0.0.1-prealpha.1": schema_0_0_1_prealpha_1, + "0.0.1-prealpha.2": schema_0_0_1_prealpha_2, }; const validator = new Validator(); diff --git a/packages/manifest-schemas/formats/web3api.infra/0.0.1-prealpha.2.json b/packages/manifest-schemas/formats/web3api.infra/0.0.1-prealpha.2.json new file mode 100644 index 0000000000..eed51a8000 --- /dev/null +++ b/packages/manifest-schemas/formats/web3api.infra/0.0.1-prealpha.2.json @@ -0,0 +1,69 @@ +{ + "id": "InfraManifest", + "type": "object", + "additionalProperties": false, + "required": ["format", "modules"], + "properties": { + "format": { + "type": "string", + "const": "0.0.1-prealpha.2" + }, + "dockerCompose": { + "type": "string" + }, + "env": { + "patternProperties": { + "^.*$": { + "type": ["string", "number"] + } + }, + "additionalProperties": false + }, + "modules": { + "patternProperties": { + "^.*$": { + "oneOf": [ + {"$ref": "#/definitions/remoteModule"}, + {"$ref": "#/definitions/localModule"}, + {"$ref": "#/definitions/defaultModule"} + ] + } + } + } + }, + "definitions": { + "remoteModule": { + "type": "object", + "additionalProperties": false, + "properties": { + "package": { + "type": "string" + }, + "registry": { + "type": "string" + }, + "version": { + "type": "string" + }, + "dockerComposePath": { + "type": "string" + } + }, + "required": ["package", "version", "registry"] + }, + "localModule": { + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "string" + } + }, + "required": ["path"] + }, + "defaultModule": { + "type": "string", + "const": "default" + } + } +} diff --git a/packages/test-cases/cases/cli/infra/005-sanity-default-module/mainnet-fork/docker-compose.yaml b/packages/test-cases/cases/cli/infra/005-sanity-default-module/mainnet-fork/docker-compose.yaml new file mode 100644 index 0000000000..f6a9218350 --- /dev/null +++ b/packages/test-cases/cases/cli/infra/005-sanity-default-module/mainnet-fork/docker-compose.yaml @@ -0,0 +1,7 @@ +version: '3' +services: + mainnet-fork: + image: 'trufflesuite/ganache-cli:v6.12.2' + ports: + - '8546:8545' + command: -l 8000000 --deterministic --hostname=0.0.0.0 --chainId 1 --fork https://mainnet.infura.io/v3/d119148113c047ca90f0311ed729c466 \ No newline at end of file diff --git a/packages/test-cases/cases/cli/infra/005-sanity-default-module/ropsten-fork/docker-compose.yml b/packages/test-cases/cases/cli/infra/005-sanity-default-module/ropsten-fork/docker-compose.yml new file mode 100644 index 0000000000..fa7abd1b03 --- /dev/null +++ b/packages/test-cases/cases/cli/infra/005-sanity-default-module/ropsten-fork/docker-compose.yml @@ -0,0 +1,7 @@ +version: '3' +services: + mainnet-fork: + image: 'trufflesuite/ganache-cli:v6.12.2' + ports: + - '8547:8545' + command: -l 8000000 --deterministic --hostname=0.0.0.0 --chainId 3 --fork https://ropsten.infura.io/v3/d119148113c047ca90f0311ed729c466 \ No newline at end of file diff --git a/packages/test-cases/cases/cli/infra/005-sanity-default-module/web3api.infra.wrong.yaml b/packages/test-cases/cases/cli/infra/005-sanity-default-module/web3api.infra.wrong.yaml new file mode 100644 index 0000000000..0058338696 --- /dev/null +++ b/packages/test-cases/cases/cli/infra/005-sanity-default-module/web3api.infra.wrong.yaml @@ -0,0 +1,3 @@ +format: 0.0.1-prealpha.2 +modules: + random-module: default \ No newline at end of file diff --git a/packages/test-cases/cases/cli/infra/005-sanity-default-module/web3api.infra.yaml b/packages/test-cases/cases/cli/infra/005-sanity-default-module/web3api.infra.yaml new file mode 100644 index 0000000000..43f428e16b --- /dev/null +++ b/packages/test-cases/cases/cli/infra/005-sanity-default-module/web3api.infra.yaml @@ -0,0 +1,7 @@ +format: 0.0.1-prealpha.2 +modules: + eth-ens-ipfs: default + mainnet-fork: + path: ./mainnet-fork/docker-compose.yaml + ropsten-fork: + path: ./ropsten-fork \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index fc22036a12..848f91b2cf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5792,9 +5792,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001349: - version "1.0.30001351" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001351.tgz#fd38e07c0ab75921169bac5076b0e0c5f58f9b50" - integrity sha512-u+Ll+RDaiQEproTQjZLjZwyfNgNezA1fERMT7/54npcz+PkbVJUAHXMUz4bkXQYRPWrcFNO0Fbi1mwjfXg6N5g== + version "1.0.30001352" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001352.tgz#cc6f5da3f983979ad1e2cdbae0505dccaa7c6a12" + integrity sha512-GUgH8w6YergqPQDGWhJGt8GDRnY0L/iJVQcU3eJ46GYf52R8tk0Wxp0PymuFVZboJYXGiCqwozAYZNRjVj6IcA== capture-exit@^2.0.0: version "2.0.0" @@ -17024,7 +17024,7 @@ stylehacks@^4.0.0: supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g== supports-color@^5.3.0: version "5.5.0"