Smart automation for Laravel project bootstrapping#33
Merged
munezaclovis merged 8 commits intomainfrom Mar 9, 2026
Merged
Conversation
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)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
automation:section in~/.pv/pv.ymlwith tri-state gates (true/false/ask) for each automation featureinternal/automation/—Stepinterface +RunPipeline()with gate checking and interactive huh promptsinternal/laravel/— smart env vars (maps running services → Laravel config), database name resolution from.env.example, artisan/composer runners, 8 pipeline step implementationspv linkautomation: copies.env.example, generatesAPP_KEY, installs Octane worker, runscomposer install, detects/binds services, setsAPP_URL, creates databases, runs migrations.envfiles onservice:add/service:start, applies safe fallbacks onservice:stop/service:remove(only overwrites values pv originally set)pv.ymlwatcher with 200ms debounce, re-resolves PHP versions and reconfigures server on config changesvendor/autoload.phpadded to FrankenPHP Octane worker watch directiveTest plan
go test ./...— all 26 packages pass (0 failures)