From 1479a9dbd8f94b926faaf9e713da29cb9fab6963 Mon Sep 17 00:00:00 2001 From: Karsa Date: Tue, 28 Feb 2023 17:24:17 +0100 Subject: [PATCH] Fixes `pre-commit` git hook to ensure the optimisation of staged icons (#958) * testing * Fixes pre-commit hook * Removing checkIcons from pre commit hook because it might result in false positives and negatives on an unclean local repository * Added checkIcons Github action --------- Co-authored-by: Karsa --- .githooks/pre-commit | 4 --- .github/actions/check-icons.yml | 41 +++++++++++++++++++++++++++++ .husky/pre-commit | 5 ++++ category.schema.json | 2 +- package.json | 8 ++---- scripts/checkIconsAndCategories.mjs | 5 ++-- scripts/optimizeStagedSvgs.mjs | 5 ++-- scripts/optimizeSvgs.mjs | 2 +- scripts/render/processSvg.mjs | 22 +++++++++------- 9 files changed, 69 insertions(+), 25 deletions(-) delete mode 100755 .githooks/pre-commit create mode 100644 .github/actions/check-icons.yml create mode 100755 .husky/pre-commit diff --git a/.githooks/pre-commit b/.githooks/pre-commit deleted file mode 100755 index 3a113353c..000000000 --- a/.githooks/pre-commit +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -pnpm run checkIcons -exit $? diff --git a/.github/actions/check-icons.yml b/.github/actions/check-icons.yml new file mode 100644 index 000000000..c32f22fe4 --- /dev/null +++ b/.github/actions/check-icons.yml @@ -0,0 +1,41 @@ +name: "Check icons" +description: "Cross-checks icon and category references in JSON descriptors" + +inputs: + name: + description: “Name of the package” + required: true + +runs: + using: "composite" + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 16 + + - uses: pnpm/action-setup@v2.0.1 + name: Install pnpm + id: pnpm-install + with: + version: 7 + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + run: | + echo "::set-output name=pnpm_cache_dir::$(pnpm store path)" + + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} + key: ${{ runner.os }}-lucide-preact-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-lucide-preact-pnpm-store- + + - name: Install dependencies + run: pnpm install --filter . + + - name: Check icons and categories + run: pnpm checkIcons diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 000000000..0675e2802 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,5 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +pnpm lint-staged +pnpm checkIcons diff --git a/category.schema.json b/category.schema.json index 20f0921b3..fa21ca809 100644 --- a/category.schema.json +++ b/category.schema.json @@ -20,7 +20,7 @@ "type": "string" }, "icon": { - "$ref": "#/$defs/types/icon-reference" + "type": "string" }, "weight": { "type": "integer" diff --git a/package.json b/package.json index 9a284d61a..ff44baeb4 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "categories2icons": "node scripts/migrateCategoriesToIcons.mjs --presets @babel/env", "generate:changelog": "node ./scripts/generateChangelog.mjs", "postinstall": "husky install", - "lint": "eslint --ext .ts,.js,.mjs ./{packages/lucide,scripts}" + "lint": "eslint --ext .ts,.js,.mjs ./{packages/lucide,scripts}", + "prepare": "husky install" }, "devDependencies": { "eslint": "^8.26.0", @@ -40,11 +41,6 @@ "svgo": "^3.0.0", "svgson": "^5.2.1" }, - "husky": { - "hooks": { - "pre-commit": "lint-staged" - } - }, "lint-staged": { "icons/*.svg": "node ./scripts/optimizeStagedSvgs.mjs" }, diff --git a/scripts/checkIconsAndCategories.mjs b/scripts/checkIconsAndCategories.mjs index 8c55cd561..ff7018b5c 100644 --- a/scripts/checkIconsAndCategories.mjs +++ b/scripts/checkIconsAndCategories.mjs @@ -7,7 +7,7 @@ const icons = readAllMetadata(ICONS_DIR); const CATEGORIES_DIR = path.resolve(currentDir, '../categories'); const categories = readAllMetadata(CATEGORIES_DIR); -console.log(`Read all icons`); +console.log('Reading all icons') const svgFiles = readSvgDirectory(ICONS_DIR); const iconNames = svgFiles.map(icon => icon.split('.')[0]); @@ -47,5 +47,6 @@ Object.keys(categories).forEach(categoryName => { }); if (error) { - throw new Error('At least one error in icon JSONs prevents from committing changes.'); + console.error('At least one error in icon JSONs prevents from committing changes.'); + process.exit(1); } diff --git a/scripts/optimizeStagedSvgs.mjs b/scripts/optimizeStagedSvgs.mjs index 9ae6989c9..265acdb6c 100644 --- a/scripts/optimizeStagedSvgs.mjs +++ b/scripts/optimizeStagedSvgs.mjs @@ -1,10 +1,11 @@ import fs from 'fs'; import processSvg from './render/processSvg.mjs'; -const svgFiles = process.argv.slice(4); +const svgFiles = process.argv.slice(2); svgFiles.forEach(async (svgFile) => { + console.log('Optimizing staged SVG file:', svgFile) const content = fs.readFileSync(svgFile); - const svg = await processSvg(content); + const svg = await processSvg(content, svgFile); fs.writeFileSync(svgFile, svg, 'utf-8'); }); diff --git a/scripts/optimizeSvgs.mjs b/scripts/optimizeSvgs.mjs index 04312bf23..bbe508250 100644 --- a/scripts/optimizeSvgs.mjs +++ b/scripts/optimizeSvgs.mjs @@ -11,5 +11,5 @@ const svgFiles = readSvgDirectory(ICONS_DIR); svgFiles.forEach((svgFile) => { const content = fs.readFileSync(path.join(ICONS_DIR, svgFile)); - processSvg(content).then((svg) => writeSvgFile(svgFile, ICONS_DIR, svg)); + processSvg(content, svgFile).then((svg) => writeSvgFile(svgFile, ICONS_DIR, svg)); }); diff --git a/scripts/render/processSvg.mjs b/scripts/render/processSvg.mjs index 6880bf777..dce979711 100644 --- a/scripts/render/processSvg.mjs +++ b/scripts/render/processSvg.mjs @@ -1,6 +1,6 @@ -import { optimize } from 'svgo'; +import {optimize} from 'svgo'; import prettier from 'prettier'; -import { parseSync, stringify } from 'svgson'; +import {parseSync, stringify} from 'svgson'; import DEFAULT_ATTRS from './default-attrs.json' assert { type: 'json' }; /** @@ -8,8 +8,9 @@ import DEFAULT_ATTRS from './default-attrs.json' assert { type: 'json' }; * @param {string} svg - An SVG string. * @returns {Promise} An optimized svg */ -async function optimizeSvg(svg) { +async function optimizeSvg(svg, path) { const result = optimize(svg, { + path, plugins: [ { name: 'preset-default', @@ -17,12 +18,15 @@ async function optimizeSvg(svg) { overrides: { convertShapeToPath: false, mergePaths: false, - removeAttrs: { - attrs: '(fill|stroke.*)', - }, }, }, }, + { + name: 'removeAttrs', + params: { + attrs: '(fill|stroke.*)', + } + } ], }); @@ -47,12 +51,12 @@ function setAttrs(svg) { * @param {string} svg An SVG string. * @returns {Promise} An optimized svg */ -function processSvg(svg) { +function processSvg(svg, path) { return ( - optimizeSvg(svg) + optimizeSvg(svg, path) .then(setAttrs) .then((optimizedSvg) => - prettier.format(optimizedSvg, { parser: 'babel' }), + prettier.format(optimizedSvg, {parser: 'babel'}), ) // remove semicolon inserted by prettier // because prettier thinks it's formatting JSX not HTML