mirror of
https://github.com/lucide-icons/lucide.git
synced 2026-11-13 13:48:26 +00:00
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
This commit is contained in:
@@ -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/<svg[^>]*>/<svg>/g' | # remove attributes from svg element
|
||||
base64 -w 0 | # encode svg
|
||||
sed "s|.*|<img title=\"$file\" alt=\"$file\" src=\"https://lucide.dev/api/gh-icon/dpi/24/&.svg\"/> |"
|
||||
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/<svg[^>]*>/<svg>/g' | # remove attributes from svg element
|
||||
base64 -w 0 | # encode svg
|
||||
sed "s|.*|<img title=\"$file\" alt=\"$file\" src=\"https://lucide.dev/api/gh-icon/stroke-width/2/&.svg\"/> |"
|
||||
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/<svg[^>]*>/<svg>/g' | # remove attributes from svg element
|
||||
base64 -w 0 | # encode svg
|
||||
sed "s|.*|<img title=\"$file\" alt=\"$file\" src=\"https://lucide.dev/api/gh-icon/stroke-width/2/&.svg\"/> |"
|
||||
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/<svg[^>]*>/<svg>/g' | # remove attributes from svg element
|
||||
base64 -w 0 | # encode svg
|
||||
sed "s|.*|<img title=\"$file\" alt=\"$file\" src=\"https://lucide.dev/api/gh-icon/stroke-width/1/&.svg\"/> |"
|
||||
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/<svg[^>]*>/<svg>/g' | # remove attributes from svg element
|
||||
base64 -w 0 | # encode svg
|
||||
sed "s|.*|<img title=\"$file\" alt=\"$file\" src=\"https://lucide.dev/api/gh-icon/stroke-width/2/&.svg\"/> |"
|
||||
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/<svg[^>]*>/<svg>/g' | # remove attributes from svg element
|
||||
base64 -w 0 | # encode svg
|
||||
sed "s|.*|<img title=\"$file\" alt=\"$file\" src=\"https://lucide.dev/api/gh-icon/stroke-width/3/&.svg\"/> |"
|
||||
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/<svg[^>]*>/<svg>/g' | # remove attributes from svg element
|
||||
base64 -w 0 | # encode svg
|
||||
sed "s|.*|<img width=\"400\" title=\"$file\" alt=\"$file\" src=\"https://lucide.dev/api/gh-icon/$(basename ${file//\.svg/})/&.svg\"/> |"
|
||||
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 }}<br/>
|
||||
<details>
|
||||
<summary>Preview cohesion</summary>
|
||||
${{ needs.generate-changed-icons-comment-data.outputs.generate-cohesion-check-squares }}<br/>
|
||||
${{ needs.generate-changed-icons-comment-data.outputs.generate-2px-stroke-width }}<br/>
|
||||
${{ needs.generate-changed-icons-comment-data.outputs.generate-cohesion-check-random }}<br/>
|
||||
</details>
|
||||
<details>
|
||||
<summary>Preview stroke widths</summary>
|
||||
${{ needs.generate-changed-icons-comment-data.outputs.generate-1px-stroke-width }}<br/>
|
||||
${{ needs.generate-changed-icons-comment-data.outputs.generate-2px-stroke-width }}<br/>
|
||||
${{ needs.generate-changed-icons-comment-data.outputs.generate-3px-stroke-width }}<br/>
|
||||
</details>
|
||||
<details>
|
||||
<summary>DPI Preview (24px)</summary>
|
||||
${{ needs.generate-changed-icons-comment-data.outputs.generate-24px-dpi-preview }}
|
||||
</details>
|
||||
<details>
|
||||
<summary>Icon X-rays</summary>
|
||||
${{ needs.generate-changed-icons-comment-data.outputs.generate-x-rays }}
|
||||
</details>
|
||||
body-path: ./comment-markup.md
|
||||
edit-mode: replace
|
||||
|
||||
@@ -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(/<svg[^>]*>/, '<svg>')
|
||||
.replaceAll(/\n| {2}|\t/g, '');
|
||||
|
||||
const base64 = Buffer.from(strippedAttrsSVG).toString('base64');
|
||||
const url = getBaseUrl(file);
|
||||
const widthAttr = width ? `width="${width}"` : '';
|
||||
|
||||
return `<img title="${file}" alt="${file}" ${widthAttr} src="${url}/${base64}.svg"/>`;
|
||||
})
|
||||
.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}
|
||||
<details>
|
||||
<summary>Preview cohesion</summary>
|
||||
${cohesionSquaresImageTags}<br/>
|
||||
${changeFiles2pxStrokeImageTags}<br/>
|
||||
${cohesionRandomImageTags}<br/>
|
||||
</details>
|
||||
<details>
|
||||
<summary>Preview stroke widths</summary>
|
||||
${changeFiles1pxStrokeImageTags}<br/>
|
||||
${changeFiles2pxStrokeImageTags}<br/>
|
||||
${changeFiles3pxStrokeImageTags}<br/>
|
||||
</details>
|
||||
<details>
|
||||
<summary>DPI Preview (24px)</summary>
|
||||
${changeFilesLowDPIImageTags}<br/>
|
||||
</details>
|
||||
<details>
|
||||
<summary>Icon X-rays</summary>
|
||||
${changeFilesXRayImageTags}
|
||||
</details>
|
||||
`;
|
||||
|
||||
console.log(commentMarkup);
|
||||
+23
-5
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user