Skip to content

Commit bc15671

Browse files
paddymulclaudegithub-actions[bot]
authored
Publish release screenshots to GitHub Pages (#656)
* feat: publish release screenshots to GitHub Pages On each release, captures theme screenshots via Playwright and pushes them to gh-pages under screenshots/<version>/. Files are named <test-name>--<version>.png for predictable URLs. An index.html is regenerated listing all releases. Screenshots are stored in gh-pages only, not checked into the repo. URL pattern: buckaroo-data.github.io/buckaroo/screenshots/<version>/<name>.png Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address codex review — reorder screenshots, preserve gh-pages - Move screenshot capture + publish before GitHub release creation, so if screenshots fail the retry logic still works correctly - Add keep_files: true to Storybook gh-pages deploy so it doesn't wipe the screenshots/ directory on each push to main Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: include screenshots from gh-pages in GitHub Pages deploy The Pages site is deployed via deploy-ghpage.yml (actions/deploy-pages), not from the gh-pages branch directly. Screenshots stored in gh-pages need to be merged into the Storybook output before uploading. Also fixes duplicate checkout step. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: temporarily allow deploy from this branch Will revert before merge. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * revert: remove temporary deploy condition for testing Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 6d14235 commit bc15671

4 files changed

Lines changed: 164 additions & 1 deletion

File tree

.github/workflows/deploy-ghpage.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ jobs:
1515
steps:
1616
- name: Checkout
1717
uses: actions/checkout@v6
18-
- uses: actions/checkout@v6
18+
with:
19+
fetch-depth: 0
1920
- uses: pnpm/action-setup@v4
2021
with:
2122
run_install: true
@@ -43,6 +44,16 @@ jobs:
4344
# cd docs
4445
# jupyter lite build --contents ./example-notebooks --output-dir ./_output
4546

47+
- name: Merge screenshots into Storybook output
48+
run: |
49+
git fetch origin gh-pages || true
50+
if git rev-parse origin/gh-pages &>/dev/null; then
51+
git checkout origin/gh-pages -- screenshots/ 2>/dev/null || true
52+
if [ -d screenshots ]; then
53+
cp -r screenshots/ ./packages/buckaroo-js-core/dist/storybook/screenshots/
54+
fi
55+
fi
56+
4657
- name: Upload artifact
4758
uses: actions/upload-pages-artifact@v3
4859
with:

.github/workflows/publish-storybook.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ jobs:
3838
with:
3939
github_token: ${{ secrets.GITHUB_TOKEN }}
4040
publish_dir: ./packages/buckaroo-js-core/dist/storybook
41+
keep_files: true
4142
# - name: Setup Pages
4243
# uses: actions/configure-pages@v3
4344
# - name: Upload Artifact

.github/workflows/release.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,43 @@ jobs:
135135
./scripts/full_build.sh
136136
uv build --sdist
137137
138+
- name: Capture release screenshots
139+
run: |
140+
cd packages/buckaroo-js-core
141+
npx playwright install chromium
142+
npx playwright test pw-tests/theme-screenshots.spec.ts --reporter=line || true
143+
VERSION="${{ steps.versions.outputs.new }}"
144+
mkdir -p /tmp/screenshots-staging/"$VERSION"
145+
for f in screenshots/*.png; do
146+
[ -f "$f" ] || continue
147+
base=$(basename "$f" .png)
148+
cp "$f" /tmp/screenshots-staging/"$VERSION"/"${base}--${VERSION}.png"
149+
done
150+
151+
- name: Publish screenshots to GitHub Pages
152+
run: |
153+
VERSION="${{ steps.versions.outputs.new }}"
154+
git fetch origin gh-pages
155+
git worktree add /tmp/gh-pages gh-pages
156+
mkdir -p /tmp/gh-pages/screenshots/"$VERSION"
157+
cp /tmp/screenshots-staging/"$VERSION"/*.png /tmp/gh-pages/screenshots/"$VERSION"/
158+
python scripts/generate_screenshots_index.py /tmp/gh-pages/screenshots
159+
cd /tmp/gh-pages
160+
git add screenshots/
161+
git diff --cached --quiet && echo "No screenshot changes" && exit 0
162+
git config user.name "github-actions[bot]"
163+
git config user.email "github-actions[bot]@users.noreply.github.com"
164+
git commit -m "screenshots: add release $VERSION screenshots"
165+
git push origin gh-pages
166+
167+
- name: Create GitHub release
168+
env:
169+
GH_TOKEN: ${{ github.token }}
170+
run: |
171+
gh release create "${{ steps.versions.outputs.new }}" \
172+
--title "${{ steps.versions.outputs.new }}" \
173+
--notes-file /tmp/release_notes.md
174+
138175
- name: Upload release assets
139176
env:
140177
GH_TOKEN: ${{ github.token }}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#!/usr/bin/env python3
2+
"""Generate an index.html for the screenshots gallery on gh-pages.
3+
4+
Reads the screenshots/ directory structure and produces a browsable page
5+
listing all releases with their screenshots.
6+
7+
Usage:
8+
python scripts/generate_screenshots_index.py <screenshots_dir>
9+
10+
The screenshots_dir should contain subdirectories named by version
11+
(e.g. screenshots/0.13.3/) each containing .png files.
12+
"""
13+
import sys
14+
from pathlib import Path
15+
16+
HTML_TEMPLATE = """\
17+
<!DOCTYPE html>
18+
<html lang="en">
19+
<head>
20+
<meta charset="utf-8">
21+
<meta name="viewport" content="width=device-width, initial-scale=1">
22+
<title>Buckaroo Screenshots</title>
23+
<style>
24+
* { box-sizing: border-box; margin: 0; padding: 0; }
25+
body { font-family: system-ui, sans-serif; background: #111; color: #eee; padding: 2rem; }
26+
h1 { margin-bottom: 1rem; }
27+
h2 { margin: 2rem 0 1rem; border-bottom: 1px solid #333; padding-bottom: 0.5rem; }
28+
.release { margin-bottom: 2rem; }
29+
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); gap: 1rem; }
30+
.card { background: #1a1a1a; border-radius: 8px; overflow: hidden; }
31+
.card img { width: 100%%; display: block; cursor: pointer; }
32+
.card .label { padding: 0.5rem; font-size: 0.85rem; color: #aaa; }
33+
a { color: #58a6ff; text-decoration: none; }
34+
a:hover { text-decoration: underline; }
35+
.nav { margin-bottom: 2rem; }
36+
.nav a { margin-right: 1rem; }
37+
</style>
38+
</head>
39+
<body>
40+
<h1>Buckaroo Screenshots</h1>
41+
<div class="nav">%(nav)s</div>
42+
%(releases)s
43+
</body>
44+
</html>
45+
"""
46+
47+
RELEASE_TEMPLATE = """\
48+
<div class="release" id="%(version)s">
49+
<h2>%(version)s</h2>
50+
<div class="grid">
51+
%(cards)s
52+
</div>
53+
</div>
54+
"""
55+
56+
CARD_TEMPLATE = """\
57+
<div class="card">
58+
<a href="%(url)s" target="_blank"><img src="%(url)s" alt="%(name)s" loading="lazy"></a>
59+
<div class="label">%(name)s</div>
60+
</div>
61+
"""
62+
63+
64+
def main():
65+
if len(sys.argv) != 2:
66+
print(f"Usage: {sys.argv[0]} <screenshots_dir>", file=sys.stderr)
67+
sys.exit(1)
68+
69+
screenshots_dir = Path(sys.argv[1])
70+
if not screenshots_dir.is_dir():
71+
print(f"Not a directory: {screenshots_dir}", file=sys.stderr)
72+
sys.exit(1)
73+
74+
# Collect versions (sorted newest first by semver)
75+
versions = sorted(
76+
[d.name for d in screenshots_dir.iterdir() if d.is_dir() and not d.name.startswith('.')],
77+
key=lambda v: [int(x) for x in v.split('.')],
78+
reverse=True,
79+
)
80+
81+
nav_links = []
82+
release_blocks = []
83+
84+
for version in versions:
85+
version_dir = screenshots_dir / version
86+
pngs = sorted(p.name for p in version_dir.iterdir() if p.suffix == '.png')
87+
if not pngs:
88+
continue
89+
90+
nav_links.append(f'<a href="#{version}">{version}</a>')
91+
92+
cards = []
93+
for png in pngs:
94+
name = png.replace('.png', '')
95+
url = f"{version}/{png}"
96+
cards.append(CARD_TEMPLATE % {'url': url, 'name': name})
97+
98+
release_blocks.append(RELEASE_TEMPLATE % {
99+
'version': version,
100+
'cards': '\n'.join(cards),
101+
})
102+
103+
html = HTML_TEMPLATE % {
104+
'nav': ' '.join(nav_links),
105+
'releases': '\n'.join(release_blocks),
106+
}
107+
108+
output = screenshots_dir / 'index.html'
109+
output.write_text(html)
110+
print(f"Wrote {output} ({len(versions)} releases)")
111+
112+
113+
if __name__ == '__main__':
114+
main()

0 commit comments

Comments
 (0)