From d171f919769be5c5c5abbe49d6ffa0d440660264 Mon Sep 17 00:00:00 2001 From: Pileks Date: Thu, 24 Nov 2022 15:16:17 +0100 Subject: [PATCH 1/4] CLI - Add --wrapper-envs option to build, codegen, docgen and test commands --- packages/cli/lang/en.json | 2 + packages/cli/lang/es.json | 2 + packages/cli/src/__tests__/e2e/build.spec.ts | 2 + .../cli/src/__tests__/e2e/codegen.spec.ts | 2 + packages/cli/src/__tests__/e2e/docgen.spec.ts | 2 + packages/cli/src/__tests__/e2e/test.spec.ts | 2 + .../option-parsers/option-parsers.spec.ts | 51 +++++++++++++++++++ .../option-parsers/samples/wrapper-env.json | 11 ++++ packages/cli/src/commands/build.ts | 14 ++++- packages/cli/src/commands/codegen.ts | 14 ++++- packages/cli/src/commands/docgen.ts | 16 +++++- packages/cli/src/commands/test.ts | 13 +++++ packages/cli/src/lib/option-parsers/index.ts | 1 + .../src/lib/option-parsers/wrapper-envs.ts | 28 ++++++++++ packages/js/plugins/ethereum/src/index.ts | 11 ++++ 15 files changed, 167 insertions(+), 4 deletions(-) create mode 100644 packages/cli/src/__tests__/unit/option-parsers/option-parsers.spec.ts create mode 100644 packages/cli/src/__tests__/unit/option-parsers/samples/wrapper-env.json create mode 100644 packages/cli/src/lib/option-parsers/wrapper-envs.ts diff --git a/packages/cli/lang/en.json b/packages/cli/lang/en.json index 825cb3db03..707d6e0b75 100644 --- a/packages/cli/lang/en.json +++ b/packages/cli/lang/en.json @@ -1,6 +1,8 @@ { "commands_common_options_configPath": "config-path", + "commands_common_options_wrapperEnvsPath": "envs-path", "commands_common_options_config": "Add custom configuration to the PolywrapClient", + "commands_common_options_wrapperEnvs": "Path to a JSON file containing wrapper envs", "commands_common_options_verbose": "Verbose output (default: false)", "commands_common_options_quiet": "Suppress output (default: false)", "commands_build_description": "Build Polywrap Projects (type: interface, wasm)", diff --git a/packages/cli/lang/es.json b/packages/cli/lang/es.json index 825cb3db03..707d6e0b75 100644 --- a/packages/cli/lang/es.json +++ b/packages/cli/lang/es.json @@ -1,6 +1,8 @@ { "commands_common_options_configPath": "config-path", + "commands_common_options_wrapperEnvsPath": "envs-path", "commands_common_options_config": "Add custom configuration to the PolywrapClient", + "commands_common_options_wrapperEnvs": "Path to a JSON file containing wrapper envs", "commands_common_options_verbose": "Verbose output (default: false)", "commands_common_options_quiet": "Suppress output (default: false)", "commands_build_description": "Build Polywrap Projects (type: interface, wasm)", diff --git a/packages/cli/src/__tests__/e2e/build.spec.ts b/packages/cli/src/__tests__/e2e/build.spec.ts index 3200b3f541..b7d5090b1c 100644 --- a/packages/cli/src/__tests__/e2e/build.spec.ts +++ b/packages/cli/src/__tests__/e2e/build.spec.ts @@ -17,6 +17,8 @@ Options: (default: ./build) -c, --client-config Add custom configuration to the PolywrapClient + --wrapper-envs Path to a JSON file containing wrapper + envs -n, --no-codegen Skip code generation -s, --strategy Strategy to use for building the wrapper (default: "vm") diff --git a/packages/cli/src/__tests__/e2e/codegen.spec.ts b/packages/cli/src/__tests__/e2e/codegen.spec.ts index 907ef8adb6..5380ca3710 100644 --- a/packages/cli/src/__tests__/e2e/codegen.spec.ts +++ b/packages/cli/src/__tests__/e2e/codegen.spec.ts @@ -22,6 +22,8 @@ Options: (JavaScript | TypeScript) -c, --client-config Add custom configuration to the PolywrapClient + --wrapper-envs Path to a JSON file containing wrapper + envs -v, --verbose Verbose output (default: false) -q, --quiet Suppress output (default: false) -l, --log-file [path] Log file to save console output to diff --git a/packages/cli/src/__tests__/e2e/docgen.spec.ts b/packages/cli/src/__tests__/e2e/docgen.spec.ts index 833ec37b14..3aef283788 100644 --- a/packages/cli/src/__tests__/e2e/docgen.spec.ts +++ b/packages/cli/src/__tests__/e2e/docgen.spec.ts @@ -26,6 +26,8 @@ Options: (default: ./docs) -c, --client-config Add custom configuration to the PolywrapClient + --wrapper-envs Path to a JSON file containing wrapper + envs -i, --imports Also generate docs for dependencies -v, --verbose Verbose output (default: false) -q, --quiet Suppress output (default: false) diff --git a/packages/cli/src/__tests__/e2e/test.spec.ts b/packages/cli/src/__tests__/e2e/test.spec.ts index 58404d54bc..8218b67916 100644 --- a/packages/cli/src/__tests__/e2e/test.spec.ts +++ b/packages/cli/src/__tests__/e2e/test.spec.ts @@ -19,6 +19,8 @@ Options: polywrap.test.yml) -c, --client-config Add custom configuration to the PolywrapClient + --wrapper-envs Path to a JSON file containing wrapper + envs -o, --output-file Output file path for the test result -j, --jobs Specify ids of jobs that you want to run diff --git a/packages/cli/src/__tests__/unit/option-parsers/option-parsers.spec.ts b/packages/cli/src/__tests__/unit/option-parsers/option-parsers.spec.ts new file mode 100644 index 0000000000..9c5c1f6752 --- /dev/null +++ b/packages/cli/src/__tests__/unit/option-parsers/option-parsers.spec.ts @@ -0,0 +1,51 @@ +import { Uri } from "@polywrap/core-js"; +import path from "path"; +import { parseWrapperEnvsOption } from "../../../lib"; + +describe("unit tests for option-parsers", () => { + describe("wrapper-envs", () => { + it("Should return undefined when no filename is provided", async () => { + const envs = await parseWrapperEnvsOption(undefined); + + expect(envs).toBeUndefined(); + }); + + it("Should throw for a nonexistent wrapper-env file", async () => { + const nonExistentFilePath = path.join( + __dirname, + "./samples/nonexistent.json" + ); + + await expect(async () => { + await parseWrapperEnvsOption(nonExistentFilePath); + }).rejects.toThrow(); + }); + + it("Should return envs for a valid json file", async () => { + const wrapperEnvsFilePath = path.join( + __dirname, + "./samples/wrapper-env.json" + ); + + const envs = await parseWrapperEnvsOption(wrapperEnvsFilePath); + + expect(envs).toEqual([ + { + uri: Uri.from("wrap://ens/hello-world.polywrap.eth"), + env: { + foo: "bar", + }, + }, + { + uri: Uri.from("ens/ethereum.polywrap.eth"), + env: { + connection: { + node: "https://mainnet.infura.io/v3/some_api_key", + networkNameOrChainId: "mainnet", + }, + }, + }, + ]); + }); + }); +}); diff --git a/packages/cli/src/__tests__/unit/option-parsers/samples/wrapper-env.json b/packages/cli/src/__tests__/unit/option-parsers/samples/wrapper-env.json new file mode 100644 index 0000000000..bcae874957 --- /dev/null +++ b/packages/cli/src/__tests__/unit/option-parsers/samples/wrapper-env.json @@ -0,0 +1,11 @@ +{ + "ens/hello-world.polywrap.eth": { + "foo": "bar" + }, + "ens/ethereum.polywrap.eth": { + "connection": { + "node": "https://mainnet.infura.io/v3/some_api_key", + "networkNameOrChainId": "mainnet" + } + } +} diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index 6cbecdce4e..c08245b58f 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -13,6 +13,7 @@ import { parseClientConfigOption, parseManifestFileOption, parseLogFileOption, + parseWrapperEnvsOption } from "../lib"; import { CodeGenerator } from "../lib/codegen"; import { @@ -25,7 +26,7 @@ import { import path from "path"; import readline from "readline"; -import { PolywrapClient } from "@polywrap/client-js"; +import { Env, PolywrapClient } from "@polywrap/client-js"; import { PolywrapManifest } from "@polywrap/polywrap-manifest-types-js"; import { IClientConfigBuilder } from "@polywrap/client-config-builder-js"; @@ -39,6 +40,7 @@ type BuildCommandOptions = { manifestFile: string; outputDir: string; configBuilder: IClientConfigBuilder; + wrapperEnvs: Env[]; codegen: boolean; // defaults to true watch?: boolean; strategy: SupportedStrategies; @@ -69,6 +71,10 @@ export const build: Command = { `-c, --client-config <${intlMsg.commands_common_options_configPath()}>`, `${intlMsg.commands_common_options_config()}` ) + .option( + `--wrapper-envs <${intlMsg.commands_common_options_wrapperEnvsPath()}>`, + `${intlMsg.commands_common_options_wrapperEnvs()}` + ) .option(`-n, --no-codegen`, `${intlMsg.commands_build_options_n()}`) .option( `-s, --strategy <${strategyStr}>`, @@ -90,6 +96,7 @@ export const build: Command = { defaultPolywrapManifest ), configBuilder: await parseClientConfigOption(options.clientConfig), + wrapperEnvs: await parseWrapperEnvsOption(options.wrapperEnvs), outputDir: parseDirOption(options.outputDir, defaultOutputDir), strategy: options.strategy, logFile: parseLogFileOption(options.logFile), @@ -139,6 +146,7 @@ async function run(options: BuildCommandOptions) { manifestFile, outputDir, configBuilder, + wrapperEnvs, strategy, codegen, verbose, @@ -147,6 +155,10 @@ async function run(options: BuildCommandOptions) { } = options; const logger = createLogger({ verbose, quiet, logFile }); + if (wrapperEnvs) { + configBuilder.addEnvs(wrapperEnvs); + } + // Get Client const client = new PolywrapClient(configBuilder.buildCoreConfig(), { noDefaults: true, diff --git a/packages/cli/src/commands/codegen.ts b/packages/cli/src/commands/codegen.ts index 522bd01c1f..22f1b24580 100644 --- a/packages/cli/src/commands/codegen.ts +++ b/packages/cli/src/commands/codegen.ts @@ -15,10 +15,11 @@ import { defaultProjectManifestFiles, defaultPolywrapManifest, parseLogFileOption, + parseWrapperEnvsOption, } from "../lib"; import { ScriptCodegenerator } from "../lib/codegen/ScriptCodeGenerator"; -import { PolywrapClient } from "@polywrap/client-js"; +import { Env, PolywrapClient } from "@polywrap/client-js"; import path from "path"; import fs from "fs"; import { IClientConfigBuilder } from "@polywrap/client-config-builder-js"; @@ -35,6 +36,7 @@ type CodegenCommandOptions = { publishDir: string; script?: string; configBuilder: IClientConfigBuilder; + wrapperEnvs: Env[]; verbose?: boolean; quiet?: boolean; logFile?: string; @@ -72,6 +74,10 @@ export const codegen: Command = { `-c, --client-config <${intlMsg.commands_common_options_configPath()}>`, `${intlMsg.commands_common_options_config()}` ) + .option( + `--wrapper-envs <${intlMsg.commands_common_options_wrapperEnvsPath()}>`, + `${intlMsg.commands_common_options_wrapperEnvs()}` + ) .option("-v, --verbose", intlMsg.commands_common_options_verbose()) .option("-q, --quiet", intlMsg.commands_common_options_quiet()) .option( @@ -82,6 +88,7 @@ export const codegen: Command = { await run({ ...options, configBuilder: await parseClientConfigOption(options.clientConfig), + wrapperEnvs: await parseWrapperEnvsOption(options.wrapperEnvs), codegenDir: parseDirOption(options.codegenDir, defaultCodegenDir), script: parseCodegenScriptOption(options.script), manifestFile: parseManifestFileOption( @@ -101,6 +108,7 @@ async function run(options: CodegenCommandOptions) { codegenDir, script, configBuilder, + wrapperEnvs, publishDir, verbose, quiet, @@ -108,6 +116,10 @@ async function run(options: CodegenCommandOptions) { } = options; const logger = createLogger({ verbose, quiet, logFile }); + if (wrapperEnvs) { + configBuilder.addEnvs(wrapperEnvs); + } + // Get Client const client = new PolywrapClient(configBuilder.buildCoreConfig(), { noDefaults: true, diff --git a/packages/cli/src/commands/docgen.ts b/packages/cli/src/commands/docgen.ts index a4f4d8565e..ae3f4fed77 100644 --- a/packages/cli/src/commands/docgen.ts +++ b/packages/cli/src/commands/docgen.ts @@ -9,6 +9,7 @@ import { defaultProjectManifestFiles, getProjectFromManifest, parseLogFileOption, + parseWrapperEnvsOption, } from "../lib"; import { Command, Program } from "./types"; import { createLogger } from "./utils/createLogger"; @@ -17,7 +18,7 @@ import { scriptPath as jsdocScriptPath } from "../lib/docgen/jsdoc"; import { scriptPath as schemaScriptPath } from "../lib/docgen/schema"; import { ScriptCodegenerator } from "../lib/codegen/ScriptCodeGenerator"; -import { PolywrapClient } from "@polywrap/client-js"; +import { Env, PolywrapClient } from "@polywrap/client-js"; import chalk from "chalk"; import { Argument } from "commander"; import { IClientConfigBuilder } from "@polywrap/client-config-builder-js"; @@ -37,6 +38,7 @@ type DocgenCommandOptions = { manifestFile: string; docgenDir: string; configBuilder: IClientConfigBuilder; + wrapperEnvs: Env[]; imports: boolean; verbose?: boolean; quiet?: boolean; @@ -93,6 +95,10 @@ export const docgen: Command = { `-c, --client-config <${intlMsg.commands_common_options_configPath()}>`, `${intlMsg.commands_common_options_config()}` ) + .option( + `--wrapper-envs <${intlMsg.commands_common_options_wrapperEnvsPath()}>`, + `${intlMsg.commands_common_options_wrapperEnvs()}` + ) .option(`-i, --imports`, `${intlMsg.commands_docgen_options_i()}`) .option("-v, --verbose", intlMsg.commands_common_options_verbose()) .option("-q, --quiet", intlMsg.commands_common_options_quiet()) @@ -109,6 +115,7 @@ export const docgen: Command = { ), docgenDir: parseDirOption(options.docgenDir, defaultDocgenDir), configBuilder: await parseClientConfigOption(options.clientConfig), + wrapperEnvs: await parseWrapperEnvsOption(options.wrapperEnvs), logFile: parseLogFileOption(options.logFile), }); }); @@ -120,13 +127,18 @@ async function run(command: DocType, options: DocgenCommandOptions) { manifestFile, docgenDir, configBuilder, + wrapperEnvs, imports, verbose, quiet, logFile, } = options; const logger = createLogger({ verbose, quiet, logFile }); - + + if (wrapperEnvs) { + configBuilder.addEnvs(wrapperEnvs); + } + let project = await getProjectFromManifest(manifestFile, logger); if (!project) { diff --git a/packages/cli/src/commands/test.ts b/packages/cli/src/commands/test.ts index 7dfc7bd3ea..ac4cfdf750 100644 --- a/packages/cli/src/commands/test.ts +++ b/packages/cli/src/commands/test.ts @@ -15,6 +15,7 @@ import { defaultWorkflowManifest, parseManifestFileOption, parseLogFileOption, + parseWrapperEnvsOption, } from "../lib"; import { createLogger } from "./utils/createLogger"; @@ -22,9 +23,11 @@ import path from "path"; import yaml from "yaml"; import fs from "fs"; import { IClientConfigBuilder } from "@polywrap/client-config-builder-js"; +import { Env } from "@polywrap/core-js"; type WorkflowCommandOptions = { configBuilder: IClientConfigBuilder; + wrapperEnvs: Env[]; manifest: string; jobs?: string[]; validationScript?: string; @@ -53,6 +56,10 @@ export const test: Command = { `-c, --client-config <${intlMsg.commands_common_options_configPath()}>`, `${intlMsg.commands_common_options_config()}` ) + .option( + `--wrapper-envs <${intlMsg.commands_common_options_wrapperEnvsPath()}>`, + `${intlMsg.commands_common_options_wrapperEnvs()}` + ) .option( `-o, --output-file <${intlMsg.commands_test_options_outputFilePath()}>`, `${intlMsg.commands_test_options_outputFile()}` @@ -75,6 +82,7 @@ export const test: Command = { defaultWorkflowManifest ), configBuilder: await parseClientConfigOption(options.clientConfig), + wrapperEnvs: await parseWrapperEnvsOption(options.wrapperEnvs), outputFile: options.outputFile ? parseWorkflowOutputFilePathOption(options.outputFile) : undefined, @@ -88,6 +96,7 @@ const _run = async (options: WorkflowCommandOptions) => { const { manifest, configBuilder, + wrapperEnvs, outputFile, verbose, quiet, @@ -95,6 +104,10 @@ const _run = async (options: WorkflowCommandOptions) => { logFile, } = options; const logger = createLogger({ verbose, quiet, logFile }); + + if (wrapperEnvs) { + configBuilder.addEnvs(wrapperEnvs); + } const manifestPath = path.resolve(manifest); const workflow = await loadWorkflowManifest(manifestPath, logger); diff --git a/packages/cli/src/lib/option-parsers/index.ts b/packages/cli/src/lib/option-parsers/index.ts index 75866c1380..63a94a4be9 100644 --- a/packages/cli/src/lib/option-parsers/index.ts +++ b/packages/cli/src/lib/option-parsers/index.ts @@ -4,3 +4,4 @@ export * from "./dir"; export * from "./test"; export * from "./manifestFile"; export * from "./log-file"; +export * from "./wrapper-envs"; diff --git a/packages/cli/src/lib/option-parsers/wrapper-envs.ts b/packages/cli/src/lib/option-parsers/wrapper-envs.ts new file mode 100644 index 0000000000..d468a6f045 --- /dev/null +++ b/packages/cli/src/lib/option-parsers/wrapper-envs.ts @@ -0,0 +1,28 @@ +import { ClientConfigBuilder } from "@polywrap/client-config-builder-js"; +import { Env, Uri } from "@polywrap/core-js"; +import fs from "fs"; + +export async function parseWrapperEnvsOption( + wrapperEnvsPath: string | undefined +): Promise[]> | undefined> { + if (!wrapperEnvsPath) { + return undefined; + } + + const envsFileContents = fs.readFileSync(wrapperEnvsPath, { + encoding: "utf-8", + }); + + const envs = JSON.parse(envsFileContents) as Record< + string, + Record + >; + + const builder = new ClientConfigBuilder(); + + for (const env in envs) { + builder.addEnv(env, envs[env]); + } + + return builder.buildCoreConfig().envs; +} diff --git a/packages/js/plugins/ethereum/src/index.ts b/packages/js/plugins/ethereum/src/index.ts index 46e731521a..75cc6ee9e5 100644 --- a/packages/js/plugins/ethereum/src/index.ts +++ b/packages/js/plugins/ethereum/src/index.ts @@ -438,6 +438,17 @@ export class EthereumPlugin extends Module { private async _getConnection( connection?: SchemaConnection | null ): Promise { + // When a `node` is not specified within `connection`, but an env variable defines a custom node with the same network name, use the envs node when getting connections + // This behavior is a consequence of how the ens-resolver uses the Ethereum plugin, always specifying the connection network name (e.g. mainnet) + if ( + !connection?.node && + this.env.connection && + this.env.connection.networkNameOrChainId === + connection?.networkNameOrChainId + ) { + return this._connections.getConnection(this.env.connection); + } + return this._connections.getConnection(connection || this.env.connection); } } From afea58430422dd44ebbbdfcb2073cc0b45ce5445 Mon Sep 17 00:00:00 2001 From: Pileks Date: Thu, 24 Nov 2022 15:43:15 +0100 Subject: [PATCH 2/4] chore: lint --- packages/cli/src/commands/build.ts | 2 +- packages/cli/src/commands/docgen.ts | 4 ++-- packages/cli/src/commands/test.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index c08245b58f..4fb7c1c9d3 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -13,7 +13,7 @@ import { parseClientConfigOption, parseManifestFileOption, parseLogFileOption, - parseWrapperEnvsOption + parseWrapperEnvsOption, } from "../lib"; import { CodeGenerator } from "../lib/codegen"; import { diff --git a/packages/cli/src/commands/docgen.ts b/packages/cli/src/commands/docgen.ts index ae3f4fed77..c18f90230d 100644 --- a/packages/cli/src/commands/docgen.ts +++ b/packages/cli/src/commands/docgen.ts @@ -134,11 +134,11 @@ async function run(command: DocType, options: DocgenCommandOptions) { logFile, } = options; const logger = createLogger({ verbose, quiet, logFile }); - + if (wrapperEnvs) { configBuilder.addEnvs(wrapperEnvs); } - + let project = await getProjectFromManifest(manifestFile, logger); if (!project) { diff --git a/packages/cli/src/commands/test.ts b/packages/cli/src/commands/test.ts index ac4cfdf750..4446a99024 100644 --- a/packages/cli/src/commands/test.ts +++ b/packages/cli/src/commands/test.ts @@ -104,7 +104,7 @@ const _run = async (options: WorkflowCommandOptions) => { logFile, } = options; const logger = createLogger({ verbose, quiet, logFile }); - + if (wrapperEnvs) { configBuilder.addEnvs(wrapperEnvs); } From 0c99e52b6319082ae32747c6c0b453160b0c2af9 Mon Sep 17 00:00:00 2001 From: Pileks Date: Tue, 29 Nov 2022 15:29:41 +0100 Subject: [PATCH 3/4] CLI - add yaml support for --wrapper-envs option --- .../option-parsers/option-parsers.spec.ts | 49 ++++++++++++------- .../{wrapper-env.json => wrapper-envs.json} | 0 .../option-parsers/samples/wrapper-envs.yaml | 6 +++ .../src/lib/option-parsers/wrapper-envs.ts | 18 +++++-- 4 files changed, 51 insertions(+), 22 deletions(-) rename packages/cli/src/__tests__/unit/option-parsers/samples/{wrapper-env.json => wrapper-envs.json} (100%) create mode 100644 packages/cli/src/__tests__/unit/option-parsers/samples/wrapper-envs.yaml diff --git a/packages/cli/src/__tests__/unit/option-parsers/option-parsers.spec.ts b/packages/cli/src/__tests__/unit/option-parsers/option-parsers.spec.ts index 9c5c1f6752..62dc907b72 100644 --- a/packages/cli/src/__tests__/unit/option-parsers/option-parsers.spec.ts +++ b/packages/cli/src/__tests__/unit/option-parsers/option-parsers.spec.ts @@ -4,6 +4,24 @@ import { parseWrapperEnvsOption } from "../../../lib"; describe("unit tests for option-parsers", () => { describe("wrapper-envs", () => { + const sampleFileEnvs = [ + { + uri: Uri.from("wrap://ens/hello-world.polywrap.eth"), + env: { + foo: "bar", + }, + }, + { + uri: Uri.from("ens/ethereum.polywrap.eth"), + env: { + connection: { + node: "https://mainnet.infura.io/v3/some_api_key", + networkNameOrChainId: "mainnet", + }, + }, + }, + ]; + it("Should return undefined when no filename is provided", async () => { const envs = await parseWrapperEnvsOption(undefined); @@ -24,28 +42,23 @@ describe("unit tests for option-parsers", () => { it("Should return envs for a valid json file", async () => { const wrapperEnvsFilePath = path.join( __dirname, - "./samples/wrapper-env.json" + "./samples/wrapper-envs.json" ); const envs = await parseWrapperEnvsOption(wrapperEnvsFilePath); - expect(envs).toEqual([ - { - uri: Uri.from("wrap://ens/hello-world.polywrap.eth"), - env: { - foo: "bar", - }, - }, - { - uri: Uri.from("ens/ethereum.polywrap.eth"), - env: { - connection: { - node: "https://mainnet.infura.io/v3/some_api_key", - networkNameOrChainId: "mainnet", - }, - }, - }, - ]); + expect(envs).toEqual(sampleFileEnvs); + }); + + it("Should return envs for a valid yaml file", async () => { + const wrapperEnvsFilePath = path.join( + __dirname, + "./samples/wrapper-envs.yaml" + ); + + const envs = await parseWrapperEnvsOption(wrapperEnvsFilePath); + + expect(envs).toEqual(sampleFileEnvs); }); }); }); diff --git a/packages/cli/src/__tests__/unit/option-parsers/samples/wrapper-env.json b/packages/cli/src/__tests__/unit/option-parsers/samples/wrapper-envs.json similarity index 100% rename from packages/cli/src/__tests__/unit/option-parsers/samples/wrapper-env.json rename to packages/cli/src/__tests__/unit/option-parsers/samples/wrapper-envs.json diff --git a/packages/cli/src/__tests__/unit/option-parsers/samples/wrapper-envs.yaml b/packages/cli/src/__tests__/unit/option-parsers/samples/wrapper-envs.yaml new file mode 100644 index 0000000000..9587221fbf --- /dev/null +++ b/packages/cli/src/__tests__/unit/option-parsers/samples/wrapper-envs.yaml @@ -0,0 +1,6 @@ +ens/hello-world.polywrap.eth: + foo: bar +ens/ethereum.polywrap.eth: + connection: + node: https://mainnet.infura.io/v3/some_api_key + networkNameOrChainId: mainnet diff --git a/packages/cli/src/lib/option-parsers/wrapper-envs.ts b/packages/cli/src/lib/option-parsers/wrapper-envs.ts index d468a6f045..64ccfa8ea1 100644 --- a/packages/cli/src/lib/option-parsers/wrapper-envs.ts +++ b/packages/cli/src/lib/option-parsers/wrapper-envs.ts @@ -1,6 +1,9 @@ import { ClientConfigBuilder } from "@polywrap/client-config-builder-js"; import { Env, Uri } from "@polywrap/core-js"; import fs from "fs"; +import YAML from "yaml"; + +type WrapperEnvs = Record>; export async function parseWrapperEnvsOption( wrapperEnvsPath: string | undefined @@ -13,10 +16,17 @@ export async function parseWrapperEnvsOption( encoding: "utf-8", }); - const envs = JSON.parse(envsFileContents) as Record< - string, - Record - >; + let envs: WrapperEnvs; + + try { + envs = JSON.parse(envsFileContents) as WrapperEnvs; + } catch (_) { + try { + envs = YAML.parse(envsFileContents) as WrapperEnvs; + } catch (_) { + throw new Error(`Unable to parse wrapper envs file: ${wrapperEnvsPath}`); + } + } const builder = new ClientConfigBuilder(); From 517355a83104da4fadf29876eb9faa12134d2018 Mon Sep 17 00:00:00 2001 From: Pileks Date: Wed, 30 Nov 2022 19:27:09 +0100 Subject: [PATCH 4/4] CLI - add environment variable support to `--wrapper-envs` command option --- packages/cli/README.md | 42 +++++++++++++++++++ .../src/lib/option-parsers/wrapper-envs.ts | 11 ++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/packages/cli/README.md b/packages/cli/README.md index f30a75bf2d..f532089401 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -79,6 +79,9 @@ This outputs the project's ABI schema (Wasm and Interface) and binary package (W - `-c, --client-config ` Use a custom Polywrap Client configuration. +- `--wrapper-envs ` + Configure wrapper environment values using the provided file. + - `-n, --no-codegen` Don't perform codegen before building. By default, `build` performs a `codegen` step before building your Project. This option skips this step. This is especially useful when you are testing manual changes to your types/bindings. @@ -119,6 +122,9 @@ This command generates types and bindings for your project based on your project - `-c, --client-config ` Use a custom Polywrap Client configuration. +- `--wrapper-envs ` + Configure wrapper environment values using the provided file. + #### Special note When running `codegen` for Plugin Projects, the Polywrap CLI will also output an ABI schema for your plugin into the `./build` directory. You can override this output directory by specifying `-p, --publish-dir `. @@ -269,6 +275,9 @@ polywrap test [options] - `-c, --client-config ` Use a custom Polywrap Client configuration. +- `--wrapper-envs ` + Configure wrapper environment values using the provided file. + - `-o, --output-file ` Specify the output file path for the workflow result @@ -426,6 +435,9 @@ polywrap docgen - `-c, --client-config ` Use a custom Polywrap Client configuration. +- `--wrapper-envs ` + Configure wrapper environment values using the provided file. + - `-i, --imports` Generate docs for your project's dependencies as well. @@ -515,6 +527,36 @@ export function getClientConfig( ): Partial ``` +### The `--wrapper-envs` option +All commands which support the `-c, --client-config` option also support the `--wrapper-envs ` option. +This option allows the user to set environment values for Wrappers using a simple YAML or JSON file. + +For example, if you would like to change the API key used within the Ethereum plugin wrapper, you can create a `envs.yaml` file: + +```yaml +ens/ethereum.polywrap.eth: + connection: + node: https://mainnet.infura.io/v3/YOUR_API_KEY # Use Infura with your API key + networkNameOrChainId: mainnet +``` + +You can then run the `build`, `codegen`, `docgen` and `test` and specify your custom `--wrapper-envs`: + +```bash +polywrap codegen --wrapper-envs envs.yaml +``` + +You can also pass environment variables into the wrappper-envs file by using `$`: + +```yaml +ens/ethereum.polywrap.eth: + connection: + node: $MY_INFURA_NODE # Use environment variable called MY_INFURA_NODE + networkNameOrChainId: mainnet +``` + +If you need to use the `$` sign within your wrapper-envs file, you can escape it using `$$`. + ## Logging By default, the Polywrap CLI outputs all of its messages to the console. diff --git a/packages/cli/src/lib/option-parsers/wrapper-envs.ts b/packages/cli/src/lib/option-parsers/wrapper-envs.ts index 64ccfa8ea1..283ac10dde 100644 --- a/packages/cli/src/lib/option-parsers/wrapper-envs.ts +++ b/packages/cli/src/lib/option-parsers/wrapper-envs.ts @@ -1,3 +1,5 @@ +import { loadEnvironmentVariables } from "../system"; + import { ClientConfigBuilder } from "@polywrap/client-config-builder-js"; import { Env, Uri } from "@polywrap/core-js"; import fs from "fs"; @@ -28,10 +30,15 @@ export async function parseWrapperEnvsOption( } } + const wrapperEnvs = loadEnvironmentVariables(envs) as Record< + string, + Record + >; + const builder = new ClientConfigBuilder(); - for (const env in envs) { - builder.addEnv(env, envs[env]); + for (const env in wrapperEnvs) { + builder.addEnv(env, wrapperEnvs[env]); } return builder.buildCoreConfig().envs;