Skip to content

Commit

Permalink
Merge pull request #1 from zeta-chain/setup
Browse files Browse the repository at this point in the history
feat: CLI
  • Loading branch information
fadeev authored Jan 27, 2025
2 parents d557590 + d9852c3 commit 65bcdb7
Show file tree
Hide file tree
Showing 17 changed files with 3,242 additions and 1 deletion.
9 changes: 9 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.yarn
artifacts
cache
coverage
node_modules
typechain-types
dist
dist/typechain-types
docs
57 changes: 57 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const path = require("path");

/**
* @type {import("eslint").Linter.Config}
*/
module.exports = {
env: {
browser: false,
es2021: true,
mocha: true,
node: true,
},
extends: ["plugin:prettier/recommended"],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 12,
},
plugins: [
"@typescript-eslint",
"prettier",
"simple-import-sort",
"sort-keys-fix",
"typescript-sort-keys",
"prefer-arrow",
],
rules: {
"@typescript-eslint/sort-type-union-intersection-members": "error",
camelcase: "off",
"func-style": ["error", "expression", { allowArrowFunctions: true }],
"prefer-arrow/prefer-arrow-functions": [
"warn",
{
classPropertiesAllowed: false,
disallowPrototype: true,
singleReturnOnly: false,
},
],
"simple-import-sort/exports": "error",
"simple-import-sort/imports": "error",
"sort-keys-fix/sort-keys-fix": "error",
"typescript-sort-keys/interface": "error",
"typescript-sort-keys/string-enum": "error",
},
settings: {
"import/parsers": {
"@typescript-eslint/parser": [".js", ".jsx", ".ts", ".tsx", ".d.ts"],
},
"import/resolver": {
node: {
extensions: [".js", ".jsx", ".ts", ".tsx", ".d.ts"],
},
typescript: {
project: path.join(__dirname, "tsconfig.json"),
},
},
},
};
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @zeta-chain/fullstack
25 changes: 25 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Build

on:
pull_request:
branches: [main]

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "18"
registry-url: "https://registry.npmjs.org"

- name: Install Dependencies
run: yarn install

- name: Build
run: yarn build
25 changes: 25 additions & 0 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Lint

on:
pull_request:
branches: [main]

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "18"
registry-url: "https://registry.npmjs.org"

- name: Install Dependencies
run: yarn install

- name: Lint
run: yarn lint:js
45 changes: 45 additions & 0 deletions .github/workflows/publish-npm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Publish to NPM

on:
release:
types: [published]

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "18"
registry-url: "https://registry.npmjs.org"

- name: Install Dependencies
run: yarn install

- name: Build
run: yarn build

- name: Determine NPM Tag
id: determine-npm-tag
run: |
VERSION_TAG=${GITHUB_REF#refs/tags/v}
if [[ $VERSION_TAG == *"-"* ]]; then
echo ::set-output name=NPM_TAG::${VERSION_TAG#*-}
else
echo ::set-output name=NPM_TAG::latest
fi
env:
GITHUB_REF: ${{ github.ref }}

- name: Publish to NPM
run:
yarn publish --new-version ${GITHUB_REF#refs/tags/v} --tag ${{
steps.determine-npm-tag.outputs.NPM_TAG }} --no-git-tag-version
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_REF: ${{ github.ref }}
16 changes: 16 additions & 0 deletions .github/workflows/semantic-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: "Semantic PR"
on:
pull_request_target:
types:
- opened
- edited
- synchronize

jobs:
main:
name: Validate PR title
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
node_modules
.env
coverage
coverage.json
typechain
dist
.DS_Store

# Hardhat files
cache
artifacts

access_token
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
# create-universal-contract
# create-universal-contract

CLI tool for creating universal smart contracts on ZetaChain

```
yarn create universal-contract
```
60 changes: 60 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"name": "create-universal-contract",
"version": "0.0.6",
"description": "CLI tool for creating universal smart contracts on ZetaChain",
"main": "index.js",
"bin": {
"create-universal-contract": "./dist/index.js"
},
"scripts": {
"build": "yarn tsc",
"lint:fix": "npm run lint:js:fix",
"lint:js:fix": "eslint --ext .js,.ts . --fix",
"lint:js": "eslint --ext .js,.ts .",
"lint": "npm run lint:js",
"main": "npx tsx src/index.ts"
},
"repository": {
"type": "git",
"url": "git+https://github.com/zeta-chain/create-universal-contract.git"
},
"files": [
"dist"
],
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"bugs": {
"url": "https://github.com/zeta-chain/create-universal-contract/issues"
},
"homepage": "https://github.com/zeta-chain/create-universal-contract#readme",
"dependencies": {
"clear": "^0.1.0",
"commander": "^13.1.0",
"fs-extra": "^11.3.0",
"inquirer": "^12.3.2",
"marked": "^15.0.6",
"marked-terminal": "^7.2.1",
"node-fetch": "^3.3.2",
"simple-git": "^3.27.0"
},
"devDependencies": {
"@types/clear": "^0.1.4",
"@types/fs-extra": "^11.0.4",
"@types/marked-terminal": "^6.1.1",
"@typescript-eslint/eslint-plugin": "^5.59.0",
"@typescript-eslint/parser": "^8.21.0",
"eslint": "^8.42.0",
"eslint-config-prettier": "^10.0.1",
"eslint-import-resolver-typescript": "^3.7.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^5.2.3",
"eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-sort-keys-fix": "^1.1.2",
"eslint-plugin-typescript-sort-keys": "^3.3.0",
"prettier": "^3.4.2",
"typescript": "^5.7.3"
}
}
36 changes: 36 additions & 0 deletions src/cloneRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import fs from "fs-extra";
import simpleGit from "simple-git";

export const cloneRepository = async (
repoUrl: string,
tempDir: string,
branchName: string,
options: any,
isVerbose: boolean,
) => {
const ONE_DAY_IN_MS = 24 * 60 * 60 * 1000;

const shouldClone = async () => {
if (!fs.existsSync(tempDir)) return true;

const stats = await fs.stat(tempDir);
const lastModified = new Date(stats.mtime).getTime();
const now = Date.now();

return now - lastModified > ONE_DAY_IN_MS;
};

if (!options.cache || (await shouldClone())) {
if (fs.existsSync(tempDir)) {
if (isVerbose) console.log("Removing cached repository...");
await fs.remove(tempDir);
}

if (isVerbose) console.log(`Cloning repository (branch: ${branchName})...`);
const git = simpleGit();
await git.clone(repoUrl, tempDir, ["--branch", branchName, "--depth=1"]);
if (isVerbose) console.log("Repository cloned successfully.");
} else {
if (isVerbose) console.log("Using cached repository. Skipping clone.");
}
};
60 changes: 60 additions & 0 deletions src/copyExample.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { select } from "@inquirer/prompts";
import fs from "fs-extra";
import { marked } from "marked";
import { markedTerminal } from "marked-terminal";
import path from "path";

marked.use(markedTerminal() as any);

export const copyExample = async (
chosenExample: string,
examplesDir: string,
outputDir: string,
isVerbose: boolean,
) => {
const sourceDir = path.join(examplesDir, chosenExample);

const isOutputDirJustName =
!path.isAbsolute(outputDir) && !outputDir.includes(path.sep);

const targetDir = isOutputDirJustName
? path.resolve(process.cwd(), outputDir)
: path.isAbsolute(outputDir)
? outputDir
: path.resolve(process.cwd(), outputDir);

const finalTargetDir = isOutputDirJustName
? path.join(targetDir)
: path.join(targetDir, chosenExample);

if (fs.existsSync(finalTargetDir)) {
const overwrite = await select({
choices: [
{ name: "Yes, overwrite it", value: true },
{ name: "No, cancel the operation", value: false },
],
message: `The directory "${finalTargetDir}" already exists. Do you want to overwrite it?`,
});

if (!overwrite) {
console.log("Operation canceled. No files were copied.");
return;
}

if (isVerbose)
console.log(`Removing existing directory: ${finalTargetDir}...`);
await fs.remove(finalTargetDir);
}

if (isVerbose) console.log(`Copying example to ${finalTargetDir}...`);
await fs.copy(sourceDir, finalTargetDir);

console.log(`\nCreated ${finalTargetDir}\n`);
if (isVerbose) console.log(`Successfully created "${chosenExample}".`);

const readmePath = path.join(finalTargetDir, "README.md");
if (fs.existsSync(readmePath)) {
const readmeContent = await fs.readFile(readmePath, "utf-8");
console.log(marked(readmeContent));
}
};
27 changes: 27 additions & 0 deletions src/getExampleDirectories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import fs from "fs-extra";
import path from "path";

export const getExampleDirectories = async (examplesDir: string) => {
const entries = fs.readdirSync(examplesDir, { withFileTypes: true });
const directories = entries.filter((entry) => entry.isDirectory());

if (directories.length === 0) {
throw new Error("No examples found in the examples directory.");
}

const examples = await Promise.all(
directories.map(async (dir) => {
const packageJsonPath = path.join(examplesDir, dir.name, "package.json");
let description = "No description available.";

if (fs.existsSync(packageJsonPath)) {
const packageJson = await fs.readJson(packageJsonPath);
description = packageJson.description || description;
}

return { description, name: dir.name };
}),
);

return examples;
};
Loading

0 comments on commit 65bcdb7

Please sign in to comment.