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

Yolo mode activated! #205

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
"bin": "bin/create-dapp-se2.js",
"scripts": {
"build": "rollup -c rollup.config.js",
"build:dev": "yarn build && rollup -c src/dev/rollup.config.js",
"build:dev": "yarn build && rollup -c src/dev/rollup.config.js && rollup -c src/yolo/rollup.config.js",
"create-extension": "node dist/create-extension/create-extension.js",
"create-extension-yolo": "node dist/create-extension-yolo/create-extension-yolo.js",
"dev": "rollup -c rollup.config.js --watch",
"cli": "node bin/create-dapp-se2.js",
"lint": "eslint .",
Expand Down
7 changes: 6 additions & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import chalk from "chalk";
import { SOLIDITY_FRAMEWORKS } from "./utils/consts";
import { validateFoundryUp } from "./utils/system-validation";
import { showHelpMessage } from "./utils/show-help-message";
import { createProjectYolo } from "./yolo";

export async function cli(args: Args) {
try {
Expand All @@ -22,7 +23,11 @@ export async function cli(args: Args) {
await validateFoundryUp();
}

await createProject(options);
if (options.yolo) {
await createProjectYolo(options);
} else {
await createProject(options);
}
} catch (error: any) {
console.error(chalk.red.bold(error.message || "An unknown error occurred."));
return;
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type BaseOptions = {
dev: boolean;
externalExtension: ExternalExtension | ExternalExtensionNameDev | null;
solidityFramework: SolidityFramework | "none" | null;
yolo: boolean;
};

export type RawOptions = BaseOptions & {
Expand Down
5 changes: 5 additions & 0 deletions src/utils/parse-arguments-into-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export async function parseArgumentsIntoOptions(

"--help": Boolean,
"-h": "--help",

"--yolo": Boolean,
},
{
argv: rawArgs.slice(2),
Expand All @@ -37,6 +39,8 @@ export async function parseArgumentsIntoOptions(

const help = args["--help"] ?? false;

const yolo = args["--yolo"] ?? false;

let project: string | null = args._[0] ?? null;

// use the original extension arg
Expand Down Expand Up @@ -97,6 +101,7 @@ export async function parseArgumentsIntoOptions(
externalExtension: extension,
help,
solidityFramework: solidityFramework as RawOptions["solidityFramework"],
yolo,
},
solidityFrameworkChoices,
};
Expand Down
2 changes: 2 additions & 0 deletions src/utils/prompt-for-missing-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const defaultOptions: RawOptions = {
dev: false,
externalExtension: null,
help: false,
yolo: false,
};

export async function promptForMissingOptions(
Expand Down Expand Up @@ -51,6 +52,7 @@ export async function promptForMissingOptions(
dev: options.dev ?? defaultOptions.dev,
solidityFramework: solidityFramework === "none" ? null : solidityFramework,
externalExtension: options.externalExtension,
yolo: options.yolo,
};

return mergedOptions;
Expand Down
192 changes: 192 additions & 0 deletions src/yolo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
import { execa } from "execa";
import { createProjectDirectory, prettierFormat, installPackages } from "./tasks";
import type { ExternalExtension, Options } from "./types";
import { renderOutroMessage } from "./utils/render-outro-message";
import chalk from "chalk";
import { Listr } from "listr2";
import path from "path";
import { getArgumentFromExternalExtensionOption } from "./utils/external-extensions";
import fs from "fs";
import { promisify } from "util";
import ncp from "ncp";

const DELETED_FILES_LOG = "deletedFiles.log";
const COMMIT_HASH_LOG = "commitHash.log";
const EXTERNAL_EXTENSION_TMP_DIR = "tmp-external-extension";

const copy = promisify(ncp);

const cloneGitRepo = async (repositoryUrl: string, targetDir: string): Promise<void> => {
try {
// 1. Create the target directory if it doesn't exist
await fs.promises.mkdir(targetDir, { recursive: true });

// 2. Clone the repository
await execa("git", ["clone", repositoryUrl, targetDir], { cwd: targetDir });

console.log(`Repository cloned to ${targetDir}`);
} catch (error: any) {
console.error(`Error cloning repository: ${error.message}`);
throw error;
}
};

const resetToCommitHash = async (externalExtensionPath: string, targetDir: string) => {
const logPath = path.join(externalExtensionPath, COMMIT_HASH_LOG);

if (fs.existsSync(logPath)) {
const commitHash = (await fs.promises.readFile(logPath, "utf8")).trim();
if (commitHash) {
try {
console.log(`Resetting repository to commit hash: ${commitHash}`);
await execa("git", ["reset", "--hard", commitHash], { cwd: targetDir });
console.log(`Repository successfully reset to commit hash: ${commitHash}`);
} catch (error: any) {
console.error(`Error resetting to commit hash: ${error.message}`);
throw error;
}
} else {
console.warn("Commit hash log is empty. Skipping reset.");
}
} else {
console.warn(`No commit hash log found at: ${logPath}. Skipping reset.`);
}
};

const removeLoggedDeletedFiles = async (externalExtensionPath: string, targetDir: string) => {
const logPath = path.join(externalExtensionPath, DELETED_FILES_LOG);
console.log(`Checking for previously logged deleted files at: ${logPath}`);
if (fs.existsSync(logPath)) {
const deletedFilesContent = await fs.promises.readFile(logPath, "utf8");
const deletedFiles = deletedFilesContent.split("\n").filter(Boolean);

for (const file of deletedFiles) {
const filePath = path.join(targetDir, file);
console.log(`Checking deleted file: ${file}`, filePath);
if (fs.existsSync(filePath)) {
await fs.promises.unlink(filePath);
console.log(`Removed previously logged deleted file: ${file}`);
}
}
}
};

const commitChanges = async (targetDir: string) => {
try {
console.log("Staging all changes...");
await execa("git", ["add", "--all"], { cwd: targetDir });

console.log("Committing changes...");
await execa("git", ["commit", "-m", "Apply changes from extension"], { cwd: targetDir });

console.log("Changes committed successfully.");
} catch (error: any) {
console.error(`Error committing changes: ${error.message}`);
throw error;
}
};

const setUpExternalExtensionFiles = async (options: Options, tmpDir: string) => {
// 1. Create tmp directory to clone external extension
await fs.promises.mkdir(tmpDir);

const { repository, branch } = options.externalExtension as ExternalExtension;

// 2. Clone external extension
if (branch) {
await execa("git", ["clone", "--branch", branch, repository, tmpDir], {
cwd: tmpDir,
});
} else {
await execa("git", ["clone", repository, tmpDir], { cwd: tmpDir });
}
};

const createExtension = async (options: Options, targetDir: string) => {
await cloneGitRepo("https://github.com/scaffold-eth/scaffold-eth-2", targetDir);

const tmpDir = path.join(targetDir, EXTERNAL_EXTENSION_TMP_DIR);

let externalExtensionPath = path.join(tmpDir, "extension");

if (options.dev) {
externalExtensionPath = path.join("externalExtensions", options.externalExtension as string, "extension");
} else {
await setUpExternalExtensionFiles(options, tmpDir);
}

await resetToCommitHash(externalExtensionPath, targetDir);

await copy(externalExtensionPath, targetDir, {
filter: file => {
const relativePath = path.relative(externalExtensionPath, file);
return ![DELETED_FILES_LOG, COMMIT_HASH_LOG].includes(relativePath);
},
});

await removeLoggedDeletedFiles(externalExtensionPath, targetDir);

await commitChanges(targetDir);
};

export async function createProjectYolo(options: Options) {
console.log(`\n`);
console.log("Yolo mode activated! 🚀");

// const currentFileUrl = import.meta.url;

const targetDirectory = path.resolve(process.cwd(), options.project);

const tasks = new Listr(
[
{
title: `📁 Create project directory ${targetDirectory}`,
task: () => createProjectDirectory(options.project),
},
{
title: `🚀 Creating a new Scaffold-ETH 2 app in ${chalk.green.bold(
options.project,
)}${options.externalExtension ? ` with the ${chalk.green.bold(options.dev ? options.externalExtension : getArgumentFromExternalExtensionOption(options.externalExtension))} extension` : ""}`,
//task: () => copyTemplateFiles(options, templateDirectory, targetDirectory),
task: () => createExtension(options, targetDirectory),
},
{
title: "📦 Installing dependencies with yarn, this could take a while",
task: (_, task) => installPackages(targetDirectory, task),
skip: () => {
if (!options.install) {
return "Manually skipped, since `--skip-install` flag was passed";
}
return false;
},
rendererOptions: {
outputBar: 8,
persistentOutput: false,
},
},
{
title: "🪄 Formatting files",
task: () => prettierFormat(targetDirectory),
skip: () => {
if (!options.install) {
return "Can't use source prettier, since `yarn install` was skipped";
}
return false;
},
},
// {
// title: `📡 Initializing Git repository${options.solidityFramework === SOLIDITY_FRAMEWORKS.FOUNDRY ? " and submodules" : ""}`,
// task: () => createFirstGitCommit(targetDirectory, options),
// },
],
{ rendererOptions: { collapseSkips: false, suffixSkips: true } },
);

try {
await tasks.run();
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!"));
}
}
Loading
Loading