Skip to content

Commit

Permalink
init verify schema github action
Browse files Browse the repository at this point in the history
  • Loading branch information
Manh Cao authored and Manh Cao committed Sep 16, 2024
1 parent 6b2a7f3 commit 4fe5526
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/combine-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
git config --global user.name "$GIT_USERNAME"
git config --global user.email "$GIT_EMAIL"
git add config.json
git commit -m "Merge JSON files"
git diff-index --quiet HEAD || git commit -m "Merge JSON files"
git push
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
41 changes: 41 additions & 0 deletions .github/workflows/validate-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Validate configuration files

on:
push:
branches:
- '**'

jobs:
merge_json_files:
runs-on: ubuntu-latest

if: github.ref != 'refs/heads/main'

steps:
- name: Checkout HEAD (current branch)
uses: actions/checkout@v4
with:
fetch-depth: 1 # Fetch only the latest commit of the current branch

- name: Save HEAD commit SHA
id: head
run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV

- name: Checkout main branch
run: |
git fetch origin main --depth=1 # Fetch only the latest commit of main
git checkout FETCH_HEAD
echo "MAIN_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '20' # Or your preferred version

- name: Calculate changed folders
run: |
echo "CHANGED_FOLDERS=$$(git diff --name-only $MAIN_SHA $HEAD_SHA -- 'protocols/*' | grep '^protocols/' | xargs -L1 dirname | sed 's|protocols/||' | sort -u)" >> $GITHUB_ENV
- name: Validate
run: |
node validate-config.js
2 changes: 1 addition & 1 deletion protocols/protocol-name-1/config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "Protocol Name 1",
"name": "Protocol Name 1 abc",
"icon": "logo.svg",
"metadata": {
"pt": [
Expand Down
2 changes: 1 addition & 1 deletion protocols/protocol-name-2/config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "Protocol Name 2",
"name": "Protocol Name 2 abc",
"icon": "logo.jpeg",
"metadata": {
"pt": [
Expand Down
99 changes: 99 additions & 0 deletions validate-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
const fs = require('fs');
const path = require('path');

const CHANGED_PROTOCOLS = process.env.CHANGED_PROTOCOLS;

function isValidEthereumAddress(address) {
const ethereumAddressPattern = /^0x[a-fA-F0-9]{40}$/;
return ethereumAddressPattern.test(address);
}

async function main() {
if (!CHANGED_PROTOCOLS) {
console.log('No changed protocols');
return;
}

const protocols = CHANGED_PROTOCOLS.split('\n');

console.log('Currently validating protocols:', protocols);

protocols.forEach((protocol) => validateConfig(protocol));
}

function validateConfig(protocol) {
const protocolsPath = path.join(__dirname, 'protocols');
const configPath = path.join(protocolsPath, protocol, 'config.json');

if (!fs.existsSync(configPath)) {
throw new Error(`protocol ${protocol}: config.json not found`);
}

const protocolConfigStr = fs.readFileSync(configPath, 'utf8');
const protocolConfig = JSON.parse(protocolConfigStr);

if (typeof protocolConfig !== 'object'){
throw new Error(`protocol ${protocol}: config is not an object`);
}

const {name, icon, metadata} = protocolConfig;

if (!mustBeNonEmptyString(name)) {
throw new Error(`protocol ${protocol}: invalid field 'name'`);
}

if (!mustBeNonEmptyString(icon)) {
throw new Error(`protocol ${protocol}: invalid field 'icon'`);
}

if (typeof metadata !== 'object') {
throw new Error(`protocol ${protocol}: invalid field 'metadata'`);
}

const iconPath = path.join(protocolsPath, protocol, icon);
if (!fs.existsSync(iconPath)) {
throw new Error(`protocol ${protocol}: icon path not found for protocol ${icon}`);
}

const {pt, yt, lp} = metadata;
checkMetadataField(pt, protocol, 'pt');
checkMetadataField(yt, protocol, 'yt');
checkMetadataField(lp, protocol, 'lp');
}

function mustBeNonEmptyString(str) {
return typeof str === 'string' && str.trim() !== '';
}

function checkMetadataField(data, protocol, field) {
if (data === null || data === undefined) {
return;
}

if (!Array.isArray(data)) {
throw new Error(`protocol ${protocol}: metadata ${field} must be an array`)
}

for (let index = 0; index < data.length; index ++) {
const item = data[index];
const {chainId, address, description, integrationUrl} = item;

if (typeof chainId !== 'number') {
throw new Error(`protocol ${protocol}: metadata ${field} invalid 'chainId' field at index ${index}`);
}

if (!mustBeNonEmptyString(address) || !isValidEthereumAddress(address)) {
throw new Error(`protocol ${protocol}: metadata ${field} invalid 'address' field at index ${index}`);
}

if (!mustBeNonEmptyString(description)) {
throw new Error(`protocol ${protocol}: metadata ${field} invalid 'description' field at index ${index}`);
}

if (!mustBeNonEmptyString(integrationUrl)) {
throw new Error(`protocol ${protocol}: metadata ${field} invalid 'integrationUrl' field at index ${index}`);
}
}
}

void main()

0 comments on commit 4fe5526

Please sign in to comment.