From 3095cf92ca597377c7881c79cabbb0594b885460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emil=20H=C3=B8rlyck?= Date: Mon, 16 Oct 2023 17:35:27 +0200 Subject: [PATCH] Pareto init (#10) * fix: styling * feat: add init command * fix: styling --------- Authored-by: emilhorlyck --- src/Commands/InitCommand.php | 368 +++++++++++++++++++++++++++++++++++ src/Commands/TestCommand.php | 17 -- src/ServiceProvider.php | 4 +- 3 files changed, 370 insertions(+), 19 deletions(-) create mode 100644 src/Commands/InitCommand.php delete mode 100644 src/Commands/TestCommand.php diff --git a/src/Commands/InitCommand.php b/src/Commands/InitCommand.php new file mode 100644 index 0000000..1deef06 --- /dev/null +++ b/src/Commands/InitCommand.php @@ -0,0 +1,368 @@ + 'Replace readme', + 'blueprint' => 'Install blueprint', + // 'backup' => 'Setup backup', + 'api-docs' => 'API Documentation', + 'erd' => 'Generate ERD', + // 'conventional-commits' => 'Conventional commit script', + // 'release' => 'Release script', + // 'pre-push' => 'Pre push git hook for pest', + // 'tests' => 'Run tests', + 'admin' => 'Fillament Admin panel', + ]; + + $chosenSteps = collect( + multiselect( + label: 'What would you like to get started?', + options: $initSteps, + // default: $initSteps, + ) + ); + + if ($chosenSteps->isEmpty()) { + info('You must choose at least one step to continue.'); + + return self::FAILURE; + + } else { + $this->addTooReadme([ + '## Packages installed using [Laravel-Pareto](https://github.com/emilhorlyck/laravel-pareto)', + ]); + } + + if ($chosenSteps->contains('readme')) { + $this->info('Replacing readme...'); + exec('rm README.md'); + exec('touch README.md'); + + $gitAuthor = text('what is you gitHub handle'); + $githubUrl = text('What is the repo url?'); + + $this->addTooReadme([ + + '![Logo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/th5xamgrr6se0x5ro4g6.png)', + '', + '', + '# Project Title', + '', + 'A brief description of what this project does and who it is used for', + '', + '', + '## Tech Stack', + '', + '**TALL:** Tailwind, Alpine.js, Laravel, and Livewire', + '', + '## Demo', + '', + 'Insert gif or link to demo', + '', + '', + '## Run Locally', + '', + 'Clone the project', + '', + '\`\`\`bash', + 'git clone '.$githubUrl, + '\`\`\`', + '', + 'Go to the project directory', + '', + '\`\`\`bash', + 'cd my-project', + '\`\`\`', + '', + 'Install dependencies', + '', + '\`\`\`bash', + 'composer install', + '\`\`\`', + '', + 'Start the server', + '', + '\`\`\`bash', + 'php artisan serve', + '\`\`\`', + '', + '', + '## Running Tests', + '', + 'To run tests, run the following command', + '', + '\`\`\`bash', + 'php artisan vendor/bin/pest', + '\`\`\`', + '', + '', + '## Deployment', + '', + 'To deploy this project push the code to github and make a PR against develop', + '', + '', + '## Authors ', + '', + '- [@'.$gitAuthor.'](https://www.github.com/'.$gitAuthor.')', + '', + '## CodeOwner', + '', + '- [@'.$gitAuthor.'](https://www.github.com/'.$gitAuthor.')', + '', + '', + '## Related', + '', + 'Here are some related projects', + '', + '## Links', + '', + '', + '## Maintenance', + '', + 'Maintenance windows are agreed to be:', + 'No windows agreed.', + ]); + + $this->info('Readme created succesfully'); + } + + // TODO: extract to action + // Blueprint installation + if ($chosenSteps->contains('blueprint')) { + + // $this->addTooReadme('echo "### [Blueprint](Blueprint) from function'); + + info('Installing blueprint...'); + exec('composer require --dev laravel-shift/blueprint'); + info(' - enabling test assertions...'); + exec('composer require --dev jasonmccreary/laravel-test-assertions'); + info(' - enabling pest tests...'); + exec('composer require --dev laravel-shift/blueprint fidum/laravel-blueprint-pestphp-addon'); + exec('echo "/draft.yaml" >> .gitignore'); + exec('echo "/.blueprint" >> .gitignore'); + info('blueprint installed successfully.'); + + // Blueprint definition + info('Creating draft.yaml...'); + exec('touch draft.yaml'); + + info('Please define your models in draft.yaml - look at the documentation for more information.'); + info('Link to documentation: https://blueprint.laravelshift.com/docs/generating-components/'); + + $blueprintDocs = confirm( + label: 'Should we open blueprint docs in chrome?', + ); + + if ($blueprintDocs) { + exec('open -a "Google Chrome.app" https://blueprint.laravelshift.com/docs/generating-components/'); + } + + if (confirm( + label: 'should we open the draft.yaml file in vscode?', + )) { + exec('code ./draft.yaml'); + } + + $confirmed = confirm( + label: 'Have you defined your Blueprint setup?', + required: 'You must provide a blueprint setup before continuing.' + ); + + exec('php artisan blueprint:build'); + info('blueprint definition created successfully.'); + + if (confirm( + label: 'do you want to a Migrate:fresh?')) { + //Todo: ask if we should seed the database + exec('php artisan migrate:fresh'); + } + + $this->addTooReadme([ + '### [Blueprint](https://blueprint.laravelshift.com/docs/generating-components/)', + '#### Usage', + '', + 'Build the application from the draft.yaml file using the following command:', + '\`\`\`bash', + 'php artisan blueprint:build', + '\`\`\`', + '', + 'Undo the last blueprint build using the following command:', + '\`\`\`bash', + 'php artisan blueprint:erase', + '\`\`\`', + '', + ]); + } + + // Backup installation + if ($chosenSteps->contains('backup')) { + $this->info('Installing backup...'); + } + + // API Documentation + if ($chosenSteps->contains('api-docs')) { + $this->info('Installing api-docs...'); + exec('composer require dedoc/scramble'); + exec('composer require doctrine/dbal'); + info('api docs installed successfully. and available at /docs/api and /docs/api.json'); + info('Docs are only visible in local environment.'); + } + + //Generate ERD + if ($chosenSteps->contains('erd')) { + $this->info('Generating ERD...'); + exec('composer require beyondcode/laravel-er-diagram-generator --dev + '); + exec('php artisan generate:erd generated_erd.png'); + + exec('open generated_erd.png'); + + info('ERD generated successfully.'); + + $this->addTooReadme([ + '### [Generate ERD](exampl.com)', + '#### Usage', + '', + 'Generate an ERD', + '\`\`\`bash', + 'php artisan generate:erd', + '\`\`\`', + ]); + + $this->addTooReadme([ + '## Generated ERD', + '![ERD](generated_erd.png)', + 'To update the ERD in the Readme run the following command', + '\`\`\`bash', + 'php artisan generate:erd generated_erd.png', + '\`\`\`', + ]); + } + + // Conventional commit script + + // Release script + + // Pre push git hook for pest + + // Fillament Admin panel + if ($chosenSteps->contains('admin')) { + $this->info('Installing Filament...'); + // exec('composer require signifly/fillament'); + // exec('php artisan fillament:install'); + + exec('composer require filament/filament:"^3.0-stable" --update-with-all-dependencies'); + $this->info('Installing Filament panels...'); + exec('php artisan filament:install --panels -q -n'); + + if (confirm(label: 'Do you want to create a user now?')) { + + $name = text('What is your name?'); + + $email = text('What is your email?'); + + $password = password('What is your password?'); + + exec('php artisan make:filament-user --name="'.$name.'" --email="'.$email.'" --password="'.$password.'"'); + } + + $this->info('models: '.$this->getModelNames()->implode(', ')); + + $adminModels = collect( + multiselect( + label: 'What models would you like to add to the Admin interface?', + options: $this->getModelNames()->values()->toArray(), + ) + ); + + $adminModels->each(function ($model) { + $this->info('Adding '.$model.' to the Admin interface...'); + exec('php artisan make:filament-resource '.$model.' --generate'); + }); + + info('Fillament installed successfully. go to /admin to see the admin panel.'); + } + + // Run tests + if ($chosenSteps->contains('tests')) { + exec('./vendor/bin/pest --init'); + exec('./vendor/bin/pest'); + } + + return self::SUCCESS; + } + + public function getModelNames(): Collection + { + $models = collect(File::allFiles(app_path())) + ->map(function ($item) { + + $path = $item->getRelativePathName(); + $class = sprintf('\%s%s', + Container::getInstance()->getNamespace(), + strtr(substr($path, 0, strrpos($path, '.')), '/', '\\')); + + return $class; + }) + ->filter(function ($class) { + $valid = false; + + if (class_exists($class)) { + $reflection = new \ReflectionClass($class); + $valid = $reflection->isSubclassOf(Model::class) && + ! $reflection->isAbstract(); + } + + return $valid; + }); + + $modelsNames = $models->map(function ($model) { + + $classNameComponents = explode('\\', $model); + + return end($classNameComponents); + }); + + return $modelsNames; //$models->values(); + } + + public function addTooReadme(array $lines) + { + foreach ($lines as $line) { + exec('echo "'.$line.'" >> README.md'); + } + } +} diff --git a/src/Commands/TestCommand.php b/src/Commands/TestCommand.php deleted file mode 100644 index 3be0721..0000000 --- a/src/Commands/TestCommand.php +++ /dev/null @@ -1,17 +0,0 @@ -info('Test command'); - } -} diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 7081aea..e9c99b0 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -2,8 +2,8 @@ namespace EmilHorlyck\LaravelPareto; +use EmilHorlyck\LaravelPareto\Commands\InitCommand; use Illuminate\Support\ServiceProvider as BaseServiceProvider; -use EmilHorlyck\LaravelPareto\Commands\TestCommand; class ServiceProvider extends BaseServiceProvider { @@ -21,7 +21,7 @@ public function boot(): void { if ($this->app->runningInConsole()) { $this->commands([ - TestCommand::class + InitCommand::class, ]); } }