Lighthouse CI #216
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Lighthouse CI | |
| on: | |
| workflow_run: | |
| workflows: ["pages-deploy"] | |
| types: | |
| - completed | |
| jobs: | |
| build-and-get-urls: | |
| if: ${{ github.event.workflow_run.conclusion == 'success' }} | |
| runs-on: ubuntu-latest | |
| outputs: | |
| urls: ${{ steps.get_urls.outputs.urls }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Setup Hugo | |
| uses: peaceiris/actions-hugo@v3 | |
| with: | |
| hugo-version: "latest" # Or your specific Hugo version | |
| extended: true | |
| - name: Build site | |
| run: hugo --minify | |
| - name: List public directory (for debugging) | |
| run: ls -R public | |
| - name: Install yq (for parsing XML) | |
| run: sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq && sudo chmod +x /usr/bin/yq | |
| - name: Extract URLs from sitemap | |
| id: get_urls | |
| run: | | |
| SITEMAP_PATH="public/sitemap.xml" | |
| BASE_URL="https://isaaclins.com" # Your website's base URL | |
| if [ -f "$SITEMAP_PATH" ]; then | |
| # Extract URLs, ensure they are absolute, and create a JSON array string | |
| URLS=$(yq -p=xml -o=json '.urlset.url[].loc' "$SITEMAP_PATH" | jq -r --arg BASE_URL "$BASE_URL" 'if type == "array" then .[] else . end | if test("^/") then $BASE_URL + . else . end' | jq -R . | jq -s -c .) | |
| echo "Found URLs: $URLS" | |
| echo "urls=$URLS" >> $GITHUB_OUTPUT | |
| else | |
| echo "sitemap.xml not found at $SITEMAP_PATH!" | |
| echo "urls=[]" >> $GITHUB_OUTPUT # Output empty array if sitemap not found | |
| fi | |
| shell: bash | |
| lighthouse-test: | |
| needs: build-and-get-urls | |
| # This condition ensures 'urls' output from previous job is a non-empty array when this job runs | |
| if: fromJson(needs.build-and-get-urls.outputs.urls)[0] != null | |
| runs-on: ubuntu-latest | |
| permissions: # Add this to grant write permissions for committing | |
| contents: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v7 | |
| - name: Prepare URLs for Lighthouse | |
| id: prepare_lighthouse_urls | |
| run: | | |
| JSON_URL_ARRAY='${{ needs.build-and-get-urls.outputs.urls }}' | |
| COMMA_SEPARATED_URLS=$(echo "$JSON_URL_ARRAY" | jq -r '. | join(",")') | |
| echo "Lighthouse URLs: $COMMA_SEPARATED_URLS" | |
| echo "LIGHTHOUSE_URL_LIST=$COMMA_SEPARATED_URLS" >> $GITHUB_ENV | |
| shell: bash | |
| - name: Create Lighthouse reports directory | |
| run: mkdir -p ./lighthouse-reports | |
| - name: Run Lighthouse CI for all pages | |
| id: lighthouse_run | |
| uses: foo-software/lighthouse-check-action@master | |
| with: | |
| urls: ${{ env.LIGHTHOUSE_URL_LIST }} | |
| outputDirectory: ./lighthouse-reports | |
| # Optional: Set budget to fail the check if scores are below thresholds | |
| # budgetPath: .github/lighthouse-budget.json | |
| - name: Generate Lighthouse Summary Report File | |
| # This condition makes the step always run, so you see the table even if some Lighthouse audits fail. | |
| if: always() | |
| shell: bash | |
| run: | | |
| RESULTS_JSON_CONTENT='${{ steps.lighthouse_run.outputs.lighthouseCheckResults || '{"data":[]}' }}' | |
| ( # Start subshell to redirect all output to lighthousetest.md | |
| echo "### Lighthouse Score Summary" | |
| echo "| URL | Accessibility | Best Practices | Performance | SEO |" | |
| echo "|-----|---------------|----------------|-------------|-----|" | |
| # Generate data rows for each URL | |
| echo "$RESULTS_JSON_CONTENT" | jq -r ' | |
| .data[]? # Iterate over each item in the data array, gracefully handle if .data is null or item is null | |
| | select(.url) # Ensure the item has a URL | |
| | ( | |
| "| " + .url + " | " + | |
| # Access scores, provide "N/A" if a score is null or missing, then convert to string | |
| (.scores.accessibility // "N/A" | tostring) + " | " + | |
| (.scores.bestPractices // "N/A" | tostring) + " | " + | |
| (.scores.performance // "N/A" | tostring) + " | " + | |
| (.scores.seo // "N/A" | tostring) + " |" | |
| ) | |
| ' | |
| # Generate average row and final score line | |
| echo "$RESULTS_JSON_CONTENT" | jq -r ' | |
| # Pass the data array directly to this jq instance | |
| .data | |
| # Check if .data is a non-empty array | |
| | if (type != "array") or (length == 0) then | |
| "| Overall Average | N/A | N/A | N/A | N/A |\\\\n\\\\n# Average Score: N/A" | |
| else | |
| # Extract all valid numerical scores for each category from the .data array | |
| [.[].scores.accessibility | select(type == "number")] as $acc_scores | | |
| [.[].scores.bestPractices | select(type == "number")] as $bp_scores | | |
| [.[].scores.performance | select(type == "number")] as $perf_scores | | |
| [.[].scores.seo | select(type == "number")] as $seo_scores | | |
| # Calculate average for accessibility, format as string (integer or "N/A") | |
| (if ($acc_scores | length) > 0 then ($acc_scores | add / length | floor | tostring) else "N/A" end) as $avg_acc_str | | |
| # Store raw numerical average for final calculation, or null if not calculable | |
| (if ($acc_scores | length) > 0 then ($acc_scores | add / length) else null end) as $raw_avg_acc | | |
| (if ($bp_scores | length) > 0 then ($bp_scores | add / length | floor | tostring) else "N/A" end) as $avg_bp_str | | |
| (if ($bp_scores | length) > 0 then ($bp_scores | add / length) else null end) as $raw_avg_bp | | |
| (if ($perf_scores | length) > 0 then ($perf_scores | add / length | floor | tostring) else "N/A" end) as $avg_perf_str | | |
| (if ($perf_scores | length) > 0 then ($perf_scores | add / length) else null end) as $raw_avg_perf | | |
| # Calculate average for seo, format as string (integer or "N/A") | |
| (if ($seo_scores | length) > 0 then ($seo_scores | add / length | floor | tostring) else "N/A" end) as $avg_seo_str | | |
| (if ($seo_scores | length) > 0 then ($seo_scores | add / length) else null end) as $raw_avg_seo | | |
| # Construct the Markdown table row for averages | |
| "| Overall Average | \($avg_acc_str) | \($avg_bp_str) | \($avg_perf_str) | \($avg_seo_str) |" as $avg_row_str | | |
| # Collect all valid raw numerical averages (those that are not null) | |
| ([$raw_avg_acc, $raw_avg_bp, $raw_avg_perf, $raw_avg_seo] | map(select(. != null))) as $valid_raw_category_averages | | |
| # Calculate the final average score from the valid category averages | |
| (if ($valid_raw_category_averages | length) > 0 then | |
| ($valid_raw_category_averages | add / length | floor | tostring) | |
| else | |
| "N/A" | |
| end) as $final_avg_score_str | | |
| # Combine the average row and the final score line | |
| $avg_row_str + "\n\n# Average Score: \($final_avg_score_str)" | |
| end | |
| ' | |
| ) > lighthousetest.md # All echos inside () go to lighthousetest.md | |
| # This echo goes to the workflow log, not the lighthousetest.md | |
| echo "Lighthouse summary report generated: lighthousetest.md" | |
| - name: Commit and Push Lighthouse Report | |
| uses: stefanzweifel/git-auto-commit-action@v7 | |
| with: | |
| commit_message: "docs: update Lighthouse report [skip ci]" | |
| branch: main # Or your default branch | |
| file_pattern: lighthousetest.md | |
| commit_user_name: "GitHub Actions Bot" | |
| commit_user_email: "actions@github.com" | |
| commit_author: "GitHub Actions Bot <actions@github.com>" | |
| - name: Upload Lighthouse Reports Artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: lighthouse-reports # A single artifact for all reports | |
| path: ./lighthouse-reports | |
| if-no-files-found: ignore |