mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-13 16:04:58 +02:00
feat: PR screenshots in /ship template + upload/auth tests
Adds Step 6.75 to /ship: detects frontend scope, offers responsive screenshots, handles auth inline, captures via browse, uploads to gstack.gg, embeds watermarked images in PR body. Tests cover screenshot-upload (usage, missing file, auth check, slug sanitization) and gstack-auth device code flow (happy path, expired, invalid secret, SSH fallback). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -285,6 +285,7 @@ You are running the `/ship` workflow. This is a **non-interactive, fully automat
|
||||
- Greptile review comments that need user decision (complex fixes, false positives)
|
||||
- TODOS.md missing and user wants to create one (ask — see Step 5.5)
|
||||
- TODOS.md disorganized and user wants to reorganize (ask — see Step 5.5)
|
||||
- Screenshots: asking whether to capture PR screenshots (see Step 6.75)
|
||||
|
||||
**Never stop for:**
|
||||
- Uncommitted changes (always include them)
|
||||
@@ -1410,6 +1411,80 @@ Claiming work is complete without verification is dishonesty, not efficiency.
|
||||
|
||||
---
|
||||
|
||||
## Step 6.75: PR Screenshots (optional)
|
||||
|
||||
Check if this PR includes frontend/UI changes:
|
||||
|
||||
```bash
|
||||
source <(~/.claude/skills/gstack/bin/gstack-diff-scope <base> 2>/dev/null) || true
|
||||
echo "SCOPE_FRONTEND: ${SCOPE_FRONTEND:-false}"
|
||||
```
|
||||
|
||||
If `SCOPE_FRONTEND=true`, check if the browse binary is available:
|
||||
|
||||
```bash
|
||||
_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
|
||||
B=""
|
||||
[ -n "$_ROOT" ] && [ -x "$_ROOT/.claude/skills/gstack/browse/dist/browse" ] && B="$_ROOT/.claude/skills/gstack/browse/dist/browse"
|
||||
[ -z "$B" ] && B=~/.claude/skills/gstack/browse/dist/browse
|
||||
[ -x "$B" ] && echo "BROWSE_READY" || echo "BROWSE_NOT_AVAILABLE"
|
||||
```
|
||||
|
||||
If both frontend scope AND browse are available, use AskUserQuestion:
|
||||
|
||||
> This PR changes frontend code. Want to add screenshots to the PR? Your screenshots
|
||||
> will get a "Screenshots · GStack" watermark — free visual evidence in your PR.
|
||||
>
|
||||
> A) Responsive screenshots (mobile + tablet + desktop) — recommended
|
||||
> B) Single desktop screenshot
|
||||
> C) Skip screenshots
|
||||
|
||||
If the user chooses A or B:
|
||||
|
||||
1. **Check authentication:**
|
||||
```bash
|
||||
~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null
|
||||
```
|
||||
If not authenticated, run `~/.claude/skills/gstack/bin/gstack-auth` inline. Wait for completion.
|
||||
|
||||
2. **Detect app URL:**
|
||||
Read CLAUDE.md and look for an `app_url` or `dev_url` setting. If not found, use
|
||||
AskUserQuestion: "What URL should I screenshot? (e.g., http://localhost:3000)"
|
||||
Persist the answer to CLAUDE.md under a `## Screenshots` section so we never ask again.
|
||||
|
||||
3. **Capture screenshots:**
|
||||
For option A (responsive):
|
||||
```bash
|
||||
$B goto <url>
|
||||
$B responsive /tmp/gstack-pr-screenshots
|
||||
```
|
||||
For option B (single):
|
||||
```bash
|
||||
$B goto <url>
|
||||
$B screenshot /tmp/gstack-pr-screenshots/desktop.png
|
||||
```
|
||||
|
||||
4. **Upload each screenshot:**
|
||||
```bash
|
||||
REPO_SLUG=$(basename "$(git rev-parse --show-toplevel 2>/dev/null)")
|
||||
BRANCH=$(git branch --show-current 2>/dev/null)
|
||||
for img in /tmp/gstack-pr-screenshots/*.png; do
|
||||
VIEWPORT=$(basename "$img" .png)
|
||||
URL=$(~/.claude/skills/gstack/bin/gstack-screenshot-upload "$img" \
|
||||
--repo-slug "$REPO_SLUG" --branch "$BRANCH" --viewport "$VIEWPORT")
|
||||
echo "SCREENSHOT_URL[$VIEWPORT]=$URL"
|
||||
done
|
||||
```
|
||||
|
||||
5. **Store proxy URLs** for use in Step 8's PR body.
|
||||
|
||||
**Failure handling:** If any step fails (browse unavailable, auth fails, upload fails),
|
||||
warn in output and continue without screenshots. Never block /ship for screenshot failures.
|
||||
|
||||
If `SCOPE_FRONTEND=false` or browse is not available, skip this step silently.
|
||||
|
||||
---
|
||||
|
||||
## Step 7: Push
|
||||
|
||||
Push to the remote with upstream tracking:
|
||||
@@ -1454,6 +1529,18 @@ gh pr create --base <base> --title "<type>: <summary>" --body "$(cat <<'EOF'
|
||||
<If TODOS.md created or reorganized: note that>
|
||||
<If TODOS.md doesn't exist and user skipped: omit this section>
|
||||
|
||||
## Screenshots
|
||||
<If Step 6.75 captured screenshots, add a responsive table:>
|
||||
|
||||
| Mobile | Tablet | Desktop |
|
||||
|--------|--------|---------|
|
||||
|  |  |  |
|
||||
|
||||
Screenshots by [GStack](https://gstack.gg)
|
||||
|
||||
<If single screenshot: just the image + caption>
|
||||
<If no screenshots captured or Step 6.75 was skipped: omit this section entirely>
|
||||
|
||||
## Test plan
|
||||
- [x] All Rails tests pass (N runs, 0 failures)
|
||||
- [x] All Vitest tests pass (N tests)
|
||||
|
||||
@@ -34,6 +34,7 @@ You are running the `/ship` workflow. This is a **non-interactive, fully automat
|
||||
- Greptile review comments that need user decision (complex fixes, false positives)
|
||||
- TODOS.md missing and user wants to create one (ask — see Step 5.5)
|
||||
- TODOS.md disorganized and user wants to reorganize (ask — see Step 5.5)
|
||||
- Screenshots: asking whether to capture PR screenshots (see Step 6.75)
|
||||
|
||||
**Never stop for:**
|
||||
- Uncommitted changes (always include them)
|
||||
@@ -462,6 +463,80 @@ Claiming work is complete without verification is dishonesty, not efficiency.
|
||||
|
||||
---
|
||||
|
||||
## Step 6.75: PR Screenshots (optional)
|
||||
|
||||
Check if this PR includes frontend/UI changes:
|
||||
|
||||
```bash
|
||||
source <(~/.claude/skills/gstack/bin/gstack-diff-scope <base> 2>/dev/null) || true
|
||||
echo "SCOPE_FRONTEND: ${SCOPE_FRONTEND:-false}"
|
||||
```
|
||||
|
||||
If `SCOPE_FRONTEND=true`, check if the browse binary is available:
|
||||
|
||||
```bash
|
||||
_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
|
||||
B=""
|
||||
[ -n "$_ROOT" ] && [ -x "$_ROOT/.claude/skills/gstack/browse/dist/browse" ] && B="$_ROOT/.claude/skills/gstack/browse/dist/browse"
|
||||
[ -z "$B" ] && B=~/.claude/skills/gstack/browse/dist/browse
|
||||
[ -x "$B" ] && echo "BROWSE_READY" || echo "BROWSE_NOT_AVAILABLE"
|
||||
```
|
||||
|
||||
If both frontend scope AND browse are available, use AskUserQuestion:
|
||||
|
||||
> This PR changes frontend code. Want to add screenshots to the PR? Your screenshots
|
||||
> will get a "Screenshots · GStack" watermark — free visual evidence in your PR.
|
||||
>
|
||||
> A) Responsive screenshots (mobile + tablet + desktop) — recommended
|
||||
> B) Single desktop screenshot
|
||||
> C) Skip screenshots
|
||||
|
||||
If the user chooses A or B:
|
||||
|
||||
1. **Check authentication:**
|
||||
```bash
|
||||
~/.claude/skills/gstack/bin/gstack-auth-refresh --check 2>/dev/null
|
||||
```
|
||||
If not authenticated, run `~/.claude/skills/gstack/bin/gstack-auth` inline. Wait for completion.
|
||||
|
||||
2. **Detect app URL:**
|
||||
Read CLAUDE.md and look for an `app_url` or `dev_url` setting. If not found, use
|
||||
AskUserQuestion: "What URL should I screenshot? (e.g., http://localhost:3000)"
|
||||
Persist the answer to CLAUDE.md under a `## Screenshots` section so we never ask again.
|
||||
|
||||
3. **Capture screenshots:**
|
||||
For option A (responsive):
|
||||
```bash
|
||||
$B goto <url>
|
||||
$B responsive /tmp/gstack-pr-screenshots
|
||||
```
|
||||
For option B (single):
|
||||
```bash
|
||||
$B goto <url>
|
||||
$B screenshot /tmp/gstack-pr-screenshots/desktop.png
|
||||
```
|
||||
|
||||
4. **Upload each screenshot:**
|
||||
```bash
|
||||
REPO_SLUG=$(basename "$(git rev-parse --show-toplevel 2>/dev/null)")
|
||||
BRANCH=$(git branch --show-current 2>/dev/null)
|
||||
for img in /tmp/gstack-pr-screenshots/*.png; do
|
||||
VIEWPORT=$(basename "$img" .png)
|
||||
URL=$(~/.claude/skills/gstack/bin/gstack-screenshot-upload "$img" \
|
||||
--repo-slug "$REPO_SLUG" --branch "$BRANCH" --viewport "$VIEWPORT")
|
||||
echo "SCREENSHOT_URL[$VIEWPORT]=$URL"
|
||||
done
|
||||
```
|
||||
|
||||
5. **Store proxy URLs** for use in Step 8's PR body.
|
||||
|
||||
**Failure handling:** If any step fails (browse unavailable, auth fails, upload fails),
|
||||
warn in output and continue without screenshots. Never block /ship for screenshot failures.
|
||||
|
||||
If `SCOPE_FRONTEND=false` or browse is not available, skip this step silently.
|
||||
|
||||
---
|
||||
|
||||
## Step 7: Push
|
||||
|
||||
Push to the remote with upstream tracking:
|
||||
@@ -506,6 +581,18 @@ gh pr create --base <base> --title "<type>: <summary>" --body "$(cat <<'EOF'
|
||||
<If TODOS.md created or reorganized: note that>
|
||||
<If TODOS.md doesn't exist and user skipped: omit this section>
|
||||
|
||||
## Screenshots
|
||||
<If Step 6.75 captured screenshots, add a responsive table:>
|
||||
|
||||
| Mobile | Tablet | Desktop |
|
||||
|--------|--------|---------|
|
||||
|  |  |  |
|
||||
|
||||
Screenshots by [GStack](https://gstack.gg)
|
||||
|
||||
<If single screenshot: just the image + caption>
|
||||
<If no screenshots captured or Step 6.75 was skipped: omit this section entirely>
|
||||
|
||||
## Test plan
|
||||
- [x] All Rails tests pass (N runs, 0 failures)
|
||||
- [x] All Vitest tests pass (N tests)
|
||||
|
||||
Reference in New Issue
Block a user