Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LF-12061 Run healthcheck on new network #985

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions .github/workflows/healthCheckForNewNetworkDeployment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
name: Health Check for New Network Deployment

# - designed to perform health checks for newly added networks
# - triggers on pull requests and first checks if the config/networks.json file was modified
# - validates that each new network has corresponding deployment and state configuration files
# - runs network-specific health checks
# - any required file is missing or a health check fails, the action exits with an error

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]

jobs:
check-new-network-health:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Check if config/networks.json was changed in this branch
id: check-file-change
run: |
if git diff --name-only origin/main...HEAD | grep -q "config/networks.json"; then
echo "config/networks.json has been modified in this branch"
echo "CONTINUE=true" >> $GITHUB_ENV
else
echo "No changes in config/networks.json detected in this branch"
echo "CONTINUE=false" >> $GITHUB_ENV
fi

- name: Detect Newly Added Networks
if: env.CONTINUE == 'true'
id: detect-changes
run: |
echo "Comparing config/networks.json with the previous commit..."
git fetch origin main --depth=1 || echo "No previous commit found."

if git show origin/main:config/networks.json > /dev/null 2>&1; then
OLD_NETWORKS=$(git show origin/main:config/networks.json | jq 'keys')
else
echo "❌ Error: No previous networks.json found. Expected existing network configuration."
exit 1
fi

NEW_NETWORKS=$(jq 'keys' config/networks.json)

ADDED_NETWORKS=$(jq -n --argjson old "$OLD_NETWORKS" --argjson new "$NEW_NETWORKS" '$new - $old')

echo "Added networks: $ADDED_NETWORKS"

if [[ "$ADDED_NETWORKS" == "[]" ]]; then
echo "No new networks detected."
echo "SKIP_CHECK=true" >> $GITHUB_ENV
else
echo "New networks detected: $ADDED_NETWORKS"
echo "added_networks=$(echo $ADDED_NETWORKS | jq -c .)" >> $GITHUB_ENV
fi

- name: Validate Network Deployment Files
if: env.CONTINUE == 'true' && env.SKIP_CHECK != 'true'
run: |
echo "Validating required files for new networks..."
for network in $(echo $added_networks | jq -r '.[]'); do
echo "🔍 Checking files for network: $network"

# Check if network exists in _targetState.json
if ! jq -e 'has("'"$network"'")' script/deploy/_targetState.json > /dev/null; then
echo "❌ Error: Network '$network' not found in script/deploy/_targetState.json"
exit 1
else
echo "✅ Confirmed: Network '$network' exists in script/deploy/_targetState.json"
fi

# Check if deployments/{network}.json file exists
if [[ ! -f "deployments/$network.json" ]]; then
echo "❌ Error: Missing deployment file: deployments/$network.json"
exit 1
else
echo "✅ Confirmed: Deployment file: deployments/$network.json exists"
fi
done

- name: Install Bun
if: env.CONTINUE == 'true' && env.SKIP_CHECK != 'true'
uses: oven-sh/setup-bun@v1
with:
bun-version: latest

- name: Install Foundry (provides cast)
if: env.CONTINUE == 'true' && env.SKIP_CHECK != 'true'
uses: foundry-rs/foundry-toolchain@v1

- name: Install dependencies
if: env.CONTINUE == 'true' && env.SKIP_CHECK != 'true'
run: bun install

- name: Run Health Checks on New Networks
if: env.CONTINUE == 'true' && env.SKIP_CHECK != 'true'
run: |
echo "Running health check for new networks..."
set -e
for network in $(echo $added_networks | jq -r '.[]'); do
echo "🔍 Checking network: $network"
if bun run script/deploy/healthCheck.ts --network "$network"; then
echo "✅ $network is fine."
else
echo "❌ Health check failed for $network. Exiting..."
exit 1
fi
done
72 changes: 41 additions & 31 deletions script/deploy/healthCheck.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-nocheck
import { consola } from 'consola'
import { $, spinner } from 'zx'
import { $ } from 'zx'
Copy link
Contributor

Choose a reason for hiding this comment

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

do we need to add zx to our package.json?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

zx is already in our dependencies in package.json

"zx": "^8.2.2"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

feel free to resolve

import { defineCommand, runMain } from 'citty'
import * as path from 'path'
import * as fs from 'fs'
Expand All @@ -24,8 +24,6 @@ import { coreFacets, pauserWallet } from '../../config/global.json'

const SAFE_THRESHOLD = 3

const louperCmd = 'louper-cli'

const corePeriphery = [
'ERC20Proxy',
'Executor',
Expand All @@ -48,26 +46,8 @@ const main = defineCommand({
},
},
async run({ args }) {
if ((await $`${louperCmd}`.exitCode) !== 0) {
const answer = await consola.prompt(
'Louper CLI is required but not installed. Would you like to install it now?',
{
type: 'confirm',
}
)
if (answer) {
await spinner(
'Installing...',
() => $`npm install -g @mark3labs/louper-cli`
)
} else {
consola.error('Louper CLI is required to run this script')
process.exit(1)
}
}

const { network } = args
const deployedContracts = await import(
const { default: deployedContracts } = await import(
`../../deployments/${network.toLowerCase()}.json`
)
const targetStateJson = await import(
Expand Down Expand Up @@ -161,16 +141,43 @@ const main = defineCommand({

let registeredFacets: string[] = []
try {
const facetsResult =
await $`${louperCmd} inspect diamond -a ${diamondAddress} -n ${network} --json`
registeredFacets = JSON.parse(facetsResult.stdout).facets.map(
(f: { name: string }) => f.name
)
if (networksConfig[network.toLowerCase()].rpcUrl) {
const rpcUrl: string = networksConfig[network.toLowerCase()].rpcUrl
const facetsResult =
await $`cast call ${diamondAddress} "facets() returns ((address,bytes4[])[])" --rpc-url ${rpcUrl}`
const rawString = facetsResult.stdout

const jsonCompatibleString = rawString
.replace(/\(/g, '[')
.replace(/\)/g, ']')
.replace(/0x[0-9a-fA-F]+/g, '"$&"')

const onChainFacets = JSON.parse(jsonCompatibleString)

if (Array.isArray(onChainFacets)) {
// mapping on-chain facet addresses to names in config
const configFacetsByAddress = Object.fromEntries(
Object.entries(deployedContracts).map(([name, address]) => {
return [address.toLowerCase(), name]
})
)

const onChainFacetAddresses = onChainFacets.map(([address]) =>
address.toLowerCase()
)

const configuredFacetAddresses = Object.keys(configFacetsByAddress)

registeredFacets = onChainFacets.map(([address]) => {
return configFacetsByAddress[address.toLowerCase()]
})
}
} else {
throw new Error('Failed to get rpc from network config file')
}
} catch (error) {
consola.warn(
'Unable to parse louper output - skipping facet registration check'
)
consola.debug('Error:', error)
consola.warn('Unable to parse output - skipping facet registration check')
consola.warn('Error:', error)
}

for (const facet of [...coreFacets, ...nonCoreFacets]) {
Expand Down Expand Up @@ -531,6 +538,7 @@ const main = defineCommand({
finish()
} else {
logError('No dexs configured')
finish()
}
},
})
Expand Down Expand Up @@ -592,8 +600,10 @@ const checkIsDeployed = async (
const finish = () => {
if (errors.length) {
consola.error(`${errors.length} Errors found in deployment`)
process.exit(1)
} else {
consola.success('Deployment checks passed')
process.exit(0)
}
}

Expand Down
Loading