From 05f209cb04cdc0c9339f1686ff9aee10f72d487b Mon Sep 17 00:00:00 2001 From: Eric Fennis Date: Sun, 7 Jan 2024 15:59:33 +0100 Subject: [PATCH] Fix icon preview comment workflow (#1775) * Add helpers * fix preview script * refactor markup to javascript * test * Add escaping * Try alternative escaping * test comment markup * update comment markup * Revert comment markup step * revert escaping * Test with markup file instead of GITHUB_OUTPUT var --- .github/workflows/pull-request.yml | 168 ++---------------- scripts/generateChangedIconsCommentMarkup.mjs | 98 ++++++++++ scripts/helpers.mjs | 28 ++- 3 files changed, 135 insertions(+), 159 deletions(-) create mode 100644 scripts/generateChangedIconsCommentMarkup.mjs diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 19924b755..1def57c29 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -6,6 +6,7 @@ on: - 'icons/*.svg' branches: - main + - fix-icon-preview jobs: lint-contributors: @@ -46,184 +47,43 @@ jobs: # Example for the previous substitution # input: +++ b/icons/accessibility.json%0A@@ -2,0 +3 @@%0A+ "contributors": ["hi"],%0A@@ -13 +14 @@%0A+}%0A # output: ::$ANNOTATION_SEVERITY file=icons/accessibility.json,line=2,endLine=3,title=$ANNOTATION_TITLE::$ANNOTATION_DESCRIPTION%0A%0A+ "contributors": ["hi"],%0A@@ -13 +14 @@%0A+}%0A - # - name: Fail if contributors have changed - # run: git diff --exit-code -- icons/*.json - generate-changed-icons-comment-data: - if: github.repository == 'lucide-icons/lucide' + generate-changed-icons-comment: runs-on: ubuntu-latest permissions: contents: read - outputs: - generate-1px-stroke-width: ${{ steps.generate-1px-stroke-width.outputs.body }} - generate-2px-stroke-width: ${{ steps.generate-2px-stroke-width.outputs.body }} - generate-3px-stroke-width: ${{ steps.generate-3px-stroke-width.outputs.body }} - generate-24px-dpi-preview: ${{ steps.generate-24px-dpi-preview.outputs.body }} - generate-cohesion-check-random: ${{ steps.generate-cohesion-check-random.outputs.body }} - generate-cohesion-check-squares: ${{ steps.generate-cohesion-check-squares.outputs.body }} - generate-x-rays: ${{ steps.generate-x-rays.outputs.body }} + pull-requests: write steps: - uses: actions/checkout@v4 with: fetch-depth: 0 ref: refs/pull/${{ github.event.pull_request.number }}/merge + - name: Get changed files id: changed-files uses: tj-actions/changed-files@v41 with: files: icons/*.svg - - name: Generate 24px dpi preview - id: generate-24px-dpi-preview - env: - CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} - run: | - delimiter="$(openssl rand -hex 8)" - echo "body<<$delimiter" >> $GITHUB_OUTPUT - while IFS= read -r file; do - cat "$file" | # get file content - tr '\n' ' ' | # remove line breaks - sed -e 's/]*>//g' | # remove attributes from svg element - base64 -w 0 | # encode svg - sed "s|.*|\"$file\" |" - done <<< "$CHANGED_FILES" | tr '\n' ' ' >> $GITHUB_OUTPUT - echo >> $GITHUB_OUTPUT - echo "$delimiter" >> $GITHUB_OUTPUT - - name: Generate cohesion check random - id: generate-cohesion-check-random - env: - CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} - run: | - delimiter="$(openssl rand -hex 8)" - echo "body<<$delimiter" >> $GITHUB_OUTPUT - for file in $(printf "%s\\n" icons/*.svg | shuf | head -n$(awk -F' ' '{print NF}' <<< '${{ steps.changed-files.outputs.all_changed_files }}')); do - cat "$file" | # get file content - tr '\n' ' ' | # remove line breaks - sed -e 's/]*>//g' | # remove attributes from svg element - base64 -w 0 | # encode svg - sed "s|.*|\"$file\" |" - done <<< "$CHANGED_FILES" | tr '\n' ' ' >> $GITHUB_OUTPUT - echo >> $GITHUB_OUTPUT - echo "$delimiter" >> $GITHUB_OUTPUT - - name: Generate cohesion check squares - id: generate-cohesion-check-squares - env: - CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} - run: | - delimiter="$(openssl rand -hex 8)" - echo "body<<$delimiter" >> $GITHUB_OUTPUT - for file in $(printf "%s\\n" icons/*square*.svg | shuf | head -n$(awk -F' ' '{print NF}' <<< '${{ steps.changed-files.outputs.all_changed_files }}')); do - cat "$file" | # get file content - tr '\n' ' ' | # remove line breaks - sed -e 's/]*>//g' | # remove attributes from svg element - base64 -w 0 | # encode svg - sed "s|.*|\"$file\" |" - done <<< "$CHANGED_FILES" | tr '\n' ' ' >> $GITHUB_OUTPUT - echo >> $GITHUB_OUTPUT - echo "$delimiter" >> $GITHUB_OUTPUT - - name: Generate 1px stroke-width - id: generate-1px-stroke-width - env: - CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} - run: | - delimiter="$(openssl rand -hex 8)" - echo "body<<$delimiter" >> $GITHUB_OUTPUT - while IFS= read -r file; do - cat "$file" | # get file content - tr '\n' ' ' | # remove line breaks - sed -e 's/]*>//g' | # remove attributes from svg element - base64 -w 0 | # encode svg - sed "s|.*|\"$file\" |" - done <<< "$CHANGED_FILES" | tr '\n' ' ' >> $GITHUB_OUTPUT - echo >> $GITHUB_OUTPUT - echo "$delimiter" >> $GITHUB_OUTPUT - - name: Generate 2px stroke-width - id: generate-2px-stroke-width - env: - CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} - run: | - delimiter="$(openssl rand -hex 8)" - echo "body<<$delimiter" >> $GITHUB_OUTPUT - while IFS= read -r file; do - cat "$file" | # get file content - tr '\n' ' ' | # remove line breaks - sed -e 's/]*>//g' | # remove attributes from svg element - base64 -w 0 | # encode svg - sed "s|.*|\"$file\" |" - done <<< "$CHANGED_FILES" | tr '\n' ' ' >> $GITHUB_OUTPUT - echo >> $GITHUB_OUTPUT - echo "$delimiter" >> $GITHUB_OUTPUT - - name: Generate 3px stroke-width - id: generate-3px-stroke-width - run: | - delimiter="$(openssl rand -hex 8)" - echo "body<<$delimiter" >> $GITHUB_OUTPUT - while IFS= read -r file; do - cat "$file" | # get file content - tr '\n' ' ' | # remove line breaks - sed -e 's/]*>//g' | # remove attributes from svg element - base64 -w 0 | # encode svg - sed "s|.*|\"$file\" |" - done <<< "$CHANGED_FILES" | tr '\n' ' ' >> $GITHUB_OUTPUT - echo >> $GITHUB_OUTPUT - echo "$delimiter" >> $GITHUB_OUTPUT - - name: Generate X-rays - id: generate-x-rays - env: - CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} - run: | - delimiter="$(openssl rand -hex 8)" - echo "body<<$delimiter" >> $GITHUB_OUTPUT - while IFS= read -r file; do - cat "$file" | # get file content - tr '\n' ' ' | # remove line breaks - sed -e 's/]*>//g' | # remove attributes from svg element - base64 -w 0 | # encode svg - sed "s|.*|\"$file\" |" - done <<< "$CHANGED_FILES" | tr '\n' ' ' >> $GITHUB_OUTPUT - echo >> $GITHUB_OUTPUT - echo "$delimiter" >> $GITHUB_OUTPUT - add-changed-icons-comment: - if: github.repository == 'lucide-icons/lucide' - runs-on: ubuntu-latest - permissions: - pull-requests: write - needs: [generate-changed-icons-comment-data] - steps: - name: Find Comment uses: peter-evans/find-comment@v2 - id: fc + id: pr-comment with: issue-number: ${{ github.event.pull_request.number }} comment-author: 'github-actions[bot]' body-includes: Added or changed icons + + - name: Generate comment markup + run: node ./scripts/generateChangedIconsCommentMarkup.mjs >> comment-markup.md + id: comment-markup + env: + CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} + - name: Create or update comment uses: peter-evans/create-or-update-comment@v3 with: - comment-id: ${{ steps.fc.outputs.comment-id }} + comment-id: ${{ steps.pr-comment.outputs.comment-id }} issue-number: ${{ github.event.pull_request.number }} - body: | - ### Added or changed icons - ${{ needs.generate-changed-icons-comment-data.outputs.generate-2px-stroke-width }}
-
- Preview cohesion - ${{ needs.generate-changed-icons-comment-data.outputs.generate-cohesion-check-squares }}
- ${{ needs.generate-changed-icons-comment-data.outputs.generate-2px-stroke-width }}
- ${{ needs.generate-changed-icons-comment-data.outputs.generate-cohesion-check-random }}
-
-
- Preview stroke widths - ${{ needs.generate-changed-icons-comment-data.outputs.generate-1px-stroke-width }}
- ${{ needs.generate-changed-icons-comment-data.outputs.generate-2px-stroke-width }}
- ${{ needs.generate-changed-icons-comment-data.outputs.generate-3px-stroke-width }}
-
-
- DPI Preview (24px) - ${{ needs.generate-changed-icons-comment-data.outputs.generate-24px-dpi-preview }} -
-
- Icon X-rays - ${{ needs.generate-changed-icons-comment-data.outputs.generate-x-rays }} -
+ body-path: ./comment-markup.md edit-mode: replace diff --git a/scripts/generateChangedIconsCommentMarkup.mjs b/scripts/generateChangedIconsCommentMarkup.mjs new file mode 100644 index 000000000..593bf037d --- /dev/null +++ b/scripts/generateChangedIconsCommentMarkup.mjs @@ -0,0 +1,98 @@ +import fs from 'fs'; +import path from 'path'; +import { shuffle, readSvgDirectory, getCurrentDirPath } from './helpers.mjs'; + +const currentDir = getCurrentDirPath(import.meta.url); +const ICONS_DIR = path.resolve(currentDir, '../icons'); +const BASE_URL = 'https://lucide.dev/api/gh-icon'; + +const changedFilesPathString = process.env.CHANGED_FILES; + +const changedFiles = changedFilesPathString + .split(' ') + .map((file) => file.replace('.json', '.svg')) + .filter((file, idx, arr) => arr.indexOf(file) === idx); + +const getImageTagsByFiles = (files, getBaseUrl, width) => + files + .map((file) => { + const svgContent = fs.readFileSync(path.join(process.cwd(), file), 'utf-8'); + const strippedAttrsSVG = svgContent + .replace(/]*>/, '') + .replaceAll(/\n| {2}|\t/g, ''); + + const base64 = Buffer.from(strippedAttrsSVG).toString('base64'); + const url = getBaseUrl(file); + const widthAttr = width ? `width="${width}"` : ''; + + return `${file}`; + }) + .join(''); + +const svgFiles = readSvgDirectory(ICONS_DIR).map((file) => `icons/${file}`); + +const iconsFilteredByName = (search) => svgFiles.filter((file) => file.includes(search)); + +const cohesionRandomImageTags = getImageTagsByFiles( + shuffle(svgFiles).slice(0, changedFiles.length), + () => `${BASE_URL}/stroke-width/2`, +); + +const cohesionSquaresImageTags = getImageTagsByFiles( + shuffle(iconsFilteredByName('square')).slice(0, changedFiles.length), + () => `${BASE_URL}/stroke-width/2`, +); + +const changeFiles1pxStrokeImageTags = getImageTagsByFiles( + changedFiles, + () => `${BASE_URL}/stroke-width/1`, +); + +const changeFiles2pxStrokeImageTags = getImageTagsByFiles( + changedFiles, + () => `${BASE_URL}/stroke-width/2`, +); + +const changeFiles3pxStrokeImageTags = getImageTagsByFiles( + changedFiles, + () => `${BASE_URL}/stroke-width/3`, +); + +const changeFilesLowDPIImageTags = getImageTagsByFiles(changedFiles, () => `${BASE_URL}/dpi/24`); + +const changeFilesXRayImageTags = getImageTagsByFiles( + changedFiles, + (file) => { + const iconName = path.basename(file, '.svg'); + + return `${BASE_URL}/${iconName}`; + }, + 400, +); + +const commentMarkup = `\ +### Added or changed icons +${changeFiles2pxStrokeImageTags} +
+Preview cohesion +${cohesionSquaresImageTags}
+${changeFiles2pxStrokeImageTags}
+${cohesionRandomImageTags}
+
+
+Preview stroke widths +${changeFiles1pxStrokeImageTags}
+${changeFiles2pxStrokeImageTags}
+${changeFiles3pxStrokeImageTags}
+
+
+DPI Preview (24px) +${changeFilesLowDPIImageTags}
+
+
+Icon X-rays +${changeFilesXRayImageTags} +
+`; + +console.log(commentMarkup); diff --git a/scripts/helpers.mjs b/scripts/helpers.mjs index e0cfc0f8f..214d5763e 100644 --- a/scripts/helpers.mjs +++ b/scripts/helpers.mjs @@ -90,12 +90,13 @@ export const writeFileIfNotExists = (content, fileName, outputDirectory) => { * @returns {object} A map of icon or category metadata */ export const readAllMetadata = (directory) => - fs.readdirSync(directory).filter((file) => path.extname(file) === '.json').reduce( - (acc, fileName, i) => { + fs + .readdirSync(directory) + .filter((file) => path.extname(file) === '.json') + .reduce((acc, fileName, i) => { acc[path.basename(fileName, '.json')] = readMetadata(fileName, directory); return acc; - }, {} - ); + }, {}); /** * Reads metadata for an icon or category @@ -111,7 +112,7 @@ export const readMetadata = (fileName, directory) => * reads the icon directory * * @param {string} directory - * @returns {array} An array of file paths containig svgs + * @returns {array} An array of file paths containing svgs */ export const readSvgDirectory = (directory, fileExtension = '.svg') => fs.readdirSync(directory).filter((file) => path.extname(file) === fileExtension); @@ -189,4 +190,21 @@ export const mergeArrays = (a, b) => { return a; }; +/** + * @param {string} currentPath + * @returns {string} + */ export const getCurrentDirPath = (currentPath) => path.dirname(fileURLToPath(currentPath)); + +/** + * @param {array} array + * @returns {array} + */ +export const shuffle = (array) => { + // eslint-disable-next-line no-plusplus + for (let i = array.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [array[i], array[j]] = [array[j], array[i]]; + } + return array; +};