Skip to content

Commit

Permalink
feat(gas-reporter): allow gas-reporter to parse stdin (#1688)
Browse files Browse the repository at this point in the history
  • Loading branch information
alvrs committed Oct 3, 2023
1 parent f99e889 commit 4385c5a
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 12 deletions.
12 changes: 12 additions & 0 deletions .changeset/silver-dolls-shave.md
@@ -0,0 +1,12 @@
---
"@latticexyz/gas-report": minor
---

Allow the `gas-report` CLI to parse logs via `stdin`, so it can be used with custom test commands (e.g. `mud test`).

Usage:

```sh
# replace `forge test -vvv` with the custom test command
GAS_REPORTER_ENABLED=true forge test -vvv | pnpm gas-report --stdin
```
49 changes: 37 additions & 12 deletions packages/gas-report/ts/index.ts
Expand Up @@ -31,6 +31,7 @@ type Options = {
path: string[];
save?: string;
compare?: string;
stdin?: boolean;
};

type GasReportEntry = {
Expand All @@ -52,20 +53,25 @@ const commandModule: CommandModule<Options, Options> = {
return yargs.options({
save: { type: "string", desc: "Save the gas report to a file" },
compare: { type: "string", desc: "Compare to an existing gas report" },
stdin: {
type: "boolean",
desc: "Parse the gas report logs from stdin instead of running an internal test command",
},
});
},

async handler({ save, compare }) {
async handler(options) {
let gasReport: GasReport;
try {
gasReport = await runGasReport();
gasReport = await runGasReport(options);
} catch (error) {
console.error(error);
setTimeout(() => process.exit());
return;
}

// If this gas report should be compared to an existing one, load the existing one
let { compare } = options;
if (compare) {
try {
const compareGasReport: GasReport = JSON.parse(readFileSync(compare, "utf8"));
Expand All @@ -84,35 +90,40 @@ const commandModule: CommandModule<Options, Options> = {
printGasReport(gasReport, compare);

// Save gas report to file if requested
if (save) saveGasReport(gasReport, save);
if (options.save) saveGasReport(gasReport, options.save);

process.exit(0);
},
};

export default commandModule;

async function runGasReport(): Promise<GasReport> {
async function runGasReport(options: Options): Promise<GasReport> {
console.log("Running gas report");
const gasReport: GasReport = [];

// Extract the logs from the child process
let stdout: string;
let logs: string;
try {
// Run the generated file using forge
const child = execa("forge", ["test", "-vvv"], {
stdio: ["inherit", "pipe", "inherit"],
env: { GAS_REPORTER_ENABLED: "true" },
});
stdout = (await child).stdout;
if (options.stdin) {
// Read the logs from stdin
logs = await readStdIn();
} else {
// Run the default test command to capture the logs
const child = execa("forge", ["test", "-vvv"], {
stdio: ["inherit", "pipe", "inherit"],
env: { GAS_REPORTER_ENABLED: "true" },
});
logs = (await child).stdout;
}
} catch (error: any) {
console.log(error.stdout ?? error);
console.log(chalk.red("\n-----------\nError while running the gas report (see above)"));
throw error;
}

// Extract the gas reports from the logs
const lines = stdout.split("\n").map(stripAnsi);
const lines = logs.split("\n").map(stripAnsi);
const gasReportPattern = /^\s*GAS REPORT: (\d+) (.*)$/;
const testFunctionPattern = /^\[(?:PASS|FAIL).*\] (\w+)\(\)/;
const testFilePattern = /^Running \d+ tests? for (.*):(.*)$/;
Expand Down Expand Up @@ -191,3 +202,17 @@ function saveGasReport(gasReport: GasReport, path: string) {
console.log(chalk.bold(`Saving gas report to ${path}`));
writeFileSync(path, `${JSON.stringify(gasReport, null, 2)}\n`);
}

function readStdIn(): Promise<string> {
return new Promise((resolve) => {
let data = "";

process.stdin.on("data", (chunk) => {
data += chunk;
});

process.stdin.on("end", () => {
resolve(data);
});
});
}

1 comment on commit 4385c5a

@vercel
Copy link

@vercel vercel bot commented on 4385c5a Oct 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.