Skip to content

Commit

Permalink
compile all contracts if contract name not specified (#121)
Browse files Browse the repository at this point in the history
Resolve #110
  • Loading branch information
shunsukew committed Mar 13, 2023
1 parent e891a87 commit bb10178
Show file tree
Hide file tree
Showing 3 changed files with 606 additions and 306 deletions.
113 changes: 62 additions & 51 deletions packages/cli/src/commands/contract/compile.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Args, Command, Flags } from "@oclif/core";
import path = require("node:path");
import { readdirSync } from "node:fs";
import {
moveArtifacts,
ensureSwankyProject,
Expand All @@ -10,7 +9,7 @@ import {
Spinner,
generateTypesFor,
} from "@astar-network/swanky-core";
import { writeJSON } from "fs-extra";
import { writeJSON, readdirSync, existsSync } from "fs-extra";

export class CompileContract extends Command {
static description = "Compile the smart contract(s) in your contracts directory";
Expand All @@ -24,84 +23,96 @@ export class CompileContract extends Command {
release: Flags.boolean({
default: false,
char: "r",
description:
"A production contract should always be build in `release` mode for building optimized wasm",
description: "A production contract should always be build in `release` mode for building optimized wasm"
}),
all: Flags.boolean({
default: false,
char: "a",
description: "Set all to true to compile all contracts"
})
};

static args = {
contractName: Args.string({
name: "contractName",
required: true,
required: false,
default: "",
description: "Name of the contract to compile",
}),
};

async run(): Promise<void> {
const { args, flags } = await this.parse(CompileContract);

await ensureSwankyProject();
if (args.contractName == "" && !flags.all) {
this.error("No contracts were selected to compile")
}

await ensureSwankyProject();
const config = await getSwankyConfig();

const contractInfo = config.contracts[args.contractName];
if (!contractInfo) {
this.error(`Cannot find a contract named ${args.contractName} in swanky.config.json`);
const contractNames = [];
if (flags.all) {
const contractList = readdirSync(path.resolve("contracts"), { withFileTypes: true });
for (const contract of contractList) {
if (contract.isDirectory()) {
console.log(`${contract.name} contract is found`);
contractNames.push(contract.name);
}
}
} else {
contractNames.push(args.contractName);
}

const spinner = new Spinner();

const contractList = readdirSync(path.resolve("contracts"));

const contractPath = path.resolve("contracts", args.contractName);
if (!contractList.includes(args.contractName)) {
this.error(`Path to contract ${args.contractName} does not exist: ${contractPath}`);
}

await spinner.runCommand(
async () => {
return new Promise<void>((resolve, reject) => {
const compile = getBuildCommandFor(contractInfo.language, contractPath, flags.release);
compile.stdout.on("data", () => spinner.ora.clear());
compile.stdout.pipe(process.stdout);
if (flags.verbose) {
compile.stderr.on("data", () => spinner.ora.clear());
compile.stderr.pipe(process.stdout);
}
compile.on("exit", (code) => {
if (code === 0) resolve();
else reject();
for (const contractName of contractNames) {
const contractInfo = config.contracts[contractName];
if (!contractInfo) {
this.error(`Cannot find contract info for ${contractName} contract in swanky.config.json`);
}
const contractPath = path.resolve("contracts", contractName);
if (!existsSync(contractPath)) {
this.error(`Contract folder not found at expected path`);
}

await spinner.runCommand(
async () => {
return new Promise<void>((resolve, reject) => {
const compile = getBuildCommandFor(contractInfo.language, contractPath, flags.release);
compile.stdout.on("data", () => spinner.ora.clear());
compile.stdout.pipe(process.stdout);
if (flags.verbose) {
compile.stderr.on("data", () => spinner.ora.clear());
compile.stderr.pipe(process.stdout);
}
compile.on("exit", (code) => {
if (code === 0) resolve();
else reject();
});
});
});
},
"Compiling contract",
"Contract compiled successfully"
);
},
`Compiling ${contractName} contract`,
`${contractName} Contract compiled successfully`,
);

await spinner.runCommand(
async () => await generateTypesFor(contractInfo.language, contractInfo.name, contractPath),
"Generating contract ts types",
"TS types Generated successfully"
);
await spinner.runCommand(
async () => await generateTypesFor(contractInfo.language, contractInfo.name, contractPath),
`Generating ${contractName} contract ts types`,
`${contractName} contract's TS types Generated successfully`
);

const buildData = (await spinner.runCommand(async () => {
return moveArtifacts(contractInfo.name);
}, "Moving artifacts")) as BuildData;
const buildData = (await spinner.runCommand(async () => {
return moveArtifacts(contractInfo.name);
}, "Moving artifacts")) as BuildData;

await spinner.runCommand(async () => {
contractInfo.build = buildData;
}

await spinner.runCommand(async () => {
await writeJSON(path.resolve("swanky.config.json"), config, {
spaces: 2,
});
}, "Writing config");
}
}

// https://github.com/Supercolony-net/typechain-polkadot#usage-of-typechain-compiler
interface TypechainCompilerConfig {
projectFiles: string[]; // Path to all project files, everystring in glob format
skipLinting: boolean; // Skip linting of project files
artifactsPath: string; // Path to artifacts folder, where artifacts will be stored it will save both .contract and .json (contract ABI)
typechainGeneratedPath: string; // Path to typechain generated folder
}
125 changes: 74 additions & 51 deletions packages/cli/src/commands/contract/test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
require("ts-mocha");
import { Args, Command } from "@oclif/core";
import { Command, Flags, Args } from "@oclif/core";
import path = require("node:path");
import { readdirSync } from "node:fs";
import { ensureSwankyProject, getSwankyConfig } from "@astar-network/swanky-core";
import globby from "globby";
import Mocha from "mocha";
import { ensureDir } from "fs-extra";
import { ensureDir, readdirSync } from "fs-extra";
import * as shell from "shelljs";

declare global {
Expand All @@ -18,6 +17,14 @@ export class CompileContract extends Command {
// hidden until the mocha loading issue is resolved
static hidden = true;

static flags = {
all: Flags.boolean({
default: false,
char: "a",
description: "Set all to true to compile all contracts"
})
};

static args = {
contractName: Args.string({
name: "contractName",
Expand All @@ -27,60 +34,76 @@ export class CompileContract extends Command {
};

async run(): Promise<void> {
const { args } = await this.parse(CompileContract);
const { args, flags } = await this.parse(CompileContract);

await ensureSwankyProject();

const config = await getSwankyConfig();

const contractInfo = config.contracts[args.contractName];
if (!contractInfo) {
this.error(`Cannot find a contract named ${args.contractName} in swanky.config.json`);
if (args.contractName == "" && !flags.all) {
this.error("No contracts were selected to compile")
}

const contractList = readdirSync(path.resolve("contracts"));

const contractPath = path.resolve("contracts", args.contractName);
if (!contractList.includes(args.contractName)) {
this.error(`Path to contract ${args.contractName} does not exist: ${contractPath}`);
}
await ensureSwankyProject();
const config = await getSwankyConfig();

if (!contractInfo.build) {
this.error(`Cannot find build data for ${args.contractName} contract in swanky.config.json`);
const contractNames = [];
if (flags.all) {
const contractList = readdirSync(path.resolve("contracts"), { withFileTypes: true });
for (const contract of contractList) {
if (contract.isDirectory()) {
console.log(`${contract.name} contract is found`);
contractNames.push(contract.name);
}
}
} else {
contractNames.push(args.contractName);
}
const buildData = contractInfo.build;

const reportDir = path.resolve(buildData.artifactsPath, "testReports", Date.now().toString());
await ensureDir(reportDir);

const mocha = new Mocha({
timeout: 200000,
reporter: "mochawesome",
reporterOptions: {
reportDir,
charts: true,
reportTitle: `${args.contractName} test report`,
quiet: true,
json: false,
},
});

const tests = await globby(`${path.resolve("test", args.contractName)}/*.test.ts`);

mocha.addFile;
tests.forEach((test) => {
mocha.addFile(test);
});

global.contractTypesPath = path.resolve("test", args.contractName, "typedContract");

shell.cd(`./test/${args.contractName}`);
mocha.run((failures) => {
if (failures) {
this.error(`At least one of the tests failed. Check report for details: ${reportDir}`);
} else {
this.log(`All tests passing. Check the report for details: ${reportDir}`);
const projectDir = path.resolve();
const testDir = path.resolve("test");
for (const contractName of contractNames) {
const contractInfo = config.contracts[contractName];
if (!contractInfo.build) {
this.error(`Cannot find build data for ${contractName} contract in swanky.config.json`);
}
});
const buildData = contractInfo.build;

const reportDir = path.resolve(projectDir, buildData.artifactsPath, "testReports", Date.now().toString());
await ensureDir(reportDir);

const mocha = new Mocha({
timeout: 200000,
reporter: "mochawesome",
reporterOptions: {
reportDir,
charts: true,
reportTitle: `${contractName} test report`,
quiet: true,
json: false,
},
});

const tests = await globby(`${path.resolve(testDir, contractName)}/*.test.ts`);

mocha.addFile;
tests.forEach((test) => {
mocha.addFile(test);
});

global.contractTypesPath = path.resolve(testDir, contractName, "typedContract");

shell.cd(`${testDir}/${contractName}`);
try {
await new Promise<void>((resolve, reject) => {
mocha.run((failures) => {
if (failures) {
reject(`At least one of the tests failed. Check report for details: ${reportDir}`);
} else {
this.log(`All tests passing. Check the report for details: ${reportDir}`);
resolve();
}
});
});
} catch (error) {
this.error(error as string);
}
}
}
}
Loading

0 comments on commit bb10178

Please sign in to comment.