Skip to content

Commit 4d8feb0

Browse files
mariomeyerclaude
andcommitted
feat(laravel): detect quality tools, capture baselines, and verify after upgrade
Detect Pint, PHPStan, ESLint, Prettier, Cypress, and Playwright during recon. Capture pass/fail baselines before the upgrade starts so the agent knows what was already broken vs what it regressed. Run detected tools conditionally in verify-fast (pint + phpstan) and verify-full (+ eslint) so CI-breaking regressions are caught during the upgrade, not after the PR is opened. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 229e6c6 commit 4d8feb0

5 files changed

Lines changed: 205 additions & 11 deletions

File tree

stacks/laravel/entrypoint.sh

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,41 @@ php artisan --version > /output/before-versions.txt 2>/dev/null || echo "unknown
7777
echo "Running baseline verification..."
7878
/skill/scripts/verify-full.sh 2>&1 | tee /output/baseline.log || echo "WARNING: Baseline verification had failures (expected pre-upgrade)."
7979

80+
# Capture quality tool baselines (non-fatal)
81+
echo "Capturing quality tool baselines..."
82+
mkdir -p /output/baseline
83+
84+
# Pint
85+
if [ -f pint.json ] || composer show laravel/pint >/dev/null 2>&1; then
86+
if [ -f vendor/bin/pint ]; then
87+
./vendor/bin/pint --test > /output/baseline/pint.log 2>&1 && echo "pass" > /output/baseline/pint.status || echo "fail" > /output/baseline/pint.status
88+
fi
89+
fi
90+
91+
# PHPStan
92+
if [ -f phpstan.neon ] || [ -f phpstan.neon.dist ]; then
93+
if [ -f vendor/bin/phpstan ]; then
94+
php -d memory_limit=512M ./vendor/bin/phpstan analyse --no-progress --error-format=json > /output/baseline/phpstan.json 2>&1 && echo "pass" > /output/baseline/phpstan.status || echo "fail" > /output/baseline/phpstan.status
95+
fi
96+
fi
97+
98+
# ESLint
99+
if npx eslint --version >/dev/null 2>&1; then
100+
npx eslint . > /output/baseline/eslint.log 2>&1 && echo "pass" > /output/baseline/eslint.status || echo "fail" > /output/baseline/eslint.status
101+
fi
102+
103+
# Cypress (dry-run only — verify config parses)
104+
if [ -f cypress.config.ts ] || [ -f cypress.config.js ]; then
105+
echo "detected" > /output/baseline/cypress.status
106+
fi
107+
108+
# Playwright (detect only)
109+
if [ -f playwright.config.ts ] || [ -f playwright.config.js ]; then
110+
echo "detected" > /output/baseline/playwright.status
111+
fi
112+
113+
echo "Quality baselines captured to /output/baseline/"
114+
80115
# Create .upgrade/ directory for all upgrade artifacts
81116
mkdir -p .upgrade/scripts
82117

@@ -91,6 +126,9 @@ cp /skill/scripts/verify-fast.sh .upgrade/scripts/verify-fast.sh
91126
cp /skill/scripts/verify-full.sh .upgrade/scripts/verify-full.sh
92127
chmod +x .upgrade/scripts/verify-*.sh
93128

129+
# Copy quality baselines into .upgrade/ so the agent can read them
130+
cp -r /output/baseline .upgrade/baseline 2>/dev/null || true
131+
94132
# Fetch the official Laravel upgrade guide
95133
echo "Fetching Laravel upgrade guide..."
96134
PREV_LARAVEL=$((TARGET_LARAVEL - 1))

stacks/laravel/scripts/recon.sh

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,5 +127,93 @@ echo "" >> "$REPORT"
127127
[ -f phpunit.xml ] && echo "- phpunit.xml exists" >> "$REPORT"
128128
[ -f phpunit.xml.dist ] && echo "- phpunit.xml.dist exists" >> "$REPORT"
129129

130+
echo "" >> "$REPORT"
131+
132+
# Quality tools detection
133+
echo "## Quality Tools" >> "$REPORT"
134+
echo "" >> "$REPORT"
135+
echo "| Tool | Detected | Config |" >> "$REPORT"
136+
echo "|------|----------|--------|" >> "$REPORT"
137+
138+
# Pint
139+
PINT_DETECTED="No"
140+
PINT_CONFIG=""
141+
if [ -f pint.json ]; then
142+
PINT_DETECTED="Yes"; PINT_CONFIG="pint.json"
143+
elif composer show laravel/pint >/dev/null 2>&1; then
144+
PINT_DETECTED="Yes"; PINT_CONFIG="(composer package)"
145+
fi
146+
echo "| Pint | $PINT_DETECTED | $PINT_CONFIG |" >> "$REPORT"
147+
148+
# PHPStan / Larastan
149+
PHPSTAN_DETECTED="No"
150+
PHPSTAN_CONFIG=""
151+
if [ -f phpstan.neon ]; then
152+
PHPSTAN_DETECTED="Yes"; PHPSTAN_CONFIG="phpstan.neon"
153+
elif [ -f phpstan.neon.dist ]; then
154+
PHPSTAN_DETECTED="Yes"; PHPSTAN_CONFIG="phpstan.neon.dist"
155+
elif composer show nunomaduro/larastan >/dev/null 2>&1 || composer show phpstan/phpstan >/dev/null 2>&1; then
156+
PHPSTAN_DETECTED="Yes"; PHPSTAN_CONFIG="(composer package)"
157+
fi
158+
echo "| PHPStan | $PHPSTAN_DETECTED | $PHPSTAN_CONFIG |" >> "$REPORT"
159+
160+
# PHP CS Fixer
161+
CSFIXER_DETECTED="No"
162+
CSFIXER_CONFIG=""
163+
if [ -f .php-cs-fixer.php ]; then
164+
CSFIXER_DETECTED="Yes"; CSFIXER_CONFIG=".php-cs-fixer.php"
165+
elif [ -f .php-cs-fixer.dist.php ]; then
166+
CSFIXER_DETECTED="Yes"; CSFIXER_CONFIG=".php-cs-fixer.dist.php"
167+
fi
168+
echo "| PHP CS Fixer | $CSFIXER_DETECTED | $CSFIXER_CONFIG |" >> "$REPORT"
169+
170+
# ESLint
171+
ESLINT_DETECTED="No"
172+
ESLINT_CONFIG=""
173+
for f in .eslintrc .eslintrc.js .eslintrc.json .eslintrc.yml .eslintrc.yaml eslint.config.js eslint.config.mjs eslint.config.ts; do
174+
if [ -f "$f" ]; then
175+
ESLINT_DETECTED="Yes"; ESLINT_CONFIG="$f"; break
176+
fi
177+
done
178+
if [ "$ESLINT_DETECTED" = "No" ] && [ -f package.json ] && jq -e '.devDependencies.eslint // .dependencies.eslint' package.json >/dev/null 2>&1; then
179+
ESLINT_DETECTED="Yes"; ESLINT_CONFIG="(package.json)"
180+
fi
181+
echo "| ESLint | $ESLINT_DETECTED | $ESLINT_CONFIG |" >> "$REPORT"
182+
183+
# Prettier
184+
PRETTIER_DETECTED="No"
185+
PRETTIER_CONFIG=""
186+
for f in .prettierrc .prettierrc.js .prettierrc.json .prettierrc.yml .prettierrc.yaml .prettierrc.toml prettier.config.js prettier.config.mjs; do
187+
if [ -f "$f" ]; then
188+
PRETTIER_DETECTED="Yes"; PRETTIER_CONFIG="$f"; break
189+
fi
190+
done
191+
if [ "$PRETTIER_DETECTED" = "No" ] && [ -f package.json ] && jq -e '.devDependencies.prettier // .dependencies.prettier' package.json >/dev/null 2>&1; then
192+
PRETTIER_DETECTED="Yes"; PRETTIER_CONFIG="(package.json)"
193+
fi
194+
echo "| Prettier | $PRETTIER_DETECTED | $PRETTIER_CONFIG |" >> "$REPORT"
195+
196+
# Cypress
197+
CYPRESS_DETECTED="No"
198+
CYPRESS_CONFIG=""
199+
if [ -f cypress.config.ts ]; then
200+
CYPRESS_DETECTED="Yes"; CYPRESS_CONFIG="cypress.config.ts"
201+
elif [ -f cypress.config.js ]; then
202+
CYPRESS_DETECTED="Yes"; CYPRESS_CONFIG="cypress.config.js"
203+
elif [ -d cypress ]; then
204+
CYPRESS_DETECTED="Yes"; CYPRESS_CONFIG="cypress/"
205+
fi
206+
echo "| Cypress | $CYPRESS_DETECTED | $CYPRESS_CONFIG |" >> "$REPORT"
207+
208+
# Playwright
209+
PLAYWRIGHT_DETECTED="No"
210+
PLAYWRIGHT_CONFIG=""
211+
if [ -f playwright.config.ts ]; then
212+
PLAYWRIGHT_DETECTED="Yes"; PLAYWRIGHT_CONFIG="playwright.config.ts"
213+
elif [ -f playwright.config.js ]; then
214+
PLAYWRIGHT_DETECTED="Yes"; PLAYWRIGHT_CONFIG="playwright.config.js"
215+
fi
216+
echo "| Playwright | $PLAYWRIGHT_DETECTED | $PLAYWRIGHT_CONFIG |" >> "$REPORT"
217+
130218
echo ""
131219
echo "Recon complete. Report saved to $REPORT"

stacks/laravel/scripts/verify-fast.sh

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,34 @@ set -e
44

55
echo "=== verify-fast ==="
66

7-
echo "[1/3] composer validate..."
7+
echo "[1/5] composer validate..."
88
composer validate --no-check-all --no-check-publish 2>&1
99

10-
echo "[2/3] php artisan route:list..."
10+
echo "[2/5] php artisan route:list..."
1111
php artisan route:list 2>&1 | tail -5
1212
echo "(route:list OK)"
1313

14-
echo "[3/3] php artisan test (fast)..."
14+
echo "[3/5] php artisan test (fast)..."
1515
php artisan test --stop-on-failure 2>&1
1616

17+
# [4/5] Pint auto-fix (if installed)
18+
if [ -f vendor/bin/pint ]; then
19+
echo "[4/5] pint (auto-fix)..."
20+
php vendor/bin/pint 2>&1
21+
else
22+
echo "[4/5] pint — skipped (not installed)"
23+
fi
24+
25+
# [5/5] PHPStan (if configured)
26+
if [ -f phpstan.neon ] || [ -f phpstan.neon.dist ]; then
27+
if [ -f vendor/bin/phpstan ]; then
28+
echo "[5/5] phpstan analyse..."
29+
php -d memory_limit=512M vendor/bin/phpstan analyse --no-progress 2>&1
30+
else
31+
echo "[5/5] phpstan — skipped (not installed)"
32+
fi
33+
else
34+
echo "[5/5] phpstan — skipped (no config)"
35+
fi
36+
1737
echo "=== verify-fast PASSED ==="

stacks/laravel/scripts/verify-full.sh

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,53 @@ set -e
44

55
echo "=== verify-full ==="
66

7-
echo "[1/6] composer validate..."
7+
echo "[1/9] composer validate..."
88
composer validate 2>&1
99

10-
echo "[2/6] php artisan route:list..."
10+
echo "[2/9] php artisan route:list..."
1111
php artisan route:list 2>&1 | tail -5
1212
echo "(route:list OK)"
1313

14-
echo "[3/6] php artisan migrate:fresh --seed..."
14+
echo "[3/9] php artisan migrate:fresh --seed..."
1515
touch database/database.sqlite 2>/dev/null || true
1616
php artisan migrate:fresh --seed --force 2>&1
1717

18-
echo "[4/6] php artisan test..."
18+
echo "[4/9] php artisan test..."
1919
php artisan test 2>&1
2020

21-
echo "[5/6] npm run build..."
21+
echo "[5/9] npm run build..."
2222
npm run build 2>&1
2323

24-
echo "[6/6] composer audit + npm audit..."
24+
echo "[6/9] composer audit + npm audit..."
2525
composer audit 2>&1 || echo "(composer audit warnings — non-blocking)"
2626
npm audit --production 2>&1 || echo "(npm audit warnings — non-blocking)"
2727

28+
# [7/9] Pint auto-fix (if installed)
29+
if [ -f vendor/bin/pint ]; then
30+
echo "[7/9] pint (auto-fix)..."
31+
php vendor/bin/pint 2>&1
32+
else
33+
echo "[7/9] pint — skipped (not installed)"
34+
fi
35+
36+
# [8/9] PHPStan (if configured)
37+
if [ -f phpstan.neon ] || [ -f phpstan.neon.dist ]; then
38+
if [ -f vendor/bin/phpstan ]; then
39+
echo "[8/9] phpstan analyse..."
40+
php -d memory_limit=512M vendor/bin/phpstan analyse --no-progress 2>&1
41+
else
42+
echo "[8/9] phpstan — skipped (not installed)"
43+
fi
44+
else
45+
echo "[8/9] phpstan — skipped (no config)"
46+
fi
47+
48+
# [9/9] ESLint (if installed)
49+
if npx eslint --version >/dev/null 2>&1; then
50+
echo "[9/9] eslint..."
51+
npx eslint . 2>&1
52+
else
53+
echo "[9/9] eslint — skipped (not installed)"
54+
fi
55+
2856
echo "=== verify-full PASSED ==="

stacks/laravel/templates/CLAUDE.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ Every time you start (including restarts):
4444
- Notes about config changes, breaking changes fixed, etc.
4545
- A Phase Summary entry with status and one-line description
4646
- The phase commit MUST include the updated changelog. Verify the changelog reflects the phase before committing.
47+
- In the **final phase**, add a "Quality Tools" section to changelog.md showing before/after status:
48+
| Tool | Before | After | Notes |
49+
|------|--------|-------|-------|
50+
| Pint | Pass | Pass | Auto-fixed after each phase |
51+
| PHPStan | 12 errors | 8 errors | Fixed 4 upgrade-related errors |
4752

4853
### Constraints
4954
- **Upgrade everything to latest** — the goal is eliminating tech debt and security risks. If a major version upgrade requires code changes (namespace migrations, API changes, config updates), DO those changes. This is expected.
@@ -86,10 +91,25 @@ This phase is optional — if the current constraint already covers the containe
8691
- `.upgrade/laravel-upgrade-guide.html` — the official Laravel upgrade guide for the target version (if available). **Read this during Phase 1** for breaking changes and required migration steps.
8792
- `.upgrade/recon-report.md` — pre-analyzed repo overview: package usage, component counts, test suite shape
8893

94+
## Baseline Awareness
95+
96+
Before the upgrade started, quality tools were run and results saved to `.upgrade/baseline/`:
97+
- `pint.status` / `pint.log` — code style baseline
98+
- `phpstan.status` / `phpstan.json` — static analysis baseline
99+
- `eslint.status` / `eslint.log` — JS linting baseline
100+
- `cypress.status` — e2e test presence
101+
102+
**Rules:**
103+
- If a tool was PASSING before the upgrade (`pass` in .status file), it MUST still pass after. Fix any regressions you introduce.
104+
- If a tool was FAILING before the upgrade (`fail` in .status file), you are NOT required to fix pre-existing failures. But if you can fix them easily as part of the upgrade, do so.
105+
- Pint runs automatically in auto-fix mode via verify-fast.sh after every change. Include any Pint-reformatted files in your phase commit.
106+
- If PHPStan/Larastan is installed: run `./vendor/bin/phpstan analyse` and fix errors that you introduced. Ignore pre-existing errors (compare with baseline).
107+
- Log any baseline comparison notes in `.upgrade/run-log.md`
108+
89109
## Verification Scripts
90110

91-
- `.upgrade/scripts/verify-fast.sh` — composer validate + route:list + tests (run frequently)
92-
- `.upgrade/scripts/verify-full.sh` — above + migrate:fresh + npm build + audits (run before phase completion)
111+
- `.upgrade/scripts/verify-fast.sh` — composer validate + route:list + tests + pint auto-fix + phpstan (run frequently)
112+
- `.upgrade/scripts/verify-full.sh` — above + migrate:fresh + npm build + audits + eslint (run before phase completion)
93113

94114
## Useful Commands
95115

0 commit comments

Comments
 (0)