Skip to content

Commit

Permalink
refactor: Update coverage script to use --ir-minimum flag
Browse files Browse the repository at this point in the history
  • Loading branch information
Aboudjem committed May 29, 2024
1 parent c213617 commit 030a281
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 105 deletions.
38 changes: 37 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,40 @@ jobs:
console.log("Slither report is empty. No comment will be posted.");
return;
}
await script({ github, context, header, body })
await script({ github, context, header, body })
gas_report:
needs: setup
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/[email protected]

- name: Cache node modules
uses: actions/cache@v4
with:
path: |
**/node_modules
key: ${{ needs.setup.outputs.cache-key }}

- name: Generate gas report
run: yarn run gas-report

- name: Commit and push gas report
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git add gas_report.md
git commit -m "Update gas report" || echo "No changes to gas report"
git push origin HEAD:${{ github.event.pull_request.head.ref }}
- name: Post gas report comment
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gas_report=$(cat gas_report.md)
curl -s -H "Authorization: token $GITHUB_TOKEN" -X POST \
-d "{\"body\":\"## Gas Report\n\n${gas_report}\"}" \
"https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments"
41 changes: 41 additions & 0 deletions .github/workflows/generate-gas-report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Generate Gas Report

on:
pull_request:
types: [opened, synchronize]

jobs:
generate-gas-report:
runs-on: ubuntu-latest

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

- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: "16"

- name: Install dependencies
run: yarn install

- name: Generate gas report
run: yarn run gas-report

- name: Commit and push gas report
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git add gas_report.md
git commit -m "Update gas report" || echo "No changes to gas report"
git push origin HEAD:${{ github.event.pull_request.head.ref }}
- name: Post gas report comment
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gas_report=$(cat gas_report.md)
curl -s -H "Authorization: token $GITHUB_TOKEN" -X POST \
-d "{\"body\":\"## Gas Report\n\n${gas_report}\"}" \
"https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments"
210 changes: 107 additions & 103 deletions scripts/foundry/generateGasReport.js
Original file line number Diff line number Diff line change
@@ -1,121 +1,125 @@
const fs = require('fs');
const readline = require('readline');
const { exec } = require('child_process');
const fs = require("fs");
const readline = require("readline");
const { exec } = require("child_process");

// Define the log file and the output markdown file
const LOG_FILE = 'gas.log';
const OUTPUT_FILE = 'gas_report.md';
const LOG_FILE = "gas.log";
const OUTPUT_FILE = "gas_report.md";

// Function to execute the `forge test` command
function runForgeTest() {
return new Promise((resolve, reject) => {
console.log('🚀 Running forge tests, this may take a few minutes...');
exec('forge test -vv --mt test_Gas > gas.log', (error, stdout, stderr) => {
if (error) {
console.error(`❌ Exec error: ${error}`);
reject(`exec error: ${error}`);
}
console.log('✅ Forge tests completed.');
resolve(stdout ? stdout : stderr);
});
return new Promise((resolve, reject) => {
console.log("🚀 Running forge tests, this may take a few minutes...");
exec("forge test -vv --mt test_Gas > gas.log", (error, stdout, stderr) => {
if (error) {
console.error(`❌ Exec error: ${error}`);
reject(`exec error: ${error}`);
}
console.log("✅ Forge tests completed.");
resolve(stdout ? stdout : stderr);
});
});
}

// Function to parse the log file and generate the report
async function generateReport() {
await runForgeTest();

const fileStream = fs.createReadStream(LOG_FILE);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});

const results = [];

console.log('📄 Parsing log file, please wait...');
for await (const line of rl) {
console.log(line);
if (line.includes('::')) {
const parts = line.split('::');
const PROTOCOL = parts[0];
const ACTION_FUNCTION = parts[1];
let ACCOUNT_TYPE;
let IS_DEPLOYED;
if (line.includes('EOA')) {
ACCOUNT_TYPE = 'EOA';
IS_DEPLOYED = 'False';
} else if (line.includes('Nexus')) {
ACCOUNT_TYPE = 'Smart Account';
IS_DEPLOYED = 'True';
} else {
ACCOUNT_TYPE = 'Smart Account';
IS_DEPLOYED = 'False';
}

const WITH_PAYMASTER = line.includes('WithPaymaster') ? 'True' : 'False';

const GAS_INFO = parts[4];
const ACCESS_TYPE = GAS_INFO.split(': ')[0];
const GAS_USED = GAS_INFO.split(': ')[1];

let RECEIVER_ACCESS;
if (ACCESS_TYPE === 'ColdAccess') {
RECEIVER_ACCESS = '🧊 ColdAccess';
} else if (ACCESS_TYPE === 'WarmAccess') {
RECEIVER_ACCESS = '🔥 WarmAccess';
} else {
RECEIVER_ACCESS = 'N/A';
}

results.push({
PROTOCOL,
ACTION_FUNCTION,
ACCOUNT_TYPE,
IS_DEPLOYED,
WITH_PAYMASTER,
RECEIVER_ACCESS,
GAS_USED,
FULL_LOG: line.trim()
});
}
await runForgeTest();

const fileStream = fs.createReadStream(LOG_FILE);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity,
});

const results = [];

console.log("📄 Parsing log file, please wait...");
for await (const line of rl) {
console.log(line);
if (line.includes("::")) {
const parts = line.split("::");
const PROTOCOL = parts[0];
const ACTION_FUNCTION = parts[1];
let ACCOUNT_TYPE;
let IS_DEPLOYED;
if (line.includes("EOA")) {
ACCOUNT_TYPE = "EOA";
IS_DEPLOYED = "False";
} else if (line.includes("Nexus")) {
ACCOUNT_TYPE = "Smart Account";
IS_DEPLOYED = "True";
} else {
ACCOUNT_TYPE = "Smart Account";
IS_DEPLOYED = "False";
}

const WITH_PAYMASTER = line.includes("WithPaymaster") ? "True" : "False";

const GAS_INFO = parts[4];
const ACCESS_TYPE = GAS_INFO.split(": ")[0];
const GAS_USED = GAS_INFO.split(": ")[1];

let RECEIVER_ACCESS;
if (ACCESS_TYPE === "ColdAccess") {
RECEIVER_ACCESS = "🧊 ColdAccess";
} else if (ACCESS_TYPE === "WarmAccess") {
RECEIVER_ACCESS = "🔥 WarmAccess";
} else {
RECEIVER_ACCESS = "N/A";
}

results.push({
PROTOCOL,
ACTION_FUNCTION,
ACCOUNT_TYPE,
IS_DEPLOYED,
WITH_PAYMASTER,
RECEIVER_ACCESS,
GAS_USED,
FULL_LOG: line.trim(),
});
}

console.log('🔄 Sorting results...');
// Custom sort: Group by protocol alphabetically, then by EOA first, Smart Account with Is Deployed=True next, then the rest
results.sort((a, b) => {
if (a.PROTOCOL < b.PROTOCOL) return -1;
if (a.PROTOCOL > b.PROTOCOL) return 1;
if (a.ACCOUNT_TYPE === 'EOA' && b.ACCOUNT_TYPE !== 'EOA') return -1;
if (a.ACCOUNT_TYPE !== 'EOA' && b.ACCOUNT_TYPE === 'EOA') return 1;
if (a.IS_DEPLOYED === 'True' && b.IS_DEPLOYED !== 'True') return -1;
if (a.IS_DEPLOYED !== 'True' && b.IS_DEPLOYED === 'True') return 1;
return 0;
});

console.log('🖋️ Writing report...');
// Write the report
const outputStream = fs.createWriteStream(OUTPUT_FILE);
outputStream.write("# Gas Report\n");
outputStream.write("| **Protocol** | **Actions / Function** | **Account Type** | **Is Deployed** | **With Paymaster?** | **Receiver Access** | **Gas Used** | **Full Log** |\n");
outputStream.write("|:------------:|:---------------------:|:----------------:|:--------------:|:-------------------:|:-------------------:|:------------:|:-------------:|\n");

results.forEach(result => {
outputStream.write(`| ${result.PROTOCOL} | ${result.ACTION_FUNCTION} | ${result.ACCOUNT_TYPE} | ${result.IS_DEPLOYED} | ${result.WITH_PAYMASTER} | ${result.RECEIVER_ACCESS} | ${result.GAS_USED} | ${result.FULL_LOG} |\n`);
});

console.log(`📊 Gas report generated and saved to ${OUTPUT_FILE}`);
}

console.log("🔄 Sorting results...");
// Custom sort: Group by protocol alphabetically, then by EOA first, Smart Account with Is Deployed=True next, then the rest
results.sort((a, b) => {
if (a.PROTOCOL < b.PROTOCOL) return -1;
if (a.PROTOCOL > b.PROTOCOL) return 1;
if (a.ACCOUNT_TYPE === "EOA" && b.ACCOUNT_TYPE !== "EOA") return -1;
if (a.ACCOUNT_TYPE !== "EOA" && b.ACCOUNT_TYPE === "EOA") return 1;
if (a.IS_DEPLOYED === "True" && b.IS_DEPLOYED !== "True") return -1;
if (a.IS_DEPLOYED !== "True" && b.IS_DEPLOYED === "True") return 1;
return 0;
});

console.log("🖋️ Writing report...");
// Write the report
const outputStream = fs.createWriteStream(OUTPUT_FILE);
outputStream.write("# Gas Report\n");
outputStream.write(
"| **Protocol** | **Actions / Function** | **Account Type** | **Is Deployed** | **With Paymaster?** | **Receiver Access** | **Gas Used** | **Full Log** |\n",
);
outputStream.write(
"|:------------:|:---------------------:|:----------------:|:--------------:|:-------------------:|:-------------------:|:------------:|:-------------:|\n",
);

results.forEach((result) => {
outputStream.write(
`| ${result.PROTOCOL} | ${result.ACTION_FUNCTION} | ${result.ACCOUNT_TYPE} | ${result.IS_DEPLOYED} | ${result.WITH_PAYMASTER} | ${result.RECEIVER_ACCESS} | ${result.GAS_USED} | ${result.FULL_LOG} |\n`,
);
});

console.log(`📊 Gas report generated and saved to ${OUTPUT_FILE}`);
}

// Function to clean up temporary files
function cleanUp() {
fs.unlink(LOG_FILE, (err) => {
if (err) console.error(`❌ Error deleting ${LOG_FILE}: ${err}`);
else console.log(`🗑️ ${LOG_FILE} deleted successfully.`);
});
fs.unlink(LOG_FILE, (err) => {
if (err) console.error(`❌ Error deleting ${LOG_FILE}: ${err}`);
else console.log(`🗑️ ${LOG_FILE} deleted successfully.`);
});
}

// Run the function to generate the report and then clean up
generateReport()
.then(cleanUp)
.catch(console.error);
generateReport().then(cleanUp).catch(console.error);
2 changes: 1 addition & 1 deletion scripts/foundry/generate_coverage_report.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash

# Generate lcov.info
forge coverage --report lcov
forge coverage --ir-minimum --report lcov

# Install lcov if not installed
if ! command -v lcov &>/dev/null; then
Expand Down

0 comments on commit 030a281

Please sign in to comment.