Add quality infrastructure: PR template, CI checks, contributing guide#626
Open
beagandica wants to merge 1 commit into
Open
Add quality infrastructure: PR template, CI checks, contributing guide#626beagandica wants to merge 1 commit into
beagandica wants to merge 1 commit into
Conversation
Comment on lines
+14
to
+30
| name: Hugo Build | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| submodules: recursive | ||
|
|
||
| - name: Setup Hugo | ||
| uses: peaceiris/actions-hugo@v3 | ||
| with: | ||
| hugo-version: 'latest' | ||
| extended: true | ||
|
|
||
| - name: Build site | ||
| run: hugo --quiet --minify | ||
|
|
||
| content-lint: |
Comment on lines
+31
to
+146
| name: Content Lint | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Get changed files | ||
| id: changed | ||
| uses: tj-actions/changed-files@v44 | ||
| with: | ||
| files: | | ||
| content/**/*.md | ||
|
|
||
| - name: Check uppercase image extensions | ||
| if: steps.changed.outputs.any_changed == 'true' | ||
| run: | | ||
| echo "🔍 Checking for uppercase image extensions (.PNG, .JPG, .GIF)..." | ||
| ERRORS=0 | ||
| for file in ${{ steps.changed.outputs.all_changed_files }}; do | ||
| if [ -f "$file" ]; then | ||
| MATCHES=$(grep -n '\.\(PNG\|JPG\|GIF\|JPEG\|BMP\)' "$file" || true) | ||
| if [ -n "$MATCHES" ]; then | ||
| echo "❌ $file:" | ||
| echo "$MATCHES" | ||
| ERRORS=$((ERRORS + 1)) | ||
| fi | ||
| fi | ||
| done | ||
| if [ $ERRORS -gt 0 ]; then | ||
| echo "" | ||
| echo "⚠️ Found $ERRORS file(s) with uppercase image extensions." | ||
| echo " Linux servers are case-sensitive — use .png, .jpg, .gif instead." | ||
| exit 1 | ||
| fi | ||
| echo "✅ No uppercase image extensions found." | ||
|
|
||
| - name: Check unquoted HTML attributes | ||
| if: steps.changed.outputs.any_changed == 'true' | ||
| run: | | ||
| echo "🔍 Checking for unquoted HTML attributes..." | ||
| ERRORS=0 | ||
| for file in ${{ steps.changed.outputs.all_changed_files }}; do | ||
| if [ -f "$file" ]; then | ||
| # Match src= or href= followed by a space then non-quote char (unquoted attr) | ||
| MATCHES=$(grep -n 'src= [^"]' "$file" || true) | ||
| if [ -n "$MATCHES" ]; then | ||
| echo "❌ $file:" | ||
| echo "$MATCHES" | ||
| ERRORS=$((ERRORS + 1)) | ||
| fi | ||
| fi | ||
| done | ||
| if [ $ERRORS -gt 0 ]; then | ||
| echo "" | ||
| echo "⚠️ Found $ERRORS file(s) with unquoted HTML attributes." | ||
| echo " Always quote attributes: src=\"file.png\" not src= file.png" | ||
| exit 1 | ||
| fi | ||
| echo "✅ No unquoted HTML attributes found." | ||
|
|
||
| - name: Check duplicate YAML frontmatter keys | ||
| if: steps.changed.outputs.any_changed == 'true' | ||
| run: | | ||
| echo "🔍 Checking for duplicate YAML frontmatter keys..." | ||
| ERRORS=0 | ||
| for file in ${{ steps.changed.outputs.all_changed_files }}; do | ||
| if [ -f "$file" ]; then | ||
| # Extract frontmatter (between --- markers), get keys, find duplicates | ||
| DUPES=$(sed -n '/^---$/,/^---$/p' "$file" | grep -E '^\w+:' | sed 's/:.*//' | sort | uniq -d) | ||
| if [ -n "$DUPES" ]; then | ||
| echo "❌ $file has duplicate YAML keys:" | ||
| echo "$DUPES" | ||
| ERRORS=$((ERRORS + 1)) | ||
| fi | ||
| fi | ||
| done | ||
| if [ $ERRORS -gt 0 ]; then | ||
| echo "" | ||
| echo "⚠️ Found $ERRORS file(s) with duplicate YAML frontmatter keys." | ||
| echo " Hugo silently uses the last value — remove duplicates." | ||
| exit 1 | ||
| fi | ||
| echo "✅ No duplicate YAML keys found." | ||
|
|
||
| - name: Check images have alt text | ||
| if: steps.changed.outputs.any_changed == 'true' | ||
| run: | | ||
| echo "🔍 Checking for images without alt text..." | ||
| WARNINGS=0 | ||
| for file in ${{ steps.changed.outputs.all_changed_files }}; do | ||
| if [ -f "$file" ]; then | ||
| # Check for  | ||
| MATCHES=$(grep -n '!\[\](' "$file" || true) | ||
| if [ -n "$MATCHES" ]; then | ||
| echo "⚠️ $file has images without alt text:" | ||
| echo "$MATCHES" | ||
| WARNINGS=$((WARNINGS + 1)) | ||
| fi | ||
| # Check for <img> tags without alt attribute | ||
| IMG_NO_ALT=$(grep -n '<img ' "$file" | grep -v 'alt=' || true) | ||
| if [ -n "$IMG_NO_ALT" ]; then | ||
| echo "⚠️ $file has <img> tags without alt attribute:" | ||
| echo "$IMG_NO_ALT" | ||
| WARNINGS=$((WARNINGS + 1)) | ||
| fi | ||
| fi | ||
| done | ||
| if [ $WARNINGS -gt 0 ]; then | ||
| echo "" | ||
| echo "⚠️ Found $WARNINGS file(s) with missing alt text." | ||
| echo " All images should have descriptive alt text for accessibility." | ||
| echo " Example: " | ||
| # Warning only — don't fail the build for alt text (too many existing files) | ||
| fi | ||
| echo "✅ Alt text check complete." | ||
|
|
||
| translation-parity: |
Comment on lines
+147
to
+192
| name: Translation Parity Check | ||
| runs-on: ubuntu-latest | ||
| if: github.event_name == 'pull_request' | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Get changed files | ||
| id: changed | ||
| uses: tj-actions/changed-files@v44 | ||
| with: | ||
| files: | | ||
| content/**/*.md | ||
|
|
||
| - name: Check if translations exist for changed workshops | ||
| if: steps.changed.outputs.any_changed == 'true' | ||
| run: | | ||
| echo "🌍 Checking translation parity for changed workshops..." | ||
| LANGUAGES=("brazilian-portuguese" "espanol" "korean" "francais" "german" "simplified-chinese" "traditional-chinese" "kyrgyz") | ||
| NOTICES=0 | ||
|
|
||
| # Get unique workshop paths from changed English files | ||
| for file in ${{ steps.changed.outputs.all_changed_files }}; do | ||
| if [[ "$file" == content/english/* ]]; then | ||
| # Extract workshop name (first directory after english/) | ||
| WORKSHOP=$(echo "$file" | sed 's|content/english/||' | cut -d'/' -f1) | ||
|
|
||
| for lang in "${LANGUAGES[@]}"; do | ||
| LANG_DIR="content/$lang/$WORKSHOP" | ||
| if [ -d "$LANG_DIR" ]; then | ||
| echo "📋 Workshop '$WORKSHOP' also exists in $lang — please verify changes apply there too." | ||
| NOTICES=$((NOTICES + 1)) | ||
| break # Only report once per workshop | ||
| fi | ||
| done | ||
| fi | ||
| done | ||
|
|
||
| if [ $NOTICES -gt 0 ]; then | ||
| echo "" | ||
| echo "ℹ️ $NOTICES workshop(s) have translations that may need matching updates." | ||
| echo " If this is a structural change (TOC, layout, images), update all languages." | ||
| echo " If this is English-only content, you can skip this." | ||
| else | ||
| echo "✅ No translation parity issues detected." | ||
| fi | ||
| # Info only — don't fail the build |
This was referenced Apr 25, 2026
Closed
3 tasks
Tier 1 quality guardrails for NuevoFoundation workshops: - PR template: checklist for Hugo build, images, alt text, YAML, translations - Content quality CI: checks for uppercase extensions, unquoted HTML attrs, duplicate YAML keys, missing alt text on all content PRs - Translation parity CI: flags when English changes have untouched translations - CONTRIBUTING.md: complete contributor guide covering folder structure, frontmatter templates, image guidelines, translation rules, testing steps - .editorconfig: standardize UTF-8, LF endings, final newline, 2-space indent Prevents recurrence of issues fixed in PRs NuevoFoundation#609, NuevoFoundation#622, NuevoFoundation#623, NuevoFoundation#624, NuevoFoundation#625. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
c25ff24 to
bd21132
Compare
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Tier 1 quality guardrails to prevent recurring content issues and help contributors submit clean PRs.
Changes
PR Template (.github/PULL_REQUEST_TEMPLATE.md)
Every new PR automatically gets a checklist covering:
Content Quality CI (.github/workflows/content-quality.yaml)
Runs automatically on every PR that touches \content/, \layouts/, \static/, or \ hemes/:
Contributing Guide (\CONTRIBUTING.md)
Complete guide for contributors covering:
EditorConfig (.editorconfig)
Standardizes: UTF-8, LF line endings, final newline, 2-space indent.
Why
These guardrails prevent the exact issues we've been fixing in PRs #609, #622, #623, #624, and #625:
Testing