Skip to content

Commit

Permalink
chore: Add cli docs linter (farcasterxyz#1353)
Browse files Browse the repository at this point in the history
  • Loading branch information
adityapk00 authored Sep 7, 2023
1 parent efd1bff commit aac4220
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 46 deletions.
5 changes: 5 additions & 0 deletions .changeset/perfect-spoons-serve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@farcaster/hubble": patch
---

chore: Add cli options documentation linter
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ jobs:
# - name: Run audit
# run: yarn audit

- name: Run build
run: yarn build

- name: Run linter
run: yarn lint:ci

Expand Down
42 changes: 42 additions & 0 deletions apps/hubble/scripts/clidocs.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const { execSync } = require("child_process");
const fs = require("fs");
const path = require("path");

module.exports = function clidocs() {
const docFileName = "www/docs/docs/cli.md";

try {
const helpOutput = execSync("node --no-warnings build/cli.js start --help").toString();

const optionNames = [];
const regex = /--\w+(-\w+)*/g;
let match;

// rome-ignore lint/suspicious/noAssignInExpressions: <explanation>
while ((match = regex.exec(helpOutput)) !== null) {
optionNames.push(match[0]);
}

// Step 2: Read the contents of the cli.md file
const cliDocPath = path.resolve(__dirname, "..", docFileName);
const cliDocContent = fs.readFileSync(cliDocPath, "utf-8");

// Step 3: Check that each option name appears in the cli.md file
let anyError = false;
optionNames.forEach((optionName) => {
if (!cliDocContent.includes(optionName)) {
console.warn(`Documentation for option "${optionName}" is missing in ${docFileName}`);
anyError = true;
}
});

if (anyError) {
process.exit(1);
} else {
console.log("✨ CLI docs are up to date");
}
} catch (error) {
console.error("Error executing command:", error);
process.exit(1);
}
};
55 changes: 55 additions & 0 deletions apps/hubble/scripts/grafanadash.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* This is a custom linter that checks for the presence of a "datasource" property
* in the Grafana dashboard JSON file. If the property is present, it must be set
* to "Graphite". This is to ensure that the dashboard is not using any other
* datasource.
*
* It runs as a part of "yarn lint"
*/

const fs = require("fs");
const path = require("path");

module.exports = function grafana() {
const filePath = path.join(__dirname, "../grafana/grafana-dashboard.json");

function checkDataSource(lineArray) {
let lineNumber = 0;

for (const line of lineArray) {
lineNumber++;

// Check if the current line contains the undesired datasource entry
if (line.includes('"datasource":') && !line.replaceAll(" ", "").includes('"datasource":"Graphite"')) {
return lineNumber;
}
}

return null;
}

return new Promise((resolve, reject) => {
fs.readFile(filePath, "utf-8", (err, data) => {
if (err) {
console.error(`Error reading ${filePath}:`, err);
process.exit(1);
}

// Split the content into lines
const lineArray = data.split("\n");
const errorLine = checkDataSource(lineArray);

if (errorLine !== null) {
console.error(`line ${errorLine}: ${lineArray[errorLine - 1]}`);
console.error(`Error: "datasource" has to be "Graphite"`);
console.error(`Replace with: "datasource": "Graphite"`);
console.error(`Error: ${filePath}`);

process.exit(1);
} else {
console.log("✨ Grafana Dashboard linter passed");
resolve();
}
});
});
};
56 changes: 13 additions & 43 deletions apps/hubble/scripts/linter.cjs
Original file line number Diff line number Diff line change
@@ -1,50 +1,20 @@
/**
* This is a custom linter that checks for the presence of a "datasource" property
* in the Grafana dashboard JSON file. If the property is present, it must be set
* to "Graphite". This is to ensure that the dashboard is not using any other
* datasource.
* Custom linters for Hubble. There are some additional things we want to check
* for that are not covered by the default linters.
*
* It runs as a part of "yarn lint"
* For eg. we want to check if the Grafana dashboards are valid JSON and if the
* datasource is set to "Graphite".
*
* Add linters as .cjs files in this directory and they will be executed as a
* part of "yarn lint".
*/

const fs = require("fs");
const path = require("path");

const filePath = path.join(__dirname, "../grafana/grafana-dashboard.json");

function checkDataSource(lineArray) {
let lineNumber = 0;

for (const line of lineArray) {
lineNumber++;
async function executeAll() {
const grafana = require("./grafanadash.cjs");
await grafana();

// Check if the current line contains the undesired datasource entry
if (line.includes('"datasource":') && !line.replaceAll(" ", "").includes('"datasource":"Graphite"')) {
return lineNumber;
}
}

return null;
const clidocs = require("./clidocs.cjs");
await clidocs();
}

fs.readFile(filePath, "utf-8", (err, data) => {
if (err) {
console.error(`Error reading ${filePath}:`, err);
process.exit(1);
}

// Split the content into lines
const lineArray = data.split("\n");
const errorLine = checkDataSource(lineArray);

if (errorLine !== null) {
console.error(`line ${errorLine}: ${lineArray[errorLine - 1]}`);
console.error(`Error: "datasource" has to be "Graphite"`);
console.error(`Replace with: "datasource": "Graphite"`);
console.error(`Error: ${filePath}`);

process.exit(1);
} else {
console.log("✨ Custom linter passed");
}
});
executeAll();
2 changes: 1 addition & 1 deletion apps/hubble/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { profileGossipServer } from "./profile/gossipProfile.js";
import { initializeStatsd } from "./utils/statsd.js";
import OnChainEventStore from "./storage/stores/onChainEventStore.js";
import { startupCheck, StartupCheckStatus } from "./utils/startupCheck.js";
import { goerli, mainnet, optimism } from "viem/chains";
import { mainnet, optimism } from "viem/chains";
import { finishAllProgressBars } from "./utils/progressBars.js";
import { MAINNET_BOOTSTRAP_PEERS } from "./bootstrapPeers.mainnet.js";
import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
Expand Down
24 changes: 22 additions & 2 deletions apps/hubble/www/docs/docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Start a Hub
Hubble Options:
-n --network <network> ID of the Farcaster Network (default: 3 (devnet))
-i, --id <filepath> Path to the PeerId file.
--hub-operator-fid The FID of the hub operator. Optional.
-c, --config <filepath> Path to the config file.
--db-name <name> The name of the RocksDB instance. (default: rocks.hub._default)
--admin-server-enabled Enable the admin server. (default: disabled)
Expand All @@ -38,10 +39,27 @@ Ethereum Options:
-m, --eth-mainnet-rpc-url <url> RPC URL of a Mainnet ETH Node (or comma separated list of URLs)
-l, --l2-rpc-url <url> RPC URL of a Goerli Optimism Node (or comma separated list of URLs)
--rank-rpcs Rank the RPCs by latency/stability and use the fastest one (default: disabled)
--fname-server-url <url> The URL for the FName registry server (default: https://fnames.farcaster.xyz
--fname-server-url <url> The URL for the FName registry server (default: https://fnames.farcaster.xyz)
--fir-address <address> The address of the Farcaster ID Registry contract
--first-block <number> The block number to begin syncing events from Farcaster contracts
L2 Options:
--l2-id-registry-address The address of the L2 Farcaster ID Registry contract
--l2-key-registry-address <address> The address of the L2 Farcaster Key Registry contract
--l2-storage-registry-address <address> The address of the L2 Farcaster Storage Registry contract
--l2-resync-events Resync events from the L2 Farcaster contracts before starting (default: disabled)
--l2-first-block <number> The block number to begin syncing events from L2 Farcaster contracts
--l2-chunk-size <number> The number of events to fetch from L2 Farcaster contracts at a time
--l2-chain-id <number> The chain ID of the L2 Farcaster contracts are deployed to
--l2-rent-expiry-override <number> The storage rent expiry in seconds to use instead of the default 1 year (ONLY FOR TESTS)
Snapshots Options:
--enable-snapshot-to-s3 Enable daily snapshots to be uploaded to S3. (default: disabled)
--s3-snapshot-bucket <bucket> The S3 bucket to upload snapshots to
--disable-snapshot-sync Disable syncing from snapshots. (default: enabled)
Metrics:
--statsd-metrics-server <host> The host to send statsd metrics to, eg "127.0.0.1:8125". (default: disabled)
Networking Options:
-a, --allowed-peers <peerIds...> Only peer with specific peer ids. (default: all peers allowed)
-b, --bootstrap <peer-multiaddrs...> Peers to bootstrap gossip and sync from. (default: none)
Expand All @@ -51,6 +69,7 @@ Networking Options:
--announce-ip <ip-address> Public IP address announced to peers (default: fetched with external service)
--announce-server-name <name> Server name announced to peers, useful if SSL/TLS enabled. (default: "none")
--direct-peers <peer-multiaddrs...> A list of peers for libp2p to directly peer with (default: [])
--denied-peers <peerIds...> Do not peer with specific peer ids. (default: no peers denied)
--rpc-rate-limit <number> RPC rate limit for peers specified in rpm. Set to -1 for none. (default: 20k/min)
Debugging Options:
Expand All @@ -63,7 +82,8 @@ Debugging Options:
--commit-lock-timeout <number> Rocks DB commit lock timeout in milliseconds (default: 500)
--commit-lock-max-pending <number> Rocks DB commit lock max pending jobs (default: 1000)
--rpc-auth <username:password,...> Require username-password auth for RPC submit. (default: disabled)
--disable-console-status Immediately log to STDOUT, and disable console status and progressbars. (default: disabled)
--fnr-address <address> The address of the Farcaster Name Registry contract
-h, --help display help for command
```
Expand Down

0 comments on commit aac4220

Please sign in to comment.