Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

early foundryup check #65

Merged
merged 12 commits into from
Jun 21, 2024
5 changes: 5 additions & 0 deletions .changeset/giant-gifts-turn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"create-eth": patch
---

foundry: use forge to setup libraries + do early check for foundryup
5 changes: 5 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@ import { promptForMissingOptions } from "./utils/prompt-for-missing-options";
import { renderIntroMessage } from "./utils/render-intro-message";
import type { Args } from "./types";
import chalk from "chalk";
import { SOLIDITY_FRAMEWORKS } from "./utils/consts";
import { validateFoundryUp } from "./utils/system-validation";

export async function cli(args: Args) {
try {
renderIntroMessage();
const rawOptions = await parseArgumentsIntoOptions(args);
const options = await promptForMissingOptions(rawOptions);
if (options.extensions.includes(SOLIDITY_FRAMEWORKS.FOUNDRY)) {
await validateFoundryUp();
}
await createProject(options);
} catch (error: any) {
console.error(chalk.red.bold(error.message || "An unknown error occurred."));
Expand Down
3 changes: 2 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Config, ExternalExtension, typedQuestion } from "./types";
import { SOLIDITY_FRAMEWORKS } from "./utils/consts";

const config: Config = {
questions: [
typedQuestion({
type: "single-select",
name: "solidityFramework",
message: "What solidity framework do you want to use?",
extensions: ["hardhat", "foundry", null],
extensions: [SOLIDITY_FRAMEWORKS.HARDHAT, SOLIDITY_FRAMEWORKS.FOUNDRY, null],
default: "hardhat",
}),
],
Expand Down
5 changes: 3 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Listr } from "listr2";
import path from "path";
import { fileURLToPath } from "url";
import { getArgumentFromExternalExtensionOption } from "./utils/external-extensions";
import { SOLIDITY_FRAMEWORKS } from "./utils/consts";

export async function createProject(options: Options) {
console.log(`\n`);
Expand Down Expand Up @@ -55,7 +56,7 @@ export async function createProject(options: Options) {
},
},
{
title: `📡 Initializing Git repository${options.extensions.includes("foundry") ? " and submodules" : ""}`,
title: `📡 Initializing Git repository${options.extensions.includes(SOLIDITY_FRAMEWORKS.FOUNDRY) ? " and submodules" : ""}`,
rin-st marked this conversation as resolved.
Show resolved Hide resolved
task: () => createFirstGitCommit(targetDirectory, options),
},
],
Expand All @@ -64,7 +65,7 @@ export async function createProject(options: Options) {

try {
await tasks.run();
await renderOutroMessage(options);
renderOutroMessage(options);
} catch (error) {
console.log("%s Error occurred", chalk.red.bold("ERROR"), error);
console.log("%s Exiting...", chalk.red.bold("Uh oh! 😕 Sorry about that!"));
Expand Down
64 changes: 6 additions & 58 deletions src/tasks/create-first-git-commit.ts
Original file line number Diff line number Diff line change
@@ -1,74 +1,22 @@
import { execa } from "execa";
import { Options } from "../types";
import path from "path";
import { SOLIDITY_FRAMEWORKS } from "../utils/consts";

// Checkout the latest release tag in a git submodule
async function checkoutLatestTag(submodulePath: string): Promise<void> {
try {
const { stdout } = await execa("git", ["tag", "-l", "--sort=-v:refname"], {
cwd: submodulePath,
});
const tagLines = stdout.split("\n");
if (tagLines.length > 0) {
const latestTag = tagLines[0];
await execa("git", ["-C", `${submodulePath}`, "checkout", latestTag]);
} else {
throw new Error(`No tags found in submodule at ${submodulePath}`);
}
} catch (error) {
console.error("Error checking out latest tag:", error);
throw error;
}
}
const foundryLibraries = ["foundry-rs/forge-std", "OpenZeppelin/openzeppelin-contracts", "gnsps/solidity-bytes-utils"];

export async function createFirstGitCommit(targetDir: string, options: Options) {
try {
// TODO: Move the logic for adding submodules to tempaltes
if (options.extensions?.includes("foundry")) {
const foundryWorkSpacePath = path.resolve(targetDir, "packages", "foundry");
await execa("git", ["submodule", "add", "https://github.com/foundry-rs/forge-std", "lib/forge-std"], {
cwd: foundryWorkSpacePath,
});
await execa(
"git",
[
"submodule",
"add",
"-b",
"release-v5.0",
"https://github.com/OpenZeppelin/openzeppelin-contracts",
"lib/openzeppelin-contracts",
],
{
cwd: foundryWorkSpacePath,
},
);
await execa(
"git",
["submodule", "add", "https://github.com/gnsps/solidity-bytes-utils", "lib/solidity-bytes-utils"],
{
cwd: foundryWorkSpacePath,
},
);
await execa("git", ["submodule", "update", "--init", "--recursive"], {
cwd: foundryWorkSpacePath,
});
await checkoutLatestTag(path.resolve(foundryWorkSpacePath, "lib", "forge-std"));
await checkoutLatestTag(path.resolve(foundryWorkSpacePath, "lib", "openzeppelin-contracts"));
}

await execa("git", ["add", "-A"], { cwd: targetDir });
await execa("git", ["commit", "-m", "Initial commit with 🏗️ Scaffold-ETH 2", "--no-verify"], { cwd: targetDir });

// Update the submodule, since we have checked out the latest tag in the previous step of foundry
if (options.extensions?.includes("foundry")) {
await execa("git", ["submodule", "update", "--init", "--recursive"], {
cwd: path.resolve(targetDir, "packages", "foundry"),
});
if (options.extensions.includes(SOLIDITY_FRAMEWORKS.FOUNDRY)) {
const foundryWorkSpacePath = path.resolve(targetDir, "packages", "foundry");
technophile-04 marked this conversation as resolved.
Show resolved Hide resolved
// forge install foundry libraries
await execa("forge", ["install", ...foundryLibraries], { cwd: foundryWorkSpacePath });
}
} catch (e: any) {
// cast error as ExecaError to get stderr

throw new Error("Failed to initialize git repository", {
cause: e?.stderr ?? e,
});
Expand Down
11 changes: 11 additions & 0 deletions src/utils/consts.ts
Original file line number Diff line number Diff line change
@@ -1 +1,12 @@
import { SolidityFramework } from "../types";

export const baseDir = "base";

export const SOLIDITY_FRAMEWORKS = {
rin-st marked this conversation as resolved.
Show resolved Hide resolved
HARDHAT: "hardhat",
FOUNDRY: "foundry",
} as const;

export const isSolidityFramework = (value: string): value is SolidityFramework => {
return Object.values(SOLIDITY_FRAMEWORKS).includes(value as SolidityFramework);
};
9 changes: 7 additions & 2 deletions src/utils/parse-arguments-into-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import * as https from "https";
import { getDataFromExternalExtensionArgument } from "./external-extensions";
import chalk from "chalk";
import { CURATED_EXTENSIONS } from "../config";
import { SOLIDITY_FRAMEWORKS } from "./consts";
import { validateFoundryUp } from "./system-validation";

const validateTemplate = async (template: string): Promise<{ repository: string; branch?: string }> => {
const { githubUrl, githubBranchUrl, branch } = getDataFromExternalExtensionArgument(template);
Expand Down Expand Up @@ -64,6 +66,10 @@ export async function parseArgumentsIntoOptions(rawArgs: Args): Promise<RawOptio

const solidityFramework = args["--solidity-framework"] ?? null;

if (solidityFramework === SOLIDITY_FRAMEWORKS.FOUNDRY) {
await validateFoundryUp();
}

// ToDo. Allow multiple
const extension = args["--extension"] ? await validateTemplate(args["--extension"]) : null;

Expand All @@ -86,8 +92,7 @@ export async function parseArgumentsIntoOptions(rawArgs: Args): Promise<RawOptio
};
}

const SOLIDITY_FRAMEWORK_OPTIONS = ["hardhat", "foundry", "none"];

const SOLIDITY_FRAMEWORK_OPTIONS = [...Object.values(SOLIDITY_FRAMEWORKS), "none"];
function solidityFrameworkHandler(value: string) {
const lowercasedValue = value.toLowerCase();
if (SOLIDITY_FRAMEWORK_OPTIONS.includes(lowercasedValue)) {
Expand Down
20 changes: 6 additions & 14 deletions src/utils/render-outro-message.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { Options } from "../types";
import chalk from "chalk";
import { execa } from "execa";
import { SOLIDITY_FRAMEWORKS } from "./consts";

export async function renderOutroMessage(options: Options) {
export function renderOutroMessage(options: Options) {
let message = `
\n
${chalk.bold.green("Congratulations!")} Your project has been scaffolded! 🎉
Expand All @@ -12,23 +12,15 @@ export async function renderOutroMessage(options: Options) {
${chalk.dim("cd")} ${options.project}
`;

if (options.extensions.includes("hardhat") || options.extensions.includes("foundry")) {
if (
options.extensions.includes(SOLIDITY_FRAMEWORKS.HARDHAT) ||
carletex marked this conversation as resolved.
Show resolved Hide resolved
options.extensions.includes(SOLIDITY_FRAMEWORKS.FOUNDRY)
) {
message += `
\t${chalk.bold("Start the local development node")}
\t${chalk.dim("yarn")} chain
`;

if (options.extensions.includes("foundry")) {
try {
await execa("foundryup", ["-h"]);
} catch (error) {
message += `
\t${chalk.bold.yellow("(NOTE: Foundryup is not installed in your system)")}
\t${chalk.dim("Checkout: https://getfoundry.sh")}
`;
}
}

message += `
\t${chalk.bold("In a new terminal window, deploy your contracts")}
\t${chalk.dim("yarn")} deploy
Expand Down
14 changes: 14 additions & 0 deletions src/utils/system-validation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import chalk from "chalk";
import { execa } from "execa";

export const validateFoundryUp = async () => {
try {
await execa("foundryup", ["-h"]);
} catch (error) {
const message = `${chalk.bold.yellow("NOTE: Foundryup is not installed in your system.")}
technophile-04 marked this conversation as resolved.
Show resolved Hide resolved
${chalk.bold.yellow("To use foundry, please install foundryup")}
carletex marked this conversation as resolved.
Show resolved Hide resolved
${chalk.bold.yellow("Checkout: https://getfoundry.sh")}
`;
throw new Error(message);
}
};
Loading