Skip to content

Commit f7ece4e

Browse files
committed
Add comprehensive PR validation workflow and tooling
- PR validation workflow tests builds, content, and images before merge - Automated checks for front matter, internal links, and missing assets - Helper script for creating new posts via PR workflow - Updated documentation with PR workflow guidelines
1 parent 077c2a6 commit f7ece4e

File tree

3 files changed

+316
-0
lines changed

3 files changed

+316
-0
lines changed
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
# PR validation workflow - test builds and content quality
2+
name: PR Validation
3+
4+
on:
5+
pull_request:
6+
branches:
7+
- main
8+
paths:
9+
- 'content/**'
10+
- 'config.yaml'
11+
- 'go.mod'
12+
- 'layouts/**'
13+
- 'assets/**'
14+
- 'static/**'
15+
- '.github/workflows/**'
16+
17+
jobs:
18+
validate-build:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v4.1.7
22+
with:
23+
fetch-depth: 0
24+
25+
- name: Setup Go
26+
uses: actions/setup-go@v5.2.0
27+
with:
28+
go-version: '1.20.14'
29+
30+
- name: Setup Hugo
31+
uses: peaceiris/actions-hugo@v2.6.0
32+
with:
33+
hugo-version: '0.148.1'
34+
extended: true
35+
36+
- name: Setup Hugo Modules
37+
run: |
38+
hugo mod tidy
39+
hugo mod get github.com/jpanther/congo/v2@v2.12.2
40+
41+
- name: Validate Hugo Configuration
42+
run: |
43+
echo "Validating Hugo configuration..."
44+
hugo config
45+
echo "✅ Configuration is valid"
46+
47+
- name: Check for Draft Posts
48+
run: |
49+
echo "Checking for draft posts..."
50+
DRAFTS=$(hugo list drafts | wc -l)
51+
if [ $DRAFTS -gt 1 ]; then
52+
echo "⚠️ Found $((DRAFTS-1)) draft posts"
53+
hugo list drafts
54+
else
55+
echo "✅ No draft posts found"
56+
fi
57+
58+
- name: Check for Future Posts
59+
run: |
60+
echo "Checking for future posts..."
61+
FUTURE=$(hugo list future | wc -l)
62+
if [ $FUTURE -gt 1 ]; then
63+
echo "⚠️ Found $((FUTURE-1)) future posts"
64+
hugo list future
65+
echo "Note: Future posts are built with --buildFuture flag in production"
66+
else
67+
echo "✅ No future posts found"
68+
fi
69+
70+
- name: Test Build (Development)
71+
run: |
72+
echo "Testing development build..."
73+
hugo --buildDrafts --buildFuture --verbose
74+
echo "✅ Development build successful"
75+
76+
- name: Test Build (Production)
77+
run: |
78+
echo "Testing production build..."
79+
hugo --minify --buildFuture --verbose
80+
echo "✅ Production build successful"
81+
82+
- name: Check Build Output
83+
run: |
84+
echo "Analysing build output..."
85+
echo "Total pages: $(find public -name "*.html" | wc -l)"
86+
echo "Total assets: $(find public -type f ! -name "*.html" | wc -l)"
87+
echo "Site size: $(du -sh public | cut -f1)"
88+
89+
# Check for common issues
90+
if [ ! -f "public/index.html" ]; then
91+
echo "❌ Missing homepage!"
92+
exit 1
93+
fi
94+
95+
if [ ! -f "public/posts/index.html" ]; then
96+
echo "❌ Missing posts index!"
97+
exit 1
98+
fi
99+
100+
echo "✅ Build output looks good"
101+
102+
validate-content:
103+
runs-on: ubuntu-latest
104+
steps:
105+
- uses: actions/checkout@v4.1.7
106+
with:
107+
fetch-depth: 0
108+
109+
- name: Check Markdown Files
110+
run: |
111+
echo "Validating markdown files..."
112+
113+
# Check for files with missing front matter
114+
for file in content/posts/*.md; do
115+
if [ -f "$file" ]; then
116+
if ! head -1 "$file" | grep -q "^---"; then
117+
echo "❌ Missing front matter in $file"
118+
exit 1
119+
fi
120+
fi
121+
done
122+
123+
# Check for required front matter fields
124+
for file in content/posts/*.md; do
125+
if [ -f "$file" ]; then
126+
if ! grep -q "^title:" "$file"; then
127+
echo "❌ Missing title in $file"
128+
exit 1
129+
fi
130+
if ! grep -q "^date:" "$file"; then
131+
echo "❌ Missing date in $file"
132+
exit 1
133+
fi
134+
fi
135+
done
136+
137+
echo "✅ All markdown files have valid front matter"
138+
139+
- name: Check for Broken Internal Links
140+
run: |
141+
echo "Checking for potential broken internal links..."
142+
143+
# Look for common broken link patterns
144+
if grep -r "](http://localhost" content/; then
145+
echo "❌ Found localhost links in content"
146+
exit 1
147+
fi
148+
149+
# Check for missing project references
150+
if grep -r "](/projects/" content/; then
151+
echo "Found internal project links, checking they exist..."
152+
for link in $(grep -ro "](/projects/[^)]*)" content/ | sed 's/.*](/projects//;s/[)].*//' | sort -u); do
153+
if [ ! -d "content/projects$link" ] && [ ! -f "content/projects$link.md" ] && [ ! -f "content/projects$link/index.md" ]; then
154+
echo "❌ Broken internal link: /projects$link"
155+
exit 1
156+
fi
157+
done
158+
fi
159+
160+
echo "✅ No obvious broken internal links found"
161+
162+
validate-images:
163+
runs-on: ubuntu-latest
164+
steps:
165+
- uses: actions/checkout@v4.1.7
166+
167+
- name: Check Image References
168+
run: |
169+
echo "Checking image references in content..."
170+
171+
# Find all image references in markdown
172+
for file in content/**/*.md; do
173+
if [ -f "$file" ]; then
174+
# Check for markdown image syntax
175+
grep -n "!\[.*\](" "$file" | while read -r line; do
176+
image_path=$(echo "$line" | sed 's/.*!\[.*\](\([^)]*\)).*/\1/')
177+
178+
# Skip external URLs
179+
if [[ "$image_path" =~ ^https?:// ]]; then
180+
continue
181+
fi
182+
183+
# Check if local image exists
184+
if [[ "$image_path" =~ ^/ ]]; then
185+
# Absolute path
186+
full_path="static${image_path}"
187+
else
188+
# Relative path
189+
dir=$(dirname "$file")
190+
full_path="${dir}/${image_path}"
191+
fi
192+
193+
if [ ! -f "$full_path" ]; then
194+
echo "❌ Missing image: $image_path referenced in $file"
195+
echo " Expected at: $full_path"
196+
fi
197+
done
198+
fi
199+
done
200+
201+
echo "✅ Image reference check complete"
202+
203+
summary:
204+
runs-on: ubuntu-latest
205+
needs: [validate-build, validate-content, validate-images]
206+
if: always()
207+
steps:
208+
- name: PR Validation Summary
209+
run: |
210+
echo "## PR Validation Results 📝" >> $GITHUB_STEP_SUMMARY
211+
echo "" >> $GITHUB_STEP_SUMMARY
212+
213+
if [ "${{ needs.validate-build.result }}" == "success" ]; then
214+
echo "✅ **Build Validation**: Passed" >> $GITHUB_STEP_SUMMARY
215+
else
216+
echo "❌ **Build Validation**: Failed" >> $GITHUB_STEP_SUMMARY
217+
fi
218+
219+
if [ "${{ needs.validate-content.result }}" == "success" ]; then
220+
echo "✅ **Content Validation**: Passed" >> $GITHUB_STEP_SUMMARY
221+
else
222+
echo "❌ **Content Validation**: Failed" >> $GITHUB_STEP_SUMMARY
223+
fi
224+
225+
if [ "${{ needs.validate-images.result }}" == "success" ]; then
226+
echo "✅ **Image Validation**: Passed" >> $GITHUB_STEP_SUMMARY
227+
else
228+
echo "❌ **Image Validation**: Failed" >> $GITHUB_STEP_SUMMARY
229+
fi
230+
231+
echo "" >> $GITHUB_STEP_SUMMARY
232+
echo "Your PR is ready to merge! 🚀" >> $GITHUB_STEP_SUMMARY

AI.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,17 @@
8282
- Work locally until a post is completely ready before pushing
8383
- Remember that pushing to main triggers the GitHub Pages deployment workflow
8484
and updates the site
85+
86+
## Pull Request Workflow
87+
- For significant changes, create a feature branch and PR instead of pushing directly to main
88+
- The PR validation workflow will automatically test:
89+
- Hugo build success (both development and production)
90+
- Content validation (front matter, required fields)
91+
- Internal link checking
92+
- Image reference validation
93+
- All validation checks must pass before merging
94+
- Use PR workflow for:
95+
- New blog posts (for review and validation)
96+
- Theme or configuration changes
97+
- Multiple file changes
98+
- Experimental features

scripts/create-post-pr.sh

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#!/bin/bash
2+
# Helper script to create a new blog post via PR workflow
3+
4+
set -e
5+
6+
# Check if post title is provided
7+
if [ $# -eq 0 ]; then
8+
echo "Usage: $0 'Post Title Here'"
9+
echo "Example: $0 'My New Blog Post'"
10+
exit 1
11+
fi
12+
13+
POST_TITLE="$1"
14+
# Convert title to slug (lowercase, spaces to hyphens, remove special chars)
15+
POST_SLUG=$(echo "$POST_TITLE" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9 ]//g' | sed 's/ \+/-/g')
16+
CURRENT_DATE=$(date '+%Y-%m-%d')
17+
BRANCH_NAME="post/$POST_SLUG"
18+
FILENAME="content/posts/$CURRENT_DATE-$POST_SLUG.md"
19+
20+
echo "Creating new post PR..."
21+
echo "Title: $POST_TITLE"
22+
echo "Slug: $POST_SLUG"
23+
echo "Branch: $BRANCH_NAME"
24+
echo "File: $FILENAME"
25+
echo ""
26+
27+
# Create and switch to new branch
28+
git checkout -b "$BRANCH_NAME"
29+
30+
# Create the post file
31+
cat > "$FILENAME" << EOF
32+
---
33+
title: "$POST_TITLE"
34+
date: $CURRENT_DATE
35+
draft: true
36+
description: ""
37+
tags: []
38+
categories: []
39+
author: "david-taylor"
40+
---
41+
42+
## Introduction
43+
44+
[Your post content here]
45+
46+
## Conclusion
47+
48+
[Wrap up your thoughts]
49+
EOF
50+
51+
echo "Created new post file: $FILENAME"
52+
echo ""
53+
echo "Next steps:"
54+
echo "1. Edit the post content in $FILENAME"
55+
echo "2. Add tags, categories, and description"
56+
echo "3. Set draft: false when ready"
57+
echo "4. Commit your changes: git add . && git commit -m 'Add $POST_TITLE post'"
58+
echo "5. Push and create PR: git push -u origin $BRANCH_NAME"
59+
echo "6. The PR validation workflow will test your changes"
60+
echo ""
61+
echo "Opening the post file for editing..."
62+
63+
# Open the file in the default editor if available
64+
if command -v code > /dev/null; then
65+
code "$FILENAME"
66+
elif command -v nano > /dev/null; then
67+
nano "$FILENAME"
68+
else
69+
echo "Edit $FILENAME with your preferred editor"
70+
fi

0 commit comments

Comments
 (0)