Skip to content

Smart automation for Laravel project bootstrapping#33

Merged
munezaclovis merged 8 commits intomainfrom
feat/smart-automation
Mar 9, 2026
Merged

Smart automation for Laravel project bootstrapping#33
munezaclovis merged 8 commits intomainfrom
feat/smart-automation

Conversation

@munezaclovis
Copy link
Copy Markdown
Contributor

@munezaclovis munezaclovis commented Mar 9, 2026

Summary

  • Automation config: New automation: section in ~/.pv/pv.yml with tri-state gates (true/false/ask) for each automation feature
  • Pipeline runner: internal/automation/Step interface + RunPipeline() with gate checking and interactive huh prompts
  • Laravel intelligence: internal/laravel/ — smart env vars (maps running services → Laravel config), database name resolution from .env.example, artisan/composer runners, 8 pipeline step implementations
  • pv link automation: copies .env.example, generates APP_KEY, installs Octane worker, runs composer install, detects/binds services, sets APP_URL, creates databases, runs migrations
  • Service hooks: auto-updates linked project .env files on service:add/service:start, applies safe fallbacks on service:stop/service:remove (only overwrites values pv originally set)
  • File watcher: fsnotify-based pv.yml watcher with 200ms debounce, re-resolves PHP versions and reconfigures server on config changes
  • Caddyfile update: vendor/autoload.php added to FrankenPHP Octane worker watch directive

Test plan

  • go test ./... — all 26 packages pass (0 failures)
  • Config tests: default automation values, round-trip save/load, missing section defaults
  • Pipeline tests: gate on/off/ask, non-interactive mode, confirm/deny prompts
  • Laravel tests: smart env vars, fallback mapping, database name resolution, project helpers, all 8 steps
  • Link tests: env copy, APP_URL setting, non-Laravel skip, Octane re-detection, existing env preservation
  • Service hooks tests: extract helpers, fallback integration
  • Watcher tests: change detection, delete detection, 200ms debounce, unwatch, non-pv.yml filtering
  • Caddy tests: Octane template includes vendor/autoload.php watch
  • Manual smoke test with a real Laravel project

Extend Settings with an Automation section that controls which
link-time steps run automatically (true/false/ask). Includes
DefaultAutomation(), applyAutomationDefaults() called after
YAML unmarshal, and three new tests covering defaults, round-trip
serialization, and missing-section defaulting.
Introduce internal/automation/ package with:
- Context struct carrying project state through pipeline steps
- Step interface (Label, Gate, ShouldRun, Run)
- RunPipeline() that iterates steps, checks gates against config,
  handles AutoOn/AutoOff/AutoAsk modes with TTY detection
- LookupGate() mapping gate strings to Automation config fields
- ConfirmFunc using huh for interactive confirmation prompts
- Swappable isInteractiveFunc and ConfirmFunc for test mocking
- Seven tests covering skip, gate-off, gate-on, ask-noninteractive,
  ask-confirmed, ask-denied, and table-driven LookupGate
…ipeline steps

Implements internal/laravel/ with four modules:

- env.go: SmartEnvVars() maps bound services to Laravel behavioral env vars
  (cache, session, queue, filesystem, mail). FallbackMapping() provides safe
  defaults when services are removed.

- database.go: ResolveDatabaseName() reads DB_DATABASE from .env.example,
  falls back to sanitized project name, and ignores the generic "laravel"
  default.

- artisan.go: Project helpers (HasComposerJSON, HasVendorDir, HasEnvExample,
  HasEnvFile, HasOctaneWorker, HasOctanePackage, ReadAppKey) and command
  runners (RunArtisan, KeyGenerate, Migrate, OctaneInstall).

- steps.go: All 8 automation.Step implementations — CopyEnvStep,
  GenerateKeyStep, SetAppURLStep, InstallOctaneStep, ComposerInstallStep,
  DetectServicesStep, CreateDatabaseStep, RunMigrationsStep. Each step has
  correct gate strings, ShouldRun guards, and Run logic.

55 tests covering all public functions and step ShouldRun/Run behavior.
CreateDatabaseStep uses index-based slice access to correctly mutate the
registry project's Databases field.
Integrates the automation pipeline into cmd/link.go so that `pv link`
automatically runs setup steps for Laravel projects: copy .env, generate
app key, install Octane, run composer install (pre-Caddyfile), then
detect services, set APP_URL, create database, and run migrations
(post-binding). Re-detects project type as laravel-octane if the Octane
worker file exists after pre-steps. Adds five integration tests covering
env copy, APP_URL setting, non-Laravel skip, Octane re-detection, and
existing .env preservation.
When services are added/started, update .env files for all linked
Laravel projects with connection vars and smart Laravel vars (e.g.,
CACHE_STORE=redis). When services are stopped/removed, apply safe
fallback values (e.g., CACHE_STORE=file) only when the current value
matches what pv originally set. Respects automation settings
(ServiceEnvUpdate, ServiceFallback) with on/off/ask modes.
Introduce fsnotify-based file watcher that monitors linked project
directories for pv.yml changes, debounces rapid edits (200ms), and
automatically re-resolves PHP versions when config files are modified
or deleted. The watcher integrates into the server supervisor lifecycle
and is dynamically updated via link/unlink commands.

Also update Octane Caddyfile templates (both main and version-specific)
to watch vendor/autoload.php alongside the existing **/*.php glob, so
FrankenPHP workers restart when Composer dependencies change.
Invalid values like "banana" in pv.yml automation config are now
reset to their defaults instead of silently falling through to
AutoOn behavior in the pipeline runner.
- Reorder preSteps: ComposerInstall before GenerateKey/InstallOctane
  (artisan needs vendor/ to bootstrap)
- Pipeline continues on step failures (best-effort automation)
- ConfirmFunc returns (bool, error) to propagate Ctrl+C as abort
- Export IsInteractive() for service hooks to check before prompting
- Service hooks: separate LoadSettings error from AutoOff, add
  IsInteractive guard for AutoAsk mode
- Log errors instead of discarding: WatchProject/UnwatchProject,
  fsnotify errors, reg.Save during Octane re-detection,
  caddy.GenerateServiceSiteConfigs in service:remove
- Unknown gates default to AutoAsk (not AutoOn) for safety
- SetAppURLStep.ShouldRun checks .env exists to avoid creating
  broken .env with only APP_URL
- RunArtisan/ComposerInstall include command output in errors
- All watcher/server messages use stderr (not stdout)
@munezaclovis munezaclovis merged commit 65a40de into main Mar 9, 2026
1 check passed
@munezaclovis munezaclovis deleted the feat/smart-automation branch March 27, 2026 22:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant