Skip to content

deps(deps): bump lucide-react from 0.577.0 to 1.7.0 in /SortVision #39

deps(deps): bump lucide-react from 0.577.0 to 1.7.0 in /SortVision

deps(deps): bump lucide-react from 0.577.0 to 1.7.0 in /SortVision #39

name: Continuous integration
# If repo "Workflow permissions" is read-only, artifact uploads / PR comments are blocked (see workflows README).
permissions:
contents: read
actions: write # upload/download Next.js build + QA / Lighthouse artifacts
pull-requests: write
issues: write
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
pull_request:
branches: [main, master, develop]
paths-ignore:
- '**.md'
- 'issue/**'
push:
branches: [main, master, develop]
paths-ignore:
- '**.md'
- 'issue/**'
merge_group:
types: [checks_requested]
workflow_dispatch:
env:
NODE_VERSION: '24'
NEXT_PUBLIC_SITE_URL: https://www.sortvision.com
# Use Node 24 for JS-based Actions (checkout, cache, artifact, etc.) β€” silences Node 20 deprecation warnings.
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
defaults:
run:
working-directory: ./SortVision
jobs:
# One checkout + install for both checks (faster than separate Formatting + Lint jobs).
format-lint:
name: Format and lint
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 (node24 runtime; fewer forced-runtime warnings)
with:
fetch-depth: 1
- name: Setup SortVision
uses: ./.github/actions/setup-sortvision
with:
node-version: ${{ env.NODE_VERSION }}
- name: Prettier (check)
run: pnpm run format:check
- name: ESLint
run: pnpm run lint
- name: Unit tests (node:test)
run: pnpm run test:unit
# Runs in parallel with format-lint so wall time is max(static, build), not sum (update branch rules if you required separate "Formatting" / "Lint" checks).
build:
name: Build
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 (node24 runtime; fewer forced-runtime warnings)
with:
fetch-depth: 1
- name: Cache Next.js build
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
with:
path: SortVision/.next/cache
key: nextjs-${{ runner.os }}-${{ hashFiles('SortVision/pnpm-lock.yaml', 'SortVision/package.json') }}
restore-keys: nextjs-${{ runner.os }}-
- name: Setup SortVision
uses: ./.github/actions/setup-sortvision
with:
node-version: ${{ env.NODE_VERSION }}
- name: Build application
run: pnpm run build
env:
NODE_ENV: production
- name: Analyze bundle size
run: |
echo "=== Bundle Size Analysis ==="
du -sh .next/static/chunks/* 2>/dev/null | sort -h | tail -10 || echo "No chunks found"
TOTAL_SIZE=$(du -sb .next 2>/dev/null | awk '{print $1}')
TOTAL_SIZE_MB=$((TOTAL_SIZE / 1024 / 1024))
echo "Total build size: ${TOTAL_SIZE_MB}MB"
if [ "$TOTAL_SIZE_MB" -gt 50 ]; then
echo "WARNING: Build size exceeds 50MB"
fi
- name: Generate and validate sitemap
run: |
pnpm run generate-sitemap
if [ ! -f public/sitemap.xml ]; then
echo "ERROR: Sitemap generation failed"
exit 1
fi
echo "Sitemap generated: $(wc -l < public/sitemap.xml) lines"
# Tarball avoids upload-artifact v4 directory flattening (files must land under SortVision/.next for `next start`).
- name: Pack Next.js build for CI artifact
working-directory: ${{ github.workspace }}
run: |
set -euo pipefail
test -f SortVision/.next/BUILD_ID
tar czf "${RUNNER_TEMP}/next-build.tar.gz" -C SortVision .next
- name: Upload Next.js build output
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: next-build
path: ${{ runner.temp }}/next-build.tar.gz
if-no-files-found: error
retention-days: 7
test:
name: Test
needs: [build]
runs-on: ubuntu-latest
timeout-minutes: 35
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 (node24 runtime; fewer forced-runtime warnings)
with:
# Full history on PRs so git diff base...head works for the "vs main" table (push stays shallow).
fetch-depth: ${{ github.event_name == 'pull_request' && '0' || '1' }}
- name: Setup SortVision
uses: ./.github/actions/setup-sortvision
with:
node-version: ${{ env.NODE_VERSION }}
- name: Restore Next.js build from artifact
uses: ./.github/actions/restore-next-build
- name: Start production server
run: |
pnpm run start &
echo $! > .server-pid
pnpm exec wait-on http://localhost:3000 --timeout 120000
sleep 2
- name: Run complete test suite (core + extended sitemap, links, security)
id: qa_tests
run: pnpm run test:ci
env:
CI: 'true'
GITHUB_ACTIONS: 'true'
QA_COMMENT_DIR: ${{ github.event.pull_request && format('{0}/SortVision/.qa-pr-comment', github.workspace) || '' }}
PR_NUMBER: ${{ github.event.pull_request.number || '' }}
- name: Prepare QA PR comment artifact
if: github.event_name == 'pull_request' && always()
run: |
DIR="${GITHUB_WORKSPACE}/SortVision/.qa-pr-comment"
mkdir -p "$DIR"
if [ ! -s "$DIR/comment.md" ]; then
echo "No QA report on disk; writing minimal placeholder for PR comment workflow."
{
echo '<!-- sortvision-qa-report -->'
echo '### QA suite report'
echo ''
echo '**Result:** No report file was written (early failure or env issue). See **Test** job logs.'
echo ''
echo "[View run](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})"
} > "$DIR/comment.md"
fi
if [ ! -s "$DIR/pr_number.txt" ]; then
echo '${{ github.event.pull_request.number }}' > "$DIR/pr_number.txt"
fi
- name: Append main vs PR diff (tests + scripts)
if: github.event_name == 'pull_request' && always()
working-directory: ${{ github.workspace }}
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
BASE_REF: ${{ github.event.pull_request.base.ref }}
QA_COMMENT_FILE: ${{ github.workspace }}/SortVision/.qa-pr-comment/comment.md
run: node SortVision/scripts/ci-append-pr-vs-base.cjs
- name: Find previous QA comment
id: find_qa_comment
if: github.event_name == 'pull_request' && always()
uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4
with:
issue-number: ${{ github.event.pull_request.number }}
body-includes: '<!-- sortvision-qa-report -->'
- name: Post QA report to pull request
if: github.event_name == 'pull_request' && always()
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5
with:
comment-id: ${{ steps.find_qa_comment.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body-path: SortVision/.qa-pr-comment/comment.md
edit-mode: replace
- name: Upload QA PR comment artifact
if: github.event_name == 'pull_request' && always()
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: qa-pr-comment
path: SortVision/.qa-pr-comment/
include-hidden-files: true
# Mobile + desktop run in parallel (matrix); combined table + gate in lighthouse-summary.
lighthouse:
name: Lighthouse (${{ matrix.variant }})
needs: [build]
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
include:
- variant: mobile
config: lighthouserc.json
artifact: lighthouse-results-mobile
- variant: desktop
config: lighthouserc.desktop.json
artifact: lighthouse-results-desktop
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 (node24 runtime; fewer forced-runtime warnings)
with:
fetch-depth: 1
- name: Setup SortVision
uses: ./.github/actions/setup-sortvision
with:
node-version: ${{ env.NODE_VERSION }}
- name: Restore Next.js build from artifact
uses: ./.github/actions/restore-next-build
- name: Start production server
run: |
pnpm run start &
echo $! > .server-pid
pnpm exec wait-on http://localhost:3000 --timeout 120000
sleep 2
- name: Lighthouse (${{ matrix.variant }})
uses: treosh/lighthouse-ci-action@3e7e23fb74242897f95c0ba9cabad3d0227b9b18 # v12
with:
configPath: ./SortVision/${{ matrix.config }}
runs: 1
urls: |
http://localhost:3000
http://localhost:3000/algorithms/config/bubble
http://localhost:3000/es
http://localhost:3000/contributions/overview
uploadArtifacts: true
artifactName: ${{ matrix.artifact }}
temporaryPublicStorage: true
# treosh uploads GitHub artifacts before `lhci upload --target=filesystem` writes manifest.json, so the zip
# from uploadArtifacts does not include it. Upload manifest after the action for lighthouse-summary / PR comment.
- name: Upload Lighthouse manifest (for summary)
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: lighthouse-manifest-${{ matrix.variant }}
path: .lighthouseci/manifest.json
if-no-files-found: error
retention-days: 7
lighthouse-summary:
name: Lighthouse summary
needs: [lighthouse]
# always(): run after matrix success or failure (still need manifest download + gate); skip if matrix never ran.
if: ${{ always() && !cancelled() && needs.lighthouse.result != 'skipped' }}
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout repository (summary script only)
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 (node24 runtime; fewer forced-runtime warnings)
with:
fetch-depth: 1
sparse-checkout: |
SortVision/scripts/lighthouse-ci-summary.cjs
sparse-checkout-cone-mode: false
- name: Download Lighthouse manifests (mobile)
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
with:
name: lighthouse-manifest-mobile
path: SortVision/lighthouse-mobile
if-no-files-found: ignore
- name: Download Lighthouse manifests (desktop)
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
with:
name: lighthouse-manifest-desktop
path: SortVision/lighthouse-desktop
if-no-files-found: ignore
- name: Print Lighthouse scores (job summary + PR comment file)
working-directory: SortVision
env:
MANIFEST_MOBILE_PATH: ${{ github.workspace }}/SortVision/lighthouse-mobile/manifest.json
MANIFEST_DESKTOP_PATH: ${{ github.workspace }}/SortVision/lighthouse-desktop/manifest.json
LIGHTHOUSE_COMMENT_DIR: ${{ github.event.pull_request && format('{0}/SortVision/.lighthouse-pr-comment', github.workspace) || '' }}
run: node scripts/lighthouse-ci-summary.cjs
- name: Prepare Lighthouse PR comment (fallback)
if: github.event_name == 'pull_request' && always()
run: |
DIR="${GITHUB_WORKSPACE}/SortVision/.lighthouse-pr-comment"
mkdir -p "$DIR"
if [ ! -s "$DIR/comment.md" ]; then
{
echo '<!-- sortvision-lighthouse-report -->'
echo '### Lighthouse (CI)'
echo ''
echo '**Result:** Score table was not written (early failure). See **Lighthouse summary** job logs.'
echo ''
echo "[View run](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})"
} > "$DIR/comment.md"
fi
- name: Find previous Lighthouse comment
id: find_lighthouse_comment
if: github.event_name == 'pull_request' && always()
uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4
with:
issue-number: ${{ github.event.pull_request.number }}
body-includes: '<!-- sortvision-lighthouse-report -->'
- name: Post Lighthouse report to pull request
if: github.event_name == 'pull_request' && always()
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5
with:
comment-id: ${{ steps.find_lighthouse_comment.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body-path: SortVision/.lighthouse-pr-comment/comment.md
edit-mode: replace
- name: Require Lighthouse audits to pass
if: always()
run: |
echo "Lighthouse matrix: ${{ needs.lighthouse.result }}"
if [ "${{ needs.lighthouse.result }}" != "success" ]; then
echo "::error::One or more Lighthouse runs failed (see Lighthouse (mobile) / (desktop) logs and job summary)."
exit 1
fi
production-validation:
name: Production validation
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
needs: [test, lighthouse, lighthouse-summary]
timeout-minutes: 10
defaults:
run:
working-directory: ./SortVision
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 (node24 runtime; fewer forced-runtime warnings)
with:
fetch-depth: 1
- name: Setup Node.js
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Test production site
run: node tests/quality-assurance.mjs --production
- name: Validate production performance
run: |
echo "=== Production Site Health Check ==="
RESPONSE_TIME=$(curl -o /dev/null -s -w '%{time_total}' https://www.sortvision.com)
HTTP_CODE=$(curl -o /dev/null -s -w '%{http_code}' https://www.sortvision.com)
echo "HTTP Status: $HTTP_CODE"
echo "Response Time: ${RESPONSE_TIME}s"
if [ "$HTTP_CODE" != "200" ]; then
echo "ERROR: Production site returned $HTTP_CODE"
exit 1
fi
RESPONSE_MS=$(echo "$RESPONSE_TIME * 1000" | bc)
if [ "$(echo "$RESPONSE_MS > 3000" | bc)" -eq 1 ]; then
echo "WARNING: Response time exceeds 3 seconds"
fi
- name: Generate production report
if: always()
run: |
echo "## Production Validation Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Production site: https://www.sortvision.com" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Check | Result |" >> $GITHUB_STEP_SUMMARY
echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Site Accessibility | Passed |" >> $GITHUB_STEP_SUMMARY
echo "| Production Tests | Passed |" >> $GITHUB_STEP_SUMMARY
echo "| Response Time | Under 3s |" >> $GITHUB_STEP_SUMMARY