fix: update GoatCounter SRI hash (#87) #33
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: CI | |
| on: | |
| pull_request: | |
| push: | |
| branches: [main] | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| jobs: | |
| ci: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: taiki-e/install-action@42721ded7ddc3cd90f687527e8602066e4e1ff3a # v2.69.2 | |
| with: | |
| tool: just | |
| - name: Lint HTML, CSS, and JS | |
| id: lint | |
| run: just lint | |
| - name: Check external URLs | |
| id: urls | |
| if: always() | |
| run: | | |
| # Extract external URLs from site files (src, href, content, @import, data-goatcounter) | |
| # Then normalize protocol-relative URLs and deduplicate | |
| urls=$(grep -roEhI --include='*.html' --include='*.css' --include='*.js' --include='*.svg' \ | |
| '(https?://|//)[^"'"'"' <>)]+' site/ \ | |
| | sed 's/^\/\//https:\/\//' \ | |
| | sed 's/;$//' \ | |
| | grep -v 'xmlns' \ | |
| | grep -v 'w3\.org' \ | |
| | grep -v 'wraas\.github\.io' \ | |
| | grep -v 'youtube\.com' \ | |
| | grep -v 'lyricsondemand\.com' \ | |
| | grep -v 'goatcounter\.com' \ | |
| | grep -v 'gc\.zgo\.at' \ | |
| | grep -v '^https://fonts\.googleapis\.com$' \ | |
| | grep -v '^https://fonts\.gstatic\.com$' \ | |
| | sort -u || true) | |
| if [ -z "$urls" ]; then | |
| echo "No external URLs found" | |
| exit 0 | |
| fi | |
| errors="" | |
| while IFS= read -r url; do | |
| # Try HEAD first, fall back to GET (some CDNs reject HEAD) | |
| status=$(curl -sSL -o /dev/null -w "%{http_code}" --head --max-time 10 --retry 2 "$url" 2>/dev/null) | |
| if [ "$status" != "200" ]; then | |
| status=$(curl -sSL -o /dev/null -w "%{http_code}" --max-time 10 --retry 2 "$url" 2>/dev/null) | |
| fi | |
| if [ "$status" != "200" ]; then | |
| file=$(grep -rl "$url" site/ | head -1) | |
| errors="${errors}- \`${url}\` in \`${file}\` (HTTP ${status})\n" | |
| echo "FAIL: $url -> HTTP $status" | |
| else | |
| echo "OK: $url -> HTTP $status" | |
| fi | |
| done <<< "$urls" | |
| if [ -n "$errors" ]; then | |
| echo "URL_ERRORS<<EOF" >> "$GITHUB_ENV" | |
| echo -e "$errors" >> "$GITHUB_ENV" | |
| echo "EOF" >> "$GITHUB_ENV" | |
| exit 1 | |
| fi | |
| - name: Validate OG metadata | |
| id: og | |
| if: always() | |
| run: | | |
| errors="" | |
| required_tags="og:title og:description og:image og:url og:site_name" | |
| for file in site/index.html site/404.html; do | |
| for tag in $required_tags; do | |
| if ! grep -q "property=\"${tag}\"" "$file"; then | |
| errors="${errors}- \`${file}\`: missing \`${tag}\`\n" | |
| fi | |
| done | |
| done | |
| if [ -n "$errors" ]; then | |
| echo "OG_ERRORS<<EOF" >> "$GITHUB_ENV" | |
| echo -e "$errors" >> "$GITHUB_ENV" | |
| echo "EOF" >> "$GITHUB_ENV" | |
| exit 1 | |
| fi | |
| echo "OG metadata: ok" | |
| - name: Comment on pull request | |
| if: failure() && github.event_name == 'pull_request' | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 | |
| with: | |
| script: | | |
| const sections = []; | |
| if ('${{ steps.lint.outcome }}' === 'failure') { | |
| sections.push('### Lint\nOne or more lint checks failed. See the workflow log for details.'); | |
| } | |
| const urlErrors = process.env.URL_ERRORS; | |
| if (urlErrors) { | |
| sections.push(`### External URLs\nThe following external URLs are unreachable:\n\n${urlErrors}`); | |
| } | |
| const ogErrors = process.env.OG_ERRORS; | |
| if (ogErrors) { | |
| sections.push(`### OG Metadata\nMissing Open Graph tags:\n\n${ogErrors}`); | |
| } | |
| if (sections.length === 0) return; | |
| const body = `## CI Failures\n\n${sections.join('\n\n')}\n\nPlease fix before merging.`; | |
| const marker = "<!-- ci-report -->"; | |
| const bodyWithMarker = marker + "\n" + body; | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const existing = comments.find(c => c.body.includes(marker)); | |
| if (existing) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: existing.id, | |
| body: bodyWithMarker, | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: bodyWithMarker, | |
| }); | |
| } |