From 2470e4633cb9730f0c1af1c7f180d54c257f4b14 Mon Sep 17 00:00:00 2001 From: Kevin Padilla Date: Wed, 15 Jul 2026 14:28:04 -0600 Subject: [PATCH] feat: enhance deployment process with Git integration and npx support --- .npmignore | 14 +++- README.md | 16 +++++ package.json | 10 +-- src/commands/deploy/deployCross.ts | 11 +++ src/commands/deploy/deploySingle.ts | 11 +++ src/commands/developer.ts | 66 ++++++++++++++--- src/index.ts | 0 src/utils/git.ts | 108 ++++++++++++++++++++++++++++ 8 files changed, 221 insertions(+), 15 deletions(-) mode change 100644 => 100755 src/index.ts create mode 100644 src/utils/git.ts diff --git a/.npmignore b/.npmignore index 9016e88..bfb6bb3 100644 --- a/.npmignore +++ b/.npmignore @@ -45,6 +45,14 @@ lib/solidity-bytes-utils/ lib/v3-core/ lib/v3-periphery/ +# Exclude most of lib/evvm except contracts +lib/evvm/testnet/broadcast/ +lib/evvm/testnet/cache/ +lib/evvm/testnet/out/ +lib/evvm/testnet/test/ +lib/evvm/testnet/script/ +lib/evvm/testnet/lib/ + # Input configuration files input/ @@ -54,5 +62,7 @@ wake.toml # TypeScript example package-ts.json.example -# Source directory (since we copy from src/ to root during packaging) -src/ \ No newline at end of file +# Executables and wrapper scripts +.executables/ +evvm +evvm.bat \ No newline at end of file diff --git a/README.md b/README.md index 0d7f6da..0efdff3 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,22 @@ Before deploying with the CLI, ensure you have the following installed: ## Quick start (2 min) +### Option A: Using bunx/npx (No clone required) + +Run the CLI directly without cloning the repository: + +```bash +# Using Bun (recommended) +bunx @evvm/cli deploy + +# Using npm/npx +npx @evvm/cli deploy +``` + +**Note:** You still need Foundry and Git installed on your system. + +### Option B: Clone & install (For development) + 1. Clone & install ```bash diff --git a/package.json b/package.json index d90664c..8ecc9c4 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "@evvm/cli", - "version": "3.1.2", + "version": "1.0.0", "type": "module", - "description": "EVVM CLI - Command-line tool for deploying and managing EVVM instances on testnets", + "description": "EVVM CLI - Command-line tool for deploying and managing EVVM instances", "keywords": [ "evvm", "ethereum", @@ -24,10 +24,10 @@ "bugs": { "url": "https://github.com/EVVM-org/evvm-cli/issues" }, + "bin": { + "evvm": "src/index.ts" + }, "scripts": { - "build": "bun run copy-files", - "copy-files": "cp -r lib/evvm/testnet/src/contracts . && cp -r lib/evvm/testnet/src/interfaces . && cp -r lib/evvm/testnet/src/library .", - "clean": "rm -rf contracts interfaces library", "evvm": "bun run src/index.ts", "buildCli": "bun build src/index.ts --compile --outfile evvm", "build-all": "bun run build-linux && bun run build-windows && bun run build-macos", diff --git a/src/commands/deploy/deployCross.ts b/src/commands/deploy/deployCross.ts index f494d00..e1534e4 100644 --- a/src/commands/deploy/deployCross.ts +++ b/src/commands/deploy/deployCross.ts @@ -22,6 +22,8 @@ import { showAllCrossChainDeployedContracts, forgeScript, } from "../../utils/foundry"; +import { areContractsInstalled } from "../../utils/git"; +import { installDependencies } from "../developer"; import { configurationBasic, configurationCrossChain, @@ -85,6 +87,15 @@ export async function deployCross(args: string[], options: any) { walletNameExternal, ]); + const contractsInstalled = await areContractsInstalled(); + if (!contractsInstalled) { + warning( + "EVVM contracts not found", + `${colors.darkGray}Installing contracts automatically...${colors.reset}` + ); + await installDependencies(); + } + if (skipInputConfig) { warning( `Skipping input configuration`, diff --git a/src/commands/deploy/deploySingle.ts b/src/commands/deploy/deploySingle.ts index 6d7f8e4..b264908 100644 --- a/src/commands/deploy/deploySingle.ts +++ b/src/commands/deploy/deploySingle.ts @@ -14,6 +14,8 @@ import { showDeployContractsAndFindEvvm, verifyFoundryInstalledAndAccountSetup, } from "../../utils/foundry"; +import { areContractsInstalled } from "../../utils/git"; +import { installDependencies } from "../developer"; import { chainIdNotSupported, confirmation, @@ -68,6 +70,15 @@ export async function deploySingle(args: string[], options: any) { await verifyFoundryInstalledAndAccountSetup([walletName]); + const contractsInstalled = await areContractsInstalled(); + if (!contractsInstalled) { + warning( + "EVVM contracts not found", + `${colors.darkGray}Installing contracts automatically...${colors.reset}` + ); + await installDependencies(); + } + if (skipInputConfig) { warning( `Skipping input configuration`, diff --git a/src/commands/developer.ts b/src/commands/developer.ts index 0e3198e..b0aa7c3 100644 --- a/src/commands/developer.ts +++ b/src/commands/developer.ts @@ -10,8 +10,9 @@ import { $ } from "bun"; import { colors } from "../constants"; import { contractInterfacesGenerator, contractTesting } from "../utils/foundry"; -import { promptSelect } from "../utils/prompts"; -import { confirmation, seccionTitle, sectionSubtitle } from "../utils/outputMesages"; +import { verifyGitInstalled, updateSubmodules, isGitRepository, areContractsInstalled, cloneContractsRepo } from "../utils/git"; +import { promptSelect, promptYesNo } from "../utils/prompts"; +import { confirmation, seccionTitle, sectionSubtitle, warning } from "../utils/outputMesages"; /** * Developer utilities command handler @@ -68,15 +69,64 @@ export async function developer(_args: string[], options: any) { export async function installDependencies() { - sectionSubtitle("Cloning EVVM Testnet Contracts"); - await $`git submodule update --init --recursive --depth 1 --jobs 4`; - await $`git submodule update --remote --merge`; + await verifyGitInstalled(); + + const contractsInstalled = await areContractsInstalled(); + + if (contractsInstalled) { + const reinstall = await promptYesNo( + "EVVM contracts are already installed. Do you want to reinstall them?", + false + ); + + if (!reinstall) { + warning("Skipping contract installation"); + sectionSubtitle("Installing EVVM CLI Dependencies"); + await $`bun install`; + sectionSubtitle("Installing EVVM Contracts Dependencies"); + await $`bun install`.cwd("lib/evvm/testnet"); + sectionSubtitle("Installing EVVM Foundry Dependencies"); + await $`forge install`.cwd("lib/evvm/testnet"); + console.log(); + confirmation(`All dependencies installed successfully`); + return; + } + } + + const isGitRepo = await isGitRepository(); + + if (isGitRepo) { + await updateSubmodules(); + } else { + await cloneContractsRepo(); + } + sectionSubtitle("Installing EVVM CLI Dependencies"); - await $`bun install`; + const bunInstallCli = Bun.spawn(["bun", "install"], { + stderr: "inherit", + stdout: "inherit", + }); + await bunInstallCli.exited; + if (bunInstallCli.exitCode !== 0) throw new Error("bun install failed"); + sectionSubtitle("Installing EVVM Contracts Dependencies"); - await $`bun install`.cwd("lib/evvm/testnet"); + const bunInstallContracts = Bun.spawn(["bun", "install"], { + cwd: "lib/evvm/testnet", + stderr: "inherit", + stdout: "inherit", + }); + await bunInstallContracts.exited; + if (bunInstallContracts.exitCode !== 0) throw new Error("bun install in lib/evvm/testnet failed"); + sectionSubtitle("Installing EVVM Foundry Dependencies"); - await $`forge install`.cwd("lib/evvm/testnet"); + const forgeInstall = Bun.spawn(["forge", "install"], { + cwd: "lib/evvm/testnet", + stderr: "inherit", + stdout: "inherit", + }); + await forgeInstall.exited; + if (forgeInstall.exitCode !== 0) throw new Error("forge install failed"); + console.log(); confirmation(`All dependencies installed successfully`); } \ No newline at end of file diff --git a/src/index.ts b/src/index.ts old mode 100644 new mode 100755 diff --git a/src/utils/git.ts b/src/utils/git.ts new file mode 100644 index 0000000..2e0856a --- /dev/null +++ b/src/utils/git.ts @@ -0,0 +1,108 @@ +/** + * Git Integration Utilities + * + * Provides functions for interacting with Git including: + * - Git installation validation + * - Submodule management + * - Repository detection + * - Direct contract cloning + * + * @module cli/utils/git + */ + +import { $ } from "bun"; +import { colors } from "../constants"; +import { criticalErrorCustom, sectionSubtitle } from "./outputMesages"; + +/** + * Checks if Git is installed + * + * @returns {Promise} True if Git is installed and accessible + */ +export async function gitIsInstalled(): Promise { + try { + await $`git --version`.quiet(); + } catch (error) { + return false; + } + return true; +} + +/** + * Verifies that Git is installed and shows error if not + * + * @returns {Promise} + */ +export async function verifyGitInstalled(): Promise { + if (!(await gitIsInstalled())) + criticalErrorCustom( + "Git installation not detected.", + "Visit https://git-scm.com/downloads for installation instructions." + ); +} + +/** + * Updates Git submodules with initialization + * + * @returns {Promise} + */ +export async function updateSubmodules(): Promise { + sectionSubtitle("Cloning EVVM Testnet Contracts"); + const init = Bun.spawn(["git", "submodule", "update", "--init", "--recursive", "--depth", "1", "--jobs", "4"], { + stderr: "inherit", + stdout: "inherit", + }); + await init.exited; + if (init.exitCode !== 0) throw new Error("git submodule update failed"); + + const merge = Bun.spawn(["git", "submodule", "update", "--remote", "--merge"], { + stderr: "inherit", + stdout: "inherit", + }); + await merge.exited; + if (merge.exitCode !== 0) throw new Error("git submodule update --remote failed"); +} + +/** + * Checks if current directory is a Git repository + * + * @returns {Promise} True if current directory is a Git repository + */ +export async function isGitRepository(): Promise { + try { + await $`git rev-parse --is-inside-work-tree`.quiet(); + return true; + } catch (error) { + return false; + } +} + +/** + * Checks if EVVM contracts are already installed + * + * @returns {Promise} True if lib/evvm/testnet directory exists + */ +export async function areContractsInstalled(): Promise { + try { + const stat = await $`test -d lib/evvm/testnet`.quiet(); + return stat.exitCode === 0; + } catch (error) { + return false; + } +} + +/** + * Clones EVVM testnet contracts repository directly + * Used when not in a Git repository (e.g., bunx/npx installation) + * + * @returns {Promise} + */ +export async function cloneContractsRepo(): Promise { + sectionSubtitle("Cloning EVVM Testnet Contracts"); + const proc = Bun.spawn(["git", "clone", "https://github.com/EVVM-org/testnet-Contracts", "lib/evvm/testnet"], { + stderr: "inherit", + stdout: "inherit", + }); + await proc.exited; + if (proc.exitCode !== 0) throw new Error("git clone failed"); +} \ No newline at end of file