Skip to content

Commit

Permalink
chore: improve workflow (#455)
Browse files Browse the repository at this point in the history
### Description

<!--
Summary of change.
Example: Add sepolia chain
-->

Improve the workflow a bit with separating validation and optimization:
- Separate SVG validation and optimization
- Refactor files by making the access to get files path easier
- Add workflow for validation of files 

PD: still need to change optimization workflow to run on (probably)
every commit to main

### Backward compatibility

<!--
Are these changes backward compatible? Note that additions are backwards
compatible.

Yes/No
-->
Yes

### Testing

<!--
Have any new metadata configs and deployment addresses been used with
any Hyperlane tooling, such as the CLI?
-->
Manual
  • Loading branch information
Xaroz authored Dec 30, 2024
1 parent 36b4c5f commit fac1e34
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 90 deletions.
5 changes: 5 additions & 0 deletions .changeset/fresh-turkeys-grow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperlane-xyz/registry': patch
---

Improve CI workflow by separating concerns
2 changes: 1 addition & 1 deletion .github/workflows/optimize-svg.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
fi
- name: setup-node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 20

Expand Down
45 changes: 45 additions & 0 deletions .github/workflows/validate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: validate-files

on:
push:
branches: ["main"]
pull_request:
# Allows you to run this workflow manually
workflow_dispatch:

jobs:
validate-files:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: |
**/node_modules
.yarn/cache
key: ${{ runner.os }}-yarn-cache-${{ hashFiles('./yarn.lock') }}

- name: yarn-install
run: |
yarn install
CHANGES=$(git status -s)
if [[ ! -z $CHANGES ]]; then
echo "Changes found: $CHANGES"
git diff
exit 1
fi
- name: setup-node
uses: actions/setup-node@v4
with:
node-version: 20

- name: validate-file-path
run: |
node ./scripts/validate-file-path.js
- name: validate-svg
run: |
node ./scripts/validate-svg.js
92 changes: 3 additions & 89 deletions scripts/optimize-svg.js
Original file line number Diff line number Diff line change
@@ -1,95 +1,10 @@
import fs from 'fs';
import path from 'path';
import { optimize } from 'svgo';
import { getFilePaths } from './utils.js';

const directories = ['./chains', './deployments'];
const MAX_FILE_SIZE = 100 * 1024; // 100KBs
const RASTER_IMAGE_REGEX = /<image[^>]*>/i;

const invalidNameSVGs = [];
const invalidSizeSVGs = [];
const rasterImgSVGs = [];

function isValidSvg(filePath) {
const fileName = path.basename(filePath);
const stats = fs.statSync(filePath);
const fileSize = (stats.size / 1024).toFixed(2);

if (!fileName.endsWith('logo.svg')) {
invalidNameSVGs.push(filePath);
}

if (stats.size > MAX_FILE_SIZE) {
invalidSizeSVGs.push({ filePath, fileSize: `${fileSize}KBs` });
}

const fileContent = fs.readFileSync(filePath, 'utf8');
if (RASTER_IMAGE_REGEX.test(fileContent)) {
rasterImgSVGs.push(filePath);
}
}

// Finds all svgs, validates and return all paths found that has svgs
function findAndValidateSVGs(directory) {
const files = fs.readdirSync(directory);

return files.flatMap((file) => {
const fullPath = path.join(directory, file);
const stats = fs.statSync(fullPath);

if (stats.isDirectory()) {
return findAndValidateSVGs(fullPath); // Recurse into subdirectories
} else if (path.extname(fullPath) === '.svg') {
isValidSvg(fullPath);
return fullPath;
}

return [];
});
}

// Get all svg paths that are validated
function getSVGPaths() {
return directories
.filter((directory) => {
if (fs.existsSync(directory)) {
console.log(`Checking directory: ${directory}`);
return true;
} else {
console.log(`Directory does not exist: ${directory}`);
return false;
}
})
.flatMap((directory) => findAndValidateSVGs(directory));
}

function validateErrors() {
const errorCount = invalidNameSVGs.length + invalidSizeSVGs.length + rasterImgSVGs.length;
if (errorCount === 0) return;

console.error(`Number of errors found: ${errorCount}`);

if (invalidNameSVGs.length > 0) {
console.error(
"Error: Files do not end with 'logo.svg' in the following paths:",
invalidNameSVGs,
);
}

if (invalidSizeSVGs.length > 0) {
console.error('Error: Files size exceed 100KBs in:', invalidSizeSVGs);
}

if (rasterImgSVGs.length > 0) {
console.error(
'Error: Files contain an <image> tag, likely embedding a raster image in the following paths:',
rasterImgSVGs,
);
}

process.exit(1);
}
// Optimize svg in given path
// Optimize svg in given paths
function optimizeSVGs(svgPaths) {
svgPaths.forEach((filePath) => {
try {
Expand Down Expand Up @@ -122,8 +37,7 @@ function optimizeSVGs(svgPaths) {
}

function main() {
const svgPaths = getSVGPaths();
validateErrors();
const svgPaths = getFilePaths(directories, ['.svg']);
optimizeSVGs(svgPaths);
}

Expand Down
34 changes: 34 additions & 0 deletions scripts/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import fs from 'fs';
import path from 'path';

function findFiles(directory, fileTypes = [], isRecursive = true) {
const files = fs.readdirSync(directory);

return files.flatMap((file) => {
const fullPath = path.join(directory, file);
const stats = fs.statSync(fullPath);

if (stats.isDirectory() && isRecursive) {
return findFiles(fullPath, fileTypes); // Recurse into subdirectories
} else if (fileTypes.includes(path.extname(fullPath))) {
return fullPath;
}

return [];
});
}

// Get all fille paths for given directories and given file types
export function getFilePaths(directories = [], fileTypes = [], isRecursive = true) {
return directories
.filter((directory) => {
if (fs.existsSync(directory)) {
console.log(`Checking directory: ${directory}`);
return true;
} else {
console.log(`Directory does not exist: ${directory}`);
return false;
}
})
.flatMap((directory) => findFiles(directory, fileTypes, isRecursive));
}
24 changes: 24 additions & 0 deletions scripts/validate-file-path.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { getFilePaths } from './utils.js';

const directories = [
{ paths: ['./src'], recursive: true },
{ paths: ['./'], recursive: false },
];

const fileExtensions = ['.svg', '.yaml'];

function main() {
const invalidFilesPaths = directories.flatMap((directory) =>
getFilePaths(directory.paths, fileExtensions, directory.recursive),
);

if (invalidFilesPaths.length === 0) return;

console.error(
'Error: invalid file paths found, make sure they are in the proper directories (chains or deployments):',
invalidFilesPaths,
);
process.exit(1);
}

main();
69 changes: 69 additions & 0 deletions scripts/validate-svg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import fs from 'fs';
import path from 'path';
import { getFilePaths } from './utils.js';

const directories = ['./chains', './deployments'];
const MAX_FILE_SIZE = 100 * 1024; // 100KBs
const RASTER_IMAGE_REGEX = /<image[^>]*>/i;

const invalidNameSVGs = [];
const invalidSizeSVGs = [];
const rasterImgSVGs = [];

function isValidSvg(filePath) {
const fileName = path.basename(filePath);
const stats = fs.statSync(filePath);
const fileSize = (stats.size / 1024).toFixed(2);

if (!fileName.endsWith('logo.svg')) {
invalidNameSVGs.push(filePath);
}

if (stats.size > MAX_FILE_SIZE) {
invalidSizeSVGs.push({ filePath, fileSize: `${fileSize}KBs` });
}

const fileContent = fs.readFileSync(filePath, 'utf8');
if (RASTER_IMAGE_REGEX.test(fileContent)) {
rasterImgSVGs.push(filePath);
}
}

function validateErrors() {
const errorCount = invalidNameSVGs.length + invalidSizeSVGs.length + rasterImgSVGs.length;
if (errorCount === 0) return;

console.error(`Number of errors found: ${errorCount}`);

if (invalidNameSVGs.length > 0) {
console.error(
"Error: Files do not end with 'logo.svg' in the following paths:",
invalidNameSVGs,
);
}

if (invalidSizeSVGs.length > 0) {
console.error('Error: Files size exceed 100KBs in:', invalidSizeSVGs);
}

if (rasterImgSVGs.length > 0) {
console.error(
'Error: Files contain an <image> tag, likely embedding a raster image in the following paths:',
rasterImgSVGs,
);
}

process.exit(1);
}

function validateSvgs(paths = []) {
paths.forEach((path) => isValidSvg(path));
validateErrors();
}

function main() {
const svgPaths = getFilePaths(directories, ['.svg']);
validateSvgs(svgPaths);
}

main();

0 comments on commit fac1e34

Please sign in to comment.