feat: add CI-friendly example generation and verification
- Add 'make examples' to regenerate README images
- Add 'make verify-examples' for CI verification
- Create GitHub Action to verify examples are up to date
- Improve generate_examples.py with better error handling
- Add update-examples.sh convenience script
- Document development workflow in README
This ensures README examples always match the actual code output.
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
3c9c06acc9
commit
1adbd1a5ff
|
|
@ -0,0 +1,52 @@
|
||||||
|
name: Verify Examples
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
paths:
|
||||||
|
- 'src/**'
|
||||||
|
- 'templates/**'
|
||||||
|
- 'docs/images/**'
|
||||||
|
- '.github/workflows/verify-examples.yml'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
verify-examples:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: '3.9'
|
||||||
|
|
||||||
|
- name: Install system dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y poppler-utils qpdf
|
||||||
|
|
||||||
|
- name: Install Typst
|
||||||
|
run: |
|
||||||
|
# Download and install Typst
|
||||||
|
wget https://github.com/typst/typst/releases/latest/download/typst-x86_64-unknown-linux-musl.tar.xz
|
||||||
|
tar -xf typst-x86_64-unknown-linux-musl.tar.xz
|
||||||
|
sudo mv typst-x86_64-unknown-linux-musl/typst /usr/local/bin/
|
||||||
|
typst --version
|
||||||
|
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
pip install pyyaml
|
||||||
|
|
||||||
|
- name: Verify examples are up to date
|
||||||
|
run: |
|
||||||
|
make verify-examples
|
||||||
|
|
||||||
|
- name: Upload example images if changed
|
||||||
|
if: failure()
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: updated-examples
|
||||||
|
path: docs/images/
|
||||||
21
Makefile
21
Makefile
|
|
@ -1,4 +1,4 @@
|
||||||
.PHONY: all clean install test samples help check-deps
|
.PHONY: all clean install test samples help check-deps examples verify-examples
|
||||||
|
|
||||||
# Default target
|
# Default target
|
||||||
all: out/flashcards.pdf out/flashcards_linear.pdf
|
all: out/flashcards.pdf out/flashcards_linear.pdf
|
||||||
|
|
@ -42,6 +42,23 @@ test: check-deps
|
||||||
@command -v qpdf >/dev/null 2>&1 && qpdf --check out/test.pdf || echo "PDF generated (validation skipped)"
|
@command -v qpdf >/dev/null 2>&1 && qpdf --check out/test.pdf || echo "PDF generated (validation skipped)"
|
||||||
@echo "Test completed successfully"
|
@echo "Test completed successfully"
|
||||||
|
|
||||||
|
# Generate README example images
|
||||||
|
examples: check-deps
|
||||||
|
@echo "Generating example images for README..."
|
||||||
|
@python3 src/generate_examples.py
|
||||||
|
@echo "✓ Example images generated in docs/images/"
|
||||||
|
|
||||||
|
# Verify examples are up to date (for CI)
|
||||||
|
verify-examples: examples
|
||||||
|
@echo "Verifying example images are up to date..."
|
||||||
|
@if git diff --quiet docs/images/; then \
|
||||||
|
echo "✓ Example images are up to date"; \
|
||||||
|
else \
|
||||||
|
echo "✗ Example images have changed - please run 'make examples' and commit the changes"; \
|
||||||
|
git diff --stat docs/images/; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
|
||||||
# Clean output files
|
# Clean output files
|
||||||
clean:
|
clean:
|
||||||
rm -rf out/
|
rm -rf out/
|
||||||
|
|
@ -53,6 +70,8 @@ help:
|
||||||
@echo " make Generate default flashcards (0-9)"
|
@echo " make Generate default flashcards (0-9)"
|
||||||
@echo " make samples Generate all sample configurations"
|
@echo " make samples Generate all sample configurations"
|
||||||
@echo " make test Run a quick test build"
|
@echo " make test Run a quick test build"
|
||||||
|
@echo " make examples Generate README example images"
|
||||||
|
@echo " make verify-examples Verify examples are up to date (CI)"
|
||||||
@echo " make install Install dependencies (macOS)"
|
@echo " make install Install dependencies (macOS)"
|
||||||
@echo " make clean Remove all generated files"
|
@echo " make clean Remove all generated files"
|
||||||
@echo " make help Show this help message"
|
@echo " make help Show this help message"
|
||||||
|
|
|
||||||
32
README.md
32
README.md
|
|
@ -394,6 +394,38 @@ The `SorobanGenerator` class provides:
|
||||||
|
|
||||||
All methods use clean TypeScript interfaces with proper types - no shell command building required!
|
All methods use clean TypeScript interfaces with proper types - no shell command building required!
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### Updating Example Images
|
||||||
|
|
||||||
|
If you make changes that affect the visual output, please update the example images:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Regenerate all example images
|
||||||
|
make examples
|
||||||
|
|
||||||
|
# Or use the update script
|
||||||
|
./scripts/update-examples.sh
|
||||||
|
|
||||||
|
# Verify examples are up to date (CI will also check this)
|
||||||
|
make verify-examples
|
||||||
|
```
|
||||||
|
|
||||||
|
The CI pipeline will automatically verify that example images are up to date with the code.
|
||||||
|
|
||||||
|
### Running Tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Quick test build
|
||||||
|
make test
|
||||||
|
|
||||||
|
# Generate all samples
|
||||||
|
make samples
|
||||||
|
|
||||||
|
# Full CI verification
|
||||||
|
make verify-examples
|
||||||
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT License - see LICENSE file for details.
|
MIT License - see LICENSE file for details.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Update README example images
|
||||||
|
# Run this script when you make changes that affect the visual output
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "🔄 Updating README example images..."
|
||||||
|
|
||||||
|
# Run the example generator
|
||||||
|
if ! python3 src/generate_examples.py; then
|
||||||
|
echo "❌ Failed to generate examples"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if there are changes
|
||||||
|
if git diff --quiet docs/images/; then
|
||||||
|
echo "✅ No changes to example images"
|
||||||
|
else
|
||||||
|
echo "📝 Example images have been updated:"
|
||||||
|
git diff --stat docs/images/
|
||||||
|
echo ""
|
||||||
|
echo "Please review the changes and commit them if they look correct:"
|
||||||
|
echo " git add docs/images/"
|
||||||
|
echo " git commit -m 'docs: update example images'"
|
||||||
|
fi
|
||||||
|
|
@ -183,8 +183,25 @@ def main():
|
||||||
|
|
||||||
examples = generate_example_pdfs()
|
examples = generate_example_pdfs()
|
||||||
|
|
||||||
|
# Check if we have a PDF to PNG converter available
|
||||||
|
converters = []
|
||||||
|
for cmd in ['pdftoppm', 'convert', 'gs']:
|
||||||
|
if subprocess.run(['which', cmd], capture_output=True).returncode == 0:
|
||||||
|
converters.append(cmd)
|
||||||
|
|
||||||
|
if not converters:
|
||||||
|
print("ERROR: No PDF to PNG converter found. Please install one of:")
|
||||||
|
print(" - poppler-utils (for pdftoppm)")
|
||||||
|
print(" - imagemagick (for convert)")
|
||||||
|
print(" - ghostscript (for gs)")
|
||||||
|
print("\nOn Ubuntu/Debian: sudo apt-get install poppler-utils")
|
||||||
|
print("On macOS: brew install poppler")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
print(f"Using PDF converters: {', '.join(converters)}")
|
||||||
print("Generating example images...")
|
print("Generating example images...")
|
||||||
|
|
||||||
|
failed = []
|
||||||
for example in examples:
|
for example in examples:
|
||||||
print(f" - {example['name']}: {example['desc']}")
|
print(f" - {example['name']}: {example['desc']}")
|
||||||
|
|
||||||
|
|
@ -207,7 +224,8 @@ def main():
|
||||||
if pdf_to_png(str(pdf_path), str(front_png), dpi=150, page=1):
|
if pdf_to_png(str(pdf_path), str(front_png), dpi=150, page=1):
|
||||||
print(f" ✓ Generated {front_png.name}")
|
print(f" ✓ Generated {front_png.name}")
|
||||||
else:
|
else:
|
||||||
print(f" WARNING: Could not convert to PNG (install pdftoppm, ImageMagick, or Ghostscript)")
|
print(f" ✗ Failed to convert {front_png.name}")
|
||||||
|
failed.append(example['name'])
|
||||||
|
|
||||||
# For single cards, also generate back page
|
# For single cards, also generate back page
|
||||||
if '--cards-per-page' in example['args'] and example['args'][example['args'].index('--cards-per-page') + 1] == '1':
|
if '--cards-per-page' in example['args'] and example['args'][example['args'].index('--cards-per-page') + 1] == '1':
|
||||||
|
|
@ -215,9 +233,13 @@ def main():
|
||||||
if pdf_to_png(str(pdf_path), str(back_png), dpi=150, page=2):
|
if pdf_to_png(str(pdf_path), str(back_png), dpi=150, page=2):
|
||||||
print(f" ✓ Generated {back_png.name}")
|
print(f" ✓ Generated {back_png.name}")
|
||||||
|
|
||||||
print("\nExample images generated in docs/images/")
|
if failed:
|
||||||
print("\nTo use in README:")
|
print(f"\n✗ Failed to generate {len(failed)} images: {', '.join(failed)}")
|
||||||
print("")
|
return 1
|
||||||
|
else:
|
||||||
|
print(f"\n✓ Successfully generated all {len(examples)} examples in docs/images/")
|
||||||
|
return 0
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
import sys
|
||||||
|
sys.exit(main())
|
||||||
Loading…
Reference in New Issue